@capyclaw/ppt-workbench 0.0.0-stage → 2.4.1

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 (130) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +126 -3
  3. package/THIRD_PARTY_NOTICES.md +21 -0
  4. package/contract/ppt-contract.json +1529 -0
  5. package/cordis.patch.yml +25 -0
  6. package/core/audit.js +500 -0
  7. package/core/chart.js +199 -0
  8. package/core/color.js +80 -0
  9. package/core/deck-layout.js +195 -0
  10. package/core/formula.js +80 -0
  11. package/core/hfmath/hershey.js +1763 -0
  12. package/core/hfmath/index.js +1176 -0
  13. package/core/hfmath/stretch.js +41 -0
  14. package/core/hfmath/symbols.js +408 -0
  15. package/core/ops/browser.js +28 -0
  16. package/core/ops/chart.js +64 -0
  17. package/core/ops/deck.js +21 -0
  18. package/core/ops/dispatcher.js +2 -0
  19. package/core/ops/element.js +55 -0
  20. package/core/ops/history.js +11 -0
  21. package/core/ops/import.js +95 -0
  22. package/core/ops/index.js +39 -0
  23. package/core/ops/playback.js +9 -0
  24. package/core/ops/recolor.js +33 -0
  25. package/core/ops/slide.js +66 -0
  26. package/core/ops/table.js +85 -0
  27. package/core/ops/text.js +35 -0
  28. package/core/ops/view.js +13 -0
  29. package/core/ops.js +12 -0
  30. package/core/quick.js +52 -0
  31. package/core/shape-library.js +122 -0
  32. package/core/table.js +178 -0
  33. package/core/text.js +200 -0
  34. package/editor/app.js +5366 -0
  35. package/editor/heartbeat-worker.js +116 -0
  36. package/editor/index.html +89 -0
  37. package/editor/ppt-full-app.js +376 -0
  38. package/lib/host.mjs +98 -0
  39. package/package.json +53 -6
  40. package/server/audit.mjs +2 -0
  41. package/server/bridge-client.mjs +174 -0
  42. package/server/constants.mjs +20 -0
  43. package/server/contract-snapshots.mjs +62 -0
  44. package/server/contract.mjs +24 -0
  45. package/server/deck-layout.mjs +2 -0
  46. package/server/http-utils.mjs +2 -0
  47. package/server/infra/http.mjs +113 -0
  48. package/server/infra/runtime/context.mjs +128 -0
  49. package/server/infra/store/blob-store.mjs +109 -0
  50. package/server/infra/tuning.mjs +82 -0
  51. package/server/infra/util/fs-lock.mjs +132 -0
  52. package/server/infra/workspace/manager.mjs +657 -0
  53. package/server/mcp/dispatch.mjs +2 -0
  54. package/server/mcp/handler.mjs +2 -0
  55. package/server/mcp/instructions.mjs +40 -0
  56. package/server/mcp-http.mjs +3 -0
  57. package/server/ppt-shim.mjs +156 -0
  58. package/server/relay.mjs +245 -0
  59. package/server/routes/assets.mjs +2 -0
  60. package/server/routes/bridge.mjs +47 -0
  61. package/server/routes/editor.mjs +9 -0
  62. package/server/routes/import.mjs +258 -0
  63. package/server/routes/mcp.mjs +17 -0
  64. package/server/runtime/recovery.mjs +9 -0
  65. package/server/runtime/watch.mjs +17 -0
  66. package/server/shared/SHARED_MANIFEST.json +47 -0
  67. package/server/shared/asset-service.mjs +217 -0
  68. package/server/shared/editor-host.mjs +125 -0
  69. package/server/shared/kit/editor/lease.mjs +139 -0
  70. package/server/shared/kit/service/api.mjs +45 -0
  71. package/server/shared/kit/service/http.mjs +113 -0
  72. package/server/shared/kit/service/mcp-http.mjs +142 -0
  73. package/server/shared/kit/service/single-instance.mjs +72 -0
  74. package/server/shared/kit/tools/validate.mjs +115 -0
  75. package/server/shared/kit/tuning.mjs +82 -0
  76. package/server/shared/kit/util/fs-lock.mjs +132 -0
  77. package/server/shared/service-host.mjs +511 -0
  78. package/server/shared/state-service.mjs +249 -0
  79. package/server/shared/tool-host.mjs +341 -0
  80. package/server/shared/tuning.mjs +63 -0
  81. package/server/single-instance.mjs +2 -0
  82. package/server/store/backends/file-backend.mjs +13 -0
  83. package/server/store/checkpoints.mjs +28 -0
  84. package/server/store/doc.mjs +52 -0
  85. package/server/store/index.mjs +34 -0
  86. package/server/store/journal.mjs +9 -0
  87. package/server/store/lease.mjs +2 -0
  88. package/server/store/sanitize.mjs +32 -0
  89. package/server/store.mjs +2 -0
  90. package/server/tools/capabilities/apply.mjs +33 -0
  91. package/server/tools/capabilities/audit.mjs +24 -0
  92. package/server/tools/capabilities/chart.mjs +83 -0
  93. package/server/tools/capabilities/compose.mjs +97 -0
  94. package/server/tools/capabilities/contract.mjs +34 -0
  95. package/server/tools/capabilities/deck.mjs +27 -0
  96. package/server/tools/capabilities/element.mjs +67 -0
  97. package/server/tools/capabilities/export.mjs +95 -0
  98. package/server/tools/capabilities/formula.mjs +72 -0
  99. package/server/tools/capabilities/history.mjs +29 -0
  100. package/server/tools/capabilities/image.mjs +152 -0
  101. package/server/tools/capabilities/imagesearch.mjs +152 -0
  102. package/server/tools/capabilities/import.mjs +180 -0
  103. package/server/tools/capabilities/index.mjs +58 -0
  104. package/server/tools/capabilities/line.mjs +58 -0
  105. package/server/tools/capabilities/notes.mjs +33 -0
  106. package/server/tools/capabilities/present.mjs +34 -0
  107. package/server/tools/capabilities/recolor.mjs +60 -0
  108. package/server/tools/capabilities/screenshot.mjs +86 -0
  109. package/server/tools/capabilities/shape.mjs +64 -0
  110. package/server/tools/capabilities/slide.mjs +81 -0
  111. package/server/tools/capabilities/style.mjs +48 -0
  112. package/server/tools/capabilities/table.mjs +127 -0
  113. package/server/tools/capabilities/task.mjs +52 -0
  114. package/server/tools/capabilities/text.mjs +82 -0
  115. package/server/tools/domains/color.mjs +4 -0
  116. package/server/tools/domains/image.mjs +49 -0
  117. package/server/tools/domains/index.mjs +7 -0
  118. package/server/tools/domains/pptx-export.mjs +566 -0
  119. package/server/tools/domains/recolor.mjs +25 -0
  120. package/server/tools/domains/remote-image.mjs +291 -0
  121. package/server/tools/domains/slide.mjs +21 -0
  122. package/server/tools/domains/text-style.mjs +11 -0
  123. package/server/tools/domains/tooling.mjs +13 -0
  124. package/server/tools/index.mjs +14 -0
  125. package/server/tools/kernel/define.mjs +5 -0
  126. package/server/tools/kernel/ports.mjs +42 -0
  127. package/server/tools/kernel/registry.mjs +17 -0
  128. package/server/tools.mjs +18 -0
  129. package/server/tuning.mjs +86 -0
  130. 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>