codesesh 0.7.2 → 0.9.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.
@@ -31,18 +31,20 @@ import {
31
31
  import { join as join7, basename as basename5 } from "path";
32
32
  import { existsSync as existsSync8, readdirSync as readdirSync4, readFileSync as readFileSync6, statSync as statSync5 } from "fs";
33
33
  import { join as join8, normalize } from "path";
34
+ import { existsSync as existsSync9, readFileSync as readFileSync7, readdirSync as readdirSync5, statSync as statSync6 } from "fs";
35
+ import { basename as basename6, join as join9 } from "path";
34
36
  import { availableParallelism } from "os";
35
37
  import { Worker } from "worker_threads";
36
- import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
38
+ import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
37
39
  import { spawnSync } from "child_process";
38
40
  import * as os from "os";
39
41
  import * as path from "path";
40
42
  import { resolve, sep } from "path";
41
- import { existsSync as existsSync10, rmSync, unlinkSync } from "fs";
42
- import { join as join9 } from "path";
43
+ import { existsSync as existsSync11, rmSync, unlinkSync } from "fs";
44
+ import { join as join10 } from "path";
43
45
  import { homedir as homedir4 } from "os";
44
46
  import { homedir as homedir5, platform as platform2 } from "os";
45
- import { join as join10 } from "path";
47
+ import { join as join11 } from "path";
46
48
  var registrations = [];
47
49
  function registerAgent(reg) {
48
50
  registrations.push(reg);
@@ -112,7 +114,8 @@ function resolveProviderRoots() {
112
114
  codexRoot: envPath("CODEX_HOME") ?? join(home, ".codex"),
113
115
  claudeRoot: envPath("CLAUDE_CONFIG_DIR") ?? join(home, ".claude"),
114
116
  kimiRoot: envPath("KIMI_SHARE_DIR") ?? join(home, ".kimi"),
115
- opencodeRoot: join(getDataHome(), "opencode")
117
+ opencodeRoot: join(getDataHome(), "opencode"),
118
+ piRoot: envPath("PI_HOME") ?? join(home, ".pi")
116
119
  };
117
120
  }
118
121
  function getCursorDataPath() {
@@ -4664,6 +4667,589 @@ var CursorAgent = class extends BaseAgent {
4664
4667
  }
4665
4668
  }
4666
4669
  };
