draftgo-cli 1.0.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/README.md +119 -0
- package/bin/draftgo.js +3 -0
- package/package.json +45 -0
- package/resources/skill/CLAUDE.md +239 -0
- package/resources/skill/SKILL.md +75 -0
- package/resources/skill/bug/SKILL.md +72 -0
- package/resources/skill/init/SKILL.md +63 -0
- package/resources/skill/rules/debugging-syntax.md +279 -0
- package/resources/skill/rules/frontend.md +462 -0
- package/resources/skill/scripts/draftgo_init.py +192 -0
- package/resources/skill/scripts/draftgo_sync.py +150 -0
- package/resources/skill/sync/SKILL.md +72 -0
- package/src/cli.js +43 -0
- package/src/commands/doctor.js +39 -0
- package/src/commands/help.js +42 -0
- package/src/commands/init.js +71 -0
- package/src/commands/listTargets.js +13 -0
- package/src/commands/status.js +23 -0
- package/src/commands/uninstall.js +52 -0
- package/src/commands/update.js +54 -0
- package/src/detect.js +29 -0
- package/src/fsx.js +62 -0
- package/src/index.js +53 -0
- package/src/installers/_entryContent.js +45 -0
- package/src/installers/antigravity.js +28 -0
- package/src/installers/base.js +54 -0
- package/src/installers/claudecode.js +29 -0
- package/src/installers/codex.js +31 -0
- package/src/installers/copilot.js +28 -0
- package/src/installers/cursor.js +28 -0
- package/src/installers/gemini.js +31 -0
- package/src/installers/index.js +33 -0
- package/src/installers/kiro.js +33 -0
- package/src/installers/windsurf.js +28 -0
- package/src/logger.js +30 -0
- package/src/paths.js +35 -0
- package/src/python.js +27 -0
- package/src/skill.js +83 -0
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: draftgo-debugging-syntax
|
|
3
|
+
description: 页面代码量大时,语法/逻辑缺陷导致页面静默失效的排查指南。页面功能不执行、无报错或报错误导时,先按此清单逐项检查。
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# DraftGo 页面排错指南
|
|
8
|
+
|
|
9
|
+
> **为什么需要这份文档:** DraftGo 页面是完整 HTML 运行在 iframe.srcdoc,业务逻辑、DOM 操作、API 调用全部混在单个文件里。代码量大之后,某些语法/逻辑缺陷不会触发控制台报错,也不会弹出异常,但功能就静默失效了。这份清单帮 AI 快速定位这类"查不到报错"的致命缺陷。
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 核心排错原则
|
|
14
|
+
|
|
15
|
+
**页面功能不执行时,按这个顺序排查,不要漫无目的地读代码:**
|
|
16
|
+
|
|
17
|
+
1. 先看浏览器控制台有没有红色报错,有就按报错定位
|
|
18
|
+
2. 没有报错 → 用本文档逐项检查(最常见的就是下面列出的几类)
|
|
19
|
+
3. 在关键位置加 `console.log('=== A 点到达 ===')` 二分定位死在哪一步
|
|
20
|
+
4. 仍找不到 → 用二分法注释掉一半代码,缩小范围
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 致命缺陷速查清单(按出现频率排序)
|
|
25
|
+
|
|
26
|
+
以下每一项都可能导致页面**完全静默失效**——无报错、无异常、功能就是不动。
|
|
27
|
+
|
|
28
|
+
### 1. 模板字符串未闭合(最常见!)
|
|
29
|
+
|
|
30
|
+
在 iframe.srcdoc 环境中,`</script>` 出现在模板字符串里会**提前关闭 script 标签**,导致后续所有 JS 代码被当 HTML 解析。这种问题**没有任何报错**。
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
// ❌ 致命:模板字符串中的 </script> 终止了外层 <script> 标签
|
|
34
|
+
const html = `
|
|
35
|
+
<script>
|
|
36
|
+
console.log('inner');
|
|
37
|
+
</script> // ← 这里!浏览器解析器看到 </script> 就关闭了外层 script
|
|
38
|
+
`;
|
|
39
|
+
|
|
40
|
+
// ✅ 安全:把 </ 拆开
|
|
41
|
+
const html = `
|
|
42
|
+
<script>
|
|
43
|
+
console.log('inner');
|
|
44
|
+
<` + `/script>
|
|
45
|
+
`;
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**排查方法:** 检查所有模板字符串,搜索 `</script>` 是否出现在 JS 字符串中。同时检查 `</style>` 是否出现在模板字符串中(同理)。
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
### 2. await 用在了非 async 函数里
|
|
53
|
+
|
|
54
|
+
浏览器对顶层 `await` 支持有限(取决于环境)。如果在普通函数里用了 `await`,**整个 script 块可能不执行**。
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
// ❌ 致命:init 不是 async 函数
|
|
58
|
+
function init() {
|
|
59
|
+
const data = await App.get('db/patients'); // SyntaxError,后续代码全死
|
|
60
|
+
render(data);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ✅ 正确
|
|
64
|
+
async function init() {
|
|
65
|
+
const data = await App.get('db/patients');
|
|
66
|
+
render(data);
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
// ❌ 致命:DOMContentLoaded 回调忘了 async
|
|
72
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
73
|
+
const data = await App.get('db/patients'); // 回调不是 async!
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// ✅ 正确
|
|
77
|
+
document.addEventListener('DOMContentLoaded', async () => {
|
|
78
|
+
const data = await App.get('db/patients');
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**排查方法:** 搜索文件中所有 `await`,逐个人工确认外层函数是否标了 `async`。
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
### 3. App.confirm() 忘了 await
|
|
87
|
+
|
|
88
|
+
`App.confirm()` 返回 `Promise<boolean>`。忘了 `await`,变量是 Promise 对象(**始终 truthy**),条件判断永远通过。
|
|
89
|
+
|
|
90
|
+
```javascript
|
|
91
|
+
// ❌ 致命:ok 是 Promise 对象,不是 boolean,if 永远为 true
|
|
92
|
+
const ok = App.confirm('确认删除?');
|
|
93
|
+
if (ok) { /* 永远执行 */ }
|
|
94
|
+
|
|
95
|
+
// ✅ 正确
|
|
96
|
+
const ok = await App.confirm('确认删除?');
|
|
97
|
+
if (ok) { /* 用户点了确定才执行 */ }
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**排查方法:** 搜索 `App.confirm(`,检查返回值是否用了 `await`。
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
### 4. 对 null/undefined 调用方法
|
|
105
|
+
|
|
106
|
+
API 返回数据不存在时,链式调用会抛出 TypeError,**打断后续所有代码执行**。
|
|
107
|
+
|
|
108
|
+
```javascript
|
|
109
|
+
// ❌ 致命:data 可能是 null
|
|
110
|
+
const name = App.get('db/patients/999').full_name.toUpperCase();
|
|
111
|
+
|
|
112
|
+
// ❌ 致命:items 可能是 undefined
|
|
113
|
+
items.forEach(item => render(item)); // TypeError: Cannot read properties of undefined
|
|
114
|
+
|
|
115
|
+
// ✅ 安全
|
|
116
|
+
const patient = await App.get('db/patients/999');
|
|
117
|
+
if (!patient) { App.showError('未找到'); return; }
|
|
118
|
+
const name = patient.full_name?.toUpperCase() || '';
|
|
119
|
+
|
|
120
|
+
// ✅ 安全
|
|
121
|
+
(items || []).forEach(item => render(item));
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**排查方法:** 搜 `.forEach(`、`.map(`、`.filter(` 等数组方法,确认调用者不会是 undefined。
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
### 5. getElementById 拿到 null 后操作
|
|
129
|
+
|
|
130
|
+
```javascript
|
|
131
|
+
// ❌ 致命:如果 DOM 中不存在 #form,直接 TypeError,后续代码全死
|
|
132
|
+
document.getElementById('form').addEventListener('submit', handler);
|
|
133
|
+
|
|
134
|
+
// ✅ 安全
|
|
135
|
+
const form = document.getElementById('form');
|
|
136
|
+
if (form) { form.addEventListener('submit', handler); }
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**排查方法:** 搜索 `document.getElementById(`,检查返回值是否判空。
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
### 6. 变量重复声明 / 提前引用
|
|
144
|
+
|
|
145
|
+
```javascript
|
|
146
|
+
// ❌ 致命:const 重复声明
|
|
147
|
+
const App = window.parent?.App;
|
|
148
|
+
// ... 500 行后 ...
|
|
149
|
+
const App = window.parent?.App; // SyntaxError: Identifier 'App' has already been declared
|
|
150
|
+
|
|
151
|
+
// ❌ 致命:TDZ 死区
|
|
152
|
+
console.log(app); // ReferenceError
|
|
153
|
+
const app = window.parent?.App;
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**排查方法:** 搜索 `const App`、`let App`、`var App` 看是否重复。搜索 `const ` 全局看是否有同名声明。
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
### 7. JSON.parse 静默失败
|
|
161
|
+
|
|
162
|
+
```javascript
|
|
163
|
+
// ❌ 如果 str 不是合法 JSON,直接抛异常
|
|
164
|
+
const config = JSON.parse(App.config.some_setting);
|
|
165
|
+
|
|
166
|
+
// ✅ 安全
|
|
167
|
+
let config = {};
|
|
168
|
+
try { config = JSON.parse(App.config.some_setting || '{}'); } catch (e) {}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
### 8. 对象字面量尾部逗号(极少见但存在)
|
|
174
|
+
|
|
175
|
+
虽然现代浏览器大多容忍,但在某些内嵌环境中尾部逗号仍可能出错。
|
|
176
|
+
|
|
177
|
+
```javascript
|
|
178
|
+
// 某些严格解析场景可能报错
|
|
179
|
+
const obj = {
|
|
180
|
+
name: 'test',
|
|
181
|
+
age: 30, // ← 尾逗号
|
|
182
|
+
};
|
|
183
|
+
```
|
|
184
|
+
这道一般不是问题,但如果其他都排除了仍找不到 bug,可以检查。
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
### 9. innerHTML 中的 HTML 片段提前闭合
|
|
189
|
+
|
|
190
|
+
```javascript
|
|
191
|
+
// ❌ 如果 row.name 包含特殊字符,可能破坏 HTML 结构
|
|
192
|
+
el.innerHTML = `<div>${row.name}</div>`;
|
|
193
|
+
|
|
194
|
+
// ✅ 安全:至少做基本转义
|
|
195
|
+
const esc = s => String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
|
196
|
+
el.innerHTML = `<div>${esc(row.name)}</div>`;
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**排查方法:** 搜索 `innerHTML =`,确认插入内容做了转义。
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
### 10. 正则表达式灾难性回溯
|
|
204
|
+
|
|
205
|
+
大文本上运行复杂正则,页面卡死,看起来像挂了。
|
|
206
|
+
|
|
207
|
+
```javascript
|
|
208
|
+
// ❌ 多个 .* 叠加可能导致回溯爆炸
|
|
209
|
+
const matches = hugeText.match(/(.*)<div>(.*)<\/div>(.*)/gs);
|
|
210
|
+
|
|
211
|
+
// ✅ 用具体选择器或限制范围
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## 系统性排查法
|
|
217
|
+
|
|
218
|
+
当你查了上面清单还是找不到 bug 时:
|
|
219
|
+
|
|
220
|
+
### 步骤 1:确认代码是否在跑
|
|
221
|
+
|
|
222
|
+
在 `<script>` 最开头加:
|
|
223
|
+
```javascript
|
|
224
|
+
console.log('=== SCRIPT START ===');
|
|
225
|
+
```
|
|
226
|
+
如果这行没输出 → script 根本没加载(检查 HTML 结构、script 标签闭合)
|
|
227
|
+
|
|
228
|
+
### 步骤 2:二分定位死点
|
|
229
|
+
|
|
230
|
+
在疑似问题区域两侧加 log:
|
|
231
|
+
```javascript
|
|
232
|
+
console.log('A');
|
|
233
|
+
// ... 代码 ...
|
|
234
|
+
console.log('B');
|
|
235
|
+
```
|
|
236
|
+
如果 A 输出但 B 没输出 → bug 在两者之间
|
|
237
|
+
|
|
238
|
+
### 步骤 3:检查全局错误处理
|
|
239
|
+
|
|
240
|
+
```javascript
|
|
241
|
+
window.addEventListener('error', e => console.error('全局错误:', e.message, e.filename, e.lineno));
|
|
242
|
+
window.addEventListener('unhandledrejection', e => console.error('未处理 Promise:', e.reason));
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### 步骤 4:检查异步代码是否真执行了
|
|
246
|
+
|
|
247
|
+
很多"没反应"是因为异步函数抛了异常但没 catch:
|
|
248
|
+
```javascript
|
|
249
|
+
// ❌ 异步异常链断裂
|
|
250
|
+
async function load() {
|
|
251
|
+
const data = await App.get('db/patients'); // 如果这里 reject,外面感知不到
|
|
252
|
+
render(data);
|
|
253
|
+
}
|
|
254
|
+
load(); // 没有 .catch()
|
|
255
|
+
|
|
256
|
+
// ✅ 加错误边界
|
|
257
|
+
load().catch(err => console.error('load 失败:', err));
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## HTML 结构层面的静默缺陷
|
|
263
|
+
|
|
264
|
+
以下缺陷不会触发任何 JS 错误,但会导致页面空白或样式错乱:
|
|
265
|
+
|
|
266
|
+
| 缺陷 | 后果 | 排查方法 |
|
|
267
|
+
|---|---|---|
|
|
268
|
+
| `</script>` 前缺少闭合引号 | 后续 HTML 全被当 JS 解析 | 检查 `<script>` 内容中是否有未闭合的字符串 |
|
|
269
|
+
| `<style>` 中有 `</style>` | CSS 提前结束,后续样式丢失 | 检查内联 CSS 中是否有 `</style>` 文本 |
|
|
270
|
+
| 属性值引号不匹配 `id="xxx'` | HTML 解析错位 | 搜 `=".*'` 或 `='.*"` 正则 |
|
|
271
|
+
| `<` 出现在 JS 比较符中没转义 | HTML 解析器误解 | 在 inline JS 中 `if (a < b)` 可能导致问题,改用 `if (b > a)` |
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## 总结:查不到 bug 时的三板斧
|
|
276
|
+
|
|
277
|
+
1. **搜索 `</script>`**——如果在 JS 字符串里出现,查!这是最最常见的静默杀手。
|
|
278
|
+
2. **搜索 `await`**——确认所有 await 都在 async 函数内。
|
|
279
|
+
3. **二分注释**——注释掉一半代码,看功能能不能跑,逐次缩小范围。不要用眼睛硬读。
|