lunel-cli 0.1.116 → 0.1.118

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.
@@ -1,4 +1,4 @@
1
- import type { AIProvider, AiEventEmitter, CodexPromptOptions, FileAttachment, ModelSelector, MessageInfo, ProviderInfo, SessionInfo, ShareInfo } from "./interface.js";
1
+ import type { AIProvider, AiEventEmitter, CodexPromptOptions, AiSyncState, FileAttachment, ModelSelector, MessageInfo, ProviderInfo, SessionInfo, ShareInfo } from "./interface.js";
2
2
  export declare class CodexProvider implements AIProvider {
3
3
  private proc;
4
4
  private shuttingDown;
@@ -14,6 +14,7 @@ export declare class CodexProvider implements AIProvider {
14
14
  private assistantMessageIdByTurnId;
15
15
  private partTextById;
16
16
  private debugLog;
17
+ private debugHistory;
17
18
  init(): Promise<void>;
18
19
  destroy(): Promise<void>;
19
20
  subscribe(emitter: AiEventEmitter): () => void;
@@ -35,6 +36,7 @@ export declare class CodexProvider implements AIProvider {
35
36
  getMessages(sessionId: string): Promise<{
36
37
  messages: MessageInfo[];
37
38
  }>;
39
+ syncState(sessionIds?: string[]): Promise<AiSyncState>;
38
40
  prompt(sessionId: string, text: string, model?: ModelSelector, agent?: string, files?: FileAttachment[], codexOptions?: CodexPromptOptions): Promise<{
39
41
  ack: true;
40
42
  }>;
package/dist/ai/codex.js CHANGED
@@ -57,6 +57,11 @@ export class CodexProvider {
57
57
  const suffix = fields ? ` ${JSON.stringify(fields)}` : "";
58
58
  console.log(`[codex] ${message}${suffix}`);
59
59
  }
60
+ debugHistory(message, fields) {
61
+ if (!DEBUG_MODE)
62
+ return;
63
+ console.log(`[codex-history] ${message} ${JSON.stringify(fields)}`);
64
+ }
60
65
  async init() {
61
66
  if (DEBUG_MODE)
62
67
  console.log("Starting Codex app-server...");
@@ -263,6 +268,64 @@ export class CodexProvider {
263
268
  }
264
269
  return { messages: session.messages };
265
270
  }
271
+ async syncState(sessionIds = []) {
272
+ await this.listSessions().catch(() => ({ sessions: [] }));
273
+ const messageSessionIds = new Set(sessionIds);
274
+ for (const session of this.sessions.values()) {
275
+ if (session.activeTurnId)
276
+ messageSessionIds.add(session.id);
277
+ }
278
+ for (const pending of this.pendingPermissionRequestIds.values()) {
279
+ if (pending.sessionId)
280
+ messageSessionIds.add(pending.sessionId);
281
+ }
282
+ for (const pending of this.pendingQuestionRequestIds.values()) {
283
+ if (pending.sessionId)
284
+ messageSessionIds.add(pending.sessionId);
285
+ }
286
+ const messages = {};
287
+ const statuses = [];
288
+ await Promise.allSettled(Array.from(messageSessionIds).map(async (sessionId) => {
289
+ const response = await this.getMessages(sessionId);
290
+ messages[sessionId] = response.messages;
291
+ const session = this.sessions.get(sessionId);
292
+ if (!session)
293
+ return;
294
+ const activeTurnId = await this.resolveInFlightTurnId(sessionId).catch(() => undefined);
295
+ session.activeTurnId = activeTurnId;
296
+ if (activeTurnId) {
297
+ statuses.push({
298
+ sessionID: sessionId,
299
+ status: { type: "running", activeTurnId },
300
+ });
301
+ }
302
+ }));
303
+ return {
304
+ sessions: Array.from(this.sessions.values()).map((session) => this.toSessionInfo(session)),
305
+ statuses,
306
+ messages,
307
+ pendingPermissions: Array.from(this.pendingPermissionRequestIds.entries()).map(([id, pending]) => ({
308
+ id,
309
+ sessionID: pending.sessionId,
310
+ messageID: pending.messageId,
311
+ callID: pending.callId,
312
+ type: pending.method,
313
+ title: pending.method,
314
+ metadata: { method: pending.method },
315
+ })),
316
+ pendingQuestions: Array.from(this.pendingQuestionRequestIds.entries()).map(([id, pending]) => ({
317
+ id,
318
+ sessionID: pending.sessionId,
319
+ questions: [],
320
+ tool: {
321
+ ...(pending.messageId ? { messageID: pending.messageId } : {}),
322
+ ...(pending.callId ? { callID: pending.callId } : {}),
323
+ },
324
+ })),
325
+ statusAuthoritative: true,
326
+ generatedAt: Date.now(),
327
+ };
328
+ }
266
329
  async prompt(sessionId, text, model, agent, files = [], codexOptions) {
267
330
  const session = this.ensureLocalSession(sessionId);
268
331
  session.updatedAt = Date.now();
@@ -1337,12 +1400,12 @@ export class CodexProvider {
1337
1400
  }),
1338
1401
  };
1339
1402
  });