4670
+ var HEAD_INDEX_VERSION3 = "pi-head-v1";
4671
+ var PARSER_VERSION2 = "pi-parser-v1";
4672
+ function parseTimestampMs3(value) {
4673
+ if (typeof value === "number") return Number.isFinite(value) ? value : 0;
4674
+ const text = String(value ?? "").trim();
4675
+ if (!text) return 0;
4676
+ const ts = Date.parse(text);
4677
+ return Number.isNaN(ts) ? 0 : ts;
4678
+ }
4679
+ function extractSessionIdFromFilename(filePath) {
4680
+ const stem = basename6(filePath, ".jsonl");
4681
+ const underscore = stem.indexOf("_");
4682
+ return underscore >= 0 ? stem.slice(underscore + 1) || stem : stem;
4683
+ }
4684
+ function isObject(value) {
4685
+ return typeof value === "object" && value !== null;
4686
+ }
4687
+ function contentToText(content) {
4688
+ if (typeof content === "string") return content;
4689
+ if (!Array.isArray(content)) return "";
4690
+ return content.map((item) => {
4691
+ if (!isObject(item)) return "";
4692
+ if (item["type"] === "text") return String(item["text"] ?? "");
4693
+ if (item["type"] === "image") return "[image]";
4694
+ return "";
4695
+ }).filter(Boolean).join("\n");
4696
+ }
4697
+ function normalizeTextParts(content, timestampMs) {
4698
+ const text = cleanInternalText(contentToText(content));
4699
+ return text ? [{ type: "text", text, time_created: timestampMs }] : [];
4700
+ }
4701
+ function buildMessage(params) {
4702
+ return {
4703
+ id: params.id,
4704
+ role: params.role,
4705
+ agent: params.agent,
4706
+ time_created: params.timestampMs,
4707
+ provider: params.provider,
4708
+ model: params.model,
4709
+ tokens: params.tokens,
4710
+ cost: params.cost,
4711
+ cost_source: params.costSource,
4712
+ parts: params.parts
4713
+ };
4714
+ }
4715
+ function getEntryTimestamp(entry) {
4716
+ return parseTimestampMs3(entry["timestamp"]);
4717
+ }
4718
+ function chooseLeafEntry(entries) {
4719
+ for (let index = entries.length - 1; index >= 0; index -= 1) {
4720
+ if (typeof entries[index]?.["id"] === "string") return entries[index];
4721
+ }
4722
+ return null;
4723
+ }
4724
+ function buildCurrentPathEntries(entries) {
4725
+ const byId = /* @__PURE__ */ new Map();
4726
+ for (const entry of entries) {
4727
+ const id = entry["id"];
4728
+ if (typeof id === "string" && id) byId.set(id, entry);
4729
+ }
4730
+ const leaf = chooseLeafEntry(entries);
4731
+ if (!leaf) return [];
4732
+ const path2 = [];
4733
+ const seen = /* @__PURE__ */ new Set();
4734
+ let current = leaf;
4735
+ while (current) {
4736
+ const id = String(current["id"] ?? "");
4737
+ if (!id || seen.has(id)) break;
4738
+ seen.add(id);
4739
+ path2.push(current);
4740
+ const parentId = current["parentId"];
4741
+ current = typeof parentId === "string" ? byId.get(parentId) : void 0;
4742
+ }
4743
+ return path2.reverse();
4744
+ }
4745
+ var PiAgent = class extends BaseAgent {
4746
+ name = "pi";
4747
+ displayName = "Pi";
4748
+ basePath = null;
4749
+ sessionMetaMap = /* @__PURE__ */ new Map();
4750
+ findBasePath() {
4751
+ const roots = resolveProviderRoots();
4752
+ return firstExisting(join9(roots.piRoot, "agent", "sessions"), "data/pi");
4753
+ }
4754
+ isAvailable() {
4755
+ this.basePath = this.findBasePath();
4756
+ if (!this.basePath) return false;
4757
+ return this.listSessionFiles().length > 0;
4758
+ }
4759
+ scan(options) {
4760
+ if (!this.basePath) return [];
4761
+ const scanMarker = perf.start("pi:scan");
4762
+ const files = this.listSessionFiles(options);
4763
+ options?.onProgress?.({ total: files.length, processed: 0, sessions: 0 });
4764
+ const heads = [];
4765
+ let processed = 0;
4766
+ for (const file of files) {
4767
+ try {
4768
+ const head = getParsedSession(this.parseSessionHeadResult(file));
4769
+ if (head) {
4770
+ heads.push(head);
4771
+ this.sessionMetaMap.set(head.id, this.buildSessionMeta(head, file));
4772
+ }
4773
+ } catch {
4774
+ } finally {
4775
+ processed += 1;
4776
+ options?.onProgress?.({ total: files.length, processed, sessions: heads.length });
4777
+ }
4778
+ }
4779
+ perf.end(scanMarker);
4780
+ return heads;
4781
+ }
4782
+ listSessionSources() {
4783
+ if (!this.basePath) return [];
4784
+ return this.listSessionFiles().map((file) => ({
4785
+ sessionId: extractSessionIdFromFilename(file),
4786
+ sourcePath: file,
4787
+ fingerprint: this.sourceFingerprint(file)
4788
+ }));
4789
+ }
4790
+ scanSessionSource(sourcePath) {
4791
+ const head = getParsedSession(this.parseSessionHeadResult(sourcePath));
4792
+ if (head) {
4793
+ this.sessionMetaMap.set(head.id, this.buildSessionMeta(head, sourcePath));
4794
+ }
4795
+ return head;
4796
+ }
4797
+ getSessionMetaMap() {
4798
+ return this.sessionMetaMap;
4799
+ }
4800
+ setSessionMetaMap(meta) {
4801
+ this.sessionMetaMap = meta;
4802
+ }
4803
+ checkForChanges(_sinceTimestamp, cachedSessions) {
4804
+ if (!this.basePath) return { hasChanges: false, timestamp: Date.now() };
4805
+ const currentFiles = this.listSessionFiles();
4806
+ const currentIds = new Set(currentFiles.map((file) => extractSessionIdFromFilename(file)));
4807
+ const cachedIds = new Set(cachedSessions.map((session) => session.id));
4808
+ const changedIds = /* @__PURE__ */ new Set();
4809
+ for (const session of cachedSessions) {
4810
+ if (!currentIds.has(session.id)) {
4811
+ changedIds.add(session.id);
4812
+ continue;
4813
+ }
4814
+ const meta = this.sessionMetaMap.get(session.id);
4815
+ if (!meta) {
4816
+ changedIds.add(session.id);
4817
+ continue;
4818
+ }
4819
+ try {
4820
+ if (this.hasMetaChanged(meta)) changedIds.add(session.id);
4821
+ } catch {
4822
+ changedIds.add(session.id);
4823
+ }
4824
+ }
4825
+ const hasAddedSessions = currentFiles.some(
4826
+ (file) => !cachedIds.has(extractSessionIdFromFilename(file))
4827
+ );
4828
+ return {
4829
+ hasChanges: changedIds.size > 0 || hasAddedSessions,
4830
+ changedIds: [...changedIds],
4831
+ timestamp: Date.now()
4832
+ };
4833
+ }
4834
+ incrementalScan(cachedSessions, changedIds) {
4835
+ if (!this.basePath) return cachedSessions;
4836
+ const sessionMap = new Map(cachedSessions.map((session) => [session.id, session]));
4837
+ const changedSet = new Set(changedIds);
4838
+ const currentFiles = this.listSessionFiles();
4839
+ const currentIds = new Set(currentFiles.map((file) => extractSessionIdFromFilename(file)));
4840
+ for (const session of cachedSessions) {
4841
+ if (!currentIds.has(session.id)) {
4842
+ sessionMap.delete(session.id);
4843
+ this.sessionMetaMap.delete(session.id);
4844
+ }
4845
+ }
4846
+ for (const file of currentFiles) {
4847
+ try {
4848
+ const sessionId = extractSessionIdFromFilename(file);
4849
+ if (!changedSet.has(sessionId) && sessionMap.has(sessionId)) continue;
4850
+ const head = getParsedSession(this.parseSessionHeadResult(file));
4851
+ if (head) {
4852
+ sessionMap.set(head.id, head);
4853
+ this.sessionMetaMap.set(head.id, this.buildSessionMeta(head, file));
4854
+ }
4855
+ } catch {
4856
+ }
4857
+ }
4858
+ return [...sessionMap.values()];
4859
+ }
4860
+ getSessionData(sessionId) {
4861
+ const meta = this.sessionMetaMap.get(sessionId);
4862
+ if (!meta) throw new Error(`Session not found: ${sessionId}`);
4863
+ if (!existsSync9(meta.sourcePath)) throw new Error(`Session file missing: ${meta.sourcePath}`);
4864
+ const parsed2 = this.parsePiFile(meta.sourcePath);
4865
+ const state = this.convertEntries(parsed2.pathEntries);
4866
+ const cleanedMessages = cleanParsedMessages(state.messages);
4867
+ return {
4868
+ id: meta.id,
4869
+ title: meta.title,
4870
+ slug: `pi/${meta.id}`,
4871
+ directory: meta.directory,
4872
+ time_created: meta.createdAt,
4873
+ time_updated: meta.updatedAt,
4874
+ stats: {
4875
+ message_count: cleanedMessages.length,
4876
+ total_input_tokens: state.totalInputTokens,
4877
+ total_output_tokens: state.totalOutputTokens,
4878
+ total_cache_read_tokens: state.totalCacheReadTokens || void 0,
4879
+ total_cache_create_tokens: state.totalCacheCreateTokens || void 0,
4880
+ total_cost: state.totalCost,
4881
+ cost_source: state.totalCost > 0 ? "recorded" : void 0
4882
+ },
4883
+ messages: cleanedMessages
4884
+ };
4885
+ }
4886
+ listSessionFiles(options) {
4887
+ if (!this.basePath) return [];
4888
+ return this.walkJsonlFiles(this.basePath, options);
4889
+ }
4890
+ walkJsonlFiles(dir, options) {
4891
+ const files = [];
4892
+ try {
4893
+ for (const entry of readdirSync5(dir, { withFileTypes: true })) {
4894
+ const fullPath = join9(dir, entry.name);
4895
+ if (entry.isDirectory()) {
4896
+ files.push(...this.walkJsonlFiles(fullPath, options));
4897
+ continue;
4898
+ }
4899
+ if (!entry.isFile() || !entry.name.endsWith(".jsonl")) continue;
4900
+ if (!matchesScanWindow(statSync6(fullPath).mtimeMs, options)) continue;
4901
+ files.push(fullPath);
4902
+ }
4903
+ } catch {
4904
+ }
4905
+ return files;
4906
+ }
4907
+ buildSessionMeta(head, file) {
4908
+ return {
4909
+ id: head.id,
4910
+ title: head.title,
4911
+ sourcePath: file,
4912
+ sourceFingerprint: this.sourceFingerprint(file),
4913
+ sourceMtimeMs: statSync6(file).mtimeMs,
4914
+ headIndexVersion: HEAD_INDEX_VERSION3,
4915
+ parserVersion: PARSER_VERSION2,
4916
+ directory: head.directory,
4917
+ messageCount: head.stats.message_count,
4918
+ createdAt: head.time_created,
4919
+ updatedAt: head.time_updated ?? head.time_created
4920
+ };
4921
+ }
4922
+ hasMetaChanged(meta) {
4923
+ if (meta.headIndexVersion !== HEAD_INDEX_VERSION3) return true;
4924
+ if (meta.parserVersion !== PARSER_VERSION2) return true;
4925
+ return statSync6(meta.sourcePath).mtimeMs !== meta.sourceMtimeMs;
4926
+ }
4927
+ sourceFingerprint(file) {
4928
+ const stat = statSync6(file);
4929
+ return JSON.stringify([HEAD_INDEX_VERSION3, PARSER_VERSION2, stat.mtimeMs, stat.size]);
4930
+ }
4931
+ parseSessionHeadResult(filePath) {
4932
+ const parsed2 = this.parsePiFile(filePath);
4933
+ const state = this.convertEntries(parsed2.pathEntries);
4934
+ const messageCount = state.messages.length;
4935
+ if (messageCount === 0) return filteredSession("no visible messages");
4936
+ const modelUsage = Object.keys(state.modelUsage).length > 0 ? state.modelUsage : void 0;
4937
+ return parsedSession({
4938
+ id: parsed2.sessionId,
4939
+ slug: `pi/${parsed2.sessionId}`,
4940
+ title: parsed2.title,
4941
+ directory: parsed2.directory,
4942
+ time_created: parsed2.createdAt,
4943
+ time_updated: parsed2.updatedAt,
4944
+ stats: {
4945
+ message_count: messageCount,
4946
+ total_input_tokens: state.totalInputTokens,
4947
+ total_output_tokens: state.totalOutputTokens,
4948
+ total_cache_read_tokens: state.totalCacheReadTokens || void 0,
4949
+ total_cache_create_tokens: state.totalCacheCreateTokens || void 0,
4950
+ total_cost: state.totalCost,
4951
+ cost_source: state.totalCost > 0 ? "recorded" : void 0
4952
+ },
4953
+ model_usage: modelUsage
4954
+ });
4955
+ }
4956
+ parsePiFile(filePath) {
4957
+ const records = Array.from(parseJsonlLines(readFileSync7(filePath, "utf-8")));
4958
+ if (records.length === 0) throw new Error("empty file");
4959
+ const header = records.find((record) => record["type"] === "session");
4960
+ if (!header) throw new Error("missing session header");
4961
+ const entries = records.filter((record) => record["type"] !== "session");
4962
+ const pathEntries = buildCurrentPathEntries(entries);
4963
+ if (pathEntries.length === 0) throw new Error("empty session tree");
4964
+ const sessionId = String(header["id"] ?? extractSessionIdFromFilename(filePath)).trim();
4965
+ if (!sessionId) throw new Error("missing session id");
4966
+ const stat = statSync6(filePath);
4967
+ const directory = String(header["cwd"] ?? "").trim() || basename6(filePath, ".jsonl");
4968
+ const createdAt = parseTimestampMs3(header["timestamp"]) || stat.mtimeMs;
4969
+ const updatedAt = pathEntries.reduce(
4970
+ (max, entry) => Math.max(max, getEntryTimestamp(entry)),
4971
+ createdAt
4972
+ );
4973
+ const explicitTitle = this.extractSessionName(pathEntries);
4974
+ const messageTitle = this.extractTitle(pathEntries);
4975
+ const directoryTitle = basenameTitle(directory);
4976
+ return {
4977
+ sessionId,
4978
+ directory,
4979
+ createdAt,
4980
+ updatedAt,
4981
+ title: resolveSessionTitle(explicitTitle, messageTitle, directoryTitle),
4982
+ pathEntries
4983
+ };
4984
+ }
4985
+ extractSessionName(entries) {
4986
+ for (let index = entries.length - 1; index >= 0; index -= 1) {
4987
+ const entry = entries[index];
4988
+ if (entry["type"] !== "session_info") continue;
4989
+ const name = normalizeTitleText(String(entry["name"] ?? ""));
4990
+ if (name) return name;
4991
+ }
4992
+ return null;
4993
+ }
4994
+ extractTitle(entries) {
4995
+ for (const entry of entries) {
4996
+ if (entry["type"] !== "message") continue;
4997
+ const message = entry["message"];
4998
+ if (!isObject(message) || message["role"] !== "user") continue;
4999
+ const title = normalizeTitleText(contentToText(message["content"]));
5000
+ if (title) return title;
5001
+ }
5002
+ return null;
5003
+ }
5004
+ convertEntries(entries) {
5005
+ const messages = [];
5006
+ const pendingToolCalls = /* @__PURE__ */ new Map();
5007
+ const modelUsage = {};
5008
+ let totalInputTokens = 0;
5009
+ let totalOutputTokens = 0;
5010
+ let totalCacheReadTokens = 0;
5011
+ let totalCacheCreateTokens = 0;
5012
+ let totalCost = 0;
5013
+ for (const entry of entries) {
5014
+ const timestampMs = getEntryTimestamp(entry);
5015
+ const type = String(entry["type"] ?? "");
5016
+ if (type === "message") {
5017
+ const message = entry["message"];
5018
+ if (!isObject(message)) continue;
5019
+ const result = this.convertAgentMessage(
5020
+ entry,
5021
+ message,
5022
+ timestampMs,
5023
+ pendingToolCalls,
5024
+ messages.length,
5025
+ messages
5026
+ );
5027
+ if (!result) continue;
5028
+ if (result.message) messages.push(result.message);
5029
+ totalInputTokens += result.inputTokens;
5030
+ totalOutputTokens += result.outputTokens;
5031
+ totalCacheReadTokens += result.cacheReadTokens;
5032
+ totalCacheCreateTokens += result.cacheCreateTokens;
5033
+ totalCost += result.cost;
5034
+ if (result.model && result.totalTokens > 0) {
5035
+ modelUsage[result.model] = (modelUsage[result.model] ?? 0) + result.totalTokens;
5036
+ }
5037
+ continue;
5038
+ }
5039
+ const summary = this.convertSummaryEntry(entry, timestampMs);
5040
+ if (summary) messages.push(summary);
5041
+ }
5042
+ return {
5043
+ messages,
5044
+ totalInputTokens,
5045
+ totalOutputTokens,
5046
+ totalCacheReadTokens,
5047
+ totalCacheCreateTokens,
5048
+ totalCost,
5049
+ modelUsage
5050
+ };
5051
+ }
5052
+ convertAgentMessage(entry, message, timestampMs, pendingToolCalls, nextMessageIndex, messages) {
5053
+ const id = String(entry["id"] ?? "");
5054
+ const role = String(message["role"] ?? "");
5055
+ if (role === "user") {
5056
+ const parts = normalizeTextParts(message["content"], timestampMs);
5057
+ if (parts.length === 0) return null;
5058
+ return this.emptyUsageResult(buildMessage({ id, role: "user", timestampMs, parts }));
5059
+ }
5060
+ if (role === "assistant") {
5061
+ const parts = this.normalizeAssistantParts(
5062
+ message["content"],
5063
+ timestampMs,
5064
+ pendingToolCalls,
5065
+ nextMessageIndex
5066
+ );
5067
+ if (parts.length === 0) return null;
5068
+ const usage = this.normalizeUsage(message["usage"]);
5069
+ const model = typeof message["model"] === "string" ? message["model"].trim() : null;
5070
+ const cost = usage.cost ?? estimateTokenCost(model, usage.tokens) ?? 0;
5071
+ return {
5072
+ message: buildMessage({
5073
+ id,
5074
+ role: "assistant",
5075
+ agent: "pi",
5076
+ timestampMs,
5077
+ parts,
5078
+ provider: typeof message["provider"] === "string" ? message["provider"] : null,
5079
+ model,
5080
+ tokens: usage.tokens,
5081
+ cost: cost || void 0,
5082
+ costSource: cost > 0 ? "recorded" : void 0
5083
+ }),
5084
+ inputTokens: usage.inputTokens,
5085
+ outputTokens: usage.outputTokens,
5086
+ cacheReadTokens: usage.cacheReadTokens,
5087
+ cacheCreateTokens: usage.cacheCreateTokens,
5088
+ totalTokens: usage.totalTokens,
5089
+ cost,
5090
+ model
5091
+ };
5092
+ }
5093
+ if (role === "toolResult") {
5094
+ this.attachToolResult(message, timestampMs, pendingToolCalls, messages);
5095
+ return this.emptyUsageResult();
5096
+ }
5097
+ if (role === "bashExecution") {
5098
+ return this.emptyUsageResult(this.convertBashExecution(id, message, timestampMs));
5099
+ }
5100
+ if (role === "custom" && message["display"] === true) {
5101
+ const parts = normalizeTextParts(message["content"], timestampMs);
5102
+ if (parts.length === 0) return null;
5103
+ return this.emptyUsageResult(buildMessage({ id, role: "user", timestampMs, parts }));
5104
+ }
5105
+ if (role === "branchSummary" || role === "compactionSummary") {
5106
+ const summary = String(message["summary"] ?? "").trim();
5107
+ if (!summary) return null;
5108
+ return this.emptyUsageResult(
5109
+ buildMessage({
5110
+ id,
5111
+ role: "assistant",
5112
+ agent: "pi",
5113
+ timestampMs,
5114
+ parts: [{ type: "text", text: summary, time_created: timestampMs }]
5115
+ })
5116
+ );
5117
+ }
5118
+ return null;
5119
+ }
5120
+ normalizeAssistantParts(content, timestampMs, pendingToolCalls, messageIndex) {
5121
+ if (!Array.isArray(content)) return [];
5122
+ const parts = [];
5123
+ for (const item of content) {
5124
+ if (!isObject(item)) continue;
5125
+ const type = item["type"];
5126
+ if (type === "text") {
5127
+ const text = cleanInternalText(String(item["text"] ?? ""));
5128
+ if (text) parts.push({ type: "text", text, time_created: timestampMs });
5129
+ continue;
5130
+ }
5131
+ if (type === "thinking") {
5132
+ const text = cleanInternalText(String(item["thinking"] ?? ""));
5133
+ if (text) parts.push({ type: "reasoning", text, time_created: timestampMs });
5134
+ continue;
5135
+ }
5136
+ if (type === "toolCall") {
5137
+ const callId = String(item["id"] ?? "").trim();
5138
+ const toolName = String(item["name"] ?? "").trim() || "tool";
5139
+ const toolPart = {
5140
+ type: "tool",
5141
+ tool: toolName,
5142
+ title: `Tool: ${toolName}`,
5143
+ callID: callId || void 0,
5144
+ time_created: timestampMs,
5145
+ state: {
5146
+ status: "running",
5147
+ input: item["arguments"] ?? {}
5148
+ }
5149
+ };
5150
+ parts.push(toolPart);
5151
+ if (callId) pendingToolCalls.set(callId, [messageIndex, parts.length - 1]);
5152
+ }
5153
+ }
5154
+ return parts;
5155
+ }
5156
+ attachToolResult(message, timestampMs, pendingToolCalls, messages) {
5157
+ const callId = String(message["toolCallId"] ?? "").trim();
5158
+ const output = normalizeTextParts(message["content"], timestampMs);
5159
+ const location = callId ? pendingToolCalls.get(callId) : void 0;
5160
+ if (!location) return;
5161
+ const [messageIndex, partIndex] = location;
5162
+ const target = messages[messageIndex]?.parts[partIndex];
5163
+ if (!target?.state) return;
5164
+ target.state.output = output;
5165
+ target.state.status = message["isError"] === true ? "error" : "completed";
5166
+ target.state.metadata = message["details"];
5167
+ pendingToolCalls.delete(callId);
5168
+ }
5169
+ convertBashExecution(id, message, timestampMs) {
5170
+ const command = String(message["command"] ?? "");
5171
+ const output = String(message["output"] ?? "");
5172
+ const isError = Number(message["exitCode"] ?? 0) !== 0 || message["cancelled"] === true;
5173
+ return buildMessage({
5174
+ id,
5175
+ role: "tool",
5176
+ timestampMs,
5177
+ parts: [
5178
+ {
5179
+ type: "tool",
5180
+ tool: "bash",
5181
+ title: "Tool: bash",
5182
+ time_created: timestampMs,
5183
+ state: {
5184
+ status: isError ? "error" : "completed",
5185
+ input: { command },
5186
+ output: output ? [{ type: "text", text: output, time_created: timestampMs }] : [],
5187
+ metadata: {
5188
+ exitCode: message["exitCode"],
5189
+ cancelled: message["cancelled"],
5190
+ truncated: message["truncated"],
5191
+ fullOutputPath: message["fullOutputPath"]
5192
+ }
5193
+ }
5194
+ }
5195
+ ]
5196
+ });
5197
+ }
5198
+ convertSummaryEntry(entry, timestampMs) {
5199
+ const type = entry["type"];
5200
+ if (type !== "compaction" && type !== "branch_summary" && type !== "custom_message") {
5201
+ return null;
5202
+ }
5203
+ if (type === "custom_message" && entry["display"] !== true) return null;
5204
+ const rawText = type === "custom_message" ? contentToText(entry["content"]) : String(entry["summary"] ?? "");
5205
+ const text = cleanInternalText(rawText);
5206
+ if (!text) return null;
5207
+ return buildMessage({
5208
+ id: String(entry["id"] ?? ""),
5209
+ role: type === "custom_message" ? "user" : "assistant",
5210
+ agent: type === "custom_message" ? void 0 : "pi",
5211
+ timestampMs,
5212
+ parts: [{ type: "text", text, time_created: timestampMs }]
5213
+ });
5214
+ }
5215
+ normalizeUsage(raw) {
5216
+ const usage = isObject(raw) ? raw : {};
5217
+ const inputTokens = Number(usage["input"] ?? 0);
5218
+ const outputTokens = Number(usage["output"] ?? 0);
5219
+ const cacheReadTokens = Number(usage["cacheRead"] ?? 0);
5220
+ const cacheCreateTokens = Number(usage["cacheWrite"] ?? 0);
5221
+ const totalTokens = Number(
5222
+ usage["totalTokens"] ?? inputTokens + outputTokens + cacheReadTokens + cacheCreateTokens
5223
+ );
5224
+ const cost = isObject(usage["cost"]) ? Number(usage["cost"]["total"] ?? 0) : null;
5225
+ return {
5226
+ inputTokens: inputTokens + cacheReadTokens + cacheCreateTokens,
5227
+ outputTokens,
5228
+ cacheReadTokens,
5229
+ cacheCreateTokens,
5230
+ totalTokens,
5231
+ cost: cost && Number.isFinite(cost) ? cost : null,
5232
+ tokens: {
5233
+ input: inputTokens + cacheReadTokens + cacheCreateTokens,
5234
+ output: outputTokens,
5235
+ cache_read: cacheReadTokens || void 0,
5236
+ cache_create: cacheCreateTokens || void 0
5237
+ }
5238
+ };
5239
+ }
5240
+ emptyUsageResult(message) {
5241
+ return {
5242
+ message,
5243
+ inputTokens: 0,
5244
+ outputTokens: 0,
5245
+ cacheReadTokens: 0,
5246
+ cacheCreateTokens: 0,
5247
+ totalTokens: 0,
5248
+ cost: 0,
5249
+ model: null
5250
+ };
5251
+ }
5252
+ };
4667
5253
  registerAgent({
4668
5254
  name: "claudecode",
4669
5255
  displayName: "Claude Code",
@@ -4688,6 +5274,12 @@ registerAgent({
4688
5274
  icon: "/icon/agent/codex.svg",
4689
5275
  create: () => new CodexAgent()
4690
5276
  });
5277
+ registerAgent({
5278
+ name: "pi",
5279
+ displayName: "Pi",
5280
+ icon: "/icon/agent/pi.svg",
5281
+ create: () => new PiAgent()
5282
+ });
4691
5283
  registerAgent({
4692
5284
  name: "cursor",
4693
5285
  displayName: "Cursor",
@@ -4702,11 +5294,11 @@ function fallbackDisplayName(input) {
4702
5294
  }
4703
5295
  var realFs = {
4704
5296
  exists(path2) {
4705
- return existsSync9(path2);
5297
+ return existsSync10(path2);
4706
5298
  },
4707
5299
  readText(path2) {
4708
5300
  try {
4709
- return readFileSync7(path2, "utf8");
5301
+ return readFileSync8(path2, "utf8");
4710
5302
  } catch {
4711
5303
  return null;
4712
5304
  }
@@ -5196,16 +5788,16 @@ var LEGACY_CACHE_FILENAME = "scan-cache.json";
5196
5788
  var SEARCH_INDEX_BULK_SYNC_THRESHOLD = 100;
5197
5789
  var ftsIntegrityCheckedPath = null;
5198
5790
  function getCacheDir2() {
5199
- return join9(homedir4(), ".cache", "codesesh");
5791
+ return join10(homedir4(), ".cache", "codesesh");
5200
5792
  }
5201
5793
  function getCachePath2() {
5202
- return join9(getCacheDir2(), CACHE_FILENAME);
5794
+ return join10(getCacheDir2(), CACHE_FILENAME);
5203
5795
  }
5204
5796
  function getLegacyCachePath() {
5205
- return join9(getCacheDir2(), LEGACY_CACHE_FILENAME);
5797
+ return join10(getCacheDir2(), LEGACY_CACHE_FILENAME);
5206
5798
  }
5207
5799
  function hasCacheStorage() {
5208
- return existsSync10(getCachePath2());
5800
+ return existsSync11(getCachePath2());
5209
5801
  }
5210
5802
  function withCacheDb(fn) {
5211
5803
  const cachePath = getCachePath2();
@@ -6644,7 +7236,7 @@ function buildSessionContentFromMessages(title, messages) {
6644
7236
  }
6645
7237
  function deleteLegacyCacheFile() {
6646
7238
  const legacyPath = getLegacyCachePath();
6647
- if (!existsSync10(legacyPath)) {
7239
+ if (!existsSync11(legacyPath)) {
6648
7240
  return;
6649
7241
  }
6650
7242
  try {
@@ -6971,7 +7563,7 @@ function clearCache() {
6971
7563
  const walPath = `${cachePath}-wal`;
6972
7564
  const shmPath = `${cachePath}-shm`;
6973
7565
  for (const filePath of [walPath, shmPath]) {
6974
- if (!existsSync10(filePath)) {
7566
+ if (!existsSync11(filePath)) {
6975
7567
  continue;
6976
7568
  }
6977
7569
  try {
@@ -8179,16 +8771,16 @@ function getStateDir() {
8179
8771
  }
8180
8772
  const p = platform2();
8181
8773
  if (p === "darwin") {
8182
- return join10(homedir5(), "Library", "Application Support", "codesesh");
8774
+ return join11(homedir5(), "Library", "Application Support", "codesesh");
8183
8775
  }
8184
8776
  if (p === "win32") {
8185
8777
  const appData = process.env.APPDATA ?? process.env.LOCALAPPDATA;
8186
- return join10(appData ?? join10(homedir5(), "AppData", "Roaming"), "codesesh");
8778
+ return join11(appData ?? join11(homedir5(), "AppData", "Roaming"), "codesesh");
8187
8779
  }
8188
- return join10(process.env.XDG_DATA_HOME ?? join10(homedir5(), ".local", "share"), "codesesh");
8780
+ return join11(process.env.XDG_DATA_HOME ?? join11(homedir5(), ".local", "share"), "codesesh");
8189
8781
  }
8190
8782
  function getStateDbPath() {
8191
- return join10(getStateDir(), BOOKMARK_DB_FILENAME);
8783
+ return join11(getStateDir(), BOOKMARK_DB_FILENAME);
8192
8784
  }
8193
8785
  function useMemoryStateStore() {
8194
8786
  return process.env.CODESESH_STATE_STORE === MEMORY_STATE_STORE;
@@ -8556,4 +9148,4 @@ export {
8556
9148
  importBookmarks,
8557
9149
  deleteBookmark
8558
9150
  };
8559
- //# sourceMappingURL=chunk-XANARSZG.js.map
9151
+ //# sourceMappingURL=chunk-LXHUIQZI.js.map