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,299 @@
|
|
|
1
|
+
// lib/common.ts — ADD Hook 协议壳(轮次 1 / Task 1.3)
|
|
2
|
+
// 与 bash 版 lib/common.sh 行为逐字对齐:
|
|
3
|
+
// stdin 解析 / stdout JSON / stderr 文本 / 退出码 0·2 / failClosed
|
|
4
|
+
// 契约红线(Plan §1.2): stdout 仅 JSON、stderr 仅人类可读文本、exit 0/2
|
|
5
|
+
// 烘焙: scripts/hook-bake.ts bundle 为各 magicDir hooks/lib/common.mjs
|
|
6
|
+
// 本文件被各入口 .ts 与 adapter 私有协议层 import(bundle 时内联,产物自包含)
|
|
7
|
+
|
|
8
|
+
import { existsSync, readFileSync, writeFileSync, unlinkSync } from "node:fs"
|
|
9
|
+
import { basename, dirname, join } from "node:path"
|
|
10
|
+
import { fileURLToPath } from "node:url"
|
|
11
|
+
import { spawnSync } from "node:child_process"
|
|
12
|
+
import { createHash } from "node:crypto"
|
|
13
|
+
import { protocol } from "./rules.js"
|
|
14
|
+
import { findUpSync } from "find-up"
|
|
15
|
+
|
|
16
|
+
/** 退出码常量(真源: hook-protocol-rules.toml [protocol.exit_codes]) */
|
|
17
|
+
export const EXIT_PASS = protocol.exit_codes.pass as number
|
|
18
|
+
export const EXIT_BLOCK = protocol.exit_codes.block as number
|
|
19
|
+
|
|
20
|
+
/** state 字段分隔符(真源: hook-protocol-rules.toml [protocol.output.field_separator]) */
|
|
21
|
+
export const STATE_SEP = protocol.output.field_separator as string
|
|
22
|
+
|
|
23
|
+
/** 从 stdin 读取完整 JSON(IDE hook 事件 payload);TTY 时返回 "{}"(对齐 bash parse_input) */
|
|
24
|
+
export function readHookInput(): string {
|
|
25
|
+
if (process.stdin.isTTY) return "{}"
|
|
26
|
+
return readFileSync(0, "utf-8")
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** 从 JSON 提取首个字符串字段值(对齐 bash json_get 的 grep/sed 语义) */
|
|
30
|
+
export function jsonGet(json: string, field: string): string {
|
|
31
|
+
const re = new RegExp(`"${field}"\\s*:\\s*"([^"]*)"`)
|
|
32
|
+
const m = re.exec(json)
|
|
33
|
+
return m?.[1] ?? ""
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** stdout 输出 JSON(机器契约一字不变: additionalContext / hookSpecificOutput / decision) */
|
|
37
|
+
export function emitJson(payload: Record<string, unknown> | string): void {
|
|
38
|
+
process.stdout.write(
|
|
39
|
+
(typeof payload === "string" ? payload : JSON.stringify(payload)) + "\n"
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** stderr 输出文本(Qoder 规范: stderr=人类可读,stdout=机器 JSON) */
|
|
44
|
+
export function emitText(text: string): void {
|
|
45
|
+
process.stderr.write(text + "\n")
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** 放行(退出码 0) */
|
|
49
|
+
export function exitOk(): never {
|
|
50
|
+
process.exit(EXIT_PASS)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** 阻断(退出码 2) */
|
|
54
|
+
export function exitBlock(): never {
|
|
55
|
+
process.exit(EXIT_BLOCK)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* STATUS_UNAVAILABLE 语义: 非零退出 + stderr 说明,禁止静默吞掉。
|
|
60
|
+
* 默认阻断码 2(hook 冒烟契约 ∈ {0,2});bridge 场景可传 3(对齐 bash return 3)。
|
|
61
|
+
*/
|
|
62
|
+
export function failClosed(msg: string, code: number = EXIT_BLOCK): never {
|
|
63
|
+
process.stderr.write(msg + "\n")
|
|
64
|
+
process.exit(code)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* magicDir 统一解析(Plan §3.2 缺陷修复要求 TS 版唯一解析链):
|
|
69
|
+
* ① 入口注入 MAGIC_DIR 优先(sync 烘焙时 bakeMagicRefs 已硬编码)
|
|
70
|
+
* ② 物理位置推导: <projectDir>/<magicDir>/hooks/... 向上找以 . 开头的目录名
|
|
71
|
+
* ③ 推导失败 → failClosed(禁止猜测 adapter 名 / 禁止孤儿变量)
|
|
72
|
+
*/
|
|
73
|
+
export function resolveMagicDir(): string {
|
|
74
|
+
const hit = tryResolveMagicDir()
|
|
75
|
+
if (hit) return hit
|
|
76
|
+
return failClosed(
|
|
77
|
+
`magicDir 未注入且无法从物理位置推导: ${fileURLToPath(import.meta.url)}`
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* 非阻断版 magicDir 解析(唯一解析链的柔和变体):
|
|
83
|
+
* 与 resolveMagicDir 同一条链,但推导失败时返回 "" 而非 failClosed——
|
|
84
|
+
* 供 vocabulary 等「文件缺失静默返回空」语义的调用方使用(对齐 bash:禁止猜测 adapter 名)。
|
|
85
|
+
* find-up 语义(2026-08-14 Task 5.1 补齐): 以当前文件为锚点向上找「以 . 开头的目录名」
|
|
86
|
+
* (magicDir 约定形态),替代手写 for 循环——层级变动零漂移(对齐 src/shared/paths.ts 范式)。
|
|
87
|
+
*/
|
|
88
|
+
export function tryResolveMagicDir(): string {
|
|
89
|
+
const injected = process.env.MAGIC_DIR
|
|
90
|
+
if (injected) return injected
|
|
91
|
+
const startDir = dirname(fileURLToPath(import.meta.url))
|
|
92
|
+
// find-up v8 matcher 约定: 返回命中值(string)或 undefined(未命中)
|
|
93
|
+
const hit = findUpSync((dir) => (basename(dir).startsWith(".") ? dir : undefined), {
|
|
94
|
+
cwd: startDir,
|
|
95
|
+
type: "directory",
|
|
96
|
+
})
|
|
97
|
+
return hit ? basename(hit) : ""
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* PROJECT_DIR 统一解析: 注入优先;否则以 magicDir 为锚点向上查找其父目录(项目根)。
|
|
102
|
+
* 失败 → failClosed(不猜测项目路径)。
|
|
103
|
+
* find-up 语义(2026-08-14 Task 5.1 补齐): 替代手写 for 循环,层级零漂移。
|
|
104
|
+
*/
|
|
105
|
+
export function resolveProjectDir(): string {
|
|
106
|
+
const injected = process.env.PROJECT_DIR
|
|
107
|
+
if (injected) return injected
|
|
108
|
+
const magicDir = resolveMagicDir()
|
|
109
|
+
const startDir = dirname(fileURLToPath(import.meta.url))
|
|
110
|
+
const hit = findUpSync((dir) => (basename(dir) === magicDir ? dir : undefined), {
|
|
111
|
+
cwd: startDir,
|
|
112
|
+
type: "directory",
|
|
113
|
+
})
|
|
114
|
+
return hit ? dirname(hit) : failClosed("PROJECT_DIR 未注入且无法从物理位置推导")
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ── ADD 活跃 Plan 检测(对齐 bash common.sh query_plan_status / detect_active_add)──
|
|
118
|
+
//
|
|
119
|
+
// lifecycle 的唯一真相源是 scoped DB。短生命周期 Hook 不常驻 LISTEN;每次触发
|
|
120
|
+
// 都通过当前 adapter 生成态的机器桥(plan-status-bridge)调用 shared resolver。
|
|
121
|
+
// Handoff/add-route 不参与 active 裁决,禁止跨 adapter 或文件系统 fallback。
|
|
122
|
+
|
|
123
|
+
export interface PlanStatusResult {
|
|
124
|
+
stdout: string
|
|
125
|
+
exitCode: number
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* 查询活跃 Plan 状态(对齐 bash query_plan_status):
|
|
130
|
+
* - MAGIC_DIR 未注入 → STATUS_UNAVAILABLE(exitCode 3)——对齐 bash:
|
|
131
|
+
* 未注入且无 HOOK_DIR 时直接放弃,不做物理推导(入口 hook 保证注入)
|
|
132
|
+
* - bridge 缺失 → STATUS_UNAVAILABLE(exitCode 3)
|
|
133
|
+
* - 否则 spawn `node --import tsx <magicDir>/scripts/plan-status-bridge.ts`
|
|
134
|
+
*/
|
|
135
|
+
export function queryPlanStatus(): PlanStatusResult {
|
|
136
|
+
const magicDir = process.env.MAGIC_DIR
|
|
137
|
+
if (!magicDir) {
|
|
138
|
+
return {
|
|
139
|
+
stdout: '{"availability":"STATUS_UNAVAILABLE","source":"database","reason":"magicDir 未注入且无法从物理位置推导"}',
|
|
140
|
+
exitCode: 3,
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const bridge = join(
|
|
144
|
+
process.env.PROJECT_DIR || process.cwd(),
|
|
145
|
+
magicDir,
|
|
146
|
+
"scripts",
|
|
147
|
+
"plan-status-bridge.ts"
|
|
148
|
+
)
|
|
149
|
+
if (!existsSync(bridge)) {
|
|
150
|
+
return {
|
|
151
|
+
stdout: '{"availability":"STATUS_UNAVAILABLE","source":"database","reason":"plan-status bridge missing"}',
|
|
152
|
+
exitCode: 3,
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const r = spawnSync("node", ["--import", "tsx", bridge], {
|
|
156
|
+
encoding: "utf-8",
|
|
157
|
+
timeout: 10_000,
|
|
158
|
+
})
|
|
159
|
+
return { stdout: r.stdout ?? "", exitCode: r.status ?? -1 }
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* 活跃 Plan 检测(对齐 bash detect_active_add):
|
|
164
|
+
* - bridge 失败 → "__STATUS_UNAVAILABLE__::<reason>::database::none::none"(调用方 fail-closed)
|
|
165
|
+
* - 非 READY/isActive → null(对齐 bash return 1)
|
|
166
|
+
* - 活跃 → "plan::done/total::approval::none::none"
|
|
167
|
+
*/
|
|
168
|
+
export function detectActiveAdd(): string | null {
|
|
169
|
+
const r = queryPlanStatus()
|
|
170
|
+
if (r.exitCode !== 0) {
|
|
171
|
+
let reason = "database status unavailable"
|
|
172
|
+
try {
|
|
173
|
+
const parsed = JSON.parse(r.stdout) as { reason?: string }
|
|
174
|
+
if (parsed.reason) reason = parsed.reason
|
|
175
|
+
} catch {
|
|
176
|
+
/* 非 JSON 输出 → 默认 reason */
|
|
177
|
+
}
|
|
178
|
+
return `__STATUS_UNAVAILABLE__::${reason}::database::none::none`
|
|
179
|
+
}
|
|
180
|
+
let snapshot: {
|
|
181
|
+
availability?: string
|
|
182
|
+
isActive?: boolean
|
|
183
|
+
planName?: string
|
|
184
|
+
approvalStatus?: string
|
|
185
|
+
progress?: { doneTasks?: number; totalTasks?: number }
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
snapshot = JSON.parse(r.stdout) as typeof snapshot
|
|
189
|
+
} catch {
|
|
190
|
+
return null
|
|
191
|
+
}
|
|
192
|
+
if (!(snapshot.availability === "READY" && snapshot.isActive === true)) return null
|
|
193
|
+
const done = snapshot.progress?.doneTasks ?? 0
|
|
194
|
+
const total = snapshot.progress?.totalTasks ?? 0
|
|
195
|
+
const approval = snapshot.approvalStatus ?? "none"
|
|
196
|
+
return `${snapshot.planName}::${done}/${total}::${approval}::none::none`
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ── 时间格式(对齐 bash date 工具链)──
|
|
200
|
+
|
|
201
|
+
/** 对齐 bash `date -Iseconds`:本地时间 + 时区偏移(如 2026-08-14T11:15:41+08:00) */
|
|
202
|
+
export function localIsoSeconds(): string {
|
|
203
|
+
const d = new Date()
|
|
204
|
+
const pad = (n: number) => String(n).padStart(2, "0")
|
|
205
|
+
const offsetMin = -d.getTimezoneOffset()
|
|
206
|
+
const sign = offsetMin >= 0 ? "+" : "-"
|
|
207
|
+
const offAbs = Math.abs(offsetMin)
|
|
208
|
+
const off = `${sign}${pad(Math.floor(offAbs / 60))}:${pad(offAbs % 60)}`
|
|
209
|
+
return (
|
|
210
|
+
`${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}` +
|
|
211
|
+
`T${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}${off}`
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// ── Dev Action 追踪(对齐 bash common.sh 标记文件管理)──
|
|
216
|
+
|
|
217
|
+
/** 项目 hash(对齐 bash echo "${PROJECT_DIR:-$PWD}" | md5sum | cut -c1-8:echo 含换行)——标记文件命名的唯一算法 */
|
|
218
|
+
export function projectHash(): string {
|
|
219
|
+
try {
|
|
220
|
+
// bash echo 输出带 \n,md5 对象为 dir + 换行
|
|
221
|
+
return createHash("md5")
|
|
222
|
+
.update(`${process.env.PROJECT_DIR || process.cwd()}\n`)
|
|
223
|
+
.digest("hex")
|
|
224
|
+
.slice(0, 8)
|
|
225
|
+
} catch {
|
|
226
|
+
return "default"
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const DEV_FLAG = `/tmp/add_dev_${projectHash()}`
|
|
231
|
+
|
|
232
|
+
export function markDevAction(): void {
|
|
233
|
+
try {
|
|
234
|
+
writeFileSync(DEV_FLAG, "")
|
|
235
|
+
} catch {
|
|
236
|
+
/* ignore */
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export function hasDevAction(): boolean {
|
|
241
|
+
return existsSync(DEV_FLAG)
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export function clearDevAction(): void {
|
|
245
|
+
try {
|
|
246
|
+
unlinkSync(DEV_FLAG)
|
|
247
|
+
} catch {
|
|
248
|
+
/* ignore */
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// ── 验收完整度检查(对齐 bash check_add_completeness)──
|
|
253
|
+
|
|
254
|
+
/** 检查 handoff + add-route 的验收完整度,返回问题列表(无问题 → 空数组) */
|
|
255
|
+
export function checkAddCompleteness(handoff: string, addRoute: string): string[] {
|
|
256
|
+
const issues: string[] = []
|
|
257
|
+
|
|
258
|
+
// devlog(内容已回流至 handoff,检查 handoff 是否含验收结果)
|
|
259
|
+
if (handoff && existsSync(handoff)) {
|
|
260
|
+
const content = readFileSync(handoff, "utf-8")
|
|
261
|
+
if (!/验收|收敛|闭环|本轮改了什么|devlog/.test(content)) {
|
|
262
|
+
issues.push(" [ ] devlog 缺失(handoff 无验收记录)")
|
|
263
|
+
}
|
|
264
|
+
const unchecked = (content.match(/\[ \]/g) || []).length
|
|
265
|
+
if (unchecked > 0) {
|
|
266
|
+
issues.push(` [ ] handoff ${unchecked} 项未勾选`)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// add-route Step
|
|
271
|
+
if (addRoute && existsSync(addRoute)) {
|
|
272
|
+
const content = readFileSync(addRoute, "utf-8")
|
|
273
|
+
const unchecked = (content.match(/\[ \]/g) || []).length
|
|
274
|
+
if (unchecked > 0) {
|
|
275
|
+
issues.push(` [ ] add-route ${unchecked} Step 未闭环`)
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return issues
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* 验收幂等保护(对齐 bash is_already_accepted):
|
|
283
|
+
* add-route Step 8 区段含 "[x].*验证并更新项目状态" 且 handoff 含验收字样 → 已验收。
|
|
284
|
+
*/
|
|
285
|
+
export function isAlreadyAccepted(addRoute: string, handoff: string): boolean {
|
|
286
|
+
if (addRoute && existsSync(addRoute)) {
|
|
287
|
+
const content = readFileSync(addRoute, "utf-8")
|
|
288
|
+
const step8 = content.match(/Step 8[\s\S]{0,2000}/)?.[0] ?? ""
|
|
289
|
+
if (/\[x\].*验证并更新项目状态/.test(step8)) {
|
|
290
|
+
if (handoff && existsSync(handoff)) {
|
|
291
|
+
const h = readFileSync(handoff, "utf-8")
|
|
292
|
+
if (/✅.*验收|收敛|全部闭环|全部.*完成/.test(h)) {
|
|
293
|
+
return true
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return false
|
|
299
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// context-inject.ts — 上下文注入模板(bash 版 context-inject.sh 的 TS 同语义实现)
|
|
2
|
+
// 共享库: SessionStart JSON 注入 + Stop 七象限分流 few-shot + 写操作前置守卫
|
|
3
|
+
// 规则真源: hook-context-rules.toml([context.quadrants] / [context.pretool])
|
|
4
|
+
// consumed 语义(Task 2.3 死代码象限归档): true = 有入口消费;false = 死代码象限
|
|
5
|
+
// (2026-08-14 实态核验: 全端 stop-check 仅消费 no_add_has_dev + has_add_dev_unclosed)
|
|
6
|
+
|
|
7
|
+
import { context } from "./rules.js"
|
|
8
|
+
|
|
9
|
+
/** 象限条目(rules.context.quadrants 结构) */
|
|
10
|
+
interface Quadrant {
|
|
11
|
+
id: string
|
|
12
|
+
consumed: boolean
|
|
13
|
+
text: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** 结构化 SessionStart JSON 注入(与 bash build_session_start_json 逐字对齐) */
|
|
17
|
+
export function buildSessionStartJson(
|
|
18
|
+
plan: string,
|
|
19
|
+
step: string,
|
|
20
|
+
round: string,
|
|
21
|
+
handoff: string
|
|
22
|
+
): string {
|
|
23
|
+
return `{
|
|
24
|
+
"continue": true,
|
|
25
|
+
"hookSpecificOutput": {
|
|
26
|
+
"hookEventName": "SessionStart",
|
|
27
|
+
"additionalContext": "上次 ADD 流程未完成:\\n Plan: ${plan}\\n 轮次: ${round}\\n 当前 Step: ${step} (add-route)\\n 恢复命令: query_audit_logs({ planKeyword: '${plan}' })\\n handoff: ${handoff}"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
`
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** 象限文本索引(真源: hook-context-rules.toml [context.quadrants])
|
|
34
|
+
* Task 9.4.3 裁剪: 仅加载 consumed=true 象限(no_add_has_dev / has_add_dev_unclosed)——
|
|
35
|
+
* 死代码象限(consumed=false ×5)从运行索引移除(不可达),文本保留 TOML 真源待归档。 */
|
|
36
|
+
const QUADRANTS: Map<string, Quadrant> = new Map(
|
|
37
|
+
(((context.quadrants as unknown as Quadrant[]) ?? [])
|
|
38
|
+
.filter((q) => q.consumed === true)
|
|
39
|
+
.map((q) => [q.id, q]) as Array<[string, Quadrant]>)
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
/** Stop 七象限分流 few-shot 上下文(文本真源 = TOML;{{info}} 占位符 replace 插值) */
|
|
43
|
+
export function buildStopContext(quadrant: string, info: string): string {
|
|
44
|
+
const q = QUADRANTS.get(quadrant)
|
|
45
|
+
if (!q) return ""
|
|
46
|
+
return q.text.replaceAll("{{info}}", info)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** 写操作前置守卫上下文(真源: hook-context-rules.toml [context.pretool]) */
|
|
50
|
+
export function buildPretoolContext(plan: string, round: string): string {
|
|
51
|
+
const tpl = (context.pretool as { text: string }).text
|
|
52
|
+
return tpl.replaceAll("{{plan}}", plan).replaceAll("{{round}}", round)
|
|
53
|
+
}
|