1340
- console.log(`[codex-history] thread/read summary ${JSON.stringify({
1403
+ this.debugHistory("thread/read summary", {
1341
1404
  sessionId,
1342
1405
  threadId: this.readString(threadObject.id) ?? null,
1343
1406
  turnCount: turns.length,
1344
1407
  turnSummaries,
1345
- })}`);
1408
+ });
1346
1409
  }
1347
1410
  decodeStoredToolLikePart(type, itemObject, threadId, messageId, itemId) {
1348
1411
  if (type === "filechange" || type === "diff" || this.isFileChangeStructuredItem(type, itemObject)) {
@@ -14,6 +14,24 @@ export declare class AiManager {
14
14
  backend: AiBackend;
15
15
  }>;
16
16
  }>;
17
+ syncState(sessionIds?: Partial<Record<AiBackend, string[]>>): Promise<{
18
+ sessions: Array<Record<string, unknown> & {
19
+ backend: AiBackend;
20
+ }>;
21
+ statuses: Array<Record<string, unknown> & {
22
+ backend: AiBackend;
23
+ }>;
24
+ messages: Record<string, unknown>;
25
+ pendingPermissions: Array<Record<string, unknown> & {
26
+ backend: AiBackend;
27
+ }>;
28
+ pendingQuestions: Array<Record<string, unknown> & {
29
+ backend: AiBackend;
30
+ }>;
31
+ statusAuthoritativeByBackend: Partial<Record<AiBackend, boolean>>;
32
+ syncedBackends: AiBackend[];
33
+ generatedAt: number;
34
+ }>;
17
35
  createSession(backend: AiBackend, title?: string): Promise<{
18
36
  session: import("./interface.js").SessionInfo;
19
37
  }>;
package/dist/ai/index.js CHANGED
@@ -68,6 +68,51 @@ export class AiManager {
68
68
  const sessions = results.flatMap((r) => (r.status === "fulfilled" ? r.value : []));
69
69
  return { sessions };
70
70
  }
71
+ async syncState(sessionIds = {}) {
72
+ const results = await Promise.allSettled(this._available.map(async (backend) => {
73
+ const provider = this._providers[backend];
74
+ const state = provider.syncState
75
+ ? await provider.syncState(sessionIds[backend])
76
+ : {
77
+ sessions: (await provider.listSessions()).sessions,
78
+ statuses: [],
79
+ messages: {},
80
+ generatedAt: Date.now(),
81
+ };
82
+ return { backend, state };
83
+ }));
84
+ const sessions = [];
85
+ const statuses = [];
86
+ const messages = {};
87
+ const pendingPermissions = [];
88
+ const pendingQuestions = [];
89
+ const statusAuthoritativeByBackend = {};
90
+ const syncedBackends = [];
91
+ for (const result of results) {
92
+ if (result.status !== "fulfilled")
93
+ continue;
94
+ const { backend, state } = result.value;
95
+ syncedBackends.push(backend);
96
+ statusAuthoritativeByBackend[backend] = state.statusAuthoritative !== false;
97
+ sessions.push(...(state.sessions ?? []).map((session) => ({ ...session, backend })));
98
+ statuses.push(...(state.statuses ?? []).map((status) => ({ ...status, backend })));
99
+ for (const [sessionId, value] of Object.entries(state.messages ?? {})) {
100
+ messages[`${backend}:${sessionId}`] = value;
101
+ }
102
+ pendingPermissions.push(...(state.pendingPermissions ?? []).map((permission) => ({ ...permission, backend })));
103
+ pendingQuestions.push(...(state.pendingQuestions ?? []).map((question) => ({ ...question, backend })));
104
+ }
105
+ return {
106
+ sessions,
107
+ statuses,
108
+ messages,
109
+ pendingPermissions,
110
+ pendingQuestions,
111
+ statusAuthoritativeByBackend,
112
+ syncedBackends,
113
+ generatedAt: Date.now(),
114
+ };
115
+ }
71
116
  // Session management — all require explicit backend
72
117
  createSession(backend, title) { return this.get(backend).createSession(title); }
73
118
  getSession(backend, id) { return this.get(backend).getSession(id); }
@@ -35,6 +35,19 @@ export interface ProviderInfo {
35
35
  default: Record<string, string>;
36
36
  [key: string]: unknown;
37
37
  }
38
+ export interface AiSessionStatus {
39
+ sessionID: string;
40
+ status: Record<string, unknown> | string;
41
+ }
42
+ export interface AiSyncState {
43
+ sessions: unknown[];
44
+ statuses: AiSessionStatus[];
45
+ messages: Record<string, MessageInfo[]>;
46
+ pendingPermissions?: Record<string, unknown>[];
47
+ pendingQuestions?: Record<string, unknown>[];
48
+ statusAuthoritative?: boolean;
49
+ generatedAt: number;
50
+ }
38
51
  /**
39
52
  * Every AI backend (OpenCode, Codex, …) implements this interface.
40
53
  * Method names map 1-to-1 with the "ai" namespace actions in index.ts.
@@ -67,6 +80,7 @@ export interface AIProvider {
67
80
  getMessages(sessionId: string): Promise<{
68
81
  messages: MessageInfo[];
69
82
  }>;
83
+ syncState?(sessionIds?: string[]): Promise<AiSyncState>;
70
84
  prompt(sessionId: string, text: string, model?: ModelSelector, agent?: string, files?: FileAttachment[], codexOptions?: CodexPromptOptions): Promise<{
71
85
  ack: true;
72
86
  }>;
@@ -1,4 +1,4 @@
1
- import type { AIProvider, AiEventEmitter, CodexPromptOptions, FileAttachment, ModelSelector, MessageInfo, ProviderInfo, SessionInfo, ShareInfo } from "./interface.js";
1
+ import type { AIProvider, AiEventEmitter, CodexPromptOptions, AiSyncState, FileAttachment, ModelSelector, MessageInfo, ProviderInfo, SessionInfo, ShareInfo } from "./interface.js";
2
2
  export declare class OpenCodeProvider implements AIProvider {
3
3
  private client;
4
4
  private server;
@@ -8,6 +8,9 @@ export declare class OpenCodeProvider implements AIProvider {
8
8
  private emitter;
9
9
  private knownPendingPermissionIds;
10
10
  private knownPendingQuestionIds;
11
+ private debugLog;
12
+ private debugWarn;
13
+ private debugError;
11
14
  init(): Promise<void>;
12
15
  destroy(): Promise<void>;
13
16
  subscribe(emitter: AiEventEmitter): () => void;
@@ -30,6 +33,7 @@ export declare class OpenCodeProvider implements AIProvider {
30
33
  getMessages(sessionId: string): Promise<{
31
34
  messages: MessageInfo[];
32
35
  }>;
36
+ syncState(sessionIds?: string[]): Promise<AiSyncState>;
33
37
  prompt(sessionId: string, text: string, model?: ModelSelector, agent?: string, files?: FileAttachment[], codexOptions?: CodexPromptOptions): Promise<{
34
38
  ack: true;
35
39
  }>;
@@ -54,6 +58,9 @@ export declare class OpenCodeProvider implements AIProvider {
54
58
  private sendPromptAsync;
55
59
  private reconcileOpenCodeState;
56
60
  private refreshBusySessionMessages;
61
+ private fetchSessionStatuses;
62
+ private listPendingPermissions;
63
+ private listPendingQuestions;
57
64
  private refreshSessionsMetadata;
58
65
  private refreshPendingPermissions;
59
66
  private refreshPendingQuestions;
@@ -262,6 +262,21 @@ export class OpenCodeProvider {
262
262
  emitter = null;
263
263
  knownPendingPermissionIds = new Set();
264
264
  knownPendingQuestionIds = new Set();
265
+ debugLog(message, ...args) {
266
+ if (!VERBOSE_AI_LOGS)
267
+ return;
268
+ console.log(message, ...args);
269
+ }
270
+ debugWarn(message, ...args) {
271
+ if (!VERBOSE_AI_LOGS)
272
+ return;
273
+ console.warn(message, ...args);
274
+ }
275
+ debugError(message, ...args) {
276
+ if (!VERBOSE_AI_LOGS)
277
+ return;
278
+ console.error(message, ...args);
279
+ }
265
280
  async init() {
266
281
  const opencodeUsername = "lunel";
267
282
  const opencodePassword = crypto.randomBytes(32).toString("base64url");
@@ -378,6 +393,52 @@ export class OpenCodeProvider {
378
393
  throw err;
379
394
  }
380
395
  }
396
+ async syncState(sessionIds = []) {
397
+ const [sessionsResult, statusesResult, permissionsResult, questionsResult] = await Promise.allSettled([
398
+ this.listSessions(),
399
+ this.fetchSessionStatuses(),
400
+ this.listPendingPermissions(),
401
+ this.listPendingQuestions(),
402
+ ]);
403
+ const sessions = sessionsResult.status === "fulfilled"
404
+ ? (sessionsResult.value.sessions ?? [])
405
+ : [];
406
+ const statuses = statusesResult.status === "fulfilled" ? statusesResult.value : [];
407
+ const pendingPermissions = permissionsResult.status === "fulfilled" ? permissionsResult.value : [];
408
+ const pendingQuestions = questionsResult.status === "fulfilled" ? questionsResult.value : [];
409
+ const messageSessionIds = new Set(sessionIds);
410
+ for (const entry of statuses) {
411
+ const statusObj = typeof entry.status === "object" && entry.status !== null ? entry.status : {};
412
+ const statusType = typeof statusObj.type === "string" ? statusObj.type.toLowerCase() : String(entry.status ?? "").toLowerCase();
413
+ if (statusType === "busy" || statusType === "running" || statusType === "working" || statusType === "retry") {
414
+ messageSessionIds.add(entry.sessionID);
415
+ }
416
+ }
417
+ for (const permission of pendingPermissions) {
418
+ const sessionID = this.readString(permission.sessionID) ?? this.readString(permission.sessionId);
419
+ if (sessionID)
420
+ messageSessionIds.add(sessionID);
421
+ }
422
+ for (const question of pendingQuestions) {
423
+ const sessionID = this.readString(question.sessionID) ?? this.readString(question.sessionId);
424
+ if (sessionID)
425
+ messageSessionIds.add(sessionID);
426
+ }
427
+ const messages = {};
428
+ await Promise.allSettled(Array.from(messageSessionIds).map(async (sessionId) => {
429
+ const response = await this.getMessages(sessionId);
430
+ messages[sessionId] = response.messages;
431
+ }));
432
+ return {
433
+ sessions,
434
+ statuses,
435
+ messages,
436
+ pendingPermissions,
437
+ pendingQuestions,
438
+ statusAuthoritative: statusesResult.status === "fulfilled",
439
+ generatedAt: Date.now(),
440
+ };
441
+ }
381
442
  // -------------------------------------------------------------------------
382
443
  // Interaction
383
444
  // -------------------------------------------------------------------------
@@ -521,13 +582,13 @@ export class OpenCodeProvider {
521
582
  path: { id: this.lastActiveSessionId },
522
583
  });
523
584
  if (checkResp.error) {
524
- console.warn(`[sse] OpenCode session ${this.lastActiveSessionId} was garbage-collected. Notifying app.`);
585
+ this.debugWarn(`[sse] OpenCode session ${this.lastActiveSessionId} was garbage-collected. Notifying app.`);
525
586
  const gcSessionId = this.lastActiveSessionId;
526
587
  this.lastActiveSessionId = null;
527
588
  this.emitter?.({ type: "session_gc", properties: { sessionId: gcSessionId } });
528
589
  }
529
590
  else {
530
- console.log(`[sse] Active session ${this.lastActiveSessionId} still valid.`);
591
+ this.debugLog(`[sse] Active session ${this.lastActiveSessionId} still valid.`);
531
592
  }
532
593
  }
533
594
  if (attempt > 0) {
@@ -535,7 +596,7 @@ export class OpenCodeProvider {
535
596
  }
536
597
  const events = await this.client.event.subscribe();
537
598
  if (attempt > 0) {
538
- console.log(`[sse] reconnected after ${attempt} attempt(s)`);
599
+ this.debugLog(`[sse] reconnected after ${attempt} attempt(s)`);
539
600
  }
540
601
  attempt = 0;
541
602
  for await (const raw of events.stream) {
@@ -549,11 +610,11 @@ export class OpenCodeProvider {
549
610
  ? parsed.payload
550
611
  : parsed;
551
612
  if (!base || typeof base.type !== "string") {
552
- console.warn("[sse] Dropped malformed event:", redactSensitive(JSON.stringify(parsed).substring(0, 200)));
613
+ this.debugWarn("[sse] Dropped malformed event:", redactSensitive(JSON.stringify(parsed).substring(0, 200)));
553
614
  continue;
554
615
  }
555
616
  if (base.type !== "server.heartbeat") {
556
- console.log("[sse]", base.type);
617
+ this.debugLog("[sse]", base.type);
557
618
  }
558
619
  const normalizedEvent = normalizeOpenCodeEvent({
559
620
  type: base.type,
@@ -562,7 +623,7 @@ export class OpenCodeProvider {
562
623
  this.trackPermissionEvent(normalizedEvent.type, normalizedEvent.properties || {});
563
624
  this.emitter?.(normalizedEvent);
564
625
  }
565
- console.log("[sse] Event stream ended, reconnecting...");
626
+ this.debugLog("[sse] Event stream ended, reconnecting...");
566
627
  attempt++;
567
628
  }
568
629
  catch (err) {
@@ -570,9 +631,9 @@ export class OpenCodeProvider {
570
631
  return;
571
632
  attempt++;
572
633
  const delay = backoffMs(attempt - 1);
573
- console.error(`[sse] Stream error (attempt ${attempt}/${SSE_MAX_RETRIES}): ${err.message}. Retrying in ${delay}ms`);
634
+ this.debugError(`[sse] Stream error (attempt ${attempt}/${SSE_MAX_RETRIES}): ${err.message}. Retrying in ${delay}ms`);
574
635
  if (attempt >= SSE_MAX_RETRIES) {
575
- console.error("[sse] Max retries reached. Sending error event to app and giving up.");
636
+ this.debugError("[sse] Max retries reached. Sending error event to app and giving up.");
576
637
  this.emitter?.({
577
638
  type: "sse_dead",
578
639
  properties: { error: err.message, attempts: attempt },
@@ -668,13 +729,50 @@ export class OpenCodeProvider {
668
729
  });
669
730
  }
670
731
  }
671
- console.log(`[sse] Re-synced messages for busy session ${sessionId} after reconnect`);
732
+ this.debugLog(`[sse] Re-synced messages for busy session ${sessionId} after reconnect`);
672
733
  }
673
734
  catch (err) {
674
- console.warn(`[sse] Failed to refresh messages for busy session ${sessionId}:`, err.message);
735
+ this.debugWarn(`[sse] Failed to refresh messages for busy session ${sessionId}:`, err.message);
675
736
  }
676
737
  }
677
738
  }
739
+ async fetchSessionStatuses() {
740
+ const payload = await this.fetchOpenCodeJson("/session/status", { method: "GET" });
741
+ if (!payload || typeof payload !== "object")
742
+ return [];
743
+ return Object.entries(payload).map(([sessionID, status]) => ({
744
+ sessionID,
745
+ status: status,
746
+ }));
747
+ }
748
+ async listPendingPermissions() {
749
+ const permissionApi = this.client?.permission;
750
+ if (!permissionApi?.list)
751
+ return [];
752
+ const response = await permissionApi.list();
753
+ const data = Array.isArray(response.data) ? response.data : [];
754
+ return data
755
+ .map((entry) => normalizePermissionProperties(this.asRecord(entry)))
756
+ .filter((entry) => !!this.readString(entry.id));
757
+ }
758
+ async listPendingQuestions() {
759
+ const data = await this.fetchOpenCodeJson("/question", { method: "GET" });
760
+ const questions = Array.isArray(data) ? data : [];
761
+ return questions
762
+ .flatMap((entry) => {
763
+ const question = this.asRecord(entry);
764
+ const id = this.readString(question.id);
765
+ const sessionID = this.readString(question.sessionID) ?? this.readString(question.sessionId);
766
+ if (!id || !sessionID)
767
+ return [];
768
+ return [{
769
+ id,
770
+ sessionID,
771
+ questions: Array.isArray(question.questions) ? question.questions : [],
772
+ tool: typeof question.tool === "object" && question.tool !== null ? question.tool : undefined,
773
+ }];
774
+ });
775
+ }
678
776
  async refreshSessionsMetadata() {
679
777
  const response = await this.client.session.list();
680
778
  const sessions = Array.isArray(response.data) ? response.data : [];
package/dist/index.js CHANGED
@@ -398,6 +398,51 @@ async function handleFsLs(payload) {
398
398
  }
399
399
  return { path: reqPath, entries: result };
400
400
  }
401
+ async function handleFsSearchFiles(payload) {
402
+ const reqPath = payload.path || ".";
403
+ const query = typeof payload.query === "string" ? payload.query.trim().toLowerCase() : "";
404
+ const maxResults = Math.max(1, Math.min(payload.maxResults || 10, 10));
405
+ const safePath = assertSafePath(reqPath);
406
+ const rootIgnore = await loadGitignore(ROOT_DIR);
407
+ const matches = [];
408
+ async function searchDir(dirPath, relativePath, ig) {
409
+ if (matches.length >= maxResults)
410
+ return;
411
+ const localIgnore = ignore().add(ig);
412
+ try {
413
+ const localGitignorePath = path.join(dirPath, ".gitignore");
414
+ const content = await fs.readFile(localGitignorePath, "utf-8");
415
+ localIgnore.add(content);
416
+ }
417
+ catch {
418
+ // No local .gitignore
419
+ }
420
+ const entries = await fs.readdir(dirPath, { withFileTypes: true });
421
+ for (const entry of entries) {
422
+ if (matches.length >= maxResults)
423
+ break;
424
+ const relPath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
425
+ const checkPath = entry.isDirectory() ? `${relPath}/` : relPath;
426
+ if (localIgnore.ignores(checkPath))
427
+ continue;
428
+ const fullPath = path.join(dirPath, entry.name);
429
+ if (entry.isDirectory()) {
430
+ await searchDir(fullPath, relPath, localIgnore);
431
+ }
432
+ else if (entry.isFile() && relPath.toLowerCase().includes(query)) {
433
+ matches.push({ path: relPath });
434
+ }
435
+ }
436
+ }
437
+ const stat = await fs.stat(safePath);
438
+ if (stat.isDirectory()) {
439
+ await searchDir(safePath, reqPath === "." ? "" : reqPath, rootIgnore);
440
+ }
441
+ else if (stat.isFile() && reqPath.toLowerCase().includes(query)) {
442
+ matches.push({ path: reqPath });
443
+ }
444
+ return { path: reqPath, query, maxResults, files: matches };
445
+ }
401
446
  async function handleFsStat(payload) {
402
447
  const reqPath = payload.path;
403
448
  if (!reqPath)
@@ -2473,6 +2518,9 @@ async function processMessage(message) {
2473
2518
  case "ls":
2474
2519
  result = await handleFsLs(payload);
2475
2520
  break;
2521
+ case "searchFiles":
2522
+ result = await handleFsSearchFiles(payload);
2523
+ break;
2476
2524
  case "stat":
2477
2525
  result = await handleFsStat(payload);
2478
2526
  break;
@@ -2668,6 +2716,14 @@ async function processMessage(message) {
2668
2716
  case "listSessions":
2669
2717
  result = await aiManager.listAllSessions();
2670
2718
  break;
2719
+ case "syncState": {
2720
+ const rawSessionIds = payload.sessionIds;
2721
+ result = await aiManager.syncState({
2722
+ opencode: Array.isArray(rawSessionIds?.opencode) ? rawSessionIds.opencode.filter((id) => typeof id === "string") : undefined,
2723
+ codex: Array.isArray(rawSessionIds?.codex) ? rawSessionIds.codex.filter((id) => typeof id === "string") : undefined,
2724
+ });
2725
+ break;
2726
+ }
2671
2727
  case "getSession":
2672
2728
  result = await aiManager.getSession(backend, payload.id);
2673
2729
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lunel-cli",
3
- "version": "0.1.116",
3
+ "version": "0.1.118",
4
4
  "author": [
5
5
  {
6
6
  "name": "Soham Bharambe",