larkway 0.3.32 → 0.3.33
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/README.md +1 -1
- package/README.zh.md +1 -1
- package/dist/main.js +63 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
You @ the bot in a Feishu thread. It runs on your machine — reading your real codebase, executing commands, opening MRs — and posts the result back. You define what the agent knows and what it can do. Larkway just carries the messages.
|
|
10
10
|
|
|
11
|
-
**Current release: v0.3.
|
|
11
|
+
**Current release: v0.3.33**
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
package/README.zh.md
CHANGED
package/dist/main.js
CHANGED
|
@@ -119133,7 +119133,30 @@ var StateFileSchema = external_exports.object({
|
|
|
119133
119133
|
* ignored and the legacy card path remains authoritative.
|
|
119134
119134
|
*/
|
|
119135
119135
|
response_surface: ResponseSurfaceStateSchema.optional(),
|
|
119136
|
-
|
|
119136
|
+
/**
|
|
119137
|
+
* Freshness signal for the handler's stale-guard (it compares this against a
|
|
119138
|
+
* pre-run snapshot to decide whether the bot rewrote state THIS turn).
|
|
119139
|
+
*
|
|
119140
|
+
* **OPTIONAL by thin-channel principle.** This used to be the ONE hard-required
|
|
119141
|
+
* field, so a bot that wrote a perfectly good `status` + `last_message` but
|
|
119142
|
+
* omitted `updated_at` had its ENTIRE state discarded → the card stranded on
|
|
119143
|
+
* "本轮没有拿到 agent 的新回复" every single turn (2026-07-02 排障: one shared
|
|
119144
|
+
* topic reproduced this on every @). Same failure class as the old
|
|
119145
|
+
* `z.string().url()` mr_url and the strict `stage`/`card_color` enums.
|
|
119146
|
+
*
|
|
119147
|
+
* When absent, {@link readStateFileDetailed} server-stamps it from the file's
|
|
119148
|
+
* mtime — which advances only on a real rewrite, so the stale-guard stays
|
|
119149
|
+
* correct even for bots that never write the field.
|
|
119150
|
+
*/
|
|
119151
|
+
updated_at: external_exports.string().optional()
|
|
119152
|
+
});
|
|
119153
|
+
var SalvageStateSchema = external_exports.object({
|
|
119154
|
+
status: external_exports.enum(["in_progress", "ready", "failed"]),
|
|
119155
|
+
last_message: external_exports.string().optional().catch(void 0),
|
|
119156
|
+
error: external_exports.string().optional().catch(void 0),
|
|
119157
|
+
card_title: external_exports.string().optional().catch(void 0),
|
|
119158
|
+
card_text: external_exports.string().optional().catch(void 0),
|
|
119159
|
+
updated_at: external_exports.string().optional().catch(void 0)
|
|
119137
119160
|
});
|
|
119138
119161
|
function stateDirOf(worktreePath) {
|
|
119139
119162
|
return path6.join(worktreePath, ".larkway");
|
|
@@ -119171,6 +119194,11 @@ async function readStateFileDetailed(worktreePath) {
|
|
|
119171
119194
|
console.warn(`[stateFile] read ${file} failed:`, err);
|
|
119172
119195
|
return { state: null, diagnostics: [] };
|
|
119173
119196
|
}
|
|
119197
|
+
let mtimeIso;
|
|
119198
|
+
try {
|
|
119199
|
+
mtimeIso = (await fs3.stat(file)).mtime.toISOString();
|
|
119200
|
+
} catch {
|
|
119201
|
+
}
|
|
119174
119202
|
let parsed;
|
|
119175
119203
|
try {
|
|
119176
119204
|
parsed = JSON.parse(raw);
|
|
@@ -119195,18 +119223,39 @@ async function readStateFileDetailed(worktreePath) {
|
|
|
119195
119223
|
}
|
|
119196
119224
|
}
|
|
119197
119225
|
const result = StateFileSchema.safeParse(parsed);
|
|
119198
|
-
if (
|
|
119199
|
-
|
|
119200
|
-
|
|
119201
|
-
|
|
119202
|
-
|
|
119203
|
-
|
|
119204
|
-
|
|
119205
|
-
|
|
119206
|
-
|
|
119226
|
+
if (result.success) {
|
|
119227
|
+
const state = withStampedUpdatedAt(result.data, mtimeIso);
|
|
119228
|
+
const diagnostics = diagnoseStateFile(parsed, result.data);
|
|
119229
|
+
for (const diagnostic of diagnostics) {
|
|
119230
|
+
console.warn(`[stateFile] ${file}: ${diagnostic}`);
|
|
119231
|
+
}
|
|
119232
|
+
return { state, diagnostics };
|
|
119233
|
+
}
|
|
119234
|
+
const salvaged = SalvageStateSchema.safeParse(parsed);
|
|
119235
|
+
if (salvaged.success) {
|
|
119236
|
+
const droppedFields = summarizeRejectedTopFields(result.error);
|
|
119237
|
+
const state = withStampedUpdatedAt(salvaged.data, mtimeIso);
|
|
119238
|
+
const diagnostic = `state.json \u90E8\u5206\u5B57\u6BB5\u65E0\u6548\u5DF2\u5FFD\u7565\uFF0C\u4FDD\u7559 status/last_message\uFF08\u53D7\u5F71\u54CD\u5B57\u6BB5\uFF1A${droppedFields}\uFF09`;
|
|
119207
119239
|
console.warn(`[stateFile] ${file}: ${diagnostic}`);
|
|
119240
|
+
return { state, diagnostics: [diagnostic] };
|
|
119241
|
+
}
|
|
119242
|
+
console.warn(
|
|
119243
|
+
`[stateFile] ${file} failed schema validation (unsalvageable):`,
|
|
119244
|
+
result.error.issues
|
|
119245
|
+
);
|
|
119246
|
+
return { state: null, diagnostics: [] };
|
|
119247
|
+
}
|
|
119248
|
+
function withStampedUpdatedAt(state, mtimeIso) {
|
|
119249
|
+
if (state.updated_at != null && state.updated_at !== "") return state;
|
|
119250
|
+
return { ...state, updated_at: mtimeIso ?? (/* @__PURE__ */ new Date()).toISOString() };
|
|
119251
|
+
}
|
|
119252
|
+
function summarizeRejectedTopFields(error) {
|
|
119253
|
+
const fields = /* @__PURE__ */ new Set();
|
|
119254
|
+
for (const issue of error.issues) {
|
|
119255
|
+
const top = issue.path[0];
|
|
119256
|
+
fields.add(top === void 0 ? "(root)" : String(top));
|
|
119208
119257
|
}
|
|
119209
|
-
return
|
|
119258
|
+
return [...fields].join(", ") || "(unknown)";
|
|
119210
119259
|
}
|
|
119211
119260
|
function diagnoseStateFile(parsed, state) {
|
|
119212
119261
|
if (parsed === null || typeof parsed !== "object") return [];
|
|
@@ -120952,7 +121001,9 @@ var BridgeHandler = class {
|
|
|
120952
121001
|
});
|
|
120953
121002
|
}
|
|
120954
121003
|
const fallbackAnswer = trustedAnswerText.trim() || cardKitProgress?.answerText.trim() || "";
|
|
120955
|
-
const
|
|
121004
|
+
const noOutputFallback = "\u26A0\uFE0F \u672C\u8F6E agent \u6CA1\u6709\u4EA7\u51FA\u6B63\u6587\uFF0C\u4E5F\u6CA1\u6709\u5199\u5165\u6709\u6548\u72B6\u6001(state.json)\u3002\n" + (result.exitCode !== 0 ? `agent \u8FDB\u7A0B\u5F02\u5E38\u9000\u51FA(exit code ${result.exitCode})\u3002
|
|
121005
|
+
` : "") + "\u4E0B\u4E00\u6B65\uFF1A\u6362\u4E2A\u8BF4\u6CD5\u91CD\u8BD5\uFF0C\u6216\u65B0\u5F00\u4E00\u4E2A\u8BDD\u9898\u7EE7\u7EED\uFF1B\u82E5\u53CD\u590D\u5982\u6B64\uFF0C\u8BF7\u8BA9\u7EF4\u62A4\u8005\u67E5\u770B\u8BE5 session \u65E5\u5FD7\u3002";
|
|
121006
|
+
const cardBody = cardKitTimeoutFailure ? "\u26A0\uFE0F \u672C\u8F6E\u88AB\u4E2D\u65AD\uFF08\u957F\u65F6\u95F4\u65E0\u6D3B\u6027\uFF0C\u5224\u5B9A\u5361\u6B7B\uFF09\uFF0C\u672A\u5B8C\u6210\u3002\u8BF7\u91CD\u8BD5\u3002" : reportedState?.last_message ?? (fallbackAnswer ? fallbackAnswer : noOutputFallback);
|
|
120956
121007
|
const noReportThisTurn = reportedState === null;
|
|
120957
121008
|
const neutralTitle = noReportThisTurn && success && !failureReason ? "\u{1F4AC} \u5DF2\u56DE\u590D" : void 0;
|
|
120958
121009
|
const baseCardPayload = {
|