@dsh-workbench/core 0.2.14 → 0.2.16
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/client.js +630 -142
- package/dist/client/client.body.js +630 -142
- package/dist/client/index.js +3524 -421
- package/dist/host/index.js +571 -44
- package/dist/types/app/client.d.ts +121 -6
- package/dist/types/app/layouts/rightbar/__tests__/board-fact.test.d.ts +1 -0
- package/dist/types/app/layouts/rightbar/board-fact.d.ts +5 -0
- package/dist/types/app/layouts/sidebar/DebugFooterAction.d.ts +17 -0
- package/dist/types/app/layouts/sidebar/ProjectSwitcher.d.ts +2 -1
- package/dist/types/app/layouts/sidebar/__tests__/debug-ui.test.d.ts +1 -0
- package/dist/types/app/layouts/sidebar/debug-footer.d.ts +4 -0
- package/dist/types/app/layouts/sidebar/session-pick.d.ts +2 -1
- package/dist/types/modules/panels/__tests__/diy-harness.d.ts +6 -3
- package/dist/types/modules/panels/model/diy-browser-act.d.ts +1 -1
- package/dist/types/modules/panels/model/diy-browser.d.ts +4 -0
- package/dist/types/modules/panels/model/diy-debug-routes.d.ts +2 -0
- package/dist/types/modules/panels/model/diy-debug-routes.test.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-debug-tools.d.ts +8 -0
- package/dist/types/modules/panels/model/diy-debug-tools.test.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-look.d.ts +2 -1
- package/dist/types/modules/panels/model/diy-page.d.ts +14 -0
- package/dist/types/modules/panels/model/diy-scripts.d.ts +2 -1
- package/dist/types/modules/panels/model/diy-tools.d.ts +2 -1
- package/dist/types/modules/panels/model/handoff.d.ts +1 -0
- package/dist/types/modules/panels/unit.d.ts +7 -2
- package/dist/types/modules/sessions/index.d.ts +1 -1
- package/dist/types/modules/sessions/model/attention.d.ts +7 -0
- package/dist/types/shared/__tests__/host-import-barrel.test.d.ts +1 -0
- package/dist/types/shared/api/host/__tests__/diy-debug-act.test.d.ts +1 -0
- package/dist/types/shared/api/host/__tests__/host-args.test.d.ts +1 -0
- package/dist/types/shared/api/host/diy-debug-act.d.ts +31 -0
- package/dist/types/shared/api/host/host-args.d.ts +3 -0
- package/dist/types/shared/hooks/use-api-resource.d.ts +1 -0
- package/dist/types/shared/hooks/use-diy-debug.d.ts +8 -0
- package/package.json +2 -2
- package/skills/workbench-module-diy/KIT.md +18 -3
package/dist/host/index.js
CHANGED
|
@@ -13,11 +13,15 @@ var PREFS_PREFIX = `${API_PREFIX}/prefs`;
|
|
|
13
13
|
var EVENTS_PATH = "/workbench/events";
|
|
14
14
|
var ACTIONS_PREFIX = `${API_PREFIX}/actions`;
|
|
15
15
|
var PROVISION_PREFIX = `${API_PREFIX}/provision`;
|
|
16
|
-
var
|
|
16
|
+
var PANEL_STATE_PATH = "panel-state";
|
|
17
|
+
var DIY_DEBUG_PATH = "diy-debug";
|
|
18
|
+
`${DIY_DEBUG_PATH}`;
|
|
19
|
+
var PANEL_STATE_PREFIX = `${API_PREFIX}/${PANEL_STATE_PATH}`;
|
|
17
20
|
var OPENCLI_PIN = "1.8.8";
|
|
18
21
|
var PANELS_SERVICE = "workbenchPanels";
|
|
19
22
|
var UNITS_SERVICE = "workbenchUnits";
|
|
20
23
|
var PANEL_STATE_SERVICE = "workbenchPanelState";
|
|
24
|
+
var DIY_DEBUG_SERVICE = "workbenchDiyDebug";
|
|
21
25
|
var OPENCLI_TIMEOUT_MS = 12e4;
|
|
22
26
|
var WARM_TIMEOUT_MS = 2e4;
|
|
23
27
|
var INSTALL_TIMEOUT_MS = 3e5;
|
|
@@ -435,6 +439,125 @@ function createPanelStateStore() {
|
|
|
435
439
|
};
|
|
436
440
|
}
|
|
437
441
|
//#endregion
|
|
442
|
+
//#region ../shared/dist/lib/board-fact.js
|
|
443
|
+
function insideWorkshop$1(root, target) {
|
|
444
|
+
if (target === root) return true;
|
|
445
|
+
const base = root.endsWith("/") ? root : `${root}/`;
|
|
446
|
+
return target.startsWith(base);
|
|
447
|
+
}
|
|
448
|
+
function boardFactOf(probe, workshop) {
|
|
449
|
+
if (!probe.workbench) return "unknown";
|
|
450
|
+
if (!probe.bar || !probe.open || !probe.drawn) return "hidden";
|
|
451
|
+
if (probe.board === "" || workshop === null) return "unknown";
|
|
452
|
+
return insideWorkshop$1(workshop, probe.board) ? "workshop" : "other";
|
|
453
|
+
}
|
|
454
|
+
function boardSituation(probe, workshop) {
|
|
455
|
+
if (!probe.workbench || workshop === null) return "unknown";
|
|
456
|
+
if (probe.bar && probe.open && probe.drawn) {
|
|
457
|
+
if (probe.board === "") return "unknown";
|
|
458
|
+
return insideWorkshop$1(workshop, probe.board) ? "ok" : "other-board";
|
|
459
|
+
}
|
|
460
|
+
if (probe.where !== "" && !insideWorkshop$1(workshop, probe.where)) return "off-workspace";
|
|
461
|
+
return "panel-closed";
|
|
462
|
+
}
|
|
463
|
+
//#endregion
|
|
464
|
+
//#region ../shared/dist/lib/diy-debug.js
|
|
465
|
+
function parseDebugIntent(value) {
|
|
466
|
+
return value === "pause" || value === "resume" || value === "stop" ? value : null;
|
|
467
|
+
}
|
|
468
|
+
function alive(state, now) {
|
|
469
|
+
if (state === null) return null;
|
|
470
|
+
return now - state.at <= 144e5 ? state : null;
|
|
471
|
+
}
|
|
472
|
+
function ownerOf(state, sessionId, now) {
|
|
473
|
+
const held = alive(state, now);
|
|
474
|
+
if (held === null) return "none";
|
|
475
|
+
return held.sessionId === sessionId ? held : "not-owner";
|
|
476
|
+
}
|
|
477
|
+
function createDebugStore() {
|
|
478
|
+
let held = null;
|
|
479
|
+
const live = (now) => alive(held, now);
|
|
480
|
+
return {
|
|
481
|
+
live,
|
|
482
|
+
begin(pact) {
|
|
483
|
+
const current = alive(held, pact.now);
|
|
484
|
+
if (current !== null) return {
|
|
485
|
+
ok: false,
|
|
486
|
+
code: current.sessionId === pact.sessionId ? "already-held" : "held-by-other"
|
|
487
|
+
};
|
|
488
|
+
const state = {
|
|
489
|
+
phase: "debugging",
|
|
490
|
+
sessionId: pact.sessionId,
|
|
491
|
+
workspace: pact.workspace,
|
|
492
|
+
board: pact.board,
|
|
493
|
+
unit: pact.unit,
|
|
494
|
+
name: pact.name,
|
|
495
|
+
startedAt: pact.now,
|
|
496
|
+
at: pact.now
|
|
497
|
+
};
|
|
498
|
+
held = state;
|
|
499
|
+
return {
|
|
500
|
+
ok: true,
|
|
501
|
+
state
|
|
502
|
+
};
|
|
503
|
+
},
|
|
504
|
+
pause(sessionId, now) {
|
|
505
|
+
const found = ownerOf(held, sessionId, now);
|
|
506
|
+
if (typeof found === "string") return {
|
|
507
|
+
ok: false,
|
|
508
|
+
code: found
|
|
509
|
+
};
|
|
510
|
+
if (found.phase === "paused") return {
|
|
511
|
+
ok: false,
|
|
512
|
+
code: "already-paused"
|
|
513
|
+
};
|
|
514
|
+
const state = {
|
|
515
|
+
...found,
|
|
516
|
+
phase: "paused",
|
|
517
|
+
at: now
|
|
518
|
+
};
|
|
519
|
+
held = state;
|
|
520
|
+
return {
|
|
521
|
+
ok: true,
|
|
522
|
+
state
|
|
523
|
+
};
|
|
524
|
+
},
|
|
525
|
+
resume(sessionId, now) {
|
|
526
|
+
const found = ownerOf(held, sessionId, now);
|
|
527
|
+
if (typeof found === "string") return {
|
|
528
|
+
ok: false,
|
|
529
|
+
code: found
|
|
530
|
+
};
|
|
531
|
+
if (found.phase === "debugging") return {
|
|
532
|
+
ok: false,
|
|
533
|
+
code: "already-debugging"
|
|
534
|
+
};
|
|
535
|
+
const state = {
|
|
536
|
+
...found,
|
|
537
|
+
phase: "debugging",
|
|
538
|
+
at: now
|
|
539
|
+
};
|
|
540
|
+
held = state;
|
|
541
|
+
return {
|
|
542
|
+
ok: true,
|
|
543
|
+
state
|
|
544
|
+
};
|
|
545
|
+
},
|
|
546
|
+
stop(sessionId, now) {
|
|
547
|
+
const found = ownerOf(held, sessionId, now);
|
|
548
|
+
if (typeof found === "string") return {
|
|
549
|
+
ok: false,
|
|
550
|
+
code: found
|
|
551
|
+
};
|
|
552
|
+
held = null;
|
|
553
|
+
return {
|
|
554
|
+
ok: true,
|
|
555
|
+
state: found
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
//#endregion
|
|
438
561
|
//#region ../shared/dist/host/opencli-window.js
|
|
439
562
|
var OPENCLI_WINDOW_ENV = "OPENCLI_WINDOW=background";
|
|
440
563
|
function backgroundPrefix() {
|
|
@@ -1661,6 +1784,15 @@ function registerPanelState(ctx, store) {
|
|
|
1661
1784
|
}]
|
|
1662
1785
|
});
|
|
1663
1786
|
}
|
|
1787
|
+
function registerDiyDebugAct(ctx, resource, log) {
|
|
1788
|
+
return registerPost(ctx, {
|
|
1789
|
+
prefix: `${API_PREFIX}/${DIY_DEBUG_PATH}`,
|
|
1790
|
+
what: "工作台 DIY 调试动作",
|
|
1791
|
+
refusedCode: "action-refused",
|
|
1792
|
+
resources: [resource],
|
|
1793
|
+
wrote: () => log?.bump(["diy-debug"])
|
|
1794
|
+
});
|
|
1795
|
+
}
|
|
1664
1796
|
//#endregion
|
|
1665
1797
|
//#region ../shared/dist/host/long-task.js
|
|
1666
1798
|
var LIVE = /* @__PURE__ */ new Set(["running", "needs-login"]);
|
|
@@ -2138,6 +2270,10 @@ function sessionWorkspace(exec) {
|
|
|
2138
2270
|
const cwd = exec?.agent?.session?.header?.cwd;
|
|
2139
2271
|
return typeof cwd === "string" && cwd.trim() !== "" ? cwd.trim() : null;
|
|
2140
2272
|
}
|
|
2273
|
+
function sessionIdOf(exec) {
|
|
2274
|
+
const id = exec?.agent?.session?.id;
|
|
2275
|
+
return typeof id === "string" && id.trim() !== "" ? id.trim() : null;
|
|
2276
|
+
}
|
|
2141
2277
|
function textOutput(text) {
|
|
2142
2278
|
return [{
|
|
2143
2279
|
type: "text",
|
|
@@ -2799,9 +2935,7 @@ function workshopPackagesDir(ctx) {
|
|
|
2799
2935
|
return root === null ? null : join(root, "packages");
|
|
2800
2936
|
}
|
|
2801
2937
|
function insideWorkshop(root, target) {
|
|
2802
|
-
|
|
2803
|
-
const real = existsSync(target) ? realpathSync(target) : resolve(target);
|
|
2804
|
-
return real === base || real.startsWith(base + sep);
|
|
2938
|
+
return insideWorkshop$1(existsSync(root) ? realpathSync(root) : resolve(root), existsSync(target) ? realpathSync(target) : resolve(target));
|
|
2805
2939
|
}
|
|
2806
2940
|
function workshopModules(packagesDir, installed = []) {
|
|
2807
2941
|
if (!existsSync(packagesDir)) return [];
|
|
@@ -2871,6 +3005,10 @@ var DIY_NET_STOP_TOOL = "workbench_diy_net_stop";
|
|
|
2871
3005
|
var DIY_LOGS_WATCH_TOOL = "workbench_diy_logs_watch";
|
|
2872
3006
|
var DIY_LOGS_READ_TOOL = "workbench_diy_logs_read";
|
|
2873
3007
|
var DIY_LOGS_STOP_TOOL = "workbench_diy_logs_stop";
|
|
3008
|
+
var DIY_DEBUG_START_TOOL = "workbench_diy_debug_start";
|
|
3009
|
+
var DIY_DEBUG_PAUSE_TOOL = "workbench_diy_debug_pause";
|
|
3010
|
+
var DIY_DEBUG_RESUME_TOOL = "workbench_diy_debug_resume";
|
|
3011
|
+
var DIY_DEBUG_STOP_TOOL = "workbench_diy_debug_stop";
|
|
2874
3012
|
var READ_TOOLS = [
|
|
2875
3013
|
PANELS_LIST_TOOL,
|
|
2876
3014
|
MODULES_LIST_TOOL,
|
|
@@ -2911,7 +3049,11 @@ var WRITE_TOOLS = [
|
|
|
2911
3049
|
MODULES_UNINSTALL_PLUGIN_TOOL,
|
|
2912
3050
|
MODULES_UPDATE_WORKBENCH_TOOL,
|
|
2913
3051
|
DIY_INSTALL_TOOL,
|
|
2914
|
-
DIY_SHOW_TOOL
|
|
3052
|
+
DIY_SHOW_TOOL,
|
|
3053
|
+
DIY_DEBUG_START_TOOL,
|
|
3054
|
+
DIY_DEBUG_PAUSE_TOOL,
|
|
3055
|
+
DIY_DEBUG_RESUME_TOOL,
|
|
3056
|
+
DIY_DEBUG_STOP_TOOL
|
|
2915
3057
|
];
|
|
2916
3058
|
var DIY_TOOLS = [
|
|
2917
3059
|
DIY_LIST_TOOL,
|
|
@@ -2938,6 +3080,12 @@ var DIY_TOOLS = [
|
|
|
2938
3080
|
DIY_LOGS_READ_TOOL,
|
|
2939
3081
|
DIY_LOGS_STOP_TOOL
|
|
2940
3082
|
];
|
|
3083
|
+
var DIY_DEBUG_TOOLS = [
|
|
3084
|
+
DIY_DEBUG_START_TOOL,
|
|
3085
|
+
DIY_DEBUG_PAUSE_TOOL,
|
|
3086
|
+
DIY_DEBUG_RESUME_TOOL,
|
|
3087
|
+
DIY_DEBUG_STOP_TOOL
|
|
3088
|
+
];
|
|
2941
3089
|
var panelsUnit = {
|
|
2942
3090
|
id: "panels",
|
|
2943
3091
|
card: null,
|
|
@@ -3031,6 +3179,13 @@ function askOf(reason, question, fallback) {
|
|
|
3031
3179
|
};
|
|
3032
3180
|
}
|
|
3033
3181
|
var panelsApproval = (call) => {
|
|
3182
|
+
if (call.name === "workbench_diy_debug_start" || call.name === "workbench_diy_debug_resume") {
|
|
3183
|
+
const starting = call.name === DIY_DEBUG_START_TOOL;
|
|
3184
|
+
const unit = argsOf$1(call)["unit"];
|
|
3185
|
+
const target = typeof unit === "string" && unit !== "" ? ` [${unit}]` : "";
|
|
3186
|
+
return askOf(`${call.name}${target} takes over the user's screen to debug a workbench module`, pair(starting ? "要在「工作台DIY」那块板上开始调试 —— 调试中请留在那一屏,允许吗?" : "要接着调试 —— 请回到「工作台DIY」那一屏,允许吗?", starting ? "it takes over your screen to debug on the workshop board — please stay on that screen. Allow?" : "it needs your screen again to keep debugging — please go back to the workshop board. Allow?"), pair(starting ? "agent 要占用你的屏幕开始调试工作台模块,允许吗?" : "agent 要接着占用你的屏幕调试,允许吗?", starting ? "The agent wants to take over your screen to start debugging a workbench module. Allow?" : "The agent wants your screen again to keep debugging. Allow?"));
|
|
3187
|
+
}
|
|
3188
|
+
if (call.name === "workbench_diy_debug_pause" || call.name === "workbench_diy_debug_stop") return { kind: "allow" };
|
|
3034
3189
|
if (call.name !== void 0 && DIY_TOOLS.includes(call.name)) return { kind: "allow" };
|
|
3035
3190
|
const raw = argsOf$1(call);
|
|
3036
3191
|
const text = (key) => {
|
|
@@ -3591,11 +3746,28 @@ function numberIn$1(value, fallback) {
|
|
|
3591
3746
|
}
|
|
3592
3747
|
var PAGE_PROBE = `(async () => {
|
|
3593
3748
|
const answer = await fetch('/workbench/api/health').then((one) => one.json()).catch(() => null);
|
|
3749
|
+
const root = document.querySelector('.wb-root');
|
|
3750
|
+
const where = root === null ? '' : (root.getAttribute('data-wb-where') ?? '');
|
|
3751
|
+
const bar = document.querySelector('.wb-rightbar');
|
|
3752
|
+
const board = bar === null ? '' : (bar.getAttribute('data-wb-board') ?? '');
|
|
3753
|
+
const open = bar === null ? null : bar.hasAttribute('data-wb-open');
|
|
3754
|
+
const style = bar === null ? null : getComputedStyle(bar);
|
|
3755
|
+
const box = bar === null ? null : bar.getBoundingClientRect();
|
|
3756
|
+
const drawn =
|
|
3757
|
+
bar !== null &&
|
|
3758
|
+
style.visibility !== 'hidden' &&
|
|
3759
|
+
style.display !== 'none' &&
|
|
3760
|
+
box.width > 0 &&
|
|
3761
|
+
box.height > 0;
|
|
3594
3762
|
return JSON.stringify({
|
|
3595
3763
|
plugin: answer === null ? null : answer.plugin,
|
|
3596
3764
|
pid: answer === null ? null : answer.pid,
|
|
3597
3765
|
url: location.href,
|
|
3598
3766
|
title: document.title,
|
|
3767
|
+
where,
|
|
3768
|
+
board,
|
|
3769
|
+
open,
|
|
3770
|
+
shown: drawn,
|
|
3599
3771
|
});
|
|
3600
3772
|
})()`;
|
|
3601
3773
|
function cardSelectorOf(unit) {
|
|
@@ -3657,6 +3829,7 @@ var NO_PICK = {
|
|
|
3657
3829
|
var EMPTY_CARD = {
|
|
3658
3830
|
ok: false,
|
|
3659
3831
|
anchored: false,
|
|
3832
|
+
visible: false,
|
|
3660
3833
|
width: 0,
|
|
3661
3834
|
height: 0,
|
|
3662
3835
|
head: "",
|
|
@@ -3703,10 +3876,13 @@ function measureScriptOf(unit, pick) {
|
|
|
3703
3876
|
};
|
|
3704
3877
|
const anchor = document.querySelector(${JSON.stringify(cardSelectorOf(unit))});
|
|
3705
3878
|
const all = [...document.querySelectorAll('.wb-card')];
|
|
3706
|
-
if (anchor === null) return JSON.stringify({ ok: false, cards: all.length, anchored: false });
|
|
3879
|
+
if (anchor === null) return JSON.stringify({ ok: false, cards: all.length, anchored: false, visible: false });
|
|
3707
3880
|
const card = anchor.classList.contains('wb-card') ? anchor : anchor.querySelector('.wb-card');
|
|
3708
|
-
if (card === null) return JSON.stringify({ ok: false, cards: all.length, anchored: true });
|
|
3881
|
+
if (card === null) return JSON.stringify({ ok: false, cards: all.length, anchored: true, visible: false });
|
|
3709
3882
|
const box = card.getBoundingClientRect();
|
|
3883
|
+
const painted = getComputedStyle(card);
|
|
3884
|
+
const visible =
|
|
3885
|
+
painted.visibility !== 'hidden' && painted.display !== 'none' && box.width > 0 && box.height > 0;
|
|
3710
3886
|
const head = card.querySelector('.wb-cardTitle');
|
|
3711
3887
|
const text = scrub(card.textContent);
|
|
3712
3888
|
const shown = scrub(card.innerText);
|
|
@@ -3749,6 +3925,7 @@ function measureScriptOf(unit, pick) {
|
|
|
3749
3925
|
return JSON.stringify({
|
|
3750
3926
|
ok: true,
|
|
3751
3927
|
cards: all.length,
|
|
3928
|
+
visible,
|
|
3752
3929
|
width: Math.ceil(box.width),
|
|
3753
3930
|
height: Math.ceil(box.height),
|
|
3754
3931
|
x: Math.round(box.x),
|
|
@@ -3900,12 +4077,21 @@ async function workbenchPageOf(shell, command, session) {
|
|
|
3900
4077
|
if (parsed === void 0) return {
|
|
3901
4078
|
ok: false,
|
|
3902
4079
|
url: "",
|
|
3903
|
-
title: ""
|
|
4080
|
+
title: "",
|
|
4081
|
+
where: "",
|
|
4082
|
+
board: "",
|
|
4083
|
+
open: null,
|
|
4084
|
+
shown: false
|
|
3904
4085
|
};
|
|
4086
|
+
const raw = parsed["open"];
|
|
3905
4087
|
return {
|
|
3906
4088
|
ok: textOf$4(parsed["plugin"]) === "@dsh-workbench/core",
|
|
3907
4089
|
url: textOf$4(parsed["url"]),
|
|
3908
|
-
title: textOf$4(parsed["title"])
|
|
4090
|
+
title: textOf$4(parsed["title"]),
|
|
4091
|
+
where: textOf$4(parsed["where"]),
|
|
4092
|
+
board: textOf$4(parsed["board"]),
|
|
4093
|
+
open: typeof raw === "boolean" ? raw : null,
|
|
4094
|
+
shown: parsed["shown"] === true
|
|
3909
4095
|
};
|
|
3910
4096
|
}
|
|
3911
4097
|
async function writeShotsDir(shell, dir) {
|
|
@@ -3951,13 +4137,15 @@ async function measureCard(shell, command, session, unit, pick) {
|
|
|
3951
4137
|
if (parsed === void 0 || parsed["ok"] !== true) return {
|
|
3952
4138
|
...EMPTY_CARD,
|
|
3953
4139
|
cards: numberIn(parsed?.["cards"], 0),
|
|
3954
|
-
anchored: parsed?.["anchored"] === true
|
|
4140
|
+
anchored: parsed?.["anchored"] === true,
|
|
4141
|
+
visible: parsed?.["visible"] === true
|
|
3955
4142
|
};
|
|
3956
4143
|
const width = numberIn(parsed["width"], 0);
|
|
3957
4144
|
const height = numberIn(parsed["height"], 0);
|
|
3958
4145
|
return {
|
|
3959
4146
|
ok: true,
|
|
3960
4147
|
anchored: true,
|
|
4148
|
+
visible: parsed["visible"] === true,
|
|
3961
4149
|
width,
|
|
3962
4150
|
height,
|
|
3963
4151
|
head: textOf$4(parsed["head"]),
|
|
@@ -4036,6 +4224,35 @@ async function shootCard(shell, command, session, unit, file, view) {
|
|
|
4036
4224
|
}
|
|
4037
4225
|
//#endregion
|
|
4038
4226
|
//#region src/modules/panels/model/diy-page.ts
|
|
4227
|
+
function debugPausedText(held) {
|
|
4228
|
+
return `调试已暂停(${held.unit})—— 动作族关闸,不再拿屏当目标。要接着看先 workbench_diy_debug_resume(会再要用户点头一次);这之前可以改源码 / build / 跑门禁。`;
|
|
4229
|
+
}
|
|
4230
|
+
function debugForeignPactText(held) {
|
|
4231
|
+
return `另一场调试正占着那块屏(${held.sessionId} 在调试 ${held.unit})—— 一台机器同时只允许一场:让它先 workbench_diy_debug_stop,或等它收工。`;
|
|
4232
|
+
}
|
|
4233
|
+
function debugOffBoardText(held, situation = "other-board") {
|
|
4234
|
+
const what = situation === "off-workspace" ? "用户现在不在 DIY 工作区(外壳选中的是别的工作区)" : situation === "panel-closed" ? "工作台面板没画在屏上(右栏收着,或那一列让给了别的面板)" : "你现在这一页画的不是工坊那块板";
|
|
4235
|
+
const next = situation === "off-workspace" ? "让用户在左栏切回「工作台DIY」那个工作区" : situation === "panel-closed" ? "让用户把「工作台面板」切回来(或把右栏展开)" : "让用户把那一页切回「工作台DIY」";
|
|
4236
|
+
return `${what} —— 看 / 动 / 网络这一族现在发不出去,我不拿别的板当目标。${held.unit} 这场调试仍然**进行中**(我没有自动替你落 paused):${next};要停下来就自己 workbench_diy_debug_pause(不问审批),页面切回来了就接着看。`;
|
|
4237
|
+
}
|
|
4238
|
+
function boardProbeOf(page) {
|
|
4239
|
+
return {
|
|
4240
|
+
workbench: page.ok,
|
|
4241
|
+
where: page.where,
|
|
4242
|
+
bar: page.open !== null,
|
|
4243
|
+
board: page.board,
|
|
4244
|
+
open: page.open === true,
|
|
4245
|
+
drawn: page.shown
|
|
4246
|
+
};
|
|
4247
|
+
}
|
|
4248
|
+
function boardStateOf(page, workshop) {
|
|
4249
|
+
return boardFactOf(boardProbeOf(page), workshop);
|
|
4250
|
+
}
|
|
4251
|
+
function boardGateText(situation, unit, page) {
|
|
4252
|
+
if (situation === "off-workspace") return `用户现在不在 DIY 工作区 —— 外壳选中的是 ${page.where || "(问不出来是哪一块)"}。工坊那块板没在屏上,${unit} 的这张卡我看不到,也不拿别的板当目标。让用户在左栏切回「工作台DIY」;这之前我可以继续改源码 / build / 跑门禁。`;
|
|
4253
|
+
if (situation === "panel-closed") return `工作台面板没画在屏上(右栏收着,或者这一页让给了别的面板:文件预览、模块市场等)。让用户把「工作台面板」切回来(或把右栏展开),我再接着看 ${unit}。`;
|
|
4254
|
+
return `你现在这一页画的是 ${page.board || "(不知道哪一块)"} 的面板,工坊那块板没在这一屏 —— ${unit} 的这张卡不在屏上,我不拿别的板当目标。请用户在左栏切回「工作台DIY」;这之前我可以继续改源码 / build / 跑门禁。`;
|
|
4255
|
+
}
|
|
4039
4256
|
async function pageAt(ctx, exec, raw, options = {}) {
|
|
4040
4257
|
const { packagesDir } = workshopOf(ctx, exec);
|
|
4041
4258
|
const args = asRecord$3(raw);
|
|
@@ -4053,6 +4270,17 @@ async function pageAt(ctx, exec, raw, options = {}) {
|
|
|
4053
4270
|
const { page } = handshake;
|
|
4054
4271
|
throw new Error(`你现在这一页不是工作台(${page.title || "(没有标题)"} ${page.url})—— 把工作台那一页切到前台,再喊我一次。我只看用户正在看的那一页。`);
|
|
4055
4272
|
}
|
|
4273
|
+
const workshop = workshopPathOf(ctx);
|
|
4274
|
+
const board = boardStateOf(handshake.page, workshop);
|
|
4275
|
+
const situation = boardSituation(boardProbeOf(handshake.page), workshop);
|
|
4276
|
+
const held = ctx.get("workbenchDiyDebug")?.live(Date.now()) ?? null;
|
|
4277
|
+
const sessionId = sessionIdOf(exec);
|
|
4278
|
+
if (options.requirePact !== false && held !== null) {
|
|
4279
|
+
if (held.sessionId !== sessionId) throw new Error(debugForeignPactText(held));
|
|
4280
|
+
if (held.phase === "paused") throw new Error(debugPausedText(held));
|
|
4281
|
+
if (board === "other" || board === "hidden") throw new Error(debugOffBoardText(held, situation));
|
|
4282
|
+
}
|
|
4283
|
+
if (options.requireBoard !== false && (board === "other" || board === "hidden")) throw new Error(boardGateText(situation, wanted, handshake.page));
|
|
4056
4284
|
return {
|
|
4057
4285
|
packagesDir,
|
|
4058
4286
|
unit: wanted,
|
|
@@ -4060,10 +4288,155 @@ async function pageAt(ctx, exec, raw, options = {}) {
|
|
|
4060
4288
|
shell,
|
|
4061
4289
|
command,
|
|
4062
4290
|
session,
|
|
4063
|
-
bound: handshake.bound
|
|
4291
|
+
bound: handshake.bound,
|
|
4292
|
+
board,
|
|
4293
|
+
boardPath: handshake.page.board
|
|
4064
4294
|
};
|
|
4065
4295
|
}
|
|
4066
4296
|
//#endregion
|
|
4297
|
+
//#region src/modules/panels/model/diy-debug-tools.ts
|
|
4298
|
+
var EMPTY = {
|
|
4299
|
+
type: "object",
|
|
4300
|
+
properties: {},
|
|
4301
|
+
additionalProperties: false
|
|
4302
|
+
};
|
|
4303
|
+
function debugRefusalText(code, held) {
|
|
4304
|
+
switch (code) {
|
|
4305
|
+
case "held-by-other": return `另一场调试还占着那块屏(${held === void 0 ? "另一个会话" : held.sessionId})—— 一台机器同时只允许一场:让它先 workbench_diy_debug_stop,或等它收工。`;
|
|
4306
|
+
case "already-held": return `你这个会话已经持有一场调试(${held === void 0 ? "" : `${held.unit},${held.phase}`})—— 要换目标先 workbench_diy_debug_stop;暂停着要接着看用 workbench_diy_debug_resume。`;
|
|
4307
|
+
case "not-owner": return "这个调试态不是你这个会话的 —— 谁开始的谁收工。";
|
|
4308
|
+
case "none": return "现在没有调试态。";
|
|
4309
|
+
case "already-paused": return "已经暂停了 —— 要接着看用 workbench_diy_debug_resume(会再要用户点头)。";
|
|
4310
|
+
case "already-debugging": return "正在调试中,不用再开一次。";
|
|
4311
|
+
}
|
|
4312
|
+
}
|
|
4313
|
+
function renderDebugStart(state) {
|
|
4314
|
+
return [`开始调试 ${state.unit}(声明的目标:${state.board === "" ? "用户那一屏" : state.board})。`, "现在看 / 动 / 网络那一族才把屏当目标 —— 收工前记得 workbench_diy_debug_stop。"].join("\n");
|
|
4315
|
+
}
|
|
4316
|
+
function renderDebugPause(state) {
|
|
4317
|
+
return [`调试暂停了(${state.unit})—— 动作族关闸,不再拿屏当目标。`, "改源码 / build / 跑门禁照常;要看屏再 workbench_diy_debug_resume(会再要用户点头一次)。"].join("\n");
|
|
4318
|
+
}
|
|
4319
|
+
function renderDebugResume(state) {
|
|
4320
|
+
return [`继续调试 ${state.unit} —— 请用户回到「工作台DIY」那一屏。`, "卡不在屏上时我会当场拒(不拿别的板当目标)。"].join("\n");
|
|
4321
|
+
}
|
|
4322
|
+
function renderDebugStop(state) {
|
|
4323
|
+
return `收工了:${state.unit} 的调试态清掉了(占用解除)。`;
|
|
4324
|
+
}
|
|
4325
|
+
function moveOrThrow(move, held) {
|
|
4326
|
+
if (move.ok) return move.state;
|
|
4327
|
+
throw new Error(debugRefusalText(move.code, held ?? void 0));
|
|
4328
|
+
}
|
|
4329
|
+
function registerDebugTools(ctx, tools, store) {
|
|
4330
|
+
const startTool = {
|
|
4331
|
+
name: DIY_DEBUG_START_TOOL,
|
|
4332
|
+
description: "开始调试:占用用户那一屏(要点头一次)。声明 unit 之后,看 / 动那一族才把屏当目标。",
|
|
4333
|
+
parameters: withApprovalNote({
|
|
4334
|
+
type: "object",
|
|
4335
|
+
properties: { unit: {
|
|
4336
|
+
type: "string",
|
|
4337
|
+
description: "工坊里的 unit(workbench_diy_list 会给)。"
|
|
4338
|
+
} },
|
|
4339
|
+
required: ["unit"],
|
|
4340
|
+
additionalProperties: false
|
|
4341
|
+
}, { required: true }),
|
|
4342
|
+
output: OUTPUT$2,
|
|
4343
|
+
async execute(raw, exec) {
|
|
4344
|
+
const { packagesDir, workspace } = workshopOf(ctx, exec);
|
|
4345
|
+
const unit = asText$1(asRecord$3(raw)["unit"]);
|
|
4346
|
+
if (unit === "") {
|
|
4347
|
+
const { modules } = modulesOf(ctx, packagesDir);
|
|
4348
|
+
throw new Error(`要一个 unit(工坊里:${modules.map((one) => one.unit).join(", ") || "(空)"})`);
|
|
4349
|
+
}
|
|
4350
|
+
const held = store.live(Date.now());
|
|
4351
|
+
const page = await pageAt(ctx, exec, raw, {
|
|
4352
|
+
requireBoard: false,
|
|
4353
|
+
requirePact: false
|
|
4354
|
+
});
|
|
4355
|
+
const state = moveOrThrow(store.begin({
|
|
4356
|
+
sessionId: sessionIdOf(exec) ?? "",
|
|
4357
|
+
workspace: workspace ?? "",
|
|
4358
|
+
board: page.boardPath,
|
|
4359
|
+
unit,
|
|
4360
|
+
name: modulesOf(ctx, packagesDir).modules.find((one) => one.unit === unit)?.name ?? unit,
|
|
4361
|
+
now: Date.now()
|
|
4362
|
+
}), held);
|
|
4363
|
+
return plainJson({
|
|
4364
|
+
workshop: packagesDir,
|
|
4365
|
+
unit,
|
|
4366
|
+
board: state.board,
|
|
4367
|
+
phase: state.phase,
|
|
4368
|
+
state,
|
|
4369
|
+
text: renderDebugStart(state)
|
|
4370
|
+
});
|
|
4371
|
+
}
|
|
4372
|
+
};
|
|
4373
|
+
const pauseTool = {
|
|
4374
|
+
name: DIY_DEBUG_PAUSE_TOOL,
|
|
4375
|
+
description: "暂停调试(不审批):动作族关闸,不再拿屏当目标。要看屏再 debug_resume。",
|
|
4376
|
+
parameters: EMPTY,
|
|
4377
|
+
output: OUTPUT$2,
|
|
4378
|
+
async execute(_raw, exec) {
|
|
4379
|
+
const { packagesDir } = workshopOf(ctx, exec);
|
|
4380
|
+
const held = store.live(Date.now());
|
|
4381
|
+
const state = moveOrThrow(store.pause(sessionIdOf(exec) ?? "", Date.now()), held);
|
|
4382
|
+
return plainJson({
|
|
4383
|
+
workshop: packagesDir,
|
|
4384
|
+
unit: state.unit,
|
|
4385
|
+
phase: state.phase,
|
|
4386
|
+
state,
|
|
4387
|
+
text: renderDebugPause(state)
|
|
4388
|
+
});
|
|
4389
|
+
}
|
|
4390
|
+
};
|
|
4391
|
+
const resumeTool = {
|
|
4392
|
+
name: DIY_DEBUG_RESUME_TOOL,
|
|
4393
|
+
description: "继续调试(要点头一次):请用户回到「工作台DIY」那一屏。",
|
|
4394
|
+
parameters: withApprovalNote(EMPTY, { required: true }),
|
|
4395
|
+
output: OUTPUT$2,
|
|
4396
|
+
async execute(_raw, exec) {
|
|
4397
|
+
const { packagesDir } = workshopOf(ctx, exec);
|
|
4398
|
+
const held = store.live(Date.now());
|
|
4399
|
+
const page = await pageAt(ctx, exec, { unit: held?.unit ?? "" }, {
|
|
4400
|
+
requireBoard: false,
|
|
4401
|
+
requirePact: false,
|
|
4402
|
+
requireUnit: false
|
|
4403
|
+
});
|
|
4404
|
+
const state = moveOrThrow(store.resume(sessionIdOf(exec) ?? "", Date.now()), held);
|
|
4405
|
+
return plainJson({
|
|
4406
|
+
workshop: packagesDir,
|
|
4407
|
+
unit: state.unit,
|
|
4408
|
+
board: page.boardPath,
|
|
4409
|
+
phase: state.phase,
|
|
4410
|
+
state,
|
|
4411
|
+
text: renderDebugResume(state)
|
|
4412
|
+
});
|
|
4413
|
+
}
|
|
4414
|
+
};
|
|
4415
|
+
const stopTool = {
|
|
4416
|
+
name: DIY_DEBUG_STOP_TOOL,
|
|
4417
|
+
description: "结束调试(不审批):清掉\"占用用户那一屏\"这件事。收工用它。",
|
|
4418
|
+
parameters: EMPTY,
|
|
4419
|
+
output: OUTPUT$2,
|
|
4420
|
+
async execute(_raw, exec) {
|
|
4421
|
+
const { packagesDir } = workshopOf(ctx, exec);
|
|
4422
|
+
const held = store.live(Date.now());
|
|
4423
|
+
const state = moveOrThrow(store.stop(sessionIdOf(exec) ?? "", Date.now()), held);
|
|
4424
|
+
return plainJson({
|
|
4425
|
+
workshop: packagesDir,
|
|
4426
|
+
unit: state.unit,
|
|
4427
|
+
phase: "idle",
|
|
4428
|
+
text: renderDebugStop(state)
|
|
4429
|
+
});
|
|
4430
|
+
}
|
|
4431
|
+
};
|
|
4432
|
+
return [
|
|
4433
|
+
tools.register(startTool),
|
|
4434
|
+
tools.register(pauseTool),
|
|
4435
|
+
tools.register(resumeTool),
|
|
4436
|
+
tools.register(stopTool)
|
|
4437
|
+
];
|
|
4438
|
+
}
|
|
4439
|
+
//#endregion
|
|
4067
4440
|
//#region src/modules/panels/model/diy-browser-act.ts
|
|
4068
4441
|
var ACT_TIMEOUT_MS = 15e3;
|
|
4069
4442
|
function actTargetOf(raw) {
|
|
@@ -4180,12 +4553,11 @@ async function scrollIntoView(shell, command, session, unit, selector) {
|
|
|
4180
4553
|
async function reloadPage(shell, command, session) {
|
|
4181
4554
|
return actBrowser(shell, command, session, ["eval", `(() => { setTimeout(() => location.reload(), 30); return JSON.stringify({ ok: true }); })()`]);
|
|
4182
4555
|
}
|
|
4183
|
-
async function shootAtWidth(shell, command, session, file, width, height) {
|
|
4556
|
+
async function shootAtWidth(shell, command, session, file, width = 0, height = 0) {
|
|
4184
4557
|
const step = await actBrowser(shell, command, session, [
|
|
4185
4558
|
"screenshot",
|
|
4186
4559
|
file,
|
|
4187
|
-
"--width",
|
|
4188
|
-
String(width),
|
|
4560
|
+
...width > 0 ? ["--width", String(width)] : [],
|
|
4189
4561
|
...height > 0 ? ["--height", String(height)] : []
|
|
4190
4562
|
], LOOK_TIMEOUT_MS);
|
|
4191
4563
|
return {
|
|
@@ -4321,16 +4693,20 @@ function registerLookTools(ctx, tools) {
|
|
|
4321
4693
|
},
|
|
4322
4694
|
output: OUTPUT$2,
|
|
4323
4695
|
async execute(raw, exec) {
|
|
4324
|
-
const { packagesDir, unit, shell, command, session } = await pageAt(ctx, exec, raw);
|
|
4696
|
+
const { packagesDir, unit, shell, command, session, board } = await pageAt(ctx, exec, raw);
|
|
4325
4697
|
const pick = pickOf(asRecord$3(raw));
|
|
4326
4698
|
let view = await measureCard(shell, command, session, unit, pick);
|
|
4327
|
-
if (!view.ok)
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4699
|
+
if (!view.ok || !view.visible) {
|
|
4700
|
+
const state = view.ok ? "hidden" : board;
|
|
4701
|
+
return plainJson({
|
|
4702
|
+
workshop: packagesDir,
|
|
4703
|
+
unit,
|
|
4704
|
+
ok: false,
|
|
4705
|
+
board: state,
|
|
4706
|
+
cards: view.cards,
|
|
4707
|
+
text: renderMissingCard(unit, view, state)
|
|
4708
|
+
});
|
|
4709
|
+
}
|
|
4334
4710
|
if (!insideViewportOf(view)) {
|
|
4335
4711
|
await scrollIntoView(shell, command, session, unit, "");
|
|
4336
4712
|
view = await measureCard(shell, command, session, unit, pick);
|
|
@@ -4431,9 +4807,12 @@ function renderLook(unit, view, shot, pick) {
|
|
|
4431
4807
|
...view.clipped ? ["有内容被裁掉了(某一格比它自己的宽度还宽)—— 这是要改的信号"] : []
|
|
4432
4808
|
].join("\n");
|
|
4433
4809
|
}
|
|
4434
|
-
function renderMissingCard(unit,
|
|
4435
|
-
if (
|
|
4436
|
-
|
|
4810
|
+
function renderMissingCard(unit, view, board) {
|
|
4811
|
+
if (board === "other") return `你现在这一页画的是别的工作区的面板,工坊那块板没在这一屏 —— ${unit} 的卡不在屏上,我不拿别的板当目标。请用户在左栏切回「工作台DIY」,或把这张卡上到他正看着的那块板上。`;
|
|
4812
|
+
if (board === "hidden") return `右栏收着 —— 面板没画在屏上(锚点还在页面里,但看不见它),量不到也不该拍 ${unit}。让用户把面板展开、或切回「工作台DIY」,我再接着看。`;
|
|
4813
|
+
if (view.anchored) return `面板里给 ${unit} 留了位置(锚点在),但里面没有卡片 —— 它的 View 没画出来:要么渲染时抛了(看 workbench_diy_panel 的运行态上报与 workbench_diy_status),要么它返回了空 / 没套卡壳。你现在这一页面板里一共 ${String(view.cards)} 张卡。`;
|
|
4814
|
+
const stale = board === "unknown" ? "③ 页面上跑的外壳可能还是旧的一份(锚点由外壳盖)—— 让用户刷新一次页面。" : "";
|
|
4815
|
+
return `你现在这一页的面板里没有 ${unit} 这张卡(面板里现在有 ${String(view.cards)} 张卡)。按顺序试:① workbench_diy_show(unit=${unit})把它上板;② 右栏可能没停在「工作台面板」那一列 —— 让用户切回来。${stale}`;
|
|
4437
4816
|
}
|
|
4438
4817
|
//#endregion
|
|
4439
4818
|
//#region src/modules/panels/model/diy-logs.ts
|
|
@@ -5089,24 +5468,26 @@ function registerActTools(ctx, tools) {
|
|
|
5089
5468
|
};
|
|
5090
5469
|
const viewportTool = {
|
|
5091
5470
|
name: DIY_VIEWPORT_TOOL,
|
|
5092
|
-
description: "
|
|
5471
|
+
description: "拍整屏图。不给宽高 = 按用户当前窗口拍;给了才换视口 —— 会回流一次。",
|
|
5093
5472
|
parameters: pageSchema({
|
|
5094
5473
|
width: {
|
|
5095
5474
|
type: "number",
|
|
5096
|
-
description: "视口宽度(CSS px
|
|
5475
|
+
description: "视口宽度(CSS px,如 390);不填按当前窗口。"
|
|
5097
5476
|
},
|
|
5098
5477
|
height: {
|
|
5099
5478
|
type: "number",
|
|
5100
5479
|
description: "视口高度(可不要)。"
|
|
5101
5480
|
}
|
|
5102
|
-
}, [
|
|
5481
|
+
}, []),
|
|
5103
5482
|
output: OUTPUT$2,
|
|
5104
5483
|
async execute(raw, exec) {
|
|
5105
5484
|
const page = await pageAt(ctx, exec, raw, { requireUnit: false });
|
|
5106
|
-
const width = asNumber(page.args["width"]);
|
|
5107
|
-
if (width
|
|
5485
|
+
const width = asNumber(page.args["width"]) ?? 0;
|
|
5486
|
+
if (width < 0) throw new Error("width 得是正的 CSS px;不给就按用户当前窗口拍。");
|
|
5108
5487
|
const height = asNumber(page.args["height"]) ?? 0;
|
|
5109
|
-
const
|
|
5488
|
+
const overrode = width > 0 || height > 0;
|
|
5489
|
+
const stamp = overrode ? `${String(width)}x${String(height)}` : "now";
|
|
5490
|
+
const file = join(dirname(page.packagesDir), "shots", `${page.unit || "page"}-${stamp}-${String(Date.now())}.png`);
|
|
5110
5491
|
await writeShotsDir(page.shell, dirname(file));
|
|
5111
5492
|
const shot = await shootAtWidth(page.shell, page.command, page.session, file, width, height);
|
|
5112
5493
|
return plainJson({
|
|
@@ -5114,12 +5495,13 @@ function registerActTools(ctx, tools) {
|
|
|
5114
5495
|
unit: page.unit,
|
|
5115
5496
|
ok: shot.ok,
|
|
5116
5497
|
file: shot.file,
|
|
5117
|
-
|
|
5118
|
-
|
|
5498
|
+
overrode,
|
|
5499
|
+
width: overrode ? width : null,
|
|
5500
|
+
viewport: overrode ? {
|
|
5119
5501
|
width,
|
|
5120
5502
|
height
|
|
5121
|
-
},
|
|
5122
|
-
text: shot.ok ?
|
|
5503
|
+
} : null,
|
|
5504
|
+
text: shot.ok ? overrode ? `重拍了一张:${shot.file}(临时换了视口${width > 0 ? ` 宽 ${String(width)}px` : ""}${height > 0 ? ` 高 ${String(height)}px` : ""},你那一屏会回流一次、拍完就恢复)。` : `按你当前窗口拍了一张:${shot.file}(没动你的视口)。` : `没拍成:${shot.reason}`
|
|
5123
5505
|
});
|
|
5124
5506
|
}
|
|
5125
5507
|
};
|
|
@@ -5483,7 +5865,7 @@ function renderList(packagesDir, modules) {
|
|
|
5483
5865
|
}
|
|
5484
5866
|
//#endregion
|
|
5485
5867
|
//#region src/modules/panels/model/diy-tools.ts
|
|
5486
|
-
function registerDiyTools(ctx, market, panels) {
|
|
5868
|
+
function registerDiyTools(ctx, market, panels, debug) {
|
|
5487
5869
|
const tools = ctx.get("tools");
|
|
5488
5870
|
if (tools === void 0) {
|
|
5489
5871
|
ctx.logger?.info?.("[dsh-workbench] 没有 tools 服务,跳过 DIY 工坊工具注册");
|
|
@@ -5831,11 +6213,20 @@ function registerDiyTools(ctx, market, panels) {
|
|
|
5831
6213
|
...registerLogTools(ctx, tools),
|
|
5832
6214
|
...registerNetTools(ctx, tools),
|
|
5833
6215
|
...registerActTools(ctx, tools),
|
|
6216
|
+
...registerDebugTools(ctx, tools, debug),
|
|
5834
6217
|
tools.register(showTool),
|
|
5835
6218
|
tools.register(installTool)
|
|
5836
6219
|
];
|
|
5837
6220
|
}
|
|
5838
6221
|
//#endregion
|
|
6222
|
+
//#region src/modules/panels/model/diy-debug-routes.ts
|
|
6223
|
+
function diyDebugRoutes(store) {
|
|
6224
|
+
return { "panels/diy-debug": () => ({
|
|
6225
|
+
ok: true,
|
|
6226
|
+
state: store.live(Date.now())
|
|
6227
|
+
}) };
|
|
6228
|
+
}
|
|
6229
|
+
//#endregion
|
|
5839
6230
|
//#region src/shared/api/host/release.ts
|
|
5840
6231
|
function parseLedgerVersion(stdout, name) {
|
|
5841
6232
|
const parsed = parseJsonLoose(stdout);
|
|
@@ -7869,7 +8260,14 @@ function applyPanelsPref(panels, payload) {
|
|
|
7869
8260
|
//#endregion
|
|
7870
8261
|
//#region src/modules/panels/model/handoff.ts
|
|
7871
8262
|
var PANELS_FACT = "panels";
|
|
8263
|
+
var DIY_DEBUG_FACT = "diy-debug";
|
|
7872
8264
|
var CAPABILITY_FACT = "capability";
|
|
8265
|
+
var DEBUG_TOOLS = [
|
|
8266
|
+
DIY_DEBUG_START_TOOL,
|
|
8267
|
+
DIY_DEBUG_PAUSE_TOOL,
|
|
8268
|
+
DIY_DEBUG_RESUME_TOOL,
|
|
8269
|
+
DIY_DEBUG_STOP_TOOL
|
|
8270
|
+
];
|
|
7873
8271
|
var PROVISION_TOOLS = {
|
|
7874
8272
|
[MODULES_INSTALL_TOOL]: "install",
|
|
7875
8273
|
[MODULES_UPDATE_TOOL]: "update",
|
|
@@ -7905,6 +8303,7 @@ function panelsFactsOf(call, manifests) {
|
|
|
7905
8303
|
if (call.source === "workbench_modules_list") return [PANELS_FACT, CAPABILITY_FACT];
|
|
7906
8304
|
if (call.source === "workbench_modules_update_workbench") return [PANELS_FACT, CAPABILITY_FACT];
|
|
7907
8305
|
if (call.source === "workbench_diy_list") return [PANELS_FACT];
|
|
8306
|
+
if (DEBUG_TOOLS.includes(call.source)) return [DIY_DEBUG_FACT];
|
|
7908
8307
|
const request = requestOf(call);
|
|
7909
8308
|
if (request === void 0) return void 0;
|
|
7910
8309
|
return [
|
|
@@ -8479,6 +8878,8 @@ var OWNED = [{
|
|
|
8479
8878
|
logger
|
|
8480
8879
|
});
|
|
8481
8880
|
ctx.provide(PANELS_SERVICE, panels);
|
|
8881
|
+
const debug = createDebugStore();
|
|
8882
|
+
ctx.provide(DIY_DEBUG_SERVICE, debug);
|
|
8482
8883
|
const profileDir = profileDirOf(ctx);
|
|
8483
8884
|
const shell = ctx.get("shell");
|
|
8484
8885
|
const moduleManifests = () => {
|
|
@@ -8526,12 +8927,13 @@ var OWNED = [{
|
|
|
8526
8927
|
...pluginRoutes({
|
|
8527
8928
|
ledger,
|
|
8528
8929
|
...shell === void 0 ? {} : { shell }
|
|
8529
|
-
})
|
|
8930
|
+
}),
|
|
8931
|
+
...diyDebugRoutes(debug)
|
|
8530
8932
|
},
|
|
8531
8933
|
registerTools: () => [
|
|
8532
8934
|
...registerPanelTools(ctx, panels, values),
|
|
8533
8935
|
...registerMarketTools(ctx, market),
|
|
8534
|
-
...registerDiyTools(ctx, market, panels)
|
|
8936
|
+
...registerDiyTools(ctx, market, panels, debug)
|
|
8535
8937
|
],
|
|
8536
8938
|
factsOf: (call) => panelsFactsOf(call, manifests()),
|
|
8537
8939
|
needsApproval: panelsApproval,
|
|
@@ -8542,7 +8944,7 @@ var OWNED = [{
|
|
|
8542
8944
|
return [...manifests().flatMap((manifest) => owned.has(manifest.id) || resolveScope({
|
|
8543
8945
|
id: manifest.id,
|
|
8544
8946
|
boards
|
|
8545
|
-
}) ? [] : manifest.tools.map((tool) => tool.name)), ...inWorkshopSession(ctx, workspace) ? [] : [...DIY_TOOLS]];
|
|
8947
|
+
}) ? [] : manifest.tools.map((tool) => tool.name)), ...inWorkshopSession(ctx, workspace) ? [] : [...DIY_TOOLS, ...DIY_DEBUG_TOOLS]];
|
|
8546
8948
|
},
|
|
8547
8949
|
subscribe: (listener) => panels.subscribe(listener)
|
|
8548
8950
|
},
|
|
@@ -8875,6 +9277,122 @@ function createPostChannels(deps) {
|
|
|
8875
9277
|
};
|
|
8876
9278
|
}
|
|
8877
9279
|
//#endregion
|
|
9280
|
+
//#region src/shared/api/host/diy-debug-act.ts
|
|
9281
|
+
var DEBUG_NOTICE_KIND = "workbench-diy";
|
|
9282
|
+
var INTENT_WORD = {
|
|
9283
|
+
pause: "暂停",
|
|
9284
|
+
resume: "继续",
|
|
9285
|
+
stop: "结束"
|
|
9286
|
+
};
|
|
9287
|
+
function debugNoticeText(intent, state) {
|
|
9288
|
+
const head = `[工作台 DIY]用户按了「${INTENT_WORD[intent]}」:`;
|
|
9289
|
+
if (intent === "pause") return `${head}${state.unit} 这场调试暂停了 —— 现在别再把那一屏当目标(看 / 动 / 网络那一族发不出去)。要接着看屏就等用户按「继续」;在那之前照常改源码 / build / 跑门禁。`;
|
|
9290
|
+
if (intent === "resume") return `${head}${state.unit} 这场调试重新开始了 —— 那一屏又归你看。屏 / 板不对的话照旧会被拒,拒了就照实说清是哪种不对。`;
|
|
9291
|
+
return `${head}${state.unit} 这场调试收工了(占用解除)。要再调试就重新 start 一场。`;
|
|
9292
|
+
}
|
|
9293
|
+
function debugNoticeSummary(intent, state) {
|
|
9294
|
+
return `工作台 DIY:用户按了${INTENT_WORD[intent]}(${state.unit})`;
|
|
9295
|
+
}
|
|
9296
|
+
function debugNotice(intent, state) {
|
|
9297
|
+
const summary = debugNoticeSummary(intent, state);
|
|
9298
|
+
return {
|
|
9299
|
+
summary,
|
|
9300
|
+
message: {
|
|
9301
|
+
role: "user",
|
|
9302
|
+
id: randomUUID(),
|
|
9303
|
+
content: [{
|
|
9304
|
+
type: "text",
|
|
9305
|
+
text: debugNoticeText(intent, state)
|
|
9306
|
+
}],
|
|
9307
|
+
source: {
|
|
9308
|
+
kind: DEBUG_NOTICE_KIND,
|
|
9309
|
+
form: "notice",
|
|
9310
|
+
summary
|
|
9311
|
+
}
|
|
9312
|
+
}
|
|
9313
|
+
};
|
|
9314
|
+
}
|
|
9315
|
+
var NOTICE_MODE = {
|
|
9316
|
+
resume: "wake",
|
|
9317
|
+
pause: "hold",
|
|
9318
|
+
stop: "drop"
|
|
9319
|
+
};
|
|
9320
|
+
var held = /* @__PURE__ */ new Map();
|
|
9321
|
+
function holdNotice(sessionId, message) {
|
|
9322
|
+
const list = held.get(sessionId);
|
|
9323
|
+
if (list === void 0) held.set(sessionId, [message]);
|
|
9324
|
+
else list.push(message);
|
|
9325
|
+
}
|
|
9326
|
+
function takeHeldNotices(sessionId) {
|
|
9327
|
+
const list = held.get(sessionId) ?? [];
|
|
9328
|
+
held.delete(sessionId);
|
|
9329
|
+
return list;
|
|
9330
|
+
}
|
|
9331
|
+
function deliverDebugNotice(agents, sessionId, message, mode = "wake") {
|
|
9332
|
+
const agent = agents?.get(sessionId);
|
|
9333
|
+
if (agent === void 0) {
|
|
9334
|
+
if (mode === "drop") return "none";
|
|
9335
|
+
holdNotice(sessionId, message);
|
|
9336
|
+
return "held";
|
|
9337
|
+
}
|
|
9338
|
+
if (agent.status !== "idle") {
|
|
9339
|
+
agent.inject(message);
|
|
9340
|
+
return "inject";
|
|
9341
|
+
}
|
|
9342
|
+
if (mode === "wake") {
|
|
9343
|
+
agent.followup(message);
|
|
9344
|
+
return "followup";
|
|
9345
|
+
}
|
|
9346
|
+
if (mode === "hold") {
|
|
9347
|
+
holdNotice(sessionId, message);
|
|
9348
|
+
return "held";
|
|
9349
|
+
}
|
|
9350
|
+
return "skipped-idle";
|
|
9351
|
+
}
|
|
9352
|
+
var REFUSAL = {
|
|
9353
|
+
"already-paused": "这一场已经是暂停态了",
|
|
9354
|
+
"already-debugging": "这一场本来就在调试中",
|
|
9355
|
+
none: "现在没有调试态",
|
|
9356
|
+
"not-owner": "这场调试不是这个会话的"
|
|
9357
|
+
};
|
|
9358
|
+
function debugActResource(deps) {
|
|
9359
|
+
const now = () => deps.now?.() ?? Date.now();
|
|
9360
|
+
return {
|
|
9361
|
+
resource: "act",
|
|
9362
|
+
handle(payload) {
|
|
9363
|
+
const intent = parseDebugIntent(payload?.intent);
|
|
9364
|
+
if (intent === null) return {
|
|
9365
|
+
ok: false,
|
|
9366
|
+
text: "不认识的意图(只认 pause / resume / stop)"
|
|
9367
|
+
};
|
|
9368
|
+
const store = deps.store();
|
|
9369
|
+
if (store === void 0) return {
|
|
9370
|
+
ok: false,
|
|
9371
|
+
text: "现在没有调试态 —— 没什么可暂停 / 继续 / 结束的"
|
|
9372
|
+
};
|
|
9373
|
+
const at = now();
|
|
9374
|
+
const held = store.live(at);
|
|
9375
|
+
if (held === null) return {
|
|
9376
|
+
ok: false,
|
|
9377
|
+
text: "现在没有调试态 —— 没什么可暂停 / 继续 / 结束的"
|
|
9378
|
+
};
|
|
9379
|
+
const move = intent === "pause" ? store.pause(held.sessionId, at) : intent === "resume" ? store.resume(held.sessionId, at) : store.stop(held.sessionId, at);
|
|
9380
|
+
if (!move.ok) return {
|
|
9381
|
+
ok: false,
|
|
9382
|
+
text: REFUSAL[move.code] ?? `按不动:${move.code}`
|
|
9383
|
+
};
|
|
9384
|
+
const notice = deps.notice?.(intent, move.state) ?? debugNotice(intent, move.state);
|
|
9385
|
+
return {
|
|
9386
|
+
ok: true,
|
|
9387
|
+
intent,
|
|
9388
|
+
delivered: deliverDebugNotice(deps.agents(), held.sessionId, notice.message, NOTICE_MODE[intent]),
|
|
9389
|
+
summary: notice.summary,
|
|
9390
|
+
state: store.live(now())
|
|
9391
|
+
};
|
|
9392
|
+
}
|
|
9393
|
+
};
|
|
9394
|
+
}
|
|
9395
|
+
//#endregion
|
|
8878
9396
|
//#region src/shared/api/host/events.ts
|
|
8879
9397
|
var HEARTBEAT_MS = 25e3;
|
|
8880
9398
|
function frame(payload) {
|
|
@@ -11004,15 +11522,17 @@ function createToolScope(options) {
|
|
|
11004
11522
|
};
|
|
11005
11523
|
}
|
|
11006
11524
|
//#endregion
|
|
11007
|
-
//#region src/
|
|
11008
|
-
var name = "dsh-workbench";
|
|
11009
|
-
var inject = ["webServer"];
|
|
11525
|
+
//#region src/shared/api/host/host-args.ts
|
|
11010
11526
|
function asArgs(value) {
|
|
11011
11527
|
return typeof value === "object" && value !== null ? value : {};
|
|
11012
11528
|
}
|
|
11013
11529
|
function warn(ctx, message) {
|
|
11014
11530
|
ctx.logger?.warn?.(`[dsh-workbench] ${message}`);
|
|
11015
11531
|
}
|
|
11532
|
+
//#endregion
|
|
11533
|
+
//#region src/app/host.ts
|
|
11534
|
+
var name = "dsh-workbench";
|
|
11535
|
+
var inject = ["webServer"];
|
|
11016
11536
|
function seedWorkbenchRuntime(ctx) {
|
|
11017
11537
|
const root = runtimeSeedRootOf(ctx);
|
|
11018
11538
|
if (root === null) return;
|
|
@@ -11384,9 +11904,10 @@ function apply(ctx) {
|
|
|
11384
11904
|
if (decision.kind === "reject") return decision;
|
|
11385
11905
|
try {
|
|
11386
11906
|
const message = await injector.inject(decision.messages ?? [], payload?.agent);
|
|
11387
|
-
|
|
11907
|
+
const extra = [...takeHeldNotices(String((payload?.agent)?.id ?? "")), ...message === void 0 ? [] : [message]];
|
|
11908
|
+
return extra.length === 0 ? decision : {
|
|
11388
11909
|
...decision,
|
|
11389
|
-
messages: [...decision.messages ?? [],
|
|
11910
|
+
messages: [...decision.messages ?? [], ...extra]
|
|
11390
11911
|
};
|
|
11391
11912
|
} catch (error) {
|
|
11392
11913
|
ctx.logger?.warn?.(`[dsh-workbench] 对话引用注入失败:${String(error)}`);
|
|
@@ -11397,6 +11918,12 @@ function apply(ctx) {
|
|
|
11397
11918
|
}, `${PLUGIN_ID}: 对话引用注入`);
|
|
11398
11919
|
ctx.effect(() => registerFactStream(ctx, facts), `${PLUGIN_ID}: 变更流`);
|
|
11399
11920
|
ctx.effect(() => registerPanelState(ctx, panelState), `${PLUGIN_ID}: 面板运行态上报(浏览器半侧报自己的取数与渲染收尾)`);
|
|
11921
|
+
ctx.effect(() => {
|
|
11922
|
+
return registerDiyDebugAct(ctx, debugActResource({
|
|
11923
|
+
store: () => ctx.get(DIY_DEBUG_SERVICE),
|
|
11924
|
+
agents: () => ctx.get("agents")
|
|
11925
|
+
}), { bump: (names) => facts.bump(names) });
|
|
11926
|
+
}, `${PLUGIN_ID}: DIY 调试的三个键(用户按的)`);
|
|
11400
11927
|
ctx.effect(() => registerApi(ctx, routes), `${PLUGIN_ID}: HTTP 投影`);
|
|
11401
11928
|
}
|
|
11402
11929
|
//#endregion
|