lunel-cli 0.1.115 → 0.1.116

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.
@@ -13,6 +13,7 @@ export declare class CodexProvider implements AIProvider {
13
13
  private pendingQuestionRequestIds;
14
14
  private assistantMessageIdByTurnId;
15
15
  private partTextById;
16
+ private debugLog;
16
17
  init(): Promise<void>;
17
18
  destroy(): Promise<void>;
18
19
  subscribe(emitter: AiEventEmitter): () => void;
@@ -87,6 +88,7 @@ export declare class CodexProvider implements AIProvider {
87
88
  private resolveSessionFromPayload;
88
89
  private resolveInFlightTurnId;
89
90
  private decodeMessagesFromThreadRead;
91
+ private logThreadReadSummary;
90
92
  private decodeStoredToolLikePart;
91
93
  private describeStoredToolName;
92
94
  private extractStoredToolInput;
package/dist/ai/codex.js CHANGED
@@ -51,6 +51,12 @@ export class CodexProvider {
51
51
  pendingQuestionRequestIds = new Map();
52
52
  assistantMessageIdByTurnId = new Map();
53
53
  partTextById = new Map();
54
+ debugLog(message, fields) {
55
+ if (!DEBUG_MODE)
56
+ return;
57
+ const suffix = fields ? ` ${JSON.stringify(fields)}` : "";
58
+ console.log(`[codex] ${message}${suffix}`);
59
+ }
54
60
  async init() {
55
61
  if (DEBUG_MODE)
56
62
  console.log("Starting Codex app-server...");
@@ -100,7 +106,10 @@ export class CodexProvider {
100
106
  };
101
107
  }
102
108
  async createSession(title) {
103
- const result = await this.call("thread/start", { cwd: process.cwd() });
109
+ const result = await this.call("thread/start", {
110
+ cwd: process.cwd(),
111
+ persistExtendedHistory: true,
112
+ });
104
113
  const threadObject = this.extractThreadObject(result);
105
114
  const threadId = this.extractThreadId(threadObject);
106
115
  if (!threadId) {
@@ -207,6 +216,11 @@ export class CodexProvider {
207
216
  }
208
217
  async getMessages(sessionId) {
209
218
  const session = this.ensureLocalSession(sessionId);
219
+ this.debugLog("getMessages start", {
220
+ sessionId,
221
+ existingMessageCount: session.messages.length,
222
+ existingPartCount: session.messages.reduce((sum, message) => sum + (message.parts?.length || 0), 0),
223
+ });
210
224
  const result = await this.call("thread/read", {
211
225
  threadId: session.id,
212
226
  includeTurns: true,
@@ -215,7 +229,16 @@ export class CodexProvider {
215
229
  if (!threadObject) {
216
230
  return { messages: session.messages };
217
231
  }
232
+ this.logThreadReadSummary(sessionId, threadObject);
218
233
  const historyMessages = this.decodeMessagesFromThreadRead(sessionId, threadObject);
234
+ this.debugLog("getMessages decoded thread", {
235
+ sessionId,
236
+ turnCount: this.readArray(threadObject.turns).length,
237
+ decodedMessageCount: historyMessages.length,
238
+ decodedPartCount: historyMessages.reduce((sum, message) => sum + (message.parts?.length || 0), 0),
239
+ decodedRoles: historyMessages.map((message) => message.role),
240
+ decodedPartTypes: historyMessages.flatMap((message) => (message.parts || []).map((part) => String(this.asRecord(part).type ?? "unknown"))),
241
+ });
219
242
  if (historyMessages.length > 0) {
220
243
  session.messages = historyMessages;
221
244
  }
@@ -1107,7 +1130,10 @@ export class CodexProvider {
1107
1130
  return;
1108
1131
  }
1109
1132
  const session = this.sessions.get(threadId);
1110
- const params = { threadId };
1133
+ const params = {
1134
+ threadId,
1135
+ persistExtendedHistory: true,
1136
+ };
1111
1137
  if (session?.cwd) {
1112
1138
  params.cwd = session.cwd;
1113
1139
  }
@@ -1174,9 +1200,11 @@ export class CodexProvider {
1174
1200
  const assistantParts = [];
1175
1201
  let assistantMessageId;
1176
1202
  let assistantTimestamp = turnTime;
1203
+ const turnItemTypes = [];
1177
1204
  for (const item of items) {
1178
1205
  const itemObject = this.asRecord(item);
1179
1206
  const type = this.normalizedItemType(this.readString(itemObject.type) ?? "");
1207
+ turnItemTypes.push(type || "unknown");
1180
1208
  const itemId = this.readString(itemObject.id) ?? crypto.randomUUID();
1181
1209
  const timestamp = this.extractUpdatedAt(itemObject) ?? this.extractCreatedAt(itemObject) ?? (turnTime + orderOffset++);
1182
1210
  if (type === "usermessage") {
@@ -1239,6 +1267,7 @@ export class CodexProvider {
1239
1267
  || type === "mcptoolcall"
1240
1268
  || type === "dynamictoolcall"
1241
1269
  || type === "collabtoolcall"
1270
+ || type === "collabagenttoolcall"
1242
1271
  || type === "websearch"
1243
1272
  || type === "imageview") {
1244
1273
  assistantMessageId = assistantMessageId ?? (turnId ? `assistant:${turnId}` : itemId);
@@ -1268,9 +1297,53 @@ export class CodexProvider {
1268
1297
  this.assistantMessageIdByTurnId.set(turnId, resolvedAssistantMessageId);
1269
1298
  }
1270
1299
  }
1300
+ this.debugLog("decoded stored turn", {
1301
+ threadId,
1302
+ turnId: turnId ?? null,
1303
+ itemCount: items.length,
1304
+ itemTypes: turnItemTypes,
1305
+ emittedUserMessages: messages.filter((message) => message.role === "user").length,
1306
+ emittedAssistantParts: assistantParts.length,
1307
+ });
1271
1308
  }
1272
1309
  return messages;
1273
1310
  }
1311
+ logThreadReadSummary(sessionId, threadObject) {
1312
+ const turns = this.readArray(threadObject.turns);
1313
+ const turnSummaries = turns.map((turn, index) => {
1314
+ const turnObject = this.asRecord(turn);
1315
+ const items = this.readArray(turnObject.items);
1316
+ return {
1317
+ index,
1318
+ turnId: this.readString(turnObject.id) ?? null,
1319
+ status: this.readString(turnObject.status) ?? this.readString(this.asRecord(turnObject.status).type) ?? null,
1320
+ itemCount: items.length,
1321
+ itemTypes: items.map((item) => this.normalizedItemType(this.readString(this.asRecord(item).type) ?? "") || "unknown"),
1322
+ itemSummaries: items.map((item) => {
1323
+ const itemObject = this.asRecord(item);
1324
+ const type = this.normalizedItemType(this.readString(itemObject.type) ?? "") || "unknown";
1325
+ return {
1326
+ id: this.readString(itemObject.id) ?? null,
1327
+ type,
1328
+ keys: Object.keys(itemObject).sort(),
1329
+ textPreview: this.firstString(itemObject, ["text", "summary", "message", "query", "path", "tool", "command"])?.slice(0, 120) ?? null,
1330
+ hasAggregatedOutput: typeof itemObject.aggregatedOutput === "string" && itemObject.aggregatedOutput.length > 0,
1331
+ aggregatedOutputLength: typeof itemObject.aggregatedOutput === "string" ? itemObject.aggregatedOutput.length : 0,
1332
+ changesCount: Array.isArray(itemObject.changes) ? itemObject.changes.length : 0,
1333
+ hasResult: itemObject.result != null,
1334
+ hasContentItems: Array.isArray(itemObject.contentItems) && itemObject.contentItems.length > 0,
1335
+ status: this.readString(itemObject.status) ?? null,
1336
+ };
1337
+ }),
1338
+ };
1339
+ });
1340
+ console.log(`[codex-history] thread/read summary ${JSON.stringify({
1341
+ sessionId,
1342
+ threadId: this.readString(threadObject.id) ?? null,
1343
+ turnCount: turns.length,
1344
+ turnSummaries,
1345
+ })}`);
1346
+ }
1274
1347
  decodeStoredToolLikePart(type, itemObject, threadId, messageId, itemId) {
1275
1348
  if (type === "filechange" || type === "diff" || this.isFileChangeStructuredItem(type, itemObject)) {
1276
1349
  const output = this.decodeFileLikeItemText(itemObject) ?? this.describeCompletedItemOutput(itemObject, itemObject, type) ?? "File changes";
@@ -1312,6 +1385,9 @@ export class CodexProvider {
1312
1385
  if (type === "imageview") {
1313
1386
  return "image-view";
1314
1387
  }
1388
+ if (type === "collabtoolcall" || type === "collabagenttoolcall") {
1389
+ return "agent";
1390
+ }
1315
1391
  if (type === "enteredreviewmode") {
1316
1392
  return "review";
1317
1393
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lunel-cli",
3
- "version": "0.1.115",
3
+ "version": "0.1.116",
4
4
  "author": [
5
5
  {
6
6
  "name": "Soham Bharambe",