deskbuddy 0.2.0-beta.35 → 0.2.0-beta.36
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/cli.js +102 -18
- package/hook/hook-debug.log +24 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2890,13 +2890,40 @@ function singleCursor(lines3, q) {
|
|
|
2890
2890
|
if (m) {
|
|
2891
2891
|
const k = Number(m[1]) - 1;
|
|
2892
2892
|
if (k >= 0 && k < n) return squash(m[2]).startsWith(squash(q.options[k].label).slice(0, 6)) ? k : -1;
|
|
2893
|
-
if (k === n) return /^Typesomething
|
|
2893
|
+
if (k === n) return /^(Typesomething)?$/.test(squash(m[2])) ? n : -1;
|
|
2894
2894
|
return -1;
|
|
2895
2895
|
}
|
|
2896
2896
|
if (new RegExp(`^\\s*${CURSOR}\\s*(Next|Submit)\\s*$`).test(l)) return n + 1;
|
|
2897
2897
|
}
|
|
2898
2898
|
return -1;
|
|
2899
2899
|
}
|
|
2900
|
+
function typeLine(lines3, n) {
|
|
2901
|
+
const start = questionStart(lines3);
|
|
2902
|
+
if (start < 0) return -1;
|
|
2903
|
+
for (let i = start; i < lines3.length; i++) {
|
|
2904
|
+
const m = lines3[i].match(/^\s*(?:[❯>›]\s*)?[☐☒]?\s*(\d+)\.(?:\s|$)/);
|
|
2905
|
+
if (m && Number(m[1]) === n + 1) return i;
|
|
2906
|
+
}
|
|
2907
|
+
return -1;
|
|
2908
|
+
}
|
|
2909
|
+
function typedText(lines3, n) {
|
|
2910
|
+
const ln = typeLine(lines3, n);
|
|
2911
|
+
if (ln < 0) return null;
|
|
2912
|
+
const parts = [lines3[ln].replace(/^\s*(?:[❯>›]\s*)?[☐☒]?\s*\d+\./, "")];
|
|
2913
|
+
for (let i = ln + 1; i < lines3.length; i++) {
|
|
2914
|
+
if (new RegExp(`^\\s*(?:${CURSOR}\\s*)?(Submit|Next)\\s*$`).test(lines3[i]) || /^\s*(?:[❯>›]\s*)?[☐☒]?\s*\d+\./.test(lines3[i])) break;
|
|
2915
|
+
parts.push(lines3[i]);
|
|
2916
|
+
}
|
|
2917
|
+
return squash(parts.join(""));
|
|
2918
|
+
}
|
|
2919
|
+
async function typeOther(io, q, text) {
|
|
2920
|
+
const n = q.options.length;
|
|
2921
|
+
const want = squash(text);
|
|
2922
|
+
if (!want) return "no_focus";
|
|
2923
|
+
if (!await waitUntil(io, (l) => onQuestion(l, q) && typedText(l, n) === "")) return "no_focus";
|
|
2924
|
+
io.write(text);
|
|
2925
|
+
return await waitUntil(io, (l) => typedText(l, n) === want) ? "typed" : "mismatch";
|
|
2926
|
+
}
|
|
2900
2927
|
async function move(io, delta) {
|
|
2901
2928
|
const key = delta > 0 ? KEY_DOWN : KEY_UP;
|
|
2902
2929
|
for (let i = 0; i < Math.abs(delta); i++) {
|
|
@@ -2904,12 +2931,16 @@ async function move(io, delta) {
|
|
|
2904
2931
|
await io.sleep(ARROW_GAP_MS);
|
|
2905
2932
|
}
|
|
2906
2933
|
}
|
|
2907
|
-
async function answerQuestions(io, questions, selections) {
|
|
2934
|
+
async function answerQuestions(io, questions, selections, others) {
|
|
2908
2935
|
if (questions.length === 0 || selections.length !== questions.length) return "not_waiting";
|
|
2936
|
+
if (others !== void 0 && others.length !== questions.length) return "not_waiting";
|
|
2909
2937
|
for (let qi = 0; qi < questions.length; qi++) {
|
|
2910
2938
|
const sel = selections[qi];
|
|
2911
2939
|
const q = questions[qi];
|
|
2912
|
-
|
|
2940
|
+
const n = q.options.length;
|
|
2941
|
+
const other = others?.[qi] ?? "";
|
|
2942
|
+
if (sel.length === 0 || sel.some((i) => !Number.isInteger(i) || i < 0 || i > n)) return "not_waiting";
|
|
2943
|
+
if (sel.includes(n) !== (squash(other) !== "")) return "not_waiting";
|
|
2913
2944
|
if (q.multiSelect !== true && sel.length !== 1) return "not_waiting";
|
|
2914
2945
|
}
|
|
2915
2946
|
if (!await settled(io, (l) => onQuestion(l, questions[0]))) return "not_waiting";
|
|
@@ -2930,6 +2961,14 @@ async function answerQuestions(io, questions, selections) {
|
|
|
2930
2961
|
for (const t of sel) {
|
|
2931
2962
|
await move(io, t - cur);
|
|
2932
2963
|
cur = t;
|
|
2964
|
+
if (t === n) {
|
|
2965
|
+
const ty = await typeOther(io, q, others?.[qi] ?? "");
|
|
2966
|
+
if (ty !== "no_focus") wrote = true;
|
|
2967
|
+
if (ty !== "typed") return fail();
|
|
2968
|
+
io.write(KEY_ENTER);
|
|
2969
|
+
if (!await waitUntil(io, (l) => checked(l, typeLine(l, n)))) return fail();
|
|
2970
|
+
continue;
|
|
2971
|
+
}
|
|
2933
2972
|
const onTarget = await waitUntil(io, (l) => {
|
|
2934
2973
|
const ln = optionLine(l, t + 1, q.options[t].label);
|
|
2935
2974
|
return ln >= 0 && io.cursorLine?.() === ln;
|
|
@@ -2948,7 +2987,11 @@ async function answerQuestions(io, questions, selections) {
|
|
|
2948
2987
|
const cur = singleCursor(io.screen(), q);
|
|
2949
2988
|
if (cur < 0) return fail();
|
|
2950
2989
|
await move(io, t - cur);
|
|
2951
|
-
if (
|
|
2990
|
+
if (t === n) {
|
|
2991
|
+
const ty = await typeOther(io, q, others?.[qi] ?? "");
|
|
2992
|
+
if (ty !== "no_focus") wrote = true;
|
|
2993
|
+
if (ty !== "typed") return fail();
|
|
2994
|
+
} else if (!await waitUntil(io, (l) => singleCursor(l, q) === t && optionLine(l, t + 1, q.options[t].label) >= 0)) return fail();
|
|
2952
2995
|
io.write(KEY_ENTER);
|
|
2953
2996
|
wrote = true;
|
|
2954
2997
|
}
|
|
@@ -7806,7 +7849,14 @@ ${PRELUDE3}
|
|
|
7806
7849
|
}
|
|
7807
7850
|
}
|
|
7808
7851
|
if (C && typeof C.currentId === 'string') return { mode: 'dom', locale: localeOf(), why };
|
|
7809
|
-
|
|
7852
|
+
// 没有 SDK 时列出页面上像接口的全局名(258 退回:WorkBuddy 5.1.7 没有 wb,日志里据此判断老版本把接口放在哪)
|
|
7853
|
+
let globals;
|
|
7854
|
+
if (why === 'no_wb') {
|
|
7855
|
+
try {
|
|
7856
|
+
globals = Object.getOwnPropertyNames(globalThis).filter((k) => /wb|work|buddy|genie|sdk|electron|bridge|ipc|conv|agent|app/i.test(k) && !/^on/.test(k) && k.length <= 40).sort().slice(0, 30);
|
|
7857
|
+
} catch (e) { globals = undefined; }
|
|
7858
|
+
}
|
|
7859
|
+
return { mode: 'none', locale: localeOf(), why, ...(globals ? { globals } : {}) };
|
|
7810
7860
|
})()`;
|
|
7811
7861
|
var IDLE_STATES = "['idle','completed','cancelled','canceled','done','failed','error','terminated','archived','deleted','']";
|
|
7812
7862
|
var SNAPSHOT2 = String.raw`(async () => {
|
|
@@ -8249,7 +8299,10 @@ var WorkbuddyAppWatch = class {
|
|
|
8249
8299
|
this.#nonSdkSince = first && kept && now - kept.at < NON_SDK_KEEP_MS ? kept.since : now;
|
|
8250
8300
|
this.#nonSdkKept = null;
|
|
8251
8301
|
}
|
|
8252
|
-
if (first || prev !== this.#mode || prevWhy !== this.#modeWhy)
|
|
8302
|
+
if (first || prev !== this.#mode || prevWhy !== this.#modeWhy) {
|
|
8303
|
+
const g = Array.isArray(r?.globals) ? r.globals.filter((x) => typeof x === "string").map((x) => x.slice(0, 40)).slice(0, 30) : null;
|
|
8304
|
+
this.#d.log(`WorkBuddy App \u6388\u6743\u6865\u6A21\u5F0F\uFF1A${this.#mode}${this.#modeWhy ? `\uFF08${modeWhyText(this.#modeWhy)}\uFF09` : ""}${g ? `\uFF1B\u9875\u9762\u5168\u5C40\u540D\uFF1A${g.join(",") || "\u65E0"}` : ""}`);
|
|
8305
|
+
}
|
|
8253
8306
|
const cands = this.#client?.target?.candidates ?? 1;
|
|
8254
8307
|
if (this.#mode !== "sdk" && this.#modeWhy === "no_wb" && cands > 1 && this.#nonSdkSince && now - this.#nonSdkSince >= NO_SDK_REPROBE_MS && now - this.#reprobeAt >= NO_SDK_REPROBE_MS) {
|
|
8255
8308
|
this.#reprobeAt = now;
|
|
@@ -8518,7 +8571,7 @@ function modeWhyText(why) {
|
|
|
8518
8571
|
const msg = rest.join(":");
|
|
8519
8572
|
switch (k) {
|
|
8520
8573
|
case "no_wb":
|
|
8521
|
-
return "\u9875\u9762\u91CC\u6CA1\u6709 WorkBuddy SDK\uFF08globalThis.wb\uFF09";
|
|
8574
|
+
return "\u9875\u9762\u91CC\u6CA1\u6709 WorkBuddy SDK\uFF08globalThis.wb\uFF09\uFF0CWorkBuddy \u7248\u672C\u53EF\u80FD\u592A\u65E7\uFF0C\u5347\u7EA7\u5230\u6700\u65B0\u7248\u540E\u4EFB\u52A1\u624D\u80FD\u76F4\u63A5\u8FDB App";
|
|
8522
8575
|
case "no_conversations":
|
|
8523
8576
|
return "\u9875\u9762\u91CC\u6CA1\u6709\u4F1A\u8BDD\u63A5\u53E3\uFF08wb.conversations\uFF09";
|
|
8524
8577
|
case "no_list_get":
|
|
@@ -10455,14 +10508,28 @@ function parseAnswer(m) {
|
|
|
10455
10508
|
const questions = parseQuestions(a.questions);
|
|
10456
10509
|
const sel = a.selections;
|
|
10457
10510
|
if (!questions || sel.length !== questions.length) return null;
|
|
10511
|
+
let others;
|
|
10512
|
+
if (a.others !== void 0) {
|
|
10513
|
+
if (!Array.isArray(a.others) || a.others.length !== questions.length) return null;
|
|
10514
|
+
others = [];
|
|
10515
|
+
for (const o of a.others) {
|
|
10516
|
+
if (typeof o !== "string" || o.length > OTHER_MAX_CHARS || /[\u0000-\u001f\u007f-\u009f\u200b-\u200f\u202a-\u202e\u2066-\u2069\ufeff]/.test(o)) return null;
|
|
10517
|
+
others.push(o);
|
|
10518
|
+
}
|
|
10519
|
+
}
|
|
10458
10520
|
const selections = [];
|
|
10459
10521
|
for (let i = 0; i < questions.length; i++) {
|
|
10460
10522
|
const s2 = sel[i];
|
|
10461
|
-
|
|
10523
|
+
const n = questions[i].options.length;
|
|
10524
|
+
const other = others?.[i] ?? "";
|
|
10525
|
+
if (!Array.isArray(s2) || s2.length === 0 || !s2.every((x) => Number.isInteger(x) && x >= 0 && x <= n)) return null;
|
|
10526
|
+
if (s2.includes(n) !== (other.trim() !== "")) return null;
|
|
10527
|
+
if (new Set(s2).size !== s2.length) return null;
|
|
10462
10528
|
selections.push(s2);
|
|
10463
10529
|
}
|
|
10464
|
-
return { instructionId, sessionId, expireAt, answer: { kind: "question", questions, selections } };
|
|
10530
|
+
return { instructionId, sessionId, expireAt, answer: { kind: "question", questions, selections, ...others ? { others } : {} } };
|
|
10465
10531
|
}
|
|
10532
|
+
var OTHER_MAX_CHARS = 500;
|
|
10466
10533
|
function parseQuestions(v) {
|
|
10467
10534
|
if (!Array.isArray(v)) return null;
|
|
10468
10535
|
const qs = v;
|
|
@@ -10828,20 +10895,31 @@ function pendingCall(text, toolName) {
|
|
|
10828
10895
|
function selectionsOf(input, lists) {
|
|
10829
10896
|
const qs = Array.isArray(input.questions) ? input.questions : null;
|
|
10830
10897
|
if (!qs || !Array.isArray(lists) || lists.length !== qs.length) return null;
|
|
10831
|
-
const
|
|
10898
|
+
const selections = [];
|
|
10899
|
+
const others = [];
|
|
10832
10900
|
for (let i = 0; i < qs.length; i++) {
|
|
10833
10901
|
const opts = Array.isArray(qs[i]?.options) ? qs[i].options : [];
|
|
10834
10902
|
const items = lists[i];
|
|
10835
10903
|
if (!Array.isArray(items) || items.length === 0) return null;
|
|
10836
10904
|
const idx = [];
|
|
10837
|
-
|
|
10905
|
+
let other = "";
|
|
10906
|
+
for (let j = 0; j < items.length; j++) {
|
|
10907
|
+
const label = items[j];
|
|
10838
10908
|
const k = opts.findIndex((o) => o?.label === label);
|
|
10839
|
-
if (k
|
|
10840
|
-
|
|
10909
|
+
if (k >= 0) {
|
|
10910
|
+
if (!idx.includes(k)) idx.push(k);
|
|
10911
|
+
continue;
|
|
10912
|
+
}
|
|
10913
|
+
if (j !== items.length - 1 || typeof label !== "string") return null;
|
|
10914
|
+
other = label.replace(/[\u0000-\u001f\u007f-\u009f\u200b-\u200f\u202a-\u202e\u2066-\u2069\ufeff]+/g, " ").replace(/\s+/g, " ").trim();
|
|
10915
|
+
if (!other) return null;
|
|
10841
10916
|
}
|
|
10842
|
-
|
|
10917
|
+
if (other) idx.push(opts.length);
|
|
10918
|
+
if (qs[i]?.multiSelect !== true && idx.length !== 1) return null;
|
|
10919
|
+
selections.push(idx);
|
|
10920
|
+
others.push(other);
|
|
10843
10921
|
}
|
|
10844
|
-
return
|
|
10922
|
+
return { selections, others };
|
|
10845
10923
|
}
|
|
10846
10924
|
var WorkbuddyBridge = class {
|
|
10847
10925
|
#d;
|
|
@@ -10979,10 +11057,16 @@ var WorkbuddyBridge = class {
|
|
|
10979
11057
|
if (reply.decision !== "allow") return;
|
|
10980
11058
|
const sel = selectionsOf(card.input, reply.answerLists);
|
|
10981
11059
|
if (!sel) {
|
|
10982
|
-
this.#d.log(`WorkBuddy\uFF1A\u4F1A\u8BDD ${card.sessionId.slice(0, 8)} \u7684\u8BBE\u5907\u7B54\u6848\u5BF9\u4E0D\u4E0A\u9009\u9879\
|
|
11060
|
+
this.#d.log(`WorkBuddy\uFF1A\u4F1A\u8BDD ${card.sessionId.slice(0, 8)} \u7684\u8BBE\u5907\u7B54\u6848\u5BF9\u4E0D\u4E0A\u9009\u9879\uFF0C\u6846\u7559\u7ED9\u7535\u8111`);
|
|
10983
11061
|
return;
|
|
10984
11062
|
}
|
|
10985
|
-
|
|
11063
|
+
const withOther = sel.others.some((o) => o !== "");
|
|
11064
|
+
spec = {
|
|
11065
|
+
kind: "question",
|
|
11066
|
+
questions: card.input.questions,
|
|
11067
|
+
selections: sel.selections,
|
|
11068
|
+
...withOther ? { others: sel.others } : {}
|
|
11069
|
+
};
|
|
10986
11070
|
} else if (reply.decision === "allow" || reply.decision === "deny") {
|
|
10987
11071
|
spec = { kind: "permission", toolName: card.toolName, fingerprint: card.fingerprint, decision: reply.decision };
|
|
10988
11072
|
} else return;
|
|
@@ -19667,7 +19751,7 @@ async function applyAnswer(req, io, trust) {
|
|
|
19667
19751
|
} else if (a.kind === "trust" && a.prompt !== "hooks" && trust?.widens) r = "not_waiting";
|
|
19668
19752
|
else if (a.kind === "trust") r = await answerTrust(keys, trust?.tool ?? "", a.decision, trust?.forms ?? [], a.prompt ?? "trust");
|
|
19669
19753
|
else if (a.kind === "permission") r = await answerPermission(keys, a.toolName, a.fingerprint, a.decision);
|
|
19670
|
-
else r = await answerQuestions(keys, a.questions, a.selections);
|
|
19754
|
+
else r = await answerQuestions(keys, a.questions, a.selections, a.others);
|
|
19671
19755
|
} catch {
|
|
19672
19756
|
r = "partial";
|
|
19673
19757
|
}
|
package/hook/hook-debug.log
CHANGED
|
@@ -338,3 +338,27 @@
|
|
|
338
338
|
2026-10-12T07:48:57.673Z [opencode] opencode 版本 读不出:带说明的拒绝不走新路由
|
|
339
339
|
2026-10-12T07:48:57.673Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
|
|
340
340
|
2026-10-12T07:49:00.208Z [opencode] 后台任务里的提问 que_r2 没法在设备上回答(后台任务不能提问,请在电脑上继续),已拒绝
|
|
341
|
+
2026-10-12T08:43:33.911Z [opencode] 回填选择题失败:/question/{requestID}/reply status=404
|
|
342
|
+
2026-10-12T08:43:38.975Z [opencode] opencode 版本 1.4.3:带说明的拒绝不走新路由
|
|
343
|
+
2026-10-12T08:43:38.975Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
|
|
344
|
+
2026-10-12T08:43:39.078Z [opencode] opencode 版本 读不出:带说明的拒绝不走新路由
|
|
345
|
+
2026-10-12T08:43:39.078Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
|
|
346
|
+
2026-10-12T08:43:41.400Z [opencode] 后台任务里的提问 que_r2 没法在设备上回答(后台任务不能提问,请在电脑上继续),已拒绝
|
|
347
|
+
2026-10-12T08:45:36.004Z [opencode] 回填选择题失败:/question/{requestID}/reply status=404
|
|
348
|
+
2026-10-12T08:45:40.986Z [opencode] opencode 版本 1.4.3:带说明的拒绝不走新路由
|
|
349
|
+
2026-10-12T08:45:40.986Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
|
|
350
|
+
2026-10-12T08:45:41.084Z [opencode] opencode 版本 读不出:带说明的拒绝不走新路由
|
|
351
|
+
2026-10-12T08:45:41.084Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
|
|
352
|
+
2026-10-12T08:45:43.292Z [opencode] 后台任务里的提问 que_r2 没法在设备上回答(后台任务不能提问,请在电脑上继续),已拒绝
|
|
353
|
+
2026-10-12T08:51:55.878Z [opencode] 回填选择题失败:/question/{requestID}/reply status=404
|
|
354
|
+
2026-10-12T08:52:01.359Z [opencode] opencode 版本 1.4.3:带说明的拒绝不走新路由
|
|
355
|
+
2026-10-12T08:52:01.360Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
|
|
356
|
+
2026-10-12T08:52:01.517Z [opencode] opencode 版本 读不出:带说明的拒绝不走新路由
|
|
357
|
+
2026-10-12T08:52:01.517Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
|
|
358
|
+
2026-10-12T08:52:04.661Z [opencode] 后台任务里的提问 que_r2 没法在设备上回答(后台任务不能提问,请在电脑上继续),已拒绝
|
|
359
|
+
2026-10-12T09:01:07.164Z [opencode] 回填选择题失败:/question/{requestID}/reply status=404
|
|
360
|
+
2026-10-12T09:01:12.193Z [opencode] opencode 版本 1.4.3:带说明的拒绝不走新路由
|
|
361
|
+
2026-10-12T09:01:12.194Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
|
|
362
|
+
2026-10-12T09:01:12.293Z [opencode] opencode 版本 读不出:带说明的拒绝不走新路由
|
|
363
|
+
2026-10-12T09:01:12.293Z [opencode] opencode 版本不确定支持带说明的拒绝,设备上的反馈没有带给模型
|
|
364
|
+
2026-10-12T09:01:14.613Z [opencode] 后台任务里的提问 que_r2 没法在设备上回答(后台任务不能提问,请在电脑上继续),已拒绝
|