@sanqianx/claude-ai-workbench 0.13.2 → 0.13.4

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.
Files changed (122) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +156 -156
  3. package/apps/agent-terminal/app.css +652 -613
  4. package/apps/agent-terminal/app.js +143 -67
  5. package/apps/agent-terminal/conversation-composer.js +44 -0
  6. package/apps/agent-terminal/index.html +172 -170
  7. package/apps/agent-terminal/panel-host-proof.html +152 -152
  8. package/apps/agent-terminal/panel-proof-content.html +41 -41
  9. package/apps/agent-terminal/right-workspace-dock.css +189 -159
  10. package/apps/agent-terminal/right-workspace-dock.js +652 -521
  11. package/apps/agent-terminal/user-question-card.js +68 -0
  12. package/apps/ai-profile-settings-host/index.html +25 -25
  13. package/apps/ai-profile-settings-host/page.css +1 -1
  14. package/apps/ai-profile-settings-host/page.js +113 -113
  15. package/apps/minimal-test-host/README.md +15 -15
  16. package/apps/minimal-test-host/host.css +2 -2
  17. package/apps/minimal-test-host/host.js +35 -35
  18. package/apps/minimal-test-host/index.html +58 -58
  19. package/apps/minimal-test-host/optional-mock/fault-injection.js +15 -15
  20. package/docs/sdk/FILE_LAYOUT.md +31 -31
  21. package/docs/sdk/INTEGRATION.md +126 -126
  22. package/docs/sdk/README.md +21 -21
  23. package/docs/sdk/SESSION_EVENTS.md +15 -13
  24. package/docs/sdk/openapi.yaml +16 -1
  25. package/package.json +1 -1
  26. package/packages/client/README.md +29 -29
  27. package/packages/client/index.d.ts +122 -122
  28. package/packages/client/index.js +260 -260
  29. package/packages/client/package.json +2 -2
  30. package/packages/contracts/README.md +9 -9
  31. package/packages/contracts/index.d.ts +519 -517
  32. package/packages/contracts/index.js +312 -312
  33. package/packages/contracts/package.json +1 -1
  34. package/packages/core/README.md +8 -8
  35. package/packages/core/index.d.ts +76 -76
  36. package/packages/core/index.js +222 -222
  37. package/packages/core/package.json +2 -2
  38. package/packages/server/README.md +17 -17
  39. package/packages/server/bin/agent-terminal-server.js +42 -42
  40. package/packages/server/bin/claude-workbench.js +225 -225
  41. package/packages/server/index.d.ts +171 -171
  42. package/packages/server/index.js +230 -230
  43. package/packages/server/lib/agent-discovery.js +133 -133
  44. package/packages/server/lib/agent-registry.js +143 -143
  45. package/packages/server/lib/agent-spawn-env.js +17 -17
  46. package/packages/server/lib/attachment-store.js +78 -78
  47. package/packages/server/lib/bridges/app-server-bridge.js +373 -373
  48. package/packages/server/lib/bridges/opencode-server-bridge.js +506 -506
  49. package/packages/server/lib/capture-settings-store.js +35 -35
  50. package/packages/server/lib/claude-history-recovery.js +87 -87
  51. package/packages/server/lib/cli-session-recovery.js +28 -28
  52. package/packages/server/lib/context-resolver.js +55 -55
  53. package/packages/server/lib/conversation-capture.js +51 -51
  54. package/packages/server/lib/delegation-phase-store.js +357 -357
  55. package/packages/server/lib/delegation-store.js +474 -468
  56. package/packages/server/lib/diagnostics.js +32 -32
  57. package/packages/server/lib/drivers/cli-json-runner.js +974 -974
  58. package/packages/server/lib/drivers/codex-driver.js +1461 -1442
  59. package/packages/server/lib/drivers/opencode-driver.js +1554 -1554
  60. package/packages/server/lib/drivers/zcode-driver.js +1250 -1250
  61. package/packages/server/lib/drivers/zcode-profile-runtime.js +71 -71
  62. package/packages/server/lib/event-stream.js +138 -138
  63. package/packages/server/lib/folder-picker.js +623 -623
  64. package/packages/server/lib/http-handler.js +339 -339
  65. package/packages/server/lib/json-file.js +26 -26
  66. package/packages/server/lib/knowledge-context.js +33 -33
  67. package/packages/server/lib/model-detection.js +295 -295
  68. package/packages/server/lib/parent-context.js +44 -0
  69. package/packages/server/lib/profile-store.js +283 -283
  70. package/packages/server/lib/project-store.js +102 -102
  71. package/packages/server/lib/runtime-loader.js +120 -120
  72. package/packages/server/lib/session-archive-store.js +53 -53
  73. package/packages/server/lib/session-history.js +612 -612
  74. package/packages/server/lib/system-doctor.js +125 -125
  75. package/packages/server/lib/ui-preferences-store.js +48 -48
  76. package/packages/server/lib/user-questions.js +67 -0
  77. package/packages/server/lib/workbench-service.js +1696 -1675
  78. package/packages/server/package.json +2 -2
  79. package/packages/ui/README.md +30 -30
  80. package/packages/ui/ai-profile-settings.d.ts +45 -45
  81. package/packages/ui/ai-profile-settings.js +283 -283
  82. package/packages/ui/claude-terminal.d.ts +31 -31
  83. package/packages/ui/claude-terminal.js +343 -343
  84. package/packages/ui/index.d.ts +18 -18
  85. package/packages/ui/index.js +51 -51
  86. package/packages/ui/package.json +2 -2
  87. package/packages/ui/theme.css +13 -13
  88. package/src/assets/claude-prompts.json +21 -21
  89. package/src/backend/http/ai-profile-routes.js +61 -61
  90. package/src/backend/http/claude-routes.js +170 -170
  91. package/src/backend/http/node-helpers.js +45 -45
  92. package/src/backend/index.js +21 -21
  93. package/src/backend/lib/ai-adapter.js +144 -144
  94. package/src/backend/lib/ai-profile-store.js +259 -259
  95. package/src/backend/lib/ai-vendor-presets.js +83 -83
  96. package/src/backend/lib/ai-workspace.js +140 -140
  97. package/src/backend/lib/automation-config.js +253 -253
  98. package/src/backend/lib/claude-cli-runner.js +2408 -2392
  99. package/src/backend/lib/data-dir.js +169 -169
  100. package/src/backend/lib/llm-client.js +176 -176
  101. package/src/backend/lib/model-context-windows.js +82 -82
  102. package/src/backend/lib/native-task-control.js +217 -217
  103. package/src/backend/lib/native-task-history-index.js +475 -475
  104. package/src/backend/lib/native-task-history-reader.js +526 -526
  105. package/src/backend/lib/native-task-messages.js +457 -457
  106. package/src/backend/lib/native-task-registry.js +325 -325
  107. package/src/backend/lib/native-task-runtime.js +242 -242
  108. package/src/backend/lib/native-task-trace.js +440 -440
  109. package/src/backend/lib/native-task-transcript.js +393 -393
  110. package/src/backend/lib/prompt-registry.js +166 -166
  111. package/src/backend/lib/runtime-config.js +121 -121
  112. package/src/backend/lib/sdk-session-stream.js +143 -143
  113. package/src/backend/lib/sdk-turn-stream.js +16 -16
  114. package/src/backend/lib/store-scope.js +131 -131
  115. package/src/backend/lib/task-identity.js +104 -104
  116. package/src/backend/lib/task-state-projection.js +58 -58
  117. package/src/index.js +7 -7
  118. package/src/sdk-wave-a.ts +1 -1
  119. package/src/sdk-wave-b.ts +1 -1
  120. package/src/sdk-wave-c.ts +1 -1
  121. package/src/sdk-wave-d.ts +1 -1
  122. package/src/sdk-wave-e.ts +1 -1
