add-coder 0.3.26 → 0.3.28
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 +282 -155
- package/dist/index.js +481 -209
- package/package.json +15 -4
- package/templates/.add-coder-src-hash.json +186 -185
- package/templates/adapters/claude/hooks/doc-format-guard.ts +32 -0
- package/templates/adapters/claude/hooks/lib/claude-env.ts +7 -0
- package/templates/adapters/claude/hooks/notification.ts +24 -0
- package/templates/adapters/claude/hooks/permission-denied.ts +33 -0
- package/templates/adapters/claude/hooks/permission-gate.ts +12 -0
- package/templates/adapters/claude/hooks/post-tool-failure.ts +4 -0
- package/templates/adapters/claude/hooks/post-tool-use.ts +17 -0
- package/templates/adapters/claude/hooks/pre-compact.ts +10 -0
- package/templates/adapters/claude/hooks/pre-tool-use.ts +81 -0
- package/templates/adapters/claude/hooks/prompt-submit.ts +82 -0
- package/templates/adapters/claude/hooks/review-checklist.ts +4 -0
- package/templates/adapters/claude/hooks/session-end.ts +10 -0
- package/templates/adapters/claude/hooks/session-start.ts +24 -0
- package/templates/adapters/claude/hooks/stop-check.ts +15 -0
- package/templates/adapters/claude/hooks/stop-failure.ts +34 -0
- package/templates/adapters/claude/hooks/subagent-guard.ts +25 -0
- package/templates/adapters/claude/hooks/subagent-stop.ts +12 -0
- package/templates/adapters/claude/settings.json +13 -13
- package/templates/adapters/codex/config.toml.example +12 -0
- package/templates/adapters/codex/hooks/doc-format-guard.ts +30 -0
- package/templates/adapters/codex/hooks/notification.ts +26 -0
- package/templates/adapters/codex/hooks/permission-gate.ts +15 -0
- package/templates/adapters/codex/hooks/post-tool-failure.ts +14 -0
- package/templates/adapters/codex/hooks/post-tool-use.ts +85 -0
- package/templates/adapters/codex/hooks/pre-compact.ts +20 -0
- package/templates/adapters/codex/hooks/pre-tool-use.ts +141 -0
- package/templates/adapters/codex/hooks/prompt-submit.ts +38 -0
- package/templates/adapters/codex/hooks/review-checklist.ts +5 -0
- package/templates/adapters/codex/hooks/session-end.ts +19 -0
- package/templates/adapters/codex/hooks/session-start.ts +45 -0
- package/templates/adapters/codex/hooks/stop-check.ts +59 -0
- package/templates/adapters/codex/hooks/subagent-guard.ts +22 -0
- package/templates/adapters/codex/hooks/subagent-stop.ts +20 -0
- package/templates/adapters/codex/hooks.json +67 -1
- package/templates/adapters/qoder/hooks/doc-format-guard.ts +34 -0
- package/templates/adapters/qoder/hooks/lib/context-inject.ts +61 -0
- package/templates/adapters/qoder/hooks/lib/qoder-env.ts +23 -0
- package/templates/adapters/qoder/hooks/lib/review-checklist.ts +5 -0
- package/templates/adapters/qoder/hooks/notification.ts +34 -0
- package/templates/adapters/qoder/hooks/permission-gate.ts +26 -0
- package/templates/adapters/qoder/hooks/post-tool-failure.ts +30 -0
- package/templates/adapters/qoder/hooks/post-tool-use.ts +32 -0
- package/templates/adapters/qoder/hooks/pre-compact.ts +16 -0
- package/templates/adapters/qoder/hooks/pre-tool-use.ts +112 -0
- package/templates/adapters/qoder/hooks/prompt-submit.ts +66 -0
- package/templates/adapters/qoder/hooks/review-checklist.ts +24 -0
- package/templates/adapters/qoder/hooks/session-end.ts +27 -0
- package/templates/adapters/qoder/hooks/session-start.ts +83 -0
- package/templates/adapters/qoder/hooks/stop-check.ts +69 -0
- package/templates/adapters/qoder/hooks/subagent-guard.ts +16 -0
- package/templates/adapters/qoder/hooks/subagent-stop.ts +33 -0
- package/templates/adapters/qoder/settings.json +13 -13
- package/templates/adapters/trae/hooks/doc-format-guard.ts +30 -0
- package/templates/adapters/trae/hooks/notification.ts +22 -0
- package/templates/adapters/trae/hooks/permission-gate.ts +15 -0
- package/templates/adapters/trae/hooks/post-tool-failure.ts +14 -0
- package/templates/adapters/trae/hooks/post-tool-use.ts +24 -0
- package/templates/adapters/trae/hooks/pre-compact.ts +15 -0
- package/templates/adapters/trae/hooks/pre-tool-use.ts +40 -0
- package/templates/adapters/trae/hooks/prompt-submit.ts +29 -0
- package/templates/adapters/trae/hooks/review-checklist.ts +5 -0
- package/templates/adapters/trae/hooks/session-end.ts +16 -0
- package/templates/adapters/trae/hooks/session-start.ts +15 -0
- package/templates/adapters/trae/hooks/stop-check.ts +20 -0
- package/templates/adapters/trae/hooks/subagent-guard.ts +22 -0
- package/templates/adapters/trae/hooks/subagent-stop.ts +15 -0
- package/templates/adapters/trae/hooks.json +1 -1
- package/templates/adapters/vscode/hooks/doc-format-guard.ts +27 -0
- package/templates/adapters/vscode/hooks/notification.ts +22 -0
- package/templates/adapters/vscode/hooks/permission-gate.ts +15 -0
- package/templates/adapters/vscode/hooks/post-tool-failure.ts +32 -0
- package/templates/adapters/vscode/hooks/post-tool-use.ts +25 -0
- package/templates/adapters/vscode/hooks/pre-compact.ts +15 -0
- package/templates/adapters/vscode/hooks/pre-tool-use.ts +78 -0
- package/templates/adapters/vscode/hooks/prompt-submit.ts +74 -0
- package/templates/adapters/vscode/hooks/review-checklist.ts +5 -0
- package/templates/adapters/vscode/hooks/session-end.ts +16 -0
- package/templates/adapters/vscode/hooks/session-start.ts +24 -0
- package/templates/adapters/vscode/hooks/stop-check.ts +21 -0
- package/templates/adapters/vscode/hooks/subagent-guard.ts +21 -0
- package/templates/adapters/vscode/hooks/subagent-stop.ts +15 -0
- package/templates/core/docs/ADD-governance-claude-code.md +4 -4
- package/templates/core/docs/ADD-governance-codex.md +6 -6
- package/templates/core/docs/ADD-governance-qoder-cn.md +5 -5
- package/templates/core/docs/ADD-governance-trae.md +3 -3
- package/templates/core/docs/ADD-governance-vscode-copilot.md +22 -23
- package/templates/core/governance/audit-bridge.ts +47 -0
- package/templates/core/governance/common.ts +299 -0
- package/templates/core/governance/context-inject.ts +53 -0
- package/templates/core/governance/doc-format-guard.ts +440 -0
- package/templates/core/governance/notification-router.ts +62 -0
- package/templates/core/governance/notify.ts +66 -0
- package/templates/core/governance/permission-gate-router.ts +42 -0
- package/templates/core/governance/post-tool-failure-router.ts +56 -0
- package/templates/core/governance/post-tool-router.ts +212 -0
- package/templates/core/governance/pre-compact-guard.ts +41 -0
- package/templates/core/governance/pre-tool-guard.ts +309 -0
- package/templates/core/governance/preload-templates.ts +241 -0
- package/templates/core/governance/prompt-router.ts +222 -0
- package/templates/core/governance/review-checklist-guard.ts +186 -0
- package/templates/core/governance/rules.ts +720 -0
- package/templates/core/governance/session-end.ts +88 -0
- package/templates/core/governance/session-start-guard.ts +99 -0
- package/templates/core/governance/state-detect.ts +6 -0
- package/templates/core/governance/stop-router.ts +140 -0
- package/templates/core/governance/subagent-guard-router.ts +35 -0
- package/templates/core/governance/subagent-stop-router.ts +93 -0
- package/templates/core/governance/subagent-stop.ts +75 -0
- package/templates/core/governance/vocabulary.ts +109 -0
- package/templates/core/hooks/doc-format-guard.ts +21 -0
- package/templates/core/hooks/notification.ts +11 -0
- package/templates/core/hooks/permission-gate.ts +7 -0
- package/templates/core/hooks/post-tool-failure.ts +7 -0
- package/templates/core/hooks/post-tool-use.ts +23 -0
- package/templates/core/hooks/pre-compact.ts +9 -0
- package/templates/core/hooks/pre-tool-use.ts +30 -0
- package/templates/core/hooks/prompt-submit.ts +11 -0
- package/templates/core/hooks/review-checklist.ts +4 -0
- package/templates/core/hooks/session-end.ts +10 -0
- package/templates/core/hooks/session-start.ts +9 -0
- package/templates/core/hooks/stop-check.ts +14 -0
- package/templates/core/hooks/subagent-guard.ts +8 -0
- package/templates/core/hooks/subagent-stop.ts +9 -0
- package/templates/core/prisma/add.prisma +140 -82
- package/templates/core/rules/project_rules.md +27 -24
- package/templates/core/scripts/db-ensure.sh +8 -0
- package/templates/core/scripts/gen-plan-index.sh +4 -15
- package/templates/core/scripts/mcp-server/notifications/hitl.ts +9 -1
- package/templates/core/scripts/mcp-server/notifications/hook.ts +25 -9
- package/templates/core/scripts/mcp-server/resources/hitl-approval-widget.ts +34 -0
- package/templates/core/scripts/mcp-server/resources/hook-events-report.ts +14 -2
- package/templates/core/scripts/mcp-server/resources/index.ts +2 -0
- package/templates/core/scripts/mcp-server/sampling/review.ts +25 -10
- package/templates/core/scripts/mcp-server/shared/db-types.ts +33 -8
- package/templates/core/scripts/mcp-server/shared/dps-scoring.strategy.ts +1 -1
- package/templates/core/scripts/mcp-server/shared/env.ts +28 -8
- package/templates/core/scripts/mcp-server/shared/fs.ts +3 -0
- package/templates/core/scripts/mcp-server/shared/hitl-interaction.strategy.ts +2 -3
- package/templates/core/scripts/mcp-server/shared/hitl-lifecycle-mutation.ts +129 -0
- package/templates/core/scripts/mcp-server/shared/hitl-proposal-mutation.ts +98 -0
- package/templates/core/scripts/mcp-server/shared/hitl-ui.ts +3 -0
- package/templates/core/scripts/mcp-server/shared/plan-lifecycle-events.ts +62 -0
- package/templates/core/scripts/mcp-server/shared/plan-lifecycle-mutation.ts +78 -0
- package/templates/core/scripts/mcp-server/shared/plan-lifecycle-subscriber.ts +145 -0
- package/templates/core/scripts/mcp-server/shared/plan-lifecycle.ts +153 -0
- package/templates/core/scripts/mcp-server/shared/plan-round-events.ts +56 -0
- package/templates/core/scripts/mcp-server/shared/plan-round-mutation.ts +143 -0
- package/templates/core/scripts/mcp-server/shared/plan-round-store.ts +47 -0
- package/templates/core/scripts/mcp-server/shared/plan-round-subscriber.ts +99 -0
- package/templates/core/scripts/mcp-server/shared/plan-status-store.ts +37 -0
- package/templates/core/scripts/mcp-server/shared/plan-tracking-mutation.ts +71 -0
- package/templates/core/scripts/mcp-server/shared/prisma.ts +12 -6
- package/templates/core/scripts/mcp-server/shared/project-root-strategy.ts +1 -2
- package/templates/core/scripts/mcp-server/shared/quant-recheck.strategy.ts +16 -0
- package/templates/core/scripts/mcp-server/shared/redact.ts +28 -0
- package/templates/core/scripts/mcp-server/shared/response.ts +3 -2
- package/templates/core/scripts/mcp-server/shared/runtime-context.ts +77 -0
- package/templates/core/scripts/mcp-server/shared/schema-topology.ts +159 -0
- package/templates/core/scripts/mcp-server/tools/audit.ts +49 -7
- package/templates/core/scripts/mcp-server/tools/context.ts +117 -121
- package/templates/core/scripts/mcp-server/tools/contract.ts +34 -9
- package/templates/core/scripts/mcp-server/tools/gateway/check_add_route_status.ts +50 -3
- package/templates/core/scripts/mcp-server/tools/gateway/check_doc_similarity.ts +218 -0
- package/templates/core/scripts/mcp-server/tools/gateway/check_dps.ts +22 -7
- package/templates/core/scripts/mcp-server/tools/gateway/check_rahs.ts +86 -4
- package/templates/core/scripts/mcp-server/tools/gateway/check_spec_sync.ts +19 -6
- package/templates/core/scripts/mcp-server/tools/gateway/index.ts +2 -0
- package/templates/core/scripts/mcp-server/tools/hitl.ts +160 -75
- package/templates/core/scripts/mcp-server/tools/hook-event-report.ts +9 -2
- package/templates/core/scripts/mcp-server/tools/index.ts +69 -3
- package/templates/core/scripts/mcp-server/tools/plan.ts +152 -17
- package/templates/core/scripts/mcp-server/tools/review.ts +44 -15
- package/templates/core/scripts/mcp-server.ts +60 -1
- package/templates/core/scripts/plan-status-bridge.ts +26 -0
- package/templates/core/skills/add-paradigm/SKILL.md +2 -2
- package/templates/core/templates/add-route-template.schema.json +24 -56
- package/templates/core/templates/collab-contract-template.md +1 -1
- package/templates/core/templates/handoff-multi-round-template.schema.json +48 -0
- package/templates/core/templates/handoff-single-round-template.schema.json +92 -0
- package/templates/core/templates/handoff-single-round.schema.json +1 -1
- package/templates/core/templates/hitl-approval-widget.html +222 -37
- package/templates/core/templates/spec-template.schema.json +9 -46
- package/templates/core/templates/standard-plan-template.schema.json +1 -1
- package/templates/core/templates/tasks-template.schema.json +13 -54
- package/templates/adapters/claude/hooks/doc-format-guard.sh +0 -202
- package/templates/adapters/claude/hooks/lib/common.sh +0 -261
- package/templates/adapters/claude/hooks/lib/context-inject.sh +0 -96
- package/templates/adapters/claude/hooks/lib/notify.sh +0 -34
- package/templates/adapters/claude/hooks/lib/preload-templates.sh +0 -187
- package/templates/adapters/claude/hooks/lib/session-end.sh +0 -76
- package/templates/adapters/claude/hooks/lib/state-detect.sh +0 -117
- package/templates/adapters/claude/hooks/lib/subagent-stop.sh +0 -90
- package/templates/adapters/claude/hooks/lib/vocabulary.sh +0 -56
- package/templates/adapters/claude/hooks/notification.sh +0 -45
- package/templates/adapters/claude/hooks/permission-denied.sh +0 -42
- package/templates/adapters/claude/hooks/permission-gate.sh +0 -18
- package/templates/adapters/claude/hooks/post-tool-failure.sh +0 -10
- package/templates/adapters/claude/hooks/post-tool-use.sh +0 -35
- package/templates/adapters/claude/hooks/pre-compact.sh +0 -37
- package/templates/adapters/claude/hooks/pre-tool-use.sh +0 -153
- package/templates/adapters/claude/hooks/prompt-submit.sh +0 -99
- package/templates/adapters/claude/hooks/review-checklist.sh +0 -10
- package/templates/adapters/claude/hooks/session-end.sh +0 -21
- package/templates/adapters/claude/hooks/session-start.sh +0 -36
- package/templates/adapters/claude/hooks/stop-check.sh +0 -45
- package/templates/adapters/claude/hooks/stop-failure.sh +0 -44
- package/templates/adapters/claude/hooks/subagent-guard.sh +0 -36
- package/templates/adapters/claude/hooks/subagent-stop.sh +0 -20
- package/templates/adapters/codex/hooks/doc-format-guard.sh +0 -261
- package/templates/adapters/codex/hooks/lib/common.sh +0 -261
- package/templates/adapters/codex/hooks/lib/context-inject.sh +0 -96
- package/templates/adapters/codex/hooks/lib/notify.sh +0 -34
- package/templates/adapters/codex/hooks/lib/preload-templates.sh +0 -187
- package/templates/adapters/codex/hooks/lib/session-end.sh +0 -76
- package/templates/adapters/codex/hooks/lib/state-detect.sh +0 -117
- package/templates/adapters/codex/hooks/lib/subagent-stop.sh +0 -90
- package/templates/adapters/codex/hooks/lib/vocabulary.sh +0 -56
- package/templates/adapters/codex/hooks/notification.sh +0 -45
- package/templates/adapters/codex/hooks/permission-gate.sh +0 -18
- package/templates/adapters/codex/hooks/post-tool-failure.sh +0 -10
- package/templates/adapters/codex/hooks/post-tool-use.sh +0 -138
- package/templates/adapters/codex/hooks/pre-compact.sh +0 -37
- package/templates/adapters/codex/hooks/pre-tool-use.sh +0 -217
- package/templates/adapters/codex/hooks/prompt-submit.sh +0 -87
- package/templates/adapters/codex/hooks/review-checklist.sh +0 -10
- package/templates/adapters/codex/hooks/session-end.sh +0 -38
- package/templates/adapters/codex/hooks/session-start.sh +0 -53
- package/templates/adapters/codex/hooks/stop-check.sh +0 -45
- package/templates/adapters/codex/hooks/subagent-guard.sh +0 -15
- package/templates/adapters/codex/hooks/subagent-stop.sh +0 -47
- package/templates/adapters/qoder/hooks/doc-format-guard.sh +0 -260
- package/templates/adapters/qoder/hooks/lib/common.sh +0 -261
- package/templates/adapters/qoder/hooks/lib/context-inject.sh +0 -96
- package/templates/adapters/qoder/hooks/lib/notify.sh +0 -34
- package/templates/adapters/qoder/hooks/lib/preload-templates.sh +0 -187
- package/templates/adapters/qoder/hooks/lib/session-end.sh +0 -76
- package/templates/adapters/qoder/hooks/lib/state-detect.sh +0 -117
- package/templates/adapters/qoder/hooks/lib/subagent-stop.sh +0 -90
- package/templates/adapters/qoder/hooks/lib/vocabulary.sh +0 -56
- package/templates/adapters/qoder/hooks/notification.sh +0 -25
- package/templates/adapters/qoder/hooks/permission-gate.sh +0 -8
- package/templates/adapters/qoder/hooks/post-tool-failure.sh +0 -8
- package/templates/adapters/qoder/hooks/post-tool-use.sh +0 -121
- package/templates/adapters/qoder/hooks/pre-compact.sh +0 -37
- package/templates/adapters/qoder/hooks/pre-tool-use.sh +0 -154
- package/templates/adapters/qoder/hooks/prompt-submit.sh +0 -96
- package/templates/adapters/qoder/hooks/review-checklist.sh +0 -157
- package/templates/adapters/qoder/hooks/session-end.sh +0 -24
- package/templates/adapters/qoder/hooks/session-start.sh +0 -45
- package/templates/adapters/qoder/hooks/stop-check.sh +0 -48
- package/templates/adapters/qoder/hooks/subagent-guard.sh +0 -27
- package/templates/adapters/qoder/hooks/subagent-stop.sh +0 -26
- package/templates/adapters/trae/hooks/doc-format-guard.sh +0 -261
- package/templates/adapters/trae/hooks/lib/common.sh +0 -261
- package/templates/adapters/trae/hooks/lib/context-inject.sh +0 -96
- package/templates/adapters/trae/hooks/lib/notify.sh +0 -34
- package/templates/adapters/trae/hooks/lib/preload-templates.sh +0 -187
- package/templates/adapters/trae/hooks/lib/session-end.sh +0 -76
- package/templates/adapters/trae/hooks/lib/state-detect.sh +0 -117
- package/templates/adapters/trae/hooks/lib/subagent-stop.sh +0 -90
- package/templates/adapters/trae/hooks/lib/vocabulary.sh +0 -56
- package/templates/adapters/trae/hooks/notification.sh +0 -45
- package/templates/adapters/trae/hooks/permission-gate.sh +0 -18
- package/templates/adapters/trae/hooks/post-tool-failure.sh +0 -10
- package/templates/adapters/trae/hooks/post-tool-use.sh +0 -138
- package/templates/adapters/trae/hooks/pre-compact.sh +0 -37
- package/templates/adapters/trae/hooks/pre-tool-use.sh +0 -217
- package/templates/adapters/trae/hooks/prompt-submit.sh +0 -87
- package/templates/adapters/trae/hooks/review-checklist.sh +0 -10
- package/templates/adapters/trae/hooks/session-end.sh +0 -38
- package/templates/adapters/trae/hooks/session-start.sh +0 -53
- package/templates/adapters/trae/hooks/stop-check.sh +0 -45
- package/templates/adapters/trae/hooks/subagent-guard.sh +0 -15
- package/templates/adapters/trae/hooks/subagent-stop.sh +0 -47
- package/templates/adapters/vscode/hooks/doc-format-guard.sh +0 -201
- package/templates/adapters/vscode/hooks/lib/common.sh +0 -261
- package/templates/adapters/vscode/hooks/lib/context-inject.sh +0 -96
- package/templates/adapters/vscode/hooks/lib/notify.sh +0 -34
- package/templates/adapters/vscode/hooks/lib/preload-templates.sh +0 -187
- package/templates/adapters/vscode/hooks/lib/session-end.sh +0 -76
- package/templates/adapters/vscode/hooks/lib/state-detect.sh +0 -117
- package/templates/adapters/vscode/hooks/lib/subagent-stop.sh +0 -90
- package/templates/adapters/vscode/hooks/lib/vocabulary.sh +0 -56
- package/templates/adapters/vscode/hooks/notification.sh +0 -45
- package/templates/adapters/vscode/hooks/permission-gate.sh +0 -18
- package/templates/adapters/vscode/hooks/post-tool-failure.sh +0 -28
- package/templates/adapters/vscode/hooks/post-tool-use.sh +0 -35
- package/templates/adapters/vscode/hooks/pre-compact.sh +0 -37
- package/templates/adapters/vscode/hooks/pre-tool-use.sh +0 -153
- package/templates/adapters/vscode/hooks/prompt-submit.sh +0 -99
- package/templates/adapters/vscode/hooks/review-checklist.sh +0 -10
- package/templates/adapters/vscode/hooks/session-end.sh +0 -13
- package/templates/adapters/vscode/hooks/session-start.sh +0 -35
- package/templates/adapters/vscode/hooks/stop-check.sh +0 -53
- package/templates/adapters/vscode/hooks/subagent-guard.sh +0 -37
- package/templates/adapters/vscode/hooks/subagent-stop.sh +0 -12
- package/templates/core/hooks/doc-format-guard.sh +0 -261
- package/templates/core/hooks/lib/common.sh +0 -261
- package/templates/core/hooks/lib/context-inject.sh +0 -96
- package/templates/core/hooks/lib/notify.sh +0 -34
- package/templates/core/hooks/lib/preload-templates.sh +0 -187
- package/templates/core/hooks/lib/session-end.sh +0 -76
- package/templates/core/hooks/lib/state-detect.sh +0 -117
- package/templates/core/hooks/lib/subagent-stop.sh +0 -90
- package/templates/core/hooks/lib/vocabulary.sh +0 -56
- package/templates/core/hooks/notification.sh +0 -45
- package/templates/core/hooks/permission-gate.sh +0 -18
- package/templates/core/hooks/post-tool-failure.sh +0 -10
- package/templates/core/hooks/post-tool-use.sh +0 -138
- package/templates/core/hooks/pre-compact.sh +0 -37
- package/templates/core/hooks/pre-tool-use.sh +0 -217
- package/templates/core/hooks/prompt-submit.sh +0 -87
- package/templates/core/hooks/review-checklist.sh +0 -10
- package/templates/core/hooks/session-end.sh +0 -38
- package/templates/core/hooks/session-start.sh +0 -53
- package/templates/core/hooks/stop-check.sh +0 -45
- package/templates/core/hooks/subagent-guard.sh +0 -15
- package/templates/core/hooks/subagent-stop.sh +0 -47
- package/templates/shared/hooks-lib/common.sh +0 -22
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// notification.ts — Notification 入口(Qoder CN 版,Task 4.1 继承体系补全)
|
|
2
|
+
// 继承 core NotificationRouter,命名子类 QoderNotificationRouter:
|
|
3
|
+
// ① 兜底 magicDir = ".qoder"(构造参数注入——替代 bash 硬编码 ${PROJECT_DIR}/.qoder/reviews)
|
|
4
|
+
// ② emitReminder override: 无 Plan 前缀(qoder bash 原文逐字「[ADD Notification] 请检查 Review 文档」,
|
|
5
|
+
// 与 core 的 Plan 前缀文本差异保留——非能力漂移,qoder bash 原文如此)
|
|
6
|
+
// ③ 输出通道: stdout(qoder bash 原文 echo 无 >&2 重定向——违反 qoder JSON 规范但缺陷照搬,
|
|
7
|
+
// 归 Task 9.4 缺陷修复专项)
|
|
8
|
+
// 协议差异仅剩: PROJECT_DIR 注入链(qoder-env)
|
|
9
|
+
|
|
10
|
+
import { readHookInput } from "../../../core/governance/common.js"
|
|
11
|
+
import { NotificationRouter } from "../../../core/governance/notification-router.js"
|
|
12
|
+
import { injectProjectDir } from "./lib/qoder-env.js"
|
|
13
|
+
|
|
14
|
+
class QoderNotificationRouter extends NotificationRouter {
|
|
15
|
+
/** 协议差异封装: fallbackMagicDir = ".qoder"(qoder 端兜底,bash 原文硬编码语义) */
|
|
16
|
+
constructor(projectDir: string) {
|
|
17
|
+
super(projectDir, ".qoder")
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** ① qoder bash 原文硬编码 ${PROJECT_DIR}/.qoder/reviews——无跨端探测循环(协议差异,不做探测) */
|
|
21
|
+
protected override resolveMagicDir(): string {
|
|
22
|
+
return process.env.MAGIC_DIR ?? ".qoder"
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** ② qoder 提醒文本: 无 Plan 前缀(bash 原文逐字) */
|
|
26
|
+
protected override emitReminder(_plan: string, reviewsDir: string): void {
|
|
27
|
+
process.stdout.write(`[ADD Notification] 请检查 Review 文档: ${reviewsDir}\n`)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const input = readHookInput()
|
|
32
|
+
const PROJECT_DIR = injectProjectDir()
|
|
33
|
+
|
|
34
|
+
process.exit(new QoderNotificationRouter(PROJECT_DIR).run(input))
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// permission-gate.ts — PermissionRequest 入口(Qoder CN 版,Task 4.1 继承体系补全)
|
|
2
|
+
// 继承 core PermissionGateRouter,命名子类 QoderPermissionGateRouter:
|
|
3
|
+
// ① emit override: 全量工具 stderr 日志(qoder bash 原文无条件输出——
|
|
4
|
+
// qoder 权限弹窗自行处理 Review 卡位;core 是仅高风险工具 stdout 提示)
|
|
5
|
+
|
|
6
|
+
import { readHookInput, tryResolveMagicDir } from "../../../core/governance/common.js"
|
|
7
|
+
import { PermissionGateRouter } from "../../../core/governance/permission-gate-router.js"
|
|
8
|
+
|
|
9
|
+
class QoderPermissionGateRouter extends PermissionGateRouter {
|
|
10
|
+
/** ① tool_name 缺失回退 "unknown"(bash jq `// \"unknown\"` 语义) */
|
|
11
|
+
protected override fallbackToolName(): string {
|
|
12
|
+
return "unknown"
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** ② qoder 协议: 全量工具 stderr 日志(bash 原文逐字) */
|
|
16
|
+
protected override emit(toolName: string): void {
|
|
17
|
+
process.stderr.write(`[ADD PermissionRequest] 工具 ${toolName} 请求权限。如有 Review 文档待确认,请先检查。\n`)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// 对齐 bash: MAGIC_DIR 由物理位置推导注入(替代 HOOK_DIR 局部变量 source 传递)
|
|
22
|
+
const inferred = tryResolveMagicDir()
|
|
23
|
+
if (inferred && !process.env.MAGIC_DIR) process.env.MAGIC_DIR = inferred
|
|
24
|
+
|
|
25
|
+
const input = readHookInput()
|
|
26
|
+
process.exit(new QoderPermissionGateRouter().run(input))
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// post-tool-failure.ts — PostToolUseFailure 入口(Qoder CN 版,Task 4.1 继承体系补全)
|
|
2
|
+
// 继承 core PostToolFailureRouter,命名子类 QoderPostToolFailureRouter:
|
|
3
|
+
// ① emit override: stderr 回退建议(qoder bash 原文逐字——
|
|
4
|
+
// 「检查是否需要回退到上一 ADD Step 重新执行」;core 是 stdout 固定提示)
|
|
5
|
+
|
|
6
|
+
import { readHookInput, tryResolveMagicDir } from "../../../core/governance/common.js"
|
|
7
|
+
import { PostToolFailureRouter } from "../../../core/governance/post-tool-failure-router.js"
|
|
8
|
+
|
|
9
|
+
class QoderPostToolFailureRouter extends PostToolFailureRouter {
|
|
10
|
+
/** ① tool_name/error 缺失回退 "unknown"(bash jq `// \"unknown\"` 语义) */
|
|
11
|
+
protected override fallbackToolName(): string {
|
|
12
|
+
return "unknown"
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
protected override fallbackError(): string {
|
|
16
|
+
return "unknown"
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** ② qoder 协议: stderr 回退建议(bash 原文逐字) */
|
|
20
|
+
protected override emit(toolName: string, error: string): void {
|
|
21
|
+
process.stderr.write(`[ADD PostToolUseFailure] 工具 ${toolName} 失败: ${error}。检查是否需要回退到上一 ADD Step 重新执行。\n`)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 对齐 bash: MAGIC_DIR 由物理位置推导注入
|
|
26
|
+
const inferred = tryResolveMagicDir()
|
|
27
|
+
if (inferred && !process.env.MAGIC_DIR) process.env.MAGIC_DIR = inferred
|
|
28
|
+
|
|
29
|
+
const input = readHookInput()
|
|
30
|
+
process.exit(new QoderPostToolFailureRouter().run(input))
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// post-tool-use.ts — PostToolUse 入口(Qoder CN 版,Task 4.1 能力演进)
|
|
2
|
+
// 继承 core PostToolRouter;协议能力实证(2026-08-14 Qoder 官方文档):
|
|
3
|
+
// Qoder PostToolUse 事件支持 stdout JSON,专属字段 hookSpecificOutput.feedback
|
|
4
|
+
// (「反馈信息,会展示给用户」)——qoder 输出通道用 feedback JSON(能力演进,
|
|
5
|
+
// 非收敛降级);段落能力(§1 DPS + §2a-e + §3)对齐 core 全段(此前 qoder §1
|
|
6
|
+
// 缺分支为 bash 时代漂移,已补齐)。
|
|
7
|
+
// 协议差异: 输出通道 collectJson=true(feedback JSON)+ PROJECT_DIR 注入链
|
|
8
|
+
|
|
9
|
+
import { jsonGet, readHookInput, tryResolveMagicDir } from "../../../core/governance/common.js"
|
|
10
|
+
import { PostToolRouter } from "../../../core/governance/post-tool-router.js"
|
|
11
|
+
import { injectProjectDir } from "./lib/qoder-env.js"
|
|
12
|
+
|
|
13
|
+
injectProjectDir()
|
|
14
|
+
const inferred = tryResolveMagicDir()
|
|
15
|
+
if (inferred && !process.env.MAGIC_DIR) process.env.MAGIC_DIR = inferred
|
|
16
|
+
const PROJECT_DIR = process.env.PROJECT_DIR || process.cwd()
|
|
17
|
+
const MAGIC_DIR = process.env.MAGIC_DIR || ".qoder"
|
|
18
|
+
|
|
19
|
+
class QoderPostToolRouter extends PostToolRouter {
|
|
20
|
+
/** 输出通道: feedback JSON(Qoder 文档实证 PostToolUse 专属字段) */
|
|
21
|
+
protected override collectJson(): boolean {
|
|
22
|
+
return true
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const input = readHookInput()
|
|
27
|
+
let toolName = jsonGet(input, "tool_name")
|
|
28
|
+
if (toolName === "") {
|
|
29
|
+
toolName = input.match(/"tool_name"\s*:\s*"([^"]*)"/)?.[1] ?? ""
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
process.exit(new QoderPostToolRouter(PROJECT_DIR, MAGIC_DIR).run(input, toolName))
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// pre-compact.ts — 上下文压缩前 ADD 状态保存(Qoder CN 版,Task 4.1 继承体系补全)
|
|
2
|
+
// 继承 core PreCompactGuard,命名子类 QoderPreCompactGuard:
|
|
3
|
+
// ① 状态保存到恢复标记 + ② tpl 标记清理 = 基类(与 qoder bash 原文逐字同构,
|
|
4
|
+
// 2026-08-14 实态核验——手写版逻辑与 core 基类完全一致,收敛为子类)
|
|
5
|
+
// 协议差异仅剩: PROJECT_DIR 注入链(qoder-env)
|
|
6
|
+
|
|
7
|
+
import { PreCompactGuard } from "../../../core/governance/pre-compact-guard.js"
|
|
8
|
+
import { injectProjectDir } from "./lib/qoder-env.js"
|
|
9
|
+
|
|
10
|
+
class QoderPreCompactGuard extends PreCompactGuard {
|
|
11
|
+
// 当前无 override(状态保存/恢复清单/tpl 清理与 core 基线一致);命名子类承载端身份 + 未来演进位
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
injectProjectDir()
|
|
15
|
+
|
|
16
|
+
process.exit(new QoderPreCompactGuard().run())
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// pre-tool-use.ts — PreToolUse 入口(Qoder CN 版,Task 4.1 继承体系)
|
|
2
|
+
// 继承 core PreToolUseGuard(模板方法固化治理流程);仅 override 协议差异(bash 原文逐字对照):
|
|
3
|
+
// ① 检测链: 构造传 adapterName="qoder" → 加载 [guard.adapter_detectors] qoder 独立链
|
|
4
|
+
// (与 claude 同构四段链,2026-08-14 实态核验)
|
|
5
|
+
// ② onBlock: stderr + stdout JSON deny(permissionDecision: deny)+ 事件 + exit 2(无 logBlock)
|
|
6
|
+
// ③ onSensitiveDeny: stderr + JSON deny + 事件 + exit 2(core 无事件上报)
|
|
7
|
+
// ④ onSectionAPass: Bash 放行 markDevAction(同 claude)
|
|
8
|
+
// ⑤ largeFileText: 「Qoder 40500」错误码提示(qoder IDE 特有)
|
|
9
|
+
// ⑥ onHitlDeny: JSON deny + additionalContext + exit 2 + event "ask"(core exit 0 + event "deny")
|
|
10
|
+
// ⑦ onOtherTool: ③ Read matcher 模板提示(同 claude)
|
|
11
|
+
|
|
12
|
+
import { jsonGet, readHookInput, tryResolveMagicDir } from "../../../core/governance/common.js"
|
|
13
|
+
import { writeHookEvent } from "../../../core/governance/notify.js"
|
|
14
|
+
import { PreToolUseGuard } from "../../../core/governance/pre-tool-guard.js"
|
|
15
|
+
import { markDevAction } from "../../../core/governance/common.js"
|
|
16
|
+
import { injectProjectDir } from "./lib/qoder-env.js"
|
|
17
|
+
|
|
18
|
+
injectProjectDir()
|
|
19
|
+
const inferred = tryResolveMagicDir()
|
|
20
|
+
if (inferred && !process.env.MAGIC_DIR) process.env.MAGIC_DIR = inferred
|
|
21
|
+
const PROJECT_DIR = process.env.PROJECT_DIR || process.cwd()
|
|
22
|
+
const MAGIC_DIR = process.env.MAGIC_DIR || ".qoder"
|
|
23
|
+
|
|
24
|
+
/** JSON deny 输出(Qoder PreToolUse 协议: permissionDecision deny) */
|
|
25
|
+
function denyJsonOut(reason: string): string {
|
|
26
|
+
return JSON.stringify({
|
|
27
|
+
hookSpecificOutput: {
|
|
28
|
+
hookEventName: "PreToolUse",
|
|
29
|
+
permissionDecision: "deny",
|
|
30
|
+
permissionDecisionReason: reason,
|
|
31
|
+
},
|
|
32
|
+
}) + "\n"
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
class QoderPreToolUseGuard extends PreToolUseGuard {
|
|
36
|
+
constructor(projectDir: string, magicDir: string) {
|
|
37
|
+
super(projectDir, magicDir, "qoder")
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** ② §A 阻断: stderr + JSON deny + 事件 + exit 2(无 logBlock) */
|
|
41
|
+
protected override onBlock(blocked: { reason: string; stderr: string }, command: string): number {
|
|
42
|
+
process.stderr.write(blocked.stderr.replaceAll("{{cmd}}", command))
|
|
43
|
+
process.stdout.write(denyJsonOut(blocked.reason))
|
|
44
|
+
writeHookEvent("pre-tool-use", "deny", command, blocked.reason, this.planKeyword, this.planStatus)
|
|
45
|
+
return 2
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** ③ §B 敏感文件: stderr + JSON deny + 事件 + exit 2 */
|
|
49
|
+
protected override onSensitiveDeny(filePath: string): number {
|
|
50
|
+
process.stderr.write(`⛔ 敏感文件受保护,禁止写入: ${filePath}\n`)
|
|
51
|
+
process.stdout.write(denyJsonOut("敏感文件受保护"))
|
|
52
|
+
writeHookEvent("pre-tool-use", "deny", filePath, "敏感文件受保护", this.planKeyword, this.planStatus)
|
|
53
|
+
return 2
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** ④ §A 放行后处理: bash 原文 mark_dev_action */
|
|
57
|
+
protected override onSectionAPass(_command: string): void {
|
|
58
|
+
markDevAction()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** ⑤ 大文件提示: Qoder 40500 错误码(qoder IDE 特有) */
|
|
62
|
+
protected override largeFileText(fsize: number): string {
|
|
63
|
+
return `⚠️ [ADD PreToolUse] 文件已有 ${fsize} 字节,Write 全量覆盖可能触发 Qoder 40500。建议用 SearchReplace 分块追加。\n`
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** ⑥ HITL 未 tongyi: JSON deny + additionalContext + exit 2 + event "ask" */
|
|
67
|
+
protected override onHitlDeny(toolName: string, filePath: string, tongyiMarker: string): number {
|
|
68
|
+
process.stderr.write(`⛔ [ADD PreToolUse §C] HITL 未 tongyi: ${filePath}\n`)
|
|
69
|
+
process.stderr.write(` 原因: 哨兵文件 ${tongyiMarker} 不存在\n`)
|
|
70
|
+
process.stderr.write(` 操作: 请先调用 create_hitl 创建审批,再 update_hitl({ status: "TONGYI" })\n`)
|
|
71
|
+
const msg = `⛔ HITL 未 tongyi: 哨兵 ${tongyiMarker} 不存在。请先 create_hitl → 人工 tongyi → update_hitl 后再写入`
|
|
72
|
+
process.stdout.write(
|
|
73
|
+
JSON.stringify({
|
|
74
|
+
hookSpecificOutput: {
|
|
75
|
+
hookEventName: "PreToolUse",
|
|
76
|
+
permissionDecision: "deny",
|
|
77
|
+
permissionDecisionReason: msg,
|
|
78
|
+
additionalContext: msg,
|
|
79
|
+
},
|
|
80
|
+
}) + "\n"
|
|
81
|
+
)
|
|
82
|
+
writeHookEvent("pre-tool-use", "ask", `${toolName} ${filePath}`, `HITL 未 tongyi: ${tongyiMarker}`, this.planKeyword, this.planStatus)
|
|
83
|
+
return 2
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** ⑦ ③ Read matcher: 模板路径兜底提示 */
|
|
87
|
+
protected override onOtherTool(input: string, toolName: string): number {
|
|
88
|
+
if (toolName === "Read") {
|
|
89
|
+
const filePath = jsonGet(input, "file_path")
|
|
90
|
+
if (/templates\//.test(filePath)) {
|
|
91
|
+
process.stderr.write("[ADD PreToolUse] 提示: 模板文件已通过 hook 预读到上下文,可跳过重复读取\n")
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return 0
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const input = readHookInput()
|
|
99
|
+
let toolName = jsonGet(input, "tool_name")
|
|
100
|
+
if (toolName === "") {
|
|
101
|
+
toolName = input.match(/"tool_name"\s*:\s*"([^"]*)"/)?.[1] ?? ""
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const guard = new QoderPreToolUseGuard(PROJECT_DIR, MAGIC_DIR)
|
|
105
|
+
|
|
106
|
+
if (toolName === "Bash") {
|
|
107
|
+
process.exit(guard.runSectionA(input))
|
|
108
|
+
} else if (toolName === "Write" || toolName === "Edit" || toolName === "SearchReplace") {
|
|
109
|
+
process.exit(guard.runSectionB(input, toolName))
|
|
110
|
+
} else {
|
|
111
|
+
process.exit(guard.runSectionC(input, toolName))
|
|
112
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// prompt-submit.ts — UserPromptSubmit 入口(Qoder CN 版,Task 4.1 继承体系)
|
|
2
|
+
// 继承 core PromptRouter(L1/L2/L3 模板方法);仅 override 协议差异(bash 原文逐字对照):
|
|
3
|
+
// ① preamble: 无条件 "ADD workflow active" JSON 注入(Qoder 主端协议)
|
|
4
|
+
// ② onAccepted: review-checklist 内存调用(checkReviewQuality,非 core 子进程)
|
|
5
|
+
// ③ devKwMatched: 逐个正则 some(core 是 join("|") 单正则)
|
|
6
|
+
// ④ layer3Json: true——Layer3 输出 hookSpecificOutput JSON 包
|
|
7
|
+
// ⑤ dailyInContext: true——日报并入 additionalContext(core 独立行)
|
|
8
|
+
// ⑥ dailyWarnText: 「建议创建 Plan」(无"或检查 hooks 误报")
|
|
9
|
+
|
|
10
|
+
import { readHookInput, tryResolveMagicDir } from "../../../core/governance/common.js"
|
|
11
|
+
import { PromptRouter } from "../../../core/governance/prompt-router.js"
|
|
12
|
+
import { checkReviewQuality } from "../../../core/governance/review-checklist-guard.js"
|
|
13
|
+
import { injectProjectDir } from "./lib/qoder-env.js"
|
|
14
|
+
|
|
15
|
+
injectProjectDir()
|
|
16
|
+
const inferred = tryResolveMagicDir()
|
|
17
|
+
if (inferred && !process.env.MAGIC_DIR) process.env.MAGIC_DIR = inferred
|
|
18
|
+
const MAGIC_DIR = process.env.MAGIC_DIR ?? ".qoder"
|
|
19
|
+
|
|
20
|
+
class QoderPromptRouter extends PromptRouter {
|
|
21
|
+
/** ① 前置注入: 无条件 JSON(Qoder CN IDE stdout JSON 注入模型上下文) */
|
|
22
|
+
protected override preamble(_input: string): void {
|
|
23
|
+
process.stdout.write(
|
|
24
|
+
JSON.stringify({
|
|
25
|
+
hookSpecificOutput: {
|
|
26
|
+
hookEventName: "UserPromptSubmit",
|
|
27
|
+
additionalContext: "ADD workflow active. Templates preloaded. Use add-paradigm SKILL.",
|
|
28
|
+
},
|
|
29
|
+
}) + "\n"
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** ② 验收后置: checklist 质量检查内存调用(bash 外部调用 → TS 内存调用,stdout 直出行为等价) */
|
|
34
|
+
protected override onAccepted(handoff: string, addRoute: string): void {
|
|
35
|
+
process.stdout.write(checkReviewQuality(handoff, addRoute) + "\n")
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** ③ 开发关键词匹配: 逐个正则 some */
|
|
39
|
+
protected override devKwMatched(prompt: string, devKw: string[]): boolean {
|
|
40
|
+
return devKw.some((kw) => {
|
|
41
|
+
try {
|
|
42
|
+
return new RegExp(kw, "i").test(prompt)
|
|
43
|
+
} catch {
|
|
44
|
+
return false
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** ④ Layer3 JSON 输出 */
|
|
50
|
+
protected override layer3Json(): boolean {
|
|
51
|
+
return true
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** ⑤ 日报并入 additionalContext */
|
|
55
|
+
protected override dailyInContext(): boolean {
|
|
56
|
+
return true
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** ⑥ 日报告警文本(无"或检查 hooks 误报") */
|
|
60
|
+
protected override dailyWarnText(noPlan: number, threshold: number): string {
|
|
61
|
+
return `[Hook ⚠️] 无 Plan 提示已达 ${noPlan} 次(≥${threshold}),建议创建 Plan`
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const input = readHookInput()
|
|
66
|
+
process.exit(new QoderPromptRouter(MAGIC_DIR).run(input))
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// review-checklist.ts — 验收 Review 模式(Qoder CN 版,Task 4.1 继承体系补全)
|
|
2
|
+
// 继承 core ReviewChecklistGuard,命名子类 QoderReviewChecklistGuard:
|
|
3
|
+
// ① specRoot = ".qoder/specs"(构造参数——checkReviewQuality 默认值同,qoder 协议差异)
|
|
4
|
+
// ② Step 0 准入失败 exit 1 语义 = 基类(qoder bash 原文逐字)
|
|
5
|
+
// 被 prompt-submit 的「验收」幂等检查后调用。
|
|
6
|
+
|
|
7
|
+
import { ReviewChecklistGuard } from "../../../core/governance/review-checklist-guard.js"
|
|
8
|
+
import { injectProjectDir } from "./lib/qoder-env.js"
|
|
9
|
+
|
|
10
|
+
class QoderReviewChecklistGuard extends ReviewChecklistGuard {
|
|
11
|
+
/** 协议差异封装: specRoot = ".qoder/specs"(qoder 端 spec 目录) */
|
|
12
|
+
constructor() {
|
|
13
|
+
super(".qoder/specs")
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// 当前无 override(Step 0 准入 exit 1 语义与 core 基线一致);命名子类承载端身份 + 未来演进位
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
injectProjectDir()
|
|
20
|
+
|
|
21
|
+
const handoff = process.argv[2] ?? ""
|
|
22
|
+
const addRoute = process.argv[3] ?? ""
|
|
23
|
+
|
|
24
|
+
process.exit(new QoderReviewChecklistGuard().run(handoff, addRoute))
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// session-end.ts — SessionEnd 入口(Qoder CN 版,Task 4.1 继承体系补全)
|
|
2
|
+
// 继承 core SessionEndGuard,命名子类 QoderSessionEndGuard:
|
|
3
|
+
// ① 清理标记(tpl + dev)= 基类(bash 原文逐字)
|
|
4
|
+
// ② emitSettle override: stdout JSON additionalContext(qoder 协议——
|
|
5
|
+
// 含 fallbackMsg 检测,bash 缺陷照搬: 清理后 hasDevAction 恒 false,fallbackMsg 恒空)
|
|
6
|
+
// ③ stopFallback = 基类(清理后 hasDevAction 恒 false → 恒无操作,与 qoder bash 原文等价)
|
|
7
|
+
|
|
8
|
+
import { hasDevAction, localIsoSeconds } from "../../../core/governance/common.js"
|
|
9
|
+
import { SessionEndGuard } from "../../../core/governance/session-end.js"
|
|
10
|
+
import { injectProjectDir } from "./lib/qoder-env.js"
|
|
11
|
+
|
|
12
|
+
class QoderSessionEndGuard extends SessionEndGuard {
|
|
13
|
+
/** ② qoder 协议: stdout JSON additionalContext(含 fallbackMsg 检测——bash 缺陷照搬顺序) */
|
|
14
|
+
protected override emitSettle(): void {
|
|
15
|
+
// bash 缺陷照搬: 先清理 dev 标记再检查 has_dev_action——清理后检查恒为 false
|
|
16
|
+
let fallbackMsg = ""
|
|
17
|
+
if (hasDevAction()) {
|
|
18
|
+
fallbackMsg = "⚠️ 检测到 dev action 标记未清除——Stop 可能未触发验收检查"
|
|
19
|
+
}
|
|
20
|
+
const ctx = `[ADD SessionEnd] 会话结束 — ${localIsoSeconds()}。标记已清理。${fallbackMsg}`
|
|
21
|
+
process.stdout.write(JSON.stringify({ hookSpecificOutput: { hookEventName: "SessionEnd", additionalContext: ctx } }) + "\n")
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
injectProjectDir()
|
|
26
|
+
|
|
27
|
+
process.exit(new QoderSessionEndGuard().run())
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// session-start.ts — SessionStart 入口(Qoder CN 版,Task 4.1 继承体系)
|
|
2
|
+
// 继承 core SessionStartGuard;仅 override 协议差异(bash 原文逐字对照):
|
|
3
|
+
// ① emitState: JSON 注入(ADD: plan Step.. Round.. + 代办并入)
|
|
4
|
+
// ② emitIndex: JSON 注入(lines 计数,对齐 bash wc -l)
|
|
5
|
+
// ③ emitTodoReminder: 空(代办已并入状态段)
|
|
6
|
+
// ④ emitHitlPending: JSON 注入
|
|
7
|
+
|
|
8
|
+
import { existsSync, readdirSync, statSync } from "node:fs"
|
|
9
|
+
import { join } from "node:path"
|
|
10
|
+
import { detectActiveAdd, tryResolveMagicDir } from "../../../core/governance/common.js"
|
|
11
|
+
import { PreloadTemplates } from "../../../core/governance/preload-templates.js"
|
|
12
|
+
import { SessionStartGuard } from "../../../core/governance/session-start-guard.js"
|
|
13
|
+
import { injectProjectDir } from "./lib/qoder-env.js"
|
|
14
|
+
|
|
15
|
+
const PROJECT_DIR = injectProjectDir()
|
|
16
|
+
const inferred = tryResolveMagicDir()
|
|
17
|
+
if (inferred && !process.env.MAGIC_DIR) process.env.MAGIC_DIR = inferred
|
|
18
|
+
const MAGIC_DIR = process.env.MAGIC_DIR ?? ""
|
|
19
|
+
|
|
20
|
+
/** JSON 输出助手(Qoder stdout 规范) */
|
|
21
|
+
function sessionJson(context: string): string {
|
|
22
|
+
return JSON.stringify({ hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: context } }) + "\n"
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
class QoderSessionStartGuard extends SessionStartGuard {
|
|
26
|
+
constructor(projectDir: string) {
|
|
27
|
+
super(projectDir)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** ① 状态恢复: JSON 注入(ADD: plan Step.. Round.. + 代办并入) */
|
|
31
|
+
protected override emitState(state: string | null): void {
|
|
32
|
+
if (state === null) return
|
|
33
|
+
const [plan, step, rounds] = state.split("::")
|
|
34
|
+
let addCtx = `ADD: ${plan} Step${step} Round${rounds}`
|
|
35
|
+
addCtx += "\n[代办] 如有未加载的 IDE 代办清单,请从 tasks.md §IDE JSON 刷新 TodoWrite"
|
|
36
|
+
process.stdout.write(sessionJson(addCtx))
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** ② 模板索引: JSON 注入(对齐 bash bash "$TPL_SCRIPT" --index | wc -l) */
|
|
40
|
+
protected override emitIndex(): void {
|
|
41
|
+
try {
|
|
42
|
+
const preload = new PreloadTemplates()
|
|
43
|
+
preload.validate()
|
|
44
|
+
const idx = preload.index()
|
|
45
|
+
const lines = idx.split("\n").length - 1 // wc -l 语义
|
|
46
|
+
process.stdout.write(sessionJson(`${lines} ADD templates available. Use preload-templates.sh --index for list.`))
|
|
47
|
+
} catch {
|
|
48
|
+
/* 对齐 bash [ -f "$TPL_SCRIPT" ] 缺失时跳过 */
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** ③ 代办已并入状态段 */
|
|
53
|
+
protected override emitTodoReminder(_state: string | null): void {
|
|
54
|
+
// qoder 协议: 代办并入 emitState
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** ④ HITL 待审批: JSON 注入(对齐 bash find *.hitl.md -mtime -7) */
|
|
58
|
+
protected override emitHitlPending(): void {
|
|
59
|
+
const plansDir = join(PROJECT_DIR, MAGIC_DIR, "plans")
|
|
60
|
+
if (MAGIC_DIR !== "" && existsSync(plansDir)) {
|
|
61
|
+
const weekAgo = Date.now() - 7 * 24 * 3600 * 1000
|
|
62
|
+
let hitlCount = 0
|
|
63
|
+
try {
|
|
64
|
+
hitlCount = readdirSync(plansDir)
|
|
65
|
+
.filter((f) => f.endsWith(".hitl.md"))
|
|
66
|
+
.filter((f) => {
|
|
67
|
+
try {
|
|
68
|
+
return statSync(join(plansDir, f)).mtimeMs >= weekAgo
|
|
69
|
+
} catch {
|
|
70
|
+
return false
|
|
71
|
+
}
|
|
72
|
+
}).length
|
|
73
|
+
} catch {
|
|
74
|
+
hitlCount = 0
|
|
75
|
+
}
|
|
76
|
+
if (hitlCount > 0) {
|
|
77
|
+
process.stdout.write(sessionJson(`[HITL 待审批] 检测到 ${hitlCount} 个待审批 HITL 提案,请检查并处理`))
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
process.exit(new QoderSessionStartGuard(PROJECT_DIR).run())
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// stop-check.ts — Stop 入口(Qoder CN 版,Task 4.1 继承体系)
|
|
2
|
+
// 继承 core StopRouter(Q0-Q4 模板方法);仅 override 协议差异(bash 原文逐字对照):
|
|
3
|
+
// ① stop_hook_active=true → 跳过(Qoder 内部 Stop 触发,入口解析)
|
|
4
|
+
// ② emitQ0/Q3/Q4Pass: stdout 输出 hookSpecificOutput JSON(Qoder stdout 规范)
|
|
5
|
+
// ③ emitQ2/emitQ4Unclosed: stderr 无 \n 后缀(qoder 版差异)
|
|
6
|
+
// ④ ~~unclosedInterpolate: false~~ → 已修复(Task 9.4.1: 回归基类 true 插值语义)
|
|
7
|
+
|
|
8
|
+
import { readHookInput, tryResolveMagicDir } from "../../../core/governance/common.js"
|
|
9
|
+
import { StopRouter } from "../../../core/governance/stop-router.js"
|
|
10
|
+
import { buildStopContext } from "./lib/context-inject.js"
|
|
11
|
+
import { injectProjectDir } from "./lib/qoder-env.js"
|
|
12
|
+
|
|
13
|
+
/** JSON 输出助手(Qoder stdout 规范) */
|
|
14
|
+
function stopJson(context: string): string {
|
|
15
|
+
return JSON.stringify({ hookSpecificOutput: { hookEventName: "Stop", additionalContext: context } }) + "\n"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
class QoderStopRouter extends StopRouter {
|
|
19
|
+
/** ② Q0: stderr + stdout JSON + 2 */
|
|
20
|
+
protected override emitQ0(reason: string): number {
|
|
21
|
+
process.stderr.write(`[ADD Stop] ⛔ Plan status 暂不可用(${reason})。未回退 Handoff/add-route 猜测,请恢复数据库或 MCP resolver 后重试。\n`)
|
|
22
|
+
process.stdout.write(stopJson(`[ADD Stop] Plan status 暂不可用(${reason}),fail-closed 阻断`))
|
|
23
|
+
return 2
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** ③ Q2: stderr few-shot 无 \n 后缀(qoder 差异) */
|
|
27
|
+
protected override emitQ2(): number {
|
|
28
|
+
process.stderr.write(buildStopContext("no_add_has_dev", ""))
|
|
29
|
+
return 2
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** ② Q3: stdout JSON + 0 */
|
|
33
|
+
protected override emitQ3(plan: string, rounds: string, step: string): number {
|
|
34
|
+
process.stdout.write(stopJson(`[ADD Stop] Plan: ${plan}, 轮次: ${rounds}, Step: ${step}。本次无代码改动,下次继续时执行 session-init 恢复上下文。`))
|
|
35
|
+
return 0
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** ③④ Q4 未闭环: stderr 无 \n + 字面量缺陷照搬(不插值) */
|
|
39
|
+
protected override emitQ4Unclosed(info: string): number {
|
|
40
|
+
process.stderr.write(buildStopContext("has_add_dev_unclosed", info))
|
|
41
|
+
return 2
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** ② Q4 通过: stdout JSON + 0 */
|
|
45
|
+
protected override emitQ4Pass(): number {
|
|
46
|
+
process.stdout.write(stopJson("[ADD Stop] ✅ 验收通过——checklist 全部勾选,devlog 已记录。"))
|
|
47
|
+
return 0
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// 注: ④ unclosedInterpolate 缺陷照搬(false → {{info}} 传空串不插值)已修复——
|
|
51
|
+
// 2026-08-14 Task 9.4.1 删除 override,回归基类 true(插值语义),golden 反写。
|
|
52
|
+
|
|
53
|
+
// ── 入口 ──
|
|
54
|
+
// 对齐 bash: stop_hook_active=true → 跳过(Qoder 内部 Stop 触发)
|
|
55
|
+
const input = readHookInput()
|
|
56
|
+
let stopActive = "false"
|
|
57
|
+
try {
|
|
58
|
+
const parsed = JSON.parse(input) as { stop_hook_active?: unknown }
|
|
59
|
+
stopActive = typeof parsed.stop_hook_active === "string" ? parsed.stop_hook_active : "false"
|
|
60
|
+
} catch {
|
|
61
|
+
stopActive = "false"
|
|
62
|
+
}
|
|
63
|
+
if (stopActive === "true") process.exit(0)
|
|
64
|
+
|
|
65
|
+
injectProjectDir()
|
|
66
|
+
const inferred = tryResolveMagicDir()
|
|
67
|
+
if (inferred && !process.env.MAGIC_DIR) process.env.MAGIC_DIR = inferred
|
|
68
|
+
|
|
69
|
+
process.exit(new QoderStopRouter().run())
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// subagent-guard.ts — SubagentStart 入口(Qoder CN 版,Task 4.1 继承体系)
|
|
2
|
+
// 继承 core SubagentGuardRouter,命名子类 QoderSubagentGuardRouter:
|
|
3
|
+
// 输出形态 = 基类默认(hookSpecificOutput JSON,与 core 同构)——当前无 override,
|
|
4
|
+
// 命名子类承载端身份 + 未来演进位(如 SubagentStart 新增字段)。
|
|
5
|
+
// 协议差异: PROJECT_DIR 注入链(qoder-env)
|
|
6
|
+
|
|
7
|
+
import { SubagentGuardRouter } from "../../../core/governance/subagent-guard-router.js"
|
|
8
|
+
import { injectProjectDir } from "./lib/qoder-env.js"
|
|
9
|
+
|
|
10
|
+
class QoderSubagentGuardRouter extends SubagentGuardRouter {
|
|
11
|
+
// 当前无 override(基类 JSON 输出即 qoder 协议)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
injectProjectDir()
|
|
15
|
+
|
|
16
|
+
process.exit(new QoderSubagentGuardRouter().run())
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// subagent-stop.ts — SubagentStop 入口(Qoder CN 版,Task 4.1 继承体系补全)
|
|
2
|
+
// 继承 core SubagentStopRouter,命名子类 QoderSubagentStopRouter(qoder 协议差异 override):
|
|
3
|
+
// ① checkDeliverables: false——qoder 轻量提示无阻断(bash 原文无交付物越界检查)
|
|
4
|
+
// ② emitNoPlanWarn: stdout JSON(qoder 协议;core 是 stderr 文本)
|
|
5
|
+
// ③ emitBoundaryPass: stdout JSON(qoder 协议;core 是 stderr 两行审计)
|
|
6
|
+
|
|
7
|
+
import { detectActiveAdd, readHookInput } from "../../../core/governance/common.js"
|
|
8
|
+
import { SubagentStopRouter } from "../../../core/governance/subagent-stop-router.js"
|
|
9
|
+
import { injectProjectDir } from "./lib/qoder-env.js"
|
|
10
|
+
|
|
11
|
+
class QoderSubagentStopRouter extends SubagentStopRouter {
|
|
12
|
+
/** ① qoder 轻量提示无阻断(bash 原文无交付物越界检查) */
|
|
13
|
+
protected override checkDeliverables(): boolean {
|
|
14
|
+
return false
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** ② 无活跃 Plan: stdout JSON(qoder 协议) */
|
|
18
|
+
protected override emitNoPlanWarn(agentName: string): void {
|
|
19
|
+
const ctx = `[ADD SubagentStop] ⚠️ ${agentName} 已完成,但无活跃 ADD Plan 无法校验边界。`
|
|
20
|
+
process.stdout.write(JSON.stringify({ hookSpecificOutput: { hookEventName: "SubagentStop", additionalContext: ctx } }) + "\n")
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** ③ 边界通过: stdout JSON(qoder 协议——bash 原文逐字文本) */
|
|
24
|
+
protected override emitBoundaryPass(agentName: string, planKw: string, handoff: string): void {
|
|
25
|
+
const ctx = `[ADD SubagentStop] ${agentName} 子代理结束。Plan: ${planKw}, handoff: ${handoff}。边界校验通过,审计已聚合。`
|
|
26
|
+
process.stdout.write(JSON.stringify({ hookSpecificOutput: { hookEventName: "SubagentStop", additionalContext: ctx } }) + "\n")
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
injectProjectDir()
|
|
31
|
+
|
|
32
|
+
const input = readHookInput()
|
|
33
|
+
process.exit(new QoderSubagentStopRouter().run(input))
|