@codexhost/cli-linux-arm64 0.16.1 → 0.17.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.
@@ -528,9 +528,9 @@ async function jsonlHeader(file2, match, signal, maxLines = 4) {
528
528
  continue;
529
529
  }
530
530
  if (typeof value === "object" && value !== null && !Array.isArray(value)) {
531
- const record7 = value;
532
- if (match(record7))
533
- return record7;
531
+ const record9 = value;
532
+ if (match(record9))
533
+ return record9;
534
534
  }
535
535
  }
536
536
  return null;
@@ -1317,10 +1317,10 @@ function mergeDefs(...defs) {
1317
1317
  function cloneDef(schema) {
1318
1318
  return mergeDefs(schema._zod.def);
1319
1319
  }
1320
- function getElementAtPath(obj, path16) {
1321
- if (!path16)
1320
+ function getElementAtPath(obj, path17) {
1321
+ if (!path17)
1322
1322
  return obj;
1323
- return path16.reduce((acc, key) => acc?.[key], obj);
1323
+ return path17.reduce((acc, key) => acc?.[key], obj);
1324
1324
  }
1325
1325
  function promiseAllObject(promisesObj) {
1326
1326
  const keys = Object.keys(promisesObj);
@@ -1729,11 +1729,11 @@ function explicitlyAborted(x, startIndex = 0) {
1729
1729
  }
1730
1730
  return false;
1731
1731
  }
1732
- function prefixIssues(path16, issues) {
1732
+ function prefixIssues(path17, issues) {
1733
1733
  return issues.map((iss) => {
1734
1734
  var _a3;
1735
1735
  (_a3 = iss).path ?? (_a3.path = []);
1736
- iss.path.unshift(path16);
1736
+ iss.path.unshift(path17);
1737
1737
  return iss;
1738
1738
  });
1739
1739
  }
@@ -1880,16 +1880,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
1880
1880
  }
1881
1881
  function formatError(error51, mapper = (issue2) => issue2.message) {
1882
1882
  const fieldErrors = { _errors: [] };
1883
- const processError = (error52, path16 = []) => {
1883
+ const processError = (error52, path17 = []) => {
1884
1884
  for (const issue2 of error52.issues) {
1885
1885
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1886
- issue2.errors.map((issues) => processError({ issues }, [...path16, ...issue2.path]));
1886
+ issue2.errors.map((issues) => processError({ issues }, [...path17, ...issue2.path]));
1887
1887
  } else if (issue2.code === "invalid_key") {
1888
- processError({ issues: issue2.issues }, [...path16, ...issue2.path]);
1888
+ processError({ issues: issue2.issues }, [...path17, ...issue2.path]);
1889
1889
  } else if (issue2.code === "invalid_element") {
1890
- processError({ issues: issue2.issues }, [...path16, ...issue2.path]);
1890
+ processError({ issues: issue2.issues }, [...path17, ...issue2.path]);
1891
1891
  } else {
1892
- const fullpath = [...path16, ...issue2.path];
1892
+ const fullpath = [...path17, ...issue2.path];
1893
1893
  if (fullpath.length === 0) {
1894
1894
  fieldErrors._errors.push(mapper(issue2));
1895
1895
  } else {
@@ -1916,17 +1916,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
1916
1916
  }
1917
1917
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
1918
1918
  const result = { errors: [] };
1919
- const processError = (error52, path16 = []) => {
1919
+ const processError = (error52, path17 = []) => {
1920
1920
  var _a3, _b;
1921
1921
  for (const issue2 of error52.issues) {
1922
1922
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1923
- issue2.errors.map((issues) => processError({ issues }, [...path16, ...issue2.path]));
1923
+ issue2.errors.map((issues) => processError({ issues }, [...path17, ...issue2.path]));
1924
1924
  } else if (issue2.code === "invalid_key") {
1925
- processError({ issues: issue2.issues }, [...path16, ...issue2.path]);
1925
+ processError({ issues: issue2.issues }, [...path17, ...issue2.path]);
1926
1926
  } else if (issue2.code === "invalid_element") {
1927
- processError({ issues: issue2.issues }, [...path16, ...issue2.path]);
1927
+ processError({ issues: issue2.issues }, [...path17, ...issue2.path]);
1928
1928
  } else {
1929
- const fullpath = [...path16, ...issue2.path];
1929
+ const fullpath = [...path17, ...issue2.path];
1930
1930
  if (fullpath.length === 0) {
1931
1931
  result.errors.push(mapper(issue2));
1932
1932
  continue;
@@ -1958,8 +1958,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
1958
1958
  }
1959
1959
  function toDotPath(_path) {
1960
1960
  const segs = [];
1961
- const path16 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1962
- for (const seg of path16) {
1961
+ const path17 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1962
+ for (const seg of path17) {
1963
1963
  if (typeof seg === "number")
1964
1964
  segs.push(`[${seg}]`);
1965
1965
  else if (typeof seg === "symbol")
@@ -8189,8 +8189,8 @@ function ko_default() {
8189
8189
  }
8190
8190
 
8191
8191
  // ../../../node_modules/zod/v4/locales/lt.js
8192
- var capitalizeFirstCharacter = (text2) => {
8193
- return text2.charAt(0).toUpperCase() + text2.slice(1);
8192
+ var capitalizeFirstCharacter = (text3) => {
8193
+ return text3.charAt(0).toUpperCase() + text3.slice(1);
8194
8194
  };
8195
8195
  function getUnitTypeFromNumber(number4) {
8196
8196
  const abs = Math.abs(number4);
@@ -14651,13 +14651,13 @@ function resolveRef(ref, ctx) {
14651
14651
  if (!ref.startsWith("#")) {
14652
14652
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
14653
14653
  }
14654
- const path16 = ref.slice(1).split("/").filter(Boolean);
14655
- if (path16.length === 0) {
14654
+ const path17 = ref.slice(1).split("/").filter(Boolean);
14655
+ if (path17.length === 0) {
14656
14656
  return ctx.rootSchema;
14657
14657
  }
14658
14658
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
14659
- if (path16[0] === defsKey) {
14660
- const key = path16[1];
14659
+ if (path17[0] === defsKey) {
14660
+ const key = path17[1];
14661
14661
  if (!key || !ctx.defs[key]) {
14662
14662
  throw new Error(`Reference not found: ${ref}`);
14663
14663
  }
@@ -15146,7 +15146,7 @@ var harnessDisplaySetSchema = external_exports.strictObject({
15146
15146
 
15147
15147
  // ../../shared-contracts/dist/harness-presentation.js
15148
15148
  var localeSchema = external_exports.string().max(64).regex(/^[a-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/u);
15149
- var displayText = (maximum) => external_exports.string().min(1).max(maximum).refine((text2) => text2.trim().length > 0);
15149
+ var displayText = (maximum) => external_exports.string().min(1).max(maximum).refine((text3) => text3.trim().length > 0);
15150
15150
  var harnessLocalizationsSchema = external_exports.record(localeSchema, external_exports.object({
15151
15151
  label: displayText(256).optional(),
15152
15152
  description: displayText(1024).optional()
@@ -15474,7 +15474,7 @@ var threadManualCompactionStartedSchema = external_exports.strictObject({
15474
15474
  var nonNegativeSafeIntegerSchema = external_exports.number().int().safe().nonnegative();
15475
15475
  var finiteNonNegativeNumberSchema = external_exports.number().finite().nonnegative();
15476
15476
  var cacheHitRatePercentSchema = external_exports.number().finite().min(0).max(100);
15477
- var indicatorTextSchema = (maximum) => harnessLocalizedTextSchema.refine((entries) => Object.values(entries).every((text2) => text2.length <= maximum));
15477
+ var indicatorTextSchema = (maximum) => harnessLocalizedTextSchema.refine((entries) => Object.values(entries).every((text3) => text3.length <= maximum));
15478
15478
  var composerIndicatorsSchema = external_exports.array(external_exports.object({
15479
15479
  kind: external_exports.literal("countdown"),
15480
15480
  id: external_exports.string().min(1).max(64),
@@ -16719,8 +16719,8 @@ async function readCandidate(file2, signal) {
16719
16719
  const message3 = isRecord(entry.message) ? entry.message : null;
16720
16720
  if (!firstMessage && entry.type === "message" && message3?.role === "user") {
16721
16721
  const content = message3.content;
16722
- const text2 = typeof content === "string" ? content : Array.isArray(content) ? content.filter((block) => isRecord(block) && block.type === "text" && typeof block.text === "string").map((block) => block.text).join(" ") : "";
16723
- firstMessage = sessionImportTitle(text2);
16722
+ const text3 = typeof content === "string" ? content : Array.isArray(content) ? content.filter((block) => isRecord(block) && block.type === "text" && typeof block.text === "string").map((block) => block.text).join(" ") : "";
16723
+ firstMessage = sessionImportTitle(text3);
16724
16724
  }
16725
16725
  hasUser = entry.type === "message" && message3?.role === "user" || typeof entry.parentId === "string" && entries.get(entry.parentId) === true;
16726
16726
  entries.set(entry.id, hasUser);
@@ -17233,8 +17233,8 @@ function liveHarnessCommandPrompt(catalog, idPrefix, commandId, argumentText) {
17233
17233
  const descriptor = catalog.commands.find(({ id }) => id === commandId);
17234
17234
  if (!descriptor)
17235
17235
  return null;
17236
- const text2 = typeof argumentText === "string" ? argumentText.trim() : "";
17237
- return text2 ? `${descriptor.invocation} ${text2}` : descriptor.invocation;
17236
+ const text3 = typeof argumentText === "string" ? argumentText.trim() : "";
17237
+ return text3 ? `${descriptor.invocation} ${text3}` : descriptor.invocation;
17238
17238
  }
17239
17239
  function mergeLiveHarnessCommands(builtIns, idPrefix, live, exclusions = {}) {
17240
17240
  if (!live)
@@ -17370,16 +17370,16 @@ var Diff = class {
17370
17370
  }
17371
17371
  }
17372
17372
  }
17373
- addToPath(path16, added, removed, oldPosInc, options) {
17374
- const last = path16.lastComponent;
17373
+ addToPath(path17, added, removed, oldPosInc, options) {
17374
+ const last = path17.lastComponent;
17375
17375
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
17376
17376
  return {
17377
- oldPos: path16.oldPos + oldPosInc,
17377
+ oldPos: path17.oldPos + oldPosInc,
17378
17378
  lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
17379
17379
  };
17380
17380
  } else {
17381
17381
  return {
17382
- oldPos: path16.oldPos + oldPosInc,
17382
+ oldPos: path17.oldPos + oldPosInc,
17383
17383
  lastComponent: { count: 1, added, removed, previousComponent: last }
17384
17384
  };
17385
17385
  }
@@ -17779,9 +17779,9 @@ function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader
17779
17779
  } }));
17780
17780
  }
17781
17781
  }
17782
- function splitLines(text2) {
17783
- const hasTrailingNl = text2.endsWith("\n");
17784
- const result = text2.split("\n").map((line) => line + "\n");
17782
+ function splitLines(text3) {
17783
+ const hasTrailingNl = text3.endsWith("\n");
17784
+ const result = text3.split("\n").map((line) => line + "\n");
17785
17785
  if (hasTrailingNl) {
17786
17786
  result.pop();
17787
17787
  } else {
@@ -18015,11 +18015,344 @@ function piNestedCallFileChanges(nestedCalls, cwd) {
18015
18015
  return projected;
18016
18016
  }
18017
18017
 
18018
- // dist/pi-subagents.js
18018
+ // dist/pi-message-item-id.js
18019
18019
  import { createHash } from "node:crypto";
18020
+ function piMessageIdentity(sessionId, message3, timestampCounts) {
18021
+ if (typeof message3 !== "object" || message3 === null || !("role" in message3) || message3.role !== "assistant")
18022
+ return void 0;
18023
+ if ("timestamp" in message3 && typeof message3.timestamp === "number" && Number.isSafeInteger(message3.timestamp) && message3.timestamp >= 0) {
18024
+ const occurrence = timestampCounts.get(message3.timestamp) ?? 0;
18025
+ timestampCounts.set(message3.timestamp, occurrence + 1);
18026
+ return { sessionId, timestamp: message3.timestamp, occurrence };
18027
+ }
18028
+ if ("responseId" in message3 && typeof message3.responseId === "string" && message3.responseId.trim().length > 0)
18029
+ return { responseId: message3.responseId };
18030
+ return void 0;
18031
+ }
18032
+ function piHistoryMessageIdentities(sessionId, entries) {
18033
+ const timestampCounts = /* @__PURE__ */ new Map();
18034
+ const identities = /* @__PURE__ */ new Map();
18035
+ for (const entry of entries) {
18036
+ const identity = piMessageIdentity(sessionId, entry.message, timestampCounts);
18037
+ if (identity)
18038
+ identities.set(entry.id, identity);
18039
+ }
18040
+ return { identities, timestampCounts };
18041
+ }
18042
+ function piMessageItemId(identity, kind) {
18043
+ if (!identity)
18044
+ return null;
18045
+ const timestampIdentity = "timestamp" in identity;
18046
+ const value = timestampIdentity ? JSON.stringify([identity.sessionId, identity.timestamp, identity.occurrence]) : identity.responseId;
18047
+ const digest = createHash("sha256").update(value).digest("hex");
18048
+ return hostItemIdSchema.parse(`pi-${timestampIdentity ? "message" : "response"}-v1-${digest}-${kind}`);
18049
+ }
18050
+
18051
+ // dist/pi-assistant-outcome.js
18052
+ function piAssistantWasAborted(value) {
18053
+ if (typeof value !== "object" || value === null || Array.isArray(value))
18054
+ return false;
18055
+ const message3 = value;
18056
+ return message3.role === "assistant" && (message3.stopReason === "aborted" || message3.stopReason === "error" && message3.errorMessage === "This operation was aborted");
18057
+ }
18058
+ function piAssistantPhase(value) {
18059
+ if (typeof value !== "object" || value === null || Array.isArray(value))
18060
+ return void 0;
18061
+ const message3 = value;
18062
+ if (message3.role !== "assistant")
18063
+ return void 0;
18064
+ const lastText = Array.isArray(message3.content) ? message3.content.findLast((part) => typeof part === "object" && part !== null && !Array.isArray(part) && "type" in part && part.type === "text" && "text" in part && typeof part.text === "string" && part.text.trim().length > 0) : void 0;
18065
+ if (!lastText && !(typeof message3.content === "string" && message3.content.trim()))
18066
+ return void 0;
18067
+ if (typeof lastText?.textSignature === "string") {
18068
+ try {
18069
+ const signature = JSON.parse(lastText.textSignature);
18070
+ if (typeof signature === "object" && signature !== null && !Array.isArray(signature) && "v" in signature && signature.v === 1 && "id" in signature && typeof signature.id === "string" && "phase" in signature && (signature.phase === "commentary" || signature.phase === "final_answer"))
18071
+ return signature.phase;
18072
+ } catch {
18073
+ }
18074
+ }
18075
+ if (message3.stopReason === "toolUse")
18076
+ return "commentary";
18077
+ if (message3.stopReason === "stop")
18078
+ return "final_answer";
18079
+ return void 0;
18080
+ }
18081
+
18082
+ // dist/pi-subagents.js
18083
+ import { createHash as createHash3 } from "node:crypto";
18084
+
18085
+ // dist/pi-gotgenes-extension.js
18086
+ import { createHash as createHash2, randomUUID } from "node:crypto";
18087
+ import { mkdir, readFile, rename, rm as rm2, writeFile as writeFile2 } from "node:fs/promises";
18088
+ import { homedir as homedir2 } from "node:os";
18089
+ import path7 from "node:path";
18090
+ var GOTGENES_WIDGET = "codexhost-gotgenes-subagents";
18091
+ var GOTGENES_PREFIX = "CODEXHOST_GOTGENES_SUBAGENTS_V1:";
18092
+ var GOTGENES_EXTENSION = `export default function(pi) {
18093
+ let ctx, timer, service, previous = "";
18094
+ const publish = () => {
18095
+ if (!ctx) return;
18096
+ // Child SDK sessions can publish their own process-global service. Bind this parent once.
18097
+ if (!service) {
18098
+ const candidate = globalThis[Symbol.for("@gotgenes/pi-subagents:service")];
18099
+ if (typeof candidate?.listAgents !== "function") return;
18100
+ service = candidate;
18101
+ }
18102
+ const agents = service.listAgents().slice(0, 128).map((r) => ({
18103
+ id: r.id, type: r.type, description: r.description?.slice(0, 2048),
18104
+ status: r.status, isBackground: r.isBackground, outputFile: r.outputFile,
18105
+ toolUses: r.toolUses, startedAt: r.startedAt, completedAt: r.completedAt,
18106
+ result: r.result?.slice(0, 2048), error: r.error?.slice(0, 2048),
18107
+ turnBudget: r.turnBudget, lifetimeUsage: r.lifetimeUsage,
18108
+ }));
18109
+ const payload = JSON.stringify({version: 1, agents});
18110
+ if (payload === previous) return;
18111
+ previous = payload;
18112
+ ctx.ui.setWidget("${GOTGENES_WIDGET}", ["${GOTGENES_PREFIX}" + payload]);
18113
+ };
18114
+ const schedule = () => queueMicrotask(publish);
18115
+ for (const name of ["created", "started", "completed", "failed", "resuming", "resumed", "compacted", "steered", "update"]) {
18116
+ pi.events.on("subagents:" + name, schedule);
18117
+ }
18118
+ pi.on("session_start", (_event, context) => {
18119
+ // A session switch keeps this extension's manager/service; only reload creates a new instance.
18120
+ ctx = context; previous = ""; clearInterval(timer);
18121
+ schedule();
18122
+ // The public service publishes outputFile only after queued session creation and has no progress event.
18123
+ timer = setInterval(publish, 1000);
18124
+ timer.unref?.();
18125
+ });
18126
+ pi.on("session_shutdown", () => { clearInterval(timer); timer = undefined; ctx = undefined; service = undefined; });
18127
+ }
18128
+ `;
18129
+ async function ensureGotgenesExtension(environment) {
18130
+ const digest = createHash2("sha256").update(GOTGENES_EXTENSION).digest("hex").slice(0, 16);
18131
+ const root = environment.CODEXHOST_DATA_DIR ?? path7.join(environment.HOME ?? environment.USERPROFILE ?? homedir2(), ".codexhost");
18132
+ const directory = path7.resolve(root, "extensions", "pi-subagent-observer");
18133
+ const file2 = path7.join(directory, `${digest}.mjs`);
18134
+ if (await readFile(file2, "utf8").catch(() => "") === GOTGENES_EXTENSION)
18135
+ return file2;
18136
+ await mkdir(directory, { recursive: true });
18137
+ const temporary = `${file2}.${randomUUID()}.tmp`;
18138
+ try {
18139
+ await writeFile2(temporary, GOTGENES_EXTENSION, { mode: 384 });
18140
+ try {
18141
+ await rename(temporary, file2);
18142
+ } catch (error51) {
18143
+ if (await readFile(file2, "utf8").catch(() => "") !== GOTGENES_EXTENSION)
18144
+ throw error51;
18145
+ }
18146
+ } finally {
18147
+ await rm2(temporary, { force: true });
18148
+ }
18149
+ return file2;
18150
+ }
18151
+
18152
+ // dist/pi-gotgenes-subagents.js
18153
+ var PREFIX = "pi-gotgenes-v1:";
18154
+ var STATUSES = {
18155
+ queued: "pending",
18156
+ running: "running",
18157
+ background: "pending",
18158
+ completed: "completed",
18159
+ aborted: "interrupted",
18160
+ stopped: "interrupted",
18161
+ error: "failed"
18162
+ };
18163
+ function isRecord4(value) {
18164
+ return typeof value === "object" && value !== null && !Array.isArray(value);
18165
+ }
18166
+ function text(value, limit = 2048) {
18167
+ return typeof value === "string" && value.length > 0 && value.length <= limit;
18168
+ }
18169
+ function gotgenesId(id) {
18170
+ return PREFIX + Buffer.from(id).toString("base64url");
18171
+ }
18172
+ function parseGotgenesId(value) {
18173
+ if (!value.startsWith(PREFIX))
18174
+ return null;
18175
+ const id = Buffer.from(value.slice(PREFIX.length), "base64url").toString("utf8");
18176
+ if (!text(id, 256) || /[\s/\\]/u.test(id) || gotgenesId(id) !== value)
18177
+ throw new Error("Invalid gotgenes subagent identity");
18178
+ return id;
18179
+ }
18180
+ function gotgenesRecord(value) {
18181
+ if (!isRecord4(value) || !text(value.id, 256) || /[\s/\\]/u.test(value.id) || !text(value.type) || !text(value.description) || typeof value.status !== "string" || !Object.hasOwn(STATUSES, value.status))
18182
+ return null;
18183
+ const status = STATUSES[value.status];
18184
+ if (!status)
18185
+ return null;
18186
+ const id = gotgenesId(value.id);
18187
+ const progress = typeof value.toolUses === "number" ? `${value.toolUses} tool uses` : void 0;
18188
+ const result = typeof value.error === "string" ? value.error : typeof value.result === "string" ? value.result : progress;
18189
+ return {
18190
+ id: value.id,
18191
+ roleKnown: value.roleKnown !== false,
18192
+ backgroundKnown: typeof value.isBackground === "boolean",
18193
+ child: {
18194
+ subagentId: id,
18195
+ nativeSubagentId: id,
18196
+ description: value.description,
18197
+ role: value.type,
18198
+ status,
18199
+ background: value.isBackground === true,
18200
+ ...text(value.modelName) ? { model: value.modelName } : {},
18201
+ ...result ? { resultSummary: result.slice(0, 2048) } : {}
18202
+ },
18203
+ ...text(value.outputFile, 8192) ? { outputFile: value.outputFile } : {},
18204
+ revision: JSON.stringify([
18205
+ value.toolUses,
18206
+ value.turnBudget,
18207
+ value.lifetimeUsage,
18208
+ value.outputFile
18209
+ ])
18210
+ };
18211
+ }
18212
+ function gotgenesToolRecord(toolName, result) {
18213
+ if (!["subagent", "get_subagent_result"].includes(toolName) || !isRecord4(result) || !isRecord4(result.details))
18214
+ return null;
18215
+ const d = result.details;
18216
+ if (!text(d.agentId, 256) || !text(d.displayName) || !text(d.description))
18217
+ return null;
18218
+ return gotgenesRecord({
18219
+ ...d,
18220
+ id: d.agentId,
18221
+ type: d.subagentType ?? d.displayName,
18222
+ roleKnown: text(d.subagentType),
18223
+ isBackground: toolName === "subagent" ? d.status === "background" || Array.isArray(d.tags) && d.tags.includes("background") : void 0,
18224
+ outputFile: d.transcriptPath,
18225
+ result: d.preview
18226
+ });
18227
+ }
18228
+ function parseGotgenesWidget(value) {
18229
+ if (!isRecord4(value) || value.type !== "extension_ui_request" || value.method !== "setWidget" || value.widgetKey !== GOTGENES_WIDGET || !Array.isArray(value.widgetLines))
18230
+ return null;
18231
+ const line = value.widgetLines.find((x) => typeof x === "string" && x.startsWith(GOTGENES_PREFIX));
18232
+ if (!line || Buffer.byteLength(line) > 1024 * 1024)
18233
+ return null;
18234
+ try {
18235
+ const payload = JSON.parse(line.slice(GOTGENES_PREFIX.length));
18236
+ if (!isRecord4(payload) || payload.version !== 1 || !Array.isArray(payload.agents) || payload.agents.length > 128)
18237
+ return null;
18238
+ const records = payload.agents.map(gotgenesRecord);
18239
+ return records.every((r) => r !== null) ? records : null;
18240
+ } catch {
18241
+ return null;
18242
+ }
18243
+ }
18244
+ function mergeGotgenesRecord(previous, record9) {
18245
+ const model2 = record9.child.model ?? previous?.child.model;
18246
+ const role = record9.roleKnown ? record9.child.role : previous?.child.role ?? record9.child.role;
18247
+ return {
18248
+ ...previous,
18249
+ ...record9,
18250
+ roleKnown: record9.roleKnown || previous?.roleKnown === true,
18251
+ backgroundKnown: record9.backgroundKnown || previous?.backgroundKnown === true,
18252
+ outputFile: record9.outputFile ?? previous?.outputFile,
18253
+ child: {
18254
+ ...previous?.child,
18255
+ ...record9.child,
18256
+ ...model2 ? { model: model2 } : {},
18257
+ ...role ? { role } : {},
18258
+ background: record9.backgroundKnown ? record9.child.background : previous?.child.background ?? record9.child.background
18259
+ }
18260
+ };
18261
+ }
18262
+ var GotgenesSubagents = class {
18263
+ emit;
18264
+ records = /* @__PURE__ */ new Map();
18265
+ #nativeObserved = /* @__PURE__ */ new Set();
18266
+ #active = /* @__PURE__ */ new Map();
18267
+ constructor(emit) {
18268
+ this.emit = emit;
18269
+ }
18270
+ observe(records, publish = true, activeTurn, nativeObservation = false) {
18271
+ for (const record9 of records) {
18272
+ if (!publish && this.#nativeObserved.has(record9.id))
18273
+ continue;
18274
+ if (nativeObservation)
18275
+ this.#nativeObserved.add(record9.id);
18276
+ const previous = this.records.get(record9.id);
18277
+ const merged = mergeGotgenesRecord(previous, record9);
18278
+ this.records.set(record9.id, merged);
18279
+ if (publish && !previous && activeTurn && !this.#active.has(record9.id)) {
18280
+ const item = {
18281
+ type: "subagentDelegation",
18282
+ itemId: activeTurn.nextItemId(),
18283
+ operation: "spawn",
18284
+ subagents: [merged.child]
18285
+ };
18286
+ this.#active.set(record9.id, { turnId: activeTurn.turnId, item });
18287
+ this.emit({ type: "item.started", turnId: activeTurn.turnId, item });
18288
+ }
18289
+ if (!publish || JSON.stringify(previous) === JSON.stringify(merged))
18290
+ continue;
18291
+ const active = this.#active.get(record9.id);
18292
+ if (active) {
18293
+ active.item = { ...active.item, subagents: [merged.child] };
18294
+ this.emit({
18295
+ type: "item.updated",
18296
+ turnId: active.turnId,
18297
+ itemId: active.item.itemId,
18298
+ update: { type: "subagents.replace", subagents: [merged.child] }
18299
+ });
18300
+ }
18301
+ this.emit({
18302
+ type: "subagent.state.changed",
18303
+ nativeSubagentId: merged.child.subagentId,
18304
+ status: merged.child.status
18305
+ });
18306
+ this.emit({ type: "subagent.transcript.changed", nativeSubagentId: merged.child.subagentId });
18307
+ }
18308
+ }
18309
+ project(toolName, result, itemId2) {
18310
+ const parsed = gotgenesToolRecord(toolName, result);
18311
+ if (!parsed || toolName !== "subagent")
18312
+ return null;
18313
+ const child = this.records.get(parsed.id)?.child ?? parsed.child;
18314
+ return { type: "subagentDelegation", itemId: itemId2, operation: "spawn", subagents: [child] };
18315
+ }
18316
+ start(turnId, toolName, result, itemId2) {
18317
+ const parsed = gotgenesToolRecord(toolName, result);
18318
+ if (!parsed)
18319
+ return false;
18320
+ const prior = this.records.get(parsed.id);
18321
+ if (!prior || !this.#nativeObserved.has(parsed.id))
18322
+ this.observe([parsed]);
18323
+ else {
18324
+ this.observe([
18325
+ {
18326
+ ...prior,
18327
+ child: { ...prior.child, ...parsed.child.model ? { model: parsed.child.model } : {} }
18328
+ }
18329
+ ]);
18330
+ }
18331
+ if (toolName === "subagent" && !this.#active.has(parsed.id)) {
18332
+ const item = this.project(toolName, result, itemId2);
18333
+ if (!item)
18334
+ return false;
18335
+ this.#active.set(parsed.id, { turnId, item });
18336
+ this.emit({ type: "item.started", turnId, item });
18337
+ }
18338
+ return true;
18339
+ }
18340
+ finish(turnId) {
18341
+ for (const [id, active] of this.#active) {
18342
+ if (active.turnId !== turnId)
18343
+ continue;
18344
+ this.#active.delete(id);
18345
+ this.emit({
18346
+ type: "item.completed",
18347
+ turnId,
18348
+ snapshot: { item: active.item, outcome: { status: "succeeded" } }
18349
+ });
18350
+ }
18351
+ }
18352
+ };
18020
18353
 
18021
18354
  // dist/pi-subagent-workflow.js
18022
- var PREFIX = "pi-subagents-workflow-v1:";
18355
+ var PREFIX2 = "pi-subagents-workflow-v1:";
18023
18356
  var STATES = {
18024
18357
  pending: "pending",
18025
18358
  running: "running",
@@ -18033,7 +18366,7 @@ var STATES = {
18033
18366
  function record2(value) {
18034
18367
  return typeof value === "object" && value !== null && !Array.isArray(value);
18035
18368
  }
18036
- function text(value, limit = 256) {
18369
+ function text2(value, limit = 256) {
18037
18370
  return typeof value === "string" && value.length > 0 && value.length <= limit;
18038
18371
  }
18039
18372
  function piWorkflowSummary(result) {
@@ -18041,15 +18374,15 @@ function piWorkflowSummary(result) {
18041
18374
  return null;
18042
18375
  const details = result.details;
18043
18376
  const summary = details.workflowChildren;
18044
- if (!record2(summary) || summary.version !== 1 || !text(summary.workflowRunId) || summary.workflowRunId !== details.runId || !text(summary.parentToolCallId) || typeof summary.inventoryComplete !== "boolean" || !Array.isArray(summary.children) || summary.children.length > 256)
18377
+ if (!record2(summary) || summary.version !== 1 || !text2(summary.workflowRunId) || summary.workflowRunId !== details.runId || !text2(summary.parentToolCallId) || typeof summary.inventoryComplete !== "boolean" || !Array.isArray(summary.children) || summary.children.length > 256)
18045
18378
  return null;
18046
18379
  const children = [];
18047
18380
  const seen = /* @__PURE__ */ new Set();
18048
18381
  for (const child of summary.children) {
18049
- if (!record2(child) || !text(child.childId) || seen.has(child.childId) || typeof child.state !== "string" || !Object.hasOwn(STATES, child.state))
18382
+ if (!record2(child) || !text2(child.childId) || seen.has(child.childId) || typeof child.state !== "string" || !Object.hasOwn(STATES, child.state))
18050
18383
  return null;
18051
18384
  for (const key of ["agent", "sessionName", "model", "thinking"]) {
18052
- if (child[key] !== void 0 && !text(child[key], 2048))
18385
+ if (child[key] !== void 0 && !text2(child[key], 2048))
18053
18386
  return null;
18054
18387
  }
18055
18388
  const mappedState = STATES[child.state];
@@ -18073,15 +18406,15 @@ function piWorkflowSummary(result) {
18073
18406
  };
18074
18407
  }
18075
18408
  function piWorkflowSubagentId(address) {
18076
- return PREFIX + Buffer.from(JSON.stringify([address.workflowRunId, address.childId])).toString("base64url");
18409
+ return PREFIX2 + Buffer.from(JSON.stringify([address.workflowRunId, address.childId])).toString("base64url");
18077
18410
  }
18078
18411
  function parsePiWorkflowSubagentId(id) {
18079
- if (!id.startsWith(PREFIX))
18412
+ if (!id.startsWith(PREFIX2))
18080
18413
  return null;
18081
18414
  if (id.length > 3e3)
18082
18415
  throw new Error("Invalid Pi workflow child identity");
18083
- const value = JSON.parse(Buffer.from(id.slice(PREFIX.length), "base64url").toString("utf8"));
18084
- if (!Array.isArray(value) || value.length !== 2 || !text(value[0]) || !text(value[1]))
18416
+ const value = JSON.parse(Buffer.from(id.slice(PREFIX2.length), "base64url").toString("utf8"));
18417
+ if (!Array.isArray(value) || value.length !== 2 || !text2(value[0]) || !text2(value[1]))
18085
18418
  throw new Error("Invalid Pi workflow child identity");
18086
18419
  const address = { workflowRunId: value[0], childId: value[1] };
18087
18420
  if (piWorkflowSubagentId(address) !== id)
@@ -18239,8 +18572,13 @@ var PiSubagents = class {
18239
18572
  #children = /* @__PURE__ */ new Map();
18240
18573
  #active = /* @__PURE__ */ new Map();
18241
18574
  #waiting = /* @__PURE__ */ new Map();
18575
+ gotgenes;
18242
18576
  constructor(emit) {
18243
18577
  this.emit = emit;
18578
+ this.gotgenes = new GotgenesSubagents(emit);
18579
+ }
18580
+ observeGotgenes(records, activeTurn) {
18581
+ this.gotgenes.observe(records, true, activeTurn, true);
18244
18582
  }
18245
18583
  observe(runs) {
18246
18584
  this.#apply(runs, true);
@@ -18294,6 +18632,9 @@ var PiSubagents = class {
18294
18632
  }
18295
18633
  }
18296
18634
  project(toolName, result, itemId2, callId) {
18635
+ const gotgenes = this.gotgenes.project(toolName, result, itemId2);
18636
+ if (gotgenes)
18637
+ return gotgenes;
18297
18638
  const workflow = toolName === "subagent" ? piWorkflowSummary(result) : null;
18298
18639
  if (workflow && (!callId || workflow.parentToolCallId === callId))
18299
18640
  return projectPiWorkflow(workflow, itemId2);
@@ -18304,6 +18645,8 @@ var PiSubagents = class {
18304
18645
  return children.length ? { type: "subagentDelegation", itemId: itemId2, operation: "spawn", subagents: children } : null;
18305
18646
  }
18306
18647
  start(turnId, toolName, result, itemId2, callId) {
18648
+ if (this.gotgenes.start(turnId, toolName, result, itemId2))
18649
+ return;
18307
18650
  const workflow = toolName === "subagent" ? piWorkflowSummary(result) : null;
18308
18651
  if (workflow && (!callId || workflow.parentToolCallId === callId)) {
18309
18652
  const key = `workflow:${workflow.workflowRunId}`;
@@ -18349,6 +18692,7 @@ var PiSubagents = class {
18349
18692
  this.emit({ type: "item.started", turnId, item });
18350
18693
  }
18351
18694
  finish(turnId) {
18695
+ this.gotgenes.finish(turnId);
18352
18696
  for (const [runId, waiting] of this.#waiting) {
18353
18697
  if (waiting.turnId === turnId)
18354
18698
  this.#waiting.delete(runId);
@@ -18396,15 +18740,15 @@ ${entry.text}`);
18396
18740
  nativeTurnRef: nativeTurnRefSchema.parse({
18397
18741
  harnessId: "pi",
18398
18742
  nativeSessionId: parentSessionId,
18399
- nativeTurnKey: `pi-subagent-${createHash("sha256").update(id).digest("hex")}`,
18743
+ nativeTurnKey: `pi-subagent-${createHash3("sha256").update(id).digest("hex")}`,
18400
18744
  formatVersion: 1
18401
18745
  }),
18402
18746
  input: reply.task ? [{ type: "text", text: reply.task }] : [],
18403
- items: texts.map((text2, index) => ({
18747
+ items: texts.map((text3, index) => ({
18404
18748
  item: {
18405
18749
  type: "agentMessage",
18406
- text: text2,
18407
- itemId: hostItemIdSchema.parse(`pi-subagent-${createHash("sha256").update(`${id}:${index}:${text2}`).digest("hex")}`)
18750
+ text: text3,
18751
+ itemId: hostItemIdSchema.parse(`pi-subagent-${createHash3("sha256").update(`${id}:${index}:${text3}`).digest("hex")}`)
18408
18752
  },
18409
18753
  outcome: { status: "succeeded" }
18410
18754
  })),
@@ -18552,22 +18896,149 @@ function normalizePiModelCatalog(nativeModels, effectiveModel, thinkingLevels, e
18552
18896
  });
18553
18897
  }
18554
18898
 
18899
+ // dist/pi-progress.js
18900
+ import { createHash as createHash4 } from "node:crypto";
18901
+ function record4(value) {
18902
+ return typeof value === "object" && value !== null && !Array.isArray(value);
18903
+ }
18904
+ function textContent(content) {
18905
+ if (typeof content === "string")
18906
+ return content;
18907
+ if (!Array.isArray(content))
18908
+ return "";
18909
+ return content.filter((part) => record4(part) && part.type === "text" && typeof part.text === "string").map((part) => part.text).join("");
18910
+ }
18911
+ function boundedPiProgress(text3) {
18912
+ const limit = 64e3;
18913
+ return text3.length <= limit ? text3 : `${text3.slice(0, limit)}
18914
+ [Pi notification truncated]`;
18915
+ }
18916
+ function visibleText(text3) {
18917
+ return text3.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
18918
+ }
18919
+ function noticeDisplay(value, fallback) {
18920
+ if (!record4(value) || !record4(value.details) || typeof value.details.summary !== "string")
18921
+ return visibleText(fallback);
18922
+ const details = value.details;
18923
+ const parts = [visibleText(details.summary)];
18924
+ if (typeof details.exitCode === "number")
18925
+ parts.push(`Exit code: ${details.exitCode}`);
18926
+ for (const key of ["signal", "error", "errorMessage"])
18927
+ if (typeof details[key] === "string" && details[key])
18928
+ parts.push(`${key}: ${visibleText(details[key])}`);
18929
+ if (record4(details.logMatch) && typeof details.logMatch.line === "string")
18930
+ parts.push(`Log: ${visibleText(details.logMatch.line)}`);
18931
+ if (typeof details.command === "string" && details.command)
18932
+ parts.push(`Command: ${visibleText(details.command)}`);
18933
+ return parts.join("\n\n");
18934
+ }
18935
+ function piCustomNoticeKey(value) {
18936
+ if (!record4(value) || value.type !== "custom_message" && value.role !== "custom" || value.display !== true || typeof value.customType !== "string")
18937
+ return null;
18938
+ const text3 = textContent(value.content);
18939
+ if (text3.trim().length === 0)
18940
+ return null;
18941
+ return JSON.stringify([value.customType, text3]);
18942
+ }
18943
+ function piCustomNotice(value, sessionId, occurrences) {
18944
+ const key = piCustomNoticeKey(value);
18945
+ if (!key)
18946
+ return null;
18947
+ const occurrence = occurrences.get(key) ?? 0;
18948
+ occurrences.set(key, occurrence + 1);
18949
+ const digest = createHash4("sha256").update(JSON.stringify([sessionId, key, occurrence])).digest("hex");
18950
+ const [customType, text3] = JSON.parse(key);
18951
+ return {
18952
+ type: "progress.message",
18953
+ itemId: hostItemIdSchema.parse(`pi-notice-v1-${digest}`),
18954
+ text: boundedPiProgress(`Pi notification (${visibleText(customType)})
18955
+
18956
+ ${noticeDisplay(value, text3)}`)
18957
+ };
18958
+ }
18959
+ function piHistoryNotices(sessionId, entries) {
18960
+ const occurrences = /* @__PURE__ */ new Map();
18961
+ const notices = /* @__PURE__ */ new Map();
18962
+ for (const entry of entries) {
18963
+ const notice = piCustomNotice(entry.message ?? entry, sessionId, occurrences);
18964
+ if (notice)
18965
+ notices.set(entry.id, notice);
18966
+ }
18967
+ return { notices, occurrences };
18968
+ }
18969
+ function piStatusText(value) {
18970
+ if (value.type === "auto_retry_start") {
18971
+ const attempt = typeof value.attempt === "number" ? ` ${value.attempt}` : "";
18972
+ const maximum = typeof value.maxAttempts === "number" ? `/${value.maxAttempts}` : "";
18973
+ const delay2 = typeof value.delayMs === "number" && value.delayMs >= 0 ? ` Waiting ${value.delayMs / 1e3} s before retrying.` : "";
18974
+ const reason = typeof value.errorMessage === "string" ? `
18975
+
18976
+ ${visibleText(value.errorMessage)}` : "";
18977
+ return boundedPiProgress(`Pi retry${attempt}${maximum}.${delay2}${reason}`);
18978
+ }
18979
+ if (value.type === "auto_retry_end") {
18980
+ if (typeof value.success !== "boolean")
18981
+ return null;
18982
+ const reason = typeof value.finalError === "string" ? `
18983
+
18984
+ ${visibleText(value.finalError)}` : "";
18985
+ return boundedPiProgress(`Pi retry ${value.success ? "succeeded" : "ended without success"}.${reason}`);
18986
+ }
18987
+ if (value.type !== "extension_ui_request")
18988
+ return null;
18989
+ if (value.method === "notify" && typeof value.message === "string" && value.message.trim()) {
18990
+ const level = typeof value.notifyType === "string" ? ` (${value.notifyType})` : "";
18991
+ return boundedPiProgress(`Pi notification${level}
18992
+
18993
+ ${visibleText(value.message)}`);
18994
+ }
18995
+ if (value.method === "setStatus" && typeof value.statusKey === "string") {
18996
+ return typeof value.statusText === "string" && value.statusText.trim() ? boundedPiProgress(`Pi status (${visibleText(value.statusKey)})
18997
+
18998
+ ${visibleText(value.statusText)}`) : `Pi status (${visibleText(value.statusKey)}) cleared.`;
18999
+ }
19000
+ return null;
19001
+ }
19002
+
19003
+ // dist/pi-tool-command.js
19004
+ function record5(value) {
19005
+ return typeof value === "object" && value !== null && !Array.isArray(value);
19006
+ }
19007
+ function stringField(value, key) {
19008
+ if (!record5(value))
19009
+ return void 0;
19010
+ for (const source of [value, value.input, value.arguments]) {
19011
+ if (record5(source) && typeof source[key] === "string" && source[key].length > 0)
19012
+ return source[key];
19013
+ }
19014
+ return void 0;
19015
+ }
19016
+ function piToolCommand(name, arguments_) {
19017
+ if (!["bash", "exec", "terminal", "run"].includes(name.toLowerCase()))
19018
+ return null;
19019
+ const command = ["command", "cmd", "script", "commandLine", "command_line"].map((key) => stringField(arguments_, key)).find((value) => value !== void 0);
19020
+ if (!command)
19021
+ return null;
19022
+ const cwd = stringField(arguments_, "cwd");
19023
+ return { command, ...cwd ? { cwd } : {} };
19024
+ }
19025
+
18555
19026
  // dist/pi-history.js
18556
19027
  var piHarnessId = harnessIdSchema.parse("pi");
18557
- function isRecord4(value) {
19028
+ function isRecord5(value) {
18558
19029
  return typeof value === "object" && value !== null && !Array.isArray(value);
18559
19030
  }
18560
- function textContent(value) {
19031
+ function textContent2(value) {
18561
19032
  if (typeof value === "string")
18562
19033
  return value;
18563
19034
  if (!Array.isArray(value))
18564
19035
  return "";
18565
- return value.filter((part) => isRecord4(part) && part.type === "text" && typeof part.text === "string").map((part) => part.text).join("");
19036
+ return value.filter((part) => isRecord5(part) && part.type === "text" && typeof part.text === "string").map((part) => part.text).join("");
18566
19037
  }
18567
19038
  function thinkingContent(value) {
18568
19039
  if (!Array.isArray(value))
18569
19040
  return "";
18570
- return value.filter((part) => isRecord4(part) && part.type === "thinking" && typeof part.thinking === "string").map((part) => part.thinking).join("");
19041
+ return value.filter((part) => isRecord5(part) && part.type === "thinking" && typeof part.thinking === "string").map((part) => part.thinking).join("");
18571
19042
  }
18572
19043
  function validatedEntry(value) {
18573
19044
  if (typeof value.id !== "string" || value.id.length === 0 || value.parentId !== null && typeof value.parentId !== "string" || typeof value.type !== "string") {
@@ -18598,7 +19069,7 @@ function activePiEntries(history) {
18598
19069
  return reversed.reverse();
18599
19070
  }
18600
19071
  function message(entry) {
18601
- return entry.type === "message" && isRecord4(entry.message) ? entry.message : null;
19072
+ return entry.type === "message" && isRecord5(entry.message) ? entry.message : null;
18602
19073
  }
18603
19074
  function messageRole(entry) {
18604
19075
  const value = message(entry)?.role;
@@ -18613,7 +19084,7 @@ function assistantOutcome(entries) {
18613
19084
  if (!final)
18614
19085
  return { status: "unknown", reason: "Pi history has no Assistant terminal" };
18615
19086
  const stopReason = final.stopReason;
18616
- if (stopReason === "aborted") {
19087
+ if (piAssistantWasAborted(final)) {
18617
19088
  return { status: "cancelled", reason: "Pi Assistant was aborted" };
18618
19089
  }
18619
19090
  if (stopReason === "error") {
@@ -18626,7 +19097,7 @@ function assistantOutcome(entries) {
18626
19097
  }
18627
19098
  };
18628
19099
  }
18629
- if (typeof stopReason === "string" || textContent(final.content).length > 0) {
19100
+ if (typeof stopReason === "string" || textContent2(final.content).length > 0) {
18630
19101
  return { status: "succeeded" };
18631
19102
  }
18632
19103
  return { status: "unknown", reason: "Pi Assistant terminal is not classifiable" };
@@ -18643,8 +19114,8 @@ function itemOutcome(outcome) {
18643
19114
  return { status: "succeeded" };
18644
19115
  }
18645
19116
  function toolOutput(value) {
18646
- const text2 = textContent(value);
18647
- return text2.length > 0 ? { content: [{ type: "text", text: text2 }] } : void 0;
19117
+ const text3 = textContent2(value);
19118
+ return text3.length > 0 ? { content: [{ type: "text", text: text3 }] } : void 0;
18648
19119
  }
18649
19120
  function historicalFileChanges(call, nativeMessage, toolItemId, cwd) {
18650
19121
  const items = [];
@@ -18667,37 +19138,52 @@ function historicalFileChanges(call, nativeMessage, toolItemId, cwd) {
18667
19138
  }
18668
19139
  return items;
18669
19140
  }
18670
- function snapshotItems(entries, outcome, subagents, cwd) {
19141
+ function snapshotItems(entries, messageIdentities, notices, outcome, subagents, cwd) {
18671
19142
  const snapshots = [];
18672
19143
  const toolCalls = /* @__PURE__ */ new Map();
18673
19144
  for (const entry of entries) {
19145
+ const notice = notices.get(entry.id);
19146
+ if (notice) {
19147
+ snapshots.push({
19148
+ item: {
19149
+ type: "agentMessage",
19150
+ itemId: notice.itemId,
19151
+ text: notice.text,
19152
+ phase: "commentary"
19153
+ },
19154
+ outcome: { status: "succeeded" }
19155
+ });
19156
+ continue;
19157
+ }
18674
19158
  const nativeMessage = message(entry);
18675
19159
  if (!nativeMessage)
18676
19160
  continue;
18677
19161
  const content = Array.isArray(nativeMessage.content) ? nativeMessage.content : [];
18678
19162
  if (nativeMessage.role === "assistant") {
18679
- const text2 = textContent(content);
19163
+ const text3 = textContent2(content);
18680
19164
  const reasoning = thinkingContent(content);
18681
19165
  let projectedText = false;
18682
19166
  let projectedReasoning = false;
18683
19167
  for (const [ordinal, part] of content.entries()) {
18684
- if (!isRecord4(part))
19168
+ if (!isRecord5(part))
18685
19169
  continue;
18686
19170
  if (part.type === "thinking" && !projectedReasoning && reasoning.length > 0) {
18687
19171
  const item2 = {
18688
19172
  type: "reasoning",
18689
- itemId: itemId(entry.id, "reasoning", 0),
19173
+ itemId: piMessageItemId(messageIdentities.get(entry.id), "reasoning") ?? itemId(entry.id, "reasoning", 0),
18690
19174
  text: reasoning
18691
19175
  };
18692
19176
  snapshots.push({ item: item2, outcome: itemOutcome(outcome) });
18693
19177
  projectedReasoning = true;
18694
19178
  continue;
18695
19179
  }
18696
- if (part.type === "text" && !projectedText && text2.length > 0) {
19180
+ if (part.type === "text" && !projectedText && text3.length > 0) {
19181
+ const phase = piAssistantPhase(nativeMessage);
18697
19182
  const item2 = {
18698
19183
  type: "agentMessage",
18699
- itemId: itemId(entry.id, "assistant", 0),
18700
- text: text2
19184
+ itemId: piMessageItemId(messageIdentities.get(entry.id), "assistant") ?? itemId(entry.id, "assistant", 0),
19185
+ text: text3,
19186
+ ...phase ? { phase } : {}
18701
19187
  };
18702
19188
  snapshots.push({ item: item2, outcome: itemOutcome(outcome) });
18703
19189
  projectedText = true;
@@ -18725,9 +19211,24 @@ function snapshotItems(entries, outcome, subagents, cwd) {
18725
19211
  if (!call || call.name !== nativeMessage.toolName)
18726
19212
  continue;
18727
19213
  const output = toolOutput(nativeMessage.content);
18728
- const item = {
18729
- type: "toolExecution",
19214
+ const shell = piToolCommand(call.name, call.arguments);
19215
+ const commandCwd = shell?.cwd ?? cwd;
19216
+ const durationMs = typeof nativeMessage.durationMs === "number" && Number.isFinite(nativeMessage.durationMs) && nativeMessage.durationMs >= 0 ? nativeMessage.durationMs : void 0;
19217
+ const base = {
18730
19218
  itemId: itemId(call.entryId, "tool", call.ordinal),
19219
+ ...durationMs !== void 0 ? { durationMs } : {}
19220
+ };
19221
+ const exitCode = typeof nativeMessage.exitCode === "number" && Number.isInteger(nativeMessage.exitCode) ? nativeMessage.exitCode : void 0;
19222
+ const item = shell ? {
19223
+ ...base,
19224
+ type: "commandExecution",
19225
+ command: shell.command,
19226
+ ...commandCwd ? { cwd: commandCwd } : {},
19227
+ ...output ? { output: textContent2(nativeMessage.content) } : {},
19228
+ ...exitCode !== void 0 ? { exitCode } : {}
19229
+ } : {
19230
+ ...base,
19231
+ type: "toolExecution",
18731
19232
  toolName: call.name,
18732
19233
  arguments: call.arguments,
18733
19234
  ...output ? { output } : {}
@@ -18758,6 +19259,10 @@ function snapshotItems(entries, outcome, subagents, cwd) {
18758
19259
  function modelChange(entry) {
18759
19260
  return entry.type === "model_change" && typeof entry.provider === "string" && typeof entry.modelId === "string" ? { provider: entry.provider, id: entry.modelId } : null;
18760
19261
  }
19262
+ function isEmptyWakeup(entry) {
19263
+ const content = message(entry)?.content;
19264
+ return content === "" || Array.isArray(content) && content.every((part) => isRecord5(part) && part.type === "text" && part.text === "");
19265
+ }
18761
19266
  function turnStarts(active) {
18762
19267
  const starts = [];
18763
19268
  let terminal = true;
@@ -18765,6 +19270,8 @@ function turnStarts(active) {
18765
19270
  for (const [index, entry] of active.entries()) {
18766
19271
  const role = messageRole(entry);
18767
19272
  if (role === "user") {
19273
+ if (pending && isEmptyWakeup(entry))
19274
+ continue;
18768
19275
  starts.push({ entry, index });
18769
19276
  pending = null;
18770
19277
  terminal = false;
@@ -18781,6 +19288,8 @@ function turnStarts(active) {
18781
19288
  }
18782
19289
  function mapPiSnapshot(history, state2, subagents = new PiSubagents(() => void 0)) {
18783
19290
  const active = activePiEntries(history);
19291
+ const { identities } = piHistoryMessageIdentities(state2.sessionId, active);
19292
+ const { notices } = piHistoryNotices(state2.sessionId, active);
18784
19293
  const turns = [];
18785
19294
  const starts = turnStarts(active);
18786
19295
  const byIndex = new Map(starts.map((start, ordinal) => [start.index, ordinal]));
@@ -18802,7 +19311,7 @@ function mapPiSnapshot(history, state2, subagents = new PiSubagents(() => void 0
18802
19311
  const end = next?.index ?? active.length;
18803
19312
  const entries = active.slice(index, end);
18804
19313
  const outcome = assistantOutcome(entries);
18805
- const userText = textContent(message(user)?.content);
19314
+ const userText = textContent2(message(user)?.content);
18806
19315
  const nativeTurnRef = nativeTurnRefSchema.parse({
18807
19316
  harnessId: piHarnessId,
18808
19317
  nativeSessionId: state2.sessionId,
@@ -18819,7 +19328,7 @@ function mapPiSnapshot(history, state2, subagents = new PiSubagents(() => void 0
18819
19328
  nativeTurnRef,
18820
19329
  ...!next || messageRole(next.entry) === "user" ? { checkpoint } : {},
18821
19330
  input: messageRole(user) === "user" ? [{ type: "text", text: userText }] : [],
18822
- items: snapshotItems(entries, outcome, subagents, state2.cwd),
19331
+ items: snapshotItems(entries, identities, notices, outcome, subagents, state2.cwd),
18823
19332
  outcome,
18824
19333
  ...effectiveModel ? { model: encodePiModelRef(effectiveModel) } : {}
18825
19334
  });
@@ -18854,14 +19363,14 @@ function resolvePiForkBoundary(history, checkpointId) {
18854
19363
  }
18855
19364
 
18856
19365
  // dist/pi-usage.js
18857
- function isRecord5(value) {
19366
+ function isRecord6(value) {
18858
19367
  return typeof value === "object" && value !== null && !Array.isArray(value);
18859
19368
  }
18860
19369
  function nonNegativeSafeInteger(value) {
18861
19370
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
18862
19371
  }
18863
19372
  function optionalPiCacheHitRatePercent(value) {
18864
- if (!isRecord5(value) || value.role !== "assistant" || !isRecord5(value.usage))
19373
+ if (!isRecord6(value) || value.role !== "assistant" || !isRecord6(value.usage))
18865
19374
  return null;
18866
19375
  const input = nonNegativeSafeInteger(value.usage.input);
18867
19376
  const cacheRead = nonNegativeSafeInteger(value.usage.cacheRead);
@@ -18874,20 +19383,20 @@ function optionalPiCacheHitRatePercent(value) {
18874
19383
  function latestPiCacheHitRatePercent(history) {
18875
19384
  let latest = null;
18876
19385
  for (const entry of activePiEntries(history)) {
18877
- if (entry.type === "message" && isRecord5(entry.message) && entry.message.role === "assistant") {
19386
+ if (entry.type === "message" && isRecord6(entry.message) && entry.message.role === "assistant") {
18878
19387
  latest = optionalPiCacheHitRatePercent(entry.message);
18879
19388
  }
18880
19389
  }
18881
19390
  return latest;
18882
19391
  }
18883
19392
  function responseData(response, operation) {
18884
- if (!isRecord5(response.data)) {
19393
+ if (!isRecord6(response.data)) {
18885
19394
  throw new Error(`Pi RPC ${operation} response has no data`);
18886
19395
  }
18887
19396
  return response.data;
18888
19397
  }
18889
19398
  function contextUsage(value) {
18890
- if (!isRecord5(value))
19399
+ if (!isRecord6(value))
18891
19400
  throw new Error("Pi RPC context Usage is invalid");
18892
19401
  return parseHostUsage({
18893
19402
  contextUsedTokens: value.tokens,
@@ -18897,15 +19406,15 @@ function contextUsage(value) {
18897
19406
  function parsePiSessionUsage(response) {
18898
19407
  const data = responseData(response, "Session stats");
18899
19408
  const tokens = data.tokens;
18900
- if (tokens !== void 0 && !isRecord5(tokens)) {
19409
+ if (tokens !== void 0 && !isRecord6(tokens)) {
18901
19410
  throw new Error("Pi RPC Session stats tokens are invalid");
18902
19411
  }
18903
19412
  return parseHostUsage({
18904
- ...isRecord5(tokens) && tokens.input !== void 0 ? { inputTokens: tokens.input } : {},
18905
- ...isRecord5(tokens) && tokens.cacheRead !== void 0 ? { cachedInputTokens: tokens.cacheRead } : {},
18906
- ...isRecord5(tokens) && tokens.cacheWrite !== void 0 ? { cacheWriteInputTokens: tokens.cacheWrite } : {},
18907
- ...isRecord5(tokens) && tokens.output !== void 0 ? { outputTokens: tokens.output } : {},
18908
- ...isRecord5(tokens) && tokens.total !== void 0 ? { totalTokens: tokens.total } : {},
19413
+ ...isRecord6(tokens) && tokens.input !== void 0 ? { inputTokens: tokens.input } : {},
19414
+ ...isRecord6(tokens) && tokens.cacheRead !== void 0 ? { cachedInputTokens: tokens.cacheRead } : {},
19415
+ ...isRecord6(tokens) && tokens.cacheWrite !== void 0 ? { cacheWriteInputTokens: tokens.cacheWrite } : {},
19416
+ ...isRecord6(tokens) && tokens.output !== void 0 ? { outputTokens: tokens.output } : {},
19417
+ ...isRecord6(tokens) && tokens.total !== void 0 ? { totalTokens: tokens.total } : {},
18909
19418
  ...data.cost !== void 0 ? { totalCostUsd: data.cost } : {},
18910
19419
  ...data.contextUsage !== void 0 ? contextUsage(data.contextUsage) : {}
18911
19420
  });
@@ -18924,9 +19433,9 @@ function optionalPiStateContextUsage(value) {
18924
19433
  }
18925
19434
  }
18926
19435
  function piUsageRecord(message3, extra = {}) {
18927
- if (!isRecord5(message3) || message3.role !== "assistant")
19436
+ if (!isRecord6(message3) || message3.role !== "assistant")
18928
19437
  return null;
18929
- const usage = isRecord5(message3.usage) ? message3.usage : null;
19438
+ const usage = isRecord6(message3.usage) ? message3.usage : null;
18930
19439
  const input = nonNegativeSafeInteger(usage?.input);
18931
19440
  const output = nonNegativeSafeInteger(usage?.output);
18932
19441
  const requestId = typeof message3.responseId === "string" && message3.responseId.length > 0 ? message3.responseId : typeof message3.timestamp === "number" && Number.isSafeInteger(message3.timestamp) ? `t${message3.timestamp}` : null;
@@ -18963,17 +19472,17 @@ function piUsageHistory(history) {
18963
19472
  for (const entry of history.entries) {
18964
19473
  if (entry.type !== "message")
18965
19474
  continue;
18966
- const record7 = piUsageRecord(entry.message, { historical: true });
18967
- if (record7?.kind === "request")
18968
- requests.push(record7.request);
18969
- else if (record7?.kind === "missing")
19475
+ const record9 = piUsageRecord(entry.message, { historical: true });
19476
+ if (record9?.kind === "request")
19477
+ requests.push(record9.request);
19478
+ else if (record9?.kind === "missing")
18970
19479
  complete = false;
18971
19480
  }
18972
19481
  return { requests, complete };
18973
19482
  }
18974
19483
 
18975
19484
  // dist/pi-usage-statistics.js
18976
- function isRecord6(value) {
19485
+ function isRecord7(value) {
18977
19486
  return typeof value === "object" && value !== null && !Array.isArray(value);
18978
19487
  }
18979
19488
  function piUserText(content) {
@@ -18981,11 +19490,11 @@ function piUserText(content) {
18981
19490
  return content;
18982
19491
  if (!Array.isArray(content))
18983
19492
  return void 0;
18984
- return content.filter((block) => isRecord6(block) && block.type === "text" && typeof block.text === "string").map((block) => String(block.text)).join(" ");
19493
+ return content.filter((block) => isRecord7(block) && block.type === "text" && typeof block.text === "string").map((block) => String(block.text)).join(" ");
18985
19494
  }
18986
19495
  async function readPiUsage(file2, signal) {
18987
19496
  const entries = [];
18988
- const header = await jsonlHeader(file2, (record7) => record7.type === "session", signal);
19497
+ const header = await jsonlHeader(file2, (record9) => record9.type === "session", signal);
18989
19498
  let name;
18990
19499
  const session = {
18991
19500
  sessionId: typeof header?.id === "string" ? header.id : void 0,
@@ -19002,11 +19511,11 @@ async function readPiUsage(file2, signal) {
19002
19511
  if (!name && message3?.role === "user") {
19003
19512
  name = usageSessionTitle(piUserText(message3.content));
19004
19513
  }
19005
- const record7 = piUsageRecord(line.message);
19006
- if (record7?.kind !== "request")
19514
+ const record9 = piUsageRecord(line.message);
19515
+ if (record9?.kind !== "request")
19007
19516
  continue;
19008
19517
  const at = nativeTimeMs(message3.timestamp) ?? nativeTimeMs(line.timestamp);
19009
- const entry = at !== null && usageEntryFromRequest(record7.request, at);
19518
+ const entry = at !== null && usageEntryFromRequest(record9.request, at);
19010
19519
  if (!entry)
19011
19520
  continue;
19012
19521
  if (!(typeof message3.responseId === "string" && message3.responseId.length > 0)) {
@@ -19027,9 +19536,9 @@ function createPiUsageStatistics(environment) {
19027
19536
  }
19028
19537
 
19029
19538
  // dist/account-balance.js
19030
- import { readFile } from "node:fs/promises";
19031
- import { homedir as homedir2 } from "node:os";
19032
- import path7 from "node:path";
19539
+ import { readFile as readFile2 } from "node:fs/promises";
19540
+ import { homedir as homedir3 } from "node:os";
19541
+ import path8 from "node:path";
19033
19542
  var DEEPSEEK_BALANCE_ENDPOINT = "https://api.deepseek.com/user/balance";
19034
19543
  var SUB2API_USAGE_PATH = "/v1/usage";
19035
19544
  var REQUEST_TIMEOUT_MS = 1e4;
@@ -19038,18 +19547,18 @@ function agentDirectory(environment) {
19038
19547
  const configured = environment.PI_CODING_AGENT_DIR?.trim();
19039
19548
  if (configured)
19040
19549
  return configured;
19041
- return path7.join(environment.HOME ?? environment.USERPROFILE ?? homedir2(), ".pi", "agent");
19550
+ return path8.join(environment.HOME ?? environment.USERPROFILE ?? homedir3(), ".pi", "agent");
19042
19551
  }
19043
- var record4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
19552
+ var record6 = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
19044
19553
  async function deepSeekApiKey(environment) {
19045
- const auth = record4(JSON.parse(await readFile(path7.join(agentDirectory(environment), "auth.json"), "utf8")));
19046
- const deepseek = record4(auth.deepseek);
19554
+ const auth = record6(JSON.parse(await readFile2(path8.join(agentDirectory(environment), "auth.json"), "utf8")));
19555
+ const deepseek = record6(auth.deepseek);
19047
19556
  if (deepseek.type !== "api_key")
19048
19557
  return void 0;
19049
19558
  return typeof deepseek.key === "string" && deepseek.key.trim() ? deepseek.key : void 0;
19050
19559
  }
19051
19560
  function projectSub2ApiUsage(payload, providerId) {
19052
- const data = record4(payload);
19561
+ const data = record6(payload);
19053
19562
  if (data.isValid === false)
19054
19563
  return null;
19055
19564
  if (data.mode !== "unrestricted" && data.mode !== "quota_limited")
@@ -19059,7 +19568,7 @@ function projectSub2ApiUsage(payload, providerId) {
19059
19568
  return null;
19060
19569
  const wallet = finiteAmount(data.balance);
19061
19570
  const remaining = finiteAmount(data.remaining);
19062
- const quotaRemaining = finiteAmount(record4(data.quota).remaining);
19571
+ const quotaRemaining = finiteAmount(record6(data.quota).remaining);
19063
19572
  const amount = wallet ?? remaining ?? quotaRemaining;
19064
19573
  if (amount === null)
19065
19574
  return null;
@@ -19079,10 +19588,10 @@ function finiteAmount(value) {
19079
19588
  return Number.isFinite(amount) && amount >= 0 ? amount : null;
19080
19589
  }
19081
19590
  function projectDeepSeekBalance(payload) {
19082
- const data = record4(payload);
19591
+ const data = record6(payload);
19083
19592
  if (!Array.isArray(data.balance_infos))
19084
19593
  return null;
19085
- const first = record4(data.balance_infos[0]);
19594
+ const first = record6(data.balance_infos[0]);
19086
19595
  const amount = finiteAmount(first.total_balance);
19087
19596
  const currency = typeof first.currency === "string" ? first.currency.trim() : "";
19088
19597
  if (amount === null || !currency)
@@ -19111,11 +19620,11 @@ function usageEndpoint(baseUrl) {
19111
19620
  }
19112
19621
  async function configuredSub2ApiProviders(environment) {
19113
19622
  try {
19114
- const models = record4(JSON.parse(await readFile(path7.join(agentDirectory(environment), "models.json"), "utf8")));
19115
- const providers = record4(models.providers);
19623
+ const models = record6(JSON.parse(await readFile2(path8.join(agentDirectory(environment), "models.json"), "utf8")));
19624
+ const providers = record6(models.providers);
19116
19625
  const found = [];
19117
19626
  for (const [id, definition] of Object.entries(providers)) {
19118
- const provider = record4(definition);
19627
+ const provider = record6(definition);
19119
19628
  const apiKey = typeof provider.apiKey === "string" ? provider.apiKey.trim() : "";
19120
19629
  const baseUrl = typeof provider.baseUrl === "string" ? provider.baseUrl.trim() : "";
19121
19630
  if (!id.trim() || id.length > 128 || !apiKey || !usageEndpoint(baseUrl))
@@ -19173,21 +19682,21 @@ async function fetchPiAccountBalance(input) {
19173
19682
  }
19174
19683
 
19175
19684
  // dist/pi-credential-imports.js
19176
- import { randomUUID } from "node:crypto";
19685
+ import { randomUUID as randomUUID2 } from "node:crypto";
19177
19686
  import { execFile as execFile2 } from "node:child_process";
19178
19687
  import { promisify } from "node:util";
19179
19688
  import { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync, readdirSync, lstatSync, renameSync, rmdirSync } from "node:fs";
19180
19689
  import { realpath as realpath2 } from "node:fs/promises";
19181
19690
  import os4 from "node:os";
19182
- import path9 from "node:path";
19691
+ import path10 from "node:path";
19183
19692
  import { pathToFileURL } from "node:url";
19184
19693
 
19185
19694
  // dist/command.js
19186
19695
  import fs2 from "node:fs";
19187
- import { homedir as homedir3, tmpdir as tmpdir2 } from "node:os";
19188
- import path8 from "node:path";
19696
+ import { homedir as homedir4, tmpdir as tmpdir2 } from "node:os";
19697
+ import path9 from "node:path";
19189
19698
  var PI_PACKAGE_NAME = "@earendil-works/pi-coding-agent";
19190
- var PI_PACKAGE_PATH = path8.join("node_modules", "@earendil-works", "pi-coding-agent");
19699
+ var PI_PACKAGE_PATH = path9.join("node_modules", "@earendil-works", "pi-coding-agent");
19191
19700
  var piDiscoverySpec = {
19192
19701
  id: "pi",
19193
19702
  command: "pi",
@@ -19213,18 +19722,18 @@ function resolvePiExecutable(input, dependencies = {}) {
19213
19722
  return resolution?.executable ?? input.command ?? input.environment.PI_COMMAND ?? "pi";
19214
19723
  }
19215
19724
  function findPiPackageDirectory(executable) {
19216
- let directory = path8.dirname(executable);
19725
+ let directory = path9.dirname(executable);
19217
19726
  while (true) {
19218
- for (const candidate of [directory, path8.join(directory, PI_PACKAGE_PATH)]) {
19727
+ for (const candidate of [directory, path9.join(directory, PI_PACKAGE_PATH)]) {
19219
19728
  try {
19220
- const manifest = JSON.parse(fs2.readFileSync(path8.join(candidate, "package.json"), "utf8"));
19729
+ const manifest = JSON.parse(fs2.readFileSync(path9.join(candidate, "package.json"), "utf8"));
19221
19730
  if (typeof manifest === "object" && manifest !== null && "name" in manifest && manifest.name === PI_PACKAGE_NAME) {
19222
19731
  return candidate;
19223
19732
  }
19224
19733
  } catch {
19225
19734
  }
19226
19735
  }
19227
- const parent = path8.dirname(directory);
19736
+ const parent = path9.dirname(directory);
19228
19737
  if (parent === directory)
19229
19738
  return void 0;
19230
19739
  directory = parent;
@@ -19232,16 +19741,16 @@ function findPiPackageDirectory(executable) {
19232
19741
  }
19233
19742
  function findPiCliEntry(packageDirectory) {
19234
19743
  try {
19235
- const manifest = JSON.parse(fs2.readFileSync(path8.join(packageDirectory, "package.json"), "utf8"));
19744
+ const manifest = JSON.parse(fs2.readFileSync(path9.join(packageDirectory, "package.json"), "utf8"));
19236
19745
  if (typeof manifest !== "object" || manifest === null || !("bin" in manifest))
19237
19746
  return void 0;
19238
19747
  const bin = manifest.bin;
19239
19748
  const entry = typeof bin === "string" ? bin : typeof bin === "object" && bin !== null && "pi" in bin ? bin.pi : void 0;
19240
19749
  if (typeof entry !== "string" || !entry.trim())
19241
19750
  return void 0;
19242
- const resolved = path8.resolve(packageDirectory, entry);
19243
- const relative = path8.relative(packageDirectory, resolved);
19244
- if (relative === ".." || relative.startsWith(`..${path8.sep}`) || path8.isAbsolute(relative) || !fs2.statSync(resolved).isFile()) {
19751
+ const resolved = path9.resolve(packageDirectory, entry);
19752
+ const relative = path9.relative(packageDirectory, resolved);
19753
+ if (relative === ".." || relative.startsWith(`..${path9.sep}`) || path9.isAbsolute(relative) || !fs2.statSync(resolved).isFile()) {
19245
19754
  return void 0;
19246
19755
  }
19247
19756
  return resolved;
@@ -19250,11 +19759,11 @@ function findPiCliEntry(packageDirectory) {
19250
19759
  }
19251
19760
  }
19252
19761
  function isFilesystemRoot(cwd) {
19253
- const resolved = path8.resolve(cwd);
19254
- return resolved === path8.parse(resolved).root;
19762
+ const resolved = path9.resolve(cwd);
19763
+ return resolved === path9.parse(resolved).root;
19255
19764
  }
19256
19765
  function writableDirectory(candidate) {
19257
- if (!candidate || !path8.isAbsolute(candidate) || isFilesystemRoot(candidate))
19766
+ if (!candidate || !path9.isAbsolute(candidate) || isFilesystemRoot(candidate))
19258
19767
  return void 0;
19259
19768
  try {
19260
19769
  if (!fs2.statSync(candidate).isDirectory())
@@ -19267,19 +19776,19 @@ function writableDirectory(candidate) {
19267
19776
  }
19268
19777
  function resolvePiInspectCwd(inputCwd, environment = process.env) {
19269
19778
  if (typeof inputCwd === "string" && inputCwd.length > 0 && !isFilesystemRoot(inputCwd)) {
19270
- return path8.resolve(inputCwd);
19779
+ return path9.resolve(inputCwd);
19271
19780
  }
19272
- const candidates = [environment.USERPROFILE, environment.HOME, homedir3(), tmpdir2()];
19781
+ const candidates = [environment.USERPROFILE, environment.HOME, homedir4(), tmpdir2()];
19273
19782
  for (const candidate of candidates) {
19274
19783
  const usable = writableDirectory(candidate);
19275
19784
  if (usable)
19276
19785
  return usable;
19277
19786
  }
19278
- return inputCwd && inputCwd.length > 0 ? path8.resolve(inputCwd) : process.cwd();
19787
+ return inputCwd && inputCwd.length > 0 ? path9.resolve(inputCwd) : process.cwd();
19279
19788
  }
19280
19789
 
19281
19790
  // dist/pi-credential-imports.js
19282
- var PREFIX2 = "codexhost-account-";
19791
+ var PREFIX3 = "codexhost-account-";
19283
19792
  function object2(value) {
19284
19793
  return typeof value === "object" && value !== null && !Array.isArray(value);
19285
19794
  }
@@ -19320,7 +19829,7 @@ function describeOauth(credential) {
19320
19829
  };
19321
19830
  }
19322
19831
  function writeAuth(filename, content) {
19323
- const temporary = `${filename}.${randomUUID()}.tmp`;
19832
+ const temporary = `${filename}.${randomUUID2()}.tmp`;
19324
19833
  try {
19325
19834
  writeFileSync(temporary, content, { flag: "wx", mode: 384 });
19326
19835
  renameSync(temporary, filename);
@@ -19329,8 +19838,8 @@ function writeAuth(filename, content) {
19329
19838
  }
19330
19839
  }
19331
19840
  function removeOwnedFiles(dir) {
19332
- rmSync(path9.join(dir, "index.ts"), { force: true });
19333
- rmSync(path9.join(dir, "import.json"), { force: true });
19841
+ rmSync(path10.join(dir, "index.ts"), { force: true });
19842
+ rmSync(path10.join(dir, "import.json"), { force: true });
19334
19843
  try {
19335
19844
  rmdirSync(dir);
19336
19845
  } catch {
@@ -19342,13 +19851,13 @@ async function installation(command, environment, authPath) {
19342
19851
  const cliEntry = directory ? findPiCliEntry(directory) : void 0;
19343
19852
  if (!directory || !cliEntry)
19344
19853
  throw new Error("Pi credential import requires a supported npm Pi installation");
19345
- const storage = await import(pathToFileURL(path9.join(directory, "dist/core/auth-storage.js")).href);
19346
- const ai = path9.join(directory, "node_modules/@earendil-works/pi-ai/dist");
19347
- const all = await import(pathToFileURL(path9.join(ai, "providers/all.js")).href);
19854
+ const storage = await import(pathToFileURL(path10.join(directory, "dist/core/auth-storage.js")).href);
19855
+ const ai = path10.join(directory, "node_modules/@earendil-works/pi-ai/dist");
19856
+ const all = await import(pathToFileURL(path10.join(ai, "providers/all.js")).href);
19348
19857
  const providers = all.getBuiltinProviders();
19349
19858
  const providerModules = {
19350
- "openai-codex": pathToFileURL(path9.join(ai, "providers/openai-codex.js")).href,
19351
- xai: pathToFileURL(path9.join(ai, "providers/xai.js")).href
19859
+ "openai-codex": pathToFileURL(path10.join(ai, "providers/openai-codex.js")).href,
19860
+ xai: pathToFileURL(path10.join(ai, "providers/xai.js")).href
19352
19861
  };
19353
19862
  for (const [id, url2] of Object.entries(providerModules)) {
19354
19863
  const module = await import(url2);
@@ -19362,8 +19871,8 @@ async function installation(command, environment, authPath) {
19362
19871
  reservedNames: providers.map((p) => typeof p === "string" ? p : p.id),
19363
19872
  async configuredProviderNames() {
19364
19873
  const { stdout } = await promisify(execFile2)(process.execPath, [cliEntry, "--offline", "--no-approve", "--list-models"], {
19365
- cwd: existsSync(path9.dirname(authPath)) ? path9.dirname(authPath) : os4.homedir(),
19366
- env: { ...environment, PI_CODING_AGENT_DIR: path9.dirname(authPath), PI_OFFLINE: "1" },
19874
+ cwd: existsSync(path10.dirname(authPath)) ? path10.dirname(authPath) : os4.homedir(),
19875
+ env: { ...environment, PI_CODING_AGENT_DIR: path10.dirname(authPath), PI_OFFLINE: "1" },
19367
19876
  timeout: 15e3,
19368
19877
  maxBuffer: 4 * 1024 * 1024
19369
19878
  });
@@ -19393,26 +19902,26 @@ export default async function (pi) {
19393
19902
  }
19394
19903
  function createPiCredentialImports(options = {}) {
19395
19904
  const env = { ...process.env, ...options.environment };
19396
- const agentDir = env.PI_CODING_AGENT_DIR ?? path9.join(env.HOME ?? os4.homedir(), ".pi/agent");
19397
- const authPath = path9.join(agentDir, "auth.json");
19398
- const extensionsDir = path9.join(agentDir, "extensions");
19905
+ const agentDir = env.PI_CODING_AGENT_DIR ?? path10.join(env.HOME ?? os4.homedir(), ".pi/agent");
19906
+ const authPath = path10.join(agentDir, "auth.json");
19907
+ const extensionsDir = path10.join(agentDir, "extensions");
19399
19908
  const saveAuth = (auth) => (options.writeAuth ?? writeAuth)(authPath, JSON.stringify(auth, null, 2) + "\n");
19400
19909
  const resolve = () => options.resolveInstallation?.(authPath) ?? installation(options.command, env, authPath);
19401
- const location = (name) => path9.join(extensionsDir, `${PREFIX2}${credentialImportNameSchema.parse(name)}`);
19910
+ const location = (name) => path10.join(extensionsDir, `${PREFIX3}${credentialImportNameSchema.parse(name)}`);
19402
19911
  const readRecord = (name) => {
19403
19912
  const dir = location(name);
19404
19913
  if (lstatSync(dir).isSymbolicLink())
19405
19914
  throw new Error("Imported configuration was changed; manage it in Pi");
19406
- const value = JSON.parse(readFileSync(path9.join(dir, "import.json"), "utf8"));
19915
+ const value = JSON.parse(readFileSync(path10.join(dir, "import.json"), "utf8"));
19407
19916
  if (value.version !== 1 || typeof value.owner !== "string" || typeof value.extension !== "string")
19408
19917
  throw new Error("Invalid import metadata");
19409
- const record7 = value.record;
19410
- if (!object2(record7))
19918
+ const record9 = value.record;
19919
+ if (!object2(record9))
19411
19920
  throw new Error("Invalid import metadata");
19412
19921
  value.record = credentialImportRecordSchema.parse({
19413
- name: record7.name,
19414
- source: record7.source,
19415
- importedAt: record7.importedAt
19922
+ name: record9.name,
19923
+ source: record9.source,
19924
+ importedAt: record9.importedAt
19416
19925
  });
19417
19926
  if (value.record.name !== name)
19418
19927
  throw new Error("Import identity mismatch");
@@ -19420,7 +19929,7 @@ function createPiCredentialImports(options = {}) {
19420
19929
  };
19421
19930
  const owned = (meta3, auth) => {
19422
19931
  const credential = auth[meta3.record.name];
19423
- const file2 = path9.join(location(meta3.record.name), "index.ts");
19932
+ const file2 = path10.join(location(meta3.record.name), "index.ts");
19424
19933
  return existsSync(file2) && !lstatSync(file2).isSymbolicLink() && readFileSync(file2, "utf8") === meta3.extension && object2(credential) && credential.type === "oauth" && credential.codexhostImportId === meta3.owner;
19425
19934
  };
19426
19935
  const readAuth = () => existsSync(authPath) ? parseAuth(readFileSync(authPath, "utf8")) : {};
@@ -19429,12 +19938,12 @@ function createPiCredentialImports(options = {}) {
19429
19938
  return [];
19430
19939
  const result = [];
19431
19940
  for (const entry of readdirSync(extensionsDir)) {
19432
- if (!entry.startsWith(PREFIX2))
19941
+ if (!entry.startsWith(PREFIX3))
19433
19942
  continue;
19434
- const name = entry.slice(PREFIX2.length);
19943
+ const name = entry.slice(PREFIX3.length);
19435
19944
  if (!credentialImportNameSchema.safeParse(name).success)
19436
19945
  continue;
19437
- if (!existsSync(path9.join(location(name), "import.json")))
19946
+ if (!existsSync(path10.join(location(name), "import.json")))
19438
19947
  continue;
19439
19948
  try {
19440
19949
  const meta3 = readRecord(name);
@@ -19455,7 +19964,7 @@ function createPiCredentialImports(options = {}) {
19455
19964
  },
19456
19965
  async listOthers() {
19457
19966
  const auth = readAuth();
19458
- const ours = new Set(ownedRecords(auth).map((record7) => record7.name));
19967
+ const ours = new Set(ownedRecords(auth).map((record9) => record9.name));
19459
19968
  const result = /* @__PURE__ */ new Map();
19460
19969
  const usable = (provider) => Boolean(provider) && provider.length <= 128 && !ours.has(provider) && !result.has(provider);
19461
19970
  for (const [provider, credential] of Object.entries(auth)) {
@@ -19468,7 +19977,7 @@ function createPiCredentialImports(options = {}) {
19468
19977
  ...describeOauth(credential)
19469
19978
  });
19470
19979
  }
19471
- const modelsPath = path9.join(agentDir, "models.json");
19980
+ const modelsPath = path10.join(agentDir, "models.json");
19472
19981
  if (existsSync(modelsPath)) {
19473
19982
  const models = JSON.parse(readFileSync(modelsPath, "utf8"));
19474
19983
  const providers = object2(models) && object2(models.providers) ? models.providers : {};
@@ -19489,8 +19998,8 @@ function createPiCredentialImports(options = {}) {
19489
19998
  throw new Error("Unsupported credential source");
19490
19999
  if (sdk.reservedNames.includes(name) || (await sdk.configuredProviderNames?.())?.includes(name))
19491
20000
  throw new Error("Provider name already exists; choose another name");
19492
- const owner = randomUUID();
19493
- const record7 = credentialImportRecordSchema.parse({
20001
+ const owner = randomUUID2();
20002
+ const record9 = credentialImportRecordSchema.parse({
19494
20003
  name,
19495
20004
  source: transfer.source,
19496
20005
  importedAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -19502,15 +20011,15 @@ function createPiCredentialImports(options = {}) {
19502
20011
  try {
19503
20012
  sdk.backend.withLock((current) => {
19504
20013
  const auth = parseAuth(current);
19505
- const modelsPath = path9.join(agentDir, "models.json");
20014
+ const modelsPath = path10.join(agentDir, "models.json");
19506
20015
  const models = existsSync(modelsPath) ? JSON.parse(readFileSync(modelsPath, "utf8")) : {};
19507
- if (Object.hasOwn(auth, name) || Object.hasOwn(models.providers ?? {}, name) || existsSync(dir) || existsSync(path9.join(extensionsDir, `${name}-provider.ts`)))
20016
+ if (Object.hasOwn(auth, name) || Object.hasOwn(models.providers ?? {}, name) || existsSync(dir) || existsSync(path10.join(extensionsDir, `${name}-provider.ts`)))
19508
20017
  throw new Error("Provider name already exists; choose another name");
19509
20018
  mkdirSync(extensionsDir, { recursive: true, mode: 448 });
19510
20019
  mkdirSync(dir, { mode: 448 });
19511
20020
  created = true;
19512
- writeFileSync(path9.join(dir, "import.json"), JSON.stringify({ version: 1, owner, record: record7, extension }), { flag: "wx", mode: 384 });
19513
- writeFileSync(path9.join(dir, "index.ts"), extension, { flag: "wx", mode: 384 });
20021
+ writeFileSync(path10.join(dir, "import.json"), JSON.stringify({ version: 1, owner, record: record9, extension }), { flag: "wx", mode: 384 });
20022
+ writeFileSync(path10.join(dir, "index.ts"), extension, { flag: "wx", mode: 384 });
19514
20023
  auth[name] = { type: "oauth", ...transfer.oauth, codexhostImportId: owner };
19515
20024
  saveAuth(auth);
19516
20025
  committed = true;
@@ -19529,7 +20038,7 @@ function createPiCredentialImports(options = {}) {
19529
20038
  const auth = parseAuth(current);
19530
20039
  if (!owned(meta3, auth) || meta3.record.source.id !== transfer.source.id || meta3.record.source.provider !== transfer.source.provider)
19531
20040
  throw new Error("Import ownership or source account changed; refusing replacement");
19532
- const metadataPath = path9.join(location(name), "import.json");
20041
+ const metadataPath = path10.join(location(name), "import.json");
19533
20042
  const previous = readFileSync(metadataPath, "utf8");
19534
20043
  const updated = {
19535
20044
  ...meta3,
@@ -19564,10 +20073,10 @@ function createPiCredentialImports(options = {}) {
19564
20073
  }
19565
20074
 
19566
20075
  // dist/pi-fast-mode.js
19567
- import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto";
19568
- import { mkdir, readFile as readFile2, rename, rm as rm2, writeFile as writeFile2 } from "node:fs/promises";
19569
- import { homedir as homedir4 } from "node:os";
19570
- import path10 from "node:path";
20076
+ import { createHash as createHash5, randomUUID as randomUUID3 } from "node:crypto";
20077
+ import { mkdir as mkdir2, readFile as readFile3, rename as rename2, rm as rm3, writeFile as writeFile3 } from "node:fs/promises";
20078
+ import { homedir as homedir5 } from "node:os";
20079
+ import path11 from "node:path";
19571
20080
  var PI_FAST_COMMAND = "codexhost-fast-mode";
19572
20081
  var PI_FAST_ACK = "codexhost-fast-mode:";
19573
20082
  var PI_FAST_EXTENSION = `export default function(pi) {
@@ -19617,24 +20126,24 @@ var PI_FAST_EXTENSION = `export default function(pi) {
19617
20126
  }
19618
20127
  `;
19619
20128
  async function ensurePiFastExtension(environment) {
19620
- const digest = createHash2("sha256").update(PI_FAST_EXTENSION).digest("hex").slice(0, 16);
19621
- const dataDirectory = environment.CODEXHOST_DATA_DIR ?? path10.join(environment.HOME ?? environment.USERPROFILE ?? homedir4(), ".codexhost");
19622
- const directory = path10.resolve(dataDirectory, "extensions", "pi-codex-fast");
19623
- const file2 = path10.join(directory, `${digest}.mjs`);
19624
- if (await readFile2(file2, "utf8").catch(() => "") === PI_FAST_EXTENSION)
20129
+ const digest = createHash5("sha256").update(PI_FAST_EXTENSION).digest("hex").slice(0, 16);
20130
+ const dataDirectory = environment.CODEXHOST_DATA_DIR ?? path11.join(environment.HOME ?? environment.USERPROFILE ?? homedir5(), ".codexhost");
20131
+ const directory = path11.resolve(dataDirectory, "extensions", "pi-codex-fast");
20132
+ const file2 = path11.join(directory, `${digest}.mjs`);
20133
+ if (await readFile3(file2, "utf8").catch(() => "") === PI_FAST_EXTENSION)
19625
20134
  return file2;
19626
- await mkdir(directory, { recursive: true });
19627
- const temporary = `${file2}.${randomUUID2()}.tmp`;
20135
+ await mkdir2(directory, { recursive: true });
20136
+ const temporary = `${file2}.${randomUUID3()}.tmp`;
19628
20137
  try {
19629
- await writeFile2(temporary, PI_FAST_EXTENSION, { mode: 384 });
20138
+ await writeFile3(temporary, PI_FAST_EXTENSION, { mode: 384 });
19630
20139
  try {
19631
- await rename(temporary, file2);
20140
+ await rename2(temporary, file2);
19632
20141
  } catch (error51) {
19633
- if (await readFile2(file2, "utf8").catch(() => "") !== PI_FAST_EXTENSION)
20142
+ if (await readFile3(file2, "utf8").catch(() => "") !== PI_FAST_EXTENSION)
19634
20143
  throw error51;
19635
20144
  }
19636
20145
  } finally {
19637
- await rm2(temporary, { force: true });
20146
+ await rm3(temporary, { force: true });
19638
20147
  }
19639
20148
  return file2;
19640
20149
  }
@@ -19651,15 +20160,15 @@ function withPiFast(catalog, supported) {
19651
20160
  // dist/pi-empty-session.js
19652
20161
  import { createReadStream as createReadStream3 } from "node:fs";
19653
20162
  import { createInterface as createInterface3 } from "node:readline";
19654
- import { randomUUID as randomUUID3 } from "node:crypto";
19655
- import { link, open as open2, rm as rm3 } from "node:fs/promises";
19656
- import path11 from "node:path";
20163
+ import { randomUUID as randomUUID4 } from "node:crypto";
20164
+ import { link, open as open2, rm as rm4 } from "node:fs/promises";
20165
+ import path12 from "node:path";
19657
20166
 
19658
20167
  // dist/pi-session-file.js
19659
20168
  import { open, realpath as realpath3 } from "node:fs/promises";
19660
20169
  var MAX_SESSION_HEADER_BYTES = 64 * 1024;
19661
20170
  var utf8Decoder = new TextDecoder("utf-8", { fatal: true });
19662
- function isRecord7(value) {
20171
+ function isRecord8(value) {
19663
20172
  return typeof value === "object" && value !== null && !Array.isArray(value);
19664
20173
  }
19665
20174
  async function readPiSessionHeader(sessionFile) {
@@ -19679,7 +20188,7 @@ async function readPiSessionHeader(sessionFile) {
19679
20188
  } catch {
19680
20189
  throw new Error("Pi Session header is not valid JSON");
19681
20190
  }
19682
- if (!isRecord7(parsed) || parsed.type !== "session" || typeof parsed.id !== "string" || parsed.id.length === 0 || typeof parsed.cwd !== "string" || parsed.cwd.length === 0) {
20191
+ if (!isRecord8(parsed) || parsed.type !== "session" || typeof parsed.id !== "string" || parsed.id.length === 0 || typeof parsed.cwd !== "string" || parsed.cwd.length === 0) {
19683
20192
  throw new Error("Pi Session header is invalid");
19684
20193
  }
19685
20194
  return {
@@ -19712,7 +20221,7 @@ async function verifyPiSessionCwd(input) {
19712
20221
  async function persistEmptyPiSession(input) {
19713
20222
  const { state: state2, history, sourceSessionFile, sourceSessionId, cwd } = input;
19714
20223
  const destination = state2.sessionFile;
19715
- if (!destination || !path11.isAbsolute(destination) || path11.resolve(destination) === path11.resolve(sourceSessionFile) || state2.sessionId === sourceSessionId || mapPiSnapshot(history, { sessionId: state2.sessionId, model: null }).turns.length !== 0)
20224
+ if (!destination || !path12.isAbsolute(destination) || path12.resolve(destination) === path12.resolve(sourceSessionFile) || state2.sessionId === sourceSessionId || mapPiSnapshot(history, { sessionId: state2.sessionId, model: null }).turns.length !== 0)
19716
20225
  throw new Error("Pi empty Session is not an independent empty native fork");
19717
20226
  await verifyPiSessionCwd({
19718
20227
  sessionFile: sourceSessionFile,
@@ -19736,7 +20245,7 @@ async function persistEmptyPiSession(input) {
19736
20245
  cwd,
19737
20246
  parentSession: sourceSessionFile
19738
20247
  };
19739
- const temporary = path11.join(path11.dirname(destination), `.codexhost-${randomUUID3()}.tmp`);
20248
+ const temporary = path12.join(path12.dirname(destination), `.codexhost-${randomUUID4()}.tmp`);
19740
20249
  try {
19741
20250
  const file2 = await open2(temporary, "wx", 384);
19742
20251
  try {
@@ -19747,7 +20256,7 @@ async function persistEmptyPiSession(input) {
19747
20256
  }
19748
20257
  await link(temporary, destination);
19749
20258
  if (process.platform !== "win32") {
19750
- const directory = await open2(path11.dirname(destination), "r");
20259
+ const directory = await open2(path12.dirname(destination), "r");
19751
20260
  try {
19752
20261
  await directory.sync();
19753
20262
  } finally {
@@ -19755,7 +20264,7 @@ async function persistEmptyPiSession(input) {
19755
20264
  }
19756
20265
  }
19757
20266
  } finally {
19758
- await rm3(temporary, { force: true });
20267
+ await rm4(temporary, { force: true });
19759
20268
  }
19760
20269
  }
19761
20270
  async function readPiEmptySessionConfiguration(sessionFile) {
@@ -19811,20 +20320,20 @@ async function readPiEmptySessionConfiguration(sessionFile) {
19811
20320
  }
19812
20321
 
19813
20322
  // dist/pi-adapter.js
19814
- import { randomUUID as randomUUID6 } from "node:crypto";
19815
- import path15 from "node:path";
20323
+ import { randomUUID as randomUUID7 } from "node:crypto";
20324
+ import path16 from "node:path";
19816
20325
 
19817
20326
  // dist/pi-workflow-child-history.js
19818
- import { createHash as createHash3 } from "node:crypto";
20327
+ import { createHash as createHash6 } from "node:crypto";
19819
20328
  import { constants } from "node:fs";
19820
20329
  import { open as open3 } from "node:fs/promises";
19821
- import path12 from "node:path";
19822
- function record5(value) {
20330
+ import path13 from "node:path";
20331
+ function record7(value) {
19823
20332
  return typeof value === "object" && value !== null && !Array.isArray(value);
19824
20333
  }
19825
20334
  var MAX_SESSION_BYTES = 8 * 1024 * 1024;
19826
- async function childHistory(file2, parentSessionId, identity) {
19827
- if (!path12.isAbsolute(file2))
20335
+ async function childHistory(file2, parentSessionId, identity, validateParent = false) {
20336
+ if (!path13.isAbsolute(file2))
19828
20337
  throw new Error("Pi child Session path is not absolute");
19829
20338
  const handle = await open3(file2, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0));
19830
20339
  try {
@@ -19837,12 +20346,14 @@ async function childHistory(file2, parentSessionId, identity) {
19837
20346
  throw new Error("Pi child Session exceeds read bounds");
19838
20347
  const values = buffer.subarray(0, bytesRead).toString("utf8").split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
19839
20348
  const header = values[0];
19840
- if (!record5(header) || header.type !== "session" || typeof header.id !== "string" || header.version !== 3)
20349
+ if (!record7(header) || header.type !== "session" || typeof header.id !== "string" || header.version !== 3)
19841
20350
  throw new Error("Unsupported Pi child Session header");
20351
+ if (validateParent && header.parentSession !== parentSessionId)
20352
+ throw new Error("Pi child Session parent identity mismatch");
19842
20353
  const entries = [];
19843
20354
  for (const entry of values.slice(1)) {
19844
20355
  const parsed = jsonValueSchema.safeParse(entry);
19845
- if (!parsed.success || !record5(parsed.data) || typeof parsed.data.id !== "string")
20356
+ if (!parsed.success || !record7(parsed.data) || typeof parsed.data.id !== "string")
19846
20357
  throw new Error("Malformed Pi child Session entry");
19847
20358
  entries.push(parsed.data);
19848
20359
  }
@@ -19852,7 +20363,7 @@ async function childHistory(file2, parentSessionId, identity) {
19852
20363
  model: null,
19853
20364
  ...typeof header.cwd === "string" ? { cwd: header.cwd } : {}
19854
20365
  });
19855
- const prefix = createHash3("sha256").update(identity).digest("hex");
20366
+ const prefix = createHash6("sha256").update(identity).digest("hex");
19856
20367
  return {
19857
20368
  turns: snapshot.turns.map((turn) => {
19858
20369
  const readonlyTurn = {
@@ -19873,7 +20384,7 @@ async function childHistory(file2, parentSessionId, identity) {
19873
20384
  async function readPiWorkflowChild(history, parentSessionId, address) {
19874
20385
  for (const entry of activePiEntries(history).reverse()) {
19875
20386
  const message3 = entry.message;
19876
- if (!record5(message3) || message3.role !== "toolResult" || message3.toolName !== "subagent")
20387
+ if (!record7(message3) || message3.role !== "toolResult" || message3.toolName !== "subagent")
19877
20388
  continue;
19878
20389
  const summary = piWorkflowSummary(message3);
19879
20390
  if (!summary || summary.workflowRunId !== address.workflowRunId || summary.parentToolCallId !== message3.toolCallId)
@@ -19882,10 +20393,10 @@ async function readPiWorkflowChild(history, parentSessionId, address) {
19882
20393
  if (!child)
19883
20394
  break;
19884
20395
  const details = message3.details;
19885
- if (!record5(details) || !Array.isArray(details.results))
20396
+ if (!record7(details) || !Array.isArray(details.results))
19886
20397
  break;
19887
- const result = details.results.findLast((candidate) => record5(candidate) && candidate.workflowKey === address.childId);
19888
- if (!record5(result))
20398
+ const result = details.results.findLast((candidate) => record7(candidate) && candidate.workflowKey === address.childId);
20399
+ if (!record7(result))
19889
20400
  break;
19890
20401
  const id = piWorkflowSubagentId(address);
19891
20402
  if (typeof result.sessionFile === "string") {
@@ -19928,25 +20439,69 @@ ${output}`,
19928
20439
  };
19929
20440
  }
19930
20441
 
20442
+ // dist/pi-gotgenes-history.js
20443
+ function gotgenesHistory(history) {
20444
+ const records = /* @__PURE__ */ new Map();
20445
+ for (const entry of activePiEntries(history)) {
20446
+ const message3 = entry.message;
20447
+ const parsed = entry.type === "custom" && entry.customType === "subagents:record" ? gotgenesRecord(entry.data) : isRecord4(message3) && message3.role === "toolResult" && typeof message3.toolName === "string" ? gotgenesToolRecord(message3.toolName, message3) : null;
20448
+ if (!parsed)
20449
+ continue;
20450
+ records.set(parsed.id, mergeGotgenesRecord(records.get(parsed.id), parsed));
20451
+ }
20452
+ return [...records.values()];
20453
+ }
20454
+ function restoreGotgenes(history, observer) {
20455
+ observer.observe(gotgenesHistory(history), false);
20456
+ }
20457
+ async function readGotgenesChild(history, parentSessionId, id, live) {
20458
+ const saved = gotgenesHistory(history).find((entry) => entry.id === id);
20459
+ const record9 = live?.outputFile ? live : saved;
20460
+ if (!record9?.outputFile)
20461
+ return {
20462
+ ok: false,
20463
+ error: {
20464
+ code: "sessionNotFound",
20465
+ message: "Pi subagent has not published its Session transcript path",
20466
+ retryable: true
20467
+ }
20468
+ };
20469
+ try {
20470
+ return {
20471
+ ok: true,
20472
+ value: await childHistory(record9.outputFile, parentSessionId, gotgenesId(id), true)
20473
+ };
20474
+ } catch (error51) {
20475
+ return {
20476
+ ok: false,
20477
+ error: {
20478
+ code: "unavailable",
20479
+ message: error51 instanceof Error ? error51.message : "Pi child transcript unavailable",
20480
+ retryable: true
20481
+ }
20482
+ };
20483
+ }
20484
+ }
20485
+
19931
20486
  // dist/pi-subagent-history.js
19932
20487
  import { constants as constants2 } from "node:fs";
19933
20488
  import { open as open4 } from "node:fs/promises";
19934
- import path13 from "node:path";
19935
- function record6(value) {
20489
+ import path14 from "node:path";
20490
+ function record8(value) {
19936
20491
  return typeof value === "object" && value !== null && !Array.isArray(value);
19937
20492
  }
19938
20493
  function state(value) {
19939
20494
  return value === "pending" ? "queued" : value === "completed" ? "complete" : value;
19940
20495
  }
19941
20496
  function piSubagentArtifact(value, runId, parentSessionId) {
19942
- if (!record6(value) || value.lifecycleArtifactVersion !== 3 || value.runId !== runId || value.sessionId !== parentSessionId || !["single", "parallel", "chain", "workflow"].includes(String(value.mode)))
20497
+ if (!record8(value) || value.lifecycleArtifactVersion !== 3 || value.runId !== runId || value.sessionId !== parentSessionId || !["single", "parallel", "chain", "workflow"].includes(String(value.mode)))
19943
20498
  return null;
19944
20499
  if (value.steps !== void 0 && (!Array.isArray(value.steps) || value.steps.length > 128))
19945
20500
  return null;
19946
20501
  const steps = Array.isArray(value.steps) ? value.steps : [];
19947
20502
  const children = [];
19948
20503
  for (const [index, step] of steps.entries()) {
19949
- if (!record6(step) || typeof step.agent !== "string")
20504
+ if (!record8(step) || typeof step.agent !== "string")
19950
20505
  return null;
19951
20506
  children.push({
19952
20507
  id: step.workflowKey ?? step.runId ?? `step:${index}`,
@@ -19977,19 +20532,20 @@ function piSubagentArtifact(value, runId, parentSessionId) {
19977
20532
  });
19978
20533
  }
19979
20534
  async function restorePiSubagents(history, parentSessionId, observer) {
20535
+ restoreGotgenes(history, observer.gotgenes);
19980
20536
  const receipts = /* @__PURE__ */ new Map();
19981
20537
  for (const entry of activePiEntries(history)) {
19982
- if (!record6(entry.message) || entry.message.role !== "toolResult" || entry.message.toolName !== "subagent" || entry.message.isError !== false || !record6(entry.message.details))
20538
+ if (!record8(entry.message) || entry.message.role !== "toolResult" || entry.message.toolName !== "subagent" || entry.message.isError !== false || !record8(entry.message.details))
19983
20539
  continue;
19984
20540
  const details = entry.message.details;
19985
- if (!["single", "parallel", "chain", "workflow"].includes(String(details.mode)) || typeof details.asyncId !== "string" || typeof details.asyncDir !== "string" || !path13.isAbsolute(details.asyncDir) || path13.basename(details.asyncDir) !== details.asyncId)
20541
+ if (!["single", "parallel", "chain", "workflow"].includes(String(details.mode)) || typeof details.asyncId !== "string" || typeof details.asyncDir !== "string" || !path14.isAbsolute(details.asyncDir) || path14.basename(details.asyncDir) !== details.asyncId)
19986
20542
  continue;
19987
20543
  receipts.set(details.asyncId, details.asyncDir);
19988
20544
  }
19989
20545
  for (const [id, directory] of [...receipts].slice(-128)) {
19990
20546
  let file2;
19991
20547
  try {
19992
- file2 = await open4(path13.join(directory, "status.json"), constants2.O_RDONLY | (constants2.O_NOFOLLOW ?? 0));
20548
+ file2 = await open4(path14.join(directory, "status.json"), constants2.O_RDONLY | (constants2.O_NOFOLLOW ?? 0));
19993
20549
  const stat2 = await file2.stat();
19994
20550
  if (!stat2.isFile() || stat2.size > 1024 * 1024)
19995
20551
  continue;
@@ -20071,8 +20627,8 @@ async function rollbackPiLastTurn(transport, sourceSessionId, cwd) {
20071
20627
 
20072
20628
  // dist/pi-rpc-session.js
20073
20629
  import { spawn, spawnSync } from "node:child_process";
20074
- import { randomUUID as randomUUID5 } from "node:crypto";
20075
- import path14 from "node:path";
20630
+ import { randomUUID as randomUUID6 } from "node:crypto";
20631
+ import path15 from "node:path";
20076
20632
 
20077
20633
  // dist/pi-slash-commands.js
20078
20634
  var DYNAMIC_ID_PREFIX = "pi.slash.";
@@ -20094,15 +20650,15 @@ function parsePiNativeCommands(response) {
20094
20650
  return data.commands.flatMap((entry) => {
20095
20651
  if (typeof entry !== "object" || entry === null)
20096
20652
  return [];
20097
- const record7 = entry;
20098
- const name = typeof record7.name === "string" ? record7.name.trim().replace(/^\//u, "") : "";
20653
+ const record9 = entry;
20654
+ const name = typeof record9.name === "string" ? record9.name.trim().replace(/^\//u, "") : "";
20099
20655
  if (!name)
20100
20656
  return [];
20101
20657
  return [
20102
20658
  {
20103
20659
  name,
20104
- ...typeof record7.description === "string" ? { description: record7.description } : {},
20105
- ...typeof record7.source === "string" ? { source: record7.source } : {}
20660
+ ...typeof record9.description === "string" ? { description: record9.description } : {},
20661
+ ...typeof record9.source === "string" ? { source: record9.source } : {}
20106
20662
  }
20107
20663
  ];
20108
20664
  });
@@ -20118,8 +20674,97 @@ function piDynamicCommandPrompt(catalog, commandId, argumentText) {
20118
20674
  return liveHarnessCommandPrompt(catalog, DYNAMIC_ID_PREFIX, commandId, argumentText);
20119
20675
  }
20120
20676
 
20677
+ // dist/pi-content-stream.js
20678
+ var PiContentStreamConflictError = class extends Error {
20679
+ };
20680
+ var PiContentStream = class {
20681
+ kind;
20682
+ #blocks = /* @__PURE__ */ new Map();
20683
+ #indexed;
20684
+ #legacyBlockIndex = 0;
20685
+ #lastEmittedIndex = -Infinity;
20686
+ constructor(kind) {
20687
+ this.kind = kind;
20688
+ }
20689
+ append(index, delta) {
20690
+ const block = this.#block(this.#key(index));
20691
+ if (block.ended && delta.length > 0)
20692
+ this.#conflict();
20693
+ block.received += delta;
20694
+ return this.#flush();
20695
+ }
20696
+ complete(index, content) {
20697
+ this.#finish(this.#key(index), content);
20698
+ if (this.#indexed === false)
20699
+ this.#legacyBlockIndex += 1;
20700
+ return this.#flush();
20701
+ }
20702
+ finalize(blocks) {
20703
+ if (this.#indexed !== true) {
20704
+ blocks = this.#legacyBlockIndex > 0 ? blocks.map(({ text: text3 }, index) => ({ index, text: text3 })) : [{ index: 0, text: blocks.map(({ text: text3 }) => text3).join("") }];
20705
+ }
20706
+ const indices = new Set(blocks.map(({ index }) => index));
20707
+ for (const [index, block] of this.#blocks) {
20708
+ if (indices.has(index))
20709
+ continue;
20710
+ if (block.emitted.length > 0)
20711
+ this.#conflict();
20712
+ this.#blocks.delete(index);
20713
+ }
20714
+ for (const { index, text: text3 } of blocks)
20715
+ this.#finish(index, text3);
20716
+ return this.#flush();
20717
+ }
20718
+ #key(index) {
20719
+ const indexed = typeof index === "number" && Number.isInteger(index) && index >= 0;
20720
+ this.#indexed ??= indexed;
20721
+ if (!this.#indexed)
20722
+ return this.#legacyBlockIndex;
20723
+ if (!indexed)
20724
+ this.#conflict();
20725
+ return index;
20726
+ }
20727
+ #block(index) {
20728
+ let block = this.#blocks.get(index);
20729
+ if (!block) {
20730
+ block = { received: "", emitted: "", ended: false };
20731
+ this.#blocks.set(index, block);
20732
+ }
20733
+ return block;
20734
+ }
20735
+ #finish(index, content) {
20736
+ const block = this.#block(index);
20737
+ if (!content.startsWith(block.emitted))
20738
+ this.#conflict();
20739
+ block.received = content;
20740
+ block.ended = true;
20741
+ }
20742
+ #flush() {
20743
+ let delta = "";
20744
+ for (const [index, block] of [...this.#blocks].sort(([left], [right]) => left - right)) {
20745
+ const visible = this.kind === "reasoning" && !block.ended ? block.received.replace(/[\r\n]+$/u, "") : block.received;
20746
+ if (!visible.startsWith(block.emitted))
20747
+ this.#conflict();
20748
+ const suffix = visible.slice(block.emitted.length);
20749
+ if (suffix.length > 0) {
20750
+ if (index < this.#lastEmittedIndex)
20751
+ this.#conflict();
20752
+ this.#lastEmittedIndex = index;
20753
+ block.emitted = visible;
20754
+ delta += suffix;
20755
+ }
20756
+ if (!block.ended)
20757
+ break;
20758
+ }
20759
+ return delta;
20760
+ }
20761
+ #conflict() {
20762
+ throw new PiContentStreamConflictError(`Pi ${this.kind} final content conflicts with already streamed content`);
20763
+ }
20764
+ };
20765
+
20121
20766
  // dist/pi-subagent-rpc.js
20122
- import { randomUUID as randomUUID4 } from "node:crypto";
20767
+ import { randomUUID as randomUUID5 } from "node:crypto";
20123
20768
  var PiSubagentRpc = class {
20124
20769
  send;
20125
20770
  timeoutMs;
@@ -20161,7 +20806,7 @@ var PiSubagentRpc = class {
20161
20806
  if (!Array.isArray(data?.commands) || !data.commands.some((command) => command?.name === "subagents-inspect-rpc" && command.source === "extension")) {
20162
20807
  throw new Error("Installed Pi has no pi-subagents Host inspection command");
20163
20808
  }
20164
- const requestId = randomUUID4();
20809
+ const requestId = randomUUID5();
20165
20810
  const reply = new Promise((resolve, reject) => {
20166
20811
  const timer = setTimeout(() => {
20167
20812
  this.#pending.delete(requestId);
@@ -20195,6 +20840,12 @@ var PiSubagentRpc = class {
20195
20840
  };
20196
20841
 
20197
20842
  // dist/pi-rpc-session.js
20843
+ var PiRpcBusyError = class extends Error {
20844
+ constructor() {
20845
+ super("Pi is still running a native Turn; wait for completion or use the active Turn's stop/steer action");
20846
+ this.name = "PiRpcBusyError";
20847
+ }
20848
+ };
20198
20849
  var PiRpcFaultError = class extends Error {
20199
20850
  kind;
20200
20851
  diagnostic;
@@ -20222,8 +20873,11 @@ var READ_ONLY_COMMANDS = /* @__PURE__ */ new Set([
20222
20873
  "get_available_thinking_levels"
20223
20874
  ]);
20224
20875
  var MAX_EXPIRED_IDS = 64;
20876
+ function nativeMessageIdentity(active) {
20877
+ return active.assistantNativeMessageIdentity ? { nativeMessageIdentity: active.assistantNativeMessageIdentity } : {};
20878
+ }
20225
20879
  var textDecoder = new TextDecoder("utf-8", { fatal: true });
20226
- function isRecord8(value) {
20880
+ function isRecord9(value) {
20227
20881
  return typeof value === "object" && value !== null && !Array.isArray(value);
20228
20882
  }
20229
20883
  function message2(value) {
@@ -20235,13 +20889,13 @@ function nonBlankString(value) {
20235
20889
  function parseNativeModel(value, context) {
20236
20890
  if (value === null || value === void 0)
20237
20891
  return null;
20238
- if (!isRecord8(value) || !nonBlankString(value.provider) || !nonBlankString(value.id)) {
20892
+ if (!isRecord9(value) || !nonBlankString(value.provider) || !nonBlankString(value.id)) {
20239
20893
  throw new PiRpcFaultError("protocolError", `Pi RPC returned an invalid ${context} Model`);
20240
20894
  }
20241
20895
  return { provider: value.provider, id: value.id };
20242
20896
  }
20243
20897
  function sessionStateData(response) {
20244
- const data = isRecord8(response.data) ? response.data : null;
20898
+ const data = isRecord9(response.data) ? response.data : null;
20245
20899
  if (!data)
20246
20900
  throw new PiRpcFaultError("protocolError", "Pi RPC state response has no data");
20247
20901
  return data;
@@ -20249,7 +20903,7 @@ function sessionStateData(response) {
20249
20903
  function parseSessionState(response) {
20250
20904
  const data = sessionStateData(response);
20251
20905
  const model2 = parseNativeModel(data.model, "state");
20252
- const modelReasoning = isRecord8(data.model) && typeof data.model.reasoning === "boolean" ? data.model.reasoning : null;
20906
+ const modelReasoning = isRecord9(data.model) && typeof data.model.reasoning === "boolean" ? data.model.reasoning : null;
20253
20907
  if (!nonBlankString(data.sessionId)) {
20254
20908
  throw new PiRpcFaultError("protocolError", "Pi RPC state has no stable Session identity");
20255
20909
  }
@@ -20275,13 +20929,13 @@ function parseSessionStreaming(response) {
20275
20929
  return isStreaming;
20276
20930
  }
20277
20931
  function parseSessionHistory(response) {
20278
- const data = isRecord8(response.data) ? response.data : null;
20932
+ const data = isRecord9(response.data) ? response.data : null;
20279
20933
  if (!data || !Array.isArray(data.entries)) {
20280
20934
  throw new PiRpcFaultError("protocolError", "Pi RPC entries response has no Entries");
20281
20935
  }
20282
20936
  const entries = data.entries.map((entry) => {
20283
20937
  const parsed = jsonValueSchema.safeParse(entry);
20284
- if (!parsed.success || !isRecord8(parsed.data)) {
20938
+ if (!parsed.success || !isRecord9(parsed.data)) {
20285
20939
  throw new PiRpcFaultError("protocolError", "Pi RPC entries response contains an invalid Entry");
20286
20940
  }
20287
20941
  return parsed.data;
@@ -20292,7 +20946,7 @@ function parseSessionHistory(response) {
20292
20946
  return { entries, leafId: data.leafId };
20293
20947
  }
20294
20948
  function parseAvailableThinkingLevels(response) {
20295
- const data = isRecord8(response.data) ? response.data : null;
20949
+ const data = isRecord9(response.data) ? response.data : null;
20296
20950
  if (!data || !Array.isArray(data.levels) || data.levels.length === 0) {
20297
20951
  throw new PiRpcFaultError("protocolError", "Pi RPC Thinking catalog response has no levels");
20298
20952
  }
@@ -20309,13 +20963,13 @@ function parseAvailableThinkingLevels(response) {
20309
20963
  return levels;
20310
20964
  }
20311
20965
  function parseAvailableModels(response) {
20312
- const data = isRecord8(response.data) ? response.data : null;
20966
+ const data = isRecord9(response.data) ? response.data : null;
20313
20967
  if (!data || !Array.isArray(data.models)) {
20314
20968
  throw new PiRpcFaultError("protocolError", "Pi RPC Model catalog response has no models");
20315
20969
  }
20316
20970
  return data.models.map((model2) => {
20317
20971
  const parsed = parseNativeModel(model2, "catalog");
20318
- if (!parsed || !isRecord8(model2) || typeof model2.reasoning !== "boolean") {
20972
+ if (!parsed || !isRecord9(model2) || typeof model2.reasoning !== "boolean") {
20319
20973
  throw new PiRpcFaultError("protocolError", "Pi RPC catalog contains a Model without reasoning capability");
20320
20974
  }
20321
20975
  return {
@@ -20326,32 +20980,32 @@ function parseAvailableModels(response) {
20326
20980
  });
20327
20981
  }
20328
20982
  function assistantText(value) {
20329
- if (!isRecord8(value) || value.role !== "assistant" || !Array.isArray(value.content))
20983
+ if (!isRecord9(value) || value.role !== "assistant" || !Array.isArray(value.content))
20330
20984
  return null;
20331
- return value.content.filter((content) => isRecord8(content) && content.type === "text" && typeof content.text === "string").map((content) => content.text).join("");
20985
+ return value.content.filter((content) => isRecord9(content) && content.type === "text" && typeof content.text === "string").map((content) => content.text).join("");
20332
20986
  }
20333
20987
  function assistantMessageId(value) {
20334
- if (!isRecord8(value) || value.role !== "assistant")
20988
+ if (!isRecord9(value) || value.role !== "assistant")
20335
20989
  return null;
20336
20990
  return nonBlankString(value.responseId) ? value.responseId : null;
20337
20991
  }
20338
20992
  function extractReasoningText(content) {
20339
- if (!isRecord8(content))
20993
+ if (!isRecord9(content))
20340
20994
  return null;
20341
20995
  const type = String(content.type ?? "");
20342
20996
  if (type === "thinking" || type === "reasoning" || type === "thought") {
20343
- const text2 = content.thinking ?? content.reasoning ?? content.text ?? content.delta;
20344
- return typeof text2 === "string" ? text2 : null;
20997
+ const text3 = content.thinking ?? content.reasoning ?? content.text ?? content.delta;
20998
+ return typeof text3 === "string" ? text3 : null;
20345
20999
  }
20346
21000
  return null;
20347
21001
  }
20348
21002
  function assistantReasoning(value) {
20349
- if (!isRecord8(value) || value.role !== "assistant" || !Array.isArray(value.content))
21003
+ if (!isRecord9(value) || value.role !== "assistant" || !Array.isArray(value.content))
20350
21004
  return null;
20351
- return value.content.map(extractReasoningText).filter((text2) => typeof text2 === "string").join("");
21005
+ return value.content.map(extractReasoningText).filter((text3) => typeof text3 === "string").join("");
20352
21006
  }
20353
21007
  function assistantFailure(value) {
20354
- if (!isRecord8(value) || value.role !== "assistant")
21008
+ if (!isRecord9(value) || value.role !== "assistant")
20355
21009
  return void 0;
20356
21010
  if (value.stopReason !== "error" && value.stopReason !== "aborted")
20357
21011
  return null;
@@ -20371,7 +21025,7 @@ function signalProcessTree(child, signal) {
20371
21025
  try {
20372
21026
  process.kill(-child.pid, signal);
20373
21027
  } catch (error51) {
20374
- if (!isRecord8(error51) || error51.code !== "ESRCH")
21028
+ if (!isRecord9(error51) || error51.code !== "ESRCH")
20375
21029
  throw error51;
20376
21030
  }
20377
21031
  }
@@ -20408,13 +21062,14 @@ function piRpcProcessCommand(options, dependencies = {}) {
20408
21062
  const thinkingArguments = options.emptySessionConfiguration ? ["--thinking", options.emptySessionConfiguration.thinkingLevel] : [];
20409
21063
  const arguments_ = [
20410
21064
  ...options.fastExtension ? ["--extension", options.fastExtension] : [],
21065
+ ...options.subagentExtension ? ["--extension", options.subagentExtension] : [],
20411
21066
  "--mode",
20412
21067
  "rpc",
20413
21068
  ...modelArguments,
20414
21069
  ...thinkingArguments,
20415
21070
  ...sessionArguments
20416
21071
  ];
20417
- const extension = path14.win32.extname(command).toLowerCase();
21072
+ const extension = path15.win32.extname(command).toLowerCase();
20418
21073
  if (platform !== "win32" || ![".cmd", ".bat"].includes(extension)) {
20419
21074
  return { command, arguments: arguments_, windowsVerbatimArguments: false };
20420
21075
  }
@@ -20443,7 +21098,13 @@ var PiRpcSession = class {
20443
21098
  #options;
20444
21099
  #processAdapter;
20445
21100
  #activeTurn = null;
21101
+ #runGeneration = 0;
21102
+ #deferredRunFrames = [];
21103
+ #deferredRunBytes = 0;
21104
+ #runWaiters = /* @__PURE__ */ new Set();
21105
+ #messageTimestampCounts = /* @__PURE__ */ new Map();
20446
21106
  #autonomousTurnHandler = null;
21107
+ #autonomousLifecycleHandler = null;
20447
21108
  #usageHandler = null;
20448
21109
  #usageRequestStartedAtMs = null;
20449
21110
  // Pieces of the unterminated frame; joined once at its newline so a large frame (a long
@@ -20463,8 +21124,15 @@ var PiRpcSession = class {
20463
21124
  #fastAcknowledgement = null;
20464
21125
  #latestCacheHitRatePercent;
20465
21126
  #manualCompaction = null;
21127
+ #noticeOccurrences = /* @__PURE__ */ new Map();
21128
+ #seenNoticeFrames = /* @__PURE__ */ new Set();
21129
+ #pendingProgress = [];
21130
+ #omittedProgress = 0;
21131
+ #extensionStatuses = /* @__PURE__ */ new Map();
20466
21132
  #stderrTail = "";
20467
21133
  #subagents;
21134
+ #gotgenesHandler;
21135
+ #gotgenesLatest;
20468
21136
  constructor(options, processAdapter = nodeProcessAdapter) {
20469
21137
  if (options.sessionFile && options.forkSessionFile) {
20470
21138
  throw new Error("Pi RPC cannot combine Session resume and Fork startup");
@@ -20494,9 +21162,17 @@ var PiRpcSession = class {
20494
21162
  get stderrTail() {
20495
21163
  return this.#stderrTail;
20496
21164
  }
21165
+ get isBusy() {
21166
+ return this.#activeTurn !== null || this.#manualCompaction !== null || this.#compactionActive || this.#deferredRunFrames.length > 0;
21167
+ }
20497
21168
  setSubagentStatusHandler(handler) {
20498
21169
  this.#subagents.setHandler(handler);
20499
21170
  }
21171
+ setGotgenesStatusHandler(handler) {
21172
+ this.#gotgenesHandler = handler;
21173
+ if (this.#gotgenesLatest)
21174
+ handler(this.#gotgenesLatest, "idle");
21175
+ }
20500
21176
  inspectSubagent(id) {
20501
21177
  return this.#subagents.inspect(id);
20502
21178
  }
@@ -20506,17 +21182,18 @@ var PiRpcSession = class {
20506
21182
  /** Every finished assistant message is one model request, with or without an active Turn. */
20507
21183
  #observeUsage(value) {
20508
21184
  if (value.type === "message_start") {
20509
- this.#usageRequestStartedAtMs = null;
21185
+ if (isRecord9(value.message) && value.message.role === "assistant")
21186
+ this.#usageRequestStartedAtMs = null;
20510
21187
  return;
20511
21188
  }
20512
21189
  if (value.type === "message_update") {
20513
21190
  const event = value.assistantMessageEvent;
20514
- if (this.#usageRequestStartedAtMs === null && isRecord8(event) && typeof event.type === "string" && /^(text|thinking|reasoning|thought|toolcall)_(start|delta)$/u.test(event.type)) {
21191
+ if (this.#usageRequestStartedAtMs === null && isRecord9(event) && typeof event.type === "string" && /^(text|thinking|reasoning|thought|toolcall)_(start|delta)$/u.test(event.type)) {
20515
21192
  this.#usageRequestStartedAtMs = Date.now();
20516
21193
  }
20517
21194
  return;
20518
21195
  }
20519
- if (value.type === "message_end" && isRecord8(value.message)) {
21196
+ if (value.type === "message_end" && isRecord9(value.message)) {
20520
21197
  if (value.message.role !== "assistant")
20521
21198
  return;
20522
21199
  const startedAtMs = this.#usageRequestStartedAtMs;
@@ -20530,14 +21207,21 @@ var PiRpcSession = class {
20530
21207
  }
20531
21208
  setAutonomousTurnHandler(handler) {
20532
21209
  this.#autonomousTurnHandler = handler;
21210
+ this.#autonomousLifecycleHandler = null;
21211
+ }
21212
+ setAutonomousTurnLifecycleHandler(handler) {
21213
+ this.#autonomousLifecycleHandler = handler;
21214
+ this.#autonomousTurnHandler = null;
20533
21215
  }
20534
21216
  async start() {
20535
21217
  if (this.#child || this.#closed)
20536
21218
  throw new Error("Pi RPC Session cannot be started twice");
20537
21219
  const fastExtension = this.#processAdapter === nodeProcessAdapter ? await ensurePiFastExtension({ ...process.env, ...this.#options.environment }) : void 0;
21220
+ const subagentExtension = this.#processAdapter === nodeProcessAdapter ? await ensureGotgenesExtension({ ...process.env, ...this.#options.environment }) : void 0;
20538
21221
  const child = this.#processAdapter.spawn({
20539
21222
  cwd: this.#options.cwd,
20540
21223
  ...fastExtension ? { fastExtension } : {},
21224
+ ...subagentExtension ? { subagentExtension } : {},
20541
21225
  ...this.#options.command ? { command: this.#options.command } : {},
20542
21226
  environment: withNodeRuntimeOnPath({
20543
21227
  ...process.env,
@@ -20561,7 +21245,7 @@ var PiRpcSession = class {
20561
21245
  this.#stderrTail = sanitizeDiagnosticTail(`${this.#stderrTail}${chunk.toString()}`);
20562
21246
  });
20563
21247
  child.once("error", (error51) => {
20564
- const kind = isRecord8(error51) && error51.code === "ENOENT" ? "notInstalled" : "unavailable";
21248
+ const kind = isRecord9(error51) && error51.code === "ENOENT" ? "notInstalled" : "unavailable";
20565
21249
  this.#fail(new PiRpcFaultError(kind, `Pi RPC failed to start: ${error51.message}`, this.stderrTail));
20566
21250
  });
20567
21251
  child.once("exit", (code, signal) => {
@@ -20578,6 +21262,7 @@ var PiRpcSession = class {
20578
21262
  ]);
20579
21263
  try {
20580
21264
  this.#state = parseSessionState(await this.#send("get_state", {}));
21265
+ await this.getEntries();
20581
21266
  } catch (error51) {
20582
21267
  const fault = error51 instanceof PiRpcFaultError ? error51 : new PiRpcFaultError("unavailable", `Pi RPC state unavailable: ${message2(error51)}`);
20583
21268
  this.#fail(fault);
@@ -20591,7 +21276,12 @@ var PiRpcSession = class {
20591
21276
  }
20592
21277
  async getEntries() {
20593
21278
  try {
20594
- return parseSessionHistory(await this.#send("get_entries", {}));
21279
+ const history = parseSessionHistory(await this.#send("get_entries", {}));
21280
+ if (!this.#activeTurn && this.#state) {
21281
+ this.#messageTimestampCounts = piHistoryMessageIdentities(this.state.sessionId, activePiEntries(history)).timestampCounts;
21282
+ this.#noticeOccurrences = piHistoryNotices(this.state.sessionId, activePiEntries(history)).occurrences;
21283
+ }
21284
+ return history;
20595
21285
  } catch (error51) {
20596
21286
  if (error51 instanceof PiRpcFaultError)
20597
21287
  this.#fail(error51);
@@ -20651,11 +21341,15 @@ var PiRpcSession = class {
20651
21341
  if (entryId.length === 0)
20652
21342
  throw new Error("Pi Fork Entry ID must not be empty");
20653
21343
  await this.#send("fork", { entryId });
20654
- return this.#refreshState("Fork");
21344
+ const state2 = await this.#refreshState("Fork");
21345
+ await this.getEntries();
21346
+ return state2;
20655
21347
  }
20656
21348
  async clone() {
20657
21349
  await this.#send("clone", {});
20658
- return this.#refreshState("Clone");
21350
+ const state2 = await this.#refreshState("Clone");
21351
+ await this.getEntries();
21352
+ return state2;
20659
21353
  }
20660
21354
  verifySessionCwd(expectedCwd) {
20661
21355
  return verifyPiSessionCwd({
@@ -20692,7 +21386,7 @@ var PiRpcSession = class {
20692
21386
  return this.state;
20693
21387
  if (!await this.supportsFastMode())
20694
21388
  throw new Error("Installed Pi does not support the Host Fast extension");
20695
- const nonce = randomUUID5();
21389
+ const nonce = randomUUID6();
20696
21390
  const mode = enabled ? "on" : "off";
20697
21391
  const acknowledgement = { message: `${PI_FAST_ACK}${nonce}:${mode}`, received: false };
20698
21392
  this.#fastAcknowledgement = acknowledgement;
@@ -20732,22 +21426,27 @@ var PiRpcSession = class {
20732
21426
  throw fault;
20733
21427
  }
20734
21428
  }
20735
- async runTurn(text2, onEvent) {
21429
+ async runTurn(text3, onEvent) {
20736
21430
  if (!this.#child || !this.#state || this.#closed || this.#failed) {
20737
21431
  throw new Error("Pi RPC Session is unavailable");
20738
21432
  }
20739
- if (this.#activeTurn)
20740
- throw new Error("Pi RPC Session already has an active Turn");
20741
- if (text2.length === 0)
21433
+ if (this.isBusy)
21434
+ throw new PiRpcBusyError();
21435
+ if (text3.length === 0)
20742
21436
  throw new Error("Pi text Turn must not be empty");
20743
21437
  const settled = new Promise((resolve, reject) => {
20744
21438
  this.#activeTurn = {
20745
21439
  origin: "requested",
21440
+ autonomousRunId: null,
21441
+ runGeneration: this.#runGeneration,
20746
21442
  autonomousEvents: null,
20747
21443
  nativeTurnKey: null,
20748
21444
  nativeCancellationObserved: false,
20749
21445
  text: "",
20750
21446
  assistantMessageId: null,
21447
+ assistantNativeMessageIdentity: void 0,
21448
+ textStream: new PiContentStream("text"),
21449
+ reasoningStream: new PiContentStream("reasoning"),
20751
21450
  sawStreamedMessageText: false,
20752
21451
  sawStreamedMessageReasoning: false,
20753
21452
  lastFinalizedMessageText: null,
@@ -20767,7 +21466,8 @@ var PiRpcSession = class {
20767
21466
  };
20768
21467
  });
20769
21468
  try {
20770
- await this.#send("prompt", { message: text2 });
21469
+ this.#drainProgress(onEvent);
21470
+ await this.#send("prompt", { message: text3 });
20771
21471
  } catch (error51) {
20772
21472
  this.#rejectActiveTurn(error51 instanceof Error ? error51 : new Error(message2(error51)));
20773
21473
  }
@@ -20839,6 +21539,10 @@ var PiRpcSession = class {
20839
21539
  void this.close().catch(() => void 0);
20840
21540
  }
20841
21541
  close() {
21542
+ this.#pendingProgress = [];
21543
+ this.#omittedProgress = 0;
21544
+ this.#seenNoticeFrames.clear();
21545
+ this.#extensionStatuses.clear();
20842
21546
  if (!this.#closed) {
20843
21547
  this.#closed = true;
20844
21548
  this.#rejectAll(new Error("Pi RPC Session closed"));
@@ -20872,19 +21576,25 @@ var PiRpcSession = class {
20872
21576
  rest = rest.subarray(newline + 1);
20873
21577
  try {
20874
21578
  const value = JSON.parse(textDecoder.decode(frame));
20875
- if (!isRecord8(value) || typeof value.type !== "string") {
21579
+ if (!isRecord9(value) || typeof value.type !== "string") {
20876
21580
  throw new PiRpcFaultError("protocolError", "Pi RPC returned an invalid envelope");
20877
21581
  }
20878
21582
  this.#handle(value);
20879
21583
  } catch (error51) {
20880
- this.#fail(error51 instanceof PiRpcFaultError ? error51 : new PiRpcFaultError("protocolError", `Pi RPC returned invalid JSONL: ${message2(error51)}`));
21584
+ this.#fail(error51 instanceof PiRpcFaultError ? error51 : new PiRpcFaultError("protocolError", error51 instanceof PiContentStreamConflictError ? error51.message : `Pi RPC returned invalid JSONL: ${message2(error51)}`));
20881
21585
  }
20882
21586
  newline = rest.indexOf(10);
20883
21587
  }
20884
21588
  if (rest.length !== 0)
20885
21589
  this.#buffer.push(rest);
20886
21590
  }
20887
- #handle(value) {
21591
+ #handle(value, observedGeneration) {
21592
+ if (observedGeneration === void 0 && value.type === "agent_start") {
21593
+ this.#runGeneration += 1;
21594
+ for (const waiter of this.#runWaiters)
21595
+ waiter.check();
21596
+ }
21597
+ const generation = observedGeneration ?? this.#runGeneration;
20888
21598
  if (value.type === "extension_ui_request" && value.method === "notify" && typeof value.message === "string" && value.message.startsWith(PI_FAST_ACK)) {
20889
21599
  if (this.#fastAcknowledgement?.message === value.message)
20890
21600
  this.#fastAcknowledgement.received = true;
@@ -20898,6 +21608,33 @@ var PiRpcSession = class {
20898
21608
  }
20899
21609
  if (this.#subagents.handle(value))
20900
21610
  return;
21611
+ const settling = this.#activeTurn;
21612
+ if (settling && settling.settlement !== "pending" && generation > settling.runGeneration) {
21613
+ this.#deferredRunBytes += Buffer.byteLength(JSON.stringify(value));
21614
+ if (this.#deferredRunBytes > 8 * 1024 * 1024) {
21615
+ this.#fail(new PiRpcFaultError("protocolError", "Pi deferred run exceeded its event buffer bound"));
21616
+ return;
21617
+ }
21618
+ this.#deferredRunFrames.push({ value, generation });
21619
+ return;
21620
+ }
21621
+ if (value.type === "agent_start") {
21622
+ if (this.#activeTurn)
21623
+ this.#activeTurn.runGeneration = generation;
21624
+ else if (!this.#manualCompaction && !this.#compactionActive && (this.#autonomousTurnHandler || this.#autonomousLifecycleHandler))
21625
+ this.#startAutonomousTurn(void 0, generation);
21626
+ return;
21627
+ }
21628
+ if (value.type === "extension_ui_request" && value.method === "setWidget" && value.widgetKey === GOTGENES_WIDGET) {
21629
+ const records = parseGotgenesWidget(value);
21630
+ if (records) {
21631
+ this.#gotgenesLatest = records;
21632
+ this.#gotgenesHandler?.(records, this.#activeTurn?.origin ?? "idle");
21633
+ }
21634
+ return;
21635
+ }
21636
+ if (this.#handleProgress(value))
21637
+ return;
20901
21638
  this.#observeUsage(value);
20902
21639
  if (value.type === "compaction_start") {
20903
21640
  this.#compactionActive = true;
@@ -20921,7 +21658,7 @@ var PiRpcSession = class {
20921
21658
  this.#armCommandTimeout(id, pending);
20922
21659
  }
20923
21660
  }
20924
- const outcome = value.aborted === true ? "cancelled" : isRecord8(value.result) ? "succeeded" : "failed";
21661
+ const outcome = value.aborted === true ? "cancelled" : isRecord9(value.result) ? "succeeded" : "failed";
20925
21662
  const event = {
20926
21663
  type: "compaction.completed",
20927
21664
  outcome,
@@ -20938,8 +21675,8 @@ var PiRpcSession = class {
20938
21675
  return;
20939
21676
  }
20940
21677
  let active = this.#activeTurn;
20941
- if (!active && !this.#manualCompaction && !this.#compactionActive && this.#autonomousTurnHandler && value.type === "message_start" && assistantText(value.message) !== null) {
20942
- active = this.#startAutonomousTurn(value.message);
21678
+ if (!active && !this.#manualCompaction && !this.#compactionActive && (this.#autonomousTurnHandler || this.#autonomousLifecycleHandler) && value.type === "message_start" && assistantText(value.message) !== null) {
21679
+ active = this.#startAutonomousTurn(value.message, generation);
20943
21680
  }
20944
21681
  if (!active) {
20945
21682
  if (value.type === "extension_ui_request" && this.#isBlockingInteraction(value)) {
@@ -20959,22 +21696,26 @@ var PiRpcSession = class {
20959
21696
  this.#startAssistantMessage(active, value.message);
20960
21697
  return;
20961
21698
  }
20962
- if (value.type === "message_update" && isRecord8(value.assistantMessageEvent)) {
21699
+ if (value.type === "message_update" && isRecord9(value.assistantMessageEvent)) {
20963
21700
  const event = value.assistantMessageEvent;
20964
21701
  const eventType = String(event.type ?? "");
20965
21702
  const isThinking = eventType === "thinking_delta" || eventType === "reasoning_delta" || eventType === "thought_delta" || eventType === "thinking" || eventType === "reasoning";
20966
21703
  const isText = eventType === "text_delta" || eventType === "text" || eventType === "content_block_delta";
20967
- const delta = typeof event.delta === "string" ? event.delta : typeof event.thinking === "string" ? event.thinking : typeof event.reasoning === "string" ? event.reasoning : typeof event.text === "string" ? event.text : isRecord8(event.delta) && typeof event.delta.thinking === "string" ? event.delta.thinking : isRecord8(event.delta) && typeof event.delta.text === "string" ? event.delta.text : null;
20968
- if (isThinking && delta !== null && delta.length > 0) {
20969
- const messageId = this.#ensureAssistantMessage(active, value.message);
20970
- active.reasoningMessageOpen = true;
20971
- active.sawStreamedMessageReasoning = true;
20972
- active.onEvent({ type: "reasoning.delta", messageId, delta });
20973
- } else if (isText && delta !== null && delta.length > 0) {
20974
- const messageId = this.#ensureAssistantMessage(active, value.message);
20975
- active.text += delta;
20976
- active.sawStreamedMessageText = true;
20977
- active.onEvent({ type: "text.delta", messageId, delta });
21704
+ const delta = typeof event.delta === "string" ? event.delta : typeof event.thinking === "string" ? event.thinking : typeof event.reasoning === "string" ? event.reasoning : typeof event.text === "string" ? event.text : isRecord9(event.delta) && typeof event.delta.thinking === "string" ? event.delta.thinking : isRecord9(event.delta) && typeof event.delta.text === "string" ? event.delta.text : null;
21705
+ const endingReasoning = eventType === "thinking_end" || eventType === "reasoning_end";
21706
+ const endingText = eventType === "text_end";
21707
+ if ((endingReasoning || endingText) && typeof event.content === "string") {
21708
+ this.#ensureAssistantMessage(active, value.message);
21709
+ const stream = endingReasoning ? active.reasoningStream : active.textStream;
21710
+ this.#emitContent(active, endingReasoning, stream.complete(event.contentIndex, event.content));
21711
+ } else if ((isThinking || isText) && delta !== null && delta.length > 0) {
21712
+ this.#ensureAssistantMessage(active, value.message);
21713
+ if (isThinking)
21714
+ active.sawStreamedMessageReasoning = true;
21715
+ else
21716
+ active.sawStreamedMessageText = true;
21717
+ const stream = isThinking ? active.reasoningStream : active.textStream;
21718
+ this.#emitContent(active, isThinking, stream.append(event.contentIndex, delta));
20978
21719
  } else if (event.type === "error") {
20979
21720
  this.#ensureAssistantMessage(active, value.message);
20980
21721
  active.failure = assistantFailure(event.error) ?? assistantFailure(value.message) ?? new Error("Pi assistant message failed");
@@ -21005,25 +21746,36 @@ var PiRpcSession = class {
21005
21746
  if (active.settlement !== "pending")
21006
21747
  return;
21007
21748
  active.settlement = "confirming";
21008
- void this.#confirmSettledTurn(active);
21749
+ void this.#confirmSettledTurn(active, active.runGeneration);
21009
21750
  }
21010
21751
  }
21011
- #startAutonomousTurn(value) {
21752
+ #startAutonomousTurn(value, generation) {
21012
21753
  const events = [];
21754
+ const runId = randomUUID6();
21013
21755
  const active = {
21014
21756
  origin: "autonomous",
21757
+ autonomousRunId: runId,
21758
+ runGeneration: generation,
21015
21759
  autonomousEvents: events,
21016
- ...isRecord8(value) ? { autonomousMessage: value } : {},
21760
+ ...isRecord9(value) ? { autonomousMessage: value } : {},
21017
21761
  nativeTurnKey: null,
21018
21762
  nativeCancellationObserved: false,
21019
21763
  text: "",
21020
21764
  assistantMessageId: null,
21765
+ assistantNativeMessageIdentity: void 0,
21766
+ textStream: new PiContentStream("text"),
21767
+ reasoningStream: new PiContentStream("reasoning"),
21021
21768
  sawStreamedMessageText: false,
21022
21769
  sawStreamedMessageReasoning: false,
21023
21770
  lastFinalizedMessageText: null,
21024
21771
  lastFinalizedMessageReasoning: null,
21025
21772
  reasoningMessageOpen: false,
21026
- onEvent: (event) => events.push(event),
21773
+ onEvent: (event) => {
21774
+ if (this.#autonomousLifecycleHandler)
21775
+ this.#autonomousLifecycleHandler({ type: "event", runId, event });
21776
+ else
21777
+ events.push(event);
21778
+ },
21027
21779
  resolve: () => void 0,
21028
21780
  reject: () => void 0,
21029
21781
  failure: null,
@@ -21036,19 +21788,108 @@ var PiRpcSession = class {
21036
21788
  abortPromise: null
21037
21789
  };
21038
21790
  this.#activeTurn = active;
21791
+ this.#autonomousLifecycleHandler?.({ type: "started", runId });
21792
+ this.#drainProgress(active.onEvent);
21039
21793
  return active;
21040
21794
  }
21795
+ #handleProgress(value) {
21796
+ if ((value.type === "message_start" || value.type === "message_end") && isRecord9(value.message) && value.message.role === "custom") {
21797
+ if (value.type !== "message_end" || !this.#state)
21798
+ return true;
21799
+ const key = piCustomNoticeKey(value.message);
21800
+ if (!key)
21801
+ return true;
21802
+ const timestamp = value.message.timestamp;
21803
+ if ((typeof timestamp === "number" || typeof timestamp === "string") && !this.#acceptNoticeFrame(JSON.stringify([key, timestamp])))
21804
+ return true;
21805
+ const progress = piCustomNotice(value.message, this.state.sessionId, this.#noticeOccurrences);
21806
+ if (progress)
21807
+ this.#publishProgress(progress);
21808
+ return true;
21809
+ }
21810
+ if (value.type === "extension_ui_request" && value.method === "setStatus") {
21811
+ if (typeof value.statusKey !== "string")
21812
+ return true;
21813
+ if (typeof value.statusText !== "string" || !value.statusText.trim()) {
21814
+ if (!this.#extensionStatuses.has(value.statusKey))
21815
+ return true;
21816
+ this.#extensionStatuses.delete(value.statusKey);
21817
+ } else {
21818
+ if (this.#extensionStatuses.get(value.statusKey) === value.statusText)
21819
+ return true;
21820
+ this.#extensionStatuses.set(value.statusKey, value.statusText);
21821
+ }
21822
+ }
21823
+ const text3 = piStatusText(value);
21824
+ if (!text3)
21825
+ return false;
21826
+ if (value.type === "extension_ui_request" && typeof value.id === "string" && !this.#acceptNoticeFrame(JSON.stringify([value.type, value.id])))
21827
+ return true;
21828
+ this.#publishProgress({
21829
+ type: "progress.message",
21830
+ itemId: hostItemIdSchema.parse(`pi-progress-${randomUUID6()}`),
21831
+ text: text3
21832
+ }, value.method === "setStatus" && typeof value.statusKey === "string" ? value.statusKey : void 0);
21833
+ return true;
21834
+ }
21835
+ #acceptNoticeFrame(key) {
21836
+ if (this.#seenNoticeFrames.has(key))
21837
+ return false;
21838
+ this.#seenNoticeFrames.add(key);
21839
+ if (this.#seenNoticeFrames.size > 512)
21840
+ this.#seenNoticeFrames.delete(this.#seenNoticeFrames.values().next().value);
21841
+ return true;
21842
+ }
21843
+ #publishProgress(progress, statusKey) {
21844
+ if (this.#activeTurn?.settlement === "pending") {
21845
+ this.#activeTurn.onEvent(progress);
21846
+ return;
21847
+ }
21848
+ if (statusKey !== void 0) {
21849
+ const previous = this.#pendingProgress.findIndex((pending) => pending.statusKey === statusKey);
21850
+ if (previous >= 0)
21851
+ this.#pendingProgress.splice(previous, 1);
21852
+ }
21853
+ if (this.#pendingProgress.length >= 128) {
21854
+ this.#pendingProgress.shift();
21855
+ this.#omittedProgress += 1;
21856
+ }
21857
+ this.#pendingProgress.push({
21858
+ event: progress,
21859
+ ...statusKey !== void 0 ? { statusKey } : {}
21860
+ });
21861
+ }
21862
+ #drainProgress(onEvent) {
21863
+ if (this.#omittedProgress > 0) {
21864
+ onEvent({
21865
+ type: "progress.message",
21866
+ itemId: hostItemIdSchema.parse(`pi-progress-${randomUUID6()}`),
21867
+ text: `Pi notifications: ${this.#omittedProgress} earlier updates were not retained while idle. Persisted notifications remain available in conversation history.`
21868
+ });
21869
+ this.#omittedProgress = 0;
21870
+ }
21871
+ for (const pending of this.#pendingProgress.splice(0))
21872
+ onEvent(pending.event);
21873
+ }
21041
21874
  #emitAutonomousTurn(active, result) {
21042
21875
  const handler = this.#autonomousTurnHandler;
21043
- if (active.origin !== "autonomous" || !active.autonomousEvents || !handler) {
21876
+ if (active.origin !== "autonomous" || !active.autonomousEvents || !active.autonomousRunId) {
21044
21877
  return;
21045
21878
  }
21046
21879
  try {
21047
- handler({
21880
+ const turn = {
21048
21881
  nativeTurnKey: active.nativeTurnKey,
21049
21882
  events: [...active.autonomousEvents],
21050
21883
  result
21051
- });
21884
+ };
21885
+ if (this.#autonomousLifecycleHandler)
21886
+ this.#autonomousLifecycleHandler({
21887
+ type: "completed",
21888
+ runId: active.autonomousRunId,
21889
+ turn
21890
+ });
21891
+ else
21892
+ handler?.(turn);
21052
21893
  } catch (error51) {
21053
21894
  this.#fail(new PiRpcFaultError("protocolError", `Pi autonomous Turn handler failed: ${message2(error51)}`));
21054
21895
  }
@@ -21195,31 +22036,73 @@ var PiRpcSession = class {
21195
22036
  isError: value.isError
21196
22037
  });
21197
22038
  }
21198
- async #confirmSettledTurn(active) {
22039
+ #isSettlementCurrent(active, generation) {
22040
+ return this.#activeTurn === active && active.runGeneration === generation && active.settlement === "confirming";
22041
+ }
22042
+ #waitForNextRun(generation) {
22043
+ if (this.#runGeneration > generation)
22044
+ return Promise.resolve();
22045
+ return new Promise((resolve, reject) => {
22046
+ const finish = (error51) => {
22047
+ clearTimeout(timer);
22048
+ this.#runWaiters.delete(waiter);
22049
+ if (error51)
22050
+ reject(error51);
22051
+ else
22052
+ resolve();
22053
+ };
22054
+ const waiter = {
22055
+ check: () => {
22056
+ if (this.#runGeneration > generation)
22057
+ finish();
22058
+ },
22059
+ reject: (error51) => finish(error51)
22060
+ };
22061
+ const timer = setTimeout(() => finish(new PiRpcFaultError("protocolError", "Pi RPC agent_settled state is still Streaming without a subsequent agent_start")), this.#options.commandTimeoutMs);
22062
+ this.#runWaiters.add(waiter);
22063
+ });
22064
+ }
22065
+ #drainDeferredRunFrames() {
22066
+ const frames = this.#deferredRunFrames;
22067
+ this.#deferredRunFrames = [];
22068
+ this.#deferredRunBytes = 0;
22069
+ for (const frame of frames) {
22070
+ if (this.#closed || this.#failed)
22071
+ break;
22072
+ this.#handle(frame.value, frame.generation);
22073
+ }
22074
+ }
22075
+ async #confirmSettledTurn(active, generation) {
21199
22076
  try {
21200
22077
  const response = await this.#send("get_state", {});
21201
22078
  const state2 = parseSessionState(response);
21202
- if (parseSessionStreaming(response)) {
21203
- throw new PiRpcFaultError("protocolError", "Pi RPC agent_settled state is still Streaming");
21204
- }
21205
- if (this.#activeTurn !== active)
22079
+ if (!this.#isSettlementCurrent(active, generation))
22080
+ return;
22081
+ if (parseSessionStreaming(response))
22082
+ await this.#waitForNextRun(generation);
22083
+ if (!this.#isSettlementCurrent(active, generation))
21206
22084
  return;
21207
- if (active.origin === "autonomous") {
22085
+ if (active.origin === "autonomous" && active.autonomousMessage) {
21208
22086
  const history = await this.getEntries();
21209
22087
  const snapshot = mapPiSnapshot(history, { sessionId: state2.sessionId, model: null });
21210
- const turn = snapshot.turns.at(-1);
22088
+ if (!this.#isSettlementCurrent(active, generation))
22089
+ return;
21211
22090
  const entries = activePiEntries(history);
21212
- const start = entries.findIndex((entry) => entry.id === turn?.nativeTurnRef.nativeTurnKey);
21213
- const firstAssistant = entries.slice(start + 1).find((entry) => isRecord8(entry.message) && entry.message.role === "assistant")?.message;
21214
22091
  const live = active.autonomousMessage;
21215
22092
  const responseId = assistantMessageId(live);
21216
- const matches = isRecord8(firstAssistant) && (responseId ? assistantMessageId(firstAssistant) === responseId : typeof live?.timestamp === "number" && firstAssistant.timestamp === live.timestamp);
21217
- if (!turn || turn.input.length !== 0 || !matches) {
22093
+ const matches = snapshot.turns.filter((turn2) => {
22094
+ if (turn2.input.length !== 0)
22095
+ return false;
22096
+ const start = entries.findIndex((entry) => entry.id === turn2.nativeTurnRef.nativeTurnKey);
22097
+ const firstAssistant = entries.slice(start + 1).find((entry) => isRecord9(entry.message) && entry.message.role === "assistant")?.message;
22098
+ return isRecord9(firstAssistant) && (responseId ? assistantMessageId(firstAssistant) === responseId : typeof live?.timestamp === "number" && firstAssistant.timestamp === live.timestamp);
22099
+ });
22100
+ const turn = matches.length === 1 ? matches[0] : void 0;
22101
+ if (!turn)
21218
22102
  throw new PiRpcFaultError("protocolError", "Pi autonomous Turn has no matching persisted custom Entry");
21219
- }
21220
22103
  active.nativeTurnKey = turn.nativeTurnRef.nativeTurnKey;
21221
22104
  }
21222
- if (this.#activeTurn !== active)
22105
+ if (!this.#isSettlementCurrent(active, generation))
21223
22106
  return;
21224
22107
  this.#state = state2;
21225
22108
  active.settlement = "confirmed";
@@ -21245,7 +22128,13 @@ var PiRpcSession = class {
21245
22128
  }
21246
22129
  this.#activeTurn = null;
21247
22130
  if (active.origin === "autonomous") {
21248
- if (active.failure) {
22131
+ if (active.cancellation === "accepted") {
22132
+ this.#emitAutonomousTurn(active, {
22133
+ status: "cancelled",
22134
+ text: active.text,
22135
+ reason: "Cancelled by user"
22136
+ });
22137
+ } else if (active.failure) {
21249
22138
  this.#emitAutonomousTurn(active, active.nativeCancellationObserved ? {
21250
22139
  status: "cancelled",
21251
22140
  text: active.text,
@@ -21260,6 +22149,7 @@ var PiRpcSession = class {
21260
22149
  } else {
21261
22150
  this.#emitAutonomousTurn(active, { status: "succeeded", text: active.text });
21262
22151
  }
22152
+ this.#drainDeferredRunFrames();
21263
22153
  return;
21264
22154
  }
21265
22155
  if (active.cancellation === "accepted") {
@@ -21271,20 +22161,56 @@ var PiRpcSession = class {
21271
22161
  } else {
21272
22162
  active.resolve({ text: active.text, cancelled: false });
21273
22163
  }
22164
+ this.#drainDeferredRunFrames();
22165
+ }
22166
+ #emitContent(active, reasoning, delta) {
22167
+ if (delta.length === 0)
22168
+ return;
22169
+ const messageId = active.assistantMessageId;
22170
+ if (messageId === null)
22171
+ throw new Error("Pi content arrived outside an Assistant message");
22172
+ if (reasoning) {
22173
+ active.reasoningMessageOpen = true;
22174
+ active.sawStreamedMessageReasoning = true;
22175
+ } else {
22176
+ active.text += delta;
22177
+ active.sawStreamedMessageText = true;
22178
+ }
22179
+ active.onEvent({
22180
+ type: reasoning ? "reasoning.delta" : "text.delta",
22181
+ messageId,
22182
+ ...nativeMessageIdentity(active),
22183
+ delta
22184
+ });
21274
22185
  }
21275
22186
  #startAssistantMessage(active, value) {
22187
+ if (active.origin === "autonomous" && !active.autonomousMessage && isRecord9(value))
22188
+ active.autonomousMessage = value;
21276
22189
  if (active.assistantMessageId !== null && active.reasoningMessageOpen) {
21277
22190
  active.onEvent({ type: "reasoning.completed", messageId: active.assistantMessageId });
21278
22191
  }
21279
- const messageId = assistantMessageId(value) ?? randomUUID5();
22192
+ const nativeResponseId = assistantMessageId(value);
22193
+ const messageId = nativeResponseId ?? randomUUID6();
21280
22194
  active.assistantMessageId = messageId;
22195
+ active.assistantNativeMessageIdentity = piMessageIdentity(this.state.sessionId, value, this.#messageTimestampCounts);
22196
+ active.textStream = new PiContentStream("text");
22197
+ active.reasoningStream = new PiContentStream("reasoning");
21281
22198
  active.sawStreamedMessageText = false;
21282
22199
  active.sawStreamedMessageReasoning = false;
21283
22200
  active.reasoningMessageOpen = false;
21284
22201
  return messageId;
21285
22202
  }
21286
22203
  #ensureAssistantMessage(active, value) {
21287
- return active.assistantMessageId ?? this.#startAssistantMessage(active, value);
22204
+ if (active.assistantMessageId === null)
22205
+ return this.#startAssistantMessage(active, value);
22206
+ if (!active.sawStreamedMessageText && !active.sawStreamedMessageReasoning) {
22207
+ const nativeResponseId = assistantMessageId(value);
22208
+ if (nativeResponseId) {
22209
+ active.assistantMessageId = nativeResponseId;
22210
+ active.assistantNativeMessageIdentity ??= { responseId: nativeResponseId };
22211
+ }
22212
+ }
22213
+ return active.assistantMessageId;
21288
22214
  }
21289
22215
  #finalizeAssistantMessage(active, value) {
21290
22216
  const finalText = assistantText(value);
@@ -21297,29 +22223,33 @@ var PiRpcSession = class {
21297
22223
  return;
21298
22224
  }
21299
22225
  active.failure = failure;
21300
- if (active.origin === "autonomous" && isRecord8(value) && value.stopReason === "aborted") {
22226
+ if (active.origin === "autonomous" && piAssistantWasAborted(value)) {
21301
22227
  active.nativeCancellationObserved = true;
21302
22228
  }
21303
22229
  this.#latestCacheHitRatePercent = cacheHitRatePercent;
21304
22230
  const messageId = this.#ensureAssistantMessage(active, value);
21305
- if (!active.sawStreamedMessageReasoning && finalReasoning.length > 0) {
21306
- active.reasoningMessageOpen = true;
21307
- active.onEvent({ type: "reasoning.delta", messageId, delta: finalReasoning });
22231
+ const content = value.content;
22232
+ if (failure === null || !active.sawStreamedMessageReasoning) {
22233
+ this.#emitContent(active, true, active.reasoningStream.finalize(content.flatMap((part, index) => {
22234
+ const text3 = extractReasoningText(part);
22235
+ return text3 === null ? [] : [{ index, text: text3 }];
22236
+ })));
21308
22237
  }
21309
22238
  if (active.reasoningMessageOpen && active.failure === null) {
21310
22239
  active.onEvent({ type: "reasoning.completed", messageId });
21311
22240
  }
21312
- if (!active.sawStreamedMessageText && finalText.length > 0) {
21313
- active.text += finalText;
21314
- active.onEvent({ type: "text.delta", messageId, delta: finalText });
22241
+ if (failure === null || !active.sawStreamedMessageText) {
22242
+ this.#emitContent(active, false, active.textStream.finalize(content.flatMap((part, index) => isRecord9(part) && part.type === "text" && typeof part.text === "string" ? [{ index, text: part.text }] : [])));
21315
22243
  }
21316
22244
  active.assistantMessageId = null;
22245
+ active.assistantNativeMessageIdentity = void 0;
21317
22246
  active.sawStreamedMessageText = false;
21318
22247
  active.sawStreamedMessageReasoning = false;
21319
22248
  active.reasoningMessageOpen = false;
21320
22249
  active.lastFinalizedMessageText = finalText;
21321
22250
  active.lastFinalizedMessageReasoning = finalReasoning;
21322
- active.onEvent({ type: "message.completed", messageId });
22251
+ const phase = piAssistantPhase(value);
22252
+ active.onEvent({ type: "message.completed", messageId, ...phase ? { phase } : {} });
21323
22253
  }
21324
22254
  #write(value) {
21325
22255
  const child = this.#child;
@@ -21337,7 +22267,7 @@ var PiRpcSession = class {
21337
22267
  if (!child?.stdin.writable || this.#closed || this.#failed) {
21338
22268
  return Promise.reject(new Error("Pi RPC stdin is unavailable"));
21339
22269
  }
21340
- const id = `codexhost-${randomUUID5()}`;
22270
+ const id = `codexhost-${randomUUID6()}`;
21341
22271
  return new Promise((resolve, reject) => {
21342
22272
  const pending = {
21343
22273
  command: type,
@@ -21427,9 +22357,16 @@ var PiRpcSession = class {
21427
22357
  } else {
21428
22358
  active.reject(error51);
21429
22359
  }
22360
+ this.#drainDeferredRunFrames();
21430
22361
  }
21431
22362
  #rejectAll(error51) {
22363
+ for (const waiter of this.#runWaiters)
22364
+ waiter.reject(error51);
22365
+ this.#deferredRunFrames = [];
22366
+ this.#deferredRunBytes = 0;
21432
22367
  this.#subagents.close(error51);
22368
+ this.#gotgenesHandler = void 0;
22369
+ this.#gotgenesLatest = void 0;
21433
22370
  for (const pending of this.#pending.values()) {
21434
22371
  if (pending.timeout)
21435
22372
  clearTimeout(pending.timeout);
@@ -21465,7 +22402,7 @@ var piCommandCatalog = harnessCommandCatalogSchema.parse({
21465
22402
  ]
21466
22403
  });
21467
22404
  var DEFAULT_TOOL_OUTPUT_LIMIT = 64e3;
21468
- function isRecord9(value) {
22405
+ function isRecord10(value) {
21469
22406
  return typeof value === "object" && value !== null && !Array.isArray(value);
21470
22407
  }
21471
22408
  function errorMessage(error51) {
@@ -21480,7 +22417,9 @@ var PiAdapterFaultError = class extends Error {
21480
22417
  }
21481
22418
  };
21482
22419
  function normalizedError(error51, fallbackCode) {
21483
- if (isRecord9(error51) && error51.code === "ENOENT") {
22420
+ if (error51 instanceof PiRpcBusyError)
22421
+ return { code: "sessionBusy", message: error51.message, retryable: true };
22422
+ if (isRecord10(error51) && error51.code === "ENOENT") {
21484
22423
  return { code: "notInstalled", message: errorMessage(error51), retryable: false };
21485
22424
  }
21486
22425
  if (error51 instanceof PiAdapterFaultError)
@@ -21543,7 +22482,7 @@ function nativeModelForHistory(state2) {
21543
22482
  return nativeModelFromState(state2);
21544
22483
  }
21545
22484
  function sessionFileFromRef(ref) {
21546
- if (ref.harnessId !== piHarnessId2 || !isRecord9(ref.locator) || typeof ref.locator.sessionFile !== "string" || ref.locator.sessionFile.length === 0) {
22485
+ if (ref.harnessId !== piHarnessId2 || !isRecord10(ref.locator) || typeof ref.locator.sessionFile !== "string" || ref.locator.sessionFile.length === 0) {
21547
22486
  throw new Error("Pi Native Session Ref has no resumable Session file");
21548
22487
  }
21549
22488
  return ref.locator.sessionFile;
@@ -21558,83 +22497,29 @@ function toolFailure(toolName) {
21558
22497
  function nativeText(value) {
21559
22498
  if (typeof value === "string")
21560
22499
  return value;
21561
- if (!isRecord9(value) || !Array.isArray(value.content))
22500
+ if (!isRecord10(value) || !Array.isArray(value.content))
21562
22501
  return "";
21563
- return value.content.filter((content) => isRecord9(content) && content.type === "text" && typeof content.text === "string").map(({ text: text2 }) => text2).join("");
22502
+ return value.content.filter((content) => isRecord10(content) && content.type === "text" && typeof content.text === "string").map(({ text: text3 }) => text3).join("");
21564
22503
  }
21565
22504
  function boundedOutput(value, limit) {
21566
- const text2 = nativeText(value);
21567
- if (text2.length === 0)
22505
+ const text3 = nativeText(value);
22506
+ if (text3.length === 0)
21568
22507
  return void 0;
21569
- const truncated = text2.length > limit;
22508
+ const truncated = text3.length > limit;
21570
22509
  return {
21571
- content: [{ type: "text", text: truncated ? text2.slice(0, limit) : text2 }],
22510
+ content: [{ type: "text", text: truncated ? text3.slice(0, limit) : text3 }],
21572
22511
  ...truncated ? { truncated: true } : {}
21573
22512
  };
21574
22513
  }
21575
22514
  function outputText(output) {
21576
- return output?.content.filter((content) => content.type === "text").map(({ text: text2 }) => text2).join("") ?? "";
21577
- }
21578
- function stringField(value, key) {
21579
- if (!isRecord9(value))
21580
- return void 0;
21581
- const field2 = value[key];
21582
- if (typeof field2 === "string" && field2.length > 0)
21583
- return field2;
21584
- if (isRecord9(value.input)) {
21585
- const nested = value.input[key];
21586
- if (typeof nested === "string" && nested.length > 0)
21587
- return nested;
21588
- }
21589
- if (isRecord9(value.arguments)) {
21590
- const nested = value.arguments[key];
21591
- if (typeof nested === "string" && nested.length > 0)
21592
- return nested;
21593
- }
21594
- return void 0;
22515
+ return output?.content.filter((content) => content.type === "text").map(({ text: text3 }) => text3).join("") ?? "";
21595
22516
  }
21596
22517
  function numberField(value, key) {
21597
- if (!isRecord9(value))
22518
+ if (!isRecord10(value))
21598
22519
  return void 0;
21599
22520
  const field2 = value[key];
21600
22521
  return typeof field2 === "number" || field2 === null ? field2 : void 0;
21601
22522
  }
21602
- function normalizeToolName(name) {
21603
- const lower = name.toLowerCase();
21604
- switch (lower) {
21605
- case "bash":
21606
- case "exec":
21607
- case "terminal":
21608
- case "run":
21609
- return "bash";
21610
- case "read":
21611
- case "read_file":
21612
- case "fileread":
21613
- return "Read";
21614
- case "edit":
21615
- case "edit_file":
21616
- case "fileedit":
21617
- return "Edit";
21618
- case "write":
21619
- case "write_file":
21620
- case "filewrite":
21621
- return "Write";
21622
- case "grep":
21623
- case "grep_search":
21624
- return "Grep";
21625
- case "find":
21626
- case "glob":
21627
- case "find_files":
21628
- return "Glob";
21629
- case "todo":
21630
- return "Todo";
21631
- case "web_search":
21632
- case "websearch":
21633
- return "WebSearch";
21634
- default:
21635
- return name.length > 0 ? `${name[0]?.toUpperCase() ?? ""}${name.slice(1)}` : name;
21636
- }
21637
- }
21638
22523
  function delay(milliseconds) {
21639
22524
  return new Promise((resolve) => setTimeout(resolve, milliseconds));
21640
22525
  }
@@ -21662,6 +22547,8 @@ var PiHarnessSession = class {
21662
22547
  #configuring = false;
21663
22548
  #phase = "open";
21664
22549
  #pendingAutonomousTurns = [];
22550
+ #pendingAutonomousLifecycle = [];
22551
+ #pendingAutonomousLifecycleBytes = 0;
21665
22552
  #starting = null;
21666
22553
  #state = {};
21667
22554
  #transport = null;
@@ -21710,13 +22597,20 @@ var PiHarnessSession = class {
21710
22597
  return this.#transport?.state.sessionId === id;
21711
22598
  }
21712
22599
  async readSubagentHistory(cwd) {
21713
- if (this.#phase !== "open" || path15.resolve(cwd) !== path15.resolve(this.#cwd)) {
22600
+ if (this.#phase !== "open" || path16.resolve(cwd) !== path16.resolve(this.#cwd)) {
21714
22601
  throw new Error("Pi Subagent parent workspace or Session is unavailable");
21715
22602
  }
21716
22603
  return (await this.#ensureTransport()).getEntries();
21717
22604
  }
22605
+ async readGotgenesChild(id, cwd) {
22606
+ const history = await this.readSubagentHistory(cwd);
22607
+ const transport = this.#transport;
22608
+ if (!transport)
22609
+ throw new Error("Pi parent Session is closed");
22610
+ return readGotgenesChild(history, transport.state.sessionId, id, this.#subagents.gotgenes.records.get(id));
22611
+ }
21718
22612
  async inspectSubagent(id, cwd) {
21719
- if (this.#phase !== "open" || path15.resolve(cwd) !== path15.resolve(this.#cwd)) {
22613
+ if (this.#phase !== "open" || path16.resolve(cwd) !== path16.resolve(this.#cwd)) {
21720
22614
  throw new Error("Pi Subagent parent workspace or Session is unavailable");
21721
22615
  }
21722
22616
  const transport = await this.#ensureTransport();
@@ -21784,7 +22678,7 @@ var PiHarnessSession = class {
21784
22678
  }
21785
22679
  };
21786
22680
  }
21787
- if (this.#acceptingTurn || this.#active || this.#configuring) {
22681
+ if (this.#acceptingTurn || this.#active || this.#configuring || this.#transport?.isBusy) {
21788
22682
  return {
21789
22683
  ok: false,
21790
22684
  error: {
@@ -21794,8 +22688,8 @@ var PiHarnessSession = class {
21794
22688
  }
21795
22689
  };
21796
22690
  }
21797
- const text2 = command.input.map((input) => input.text).join("\n");
21798
- if (text2.length === 0) {
22691
+ const text3 = command.input.map((input) => input.text).join("\n");
22692
+ if (text3.length === 0) {
21799
22693
  return {
21800
22694
  ok: false,
21801
22695
  error: {
@@ -21825,6 +22719,9 @@ var PiHarnessSession = class {
21825
22719
  } catch (error51) {
21826
22720
  return { ok: false, error: normalizedError(error51, "protocolError") };
21827
22721
  }
22722
+ if (this.#active || transport.isBusy || this.#pendingAutonomousLifecycle.length > 0 || this.#pendingAutonomousTurns.length > 0) {
22723
+ return { ok: false, error: normalizedError(new PiRpcBusyError(), "sessionBusy") };
22724
+ }
21828
22725
  let resolveCompletion = () => void 0;
21829
22726
  const completion = new Promise((resolve) => {
21830
22727
  resolveCompletion = resolve;
@@ -21845,21 +22742,27 @@ var PiHarnessSession = class {
21845
22742
  interactions: /* @__PURE__ */ new Map(),
21846
22743
  interactionByNativeId: /* @__PURE__ */ new Map(),
21847
22744
  cancellationRequested: false,
22745
+ settling: false,
21848
22746
  beforeNativeTurnKeys: new Set(beforeHistory.turns.map((turn) => turn.nativeTurnRef.nativeTurnKey)),
22747
+ progressItems: /* @__PURE__ */ new Set(),
21849
22748
  completion,
21850
22749
  resolveCompletion
21851
22750
  };
21852
22751
  this.#active = active;
21853
22752
  this.#event({ type: "turn.started", turnId: command.turnId });
21854
22753
  this.#event({ type: "item.started", turnId: command.turnId, item });
21855
- void transport.runTurn(text2, (event) => this.#handleTurnEvent(active, event)).then(async (result) => {
22754
+ void transport.runTurn(text3, (event) => this.#handleTurnEvent(active, event)).then(async (result) => {
22755
+ active.settling = true;
21856
22756
  try {
21857
22757
  const identity = await this.#completedTurnIdentity(active, transport);
21858
22758
  this.#completeTurn(active, result.cancelled ? {
21859
22759
  status: "cancelled",
21860
22760
  reason: "Cancelled by user",
21861
- checkpoint: identity.checkpoint
21862
- } : { status: "succeeded", checkpoint: identity.checkpoint }, result.text, identity.nativeTurnRef);
22761
+ ...identity.checkpoint ? { checkpoint: identity.checkpoint } : {}
22762
+ } : {
22763
+ status: "succeeded",
22764
+ ...identity.checkpoint ? { checkpoint: identity.checkpoint } : {}
22765
+ }, result.text, identity.nativeTurnRef);
21863
22766
  } catch (error51) {
21864
22767
  this.#completeTurn(active, {
21865
22768
  status: "failed",
@@ -21867,6 +22770,7 @@ var PiHarnessSession = class {
21867
22770
  });
21868
22771
  }
21869
22772
  }).catch(async (error51) => {
22773
+ active.settling = true;
21870
22774
  let identity;
21871
22775
  try {
21872
22776
  identity = await this.#completedTurnIdentity(active, transport);
@@ -21875,12 +22779,14 @@ var PiHarnessSession = class {
21875
22779
  this.#completeTurn(active, {
21876
22780
  status: "failed",
21877
22781
  error: normalizedError(error51, "nativeFailure"),
21878
- ...identity ? { checkpoint: identity.checkpoint } : {}
22782
+ ...identity?.checkpoint ? { checkpoint: identity.checkpoint } : {}
21879
22783
  }, void 0, identity?.nativeTurnRef);
21880
22784
  });
21881
22785
  return { ok: true, value: { turnId: command.turnId } };
21882
22786
  } finally {
21883
22787
  this.#acceptingTurn = false;
22788
+ if (this.#transport)
22789
+ this.#drainPendingAutonomousTurns(this.#transport);
21884
22790
  }
21885
22791
  }
21886
22792
  close() {
@@ -22008,6 +22914,8 @@ var PiHarnessSession = class {
22008
22914
  return { ok: true, value: { completed: true } };
22009
22915
  } finally {
22010
22916
  this.#configuring = false;
22917
+ if (this.#transport)
22918
+ this.#drainPendingAutonomousTurns(this.#transport);
22011
22919
  }
22012
22920
  }
22013
22921
  async #selectThinking(command) {
@@ -22082,6 +22990,8 @@ var PiHarnessSession = class {
22082
22990
  return { ok: true, value: { completed: true } };
22083
22991
  } finally {
22084
22992
  this.#configuring = false;
22993
+ if (this.#transport)
22994
+ this.#drainPendingAutonomousTurns(this.#transport);
22085
22995
  }
22086
22996
  }
22087
22997
  async #cancel(command) {
@@ -22092,6 +23002,12 @@ var PiHarnessSession = class {
22092
23002
  error: invalidState("Pi Turn Cancel must reference the active Turn")
22093
23003
  };
22094
23004
  }
23005
+ if (active.settling) {
23006
+ return {
23007
+ ok: false,
23008
+ error: invalidState("Pi Turn has finished native execution and is recording its completion")
23009
+ };
23010
+ }
22095
23011
  if (active.cancellationRequested) {
22096
23012
  return { ok: true, value: { cancellationRequested: true } };
22097
23013
  }
@@ -22206,7 +23122,9 @@ var PiHarnessSession = class {
22206
23122
  interactions: /* @__PURE__ */ new Map(),
22207
23123
  interactionByNativeId: /* @__PURE__ */ new Map(),
22208
23124
  cancellationRequested: false,
23125
+ settling: false,
22209
23126
  beforeNativeTurnKeys: /* @__PURE__ */ new Set(),
23127
+ progressItems: /* @__PURE__ */ new Set(),
22210
23128
  completion,
22211
23129
  resolveCompletion
22212
23130
  };
@@ -22239,6 +23157,8 @@ var PiHarnessSession = class {
22239
23157
  return { ok: true, value: { turnId: command.turnId } };
22240
23158
  } finally {
22241
23159
  this.#acceptingTurn = false;
23160
+ if (this.#transport)
23161
+ this.#drainPendingAutonomousTurns(this.#transport);
22242
23162
  }
22243
23163
  }
22244
23164
  async #ensureTransport() {
@@ -22289,6 +23209,8 @@ var PiHarnessSession = class {
22289
23209
  return transport;
22290
23210
  }).catch(async (error51) => {
22291
23211
  this.#pendingAutonomousTurns = this.#pendingAutonomousTurns.filter((pending) => pending.transport !== transport);
23212
+ this.#pendingAutonomousLifecycle = this.#pendingAutonomousLifecycle.filter((pending) => pending.transport !== transport);
23213
+ this.#pendingAutonomousLifecycleBytes = this.#pendingAutonomousLifecycle.reduce((total, pending) => total + pending.bytes, 0);
22292
23214
  await transport.close().catch(() => void 0);
22293
23215
  if (this.#phase === "open")
22294
23216
  this.#fault(error51);
@@ -22301,6 +23223,11 @@ var PiHarnessSession = class {
22301
23223
  return starting;
22302
23224
  }
22303
23225
  #bindAutonomousTurnHandler(transport) {
23226
+ transport.setGotgenesStatusHandler?.((records, owner) => {
23227
+ if (this.#phase !== "open")
23228
+ return;
23229
+ this.#subagents.observeGotgenes(records, owner === "requested" && this.#active && !this.#active.settling ? { turnId: this.#active.command.turnId, nextItemId: () => this.#newItemId() } : void 0);
23230
+ });
22304
23231
  transport.setSubagentStatusHandler?.((runs) => {
22305
23232
  if (this.#phase !== "open")
22306
23233
  return;
@@ -22312,12 +23239,16 @@ var PiHarnessSession = class {
22312
23239
  transport.setUsageHandler?.((observation) => {
22313
23240
  if (this.#phase !== "open")
22314
23241
  return;
22315
- const record7 = piUsageRecord(observation.message, observation);
22316
- if (record7?.kind === "request")
22317
- this.#event({ type: "usage.request", request: record7.request });
22318
- else if (record7?.kind === "missing")
23242
+ const record9 = piUsageRecord(observation.message, observation);
23243
+ if (record9?.kind === "request")
23244
+ this.#event({ type: "usage.request", request: record9.request });
23245
+ else if (record9?.kind === "missing")
22319
23246
  this.#event({ type: "usage.history", complete: false });
22320
23247
  });
23248
+ if (transport.setAutonomousTurnLifecycleHandler) {
23249
+ transport.setAutonomousTurnLifecycleHandler((update) => this.#handleAutonomousLifecycle(transport, update));
23250
+ return;
23251
+ }
22321
23252
  transport.setAutonomousTurnHandler((turn) => {
22322
23253
  if (this.#phase !== "open")
22323
23254
  return;
@@ -22329,6 +23260,20 @@ var PiHarnessSession = class {
22329
23260
  });
22330
23261
  }
22331
23262
  #drainPendingAutonomousTurns(transport) {
23263
+ if (this.#phase !== "open" || this.#acceptingTurn || this.#configuring)
23264
+ return;
23265
+ for (; ; ) {
23266
+ const pending2 = this.#pendingAutonomousLifecycle[0];
23267
+ if (!pending2 || pending2.transport !== transport || this.#active && this.#active.autonomousRunId !== pending2.update.runId)
23268
+ break;
23269
+ this.#pendingAutonomousLifecycle.shift();
23270
+ this.#pendingAutonomousLifecycleBytes -= pending2.bytes;
23271
+ this.#applyAutonomousLifecycle(transport, pending2.update);
23272
+ if (this.#phase !== "open")
23273
+ return;
23274
+ }
23275
+ if (this.#active)
23276
+ return;
22332
23277
  if (this.#pendingSubagentStatus) {
22333
23278
  this.#subagents.observe(this.#pendingSubagentStatus);
22334
23279
  this.#pendingSubagentStatus = null;
@@ -22341,6 +23286,52 @@ var PiHarnessSession = class {
22341
23286
  this.#handleAutonomousTurn(transport, candidate.turn);
22342
23287
  }
22343
23288
  }
23289
+ #handleAutonomousLifecycle(transport, update) {
23290
+ if (this.#phase === "closing" && this.#transport === transport && update.type !== "started" && this.#active?.autonomousRunId === update.runId) {
23291
+ this.#applyAutonomousLifecycle(transport, update);
23292
+ return;
23293
+ }
23294
+ if (this.#phase !== "open")
23295
+ return;
23296
+ if (this.#transport !== transport || this.#acceptingTurn || this.#configuring || this.#pendingAutonomousLifecycle.length > 0 || this.#active && this.#active.autonomousRunId !== update.runId) {
23297
+ const bytes = Buffer.byteLength(JSON.stringify(update));
23298
+ if (this.#pendingAutonomousLifecycleBytes + bytes > 8 * 1024 * 1024) {
23299
+ this.#fault(new PiAdapterFaultError({
23300
+ code: "protocolError",
23301
+ message: "Pi autonomous lifecycle exceeded its ordered event buffer bound",
23302
+ retryable: false
23303
+ }));
23304
+ return;
23305
+ }
23306
+ this.#pendingAutonomousLifecycle.push({ transport, update, bytes });
23307
+ this.#pendingAutonomousLifecycleBytes += bytes;
23308
+ if (this.#transport === transport)
23309
+ this.#drainPendingAutonomousTurns(transport);
23310
+ return;
23311
+ }
23312
+ this.#applyAutonomousLifecycle(transport, update);
23313
+ }
23314
+ #applyAutonomousLifecycle(transport, update) {
23315
+ if (update.type === "started" && !this.#active) {
23316
+ this.#startAutonomousHostTurn(update.runId);
23317
+ return;
23318
+ }
23319
+ const active = this.#active;
23320
+ if (!active || active.autonomousRunId !== update.runId || update.type === "started") {
23321
+ this.#fault(new PiAdapterFaultError({
23322
+ code: "protocolError",
23323
+ message: "Pi autonomous event has no matching active run",
23324
+ retryable: false
23325
+ }));
23326
+ return;
23327
+ }
23328
+ if (update.type === "event")
23329
+ this.#handleTurnEvent(active, update.event);
23330
+ else {
23331
+ active.settling = true;
23332
+ this.#finishAutonomousHostTurn(transport, active, update.turn);
23333
+ }
23334
+ }
22344
23335
  #handleAutonomousTurn(transport, turn) {
22345
23336
  if (this.#phase !== "open")
22346
23337
  return;
@@ -22352,7 +23343,7 @@ var PiHarnessSession = class {
22352
23343
  }));
22353
23344
  return;
22354
23345
  }
22355
- if (this.#active || this.#acceptingTurn || this.#configuring) {
23346
+ if (this.#active && !this.#active.settling) {
22356
23347
  this.#fault(new PiAdapterFaultError({
22357
23348
  code: "protocolError",
22358
23349
  message: "Pi autonomous Turn overlapped another Host operation",
@@ -22360,7 +23351,22 @@ var PiHarnessSession = class {
22360
23351
  }));
22361
23352
  return;
22362
23353
  }
22363
- const turnId = hostTurnIdSchema.parse(randomUUID6());
23354
+ if (this.#active || this.#acceptingTurn || this.#configuring) {
23355
+ if (this.#pendingAutonomousTurns.length >= 128) {
23356
+ this.#fault(new PiAdapterFaultError({
23357
+ code: "protocolError",
23358
+ message: "Pi autonomous completion queue exceeded its bound",
23359
+ retryable: false
23360
+ }));
23361
+ } else
23362
+ this.#pendingAutonomousTurns.push({ transport, turn });
23363
+ return;
23364
+ }
23365
+ const active = this.#startAutonomousHostTurn();
23366
+ this.#finishAutonomousHostTurn(transport, active, turn);
23367
+ }
23368
+ #startAutonomousHostTurn(runId) {
23369
+ const turnId = hostTurnIdSchema.parse(randomUUID7());
22364
23370
  let resolveCompletion = () => void 0;
22365
23371
  const completion = new Promise((resolve) => {
22366
23372
  resolveCompletion = resolve;
@@ -22372,6 +23378,7 @@ var PiHarnessSession = class {
22372
23378
  };
22373
23379
  const active = {
22374
23380
  command: { type: "turn.start", turnId, input: [] },
23381
+ ...runId ? { autonomousRunId: runId } : {},
22375
23382
  agentItem: item,
22376
23383
  agentMessageId: null,
22377
23384
  compactionItem: null,
@@ -22381,10 +23388,19 @@ var PiHarnessSession = class {
22381
23388
  interactions: /* @__PURE__ */ new Map(),
22382
23389
  interactionByNativeId: /* @__PURE__ */ new Map(),
22383
23390
  cancellationRequested: false,
23391
+ settling: false,
22384
23392
  beforeNativeTurnKeys: /* @__PURE__ */ new Set(),
23393
+ progressItems: /* @__PURE__ */ new Set(),
22385
23394
  completion,
22386
23395
  resolveCompletion
22387
23396
  };
23397
+ this.#active = active;
23398
+ this.#event({ type: "turn.autonomous.started", turnId, input: [] });
23399
+ this.#event({ type: "turn.started", turnId });
23400
+ this.#event({ type: "item.started", turnId, item });
23401
+ return active;
23402
+ }
23403
+ #finishAutonomousHostTurn(transport, active, turn) {
22388
23404
  const nativeTurnRef = turn.nativeTurnKey ? nativeTurnRefSchema.parse({
22389
23405
  harnessId: this.harnessId,
22390
23406
  nativeSessionId: transport.state.sessionId,
@@ -22397,10 +23413,6 @@ var PiHarnessSession = class {
22397
23413
  checkpointId: nativeTurnRef.nativeTurnKey,
22398
23414
  formatVersion: 1
22399
23415
  }) : void 0;
22400
- this.#active = active;
22401
- this.#event({ type: "turn.autonomous.started", turnId, input: [] });
22402
- this.#event({ type: "turn.started", turnId });
22403
- this.#event({ type: "item.started", turnId, item });
22404
23416
  try {
22405
23417
  for (const event of turn.events)
22406
23418
  this.#handleTurnEvent(active, event);
@@ -22470,17 +23482,35 @@ var PiHarnessSession = class {
22470
23482
  if (this.#active !== active || this.#phase === "closed" || this.#phase === "faulted")
22471
23483
  return;
22472
23484
  switch (event.type) {
23485
+ case "progress.message": {
23486
+ if (active.progressItems.has(event.itemId))
23487
+ return;
23488
+ active.progressItems.add(event.itemId);
23489
+ const item = {
23490
+ type: "agentMessage",
23491
+ itemId: event.itemId,
23492
+ text: event.text,
23493
+ phase: "commentary"
23494
+ };
23495
+ this.#event({ type: "item.started", turnId: active.command.turnId, item });
23496
+ this.#completeItem(active, item, { status: "succeeded" });
23497
+ return;
23498
+ }
22473
23499
  case "text.delta":
22474
- this.#activateAgentMessage(active, event.messageId);
23500
+ this.#activateAgentMessage(active, event.messageId, event.nativeMessageIdentity);
23501
+ active.sawAssistantMessage = true;
22475
23502
  this.#appendText(active, event.delta);
22476
23503
  return;
22477
23504
  case "reasoning.delta":
22478
- this.#appendReasoning(active, event.delta);
23505
+ this.#activateAgentMessage(active, event.messageId, event.nativeMessageIdentity);
23506
+ this.#appendReasoning(active, event.delta, event.nativeMessageIdentity);
22479
23507
  return;
22480
23508
  case "reasoning.completed":
22481
23509
  this.#completeReasoning(active, { status: "succeeded" });
22482
23510
  return;
22483
23511
  case "message.completed":
23512
+ if (event.phase && active.agentMessageId === event.messageId && active.agentItem)
23513
+ active.agentItem = { ...active.agentItem, phase: event.phase };
22484
23514
  void this.#refreshUsage(active.command.turnId);
22485
23515
  return;
22486
23516
  case "compaction.started":
@@ -22538,7 +23568,7 @@ var PiHarnessSession = class {
22538
23568
  if (active.interactionByNativeId.has(request.requestId)) {
22539
23569
  throw new Error("Pi Interaction started more than once");
22540
23570
  }
22541
- const interactionId = hostInteractionIdSchema.parse(randomUUID6());
23571
+ const interactionId = hostInteractionIdSchema.parse(randomUUID7());
22542
23572
  const question = request.method === "select" ? {
22543
23573
  id: "answer",
22544
23574
  type: "choice",
@@ -22595,17 +23625,21 @@ var PiHarnessSession = class {
22595
23625
  reason
22596
23626
  });
22597
23627
  }
22598
- #activateAgentMessage(active, messageId) {
23628
+ #activateAgentMessage(active, messageId, nativeMessageIdentity2) {
22599
23629
  if (active.agentMessageId === messageId)
22600
23630
  return;
23631
+ const nativeItemId = piMessageItemId(nativeMessageIdentity2, "assistant");
23632
+ if (nativeItemId && active.agentMessageId === null && active.agentItem?.text === "") {
23633
+ this.#completeAgentItem(active, { status: "succeeded" }, true);
23634
+ }
22601
23635
  if (active.agentMessageId !== null) {
22602
23636
  this.#completeReasoning(active, { status: "succeeded" });
22603
- this.#completeAgentItem(active, { status: "succeeded" }, false);
23637
+ this.#completeAgentItem(active, { status: "succeeded" }, true);
22604
23638
  }
22605
23639
  if (!active.agentItem) {
22606
23640
  active.agentItem = {
22607
23641
  type: "agentMessage",
22608
- itemId: this.#newItemId(),
23642
+ itemId: nativeItemId ?? this.#newItemId(),
22609
23643
  text: ""
22610
23644
  };
22611
23645
  this.#event({
@@ -22615,18 +23649,17 @@ var PiHarnessSession = class {
22615
23649
  });
22616
23650
  }
22617
23651
  active.agentMessageId = messageId;
22618
- active.sawAssistantMessage = true;
22619
23652
  }
22620
- #appendText(active, text2) {
23653
+ #appendText(active, text3) {
22621
23654
  if (active.agentMessageId === null || !active.agentItem) {
22622
23655
  throw new Error("Pi Assistant text arrived outside an active message");
22623
23656
  }
22624
- active.agentItem = { ...active.agentItem, text: active.agentItem.text + text2 };
23657
+ active.agentItem = { ...active.agentItem, text: active.agentItem.text + text3 };
22625
23658
  this.#event({
22626
23659
  type: "item.updated",
22627
23660
  turnId: active.command.turnId,
22628
23661
  itemId: active.agentItem.itemId,
22629
- update: { type: "text.append", text: text2 }
23662
+ update: { type: "text.append", text: text3 }
22630
23663
  });
22631
23664
  }
22632
23665
  #completeAgentItem(active, outcome, completeEmpty) {
@@ -22637,13 +23670,13 @@ var PiHarnessSession = class {
22637
23670
  active.agentItem = null;
22638
23671
  this.#completeItem(active, item, outcome);
22639
23672
  }
22640
- #appendReasoning(active, text2) {
22641
- if (text2.length === 0)
23673
+ #appendReasoning(active, text3, nativeMessageIdentity2) {
23674
+ if (text3.length === 0)
22642
23675
  return;
22643
23676
  if (!active.reasoningItem) {
22644
23677
  active.reasoningItem = {
22645
23678
  type: "reasoning",
22646
- itemId: this.#newItemId(),
23679
+ itemId: piMessageItemId(nativeMessageIdentity2, "reasoning") ?? this.#newItemId(),
22647
23680
  text: ""
22648
23681
  };
22649
23682
  this.#event({
@@ -22654,13 +23687,13 @@ var PiHarnessSession = class {
22654
23687
  }
22655
23688
  active.reasoningItem = {
22656
23689
  ...active.reasoningItem,
22657
- text: active.reasoningItem.text + text2
23690
+ text: active.reasoningItem.text + text3
22658
23691
  };
22659
23692
  this.#event({
22660
23693
  type: "item.updated",
22661
23694
  turnId: active.command.turnId,
22662
23695
  itemId: active.reasoningItem.itemId,
22663
- update: { type: "text.append", text: text2 }
23696
+ update: { type: "text.append", text: text3 }
22664
23697
  });
22665
23698
  }
22666
23699
  #completeReasoning(active, outcome) {
@@ -22673,13 +23706,12 @@ var PiHarnessSession = class {
22673
23706
  #startTool(active, event) {
22674
23707
  if (active.tools.has(event.callId))
22675
23708
  throw new Error("Pi Tool started more than once");
22676
- const normalizedName = normalizeToolName(event.toolName);
22677
- const command = normalizedName === "bash" ? stringField(event.arguments, "command") ?? stringField(event.arguments, "cmd") ?? stringField(event.arguments, "script") ?? stringField(event.arguments, "commandLine") ?? stringField(event.arguments, "command_line") : void 0;
22678
- const item = command ? {
23709
+ const shell = piToolCommand(event.toolName, event.arguments);
23710
+ const item = shell ? {
22679
23711
  type: "commandExecution",
22680
23712
  itemId: this.#newItemId(),
22681
- command,
22682
- cwd: stringField(event.arguments, "cwd") ?? this.#cwd
23713
+ command: shell.command,
23714
+ cwd: shell.cwd ?? this.#cwd
22683
23715
  } : {
22684
23716
  type: "toolExecution",
22685
23717
  itemId: this.#newItemId(),
@@ -22797,14 +23829,17 @@ var PiHarnessSession = class {
22797
23829
  sessionId: transport.state.sessionId,
22798
23830
  model: nativeModelForHistory(transport.state)
22799
23831
  });
22800
- const created = snapshot.turns.filter((turn2) => !active.beforeNativeTurnKeys.has(turn2.nativeTurnRef.nativeTurnKey));
23832
+ const created = snapshot.turns.filter((turn2) => turn2.input.length > 0 && !active.beforeNativeTurnKeys.has(turn2.nativeTurnRef.nativeTurnKey));
22801
23833
  if (created.length !== 1) {
22802
23834
  throw new Error(`Pi Turn persisted ${created.length} new User Entries; exactly one is required`);
22803
23835
  }
22804
23836
  const turn = created[0];
22805
- if (!turn?.checkpoint)
22806
- throw new Error("Pi Turn has no terminal Checkpoint identity");
22807
- return { nativeTurnRef: turn.nativeTurnRef, checkpoint: turn.checkpoint };
23837
+ if (!turn)
23838
+ throw new Error("Pi Turn has no persisted User identity");
23839
+ return {
23840
+ nativeTurnRef: turn.nativeTurnRef,
23841
+ ...turn.checkpoint ? { checkpoint: turn.checkpoint } : {}
23842
+ };
22808
23843
  }
22809
23844
  #completeTurn(active, outcome, finalText, nativeTurnRef) {
22810
23845
  if (this.#active !== active)
@@ -22833,14 +23868,20 @@ var PiHarnessSession = class {
22833
23868
  });
22834
23869
  active.resolveCompletion();
22835
23870
  queueMicrotask(() => {
22836
- if (this.#phase === "open")
22837
- void this.#refreshUsage(active.command.turnId);
23871
+ if (this.#phase !== "open")
23872
+ return;
23873
+ if (this.#transport)
23874
+ this.#drainPendingAutonomousTurns(this.#transport);
23875
+ void this.#refreshUsage(active.command.turnId);
22838
23876
  });
22839
23877
  }
22840
23878
  #fault(error51) {
22841
23879
  if (this.#phase === "closed" || this.#phase === "faulted")
22842
23880
  return;
22843
23881
  const normalized = normalizedError(error51, "internalError");
23882
+ this.#pendingAutonomousTurns = [];
23883
+ this.#pendingAutonomousLifecycle = [];
23884
+ this.#pendingAutonomousLifecycleBytes = 0;
22844
23885
  if (this.#active) {
22845
23886
  this.#completeTurn(this.#active, { status: "failed", error: normalized });
22846
23887
  }
@@ -22849,6 +23890,9 @@ var PiHarnessSession = class {
22849
23890
  this.#channel.end();
22850
23891
  }
22851
23892
  async #close() {
23893
+ this.#pendingAutonomousTurns = [];
23894
+ this.#pendingAutonomousLifecycle = [];
23895
+ this.#pendingAutonomousLifecycleBytes = 0;
22852
23896
  if (this.#phase === "closed")
22853
23897
  return;
22854
23898
  const wasFaulted = this.#phase === "faulted";
@@ -22881,7 +23925,7 @@ var PiHarnessSession = class {
22881
23925
  this.#channel.emit({ kind: "event", event });
22882
23926
  }
22883
23927
  #newItemId() {
22884
- return hostItemIdSchema.parse(randomUUID6());
23928
+ return hostItemIdSchema.parse(randomUUID7());
22885
23929
  }
22886
23930
  };
22887
23931
  var PiAdapter = class {
@@ -22896,12 +23940,15 @@ var PiAdapter = class {
22896
23940
  if (this.#closePromise || parent.harnessId !== this.harnessId) {
22897
23941
  return { ok: false, error: invalidState("Pi Subagent parent is unavailable") };
22898
23942
  }
23943
+ const gotgenes = parseGotgenesId(nativeSubagentId);
22899
23944
  const workflow = parsePiWorkflowSubagentId(nativeSubagentId);
22900
- if (!workflow)
23945
+ if (!workflow && !gotgenes)
22901
23946
  parsePiSubagentId(nativeSubagentId);
22902
23947
  const live = [...this.#sessions].find((session) => session.ownsNativeSession(parent.nativeSessionId));
22903
23948
  let reply;
22904
23949
  if (live) {
23950
+ if (gotgenes)
23951
+ return await live.readGotgenesChild(gotgenes, cwd);
22905
23952
  if (workflow)
22906
23953
  return await readPiWorkflowChild(await live.readSubagentHistory(cwd), parent.nativeSessionId, workflow);
22907
23954
  reply = await live.inspectSubagent(nativeSubagentId, cwd);
@@ -22913,6 +23960,8 @@ var PiAdapter = class {
22913
23960
  if (transport.state.sessionId !== parent.nativeSessionId)
22914
23961
  throw new Error("Pi Subagent parent identity mismatch");
22915
23962
  await transport.verifySessionCwd(cwd);
23963
+ if (gotgenes)
23964
+ return await readGotgenesChild(await transport.getEntries(), parent.nativeSessionId, gotgenes);
22916
23965
  if (workflow)
22917
23966
  return await readPiWorkflowChild(await transport.getEntries(), parent.nativeSessionId, workflow);
22918
23967
  if (!transport.inspectSubagent)