@@ -1,152 +1,152 @@
1
- <!DOCTYPE html>
2
- <html lang="zh-CN">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <title>W3 Panel Host Proof(最小可信宿主)</title>
7
- <style>
8
- :root { color-scheme: dark; }
9
- body { margin: 0; font: 13px/1.5 system-ui, sans-serif; background: #101016; color: #e8e8ee; display: flex; flex-direction: column; height: 100vh; }
10
- header { padding: 8px 12px; border-bottom: 1px solid #2a2a33; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
11
- header h1 { font-size: 14px; margin: 0 12px 0 0; }
12
- header .note { color: #9a9aa5; font-size: 11px; }
13
- button { font: inherit; padding: 3px 10px; border: 1px solid #2a2a33; border-radius: 6px; background: #1a1a22; color: inherit; cursor: pointer; }
14
- button:disabled { opacity: 0.45; cursor: not-allowed; }
15
- main { flex: 1; display: flex; min-height: 0; }
16
- #terminal-frame { flex: 1 1 62%; border: none; background: #14141a; }
17
- aside { flex: 0 0 38%; border-left: 1px solid #2a2a33; display: flex; flex-direction: column; min-width: 0; }
18
- .state-head { padding: 6px 10px; border-bottom: 1px solid #2a2a33; display: flex; gap: 8px; align-items: baseline; }
19
- .state-head strong { font-size: 12px; }
20
- #panel-status { font-size: 11px; color: #9a9aa5; }
21
- #state-log { flex: 1; overflow-y: auto; margin: 0; padding: 6px 10px; font: 11px/1.6 ui-monospace, monospace; white-space: pre-wrap; word-break: break-all; }
22
- #state-log .line { display: block; border-bottom: 1px dashed #22222b; padding: 2px 0; }
23
- #state-log .dir-host { color: #7fa3e8; }
24
- #state-log .dir-app { color: #2e9e5b; }
25
- #state-log .dir-err { color: #d64545; }
26
- </style>
27
- </head>
28
- <body>
29
- <header>
30
- <h1>W3 Panel Host Proof</h1>
31
- <span class="note">同源最小宿主:以 embed 模式加载真实 Agent Terminal,注册同源 knowledge iframe 面板。独立 Workbench 不依赖本页代码。</span>
32
- </header>
33
- <header>
34
- <button id="btn-register" disabled>注册知识面板</button>
35
- <button id="btn-unregister" disabled>注销</button>
36
- <button id="btn-open-1" disabled>打开一个</button>
37
- <button id="btn-open-2" disabled>打开第二个</button>
38
- <button id="btn-close-last" disabled>关闭最后一个</button>
39
- <button id="btn-activate-first" disabled>切换激活到第一个</button>
40
- </header>
41
- <main>
42
- <iframe id="terminal-frame" title="Agent Terminal(embed)" src="/agent-terminal/?embed=1"></iframe>
43
- <aside>
44
- <div class="state-head"><strong>panel state 事件日志</strong><span id="panel-status">等待 kb:ready…</span></div>
45
- <pre id="state-log"></pre>
46
- </aside>
47
- </main>
48
- <script>
49
- (function () {
50
- 'use strict';
51
- var frame = document.getElementById('terminal-frame');
52
- var log = document.getElementById('state-log');
53
- var status = document.getElementById('panel-status');
54
- var buttons = {
55
- register: document.getElementById('btn-register'),
56
- unregister: document.getElementById('btn-unregister'),
57
- open1: document.getElementById('btn-open-1'),
58
- open2: document.getElementById('btn-open-2'),
59
- closeLast: document.getElementById('btn-close-last'),
60
- activateFirst: document.getElementById('btn-activate-first'),
61
- };
62
- var ORIGIN = window.location.origin;
63
- var PROVIDER_ID = 'kb.proof.knowledge';
64
- var ready = false;
65
- var registered = false;
66
- var panels = [];
67
- var requestSeq = 0;
68
-
69
- function line(text, dir) {
70
- var entry = document.createElement('span');
71
- entry.className = 'line ' + (dir === 'host' ? 'dir-host' : dir === 'app' ? 'dir-app' : 'dir-err');
72
- entry.textContent = new Date().toISOString().slice(11, 23) + ' ' + text;
73
- log.append(entry);
74
- log.scrollTop = log.scrollHeight;
75
- }
76
-
77
- function send(message) {
78
- if (!ready) { line('宿主 → 终端:忽略(终端未 ready)', 'err'); return; }
79
- message.requestId = 'proof-' + (++requestSeq);
80
- frame.contentWindow.postMessage(message, ORIGIN);
81
- line('宿主 → 终端 ' + message.type + ' ' + JSON.stringify(message), 'host');
82
- }
83
-
84
- function refreshButtons() {
85
- var knowledgeOpen = panels.filter(function (p) { return p.providerId === PROVIDER_ID; });
86
- buttons.register.disabled = !ready || registered;
87
- buttons.unregister.disabled = !ready || !registered;
88
- buttons.open1.disabled = !ready || !registered;
89
- buttons.open2.disabled = !ready || !registered;
90
- buttons.closeLast.disabled = knowledgeOpen.length === 0;
91
- buttons.activateFirst.disabled = knowledgeOpen.length < 2;
92
- status.textContent = ready
93
- ? (registered ? '已注册 knowledge 面板;当前打开 ' + knowledgeOpen.length + ' 个实例' : '未注册 provider:knowledge 不显示为可用')
94
- : '等待 kb:ready…';
95
- }
96
-
97
- window.addEventListener('message', function (ev) {
98
- if (ev.source !== frame.contentWindow || ev.origin !== ORIGIN) return;
99
- var data = ev.data;
100
- if (!data || typeof data !== 'object') return;
101
- if (data.type === 'kb:ready') {
102
- ready = true;
103
- line('终端 → 宿主 kb:ready(注册自此生效)', 'app');
104
- refreshButtons();
105
- return;
106
- }
107
- if (data.type === 'kb:panel/state') {
108
- panels = Array.isArray(data.panels) ? data.panels : [];
109
- var providers = (data.providers || []).map(function (p) { return p.providerId; });
110
- line('终端 → 宿主 kb:panel/state reason=' + data.reason +
111
- ' panels=' + JSON.stringify(panels.map(function (p) {
112
- return { id: p.panelId, provider: p.providerId, active: p.active, error: p.error, scope: p.scope };
113
- })) +
114
- ' providers=' + JSON.stringify(providers), 'app');
115
- refreshButtons();
116
- return;
117
- }
118
- if (typeof data.type === 'string' && data.type.indexOf('kb:panel/') === 0) {
119
- line('终端 → 宿主 ' + data.type + ' ' + JSON.stringify(data), 'app');
120
- if (data.type === 'kb:panel/registered' && data.ok) registered = true;
121
- if (data.type === 'kb:panel/unregistered' && data.ok) registered = false;
122
- refreshButtons();
123
- }
124
- });
125
-
126
- buttons.register.addEventListener('click', function () {
127
- send({ type: 'kb:panel/register', panel: {
128
- providerId: PROVIDER_ID,
129
- panelType: 'knowledge',
130
- title: '知识引用(proof)',
131
- url: new URL('panel-proof-content.html?panel=knowledge&source=host-proof', window.location.href).href,
132
- capabilities: ['read-only', 'proof'],
133
- multiInstance: 'multiple',
134
- appliesTo: { projects: '*' },
135
- } });
136
- });
137
- buttons.unregister.addEventListener('click', function () { send({ type: 'kb:panel/unregister', providerId: PROVIDER_ID }); });
138
- buttons.open1.addEventListener('click', function () { send({ type: 'kb:panel/open', providerId: PROVIDER_ID }); });
139
- buttons.open2.addEventListener('click', function () { send({ type: 'kb:panel/open', providerId: PROVIDER_ID }); });
140
- buttons.closeLast.addEventListener('click', function () {
141
- var open = panels.filter(function (p) { return p.providerId === PROVIDER_ID; });
142
- if (open.length) send({ type: 'kb:panel/close', panelId: open[open.length - 1].panelId });
143
- });
144
- buttons.activateFirst.addEventListener('click', function () {
145
- var open = panels.filter(function (p) { return p.providerId === PROVIDER_ID; });
146
- if (open.length >= 2) send({ type: 'kb:panel/activate', panelId: open[0].panelId });
147
- });
148
- refreshButtons();
149
- })();
150
- </script>
151
- </body>
152
- </html>
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>W3 Panel Host Proof(最小可信宿主)</title>
7
+ <style>
8
+ :root { color-scheme: dark; }
9
+ body { margin: 0; font: 13px/1.5 system-ui, sans-serif; background: #101016; color: #e8e8ee; display: flex; flex-direction: column; height: 100vh; }
10
+ header { padding: 8px 12px; border-bottom: 1px solid #2a2a33; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
11
+ header h1 { font-size: 14px; margin: 0 12px 0 0; }
12
+ header .note { color: #9a9aa5; font-size: 11px; }
13
+ button { font: inherit; padding: 3px 10px; border: 1px solid #2a2a33; border-radius: 6px; background: #1a1a22; color: inherit; cursor: pointer; }
14
+ button:disabled { opacity: 0.45; cursor: not-allowed; }
15
+ main { flex: 1; display: flex; min-height: 0; }
16
+ #terminal-frame { flex: 1 1 62%; border: none; background: #14141a; }
17
+ aside { flex: 0 0 38%; border-left: 1px solid #2a2a33; display: flex; flex-direction: column; min-width: 0; }
18
+ .state-head { padding: 6px 10px; border-bottom: 1px solid #2a2a33; display: flex; gap: 8px; align-items: baseline; }
19
+ .state-head strong { font-size: 12px; }
20
+ #panel-status { font-size: 11px; color: #9a9aa5; }
21
+ #state-log { flex: 1; overflow-y: auto; margin: 0; padding: 6px 10px; font: 11px/1.6 ui-monospace, monospace; white-space: pre-wrap; word-break: break-all; }
22
+ #state-log .line { display: block; border-bottom: 1px dashed #22222b; padding: 2px 0; }
23
+ #state-log .dir-host { color: #7fa3e8; }
24
+ #state-log .dir-app { color: #2e9e5b; }
25
+ #state-log .dir-err { color: #d64545; }
26
+ </style>
27
+ </head>
28
+ <body>
29
+ <header>
30
+ <h1>W3 Panel Host Proof</h1>
31
+ <span class="note">同源最小宿主:以 embed 模式加载真实 Agent Terminal,注册同源 knowledge iframe 面板。独立 Workbench 不依赖本页代码。</span>
32
+ </header>
33
+ <header>
34
+ <button id="btn-register" disabled>注册知识面板</button>
35
+ <button id="btn-unregister" disabled>注销</button>
36
+ <button id="btn-open-1" disabled>打开一个</button>
37
+ <button id="btn-open-2" disabled>打开第二个</button>
38
+ <button id="btn-close-last" disabled>关闭最后一个</button>
39
+ <button id="btn-activate-first" disabled>切换激活到第一个</button>
40
+ </header>
41
+ <main>
42
+ <iframe id="terminal-frame" title="Agent Terminal(embed)" src="/agent-terminal/?embed=1"></iframe>
43
+ <aside>
44
+ <div class="state-head"><strong>panel state 事件日志</strong><span id="panel-status">等待 kb:ready…</span></div>
45
+ <pre id="state-log"></pre>
46
+ </aside>
47
+ </main>
48
+ <script>
49
+ (function () {
50
+ 'use strict';
51
+ var frame = document.getElementById('terminal-frame');
52
+ var log = document.getElementById('state-log');
53
+ var status = document.getElementById('panel-status');
54
+ var buttons = {
55
+ register: document.getElementById('btn-register'),
56
+ unregister: document.getElementById('btn-unregister'),
57
+ open1: document.getElementById('btn-open-1'),
58
+ open2: document.getElementById('btn-open-2'),
59
+ closeLast: document.getElementById('btn-close-last'),
60
+ activateFirst: document.getElementById('btn-activate-first'),
61
+ };
62
+ var ORIGIN = window.location.origin;
63
+ var PROVIDER_ID = 'kb.proof.knowledge';
64
+ var ready = false;
65
+ var registered = false;
66
+ var panels = [];
67
+ var requestSeq = 0;
68
+
69
+ function line(text, dir) {
70
+ var entry = document.createElement('span');
71
+ entry.className = 'line ' + (dir === 'host' ? 'dir-host' : dir === 'app' ? 'dir-app' : 'dir-err');
72
+ entry.textContent = new Date().toISOString().slice(11, 23) + ' ' + text;
73
+ log.append(entry);
74
+ log.scrollTop = log.scrollHeight;
75
+ }
76
+
77
+ function send(message) {
78
+ if (!ready) { line('宿主 → 终端:忽略(终端未 ready)', 'err'); return; }
79
+ message.requestId = 'proof-' + (++requestSeq);
80
+ frame.contentWindow.postMessage(message, ORIGIN);
81
+ line('宿主 → 终端 ' + message.type + ' ' + JSON.stringify(message), 'host');
82
+ }
83
+
84
+ function refreshButtons() {
85
+ var knowledgeOpen = panels.filter(function (p) { return p.providerId === PROVIDER_ID; });
86
+ buttons.register.disabled = !ready || registered;
87
+ buttons.unregister.disabled = !ready || !registered;
88
+ buttons.open1.disabled = !ready || !registered;
89
+ buttons.open2.disabled = !ready || !registered;
90
+ buttons.closeLast.disabled = knowledgeOpen.length === 0;
91
+ buttons.activateFirst.disabled = knowledgeOpen.length < 2;
92
+ status.textContent = ready
93
+ ? (registered ? '已注册 knowledge 面板;当前打开 ' + knowledgeOpen.length + ' 个实例' : '未注册 provider:knowledge 不显示为可用')
94
+ : '等待 kb:ready…';
95
+ }
96
+
97
+ window.addEventListener('message', function (ev) {
98
+ if (ev.source !== frame.contentWindow || ev.origin !== ORIGIN) return;
99
+ var data = ev.data;
100
+ if (!data || typeof data !== 'object') return;
101
+ if (data.type === 'kb:ready') {
102
+ ready = true;
103
+ line('终端 → 宿主 kb:ready(注册自此生效)', 'app');
104
+ refreshButtons();
105
+ return;
106
+ }
107
+ if (data.type === 'kb:panel/state') {
108
+ panels = Array.isArray(data.panels) ? data.panels : [];
109
+ var providers = (data.providers || []).map(function (p) { return p.providerId; });
110
+ line('终端 → 宿主 kb:panel/state reason=' + data.reason +
111
+ ' panels=' + JSON.stringify(panels.map(function (p) {
112
+ return { id: p.panelId, provider: p.providerId, active: p.active, error: p.error, scope: p.scope };
113
+ })) +
114
+ ' providers=' + JSON.stringify(providers), 'app');
115
+ refreshButtons();
116
+ return;
117
+ }
118
+ if (typeof data.type === 'string' && data.type.indexOf('kb:panel/') === 0) {
119
+ line('终端 → 宿主 ' + data.type + ' ' + JSON.stringify(data), 'app');
120
+ if (data.type === 'kb:panel/registered' && data.ok) registered = true;
121
+ if (data.type === 'kb:panel/unregistered' && data.ok) registered = false;
122
+ refreshButtons();
123
+ }
124
+ });
125
+
126
+ buttons.register.addEventListener('click', function () {
127
+ send({ type: 'kb:panel/register', panel: {
128
+ providerId: PROVIDER_ID,
129
+ panelType: 'knowledge',
130
+ title: '知识引用(proof)',
131
+ url: new URL('panel-proof-content.html?panel=knowledge&source=host-proof', window.location.href).href,
132
+ capabilities: ['read-only', 'proof'],
133
+ multiInstance: 'multiple',
134
+ appliesTo: { projects: '*' },
135
+ } });
136
+ });
137
+ buttons.unregister.addEventListener('click', function () { send({ type: 'kb:panel/unregister', providerId: PROVIDER_ID }); });
138
+ buttons.open1.addEventListener('click', function () { send({ type: 'kb:panel/open', providerId: PROVIDER_ID }); });
139
+ buttons.open2.addEventListener('click', function () { send({ type: 'kb:panel/open', providerId: PROVIDER_ID }); });
140
+ buttons.closeLast.addEventListener('click', function () {
141
+ var open = panels.filter(function (p) { return p.providerId === PROVIDER_ID; });
142
+ if (open.length) send({ type: 'kb:panel/close', panelId: open[open.length - 1].panelId });
143
+ });
144
+ buttons.activateFirst.addEventListener('click', function () {
145
+ var open = panels.filter(function (p) { return p.providerId === PROVIDER_ID; });
146
+ if (open.length >= 2) send({ type: 'kb:panel/activate', panelId: open[0].panelId });
147
+ });
148
+ refreshButtons();
149
+ })();
150
+ </script>
151
+ </body>
152
+ </html>
@@ -1,41 +1,41 @@
1
- <!DOCTYPE html>
2
- <html lang="zh-CN">
3
- <head>
4
- <meta charset="UTF-8">
5
- <title>Panel Proof Content</title>
6
- <style>
7
- :root { color-scheme: dark; }
8
- body { margin: 0; padding: 12px; font: 12px/1.6 system-ui, sans-serif; background: #14141a; color: #e8e8ee; }
9
- h1 { font-size: 13px; margin: 0 0 8px; }
10
- dl { display: grid; grid-template-columns: 110px 1fr; gap: 4px 10px; margin: 0; }
11
- dt { color: #9a9aa5; }
12
- dd { margin: 0; word-break: break-all; }
13
- #marker { color: #2e9e5b; font-weight: 600; }
14
- #sandbox-state { color: #7fa3e8; }
15
- </style>
16
- </head>
17
- <body>
18
- <h1>知识引用面板内容(proof)</h1>
19
- <dl>
20
- <dt>稳定 marker</dt><dd id="marker">KB-PANEL-PROOF-CONTENT-v1</dd>
21
- <dt>自身 query</dt><dd id="query"></dd>
22
- <dt>自身 href</dt><dd id="href"></dd>
23
- <dt>sandbox 状态</dt><dd id="sandbox-state"></dd>
24
- <dt>自身 origin</dt><dd id="origin"></dd>
25
- </dl>
26
- <script>
27
- (function () {
28
- 'use strict';
29
- document.getElementById('query').textContent = window.location.search || '(无 query)';
30
- document.getElementById('href').textContent = window.location.href;
31
- document.getElementById('origin').textContent = window.location.origin;
32
- // The dock mounts panels with sandbox="allow-scripts" (no allow-same-origin):
33
- // reaching the parent must throw, proving the frame is credibly contained.
34
- var contained = '未知';
35
- try { if (window.parent && window.parent !== window) { void window.parent.location.href; contained = '否(可访问父窗口,sandbox 未生效)'; } else contained = '无父窗口'; }
36
- catch (error) { contained = '是(父窗口不可达:' + (error && error.name ? error.name : 'Error') + ')'; }
37
- document.getElementById('sandbox-state').textContent = contained;
38
- })();
39
- </script>
40
- </body>
41
- </html>
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Panel Proof Content</title>
6
+ <style>
7
+ :root { color-scheme: dark; }
8
+ body { margin: 0; padding: 12px; font: 12px/1.6 system-ui, sans-serif; background: #14141a; color: #e8e8ee; }
9
+ h1 { font-size: 13px; margin: 0 0 8px; }
10
+ dl { display: grid; grid-template-columns: 110px 1fr; gap: 4px 10px; margin: 0; }
11
+ dt { color: #9a9aa5; }
12
+ dd { margin: 0; word-break: break-all; }
13
+ #marker { color: #2e9e5b; font-weight: 600; }
14
+ #sandbox-state { color: #7fa3e8; }
15
+ </style>
16
+ </head>
17
+ <body>
18
+ <h1>知识引用面板内容(proof)</h1>
19
+ <dl>
20
+ <dt>稳定 marker</dt><dd id="marker">KB-PANEL-PROOF-CONTENT-v1</dd>
21
+ <dt>自身 query</dt><dd id="query"></dd>
22
+ <dt>自身 href</dt><dd id="href"></dd>
23
+ <dt>sandbox 状态</dt><dd id="sandbox-state"></dd>
24
+ <dt>自身 origin</dt><dd id="origin"></dd>
25
+ </dl>
26
+ <script>
27
+ (function () {
28
+ 'use strict';
29
+ document.getElementById('query').textContent = window.location.search || '(无 query)';
30
+ document.getElementById('href').textContent = window.location.href;
31
+ document.getElementById('origin').textContent = window.location.origin;
32
+ // The dock mounts panels with sandbox="allow-scripts" (no allow-same-origin):
33
+ // reaching the parent must throw, proving the frame is credibly contained.
34
+ var contained = '未知';
35
+ try { if (window.parent && window.parent !== window) { void window.parent.location.href; contained = '否(可访问父窗口,sandbox 未生效)'; } else contained = '无父窗口'; }
36
+ catch (error) { contained = '是(父窗口不可达:' + (error && error.name ? error.name : 'Error') + ')'; }
37
+ document.getElementById('sandbox-state').textContent = contained;
38
+ })();
39
+ </script>
40
+ </body>
41
+ </html>