lark-remote 0.1.6 → 0.1.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/CHANGELOG.md +23 -1
- package/README.en.md +9 -1
- package/README.md +14 -2
- package/dist/bridge/approval-coordinator.d.ts +57 -34
- package/dist/bridge/approval-coordinator.js +191 -40
- package/dist/bridge/inbound-media.d.ts +62 -0
- package/dist/bridge/inbound-media.js +282 -0
- package/dist/bridge/index.d.ts +78 -7
- package/dist/bridge/index.js +202 -79
- package/dist/bridge/queue-manager.d.ts +2 -1
- package/dist/bridge/queue-manager.js +1 -0
- package/dist/card/approval-render.js +152 -36
- package/dist/card/bash-card-session.d.ts +2 -24
- package/dist/card/bash-card-session.js +6 -73
- package/dist/card/bash-renderer.js +2 -3
- package/dist/card/card-budget.js +29 -75
- package/dist/card/card-session.d.ts +48 -0
- package/dist/card/card-session.js +86 -0
- package/dist/card/card-shared.d.ts +1 -12
- package/dist/card/card-shared.js +1 -26
- package/dist/card/run-card-session.d.ts +2 -55
- package/dist/card/run-card-session.js +6 -104
- package/dist/card/run-renderer.js +99 -232
- package/dist/card/run-state.d.ts +13 -0
- package/dist/card/run-state.js +25 -16
- package/dist/card/text-truncate.d.ts +13 -12
- package/dist/card/text-truncate.js +13 -63
- package/dist/common/fs.d.ts +8 -0
- package/dist/common/fs.js +17 -0
- package/dist/common/guards.d.ts +0 -20
- package/dist/common/guards.js +0 -43
- package/dist/common/sleep.d.ts +2 -0
- package/dist/common/sleep.js +5 -0
- package/dist/common/truncate.d.ts +39 -0
- package/dist/common/truncate.js +92 -0
- package/dist/config/codex-config.d.ts +1 -1
- package/dist/config/codex-config.js +1 -1
- package/dist/config/index.d.ts +88 -23
- package/dist/config/index.js +105 -34
- package/dist/connector/index.d.ts +69 -2
- package/dist/connector/index.js +107 -1
- package/dist/index.js +123 -105
- package/dist/instance-lock.js +4 -12
- package/dist/order/alias-resolve.d.ts +13 -0
- package/dist/order/alias-resolve.js +22 -0
- package/dist/order/alias-store.d.ts +38 -0
- package/dist/order/alias-store.js +106 -0
- package/dist/persistence/atomic-write.d.ts +8 -2
- package/dist/persistence/atomic-write.js +23 -7
- package/dist/restart.js +2 -1
- package/dist/router/card-helpers.d.ts +63 -0
- package/dist/router/card-helpers.js +146 -0
- package/dist/router/config/claude.js +25 -1
- package/dist/router/config/codex.js +29 -50
- package/dist/router/config/common/model-patch.d.ts +22 -0
- package/dist/router/config/common/model-patch.js +26 -0
- package/dist/router/config/common/render.js +5 -4
- package/dist/router/config/index.d.ts +12 -0
- package/dist/router/config/index.js +25 -1
- package/dist/router/config/kimi.d.ts +4 -1
- package/dist/router/config/kimi.js +27 -0
- package/dist/router/config/opencode.js +18 -5
- package/dist/router/config/pi.js +4 -5
- package/dist/router/config/types.d.ts +11 -2
- package/dist/router/index.d.ts +56 -21
- package/dist/router/index.js +373 -548
- package/dist/router/utils.d.ts +2 -0
- package/dist/router/utils.js +4 -0
- package/dist/runner/agent-choices-common.d.ts +16 -0
- package/dist/runner/agent-choices-common.js +31 -0
- package/dist/runner/claude/runner.d.ts +47 -10
- package/dist/runner/claude/runner.js +117 -46
- package/dist/runner/claude/session.d.ts +166 -0
- package/dist/runner/claude/session.js +749 -0
- package/dist/runner/codex/app-server/protocol-types.d.ts +31 -39
- package/dist/runner/codex/app-server/protocol-types.js +1 -12
- package/dist/runner/codex/app-server/runner.d.ts +42 -59
- package/dist/runner/codex/app-server/runner.js +160 -337
- package/dist/runner/codex/app-server/translator.d.ts +1 -21
- package/dist/runner/codex/app-server/translator.js +0 -18
- package/dist/runner/codex/index.d.ts +0 -2
- package/dist/runner/codex/index.js +0 -2
- package/dist/runner/common/acp/protocol-helpers.d.ts +14 -0
- package/dist/runner/common/acp/protocol-helpers.js +21 -0
- package/dist/runner/common/acp/protocol-types.d.ts +238 -0
- package/dist/runner/common/acp/protocol-types.js +75 -0
- package/dist/runner/common/connection-based-runner.d.ts +111 -0
- package/dist/runner/common/connection-based-runner.js +261 -0
- package/dist/runner/{codex/app-server → common/jsonrpc}/client.d.ts +14 -7
- package/dist/runner/{codex/app-server → common/jsonrpc}/client.js +27 -18
- package/dist/runner/common/jsonrpc/connection-manager.d.ts +125 -0
- package/dist/runner/{codex/app-server → common/jsonrpc}/connection-manager.js +63 -28
- package/dist/runner/{codex/app-server → common/jsonrpc}/transport.d.ts +5 -4
- package/dist/runner/{codex/app-server → common/jsonrpc}/transport.js +18 -19
- package/dist/runner/common/jsonrpc/types.d.ts +32 -0
- package/dist/runner/common/jsonrpc/types.js +9 -0
- package/dist/runner/common/process-stopper.d.ts +2 -1
- package/dist/runner/common/process-stopper.js +1 -0
- package/dist/runner/common/runner-utils.d.ts +6 -13
- package/dist/runner/common/runner-utils.js +6 -47
- package/dist/runner/common/spawning-runner.d.ts +24 -70
- package/dist/runner/common/spawning-runner.js +98 -152
- package/dist/runner/index.d.ts +4 -4
- package/dist/runner/index.js +4 -4
- package/dist/runner/kimi/acp/runner.d.ts +106 -0
- package/dist/runner/kimi/acp/runner.js +448 -0
- package/dist/runner/kimi/acp/translator.d.ts +124 -0
- package/dist/runner/kimi/acp/translator.js +336 -0
- package/dist/runner/kimi/index.d.ts +1 -1
- package/dist/runner/kimi/index.js +1 -1
- package/dist/runner/opencode/acp/index.d.ts +1 -0
- package/dist/runner/opencode/acp/index.js +2 -0
- package/dist/runner/opencode/acp/runner.d.ts +121 -0
- package/dist/runner/opencode/acp/runner.js +429 -0
- package/dist/runner/opencode/acp/translator.d.ts +119 -0
- package/dist/runner/opencode/acp/translator.js +345 -0
- package/dist/runner/opencode/index.d.ts +1 -1
- package/dist/runner/opencode/index.js +1 -1
- package/dist/runner/pi/index.d.ts +1 -1
- package/dist/runner/pi/index.js +1 -1
- package/dist/runner/pi/rpc/client.d.ts +52 -0
- package/dist/runner/pi/rpc/client.js +114 -0
- package/dist/runner/pi/rpc/index.d.ts +4 -0
- package/dist/runner/pi/rpc/index.js +4 -0
- package/dist/runner/pi/rpc/protocol-types.d.ts +127 -0
- package/dist/runner/pi/rpc/protocol-types.js +21 -0
- package/dist/runner/pi/rpc/runner.d.ts +80 -0
- package/dist/runner/pi/rpc/runner.js +199 -0
- package/dist/runner/pi/rpc/translator.d.ts +55 -0
- package/dist/runner/pi/rpc/translator.js +258 -0
- package/dist/runner/registry.d.ts +7 -8
- package/dist/runner/registry.js +3 -4
- package/dist/runner/resolve-agent-choices.js +18 -59
- package/dist/runner/sync-agent-choices.js +16 -67
- package/dist/runner/types.d.ts +43 -13
- package/dist/session/claude/session-index.js +2 -3
- package/dist/session/claude/session-reader.js +3 -6
- package/dist/session/claude/sessions.js +6 -13
- package/dist/session/codex/rollout-reader.d.ts +2 -2
- package/dist/session/codex/rollout-reader.js +14 -17
- package/dist/session/codex/sessions.d.ts +1 -1
- package/dist/session/codex/sessions.js +2 -2
- package/dist/session/common/content-blocks.d.ts +7 -0
- package/dist/session/common/content-blocks.js +13 -9
- package/dist/session/common/jsonl.d.ts +8 -25
- package/dist/session/common/jsonl.js +126 -261
- package/dist/session/common/pagination.d.ts +28 -0
- package/dist/session/common/pagination.js +33 -0
- package/dist/session/kimi/sessions.d.ts +34 -1
- package/dist/session/kimi/sessions.js +208 -98
- package/dist/session/opencode/sessions.d.ts +17 -3
- package/dist/session/opencode/sessions.js +29 -29
- package/dist/session/pi/sessions.d.ts +5 -1
- package/dist/session/pi/sessions.js +12 -16
- package/dist/session/session-store.d.ts +11 -1
- package/dist/session/session-store.js +75 -178
- package/dist/update/index.d.ts +2 -2
- package/dist/update/index.js +2 -2
- package/dist/update/install.d.ts +20 -2
- package/dist/update/install.js +51 -7
- package/package.json +1 -1
- package/dist/runner/codex/app-server/connection-manager.d.ts +0 -56
- package/dist/runner/codex/argv.d.ts +0 -33
- package/dist/runner/codex/argv.js +0 -40
- package/dist/runner/codex/factory.d.ts +0 -29
- package/dist/runner/codex/factory.js +0 -39
- package/dist/runner/codex/jsonl.d.ts +0 -37
- package/dist/runner/codex/jsonl.js +0 -221
- package/dist/runner/codex/runner.d.ts +0 -66
- package/dist/runner/codex/runner.js +0 -129
- package/dist/runner/common/exec-translator.d.ts +0 -73
- package/dist/runner/common/exec-translator.js +0 -105
- package/dist/runner/kimi/jsonl.d.ts +0 -28
- package/dist/runner/kimi/jsonl.js +0 -143
- package/dist/runner/kimi/runner.d.ts +0 -49
- package/dist/runner/kimi/runner.js +0 -105
- package/dist/runner/opencode/argv.d.ts +0 -32
- package/dist/runner/opencode/argv.js +0 -35
- package/dist/runner/opencode/jsonl.d.ts +0 -68
- package/dist/runner/opencode/jsonl.js +0 -295
- package/dist/runner/opencode/runner.d.ts +0 -61
- package/dist/runner/opencode/runner.js +0 -93
- package/dist/runner/pi/jsonl.d.ts +0 -128
- package/dist/runner/pi/jsonl.js +0 -249
- package/dist/runner/pi/runner.d.ts +0 -36
- package/dist/runner/pi/runner.js +0 -76
- package/dist/session/common/catch-up.d.ts +0 -12
- package/dist/session/common/catch-up.js +0 -31
|
@@ -4,8 +4,8 @@ import os from 'node:os';
|
|
|
4
4
|
import { findJsonlLine, scanJsonlLines, readJsonlLinesFromOffset } from '../common/jsonl.js';
|
|
5
5
|
import { extractContentBlocks } from '../common/content-blocks.js';
|
|
6
6
|
import { UsageAccumulator } from '../common/usage-accumulator.js';
|
|
7
|
-
import { truncate } from '../../card/card-shared.js';
|
|
8
7
|
import { STALE_MS } from '../common/constants.js';
|
|
8
|
+
import { capEvents, paginate } from '../common/pagination.js';
|
|
9
9
|
function defaultPiDir() {
|
|
10
10
|
return path.join(os.homedir(), '.pi', 'agent');
|
|
11
11
|
}
|
|
@@ -24,7 +24,7 @@ const PI_LIST_TTL_MS = 5000;
|
|
|
24
24
|
const PI_LIST_MAX_ENTRIES = 32;
|
|
25
25
|
const piListCache = new Map();
|
|
26
26
|
/** Pi-specific field-name mapping for content block extraction. */
|
|
27
|
-
const PI_MAPPING = {
|
|
27
|
+
export const PI_MAPPING = {
|
|
28
28
|
toolUseType: 'toolCall',
|
|
29
29
|
toolResultType: 'toolResult',
|
|
30
30
|
toolInputField: 'arguments',
|
|
@@ -187,9 +187,10 @@ function piScalarScan(filePath) {
|
|
|
187
187
|
return {
|
|
188
188
|
tailOffset,
|
|
189
189
|
usage: buildPiUsage(acc),
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
190
|
+
// Whitespace-normalized single-line display title (no length truncation —
|
|
191
|
+
// the consumer truncates). Normalization collapses the skill-injection
|
|
192
|
+
// newlines so the title stays on one line.
|
|
193
|
+
displayTitle: lastUserText ? lastUserText.replace(/\s+/g, ' ').trim() : undefined,
|
|
193
194
|
};
|
|
194
195
|
}
|
|
195
196
|
/**
|
|
@@ -273,19 +274,19 @@ function extractPiEventsFromTail(tailLines) {
|
|
|
273
274
|
*/
|
|
274
275
|
export class PiSessionReader {
|
|
275
276
|
piDir;
|
|
277
|
+
/** 会话目录(public:测试可重定向到 fixture 目录,替代 as any)。 */
|
|
276
278
|
sessionsDir;
|
|
277
279
|
constructor(opts = {}) {
|
|
278
280
|
this.piDir = opts.piDir ?? defaultPiDir();
|
|
279
281
|
this.sessionsDir = path.join(this.piDir, 'sessions');
|
|
280
282
|
}
|
|
281
283
|
listSessions(cwd, opts) {
|
|
282
|
-
const limit = opts?.limit ?? 20;
|
|
283
|
-
const offset = Math.max(0, opts?.offset ?? 0);
|
|
284
284
|
// SCAN: filesystem is the source of truth for pi sessions.
|
|
285
285
|
const scanned = this.listSessionsByScan(cwd);
|
|
286
|
+
const { items, total } = paginate(scanned, opts ?? {});
|
|
286
287
|
return {
|
|
287
|
-
sessions:
|
|
288
|
-
total
|
|
288
|
+
sessions: items,
|
|
289
|
+
total,
|
|
289
290
|
};
|
|
290
291
|
}
|
|
291
292
|
getNewestSession(cwd) {
|
|
@@ -322,12 +323,7 @@ export class PiSessionReader {
|
|
|
322
323
|
// Apply maxEvents cap: keep the LAST N events (most recent), matching
|
|
323
324
|
// CodexSessionReader's slice(-maxEvents). maxEvents limits the catch-up
|
|
324
325
|
// tail so auto-resume cards don't load the entire session.
|
|
325
|
-
|
|
326
|
-
const cappedEvents = opts?.maxEvents !== undefined
|
|
327
|
-
? opts.maxEvents <= 0
|
|
328
|
-
? []
|
|
329
|
-
: events.slice(-opts.maxEvents)
|
|
330
|
-
: events;
|
|
326
|
+
const cappedEvents = capEvents(events, opts?.maxEvents);
|
|
331
327
|
return {
|
|
332
328
|
events: cappedEvents,
|
|
333
329
|
usage: scan.usage,
|
|
@@ -376,7 +372,7 @@ export class PiSessionReader {
|
|
|
376
372
|
const sessionId = stem.includes('_') ? stem.slice(stem.lastIndexOf('_') + 1) : stem;
|
|
377
373
|
sessions.push({
|
|
378
374
|
sessionId,
|
|
379
|
-
summary:
|
|
375
|
+
summary: summarizePiSession(full),
|
|
380
376
|
mtime: st.mtimeMs,
|
|
381
377
|
});
|
|
382
378
|
}
|
|
@@ -48,6 +48,16 @@ export declare class SessionStore {
|
|
|
48
48
|
/** 用户意图移动了全部 agent 的 session 指针(/cd、/ws use 的 setCwd)。 */
|
|
49
49
|
private bumpUserEpoch;
|
|
50
50
|
constructor(persistPath?: string, defaultAgent?: AgentKind);
|
|
51
|
+
/** A fresh, empty session entry (default factory). */
|
|
52
|
+
private static emptyEntry;
|
|
53
|
+
/**
|
|
54
|
+
* Clone the user's entry, apply `mutate` to it, and store the result.
|
|
55
|
+
* Creates a fresh empty entry when the user has none. All the per-field
|
|
56
|
+
* setters (clearSessionId / setPreviousSessionId / setArrivalSessionId /
|
|
57
|
+
* setCwd / setSessionId / setSessionIdAndCwd / setSessionIdAndSessionCwd)
|
|
58
|
+
* use this to avoid each re-spelling the "clone entry, tweak one Map" dance.
|
|
59
|
+
*/
|
|
60
|
+
private mutateEntry;
|
|
51
61
|
get(userId: string): SessionEntry | undefined;
|
|
52
62
|
set(userId: string, entry: SessionEntry): void;
|
|
53
63
|
delete(userId: string): void;
|
|
@@ -79,7 +89,7 @@ export declare class SessionStore {
|
|
|
79
89
|
getSessionCwd(userId: string, agent?: AgentKind): string | undefined;
|
|
80
90
|
/** Set sessionId and sessionCwd for a specific agent, without touching cwd */
|
|
81
91
|
setSessionIdAndSessionCwd(userId: string, agent: AgentKind, sessionId: string, sessionCwd: string): void;
|
|
82
|
-
/** Persisted format:
|
|
92
|
+
/** Persisted format: cwd + sessions + previous/arrival session maps. */
|
|
83
93
|
private load;
|
|
84
94
|
private autoPersist;
|
|
85
95
|
}
|
|
@@ -53,6 +53,37 @@ export class SessionStore {
|
|
|
53
53
|
if (persistPath)
|
|
54
54
|
this.load();
|
|
55
55
|
}
|
|
56
|
+
/** A fresh, empty session entry (default factory). */
|
|
57
|
+
static emptyEntry(cwd = '') {
|
|
58
|
+
return {
|
|
59
|
+
sessions: new Map(),
|
|
60
|
+
previousSessions: new Map(),
|
|
61
|
+
sessionCwds: new Map(),
|
|
62
|
+
arrivalSessions: new Map(),
|
|
63
|
+
cwd,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Clone the user's entry, apply `mutate` to it, and store the result.
|
|
68
|
+
* Creates a fresh empty entry when the user has none. All the per-field
|
|
69
|
+
* setters (clearSessionId / setPreviousSessionId / setArrivalSessionId /
|
|
70
|
+
* setCwd / setSessionId / setSessionIdAndCwd / setSessionIdAndSessionCwd)
|
|
71
|
+
* use this to avoid each re-spelling the "clone entry, tweak one Map" dance.
|
|
72
|
+
*/
|
|
73
|
+
mutateEntry(userId, mutate) {
|
|
74
|
+
const current = this.sessions.get(userId);
|
|
75
|
+
const base = current
|
|
76
|
+
? {
|
|
77
|
+
sessions: new Map(current.sessions),
|
|
78
|
+
previousSessions: new Map(current.previousSessions),
|
|
79
|
+
sessionCwds: new Map(current.sessionCwds),
|
|
80
|
+
arrivalSessions: new Map(current.arrivalSessions),
|
|
81
|
+
cwd: current.cwd,
|
|
82
|
+
}
|
|
83
|
+
: SessionStore.emptyEntry();
|
|
84
|
+
this.sessions.set(userId, mutate(base));
|
|
85
|
+
this.autoPersist();
|
|
86
|
+
}
|
|
56
87
|
get(userId) {
|
|
57
88
|
return this.sessions.get(userId);
|
|
58
89
|
}
|
|
@@ -69,23 +100,13 @@ export class SessionStore {
|
|
|
69
100
|
// 无条件 bump:空→空也必须可检测(事故场景正是 run 以 (none) 启动,
|
|
70
101
|
// /new 后 store 仍为空,值比较会误判「没变」)。entry 不存在同样 bump。
|
|
71
102
|
this.bumpSessionEpoch(userId, agent);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const newSessions = new Map(entry.sessions);
|
|
75
|
-
newSessions.set(agent, '');
|
|
76
|
-
const newSessionCwds = new Map(entry.sessionCwds);
|
|
103
|
+
this.mutateEntry(userId, (entry) => {
|
|
104
|
+
entry.sessions.set(agent, '');
|
|
77
105
|
if (opts?.clearSessionCwd) {
|
|
78
|
-
|
|
106
|
+
entry.sessionCwds.set(agent, '');
|
|
79
107
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
previousSessions: entry.previousSessions,
|
|
83
|
-
sessionCwds: newSessionCwds,
|
|
84
|
-
arrivalSessions: entry.arrivalSessions,
|
|
85
|
-
cwd: entry.cwd,
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
this.autoPersist();
|
|
108
|
+
return entry;
|
|
109
|
+
});
|
|
89
110
|
}
|
|
90
111
|
/** Get previous sessionId for a specific agent (stored when switching away) */
|
|
91
112
|
getPreviousSessionId(userId, agent) {
|
|
@@ -99,46 +120,17 @@ export class SessionStore {
|
|
|
99
120
|
}
|
|
100
121
|
/** Set previous sessionId for a specific agent (for potential restore when switching back) */
|
|
101
122
|
setPreviousSessionId(userId, agent, sessionId) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
this.sessions.set(userId, {
|
|
107
|
-
sessions: entry.sessions,
|
|
108
|
-
previousSessions: newPrevious,
|
|
109
|
-
sessionCwds: entry.sessionCwds,
|
|
110
|
-
arrivalSessions: entry.arrivalSessions,
|
|
111
|
-
cwd: entry.cwd,
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
const newPrevious = new Map();
|
|
116
|
-
newPrevious.set(agent, sessionId);
|
|
117
|
-
this.sessions.set(userId, {
|
|
118
|
-
sessions: new Map(),
|
|
119
|
-
previousSessions: newPrevious,
|
|
120
|
-
sessionCwds: new Map(),
|
|
121
|
-
arrivalSessions: new Map(),
|
|
122
|
-
cwd: '',
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
this.autoPersist();
|
|
123
|
+
this.mutateEntry(userId, (entry) => {
|
|
124
|
+
entry.previousSessions.set(agent, sessionId);
|
|
125
|
+
return entry;
|
|
126
|
+
});
|
|
126
127
|
}
|
|
127
128
|
/** Clear previous sessionId for a specific agent */
|
|
128
129
|
clearPreviousSessionId(userId, agent) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
this.sessions.set(userId, {
|
|
134
|
-
sessions: entry.sessions,
|
|
135
|
-
previousSessions: newPrevious,
|
|
136
|
-
sessionCwds: entry.sessionCwds,
|
|
137
|
-
arrivalSessions: entry.arrivalSessions,
|
|
138
|
-
cwd: entry.cwd,
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
this.autoPersist();
|
|
130
|
+
this.mutateEntry(userId, (entry) => {
|
|
131
|
+
entry.previousSessions.delete(agent);
|
|
132
|
+
return entry;
|
|
133
|
+
});
|
|
142
134
|
}
|
|
143
135
|
/** Get the arrival baseline sessionId for a specific agent ('' and missing → undefined) */
|
|
144
136
|
getArrivalSessionId(userId, agent) {
|
|
@@ -152,60 +144,26 @@ export class SessionStore {
|
|
|
152
144
|
}
|
|
153
145
|
/** Set the arrival baseline for a specific agent ('' explicitly clears the arrival baseline) */
|
|
154
146
|
setArrivalSessionId(userId, agent, sessionId) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
this.sessions.set(userId, {
|
|
160
|
-
sessions: entry.sessions,
|
|
161
|
-
previousSessions: entry.previousSessions,
|
|
162
|
-
sessionCwds: entry.sessionCwds,
|
|
163
|
-
arrivalSessions: newArrival,
|
|
164
|
-
cwd: entry.cwd,
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
else {
|
|
168
|
-
const newArrival = new Map();
|
|
169
|
-
newArrival.set(agent, sessionId);
|
|
170
|
-
this.sessions.set(userId, {
|
|
171
|
-
sessions: new Map(),
|
|
172
|
-
previousSessions: new Map(),
|
|
173
|
-
sessionCwds: new Map(),
|
|
174
|
-
arrivalSessions: newArrival,
|
|
175
|
-
cwd: '',
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
this.autoPersist();
|
|
147
|
+
this.mutateEntry(userId, (entry) => {
|
|
148
|
+
entry.arrivalSessions.set(agent, sessionId);
|
|
149
|
+
return entry;
|
|
150
|
+
});
|
|
179
151
|
}
|
|
180
152
|
/** Set cwd for a user, clearing all sessionIds (§9.1) */
|
|
181
153
|
setCwd(userId, cwd) {
|
|
182
154
|
// §9.1 setCwd 清全部 agent 的 sessionId → user 级 bump,覆盖 sessions
|
|
183
155
|
// map 里还没有 key 的 agent(run 刚启动、首个 init 未写回时 /cd 的边界)。
|
|
184
156
|
this.bumpUserEpoch(userId);
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
for (const key of newSessions.keys()) {
|
|
189
|
-
newSessions.set(key, '');
|
|
157
|
+
this.mutateEntry(userId, (entry) => {
|
|
158
|
+
for (const key of entry.sessions.keys()) {
|
|
159
|
+
entry.sessions.set(key, '');
|
|
190
160
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
else {
|
|
200
|
-
this.sessions.set(userId, {
|
|
201
|
-
sessions: new Map(),
|
|
202
|
-
previousSessions: new Map(),
|
|
203
|
-
sessionCwds: new Map(),
|
|
204
|
-
arrivalSessions: new Map(),
|
|
205
|
-
cwd,
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
this.autoPersist();
|
|
161
|
+
entry.previousSessions = new Map();
|
|
162
|
+
entry.sessionCwds = new Map();
|
|
163
|
+
entry.arrivalSessions = new Map();
|
|
164
|
+
entry.cwd = cwd;
|
|
165
|
+
return entry;
|
|
166
|
+
});
|
|
209
167
|
}
|
|
210
168
|
/** Get cwd for a user, or undefined if no session */
|
|
211
169
|
getCwd(userId) {
|
|
@@ -224,61 +182,23 @@ export class SessionStore {
|
|
|
224
182
|
/** Set sessionId for a specific agent, optionally with cwd */
|
|
225
183
|
setSessionId(userId, agent, sessionId, cwd) {
|
|
226
184
|
this.bumpSessionEpoch(userId, agent);
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
previousSessions: entry.previousSessions,
|
|
234
|
-
sessionCwds: entry.sessionCwds,
|
|
235
|
-
arrivalSessions: entry.arrivalSessions,
|
|
236
|
-
cwd: cwd ?? entry.cwd,
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
else {
|
|
240
|
-
const newSessions = new Map();
|
|
241
|
-
newSessions.set(agent, sessionId);
|
|
242
|
-
this.sessions.set(userId, {
|
|
243
|
-
sessions: newSessions,
|
|
244
|
-
previousSessions: new Map(),
|
|
245
|
-
sessionCwds: new Map(),
|
|
246
|
-
arrivalSessions: new Map(),
|
|
247
|
-
cwd: cwd ?? '',
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
this.autoPersist();
|
|
185
|
+
this.mutateEntry(userId, (entry) => {
|
|
186
|
+
entry.sessions.set(agent, sessionId);
|
|
187
|
+
if (cwd !== undefined)
|
|
188
|
+
entry.cwd = cwd;
|
|
189
|
+
return entry;
|
|
190
|
+
});
|
|
251
191
|
}
|
|
252
192
|
/** Set sessionId for a specific agent and cwd together */
|
|
253
193
|
setSessionIdAndCwd(userId, agent, sessionId, cwd, sessionCwd) {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
const newSessions = new Map(entry.sessions);
|
|
257
|
-
newSessions.set(agent, sessionId);
|
|
258
|
-
const newSessionCwds = new Map(entry.sessionCwds);
|
|
194
|
+
this.mutateEntry(userId, (entry) => {
|
|
195
|
+
entry.sessions.set(agent, sessionId);
|
|
259
196
|
if (sessionCwd !== undefined) {
|
|
260
|
-
|
|
197
|
+
entry.sessionCwds.set(agent, sessionCwd);
|
|
261
198
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
sessionCwds: newSessionCwds,
|
|
266
|
-
arrivalSessions: entry.arrivalSessions,
|
|
267
|
-
cwd,
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
else {
|
|
271
|
-
const newSessions = new Map();
|
|
272
|
-
newSessions.set(agent, sessionId);
|
|
273
|
-
this.sessions.set(userId, {
|
|
274
|
-
sessions: newSessions,
|
|
275
|
-
previousSessions: new Map(),
|
|
276
|
-
sessionCwds: new Map(),
|
|
277
|
-
arrivalSessions: new Map(),
|
|
278
|
-
cwd,
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
this.autoPersist();
|
|
199
|
+
entry.cwd = cwd;
|
|
200
|
+
return entry;
|
|
201
|
+
});
|
|
282
202
|
}
|
|
283
203
|
/** Get sessionCwd for a specific agent, or undefined if not set */
|
|
284
204
|
getSessionCwd(userId, agent = 'claude') {
|
|
@@ -292,37 +212,14 @@ export class SessionStore {
|
|
|
292
212
|
}
|
|
293
213
|
/** Set sessionId and sessionCwd for a specific agent, without touching cwd */
|
|
294
214
|
setSessionIdAndSessionCwd(userId, agent, sessionId, sessionCwd) {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
newSessionCwds.set(agent, sessionCwd);
|
|
301
|
-
this.sessions.set(userId, {
|
|
302
|
-
sessions: newSessions,
|
|
303
|
-
previousSessions: entry.previousSessions,
|
|
304
|
-
sessionCwds: newSessionCwds,
|
|
305
|
-
arrivalSessions: entry.arrivalSessions,
|
|
306
|
-
cwd: entry.cwd,
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
else {
|
|
310
|
-
const newSessions = new Map();
|
|
311
|
-
newSessions.set(agent, sessionId);
|
|
312
|
-
const newSessionCwds = new Map();
|
|
313
|
-
newSessionCwds.set(agent, sessionCwd);
|
|
314
|
-
this.sessions.set(userId, {
|
|
315
|
-
sessions: newSessions,
|
|
316
|
-
previousSessions: new Map(),
|
|
317
|
-
sessionCwds: newSessionCwds,
|
|
318
|
-
arrivalSessions: new Map(),
|
|
319
|
-
cwd: '',
|
|
320
|
-
});
|
|
321
|
-
}
|
|
322
|
-
this.autoPersist();
|
|
215
|
+
this.mutateEntry(userId, (entry) => {
|
|
216
|
+
entry.sessions.set(agent, sessionId);
|
|
217
|
+
entry.sessionCwds.set(agent, sessionCwd);
|
|
218
|
+
return entry;
|
|
219
|
+
});
|
|
323
220
|
}
|
|
324
221
|
// -- Persistence helpers --
|
|
325
|
-
/** Persisted format:
|
|
222
|
+
/** Persisted format: cwd + sessions + previous/arrival session maps. */
|
|
326
223
|
load() {
|
|
327
224
|
if (!this.persistPath)
|
|
328
225
|
return;
|
package/dist/update/index.d.ts
CHANGED
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
* package installation (detect package manager + global install),
|
|
6
6
|
* and the combined workflow for the /update command and --update CLI flag.
|
|
7
7
|
*/
|
|
8
|
-
export { isNewer, checkLatestVersion, type VersionCheckResult, type UpdateCache,
|
|
9
|
-
export {
|
|
8
|
+
export { isNewer, checkLatestVersion, type VersionCheckResult, type UpdateCache, } from './version-check.js';
|
|
9
|
+
export { runInstallLatest, type PackageManager, type InstallResult } from './install.js';
|
|
10
10
|
export { formatUpdateHint } from './startup-hint.js';
|
package/dist/update/index.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* package installation (detect package manager + global install),
|
|
6
6
|
* and the combined workflow for the /update command and --update CLI flag.
|
|
7
7
|
*/
|
|
8
|
-
export { isNewer, checkLatestVersion,
|
|
9
|
-
export {
|
|
8
|
+
export { isNewer, checkLatestVersion, } from './version-check.js';
|
|
9
|
+
export { runInstallLatest } from './install.js';
|
|
10
10
|
export { formatUpdateHint } from './startup-hint.js';
|
|
11
11
|
//# sourceMappingURL=index.js.map
|
package/dist/update/install.d.ts
CHANGED
|
@@ -8,14 +8,32 @@ export interface InstallResult {
|
|
|
8
8
|
/** Type signature matching execFile's callback style. */
|
|
9
9
|
type ExecFileCallback = (error: Error | null, stdout: string | Buffer, stderr: string | Buffer) => void;
|
|
10
10
|
type ExecFileFn = (file: string, args: readonly string[], options: object, callback: ExecFileCallback) => void;
|
|
11
|
+
/**
|
|
12
|
+
* Infer the installing package manager from the real path of the running
|
|
13
|
+
* script (e.g. `.../node_modules/lark-remote/dist/index.js`).
|
|
14
|
+
*
|
|
15
|
+
* Layout markers (check order matters — bun/pnpm paths also contain
|
|
16
|
+
* `/node_modules/lark-remote/`):
|
|
17
|
+
* - bun: `~/.bun/install/global/node_modules/lark-remote/...`
|
|
18
|
+
* - pnpm: `<global>/node_modules/.pnpm/lark-remote@<ver>/node_modules/lark-remote/...`
|
|
19
|
+
* - npm: `<prefix>/lib/node_modules/lark-remote/...` (POSIX) or
|
|
20
|
+
* `<prefix>/node_modules/lark-remote/...` (Windows)
|
|
21
|
+
*
|
|
22
|
+
* Returns null when the path has no marker (e.g. running from a source
|
|
23
|
+
* checkout in dev mode).
|
|
24
|
+
*/
|
|
25
|
+
export declare function inferPackageManagerFromPath(scriptPath: string): PackageManager | null;
|
|
11
26
|
/**
|
|
12
27
|
* Detect which package manager to use for global install.
|
|
13
28
|
*
|
|
14
29
|
* Priority:
|
|
15
30
|
* 1. Environment variable override (LARK_REMOTE_MANAGED_BY)
|
|
16
|
-
* 2.
|
|
31
|
+
* 2. Install location of the running script (upgrades must target the same
|
|
32
|
+
* copy that is actually running — a different PM would install a second
|
|
33
|
+
* copy and leave the running one stale)
|
|
34
|
+
* 3. `which` availability: npm → bun → pnpm
|
|
17
35
|
*/
|
|
18
|
-
export declare function detectPackageManager(): PackageManager | null;
|
|
36
|
+
export declare function detectPackageManager(scriptPath?: string): PackageManager | null;
|
|
19
37
|
/**
|
|
20
38
|
* Run the global install command to upgrade lark-remote to the latest version.
|
|
21
39
|
*
|
package/dist/update/install.js
CHANGED
|
@@ -1,18 +1,60 @@
|
|
|
1
1
|
import { execFile, execFileSync } from 'node:child_process';
|
|
2
|
+
import fs from 'node:fs';
|
|
2
3
|
import { getLogger } from '../logger/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* Infer the installing package manager from the real path of the running
|
|
6
|
+
* script (e.g. `.../node_modules/lark-remote/dist/index.js`).
|
|
7
|
+
*
|
|
8
|
+
* Layout markers (check order matters — bun/pnpm paths also contain
|
|
9
|
+
* `/node_modules/lark-remote/`):
|
|
10
|
+
* - bun: `~/.bun/install/global/node_modules/lark-remote/...`
|
|
11
|
+
* - pnpm: `<global>/node_modules/.pnpm/lark-remote@<ver>/node_modules/lark-remote/...`
|
|
12
|
+
* - npm: `<prefix>/lib/node_modules/lark-remote/...` (POSIX) or
|
|
13
|
+
* `<prefix>/node_modules/lark-remote/...` (Windows)
|
|
14
|
+
*
|
|
15
|
+
* Returns null when the path has no marker (e.g. running from a source
|
|
16
|
+
* checkout in dev mode).
|
|
17
|
+
*/
|
|
18
|
+
export function inferPackageManagerFromPath(scriptPath) {
|
|
19
|
+
const p = scriptPath.replace(/\\/g, '/');
|
|
20
|
+
if (p.includes('/.bun/install/global/'))
|
|
21
|
+
return 'bun';
|
|
22
|
+
if (p.includes('/.pnpm/lark-remote@'))
|
|
23
|
+
return 'pnpm';
|
|
24
|
+
if (p.includes('/node_modules/lark-remote/'))
|
|
25
|
+
return 'npm';
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
3
28
|
/**
|
|
4
29
|
* Detect which package manager to use for global install.
|
|
5
30
|
*
|
|
6
31
|
* Priority:
|
|
7
32
|
* 1. Environment variable override (LARK_REMOTE_MANAGED_BY)
|
|
8
|
-
* 2.
|
|
33
|
+
* 2. Install location of the running script (upgrades must target the same
|
|
34
|
+
* copy that is actually running — a different PM would install a second
|
|
35
|
+
* copy and leave the running one stale)
|
|
36
|
+
* 3. `which` availability: npm → bun → pnpm
|
|
9
37
|
*/
|
|
10
|
-
export function detectPackageManager() {
|
|
38
|
+
export function detectPackageManager(scriptPath) {
|
|
11
39
|
// 1. Env override (highest priority)
|
|
12
40
|
const env = process.env.LARK_REMOTE_MANAGED_BY;
|
|
13
41
|
if (env === 'npm' || env === 'bun' || env === 'pnpm')
|
|
14
42
|
return env;
|
|
15
|
-
// 2.
|
|
43
|
+
// 2. Infer from where this process was loaded from
|
|
44
|
+
const raw = scriptPath ?? process.argv[1];
|
|
45
|
+
if (raw) {
|
|
46
|
+
let resolved = raw;
|
|
47
|
+
try {
|
|
48
|
+
resolved = fs.realpathSync(raw);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Keep raw path (e.g. synthetic path in tests)
|
|
52
|
+
}
|
|
53
|
+
const inferred = inferPackageManagerFromPath(resolved);
|
|
54
|
+
if (inferred)
|
|
55
|
+
return inferred;
|
|
56
|
+
}
|
|
57
|
+
// 3. which availability fallback
|
|
16
58
|
const candidates = ['npm', 'bun', 'pnpm'];
|
|
17
59
|
for (const cmd of candidates) {
|
|
18
60
|
try {
|
|
@@ -73,10 +115,12 @@ export function runInstallLatest(opts) {
|
|
|
73
115
|
logger.error(`[update] install failed: ${msg}`);
|
|
74
116
|
// Detect common errors and give actionable advice
|
|
75
117
|
if (msg.includes('EACCES') || msg.includes('permission')) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
118
|
+
// bun/pnpm install into the user dir — sudo is wrong advice there
|
|
119
|
+
// (it would install into root's global dir instead).
|
|
120
|
+
const hint = pm === 'npm'
|
|
121
|
+
? `权限不足,尝试 sudo ${cmd} ${args.join(' ')}`
|
|
122
|
+
: `权限不足,请检查 ${cmd} 全局安装目录的写权限`;
|
|
123
|
+
resolve({ success: false, error: hint });
|
|
80
124
|
return;
|
|
81
125
|
}
|
|
82
126
|
resolve({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lark-remote",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
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",
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ConnectionManager: manages Codex App Server connections per workspace.
|
|
3
|
-
*
|
|
4
|
-
* Each workspace gets its own connection (transport + client). Connections are
|
|
5
|
-
* created on demand via `acquire()`, cached for reuse, and released after an
|
|
6
|
-
* idle timeout (30 minutes default).
|
|
7
|
-
*/
|
|
8
|
-
import { CodexAppServerClient } from './client.js';
|
|
9
|
-
export interface ConnectionManagerOptions {
|
|
10
|
-
/** Path to the codex binary. */
|
|
11
|
-
binary: string;
|
|
12
|
-
/** Args to spawn the app server with. Defaults to `['app-server', '--stdio']`. */
|
|
13
|
-
args?: string[];
|
|
14
|
-
/** Environment variables to pass to the binary. */
|
|
15
|
-
env?: Record<string, string | undefined>;
|
|
16
|
-
/** Request timeout in milliseconds. */
|
|
17
|
-
requestTimeoutMs?: number;
|
|
18
|
-
/** Idle TTL in milliseconds. */
|
|
19
|
-
idleTtlMs?: number;
|
|
20
|
-
}
|
|
21
|
-
export declare class ConnectionManager {
|
|
22
|
-
private slots;
|
|
23
|
-
private readonly binary;
|
|
24
|
-
private readonly args;
|
|
25
|
-
private readonly env;
|
|
26
|
-
private readonly requestTimeoutMs;
|
|
27
|
-
private readonly idleTtlMs;
|
|
28
|
-
/** Callback when a connection is lost — cleared from slot map. */
|
|
29
|
-
onConnectionLost?: (workspace: string) => void;
|
|
30
|
-
constructor(opts: ConnectionManagerOptions);
|
|
31
|
-
/**
|
|
32
|
-
* Acquire a connection for the given workspace.
|
|
33
|
-
* Creates a new connection if one does not exist or the previous one was lost.
|
|
34
|
-
* Serializes creation so concurrent calls share the same connection.
|
|
35
|
-
*/
|
|
36
|
-
acquire(workspace: string): Promise<CodexAppServerClient>;
|
|
37
|
-
/**
|
|
38
|
-
* Release (dispose) a connection for the given workspace.
|
|
39
|
-
*/
|
|
40
|
-
release(workspace: string): Promise<void>;
|
|
41
|
-
/**
|
|
42
|
-
* Dispose all connections.
|
|
43
|
-
*/
|
|
44
|
-
disposeAll(): Promise<void>;
|
|
45
|
-
/**
|
|
46
|
-
* Notify that the workspace is active — disarm the idle timer.
|
|
47
|
-
*/
|
|
48
|
-
notifyActivity(workspace: string): void;
|
|
49
|
-
/**
|
|
50
|
-
* Notify that the workspace is idle — arm the idle timer.
|
|
51
|
-
*/
|
|
52
|
-
notifyIdle(workspace: string): void;
|
|
53
|
-
private createClient;
|
|
54
|
-
private clearIdleTimer;
|
|
55
|
-
private disposeSlot;
|
|
56
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Builds `codex exec` command-line arguments.
|
|
3
|
-
*
|
|
4
|
-
* Key design decisions:
|
|
5
|
-
* - `approval_policy="never"` eliminates the approval handshake (root cause ①).
|
|
6
|
-
* - Prompt goes via stdin (`-` flag) to avoid argv escaping issues.
|
|
7
|
-
* - `--skip-git-repo-check`: lark-remote's cwd may not be a git repo.
|
|
8
|
-
* - User's `~/.codex/config.toml` and project rules are preserved
|
|
9
|
-
* (no `--ignore-user-config` / `--ignore-rules`).
|
|
10
|
-
*/
|
|
11
|
-
interface BuildCodexExecArgsInput {
|
|
12
|
-
/** Working directory for the codex process. */
|
|
13
|
-
cwd: string;
|
|
14
|
-
/** Model override (maps to `-m`). Omitted uses codex config.toml default. */
|
|
15
|
-
model?: string;
|
|
16
|
-
/** Model provider override (maps to `-c model_provider="xxx"`).
|
|
17
|
-
* Omitted uses codex config.toml default. */
|
|
18
|
-
modelProvider?: string;
|
|
19
|
-
/** Thread ID for session resumption (maps to `exec resume --json <threadId> -`). */
|
|
20
|
-
threadId?: string;
|
|
21
|
-
/** Reasoning effort level (maps to `-c model_reasoning_effort="xxx"`). */
|
|
22
|
-
reasoningEffort?: string;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Construct the argv array for `codex exec --json`.
|
|
26
|
-
*
|
|
27
|
-
* New session:
|
|
28
|
-
* `codex exec --json --sandbox danger-full-access -c approval_policy="never" ... -`
|
|
29
|
-
* Resume session:
|
|
30
|
-
* `codex exec --sandbox danger-full-access ... resume --json <threadId> -`
|
|
31
|
-
*/
|
|
32
|
-
export declare function buildCodexExecArgs(input: BuildCodexExecArgsInput): string[];
|
|
33
|
-
export {};
|