linkshell-cli 0.3.5 → 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/src/runtime/acp/acp-client.js +1 -0
- package/dist/cli/src/runtime/acp/acp-client.js.map +1 -1
- package/dist/cli/src/runtime/acp/agent-workspace.d.ts +1 -0
- package/dist/cli/src/runtime/acp/agent-workspace.js +35 -27
- package/dist/cli/src/runtime/acp/agent-workspace.js.map +1 -1
- package/dist/cli/src/runtime/acp/codex-sessions.d.ts +1 -0
- package/dist/cli/src/runtime/acp/codex-sessions.js +9 -7
- package/dist/cli/src/runtime/acp/codex-sessions.js.map +1 -1
- package/dist/cli/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/runtime/acp/acp-client.ts +1 -0
- package/src/runtime/acp/agent-workspace.ts +38 -27
- package/src/runtime/acp/codex-sessions.ts +11 -8
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
import { AcpClient } from "./acp-client.js";
|
|
10
10
|
import { ClaudeSdkClient } from "./claude-sdk-client.js";
|
|
11
11
|
import { ClaudeStreamJsonClient } from "./claude-stream-json-client.js";
|
|
12
|
+
import { listClaudeStoredSessions } from "./claude-sessions.js";
|
|
13
|
+
import { listCodexStoredSessions } from "./codex-sessions.js";
|
|
12
14
|
import type { AgentProtocol, AgentProvider } from "./provider-resolver.js";
|
|
13
15
|
import { resolveAgentCommand } from "./provider-resolver.js";
|
|
14
16
|
|
|
@@ -1161,6 +1163,7 @@ function parseRemoteSessions(value: unknown): Array<{
|
|
|
1161
1163
|
model?: string;
|
|
1162
1164
|
createdAt?: number;
|
|
1163
1165
|
lastActivityAt?: number;
|
|
1166
|
+
archived?: boolean;
|
|
1164
1167
|
}> {
|
|
1165
1168
|
const raw = asRecord(value);
|
|
1166
1169
|
const sessionsValue =
|
|
@@ -1176,6 +1179,7 @@ function parseRemoteSessions(value: unknown): Array<{
|
|
|
1176
1179
|
model?: string;
|
|
1177
1180
|
createdAt?: number;
|
|
1178
1181
|
lastActivityAt?: number;
|
|
1182
|
+
archived?: boolean;
|
|
1179
1183
|
}> = [];
|
|
1180
1184
|
for (const entry of sessionsValue) {
|
|
1181
1185
|
const session = asRecord(entry);
|
|
@@ -1194,6 +1198,7 @@ function parseRemoteSessions(value: unknown): Array<{
|
|
|
1194
1198
|
model: firstString(source, ["model", "modelId"]),
|
|
1195
1199
|
createdAt: parseTimestamp(source.createdAt ?? source.created_at),
|
|
1196
1200
|
lastActivityAt: parseTimestamp(source.lastActivityAt ?? source.updatedAt ?? source.modifiedAt ?? source.lastModified ?? source.updated_at),
|
|
1201
|
+
archived: typeof source.archived === "boolean" ? source.archived : undefined,
|
|
1197
1202
|
});
|
|
1198
1203
|
}
|
|
1199
1204
|
return result;
|
|
@@ -1437,36 +1442,12 @@ export class AgentWorkspaceProxy {
|
|
|
1437
1442
|
|
|
1438
1443
|
private async syncProviderSessions(): Promise<void> {
|
|
1439
1444
|
await this.initialize();
|
|
1445
|
+
this.upsertProviderSessions("codex", listCodexStoredSessions(this.input.cwd));
|
|
1446
|
+
this.upsertProviderSessions("claude", listClaudeStoredSessions(this.input.cwd));
|
|
1440
1447
|
for (const [provider, client] of this.clients) {
|
|
1441
1448
|
try {
|
|
1442
1449
|
const result = await client.listSessions();
|
|
1443
|
-
|
|
1444
|
-
const agentSessionId = remote.id;
|
|
1445
|
-
const existingId = this.conversationByAgentSessionId.get(agentSessionId);
|
|
1446
|
-
const now = Date.now();
|
|
1447
|
-
const conversationId = existingId ?? `agent:${agentSessionId}`;
|
|
1448
|
-
const existing = this.conversations.get(conversationId);
|
|
1449
|
-
const cwd = remote.cwd ?? existing?.cwd ?? this.input.cwd;
|
|
1450
|
-
const conversation: AgentConversation = {
|
|
1451
|
-
id: conversationId,
|
|
1452
|
-
agentSessionId,
|
|
1453
|
-
provider,
|
|
1454
|
-
cwd,
|
|
1455
|
-
title: remote.title ?? existing?.title ?? titleFromCwd(cwd),
|
|
1456
|
-
model: remote.model ?? existing?.model,
|
|
1457
|
-
reasoningEffort: existing?.reasoningEffort,
|
|
1458
|
-
permissionMode: existing?.permissionMode,
|
|
1459
|
-
collaborationMode: existing?.collaborationMode,
|
|
1460
|
-
status: existing?.status ?? "idle",
|
|
1461
|
-
archived: existing?.archived ?? false,
|
|
1462
|
-
lastMessagePreview: existing?.lastMessagePreview,
|
|
1463
|
-
lastActivityAt: remote.lastActivityAt ?? existing?.lastActivityAt ?? now,
|
|
1464
|
-
createdAt: remote.createdAt ?? existing?.createdAt ?? now,
|
|
1465
|
-
};
|
|
1466
|
-
this.conversations.set(conversation.id, conversation);
|
|
1467
|
-
this.conversationByAgentSessionId.set(agentSessionId, conversation.id);
|
|
1468
|
-
this.timelines.set(conversation.id, this.timelines.get(conversation.id) ?? []);
|
|
1469
|
-
}
|
|
1450
|
+
this.upsertProviderSessions(provider, result);
|
|
1470
1451
|
} catch (error) {
|
|
1471
1452
|
if (this.input.verbose) {
|
|
1472
1453
|
process.stderr.write(`[agent:v2] session list failed for ${provider}: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
@@ -1475,6 +1456,36 @@ export class AgentWorkspaceProxy {
|
|
|
1475
1456
|
}
|
|
1476
1457
|
}
|
|
1477
1458
|
|
|
1459
|
+
private upsertProviderSessions(provider: AgentProvider, result: unknown): void {
|
|
1460
|
+
for (const remote of parseRemoteSessions(result)) {
|
|
1461
|
+
const agentSessionId = remote.id;
|
|
1462
|
+
const existingId = this.conversationByAgentSessionId.get(agentSessionId);
|
|
1463
|
+
const now = Date.now();
|
|
1464
|
+
const conversationId = existingId ?? `agent:${agentSessionId}`;
|
|
1465
|
+
const existing = this.conversations.get(conversationId);
|
|
1466
|
+
const cwd = remote.cwd ?? existing?.cwd ?? this.input.cwd;
|
|
1467
|
+
const conversation: AgentConversation = {
|
|
1468
|
+
id: conversationId,
|
|
1469
|
+
agentSessionId,
|
|
1470
|
+
provider,
|
|
1471
|
+
cwd,
|
|
1472
|
+
title: remote.title ?? existing?.title ?? titleFromCwd(cwd),
|
|
1473
|
+
model: remote.model ?? existing?.model,
|
|
1474
|
+
reasoningEffort: existing?.reasoningEffort,
|
|
1475
|
+
permissionMode: existing?.permissionMode,
|
|
1476
|
+
collaborationMode: existing?.collaborationMode,
|
|
1477
|
+
status: existing?.status ?? "idle",
|
|
1478
|
+
archived: remote.archived ?? existing?.archived ?? false,
|
|
1479
|
+
lastMessagePreview: existing?.lastMessagePreview,
|
|
1480
|
+
lastActivityAt: remote.lastActivityAt ?? existing?.lastActivityAt ?? now,
|
|
1481
|
+
createdAt: remote.createdAt ?? existing?.createdAt ?? now,
|
|
1482
|
+
};
|
|
1483
|
+
this.conversations.set(conversation.id, conversation);
|
|
1484
|
+
this.conversationByAgentSessionId.set(agentSessionId, conversation.id);
|
|
1485
|
+
this.timelines.set(conversation.id, this.timelines.get(conversation.id) ?? []);
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1478
1489
|
private sendCapabilities(): void {
|
|
1479
1490
|
const providers = this.input.availableProviders.map((provider) => {
|
|
1480
1491
|
const client = this.clients.get(provider);
|
|
@@ -11,6 +11,7 @@ export interface CodexStoredSession {
|
|
|
11
11
|
title?: string;
|
|
12
12
|
createdAt?: number;
|
|
13
13
|
lastModified: number;
|
|
14
|
+
archived?: boolean;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
interface CodexIndexEntry {
|
|
@@ -158,15 +159,15 @@ function readCodexSessionFile(filePath: string, fallbackCwd: string): Omit<Codex
|
|
|
158
159
|
};
|
|
159
160
|
}
|
|
160
161
|
|
|
161
|
-
function collectJsonlFiles(dir: string, result: string
|
|
162
|
+
function collectJsonlFiles(dir: string, result: Array<{ path: string; archived: boolean }>, archived: boolean): void {
|
|
162
163
|
if (!existsSync(dir)) return;
|
|
163
164
|
try {
|
|
164
165
|
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
165
166
|
const path = join(dir, entry.name);
|
|
166
167
|
if (entry.isDirectory()) {
|
|
167
|
-
collectJsonlFiles(path, result);
|
|
168
|
+
collectJsonlFiles(path, result, archived);
|
|
168
169
|
} else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
169
|
-
result.push(path);
|
|
170
|
+
result.push({ path, archived });
|
|
170
171
|
}
|
|
171
172
|
}
|
|
172
173
|
} catch {
|
|
@@ -179,13 +180,13 @@ export function listCodexStoredSessions(inputCwd: string): { sessions: CodexStor
|
|
|
179
180
|
if (!existsSync(root)) return { sessions: [] };
|
|
180
181
|
|
|
181
182
|
const index = loadSessionIndex(root);
|
|
182
|
-
const files: string
|
|
183
|
-
collectJsonlFiles(join(root, "sessions"), files);
|
|
184
|
-
collectJsonlFiles(join(root, "archived_sessions"), files);
|
|
183
|
+
const files: Array<{ path: string; archived: boolean }> = [];
|
|
184
|
+
collectJsonlFiles(join(root, "sessions"), files, false);
|
|
185
|
+
collectJsonlFiles(join(root, "archived_sessions"), files, true);
|
|
185
186
|
|
|
186
187
|
const sessionsById = new Map<string, CodexStoredSession>();
|
|
187
188
|
for (const file of files) {
|
|
188
|
-
const metadata = readCodexSessionFile(file, inputCwd);
|
|
189
|
+
const metadata = readCodexSessionFile(file.path, inputCwd);
|
|
189
190
|
if (!metadata) continue;
|
|
190
191
|
const indexed = index.get(metadata.id);
|
|
191
192
|
const session: CodexStoredSession = {
|
|
@@ -194,9 +195,10 @@ export function listCodexStoredSessions(inputCwd: string): { sessions: CodexStor
|
|
|
194
195
|
title: indexed?.title,
|
|
195
196
|
createdAt: metadata.createdAt,
|
|
196
197
|
lastModified: indexed?.updatedAt ?? metadata.lastModified ?? Date.now(),
|
|
198
|
+
archived: file.archived,
|
|
197
199
|
};
|
|
198
200
|
const existing = sessionsById.get(session.id);
|
|
199
|
-
if (!existing || session.lastModified > existing.lastModified) {
|
|
201
|
+
if (!existing || session.lastModified > existing.lastModified || session.archived) {
|
|
200
202
|
sessionsById.set(session.id, session);
|
|
201
203
|
}
|
|
202
204
|
}
|
|
@@ -208,6 +210,7 @@ export function listCodexStoredSessions(inputCwd: string): { sessions: CodexStor
|
|
|
208
210
|
cwd: resolve(inputCwd),
|
|
209
211
|
title: indexed.title,
|
|
210
212
|
lastModified: indexed.updatedAt ?? Date.now(),
|
|
213
|
+
archived: false,
|
|
211
214
|
});
|
|
212
215
|
}
|
|
213
216
|
|