openclaw-lark-multi-agent 1.7.0 → 1.8.0
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/compact-progress.d.ts +3 -1
- package/dist/compact-progress.js +7 -1
- package/dist/feishu-bot.js +56 -14
- package/dist/openclaw-client.d.ts +10 -0
- package/dist/openclaw-client.js +111 -0
- package/package.json +5 -4
- package/scripts/update-lma-core.sh +45 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Coarse phase of the compaction flow, drives the card's primary line. */
|
|
2
|
-
export type CompactPhase = "native" | "transcript-trim" | "trim";
|
|
2
|
+
export type CompactPhase = "native" | "transcript-trim" | "trim" | "tooltrim";
|
|
3
3
|
/** Terminal outcome used by the renderer to pick color/emoji. */
|
|
4
4
|
export type CompactState = "running" | "done" | "failed" | "noop";
|
|
5
5
|
/** Structured snapshot the renderer turns into a Feishu interactive card. */
|
|
@@ -52,6 +52,8 @@ export declare class CompactProgressController {
|
|
|
52
52
|
start(): void;
|
|
53
53
|
/** Switch straight into explicit transcript-trim mode (user-requested trim). */
|
|
54
54
|
toTrim(): void;
|
|
55
|
+
/** Switch into ToolTrim mode (keep text, filter tool payload). */
|
|
56
|
+
toToolTrim(): void;
|
|
55
57
|
/** Native compaction gave up; switch to Gateway-owned transcript-tail trim. */
|
|
56
58
|
toTranscriptTrim(): Promise<void>;
|
|
57
59
|
/** Finished successfully; patch the card to the done state with a detail line. */
|
package/dist/compact-progress.js
CHANGED
|
@@ -47,10 +47,16 @@ export class CompactProgressController {
|
|
|
47
47
|
}
|
|
48
48
|
/** Switch straight into explicit transcript-trim mode (user-requested trim). */
|
|
49
49
|
toTrim() {
|
|
50
|
-
if (this.finalized || this.phase === "trim" || this.phase === "transcript-trim")
|
|
50
|
+
if (this.finalized || this.phase === "trim" || this.phase === "transcript-trim" || this.phase === "tooltrim")
|
|
51
51
|
return;
|
|
52
52
|
this.phase = "trim";
|
|
53
53
|
}
|
|
54
|
+
/** Switch into ToolTrim mode (keep text, filter tool payload). */
|
|
55
|
+
toToolTrim() {
|
|
56
|
+
if (this.finalized || this.phase === "tooltrim" || this.phase === "transcript-trim")
|
|
57
|
+
return;
|
|
58
|
+
this.phase = "tooltrim";
|
|
59
|
+
}
|
|
54
60
|
/** Native compaction gave up; switch to Gateway-owned transcript-tail trim. */
|
|
55
61
|
async toTranscriptTrim() {
|
|
56
62
|
if (this.finalized || this.phase === "transcript-trim")
|
package/dist/feishu-bot.js
CHANGED
|
@@ -886,7 +886,7 @@ export class FeishuBot {
|
|
|
886
886
|
`━━━━━━━━━━━━━━━━━━`,
|
|
887
887
|
`桥接层命令(单斜杠,由 openclaw-lark-multi-agent 本地处理)`,
|
|
888
888
|
`📊 /status — 查看当前模型、Token 用量、Session 状态`,
|
|
889
|
-
`🧹 /compact
|
|
889
|
+
`🧹 /compact — 默认 ToolTrim:保文本、过滤工具载荷(保留最近 10 条);/compact semantic 走 LLM 总结;/compact trim 或 N 裁剪转录尾部`,
|
|
890
890
|
`🔄 /reset — 重置当前 bot 的 OpenClaw session`,
|
|
891
891
|
`⏹️ /stop — 强制停止当前 bot 在本聊天的卡死 run,解锁队列`,
|
|
892
892
|
`🔊 /verbose — 开关当前聊天里的 Tool Call 显示`,
|
|
@@ -3422,9 +3422,11 @@ export class FeishuBot {
|
|
|
3422
3422
|
// Running: phase line + ticking elapsed footer.
|
|
3423
3423
|
const phaseLine = view.phase === "transcript-trim"
|
|
3424
3424
|
? (en ? "🧹 Semantic compaction unavailable — trimming transcript safely…" : "🧹 语义压缩不可用,正在安全裁剪转录…")
|
|
3425
|
-
: view.phase === "
|
|
3426
|
-
? (en ? "🧹
|
|
3427
|
-
:
|
|
3425
|
+
: view.phase === "tooltrim"
|
|
3426
|
+
? (en ? "🧹 ToolTrim: keeping text, filtering tool payload (last 10 tool calls kept)…" : "🧹 ToolTrim 压缩:保留文本,过滤工具载荷(保留最近 10 条工具调用)…")
|
|
3427
|
+
: view.phase === "trim"
|
|
3428
|
+
? (en ? "🧹 Trimming transcript tail (keeping the most recent events)…" : "🧹 正在裁剪转录尾部(保留最近的事件)…")
|
|
3429
|
+
: (en ? "🧹 Compacting session…" : "🧹 正在压缩 session…");
|
|
3428
3430
|
const footer = en ? `⏱ ${view.elapsed}` : `⏱ 已用 ${view.elapsed}`;
|
|
3429
3431
|
return {
|
|
3430
3432
|
schema: "2.0",
|
|
@@ -4319,7 +4321,25 @@ export class FeishuBot {
|
|
|
4319
4321
|
* a trim so the session is still reclaimed.
|
|
4320
4322
|
*/
|
|
4321
4323
|
async compactWithFallback(sessionKey, onPhase, opts = {}) {
|
|
4322
|
-
const mode = opts.mode === "semantic" ? "semantic" : "
|
|
4324
|
+
const mode = opts.mode === "trim" ? "trim" : opts.mode === "semantic" ? "semantic" : "tooltrim";
|
|
4325
|
+
if (mode === "tooltrim") {
|
|
4326
|
+
onPhase?.("tooltrim");
|
|
4327
|
+
try {
|
|
4328
|
+
const res = await this.openclawClient.toolTrimCompact(sessionKey, 10);
|
|
4329
|
+
if (res?.compacted === true) {
|
|
4330
|
+
return {
|
|
4331
|
+
compacted: true,
|
|
4332
|
+
method: "tooltrim",
|
|
4333
|
+
detail: typeof res?.detail === "string" ? res.detail : "文本保留;仅保留最近 10 条工具调用",
|
|
4334
|
+
};
|
|
4335
|
+
}
|
|
4336
|
+
const reason = typeof res?.detail === "string" ? res.detail : typeof res?.reason === "string" ? res.reason : undefined;
|
|
4337
|
+
return { compacted: false, method: "none", reason: reason || "tooltrim made no change" };
|
|
4338
|
+
}
|
|
4339
|
+
catch (err) {
|
|
4340
|
+
return { compacted: false, method: "none", reason: err.message };
|
|
4341
|
+
}
|
|
4342
|
+
}
|
|
4323
4343
|
const trimMaxLines = Number.isFinite(opts.maxLines) && opts.maxLines >= 20
|
|
4324
4344
|
? Math.floor(opts.maxLines)
|
|
4325
4345
|
: compactFallbackMaxLines();
|
|
@@ -4341,7 +4361,7 @@ export class FeishuBot {
|
|
|
4341
4361
|
// semantic mode: LLM summarize first, trim as fallback.
|
|
4342
4362
|
let nativeReason;
|
|
4343
4363
|
try {
|
|
4344
|
-
const res = await this.openclawClient.
|
|
4364
|
+
const res = await this.openclawClient.semanticCompact(sessionKey);
|
|
4345
4365
|
if (res?.compacted === true)
|
|
4346
4366
|
return { compacted: true, method: "native" };
|
|
4347
4367
|
nativeReason = typeof res?.reason === "string" ? res.reason : undefined;
|
|
@@ -4387,7 +4407,10 @@ export class FeishuBot {
|
|
|
4387
4407
|
// /compact 500 → tail trim keeping the last 500 events
|
|
4388
4408
|
// /compact maxLines=500 → same as above
|
|
4389
4409
|
const argTokens = args.split(/\s+/).filter(Boolean);
|
|
4390
|
-
|
|
4410
|
+
// toolTrim is the default (user directive 2026-10-10): bare /compact keeps
|
|
4411
|
+
// text and filters tool payload. Explicit tokens: semantic (LLM summarize),
|
|
4412
|
+
// trim/tail or a bare number N (mechanical tail trim keeping N events).
|
|
4413
|
+
let mode = "tooltrim";
|
|
4391
4414
|
let maxLines;
|
|
4392
4415
|
for (const tok of argTokens) {
|
|
4393
4416
|
const semanticMatch = /^(semantic|summarize|llm)$/i.exec(tok);
|
|
@@ -4395,9 +4418,20 @@ export class FeishuBot {
|
|
|
4395
4418
|
mode = "semantic";
|
|
4396
4419
|
continue;
|
|
4397
4420
|
}
|
|
4421
|
+
const toolTrimMatch = /^(tooltrim|tool_trim|tool-trim)$/i.exec(tok);
|
|
4422
|
+
if (toolTrimMatch) {
|
|
4423
|
+
mode = "tooltrim";
|
|
4424
|
+
continue;
|
|
4425
|
+
}
|
|
4426
|
+
const trimMatch = /^(trim|tail)$/i.exec(tok);
|
|
4427
|
+
if (trimMatch) {
|
|
4428
|
+
mode = "trim";
|
|
4429
|
+
continue;
|
|
4430
|
+
}
|
|
4398
4431
|
const linesMatch = /^(?:maxlines|max_lines)[=:](\d{2,})$/i.exec(tok) || /^(\d{2,})$/.exec(tok);
|
|
4399
4432
|
if (linesMatch) {
|
|
4400
4433
|
maxLines = Number(linesMatch[1] || linesMatch[2]);
|
|
4434
|
+
mode = "trim";
|
|
4401
4435
|
continue;
|
|
4402
4436
|
}
|
|
4403
4437
|
}
|
|
@@ -4408,6 +4442,8 @@ export class FeishuBot {
|
|
|
4408
4442
|
}, { locale: en ? "en" : "zh" });
|
|
4409
4443
|
if (mode === "trim")
|
|
4410
4444
|
progress.toTrim();
|
|
4445
|
+
else if (mode === "tooltrim")
|
|
4446
|
+
progress.toToolTrim();
|
|
4411
4447
|
progress.start();
|
|
4412
4448
|
try {
|
|
4413
4449
|
const r = await this.compactWithFallback(sessionKey, (phase) => {
|
|
@@ -4420,16 +4456,22 @@ export class FeishuBot {
|
|
|
4420
4456
|
const localizedTrimDetail = r.detail
|
|
4421
4457
|
?.replace("kept ", en ? "kept " : "保留最近 ")
|
|
4422
4458
|
.replace(" transcript events", en ? " transcript events" : " 条转录事件");
|
|
4423
|
-
const detail = r.method === "
|
|
4424
|
-
? (en ? `
|
|
4425
|
-
:
|
|
4459
|
+
const detail = r.method === "tooltrim"
|
|
4460
|
+
? (en ? `tooltrim: ${r.detail || "text kept; tool payload filtered"}` : `ToolTrim:${r.detail || "文本保留,工具载荷已过滤"}`)
|
|
4461
|
+
: r.method === "transcript-trim" && localizedTrimDetail
|
|
4462
|
+
? (en ? `transcript trim: ${localizedTrimDetail}` : `转录裁剪:${localizedTrimDetail}`)
|
|
4463
|
+
: (en ? "native" : "原生压缩");
|
|
4426
4464
|
await progress.done(detail);
|
|
4427
4465
|
if (!progress.id) {
|
|
4428
|
-
await this.replyMessage(messageId, r.method === "
|
|
4466
|
+
await this.replyMessage(messageId, r.method === "tooltrim"
|
|
4429
4467
|
? (en
|
|
4430
|
-
? `✅ Session compacted (
|
|
4431
|
-
: `✅ Session
|
|
4432
|
-
:
|
|
4468
|
+
? `✅ Session compacted (tooltrim${r.detail ? `: ${r.detail}` : ""})`
|
|
4469
|
+
: `✅ Session 已压缩(ToolTrim${r.detail ? `:${r.detail}` : ""})`)
|
|
4470
|
+
: r.method === "transcript-trim"
|
|
4471
|
+
? (en
|
|
4472
|
+
? `✅ Session compacted (transcript trim${localizedTrimDetail ? ": " + localizedTrimDetail : ""})`
|
|
4473
|
+
: `✅ Session 已压缩(转录裁剪${localizedTrimDetail ? ":" + localizedTrimDetail : ""})`)
|
|
4474
|
+
: (en ? `✅ Session compacted` : `✅ Session 已压缩`));
|
|
4433
4475
|
}
|
|
4434
4476
|
}
|
|
4435
4477
|
else {
|
|
@@ -219,6 +219,16 @@ export declare class OpenClawClient {
|
|
|
219
219
|
ensureModel(sessionKey: string, expectedModel: string): Promise<boolean>;
|
|
220
220
|
deleteSession(key: string, deleteTranscript?: boolean): Promise<any>;
|
|
221
221
|
resetSession(key: string): Promise<any>;
|
|
222
|
+
/** One-shot ToolTrim compaction: route the native semantic compaction
|
|
223
|
+
* through the lma-core plugin's lma-tooltrim provider (keep text, keep only
|
|
224
|
+
* the 10 most recent tool calls, drop the rest of the tool payload).
|
|
225
|
+
* Orchestration (validated E2E 2026-10-10): config.set {raw, baseHash} →
|
|
226
|
+
* sessions.compact → restore the original config (always). */
|
|
227
|
+
toolTrimCompact(key: string, keepRecentToolCalls?: number): Promise<any>;
|
|
228
|
+
/** Explicit LLM-summarize compaction (/compact semantic). Since lma-tooltrim
|
|
229
|
+
* is the persistent default provider, temporarily unset it so the built-in
|
|
230
|
+
* summarization pipeline runs, then restore the original config (always). */
|
|
231
|
+
semanticCompact(key: string): Promise<any>;
|
|
222
232
|
compactSession(key: string, options?: {
|
|
223
233
|
maxLines?: number;
|
|
224
234
|
}): Promise<any>;
|
package/dist/openclaw-client.js
CHANGED
|
@@ -1844,6 +1844,117 @@ export class OpenClawClient {
|
|
|
1844
1844
|
// sessions.reset may not return a response; use short timeout
|
|
1845
1845
|
return this.rpc("sessions.reset", { key: this.canonicalSessionKey(key) }, 5000).catch(() => { });
|
|
1846
1846
|
}
|
|
1847
|
+
/** One-shot ToolTrim compaction: route the native semantic compaction
|
|
1848
|
+
* through the lma-core plugin's lma-tooltrim provider (keep text, keep only
|
|
1849
|
+
* the 10 most recent tool calls, drop the rest of the tool payload).
|
|
1850
|
+
* Orchestration (validated E2E 2026-10-10): config.set {raw, baseHash} →
|
|
1851
|
+
* sessions.compact → restore the original config (always). */
|
|
1852
|
+
async toolTrimCompact(key, keepRecentToolCalls = 10) {
|
|
1853
|
+
const release = await this.acquireMaintenanceSlot("tooltrim");
|
|
1854
|
+
const startedAt = Date.now();
|
|
1855
|
+
const PROVIDER = "lma-tooltrim";
|
|
1856
|
+
let restoreInfo = null;
|
|
1857
|
+
const restoreProvider = async () => {
|
|
1858
|
+
if (!restoreInfo)
|
|
1859
|
+
return;
|
|
1860
|
+
try {
|
|
1861
|
+
await this.rpc("config.set", { raw: restoreInfo.raw, baseHash: restoreInfo.baseHash }, 30000);
|
|
1862
|
+
console.log(`[OpenClaw] tooltrim: compaction provider config restored`);
|
|
1863
|
+
}
|
|
1864
|
+
catch (err) {
|
|
1865
|
+
console.warn(`[OpenClaw] tooltrim: config restore failed:`, err.message);
|
|
1866
|
+
}
|
|
1867
|
+
};
|
|
1868
|
+
try {
|
|
1869
|
+
// 1. Read the full config + its base hash (optimistic-concurrency token).
|
|
1870
|
+
const full = await this.rpc("config.get", {}, 30000);
|
|
1871
|
+
const hash = full?.hash;
|
|
1872
|
+
const cfg = full?.config ?? full?.parsed;
|
|
1873
|
+
if (typeof hash !== "string" || !cfg || typeof cfg !== "object") {
|
|
1874
|
+
return { compacted: false, reason: "无法读取网关配置(config.get)" };
|
|
1875
|
+
}
|
|
1876
|
+
const compNode0 = cfg?.agents?.defaults?.compaction;
|
|
1877
|
+
if (compNode0?.provider !== PROVIDER) {
|
|
1878
|
+
// Provider is not the persistent default: toggle it on for this run and
|
|
1879
|
+
// restore afterwards (portable path for hosts without the default set).
|
|
1880
|
+
const originalRaw = typeof full?.raw === "string" ? full.raw : JSON.stringify(cfg);
|
|
1881
|
+
const agentsNode = (cfg.agents ??= {});
|
|
1882
|
+
const defaultsNode = (agentsNode.defaults ??= {});
|
|
1883
|
+
const comp = (defaultsNode.compaction ??= {});
|
|
1884
|
+
comp.provider = PROVIDER;
|
|
1885
|
+
const setRes = await this.rpc("config.set", { raw: JSON.stringify(cfg), baseHash: hash }, 30000);
|
|
1886
|
+
if (setRes?.ok !== true || typeof setRes?.hash !== "string") {
|
|
1887
|
+
return { compacted: false, reason: `config.set 失败: ${JSON.stringify(setRes).slice(0, 160)}` };
|
|
1888
|
+
}
|
|
1889
|
+
restoreInfo = { raw: originalRaw, baseHash: setRes.hash };
|
|
1890
|
+
}
|
|
1891
|
+
// 2. Native semantic compaction now routes through our provider.
|
|
1892
|
+
const result = await this.rpc("sessions.compact", { key: this.canonicalSessionKey(key) }, 10 * 60 * 1000);
|
|
1893
|
+
await restoreProvider();
|
|
1894
|
+
const ok = result?.compacted === true;
|
|
1895
|
+
return {
|
|
1896
|
+
compacted: ok,
|
|
1897
|
+
method: "tooltrim",
|
|
1898
|
+
detail: ok
|
|
1899
|
+
? `文本保留;工具载荷已过滤(保留最近 ${keepRecentToolCalls} 条工具调用)`
|
|
1900
|
+
: (typeof result?.reason === "string" ? result.reason : "网关未执行压缩(会话可能正在运行或不需压缩)"),
|
|
1901
|
+
tokensBefore: result?.result?.tokensBefore,
|
|
1902
|
+
};
|
|
1903
|
+
}
|
|
1904
|
+
catch (err) {
|
|
1905
|
+
await restoreProvider();
|
|
1906
|
+
return { compacted: false, method: "tooltrim", reason: err.message };
|
|
1907
|
+
}
|
|
1908
|
+
finally {
|
|
1909
|
+
console.log(`[OpenClaw] tooltrim finished for ${key} in ${Date.now() - startedAt}ms`);
|
|
1910
|
+
release();
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
/** Explicit LLM-summarize compaction (/compact semantic). Since lma-tooltrim
|
|
1914
|
+
* is the persistent default provider, temporarily unset it so the built-in
|
|
1915
|
+
* summarization pipeline runs, then restore the original config (always). */
|
|
1916
|
+
async semanticCompact(key) {
|
|
1917
|
+
const release = await this.acquireMaintenanceSlot("semantic");
|
|
1918
|
+
const PROVIDER = "lma-tooltrim";
|
|
1919
|
+
let restoreInfo = null;
|
|
1920
|
+
const restoreProvider = async () => {
|
|
1921
|
+
if (!restoreInfo)
|
|
1922
|
+
return;
|
|
1923
|
+
try {
|
|
1924
|
+
await this.rpc("config.set", { raw: restoreInfo.raw, baseHash: restoreInfo.baseHash }, 30000);
|
|
1925
|
+
console.log(`[OpenClaw] semantic: compaction provider config restored`);
|
|
1926
|
+
}
|
|
1927
|
+
catch (err) {
|
|
1928
|
+
console.warn(`[OpenClaw] semantic: config restore failed:`, err.message);
|
|
1929
|
+
}
|
|
1930
|
+
};
|
|
1931
|
+
try {
|
|
1932
|
+
const full = await this.rpc("config.get", {}, 30000);
|
|
1933
|
+
const hash = full?.hash;
|
|
1934
|
+
const cfg = full?.config ?? full?.parsed;
|
|
1935
|
+
const comp = cfg && typeof cfg === "object" ? cfg?.agents?.defaults?.compaction : undefined;
|
|
1936
|
+
if (typeof hash === "string" && cfg && typeof cfg === "object" && comp?.provider) {
|
|
1937
|
+
const originalRaw = typeof full?.raw === "string" ? full.raw : JSON.stringify(cfg);
|
|
1938
|
+
delete comp.provider;
|
|
1939
|
+
const setRes = await this.rpc("config.set", { raw: JSON.stringify(cfg), baseHash: hash }, 30000);
|
|
1940
|
+
if (setRes?.ok === true && typeof setRes?.hash === "string") {
|
|
1941
|
+
restoreInfo = { raw: originalRaw, baseHash: setRes.hash };
|
|
1942
|
+
}
|
|
1943
|
+
// If the toggle failed we still compact below: routing through the
|
|
1944
|
+
// default provider is a degraded-but-useful outcome vs not compacting.
|
|
1945
|
+
}
|
|
1946
|
+
const result = await this.rpc("sessions.compact", { key: this.canonicalSessionKey(key) }, 10 * 60 * 1000);
|
|
1947
|
+
await restoreProvider();
|
|
1948
|
+
return result;
|
|
1949
|
+
}
|
|
1950
|
+
catch (err) {
|
|
1951
|
+
await restoreProvider();
|
|
1952
|
+
throw err;
|
|
1953
|
+
}
|
|
1954
|
+
finally {
|
|
1955
|
+
release();
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1847
1958
|
async compactSession(key, options = {}) {
|
|
1848
1959
|
const release = await this.acquireMaintenanceSlot("sessions.compact");
|
|
1849
1960
|
const startedAt = Date.now();
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openclaw-lark-multi-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "Multi-bot Lark/Feishu bridge for OpenClaw, with per-bot model routing and isolated sessions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"build": "tsc && npm run build:steer-plugin && npm run build:go-plugin",
|
|
7
|
+
"build": "tsc && npm run build:steer-plugin && npm run build:go-plugin && npm run build:core-plugin",
|
|
8
8
|
"build:steer-plugin": "tsc -p plugins/lma-steer/tsconfig.json",
|
|
9
9
|
"start": "node dist/index.js",
|
|
10
10
|
"dev": "tsx src/index.ts",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"test:coverage": "vitest run --config tests/normal-flow-offline.config.ts --coverage",
|
|
13
13
|
"prepack": "npm run build",
|
|
14
14
|
"prepublishOnly": "npm test && npm pack --dry-run",
|
|
15
|
-
"build:go-plugin": "tsc -p plugins/lma-go/tsconfig.json"
|
|
15
|
+
"build:go-plugin": "tsc -p plugins/lma-go/tsconfig.json",
|
|
16
|
+
"build:core-plugin": "tsc -p plugins/lma-core/tsconfig.json"
|
|
16
17
|
},
|
|
17
18
|
"dependencies": {
|
|
18
19
|
"@larksuiteoapi/node-sdk": "^1.73.3",
|
|
@@ -74,4 +75,4 @@
|
|
|
74
75
|
"publishConfig": {
|
|
75
76
|
"access": "public"
|
|
76
77
|
}
|
|
77
|
-
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Update the consolidated lma-core gateway plugin from the LMA repo source.
|
|
3
|
+
#
|
|
4
|
+
# Usage: bash scripts/update-lma-core.sh (build + deploy + hot reload)
|
|
5
|
+
# bash scripts/update-lma-core.sh --check (verify only, no changes)
|
|
6
|
+
#
|
|
7
|
+
# Requirements: repo at ~/openclaw-lark-multi-agent with the plugin sources
|
|
8
|
+
# under plugins/lma-core/src. The gateway hot-reloads the plugin; no gateway
|
|
9
|
+
# restart is needed for code updates (method names are stable).
|
|
10
|
+
set -euo pipefail
|
|
11
|
+
|
|
12
|
+
REPO="${LMA_REPO:-$HOME/openclaw-lark-multi-agent}"
|
|
13
|
+
EXT_DIR="$HOME/.openclaw/extensions/lma-core"
|
|
14
|
+
PLUGIN_ID="lma-core"
|
|
15
|
+
|
|
16
|
+
say() { printf '[update-lma-core] %s\n' "$*"; }
|
|
17
|
+
|
|
18
|
+
if [[ "${1:-}" == "--check" ]]; then
|
|
19
|
+
say "verifying deployed plugin health..."
|
|
20
|
+
openclaw gateway call health 2>/dev/null | grep -o "\"$PLUGIN_ID\"" >/dev/null \
|
|
21
|
+
&& say "OK: $PLUGIN_ID loaded in gateway" || { say "FAIL: $PLUGIN_ID not in loaded list"; exit 1; }
|
|
22
|
+
openclaw gateway call lma.core.capabilities 2>/dev/null | grep -q '"lma-core"' \
|
|
23
|
+
&& say "OK: lma.core.capabilities responds" || { say "FAIL: capabilities RPC"; exit 1; }
|
|
24
|
+
say "all checks passed."
|
|
25
|
+
exit 0
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
cd "$REPO"
|
|
29
|
+
say "building plugins/lma-core..."
|
|
30
|
+
npm run build:core-plugin
|
|
31
|
+
|
|
32
|
+
say "deploying to $EXT_DIR..."
|
|
33
|
+
mkdir -p "$EXT_DIR"
|
|
34
|
+
rm -rf "$EXT_DIR/dist"
|
|
35
|
+
cp -r plugins/lma-core/dist "$EXT_DIR/dist"
|
|
36
|
+
cp plugins/lma-core/openclaw.plugin.json plugins/lma-core/package.json "$EXT_DIR/"
|
|
37
|
+
if [[ -f plugins/lma-core/README.md ]]; then cp plugins/lma-core/README.md "$EXT_DIR/"; fi
|
|
38
|
+
|
|
39
|
+
say "hot-reloading $PLUGIN_ID..."
|
|
40
|
+
openclaw plugins reload "$PLUGIN_ID"
|
|
41
|
+
|
|
42
|
+
say "verifying..."
|
|
43
|
+
sleep 1
|
|
44
|
+
bash "$0" --check
|
|
45
|
+
say "done. (rollback: git -C $REPO checkout <prev> && re-run this script)"
|