lark-remote 0.1.8 → 0.1.9
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 +18 -0
- package/dist/bridge/approval-coordinator.d.ts +15 -0
- package/dist/bridge/approval-coordinator.js +58 -3
- package/dist/bridge/index.d.ts +17 -0
- package/dist/bridge/index.js +31 -2
- package/dist/card/approval-render.js +105 -8
- package/dist/index.js +13 -3
- package/dist/order/alias-resolve.d.ts +6 -2
- package/dist/order/index.d.ts +9 -2
- package/dist/order/index.js +33 -0
- package/dist/router/index.d.ts +19 -3
- package/dist/router/index.js +359 -84
- package/dist/runner/claude/runner.js +22 -0
- package/dist/runner/claude/session.d.ts +26 -0
- package/dist/runner/claude/session.js +90 -13
- package/dist/runner/common/connection-based-runner.js +10 -5
- package/dist/runner/dsh/runner.js +94 -74
- package/dist/runner/kimi/acp/runner.js +15 -0
- package/dist/runner/pi/rpc/runner.js +6 -1
- package/dist/runner/types.d.ts +31 -0
- package/dist/session/dsh/sessions.d.ts +6 -1
- package/dist/session/dsh/sessions.js +20 -5
- package/dist/workspace/index.d.ts +8 -0
- package/dist/workspace/index.js +20 -1
- package/package.json +1 -1
- package/dist/order/alias-store.d.ts +0 -38
- package/dist/order/alias-store.js +0 -106
package/dist/workspace/index.js
CHANGED
|
@@ -13,6 +13,8 @@ import { getLogger } from '../logger/index.js';
|
|
|
13
13
|
* lastUsedAt 语义(2026-08-19 语义对齐):保存(save)与使用(use/touch)
|
|
14
14
|
* 都会把时间戳更新为当前时间。save 内部调用 touch,保证「最近使用」排序
|
|
15
15
|
* 对新保存的 workspace 同样生效(新条目应排在列表最前,而非沉底)。
|
|
16
|
+
* 同一毫秒内连续操作时 touch 会用 max+1 保证严格递增,避免 Date.now 相同
|
|
17
|
+
* 导致最近排序退化为字母序。
|
|
16
18
|
*
|
|
17
19
|
* Data migration: old format `{ alias: "path" }` is normalized to
|
|
18
20
|
* `{ alias: { path, lastUsedAt: 0 } }` on first load and persisted.
|
|
@@ -83,12 +85,29 @@ export class WorkspaceStore {
|
|
|
83
85
|
/**
|
|
84
86
|
* Update lastUsedAt to now for the given alias and persist.
|
|
85
87
|
* No-op if the alias does not exist.
|
|
88
|
+
*
|
|
89
|
+
* To keep "recent" ordering stable even for rapid successive saves/uses in
|
|
90
|
+
* the same millisecond, never allow another entry to share the same
|
|
91
|
+
* timestamp while this entry is being touched. If a peer already has a
|
|
92
|
+
* timestamp at or after the current wall-clock time, use max+1 so the
|
|
93
|
+
* touched entry always becomes the most recently used.
|
|
86
94
|
*/
|
|
87
95
|
touch(name) {
|
|
88
96
|
const entry = this.data.get(name);
|
|
89
97
|
if (!entry)
|
|
90
98
|
return;
|
|
91
|
-
|
|
99
|
+
const now = Date.now();
|
|
100
|
+
let max = Math.max(now, entry.lastUsedAt);
|
|
101
|
+
let hasPeerAtOrAfterNow = false;
|
|
102
|
+
for (const [otherName, other] of this.data) {
|
|
103
|
+
if (otherName === name)
|
|
104
|
+
continue;
|
|
105
|
+
if (other.lastUsedAt > max)
|
|
106
|
+
max = other.lastUsedAt;
|
|
107
|
+
if (other.lastUsedAt >= now)
|
|
108
|
+
hasPeerAtOrAfterNow = true;
|
|
109
|
+
}
|
|
110
|
+
entry.lastUsedAt = hasPeerAtOrAfterNow ? max + 1 : max;
|
|
92
111
|
this.persist();
|
|
93
112
|
}
|
|
94
113
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lark-remote",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
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,38 +0,0 @@
|
|
|
1
|
-
export declare const MAX_ALIASES = 50;
|
|
2
|
-
export declare const MAX_ALIAS_NAME_LENGTH = 20;
|
|
3
|
-
export declare const MAX_ALIAS_TEXT_LENGTH = 200;
|
|
4
|
-
/**
|
|
5
|
-
* 别名名称规则:`[A-Za-z_][A-Za-z0-9_]*`,≤20 字符,不能数字开头
|
|
6
|
-
* —— `$500`、`$3d` 这类正常文本永远不匹配,不会误展开。
|
|
7
|
-
*/
|
|
8
|
-
export declare const ALIAS_NAME_PATTERN: RegExp;
|
|
9
|
-
export interface AliasEntry {
|
|
10
|
-
name: string;
|
|
11
|
-
text: string;
|
|
12
|
-
createdAt: string;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* 全局别名存储。
|
|
16
|
-
*
|
|
17
|
-
* 独立于 OrderStore(aliases.json),避免破坏 orders.json 向后兼容。
|
|
18
|
-
* 原子写(tmp + rename)+ 损坏恢复,复用 OrderStore/WorkspaceStore 同一模式。
|
|
19
|
-
*/
|
|
20
|
-
export declare class AliasStore {
|
|
21
|
-
private filePath;
|
|
22
|
-
private data;
|
|
23
|
-
constructor(filePath?: string);
|
|
24
|
-
/** Reload data from disk (useful when another process may have written). */
|
|
25
|
-
reload(): void;
|
|
26
|
-
private load;
|
|
27
|
-
private persist;
|
|
28
|
-
has(name: string): boolean;
|
|
29
|
-
get(name: string): AliasEntry | undefined;
|
|
30
|
-
list(): AliasEntry[];
|
|
31
|
-
/**
|
|
32
|
-
* 注册/更新别名(同名覆盖文本,保留 createdAt)。返回写入后的条目。
|
|
33
|
-
* 名称/文本/数量超限时抛错,由调用方提示用户。
|
|
34
|
-
*/
|
|
35
|
-
set(name: string, text: string): AliasEntry;
|
|
36
|
-
/** 删除别名;不存在返回 false。 */
|
|
37
|
-
remove(name: string): boolean;
|
|
38
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import os from 'node:os';
|
|
3
|
-
import { atomicWriteJson } from '../persistence/atomic-write.js';
|
|
4
|
-
import { loadJsonFile } from '../persistence/load-json-file.js';
|
|
5
|
-
export const MAX_ALIASES = 50;
|
|
6
|
-
export const MAX_ALIAS_NAME_LENGTH = 20;
|
|
7
|
-
export const MAX_ALIAS_TEXT_LENGTH = 200;
|
|
8
|
-
/**
|
|
9
|
-
* 别名名称规则:`[A-Za-z_][A-Za-z0-9_]*`,≤20 字符,不能数字开头
|
|
10
|
-
* —— `$500`、`$3d` 这类正常文本永远不匹配,不会误展开。
|
|
11
|
-
*/
|
|
12
|
-
export const ALIAS_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
13
|
-
/**
|
|
14
|
-
* 全局别名存储。
|
|
15
|
-
*
|
|
16
|
-
* 独立于 OrderStore(aliases.json),避免破坏 orders.json 向后兼容。
|
|
17
|
-
* 原子写(tmp + rename)+ 损坏恢复,复用 OrderStore/WorkspaceStore 同一模式。
|
|
18
|
-
*/
|
|
19
|
-
export class AliasStore {
|
|
20
|
-
filePath;
|
|
21
|
-
data;
|
|
22
|
-
constructor(filePath) {
|
|
23
|
-
this.filePath = filePath ?? path.join(os.homedir(), '.lark-remote', 'aliases.json');
|
|
24
|
-
this.data = [];
|
|
25
|
-
this.load();
|
|
26
|
-
}
|
|
27
|
-
/** Reload data from disk (useful when another process may have written). */
|
|
28
|
-
reload() {
|
|
29
|
-
this.load();
|
|
30
|
-
}
|
|
31
|
-
load() {
|
|
32
|
-
const parsed = loadJsonFile(this.filePath, undefined);
|
|
33
|
-
if (!parsed || !Array.isArray(parsed)) {
|
|
34
|
-
this.data = [];
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
const valid = [];
|
|
38
|
-
for (const e of parsed) {
|
|
39
|
-
if (e &&
|
|
40
|
-
typeof e.name === 'string' &&
|
|
41
|
-
typeof e.text === 'string' &&
|
|
42
|
-
typeof e.createdAt === 'string' &&
|
|
43
|
-
ALIAS_NAME_PATTERN.test(e.name) &&
|
|
44
|
-
e.name.length <= MAX_ALIAS_NAME_LENGTH) {
|
|
45
|
-
valid.push({
|
|
46
|
-
name: e.name,
|
|
47
|
-
text: e.text.slice(0, MAX_ALIAS_TEXT_LENGTH),
|
|
48
|
-
createdAt: e.createdAt,
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
this.data = valid;
|
|
53
|
-
}
|
|
54
|
-
persist() {
|
|
55
|
-
atomicWriteJson(this.filePath, this.data);
|
|
56
|
-
}
|
|
57
|
-
has(name) {
|
|
58
|
-
return this.data.some((a) => a.name === name);
|
|
59
|
-
}
|
|
60
|
-
get(name) {
|
|
61
|
-
return this.data.find((a) => a.name === name);
|
|
62
|
-
}
|
|
63
|
-
list() {
|
|
64
|
-
return [...this.data];
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* 注册/更新别名(同名覆盖文本,保留 createdAt)。返回写入后的条目。
|
|
68
|
-
* 名称/文本/数量超限时抛错,由调用方提示用户。
|
|
69
|
-
*/
|
|
70
|
-
set(name, text) {
|
|
71
|
-
if (!ALIAS_NAME_PATTERN.test(name) || name.length > MAX_ALIAS_NAME_LENGTH) {
|
|
72
|
-
throw new Error(`别名名称只能包含字母/数字/下划线,不能数字开头,且不超过 ${MAX_ALIAS_NAME_LENGTH} 字符`);
|
|
73
|
-
}
|
|
74
|
-
if (text.length > MAX_ALIAS_TEXT_LENGTH) {
|
|
75
|
-
throw new Error(`别名文本超过 ${MAX_ALIAS_TEXT_LENGTH} 字符限制`);
|
|
76
|
-
}
|
|
77
|
-
if (!this.has(name) && this.data.length >= MAX_ALIASES) {
|
|
78
|
-
throw new Error(`别名数量已达上限 ${MAX_ALIASES}`);
|
|
79
|
-
}
|
|
80
|
-
const existing = this.get(name);
|
|
81
|
-
const entry = {
|
|
82
|
-
name,
|
|
83
|
-
text,
|
|
84
|
-
createdAt: existing?.createdAt ?? new Date().toISOString(),
|
|
85
|
-
};
|
|
86
|
-
const idx = this.data.findIndex((a) => a.name === name);
|
|
87
|
-
if (idx >= 0) {
|
|
88
|
-
this.data[idx] = entry;
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
this.data.push(entry);
|
|
92
|
-
}
|
|
93
|
-
this.persist();
|
|
94
|
-
return entry;
|
|
95
|
-
}
|
|
96
|
-
/** 删除别名;不存在返回 false。 */
|
|
97
|
-
remove(name) {
|
|
98
|
-
const before = this.data.length;
|
|
99
|
-
this.data = this.data.filter((a) => a.name !== name);
|
|
100
|
-
if (this.data.length === before)
|
|
101
|
-
return false;
|
|
102
|
-
this.persist();
|
|
103
|
-
return true;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
//# sourceMappingURL=alias-store.js.map
|