@yeaft/webchat-agent 0.1.435 → 0.1.437
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/connection/index.js +3 -1
- package/crew/shared-dir.js +6 -0
- package/crew-i18n.js +26 -2
- package/package.json +1 -1
- package/unify/web-bridge.js +42 -2
package/connection/index.js
CHANGED
package/crew/shared-dir.js
CHANGED
|
@@ -156,6 +156,12 @@ ${roles.length > 0 ? roles.map(r => `- ${roleLabel(r)}(${r.name}): ${r.descripti
|
|
|
156
156
|
${m.workConventions}
|
|
157
157
|
${m.workConventionsContent}
|
|
158
158
|
|
|
159
|
+
${m.mergeRules}
|
|
160
|
+
${m.mergeRulesContent}
|
|
161
|
+
|
|
162
|
+
${m.taskSplitRules}
|
|
163
|
+
${m.taskSplitRulesContent}
|
|
164
|
+
|
|
159
165
|
${m.stuckRules}
|
|
160
166
|
${m.stuckRulesContent}
|
|
161
167
|
|
package/crew-i18n.js
CHANGED
|
@@ -179,7 +179,19 @@ UI/交互方案不确定时找设计师确认。需求不明确时找决策者 "
|
|
|
179
179
|
workConventionsContent: `- 文档产出写入 .crew/context/ 目录
|
|
180
180
|
- 重要决策记录在 .crew/context/decisions.md
|
|
181
181
|
- 代码修改使用项目代码路径的绝对路径
|
|
182
|
-
- **Plan mode 自动退出**:可以进入 plan mode 梳理思路和写计划,但计划写完后必须立即调用 ExitPlanMode
|
|
182
|
+
- **Plan mode 自动退出**:可以进入 plan mode 梳理思路和写计划,但计划写完后必须立即调用 ExitPlanMode 自动退出并直接开始执行,不要等待用户审批。只有在方案有重大歧义、需要用户做选择时才停下来确认
|
|
183
|
+
- **PM 委派优先(Delegation-First)**:PM 收到 bug 报告或技术问题时,不自己分析代码,直接转发给空闲的 dev 分析根因和提方案。PM 等方案回来后做判断和决策。PM 的工作是"转发给合适的人"+"做决策",不是"自己分析技术细节"。
|
|
184
|
+
- **PM 主动巡检(Task Progress Polling)**:PM 在分配任务后,必须每 3-5 分钟主动检查任务进度(读取 feature 文件和 kanban)。如果某个角色 5 分钟内没有新进展,PM 需要 ping 对应角色确认状态。连续两次无响应则考虑转派任务或上报 human。这确保任务不会因角色掉线或卡住而停滞。`,
|
|
185
|
+
mergeRules: '# 🚨 代码合并与发布规则(全角色必须遵守)',
|
|
186
|
+
mergeRulesContent: `- **Dev 严禁直接 push 到 main** — 所有代码必须通过 PR + reviewer review 流程
|
|
187
|
+
- **Dev 严禁自己打 tag** — tag 只能由 PM 或 reviewer 合并后打
|
|
188
|
+
- **Dev 完成后必须 ROUTE 给 reviewer** — 不 ROUTE 等于没完成,消息无法传递
|
|
189
|
+
- **即使是小修复(一行改动),也必须走 PR + review 流程**
|
|
190
|
+
- **合并和打 tag 由 reviewer 或 PM 执行**,dev 不自己合并`,
|
|
191
|
+
taskSplitRules: '# 任务拆分原则',
|
|
192
|
+
taskSplitRulesContent: `- **不相干的修改必须分给不同的 dev,产出独立的 PR**。严禁把两个不相关的 bug fix / feature 放在同一个 PR 中。
|
|
193
|
+
- 即使两个改动看似相关(如同一个 bug 的两个方面),如果它们改的文件不同、逻辑独立,也应该拆成独立 task + 独立 PR。
|
|
194
|
+
- 原因:混合 PR 无法单独 revert,也无法单独合并其中一个改动。一个改动被 block 会导致另一个也无法合并。`,
|
|
183
195
|
stuckRules: '# 卡住上报规则',
|
|
184
196
|
stuckRulesContent: `当你遇到以下情况时,不要自己空转或反复重试,立即 ROUTE 给 PM(pm)请求协调:
|
|
185
197
|
1. 缺少前置依赖(如需要的文件、目录、代码不存在)
|
|
@@ -425,7 +437,19 @@ After development is complete, send two ROUTE blocks simultaneously to ${revName
|
|
|
425
437
|
workConventions: '# Work Conventions',
|
|
426
438
|
workConventionsContent: `- Write documentation output to .crew/context/ directory
|
|
427
439
|
- Record important decisions in .crew/context/decisions.md
|
|
428
|
-
- Use the project code path (absolute path) for code changes
|
|
440
|
+
- Use the project code path (absolute path) for code changes
|
|
441
|
+
- **PM Delegation-First**: When PM receives bug reports or technical issues, do not analyze code yourself. Forward to an idle dev for root cause analysis and proposed solution. PM waits for the analysis, then makes judgment and decisions.
|
|
442
|
+
- **PM Task Progress Polling**: After assigning tasks, PM must check task progress every 3-5 minutes (read feature files and kanban). If a role has no new progress within 5 minutes, PM pings the role to confirm status. Two consecutive no-responses → consider reassigning or escalating to human.`,
|
|
443
|
+
mergeRules: '# 🚨 Code Merge & Release Rules (All roles must follow)',
|
|
444
|
+
mergeRulesContent: `- **Dev must never push directly to main** — All code must go through PR + reviewer review workflow
|
|
445
|
+
- **Dev must never create tags** — Tags can only be created by PM or reviewer after merge
|
|
446
|
+
- **Dev must ROUTE to reviewer after completion** — Not ROUTEing = work not delivered, message cannot be passed
|
|
447
|
+
- **Even small fixes (single-line changes) must go through PR + review workflow**
|
|
448
|
+
- **Merge and tagging are done by reviewer or PM** — dev does not merge themselves`,
|
|
449
|
+
taskSplitRules: '# Task Split Principles',
|
|
450
|
+
taskSplitRulesContent: `- **Unrelated changes must go to different devs with independent PRs**. Never put two unrelated bug fixes / features in the same PR.
|
|
451
|
+
- Even if two changes seem related (e.g., two aspects of the same bug), if they modify different files and have independent logic, they should be split into independent tasks + independent PRs.
|
|
452
|
+
- Reason: Mixed PRs cannot be individually reverted, nor can one change be merged independently. One blocked change prevents the other from merging.`,
|
|
429
453
|
stuckRules: '# Escalation Rules',
|
|
430
454
|
stuckRulesContent: `When you encounter the following situations, do not spin or retry repeatedly — immediately ROUTE to PM (pm) for coordination:
|
|
431
455
|
1. Missing prerequisites (required files, directories, or code don't exist)
|
package/package.json
CHANGED
package/unify/web-bridge.js
CHANGED
|
@@ -23,6 +23,9 @@ let session = null;
|
|
|
23
23
|
/** @type {AbortController | null} */
|
|
24
24
|
let currentAbort = null;
|
|
25
25
|
|
|
26
|
+
/** Query timeout in ms — abort if LLM doesn't respond within this window */
|
|
27
|
+
const QUERY_TIMEOUT_MS = 120_000;
|
|
28
|
+
|
|
26
29
|
/** Virtual conversationId for the Unify session */
|
|
27
30
|
let unifyConversationId = null;
|
|
28
31
|
|
|
@@ -100,12 +103,29 @@ export async function handleUnifyChat(msg) {
|
|
|
100
103
|
|
|
101
104
|
currentAbort = new AbortController();
|
|
102
105
|
|
|
106
|
+
// ─── Timeout guard: abort query if LLM hangs beyond threshold ──
|
|
107
|
+
// Resets on every event — fires only after prolonged silence.
|
|
108
|
+
let queryTimer = null;
|
|
109
|
+
const resetQueryTimer = () => {
|
|
110
|
+
if (queryTimer) clearTimeout(queryTimer);
|
|
111
|
+
queryTimer = setTimeout(() => {
|
|
112
|
+
if (currentAbort) {
|
|
113
|
+
console.error(`[Unify] query timeout after ${QUERY_TIMEOUT_MS / 1000}s of silence — aborting`);
|
|
114
|
+
currentAbort.abort();
|
|
115
|
+
}
|
|
116
|
+
}, QUERY_TIMEOUT_MS);
|
|
117
|
+
};
|
|
118
|
+
resetQueryTimer();
|
|
119
|
+
|
|
120
|
+
try {
|
|
103
121
|
// ─── Stream Engine events → claude_output format ──
|
|
104
122
|
for await (const event of session.engine.query({
|
|
105
123
|
prompt,
|
|
106
124
|
mode: currentMode,
|
|
107
125
|
signal: currentAbort.signal,
|
|
108
126
|
})) {
|
|
127
|
+
// Reset timeout on every event — activity means the query is alive
|
|
128
|
+
resetQueryTimer();
|
|
109
129
|
switch (event.type) {
|
|
110
130
|
// ── Text streaming ──
|
|
111
131
|
case 'text_delta':
|
|
@@ -261,9 +281,29 @@ export async function handleUnifyChat(msg) {
|
|
|
261
281
|
result_text: '',
|
|
262
282
|
});
|
|
263
283
|
|
|
284
|
+
} finally {
|
|
285
|
+
// Always clear the timeout guard
|
|
286
|
+
if (queryTimer) clearTimeout(queryTimer);
|
|
287
|
+
}
|
|
288
|
+
|
|
264
289
|
} catch (err) {
|
|
265
|
-
// Don't report abort errors
|
|
266
|
-
if (err.name === 'AbortError')
|
|
290
|
+
// Don't report abort errors — but still send result to unblock frontend
|
|
291
|
+
if (err.name === 'AbortError') {
|
|
292
|
+
sendUnifyOutput({
|
|
293
|
+
type: 'assistant',
|
|
294
|
+
message: {
|
|
295
|
+
content: [{
|
|
296
|
+
type: 'text',
|
|
297
|
+
text: '⚠️ Query timed out — no response from LLM. Please try again.',
|
|
298
|
+
}],
|
|
299
|
+
},
|
|
300
|
+
});
|
|
301
|
+
sendUnifyOutput({
|
|
302
|
+
type: 'result',
|
|
303
|
+
result_text: '',
|
|
304
|
+
});
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
267
307
|
|
|
268
308
|
console.error('[Unify] query error:', err.message);
|
|
269
309
|
sendUnifyOutput({
|