@capyclaw/ppt-workbench 0.0.0-stage → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +126 -3
- package/THIRD_PARTY_NOTICES.md +21 -0
- package/contract/ppt-contract.json +1529 -0
- package/cordis.patch.yml +25 -0
- package/core/audit.js +500 -0
- package/core/chart.js +199 -0
- package/core/color.js +80 -0
- package/core/deck-layout.js +195 -0
- package/core/formula.js +80 -0
- package/core/hfmath/hershey.js +1763 -0
- package/core/hfmath/index.js +1176 -0
- package/core/hfmath/stretch.js +41 -0
- package/core/hfmath/symbols.js +408 -0
- package/core/ops/browser.js +28 -0
- package/core/ops/chart.js +64 -0
- package/core/ops/deck.js +21 -0
- package/core/ops/dispatcher.js +2 -0
- package/core/ops/element.js +55 -0
- package/core/ops/history.js +11 -0
- package/core/ops/import.js +95 -0
- package/core/ops/index.js +39 -0
- package/core/ops/playback.js +9 -0
- package/core/ops/recolor.js +33 -0
- package/core/ops/slide.js +66 -0
- package/core/ops/table.js +85 -0
- package/core/ops/text.js +35 -0
- package/core/ops/view.js +13 -0
- package/core/ops.js +12 -0
- package/core/quick.js +52 -0
- package/core/shape-library.js +122 -0
- package/core/table.js +178 -0
- package/core/text.js +200 -0
- package/editor/app.js +5366 -0
- package/editor/heartbeat-worker.js +116 -0
- package/editor/index.html +89 -0
- package/editor/ppt-full-app.js +376 -0
- package/lib/host.mjs +98 -0
- package/package.json +51 -4
- package/server/audit.mjs +2 -0
- package/server/bridge-client.mjs +174 -0
- package/server/constants.mjs +20 -0
- package/server/contract-snapshots.mjs +62 -0
- package/server/contract.mjs +24 -0
- package/server/deck-layout.mjs +2 -0
- package/server/http-utils.mjs +2 -0
- package/server/infra/http.mjs +113 -0
- package/server/infra/runtime/context.mjs +128 -0
- package/server/infra/store/blob-store.mjs +109 -0
- package/server/infra/tuning.mjs +82 -0
- package/server/infra/util/fs-lock.mjs +132 -0
- package/server/infra/workspace/manager.mjs +657 -0
- package/server/mcp/dispatch.mjs +2 -0
- package/server/mcp/handler.mjs +2 -0
- package/server/mcp/instructions.mjs +40 -0
- package/server/mcp-http.mjs +3 -0
- package/server/ppt-shim.mjs +156 -0
- package/server/relay.mjs +245 -0
- package/server/routes/assets.mjs +2 -0
- package/server/routes/bridge.mjs +47 -0
- package/server/routes/editor.mjs +9 -0
- package/server/routes/import.mjs +258 -0
- package/server/routes/mcp.mjs +17 -0
- package/server/runtime/recovery.mjs +9 -0
- package/server/runtime/watch.mjs +17 -0
- package/server/shared/SHARED_MANIFEST.json +47 -0
- package/server/shared/asset-service.mjs +217 -0
- package/server/shared/editor-host.mjs +125 -0
- package/server/shared/kit/editor/lease.mjs +139 -0
- package/server/shared/kit/service/api.mjs +45 -0
- package/server/shared/kit/service/http.mjs +113 -0
- package/server/shared/kit/service/mcp-http.mjs +142 -0
- package/server/shared/kit/service/single-instance.mjs +72 -0
- package/server/shared/kit/tools/validate.mjs +115 -0
- package/server/shared/kit/tuning.mjs +82 -0
- package/server/shared/kit/util/fs-lock.mjs +132 -0
- package/server/shared/service-host.mjs +511 -0
- package/server/shared/state-service.mjs +249 -0
- package/server/shared/tool-host.mjs +341 -0
- package/server/shared/tuning.mjs +63 -0
- package/server/single-instance.mjs +2 -0
- package/server/store/backends/file-backend.mjs +13 -0
- package/server/store/checkpoints.mjs +28 -0
- package/server/store/doc.mjs +52 -0
- package/server/store/index.mjs +34 -0
- package/server/store/journal.mjs +9 -0
- package/server/store/lease.mjs +2 -0
- package/server/store/sanitize.mjs +32 -0
- package/server/store.mjs +2 -0
- package/server/tools/capabilities/apply.mjs +33 -0
- package/server/tools/capabilities/audit.mjs +24 -0
- package/server/tools/capabilities/chart.mjs +83 -0
- package/server/tools/capabilities/compose.mjs +97 -0
- package/server/tools/capabilities/contract.mjs +34 -0
- package/server/tools/capabilities/deck.mjs +27 -0
- package/server/tools/capabilities/element.mjs +67 -0
- package/server/tools/capabilities/export.mjs +95 -0
- package/server/tools/capabilities/formula.mjs +72 -0
- package/server/tools/capabilities/history.mjs +29 -0
- package/server/tools/capabilities/image.mjs +152 -0
- package/server/tools/capabilities/imagesearch.mjs +152 -0
- package/server/tools/capabilities/import.mjs +180 -0
- package/server/tools/capabilities/index.mjs +58 -0
- package/server/tools/capabilities/line.mjs +58 -0
- package/server/tools/capabilities/notes.mjs +33 -0
- package/server/tools/capabilities/present.mjs +34 -0
- package/server/tools/capabilities/recolor.mjs +60 -0
- package/server/tools/capabilities/screenshot.mjs +86 -0
- package/server/tools/capabilities/shape.mjs +64 -0
- package/server/tools/capabilities/slide.mjs +81 -0
- package/server/tools/capabilities/style.mjs +48 -0
- package/server/tools/capabilities/table.mjs +127 -0
- package/server/tools/capabilities/task.mjs +52 -0
- package/server/tools/capabilities/text.mjs +82 -0
- package/server/tools/domains/color.mjs +4 -0
- package/server/tools/domains/image.mjs +49 -0
- package/server/tools/domains/index.mjs +7 -0
- package/server/tools/domains/pptx-export.mjs +566 -0
- package/server/tools/domains/recolor.mjs +25 -0
- package/server/tools/domains/remote-image.mjs +291 -0
- package/server/tools/domains/slide.mjs +21 -0
- package/server/tools/domains/text-style.mjs +11 -0
- package/server/tools/domains/tooling.mjs +13 -0
- package/server/tools/index.mjs +14 -0
- package/server/tools/kernel/define.mjs +5 -0
- package/server/tools/kernel/ports.mjs +42 -0
- package/server/tools/kernel/registry.mjs +17 -0
- package/server/tools.mjs +18 -0
- package/server/tuning.mjs +86 -0
- package/server/validate.mjs +2 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/* Web Worker:独立线程保持心跳,不受浏览器标签页节流影响
|
|
2
|
+
*
|
|
3
|
+
* 设计原则:
|
|
4
|
+
* 1. 健壮降级:任何失败都通知主线程,主线程决定是否降级
|
|
5
|
+
* 2. 自我监控:内置健康检查,连续失败自动报告
|
|
6
|
+
* 3. 优雅退出:stop 后立即停止,不留残留定时器
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
let active = false;
|
|
10
|
+
let clientId = null;
|
|
11
|
+
let apiBase = null;
|
|
12
|
+
let intervalHandle = null;
|
|
13
|
+
let consecutiveFailures = 0;
|
|
14
|
+
const MAX_FAILURES = 3; // 连续失败 3 次后通知主线程降级
|
|
15
|
+
|
|
16
|
+
self.onmessage = function(e) {
|
|
17
|
+
const { type, data } = e.data;
|
|
18
|
+
|
|
19
|
+
if (type === 'start') {
|
|
20
|
+
active = true;
|
|
21
|
+
clientId = data.clientId;
|
|
22
|
+
apiBase = data.apiBase;
|
|
23
|
+
consecutiveFailures = 0;
|
|
24
|
+
startHeartbeat();
|
|
25
|
+
self.postMessage({ type: 'started', clientId });
|
|
26
|
+
} else if (type === 'stop') {
|
|
27
|
+
active = false;
|
|
28
|
+
if (intervalHandle) {
|
|
29
|
+
clearInterval(intervalHandle);
|
|
30
|
+
intervalHandle = null;
|
|
31
|
+
}
|
|
32
|
+
self.postMessage({ type: 'stopped' });
|
|
33
|
+
} else if (type === 'ping') {
|
|
34
|
+
// 主线程健康检查:返回当前状态
|
|
35
|
+
self.postMessage({
|
|
36
|
+
type: 'pong',
|
|
37
|
+
active,
|
|
38
|
+
clientId,
|
|
39
|
+
consecutiveFailures,
|
|
40
|
+
timestamp: Date.now()
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
function startHeartbeat() {
|
|
46
|
+
if (intervalHandle) clearInterval(intervalHandle);
|
|
47
|
+
|
|
48
|
+
// 每 4 秒发送心跳(留 1 秒缓冲,避免刚好 5 秒时被判过期)
|
|
49
|
+
intervalHandle = setInterval(() => {
|
|
50
|
+
if (!active) return;
|
|
51
|
+
|
|
52
|
+
sendClaim().catch(err => {
|
|
53
|
+
consecutiveFailures++;
|
|
54
|
+
self.postMessage({
|
|
55
|
+
type: 'error',
|
|
56
|
+
message: err.message,
|
|
57
|
+
consecutiveFailures,
|
|
58
|
+
fatal: consecutiveFailures >= MAX_FAILURES
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// 连续失败达到阈值,建议主线程降级
|
|
62
|
+
if (consecutiveFailures >= MAX_FAILURES) {
|
|
63
|
+
self.postMessage({
|
|
64
|
+
type: 'fatal',
|
|
65
|
+
message: `连续 ${MAX_FAILURES} 次心跳失败,建议降级到主线程`
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}, 4000);
|
|
70
|
+
|
|
71
|
+
// 立即发送第一次
|
|
72
|
+
sendClaim().catch(() => {});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function sendClaim() {
|
|
76
|
+
if (!apiBase || !clientId) {
|
|
77
|
+
throw new Error('Worker 未初始化:缺少 apiBase 或 clientId');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const url = `${apiBase}/claim`;
|
|
81
|
+
const controller = new AbortController();
|
|
82
|
+
const timeoutId = setTimeout(() => controller.abort(), 8000); // 8 秒超时
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
const response = await fetch(url, {
|
|
86
|
+
method: 'POST',
|
|
87
|
+
headers: { 'content-type': 'application/json' },
|
|
88
|
+
body: JSON.stringify({ id: clientId }),
|
|
89
|
+
signal: controller.signal,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
clearTimeout(timeoutId);
|
|
93
|
+
|
|
94
|
+
if (!response.ok) {
|
|
95
|
+
throw new Error(`HTTP ${response.status}`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const data = await response.json();
|
|
99
|
+
|
|
100
|
+
// 成功:重置失败计数
|
|
101
|
+
if (consecutiveFailures > 0) {
|
|
102
|
+
consecutiveFailures = 0;
|
|
103
|
+
self.postMessage({ type: 'recovered' }); // 通知主线程已恢复
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
self.postMessage({
|
|
107
|
+
type: 'heartbeat',
|
|
108
|
+
timestamp: Date.now(),
|
|
109
|
+
response: data,
|
|
110
|
+
consecutiveFailures: 0
|
|
111
|
+
});
|
|
112
|
+
} catch (err) {
|
|
113
|
+
clearTimeout(timeoutId);
|
|
114
|
+
throw err;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
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>PPTist</title>
|
|
7
|
+
<style>
|
|
8
|
+
* { box-sizing: border-box; margin: 0; }
|
|
9
|
+
html, body { height: 100%; }
|
|
10
|
+
body {
|
|
11
|
+
background: #fff;
|
|
12
|
+
display: flex; flex-direction: column;
|
|
13
|
+
font: 13px/1.5 -apple-system, "Segoe UI", "Microsoft YaHei", sans-serif;
|
|
14
|
+
color: #1f2937;
|
|
15
|
+
}
|
|
16
|
+
.wb-bar {
|
|
17
|
+
height: 44px; flex: 0 0 44px;
|
|
18
|
+
display: flex; align-items: center; gap: 10px;
|
|
19
|
+
padding: 0 12px; border-bottom: 1px solid #e5e7eb; background: #fff;
|
|
20
|
+
position: relative; z-index: 10;
|
|
21
|
+
}
|
|
22
|
+
.wb-brand { font-weight: 700; letter-spacing: .2px; color: #111827; }
|
|
23
|
+
.wb-dot {
|
|
24
|
+
width: 7px; height: 7px; border-radius: 50%;
|
|
25
|
+
background: #22c55e; flex: 0 0 7px;
|
|
26
|
+
}
|
|
27
|
+
.wb-dot[data-kind="standby"] { background: #9ca3af; }
|
|
28
|
+
.wb-dot[data-kind="warn"] { background: #f59e0b; }
|
|
29
|
+
.wb-dot[data-kind="error"] { background: #ef4444; }
|
|
30
|
+
.wb-note {
|
|
31
|
+
min-width: 0; max-width: 44vw; color: #6b7280; font-size: 12px;
|
|
32
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
33
|
+
}
|
|
34
|
+
.wb-spacer { flex: 1 1 auto; }
|
|
35
|
+
.wb-quick {
|
|
36
|
+
width: min(360px, 32vw); height: 30px; padding: 0 10px;
|
|
37
|
+
border: 1px solid #d1d5db; border-radius: 7px; outline: none;
|
|
38
|
+
font: inherit; background: #f9fafb;
|
|
39
|
+
}
|
|
40
|
+
.wb-quick:focus { border-color: #93c5fd; background: #fff; box-shadow: 0 0 0 3px rgba(147,197,253,.2); }
|
|
41
|
+
.wb-actions { display: flex; align-items: center; gap: 6px; }
|
|
42
|
+
.wb-actions button {
|
|
43
|
+
height: 30px; padding: 0 10px; border: 1px solid #d1d5db; border-radius: 7px;
|
|
44
|
+
background: #fff; color: #374151; font: inherit; cursor: pointer;
|
|
45
|
+
}
|
|
46
|
+
.wb-actions button:hover { background: #f3f4f6; }
|
|
47
|
+
.wb-actions button[data-act="pptx"] { border-color: #2563eb; color: #1d4ed8; }
|
|
48
|
+
main { flex: 1; min-height: 0; position: relative; }
|
|
49
|
+
[data-editor] { position: absolute; inset: 0; }
|
|
50
|
+
[data-veil] {
|
|
51
|
+
position: absolute; inset: 0; background: #fff;
|
|
52
|
+
display: grid; place-items: center; text-align: center;
|
|
53
|
+
color: #666; font-size: 13px; transition: opacity .25s; pointer-events: none;
|
|
54
|
+
}
|
|
55
|
+
[data-veil] .hint { color: #999; font-size: 12px; margin-top: 6px; }
|
|
56
|
+
/* 底部演讲者备注栏不属于 PPTist 编辑画布,隐藏 */
|
|
57
|
+
.remark { display: none !important; }
|
|
58
|
+
@media (max-width: 900px) {
|
|
59
|
+
.wb-note { display: none; }
|
|
60
|
+
.wb-quick { width: 200px; }
|
|
61
|
+
.wb-actions button[data-act="json"] { display: none; }
|
|
62
|
+
}
|
|
63
|
+
</style>
|
|
64
|
+
</head>
|
|
65
|
+
<body>
|
|
66
|
+
<header class="wb-bar">
|
|
67
|
+
<span class="wb-brand">PPTist</span>
|
|
68
|
+
<span class="wb-dot" data-badge data-kind="ok" title="编辑器状态"></span>
|
|
69
|
+
<span class="wb-note" data-note aria-live="polite"></span>
|
|
70
|
+
<span class="wb-spacer"></span>
|
|
71
|
+
<input class="wb-quick" data-quick placeholder="⚡ 背景天蓝 / 第2页标题改成…" aria-label="本地快捷指令">
|
|
72
|
+
<div class="wb-actions">
|
|
73
|
+
<button data-act="pptx" title="保存回打开时的 pptx(自动备份);另存请让 agent 用 ppt_export_pptx">保存 PPTX</button>
|
|
74
|
+
<button data-act="json">保存 JSON</button>
|
|
75
|
+
<button data-act="present">放映</button>
|
|
76
|
+
</div>
|
|
77
|
+
</header>
|
|
78
|
+
<main>
|
|
79
|
+
<div data-editor></div>
|
|
80
|
+
<div data-veil>
|
|
81
|
+
<div>
|
|
82
|
+
<div data-editor-note>正在装载编辑器…</div>
|
|
83
|
+
<div class="hint">在 DeepSeek Harness 会话里让 AI 做 PPT,改动会实时出现在这里</div>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
</main>
|
|
87
|
+
<script src="./app-v20261103.js"></script>
|
|
88
|
+
</body>
|
|
89
|
+
</html>
|