lark-remote 0.5.19 → 0.5.21
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/CHANGELOG.md +29 -0
- package/dist/bridge/approval-actions.d.ts +1 -1
- package/dist/bridge/approval-actions.js +1 -1
- package/dist/bridge/bash-run.d.ts +71 -0
- package/dist/bridge/bash-run.js +217 -0
- package/dist/bridge/compact.d.ts +155 -0
- package/dist/bridge/compact.js +450 -0
- package/dist/bridge/final-usage.js +4 -4
- package/dist/bridge/inbound-media.js +72 -46
- package/dist/bridge/index.d.ts +106 -153
- package/dist/bridge/index.js +400 -1000
- package/dist/bridge/job-watch.d.ts +68 -0
- package/dist/bridge/job-watch.js +146 -0
- package/dist/bridge/queue-manager.d.ts +3 -3
- package/dist/bridge/queue-manager.js +10 -29
- package/dist/card/approval-render.d.ts +2 -2
- package/dist/card/approval-render.js +141 -130
- package/dist/card/card-budget.js +123 -98
- package/dist/card/card-helpers.d.ts +3 -3
- package/dist/card/card-helpers.js +6 -6
- package/dist/card/final-answer-file.js +1 -1
- package/dist/card/run-renderer.d.ts +3 -3
- package/dist/card/run-renderer.js +114 -159
- package/dist/card/run-state.d.ts +1 -15
- package/dist/card/run-state.js +358 -292
- package/dist/card/tool-render.d.ts +1 -1
- package/dist/card/tool-render.js +21 -17
- package/dist/card/usage-format.d.ts +22 -7
- package/dist/card/usage-format.js +119 -100
- package/dist/cli.js +15 -3
- package/dist/clone.js +2 -2
- package/dist/common/text-width.js +36 -24
- package/dist/common/tool-summary.js +132 -90
- package/dist/config/codex-config.js +130 -106
- package/dist/config/index.d.ts +16 -2
- package/dist/config/index.js +23 -8
- package/dist/connector/index.js +6 -6
- package/dist/error-classification.js +3 -2
- package/dist/inbound/placeholder.d.ts +1 -1
- package/dist/inbound/placeholder.js +1 -1
- package/dist/index.js +387 -281
- package/dist/logger/index.js +6 -6
- package/dist/message-handlers.d.ts +0 -5
- package/dist/message-handlers.js +254 -237
- package/dist/model-catalog.d.ts +2 -2
- package/dist/model-catalog.js +3 -8
- package/dist/platform/identity.js +1 -1
- package/dist/platform/path.d.ts +1 -1
- package/dist/platform/path.js +1 -1
- package/dist/platform/sleep-blocker.js +1 -1
- package/dist/platform/terminator-win32.js +2 -1
- package/dist/router/commands/ls.d.ts +3 -0
- package/dist/router/commands/ls.js +256 -175
- package/dist/router/commands/order.js +184 -159
- package/dist/router/commands/resume.js +190 -152
- package/dist/router/commands/ws.js +219 -174
- package/dist/router/config/dsh.d.ts +4 -8
- package/dist/router/config/dsh.js +3 -10
- package/dist/router/config/kimi.js +1 -1
- package/dist/router/config/types.d.ts +1 -1
- package/dist/router/config-diff.js +1 -1
- package/dist/router/index.d.ts +56 -11
- package/dist/router/index.js +401 -391
- package/dist/runner/bash/runner.js +2 -4
- package/dist/runner/claude/session.d.ts +1 -1
- package/dist/runner/claude/session.js +6 -4
- package/dist/runner/codex/app-server/runner.d.ts +9 -2
- package/dist/runner/codex/app-server/runner.js +30 -25
- package/dist/runner/codex/app-server/translator.d.ts +2 -5
- package/dist/runner/codex/app-server/translator.js +291 -238
- package/dist/runner/common/acp/acp-approval.d.ts +1 -1
- package/dist/runner/common/acp/acp-approval.js +1 -1
- package/dist/runner/common/acp/base-acp-runner.d.ts +5 -2
- package/dist/runner/common/acp/base-acp-runner.js +26 -65
- package/dist/runner/common/acp/base-translator.d.ts +12 -2
- package/dist/runner/common/acp/base-translator.js +50 -26
- package/dist/runner/common/acp/protocol-types.d.ts +1 -1
- package/dist/runner/common/acp/protocol-types.js +2 -2
- package/dist/runner/common/connection-based-runner.d.ts +32 -1
- package/dist/runner/common/connection-based-runner.js +32 -2
- package/dist/runner/common/jsonl-stream.js +154 -187
- package/dist/runner/common/jsonrpc/client.d.ts +29 -0
- package/dist/runner/common/jsonrpc/client.js +43 -12
- package/dist/runner/common/jsonrpc/connection-manager.d.ts +2 -2
- package/dist/runner/common/jsonrpc/connection-manager.js +4 -4
- package/dist/runner/common/spawning-runner.d.ts +6 -1
- package/dist/runner/common/spawning-runner.js +9 -4
- package/dist/runner/common/turn-started.d.ts +8 -0
- package/dist/runner/common/turn-started.js +11 -0
- package/dist/runner/dsh/approval.js +84 -51
- package/dist/runner/dsh/catalog-probe.d.ts +17 -0
- package/dist/runner/dsh/catalog-probe.js +10 -0
- package/dist/runner/dsh/client.d.ts +7 -11
- package/dist/runner/dsh/client.js +356 -289
- package/dist/runner/dsh/exit-cancel.d.ts +2 -2
- package/dist/runner/dsh/exit-cancel.js +2 -2
- package/dist/runner/dsh/inflight.d.ts +1 -1
- package/dist/runner/dsh/inflight.js +1 -1
- package/dist/runner/dsh/mux-stream.js +28 -8
- package/dist/runner/dsh/runner.d.ts +44 -4
- package/dist/runner/dsh/runner.js +296 -199
- package/dist/runner/dsh/translator.d.ts +1 -31
- package/dist/runner/dsh/translator.js +180 -178
- package/dist/runner/index.d.ts +1 -1
- package/dist/runner/kimi/acp/runner.d.ts +1 -2
- package/dist/runner/kimi/acp/runner.js +82 -46
- package/dist/runner/kimi/acp/translator.d.ts +1 -1
- package/dist/runner/kimi/acp/translator.js +3 -4
- package/dist/runner/opencode/acp/error-monitor.js +5 -5
- package/dist/runner/opencode/acp/runner.d.ts +2 -2
- package/dist/runner/opencode/acp/runner.js +4 -4
- package/dist/runner/pi/rpc/client.js +4 -13
- package/dist/runner/pi/rpc/protocol-types.d.ts +1 -1
- package/dist/runner/pi/rpc/protocol-types.js +1 -1
- package/dist/runner/pi/rpc/runner.d.ts +3 -0
- package/dist/runner/pi/rpc/runner.js +27 -42
- package/dist/runner/pi/rpc/translator.js +61 -60
- package/dist/runner/types.d.ts +2 -2
- package/dist/runner/types.js +1 -1
- package/dist/session/claude/sessions.d.ts +45 -0
- package/dist/session/claude/sessions.js +160 -122
- package/dist/session/codex/rollout-reader.js +181 -182
- package/dist/session/common/throw-session-list-error.d.ts +10 -0
- package/dist/session/common/throw-session-list-error.js +16 -0
- package/dist/session/dsh/sessions.js +291 -235
- package/dist/session/kimi/sessions.d.ts +40 -8
- package/dist/session/kimi/sessions.js +373 -301
- package/dist/session/opencode/sessions.d.ts +142 -1
- package/dist/session/opencode/sessions.js +378 -321
- package/dist/session/pi/sessions.js +4 -5
- package/dist/session/session-store.d.ts +9 -1
- package/dist/session/session-store.js +99 -99
- package/dist/update/version-check.js +2 -1
- package/dist/workspace/index.d.ts +1 -1
- package/dist/workspace/index.js +1 -1
- package/package.json +1 -1
|
@@ -3,6 +3,7 @@ import path from 'node:path';
|
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import { findJsonlLine } from '../common/jsonl.js';
|
|
5
5
|
import { scanJsonlOnce, tailOffsetAfter, scanTailEvents } from '../common/two-pass.js';
|
|
6
|
+
import { throwSessionListError } from '../common/throw-session-list-error.js';
|
|
6
7
|
import { extractContentBlocks } from '../common/content-blocks.js';
|
|
7
8
|
import { UsageAccumulator, contextWindowOccupancy, cumulativeUsageFields, } from '../common/usage-accumulator.js';
|
|
8
9
|
import { isStale } from '../common/constants.js';
|
|
@@ -63,7 +64,7 @@ function extractPiText(content) {
|
|
|
63
64
|
* dominates displayTitle and squeezes out the user's actual words.
|
|
64
65
|
* Replace the whole `<skill>…</skill>` block with `skill:x`, preserving any
|
|
65
66
|
* trailing real text. Falls back to the original text when no skill block
|
|
66
|
-
* is present (or the block is malformed/unclosed).
|
|
67
|
+
* is present (or the block is malformed/unclosed).
|
|
67
68
|
*/
|
|
68
69
|
function compressSkillInjection(text) {
|
|
69
70
|
return text
|
|
@@ -193,7 +194,7 @@ function piScalarScan(filePath) {
|
|
|
193
194
|
const text = extractPiText(msg.content);
|
|
194
195
|
// Compress skill-injection bodies so the "最近输入" label shows what
|
|
195
196
|
// the user invoked (skill:x) + any trailing real input, not a
|
|
196
|
-
// truncated SKILL.md head.
|
|
197
|
+
// truncated SKILL.md head.
|
|
197
198
|
if (text)
|
|
198
199
|
lastUserText = compressSkillInjection(text);
|
|
199
200
|
}
|
|
@@ -367,9 +368,7 @@ export class PiSessionReader {
|
|
|
367
368
|
if (err.code === 'ENOENT') {
|
|
368
369
|
return [];
|
|
369
370
|
}
|
|
370
|
-
|
|
371
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
372
|
-
throw new Error(`pi session list 读取失败: ${msg}`, { cause: err });
|
|
371
|
+
throwSessionListError('pi', err);
|
|
373
372
|
}
|
|
374
373
|
const sessions = [];
|
|
375
374
|
for (const f of files) {
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import type { AgentKind } from '../agent-kinds.js';
|
|
2
|
+
/**
|
|
3
|
+
* session reader 共用的失败留痕(claude stat / kimi realpath):ENOENT 是两次
|
|
4
|
+
* 查询之间的正常竞态,静默;其余 errno 必须 debug 留痕,否则「文件不可读」
|
|
5
|
+
* 会被误判成「会话不活跃」。文案由调用方按场景给出,逐字保持。
|
|
6
|
+
*/
|
|
7
|
+
export declare function logNonEnoentDebug(err: unknown, message: (errText: string) => string): void;
|
|
2
8
|
interface SessionEntry {
|
|
3
9
|
/** Session IDs per agent kind (Map for in-memory, plain object for persistence). */
|
|
4
10
|
sessions: Map<AgentKind, string>;
|
|
@@ -30,7 +36,7 @@ export declare class SessionStore {
|
|
|
30
36
|
private sessions;
|
|
31
37
|
private readonly persistPath?;
|
|
32
38
|
/**
|
|
33
|
-
*
|
|
39
|
+
* 进程内会话代际(防 /new 被在途 run init 写回撤销):
|
|
34
40
|
* 每次「用户意图移动 session 指针」+1。system.init 写回通道不 bump。
|
|
35
41
|
* Bridge 在 run 启动时快照 epoch,init 写回前比较——不一致说明 /new、
|
|
36
42
|
* /cd、/resume 等在 run 在途时移动了指针,该 run 的写回是 stale 的,丢弃。
|
|
@@ -73,6 +79,8 @@ export declare class SessionStore {
|
|
|
73
79
|
getArrivalSessionId(userId: string, agent: AgentKind): string | undefined;
|
|
74
80
|
/** Set the arrival baseline for a specific agent ('' explicitly clears the arrival baseline) */
|
|
75
81
|
setArrivalSessionId(userId: string, agent: AgentKind, sessionId: string): void;
|
|
82
|
+
/** previous/arrival 两类 setter 共用的单一实现(合并完全重复块)。 */
|
|
83
|
+
private writeSessionId;
|
|
76
84
|
/** Set cwd for a user, clearing all sessionIds (§9.1) */
|
|
77
85
|
setCwd(userId: string, cwd: string): void;
|
|
78
86
|
/** Get cwd for a user, or undefined if no session */
|
|
@@ -1,6 +1,90 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import { getLogger } from '../logger/index.js';
|
|
3
3
|
import { atomicWriteJson } from '../persistence/atomic-write.js';
|
|
4
|
+
/**
|
|
5
|
+
* session reader 共用的失败留痕(claude stat / kimi realpath):ENOENT 是两次
|
|
6
|
+
* 查询之间的正常竞态,静默;其余 errno 必须 debug 留痕,否则「文件不可读」
|
|
7
|
+
* 会被误判成「会话不活跃」。文案由调用方按场景给出,逐字保持。
|
|
8
|
+
*/
|
|
9
|
+
export function logNonEnoentDebug(err, message) {
|
|
10
|
+
if (err.code === 'ENOENT')
|
|
11
|
+
return;
|
|
12
|
+
getLogger().debug(message(err?.message ?? String(err)));
|
|
13
|
+
}
|
|
14
|
+
/** 四类 getter 共用的单一实现:entry 缺失 / 空串 → undefined。 */
|
|
15
|
+
function readSessionId(entry, key, agent) {
|
|
16
|
+
if (!entry)
|
|
17
|
+
return undefined;
|
|
18
|
+
const value = entry[key].get(agent);
|
|
19
|
+
if (!value)
|
|
20
|
+
return undefined;
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
/** 四个 session 字段缺一即损坏记录(整条跳过,cwd 允许缺失)。 */
|
|
24
|
+
function hasRequiredSessionFields(entry) {
|
|
25
|
+
return (!!entry.sessions && !!entry.previousSessions && !!entry.arrivalSessions && !!entry.sessionCwds);
|
|
26
|
+
}
|
|
27
|
+
/** 只保留 truthy 值(sessions / previousSessions / sessionCwds 的口径)。 */
|
|
28
|
+
function truthySessionMap(record) {
|
|
29
|
+
const map = new Map();
|
|
30
|
+
for (const [agent, sid] of Object.entries(record)) {
|
|
31
|
+
if (sid)
|
|
32
|
+
map.set(agent, sid);
|
|
33
|
+
}
|
|
34
|
+
return map;
|
|
35
|
+
}
|
|
36
|
+
/** 全保留(arrivalSessions 的 '' 是显式清空基线,必须跨重启存活)。 */
|
|
37
|
+
function fullSessionMap(record) {
|
|
38
|
+
const map = new Map();
|
|
39
|
+
for (const [agent, sid] of Object.entries(record)) {
|
|
40
|
+
map.set(agent, sid);
|
|
41
|
+
}
|
|
42
|
+
return map;
|
|
43
|
+
}
|
|
44
|
+
/** 单条持久化记录 → 内存 entry;损坏 / 完全空记录返回 undefined。 */
|
|
45
|
+
function parsePersistedEntry(data) {
|
|
46
|
+
if (typeof data !== 'object' || data === null)
|
|
47
|
+
return undefined;
|
|
48
|
+
const entry = data;
|
|
49
|
+
// 四个 session 字段缺失 = 损坏记录,整条跳过。cwd 允许缺失:
|
|
50
|
+
// 全新用户(未 /cd)先切 agent 时 previous/arrival 停车位已落盘,
|
|
51
|
+
// cwd 尚为空——不能因 cwd 缺失把停车位整条丢掉
|
|
52
|
+
// (anchor_r7_parked_previous_survives_rebuild_without_cwd)。
|
|
53
|
+
if (!hasRequiredSessionFields(entry))
|
|
54
|
+
return undefined;
|
|
55
|
+
const sessions = truthySessionMap(entry.sessions);
|
|
56
|
+
const previousSessions = truthySessionMap(entry.previousSessions);
|
|
57
|
+
const arrivalSessions = fullSessionMap(entry.arrivalSessions);
|
|
58
|
+
const sessionCwds = truthySessionMap(entry.sessionCwds);
|
|
59
|
+
// Persist any user that has state: cwd set, or any meaningful
|
|
60
|
+
// sessions/previousSessions value, or any arrival baseline entry
|
|
61
|
+
// ('' arrivals are meaningful). Fully empty records are skipped.
|
|
62
|
+
const hasCwd = !!entry.cwd && entry.cwd.length > 0;
|
|
63
|
+
if (hasCwd || sessions.size > 0 || previousSessions.size > 0 || arrivalSessions.size > 0) {
|
|
64
|
+
return {
|
|
65
|
+
sessions,
|
|
66
|
+
previousSessions,
|
|
67
|
+
sessionCwds,
|
|
68
|
+
arrivalSessions,
|
|
69
|
+
cwd: entry.cwd ?? '',
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
/** 损坏现场留痕:日志 + 改名保留(原文件继续躺着会重复告警、丢排障证据)。 */
|
|
75
|
+
function preserveCorruptStore(persistPath, err) {
|
|
76
|
+
getLogger().warn(`[session] persisted session store corrupted (${persistPath ?? '(memory)'}), ignoring:`, err);
|
|
77
|
+
if (persistPath) {
|
|
78
|
+
const brokenPath = `${persistPath}.corrupt-${Date.now()}`;
|
|
79
|
+
try {
|
|
80
|
+
fs.renameSync(persistPath, brokenPath);
|
|
81
|
+
getLogger().warn(`[session] moved corrupt store to ${brokenPath}`);
|
|
82
|
+
}
|
|
83
|
+
catch (renameErr) {
|
|
84
|
+
getLogger().warn('[session] failed to preserve corrupt store:', renameErr);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
4
88
|
/**
|
|
5
89
|
* Per-user session store. Persists cwd + per-agent sessions to disk so that
|
|
6
90
|
* the last cwd AND the last-used sessionId per agent are restored after
|
|
@@ -20,7 +104,7 @@ export class SessionStore {
|
|
|
20
104
|
sessions = new Map();
|
|
21
105
|
persistPath;
|
|
22
106
|
/**
|
|
23
|
-
*
|
|
107
|
+
* 进程内会话代际(防 /new 被在途 run init 写回撤销):
|
|
24
108
|
* 每次「用户意图移动 session 指针」+1。system.init 写回通道不 bump。
|
|
25
109
|
* Bridge 在 run 启动时快照 epoch,init 写回前比较——不一致说明 /new、
|
|
26
110
|
* /cd、/resume 等在 run 在途时移动了指针,该 run 的写回是 stale 的,丢弃。
|
|
@@ -104,20 +188,11 @@ export class SessionStore {
|
|
|
104
188
|
}
|
|
105
189
|
/** Get previous sessionId for a specific agent (stored when switching away) */
|
|
106
190
|
getPreviousSessionId(userId, agent) {
|
|
107
|
-
|
|
108
|
-
if (!entry)
|
|
109
|
-
return undefined;
|
|
110
|
-
const sessionId = entry.previousSessions.get(agent);
|
|
111
|
-
if (!sessionId)
|
|
112
|
-
return undefined;
|
|
113
|
-
return sessionId;
|
|
191
|
+
return readSessionId(this.sessions.get(userId), 'previousSessions', agent);
|
|
114
192
|
}
|
|
115
193
|
/** Set previous sessionId for a specific agent (for potential restore when switching back) */
|
|
116
194
|
setPreviousSessionId(userId, agent, sessionId) {
|
|
117
|
-
this.
|
|
118
|
-
entry.previousSessions.set(agent, sessionId);
|
|
119
|
-
return entry;
|
|
120
|
-
});
|
|
195
|
+
this.writeSessionId(userId, 'previousSessions', agent, sessionId);
|
|
121
196
|
}
|
|
122
197
|
/** Clear previous sessionId for a specific agent */
|
|
123
198
|
clearPreviousSessionId(userId, agent) {
|
|
@@ -128,18 +203,16 @@ export class SessionStore {
|
|
|
128
203
|
}
|
|
129
204
|
/** Get the arrival baseline sessionId for a specific agent ('' and missing → undefined) */
|
|
130
205
|
getArrivalSessionId(userId, agent) {
|
|
131
|
-
|
|
132
|
-
if (!entry)
|
|
133
|
-
return undefined;
|
|
134
|
-
const sessionId = entry.arrivalSessions.get(agent);
|
|
135
|
-
if (!sessionId)
|
|
136
|
-
return undefined;
|
|
137
|
-
return sessionId;
|
|
206
|
+
return readSessionId(this.sessions.get(userId), 'arrivalSessions', agent);
|
|
138
207
|
}
|
|
139
208
|
/** Set the arrival baseline for a specific agent ('' explicitly clears the arrival baseline) */
|
|
140
209
|
setArrivalSessionId(userId, agent, sessionId) {
|
|
210
|
+
this.writeSessionId(userId, 'arrivalSessions', agent, sessionId);
|
|
211
|
+
}
|
|
212
|
+
/** previous/arrival 两类 setter 共用的单一实现(合并完全重复块)。 */
|
|
213
|
+
writeSessionId(userId, key, agent, sessionId) {
|
|
141
214
|
this.mutateEntry(userId, (entry) => {
|
|
142
|
-
entry.
|
|
215
|
+
entry[key].set(agent, sessionId);
|
|
143
216
|
return entry;
|
|
144
217
|
});
|
|
145
218
|
}
|
|
@@ -165,13 +238,7 @@ export class SessionStore {
|
|
|
165
238
|
}
|
|
166
239
|
/** Get sessionId for a specific agent, or undefined if no session or sessionId is empty */
|
|
167
240
|
getSessionId(userId, agent = 'claude') {
|
|
168
|
-
|
|
169
|
-
if (!entry)
|
|
170
|
-
return undefined;
|
|
171
|
-
const sessionId = entry.sessions.get(agent);
|
|
172
|
-
if (!sessionId)
|
|
173
|
-
return undefined;
|
|
174
|
-
return sessionId;
|
|
241
|
+
return readSessionId(this.sessions.get(userId), 'sessions', agent);
|
|
175
242
|
}
|
|
176
243
|
/** Set sessionId for a specific agent, optionally with cwd */
|
|
177
244
|
setSessionId(userId, agent, sessionId, cwd) {
|
|
@@ -196,13 +263,7 @@ export class SessionStore {
|
|
|
196
263
|
}
|
|
197
264
|
/** Get sessionCwd for a specific agent, or undefined if not set */
|
|
198
265
|
getSessionCwd(userId, agent = 'claude') {
|
|
199
|
-
|
|
200
|
-
if (!entry)
|
|
201
|
-
return undefined;
|
|
202
|
-
const sessionCwd = entry.sessionCwds.get(agent);
|
|
203
|
-
if (!sessionCwd)
|
|
204
|
-
return undefined;
|
|
205
|
-
return sessionCwd;
|
|
266
|
+
return readSessionId(this.sessions.get(userId), 'sessionCwds', agent);
|
|
206
267
|
}
|
|
207
268
|
/** Set sessionId and sessionCwd for a specific agent, without touching cwd */
|
|
208
269
|
setSessionIdAndSessionCwd(userId, agent, sessionId, sessionCwd) {
|
|
@@ -224,75 +285,14 @@ export class SessionStore {
|
|
|
224
285
|
const parsed = JSON.parse(raw);
|
|
225
286
|
if (typeof parsed === 'object' && parsed !== null) {
|
|
226
287
|
for (const [userId, data] of Object.entries(parsed)) {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
// 全新用户(未 /cd)先切 agent 时 previous/arrival 停车位已落盘,
|
|
231
|
-
// cwd 尚为空——不能因 cwd 缺失把停车位整条丢掉
|
|
232
|
-
// (anchor_r7_parked_previous_survives_rebuild_without_cwd)。
|
|
233
|
-
if (!entry.sessions ||
|
|
234
|
-
!entry.previousSessions ||
|
|
235
|
-
!entry.arrivalSessions ||
|
|
236
|
-
!entry.sessionCwds) {
|
|
237
|
-
continue;
|
|
238
|
-
}
|
|
239
|
-
const sessions = new Map();
|
|
240
|
-
for (const [agent, sid] of Object.entries(entry.sessions)) {
|
|
241
|
-
if (sid) {
|
|
242
|
-
sessions.set(agent, sid);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
const previousSessions = new Map();
|
|
246
|
-
for (const [agent, sid] of Object.entries(entry.previousSessions)) {
|
|
247
|
-
if (sid) {
|
|
248
|
-
previousSessions.set(agent, sid);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
const arrivalSessions = new Map();
|
|
252
|
-
for (const [agent, sid] of Object.entries(entry.arrivalSessions)) {
|
|
253
|
-
// '' entries are meaningful: explicit "cleared arrival" must
|
|
254
|
-
// survive a restart instead of being re-defaulted.
|
|
255
|
-
arrivalSessions.set(agent, sid);
|
|
256
|
-
}
|
|
257
|
-
const sessionCwds = new Map();
|
|
258
|
-
for (const [agent, scwd] of Object.entries(entry.sessionCwds)) {
|
|
259
|
-
if (scwd) {
|
|
260
|
-
sessionCwds.set(agent, scwd);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
// Persist any user that has state: cwd set, or any meaningful
|
|
264
|
-
// sessions/previousSessions value, or any arrival baseline entry
|
|
265
|
-
// ('' arrivals are meaningful). Fully empty records are skipped.
|
|
266
|
-
const hasCwd = !!entry.cwd && entry.cwd.length > 0;
|
|
267
|
-
if (hasCwd ||
|
|
268
|
-
sessions.size > 0 ||
|
|
269
|
-
previousSessions.size > 0 ||
|
|
270
|
-
arrivalSessions.size > 0) {
|
|
271
|
-
this.sessions.set(userId, {
|
|
272
|
-
sessions,
|
|
273
|
-
previousSessions,
|
|
274
|
-
sessionCwds,
|
|
275
|
-
arrivalSessions,
|
|
276
|
-
cwd: entry.cwd ?? '',
|
|
277
|
-
});
|
|
278
|
-
}
|
|
279
|
-
}
|
|
288
|
+
const entry = parsePersistedEntry(data);
|
|
289
|
+
if (entry)
|
|
290
|
+
this.sessions.set(userId, entry);
|
|
280
291
|
}
|
|
281
292
|
}
|
|
282
293
|
}
|
|
283
294
|
catch (err) {
|
|
284
|
-
|
|
285
|
-
// 改名保留现场:原文件继续原地躺着会让下次启动重复告警,也丢掉排障证据。
|
|
286
|
-
if (this.persistPath) {
|
|
287
|
-
const brokenPath = `${this.persistPath}.corrupt-${Date.now()}`;
|
|
288
|
-
try {
|
|
289
|
-
fs.renameSync(this.persistPath, brokenPath);
|
|
290
|
-
getLogger().warn(`[session] moved corrupt store to ${brokenPath}`);
|
|
291
|
-
}
|
|
292
|
-
catch (renameErr) {
|
|
293
|
-
getLogger().warn('[session] failed to preserve corrupt store:', renameErr);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
295
|
+
preserveCorruptStore(this.persistPath, err);
|
|
296
296
|
}
|
|
297
297
|
}
|
|
298
298
|
autoPersist() {
|
|
@@ -11,7 +11,7 @@ export interface WorkspaceEntry {
|
|
|
11
11
|
* mid-write cannot leave a truncated JSON file. On load, a corrupt file
|
|
12
12
|
* is treated as empty (with a warning) so the lark-remote can still start.
|
|
13
13
|
*
|
|
14
|
-
* lastUsedAt
|
|
14
|
+
* lastUsedAt 语义:保存(save)与使用(use/touch)
|
|
15
15
|
* 都会把时间戳更新为当前时间。save 内部调用 touch,保证「最近使用」排序
|
|
16
16
|
* 对新保存的 cwd 同样生效(新条目应排在列表最前,而非沉底)。
|
|
17
17
|
* 同一毫秒内连续操作时 touch 会用 max+1 保证严格递增,避免 Date.now 相同
|
package/dist/workspace/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import { getLogger } from '../logger/index.js';
|
|
|
10
10
|
* mid-write cannot leave a truncated JSON file. On load, a corrupt file
|
|
11
11
|
* is treated as empty (with a warning) so the lark-remote can still start.
|
|
12
12
|
*
|
|
13
|
-
* lastUsedAt
|
|
13
|
+
* lastUsedAt 语义:保存(save)与使用(use/touch)
|
|
14
14
|
* 都会把时间戳更新为当前时间。save 内部调用 touch,保证「最近使用」排序
|
|
15
15
|
* 对新保存的 cwd 同样生效(新条目应排在列表最前,而非沉底)。
|
|
16
16
|
* 同一毫秒内连续操作时 touch 会用 max+1 保证严格递增,避免 Date.now 相同
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lark-remote",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.21",
|
|
4
4
|
"description": "Feishu (Lark) private-chat bridge to local coding agents — Claude Code / Codex / opencode / pi / kimi, with live-streaming CardKit 2.0 cards",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|