@uzysjung/agent-harness 26.88.1 → 26.89.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +3 -26
- package/README.md +8 -32
- package/dist/{chunk-QHYH6P32.js → chunk-EZZOJPG4.js} +1 -11
- package/dist/chunk-EZZOJPG4.js.map +1 -0
- package/dist/index.js +262 -748
- package/dist/index.js.map +1 -1
- package/dist/trust-tier-drift.js +1 -1
- package/package.json +1 -1
- package/templates/agents/plan-checker.md +3 -4
- package/templates/agents/reviewer.md +1 -1
- package/templates/antigravity/AGENTS.md.template +0 -28
- package/templates/codex/AGENTS.md.template +0 -25
- package/templates/codex/README.md +5 -15
- package/templates/codex/config.toml.template +0 -10
- package/templates/codex/hooks/README.md +0 -2
- package/templates/hooks/checkpoint-snapshot.sh +1 -22
- package/templates/hooks/session-start.sh +1 -1
- package/templates/hooks/spec-drift-check.sh +2 -20
- package/templates/opencode/AGENTS.md.template +3 -38
- package/templates/opencode/README.md +0 -4
- package/templates/opencode/opencode.json.template +1 -3
- package/templates/project-claude/fragments/csr-fastapi/boundaries.md +0 -1
- package/templates/project-claude/fragments/csr-fastapi/commands.md +0 -1
- package/templates/project-claude/fragments/csr-fastapi/plugins.md +1 -1
- package/templates/project-claude/fragments/csr-fastify/boundaries.md +0 -1
- package/templates/project-claude/fragments/csr-fastify/commands.md +0 -1
- package/templates/project-claude/fragments/csr-fastify/plugins.md +1 -1
- package/templates/project-claude/fragments/csr-supabase/boundaries.md +0 -1
- package/templates/project-claude/fragments/csr-supabase/commands.md +0 -1
- package/templates/project-claude/fragments/csr-supabase/plugins.md +1 -1
- package/templates/project-claude/fragments/csr-supabase/supabase-auth.md +0 -2
- package/templates/project-claude/fragments/data/boundaries.md +0 -1
- package/templates/project-claude/fragments/data/commands.md +0 -1
- package/templates/project-claude/fragments/data/plugins.md +1 -1
- package/templates/project-claude/fragments/executive/boundaries.md +0 -1
- package/templates/project-claude/fragments/executive/commands.md +0 -1
- package/templates/project-claude/fragments/executive/skills.md +1 -1
- package/templates/project-claude/fragments/executive/workflow.md +1 -2
- package/templates/project-claude/fragments/growth-marketing/boundaries.md +0 -1
- package/templates/project-claude/fragments/growth-marketing/commands.md +0 -1
- package/templates/project-claude/fragments/growth-marketing/skills.md +1 -1
- package/templates/project-claude/fragments/growth-marketing/workflow.md +1 -2
- package/templates/project-claude/fragments/project-management/boundaries.md +0 -1
- package/templates/project-claude/fragments/project-management/commands.md +0 -1
- package/templates/project-claude/fragments/project-management/skills.md +1 -1
- package/templates/project-claude/fragments/project-management/workflow.md +1 -2
- package/templates/project-claude/fragments/ssr-htmx/boundaries.md +0 -1
- package/templates/project-claude/fragments/ssr-htmx/commands.md +0 -1
- package/templates/project-claude/fragments/ssr-htmx/plugins.md +1 -1
- package/templates/project-claude/fragments/ssr-nextjs/boundaries.md +0 -1
- package/templates/project-claude/fragments/ssr-nextjs/commands.md +0 -1
- package/templates/project-claude/fragments/ssr-nextjs/plugins.md +1 -1
- package/templates/project-claude/fragments/tooling/boundaries.md +0 -1
- package/templates/project-claude/fragments/tooling/commands.md +0 -1
- package/templates/project-claude/fragments/tooling/skills.md +1 -1
- package/templates/rules/git-policy.md +2 -2
- package/templates/rules/ship-checklist.md +3 -3
- package/templates/settings.json +0 -13
- package/templates/skills/gh-issue-workflow/SKILL.md +8 -8
- package/templates/skills/north-star/SKILL.md +4 -4
- package/templates/skills/ui-visual-review/SKILL.md +6 -6
- package/dist/chunk-QHYH6P32.js.map +0 -1
- package/templates/codex/hooks/gate-check.sh +0 -7
- package/templates/codex/skills/uzys-build/SKILL.md +0 -24
- package/templates/codex/skills/uzys-plan/SKILL.md +0 -24
- package/templates/codex/skills/uzys-review/SKILL.md +0 -24
- package/templates/codex/skills/uzys-ship/SKILL.md +0 -24
- package/templates/codex/skills/uzys-spec/SKILL.md +0 -28
- package/templates/codex/skills/uzys-test/SKILL.md +0 -24
- package/templates/commands/uzys/auto.md +0 -190
- package/templates/commands/uzys/build.md +0 -42
- package/templates/commands/uzys/plan.md +0 -55
- package/templates/commands/uzys/review.md +0 -44
- package/templates/commands/uzys/ship.md +0 -49
- package/templates/commands/uzys/spec.md +0 -93
- package/templates/commands/uzys/test.md +0 -58
- package/templates/hooks/agentshield-gate.sh +0 -101
- package/templates/hooks/gate-check.sh +0 -138
- package/templates/opencode/.opencode/commands/uzys-build.md +0 -22
- package/templates/opencode/.opencode/commands/uzys-plan.md +0 -22
- package/templates/opencode/.opencode/commands/uzys-review.md +0 -22
- package/templates/opencode/.opencode/commands/uzys-ship.md +0 -22
- package/templates/opencode/.opencode/commands/uzys-spec.md +0 -28
- package/templates/opencode/.opencode/commands/uzys-test.md +0 -22
- package/templates/opencode/.opencode/plugins/uzys-harness.ts +0 -146
- package/templates/project-claude/fragments/csr-fastapi/workflow.md +0 -8
- package/templates/project-claude/fragments/csr-fastify/workflow.md +0 -8
- package/templates/project-claude/fragments/csr-supabase/workflow.md +0 -8
- package/templates/project-claude/fragments/data/workflow.md +0 -9
- package/templates/project-claude/fragments/ssr-htmx/workflow.md +0 -8
- package/templates/project-claude/fragments/ssr-nextjs/workflow.md +0 -8
- package/templates/project-claude/fragments/tooling/workflow.md +0 -5
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# PreToolUse Hook: 워크플로우 게이트 강제
|
|
3
|
-
# Skill 도구 호출 시 이전 게이트 완료 여부 확인
|
|
4
|
-
# 미완료 시 exit code 2로 차단
|
|
5
|
-
set -e
|
|
6
|
-
|
|
7
|
-
GATE_FILE=".claude/gate-status.json"
|
|
8
|
-
INPUT_JSON=$(cat)
|
|
9
|
-
|
|
10
|
-
# tool_input에서 skill 이름 추출 (jq 우선, bash 폴백)
|
|
11
|
-
if command -v jq &> /dev/null; then
|
|
12
|
-
SKILL_NAME=$(echo "$INPUT_JSON" | jq -r '.tool_input.skill // .tool_input.args // ""' 2>/dev/null || echo "")
|
|
13
|
-
else
|
|
14
|
-
# jq 없을 때 bash 폴백
|
|
15
|
-
SKILL_NAME=$(echo "$INPUT_JSON" | grep -o '"skill"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*: *"//;s/"//')
|
|
16
|
-
if [ -z "$SKILL_NAME" ]; then
|
|
17
|
-
SKILL_NAME=$(echo "$INPUT_JSON" | grep -o '"args"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*: *"//;s/"//')
|
|
18
|
-
fi
|
|
19
|
-
fi
|
|
20
|
-
|
|
21
|
-
# uzys: 커맨드가 아니면 통과
|
|
22
|
-
# uzys:auto는 게이트 체크 제외 (auto 커맨드가 내부에서 gate-status 직접 관리)
|
|
23
|
-
case "$SKILL_NAME" in
|
|
24
|
-
uzys:spec|uzys:plan|uzys:build|uzys:test|uzys:review|uzys:ship) ;;
|
|
25
|
-
uzys:auto) exit 0 ;;
|
|
26
|
-
*) exit 0 ;;
|
|
27
|
-
esac
|
|
28
|
-
|
|
29
|
-
# gate-status.json 없으면 초기 상태 생성 (모두 미완료)
|
|
30
|
-
if [ ! -f "$GATE_FILE" ]; then
|
|
31
|
-
mkdir -p "$(dirname "$GATE_FILE")"
|
|
32
|
-
cat > "$GATE_FILE" << 'INIT'
|
|
33
|
-
{
|
|
34
|
-
"define": { "completed": false },
|
|
35
|
-
"plan": { "completed": false },
|
|
36
|
-
"build": { "completed": false },
|
|
37
|
-
"verify": { "completed": false },
|
|
38
|
-
"review": { "completed": false },
|
|
39
|
-
"ship": { "completed": false },
|
|
40
|
-
"hotfix": false
|
|
41
|
-
}
|
|
42
|
-
INIT
|
|
43
|
-
fi
|
|
44
|
-
|
|
45
|
-
# v26.11.2 — 게이트 상태 읽기. jq 실패/손상된 JSON 시 안전한 default "false"로 fail-secure.
|
|
46
|
-
# (이전: jq 실패 시 빈 출력 가능 → 호출자에서 일관성 없는 처리. C2 수정)
|
|
47
|
-
is_completed() {
|
|
48
|
-
local result=""
|
|
49
|
-
if command -v jq &> /dev/null; then
|
|
50
|
-
result=$(jq -r ".$1.completed // false" "$GATE_FILE" 2>/dev/null) || result="false"
|
|
51
|
-
else
|
|
52
|
-
grep -A1 "\"$1\"" "$GATE_FILE" 2>/dev/null | grep -o '"completed"[[:space:]]*:[[:space:]]*true' | head -1 | grep -q 'true' && result="true" || result="false"
|
|
53
|
-
fi
|
|
54
|
-
case "$result" in
|
|
55
|
-
true|false) echo "$result" ;;
|
|
56
|
-
*) echo "false" ;;
|
|
57
|
-
esac
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
is_hotfix() {
|
|
61
|
-
local result=""
|
|
62
|
-
if command -v jq &> /dev/null; then
|
|
63
|
-
result=$(jq -r ".hotfix // false" "$GATE_FILE" 2>/dev/null) || result="false"
|
|
64
|
-
else
|
|
65
|
-
grep -o '"hotfix"[[:space:]]*:[[:space:]]*true' "$GATE_FILE" 2>/dev/null | head -1 | grep -q 'true' && result="true" || result="false"
|
|
66
|
-
fi
|
|
67
|
-
case "$result" in
|
|
68
|
-
true|false) echo "$result" ;;
|
|
69
|
-
*) echo "false" ;;
|
|
70
|
-
esac
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
HOTFIX=$(is_hotfix)
|
|
74
|
-
|
|
75
|
-
# 게이트 순서 검증
|
|
76
|
-
case "$SKILL_NAME" in
|
|
77
|
-
uzys:spec)
|
|
78
|
-
# Define은 항상 허용 (첫 단계). 새 사이클 시작이므로 모든 게이트 리셋
|
|
79
|
-
cat > "$GATE_FILE" << 'RESET'
|
|
80
|
-
{
|
|
81
|
-
"define": { "completed": false },
|
|
82
|
-
"plan": { "completed": false },
|
|
83
|
-
"build": { "completed": false },
|
|
84
|
-
"verify": { "completed": false },
|
|
85
|
-
"review": { "completed": false },
|
|
86
|
-
"ship": { "completed": false },
|
|
87
|
-
"hotfix": false
|
|
88
|
-
}
|
|
89
|
-
RESET
|
|
90
|
-
exit 0
|
|
91
|
-
;;
|
|
92
|
-
uzys:plan)
|
|
93
|
-
if [ "$(is_completed define)" != "true" ]; then
|
|
94
|
-
echo "BLOCKED: Define 단계가 완료되지 않았습니다. /uzys:spec을 먼저 실행하세요. (docs/SPEC.md 필요)" >&2
|
|
95
|
-
exit 2
|
|
96
|
-
fi
|
|
97
|
-
;;
|
|
98
|
-
uzys:build)
|
|
99
|
-
if [ "$HOTFIX" = "true" ]; then
|
|
100
|
-
exit 0 # hotfix 모드: plan 건너뛰기 허용
|
|
101
|
-
fi
|
|
102
|
-
if [ "$(is_completed plan)" != "true" ]; then
|
|
103
|
-
echo "BLOCKED: Plan 단계가 완료되지 않았습니다. /uzys:plan을 먼저 실행하세요. (docs/todo.md 필요)" >&2
|
|
104
|
-
exit 2
|
|
105
|
-
fi
|
|
106
|
-
;;
|
|
107
|
-
uzys:test)
|
|
108
|
-
if [ "$(is_completed build)" != "true" ]; then
|
|
109
|
-
echo "BLOCKED: Build 단계가 완료되지 않았습니다. /uzys:build를 먼저 실행하세요." >&2
|
|
110
|
-
exit 2
|
|
111
|
-
fi
|
|
112
|
-
;;
|
|
113
|
-
uzys:review)
|
|
114
|
-
if [ "$HOTFIX" = "true" ]; then
|
|
115
|
-
exit 0 # hotfix 모드: review 건너뛰기 허용
|
|
116
|
-
fi
|
|
117
|
-
if [ "$(is_completed verify)" != "true" ]; then
|
|
118
|
-
echo "BLOCKED: Verify 단계가 완료되지 않았습니다. /uzys:test를 먼저 실행하세요." >&2
|
|
119
|
-
exit 2
|
|
120
|
-
fi
|
|
121
|
-
;;
|
|
122
|
-
uzys:ship)
|
|
123
|
-
if [ "$HOTFIX" = "true" ]; then
|
|
124
|
-
# hotfix: verify만 필수
|
|
125
|
-
if [ "$(is_completed verify)" != "true" ]; then
|
|
126
|
-
echo "BLOCKED: Hotfix 모드에서도 Verify는 필수입니다. /uzys:test를 먼저 실행하세요." >&2
|
|
127
|
-
exit 2
|
|
128
|
-
fi
|
|
129
|
-
exit 0
|
|
130
|
-
fi
|
|
131
|
-
if [ "$(is_completed review)" != "true" ]; then
|
|
132
|
-
echo "BLOCKED: Review 단계가 완료되지 않았습니다. /uzys:review를 먼저 실행하세요." >&2
|
|
133
|
-
exit 2
|
|
134
|
-
fi
|
|
135
|
-
;;
|
|
136
|
-
esac
|
|
137
|
-
|
|
138
|
-
exit 0
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Build phase — TDD로 점진적 구현한다."
|
|
3
|
-
agent: build
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# /uzys-build — OpenCode
|
|
7
|
-
|
|
8
|
-
> **Generated from**: `.claude/commands/uzys/build.md` via TS CLI `src/opencode/skills.ts` (Phase C)
|
|
9
|
-
> **Slash**: `/uzys-build` (OpenCode namespace 미사용 — Phase B2 결정, hyphen 채택)
|
|
10
|
-
|
|
11
|
-
## Goal
|
|
12
|
-
|
|
13
|
-
{COMMAND_BODY_PLACEHOLDER}
|
|
14
|
-
|
|
15
|
-
## OpenCode 제약 참고
|
|
16
|
-
|
|
17
|
-
- Slash 콜론 namespace 미사용 — 파일명 = 커맨드명 (`uzys-build.md` → `/uzys-build`)
|
|
18
|
-
- Plugin lifecycle (`.opencode/plugins/uzys-harness.ts`)이 gate-check / spec-drift / HITO 처리
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
*Phase C에서 본 command 본문이 `.claude/commands/uzys/build.md`로부터 포팅됨.*
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Plan phase — 작업을 검증 가능한 작은 단위로 분해한다."
|
|
3
|
-
agent: plan
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# /uzys-plan — OpenCode
|
|
7
|
-
|
|
8
|
-
> **Generated from**: `.claude/commands/uzys/plan.md` via TS CLI `src/opencode/skills.ts` (Phase C)
|
|
9
|
-
> **Slash**: `/uzys-plan` (OpenCode namespace 미사용 — Phase B2 결정, hyphen 채택)
|
|
10
|
-
|
|
11
|
-
## Goal
|
|
12
|
-
|
|
13
|
-
{COMMAND_BODY_PLACEHOLDER}
|
|
14
|
-
|
|
15
|
-
## OpenCode 제약 참고
|
|
16
|
-
|
|
17
|
-
- Slash 콜론 namespace 미사용 — 파일명 = 커맨드명 (`uzys-plan.md` → `/uzys-plan`)
|
|
18
|
-
- Plugin lifecycle (`.opencode/plugins/uzys-harness.ts`)이 gate-check / spec-drift / HITO 처리
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
*Phase C에서 본 command 본문이 `.claude/commands/uzys/plan.md`로부터 포팅됨.*
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Review phase — 다중 관점 리뷰로 품질을 검증한다."
|
|
3
|
-
agent: plan
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# /uzys-review — OpenCode
|
|
7
|
-
|
|
8
|
-
> **Generated from**: `.claude/commands/uzys/review.md` via TS CLI `src/opencode/skills.ts` (Phase C)
|
|
9
|
-
> **Slash**: `/uzys-review` (OpenCode namespace 미사용 — Phase B2 결정, hyphen 채택)
|
|
10
|
-
|
|
11
|
-
## Goal
|
|
12
|
-
|
|
13
|
-
{COMMAND_BODY_PLACEHOLDER}
|
|
14
|
-
|
|
15
|
-
## OpenCode 제약 참고
|
|
16
|
-
|
|
17
|
-
- Slash 콜론 namespace 미사용 — 파일명 = 커맨드명 (`uzys-review.md` → `/uzys-review`)
|
|
18
|
-
- Plugin lifecycle (`.opencode/plugins/uzys-harness.ts`)이 gate-check / spec-drift / HITO 처리
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
*Phase C에서 본 command 본문이 `.claude/commands/uzys/review.md`로부터 포팅됨.*
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Ship phase — 프리런치 체크리스트 실행 후 배포한다."
|
|
3
|
-
agent: build
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# /uzys-ship — OpenCode
|
|
7
|
-
|
|
8
|
-
> **Generated from**: `.claude/commands/uzys/ship.md` via TS CLI `src/opencode/skills.ts` (Phase C)
|
|
9
|
-
> **Slash**: `/uzys-ship` (OpenCode namespace 미사용 — Phase B2 결정, hyphen 채택)
|
|
10
|
-
|
|
11
|
-
## Goal
|
|
12
|
-
|
|
13
|
-
{COMMAND_BODY_PLACEHOLDER}
|
|
14
|
-
|
|
15
|
-
## OpenCode 제약 참고
|
|
16
|
-
|
|
17
|
-
- Slash 콜론 namespace 미사용 — 파일명 = 커맨드명 (`uzys-ship.md` → `/uzys-ship`)
|
|
18
|
-
- Plugin lifecycle (`.opencode/plugins/uzys-harness.ts`)이 gate-check / spec-drift / HITO 처리
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
*Phase C에서 본 command 본문이 `.claude/commands/uzys/ship.md`로부터 포팅됨.*
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Define phase — 구조화된 스펙을 코드 작성 전에 작성한다."
|
|
3
|
-
agent: plan
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# /uzys-spec — Define Phase (OpenCode)
|
|
7
|
-
|
|
8
|
-
> **Generated from**: `.claude/commands/uzys/spec.md` via TS CLI `src/opencode/skills.ts` (Phase C)
|
|
9
|
-
> **Slash**: `/uzys-spec` (OpenCode namespace 미사용 — Phase B2 결정, hyphen 채택)
|
|
10
|
-
|
|
11
|
-
## Pre-flight
|
|
12
|
-
|
|
13
|
-
이 command 호출 전 확인:
|
|
14
|
-
- 직전 단계 없음 (최초 진입점)
|
|
15
|
-
- `docs/SPEC.md` 또는 `docs/specs/<feature>.md`가 아직 없거나 갱신 필요한 상황
|
|
16
|
-
|
|
17
|
-
## Goal
|
|
18
|
-
|
|
19
|
-
{COMMAND_BODY_PLACEHOLDER}
|
|
20
|
-
|
|
21
|
-
## OpenCode 제약 참고
|
|
22
|
-
|
|
23
|
-
- Slash 콜론 namespace 미사용 — 파일명 = 커맨드명 (`uzys-spec.md` → `/uzys-spec`)
|
|
24
|
-
- Plugin lifecycle (`.opencode/plugins/uzys-harness.ts`)이 gate-check / spec-drift / HITO 처리
|
|
25
|
-
|
|
26
|
-
---
|
|
27
|
-
|
|
28
|
-
*Phase C에서 본 command 본문이 `.claude/commands/uzys/spec.md`로부터 포팅됨.*
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Verify phase — TDD 워크플로우와 Track별 커버리지 게이트를 실행한다."
|
|
3
|
-
agent: build
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# /uzys-test — OpenCode
|
|
7
|
-
|
|
8
|
-
> **Generated from**: `.claude/commands/uzys/test.md` via TS CLI `src/opencode/skills.ts` (Phase C)
|
|
9
|
-
> **Slash**: `/uzys-test` (OpenCode namespace 미사용 — Phase B2 결정, hyphen 채택)
|
|
10
|
-
|
|
11
|
-
## Goal
|
|
12
|
-
|
|
13
|
-
{COMMAND_BODY_PLACEHOLDER}
|
|
14
|
-
|
|
15
|
-
## OpenCode 제약 참고
|
|
16
|
-
|
|
17
|
-
- Slash 콜론 namespace 미사용 — 파일명 = 커맨드명 (`uzys-test.md` → `/uzys-test`)
|
|
18
|
-
- Plugin lifecycle (`.opencode/plugins/uzys-harness.ts`)이 gate-check / spec-drift / HITO 처리
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
*Phase C에서 본 command 본문이 `.claude/commands/uzys/test.md`로부터 포팅됨.*
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
// uzys-harness — OpenCode plugin (Phase E1 본문)
|
|
2
|
-
//
|
|
3
|
-
// SPEC: docs/specs/opencode-compat.md AC5
|
|
4
|
-
// ADR: docs/decisions/ADR-004-opencode-plugin-mapping.md
|
|
5
|
-
//
|
|
6
|
-
// Hook 매핑 (ADR-004 v1):
|
|
7
|
-
// - PreToolUse → tool.execute.before (gate-check 등가)
|
|
8
|
-
// - PostToolUse → tool.execute.after (spec-drift-check 등가)
|
|
9
|
-
// - UserPromptSubmit → messageCreated filter role==="user" (HITO 카운터)
|
|
10
|
-
//
|
|
11
|
-
// Reference: templates/hooks/{hito-counter,gate-check,spec-drift-check}.sh
|
|
12
|
-
//
|
|
13
|
-
// 본 파일은 사용자 프로젝트에 그대로 복사되는 self-contained template.
|
|
14
|
-
// 핵심 로직은 src/opencode/plugin-helpers.ts에서도 동일하게 유지(테스트용 미러).
|
|
15
|
-
//
|
|
16
|
-
// Phase E2 실측 항목 (한계 L1~L4):
|
|
17
|
-
// L1 Plugin runtime (Bun vs Node) — OpenCode CLI 실측 필요
|
|
18
|
-
// L2 tool.execute.before 인자 정확한 시그니처
|
|
19
|
-
// L3 messageCreated user-only 필터 충분 여부
|
|
20
|
-
// L4 throw 시 graceful 차단/crash 동작
|
|
21
|
-
|
|
22
|
-
import type { Plugin } from "@opencode-ai/plugin";
|
|
23
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
24
|
-
import { join } from "node:path";
|
|
25
|
-
|
|
26
|
-
type GateStatus = {
|
|
27
|
-
define?: { completed?: boolean };
|
|
28
|
-
plan?: { completed?: boolean };
|
|
29
|
-
build?: { completed?: boolean };
|
|
30
|
-
verify?: { completed?: boolean };
|
|
31
|
-
review?: { completed?: boolean };
|
|
32
|
-
ship?: { completed?: boolean };
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
type Phase = "define" | "plan" | "build" | "verify" | "review" | "ship";
|
|
36
|
-
|
|
37
|
-
const PHASE_DEPENDENCY: Record<string, Phase | null> = {
|
|
38
|
-
"uzys-spec": null,
|
|
39
|
-
"uzys-plan": "define",
|
|
40
|
-
"uzys-build": "plan",
|
|
41
|
-
"uzys-test": "build",
|
|
42
|
-
"uzys-review": "verify",
|
|
43
|
-
"uzys-ship": "review",
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const PHASE_TO_COMMAND: Record<Phase, string> = {
|
|
47
|
-
define: "spec",
|
|
48
|
-
plan: "plan",
|
|
49
|
-
build: "build",
|
|
50
|
-
verify: "test",
|
|
51
|
-
review: "review",
|
|
52
|
-
ship: "ship",
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const SPEC_PATH_RE = /docs\/SPEC\.md$|docs\/specs\/[^/]+\.md$/;
|
|
56
|
-
|
|
57
|
-
const UzysHarness: Plugin = async ({ directory }) => {
|
|
58
|
-
return {
|
|
59
|
-
"tool.execute.before": async (input, _output) => {
|
|
60
|
-
const command = extractSlashCommand(input);
|
|
61
|
-
if (!command) return;
|
|
62
|
-
|
|
63
|
-
const required = PHASE_DEPENDENCY[command];
|
|
64
|
-
if (required === undefined) return;
|
|
65
|
-
if (required === null) return;
|
|
66
|
-
|
|
67
|
-
const status = readGateStatus(directory);
|
|
68
|
-
if (status[required]?.completed !== true) {
|
|
69
|
-
throw new Error(
|
|
70
|
-
`[uzys-harness] /${command} requires ${required} gate completion. ` +
|
|
71
|
-
`Run /uzys-${PHASE_TO_COMMAND[required]} first.`,
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
|
|
76
|
-
"tool.execute.after": async (input, _output) => {
|
|
77
|
-
const filePath = extractFilePath(input);
|
|
78
|
-
if (!filePath || !SPEC_PATH_RE.test(filePath)) return;
|
|
79
|
-
|
|
80
|
-
const date = new Date().toISOString().slice(0, 10);
|
|
81
|
-
const logDir = join(directory, ".claude/evals");
|
|
82
|
-
try {
|
|
83
|
-
mkdirSync(logDir, { recursive: true });
|
|
84
|
-
const stamp = new Date().toISOString();
|
|
85
|
-
writeFileSync(join(logDir, `spec-drift-${date}.log`), `${stamp} edited ${filePath}\n`, {
|
|
86
|
-
flag: "a",
|
|
87
|
-
});
|
|
88
|
-
} catch {
|
|
89
|
-
// Best-effort logging — never block tool execution.
|
|
90
|
-
}
|
|
91
|
-
},
|
|
92
|
-
|
|
93
|
-
messageCreated: async (message, _output) => {
|
|
94
|
-
if (message.role !== "user") return;
|
|
95
|
-
|
|
96
|
-
const date = new Date().toISOString().slice(0, 10);
|
|
97
|
-
const logDir = join(directory, ".claude/evals");
|
|
98
|
-
try {
|
|
99
|
-
mkdirSync(logDir, { recursive: true });
|
|
100
|
-
const stamp = new Date().toISOString();
|
|
101
|
-
writeFileSync(join(logDir, `hito-${date}.log`), `${stamp} prompt_submit\n`, {
|
|
102
|
-
flag: "a",
|
|
103
|
-
});
|
|
104
|
-
} catch {
|
|
105
|
-
// Privacy: prompt body never logged. Best-effort.
|
|
106
|
-
}
|
|
107
|
-
},
|
|
108
|
-
};
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
export default UzysHarness;
|
|
112
|
-
|
|
113
|
-
function readGateStatus(projectDir: string): GateStatus {
|
|
114
|
-
const path = join(projectDir, ".claude/gate-status.json");
|
|
115
|
-
if (!existsSync(path)) return {};
|
|
116
|
-
try {
|
|
117
|
-
return JSON.parse(readFileSync(path, "utf8")) as GateStatus;
|
|
118
|
-
} catch {
|
|
119
|
-
return {};
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function extractSlashCommand(input: unknown): string | null {
|
|
124
|
-
if (!input || typeof input !== "object") return null;
|
|
125
|
-
const c = input as { command?: unknown; tool?: unknown; args?: { command?: unknown } };
|
|
126
|
-
if (typeof c.command === "string") return c.command.startsWith("/") ? c.command.slice(1) : c.command;
|
|
127
|
-
if (typeof c.tool === "string" && c.tool.startsWith("uzys-")) return c.tool;
|
|
128
|
-
if (c.args && typeof c.args === "object" && typeof c.args.command === "string") {
|
|
129
|
-
return c.args.command.startsWith("/") ? c.args.command.slice(1) : c.args.command;
|
|
130
|
-
}
|
|
131
|
-
return null;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function extractFilePath(input: unknown): string | null {
|
|
135
|
-
if (!input || typeof input !== "object") return null;
|
|
136
|
-
const c = input as {
|
|
137
|
-
filePath?: unknown;
|
|
138
|
-
args?: { filePath?: unknown; path?: unknown };
|
|
139
|
-
};
|
|
140
|
-
if (typeof c.filePath === "string") return c.filePath;
|
|
141
|
-
if (c.args && typeof c.args === "object") {
|
|
142
|
-
if (typeof c.args.filePath === "string") return c.args.filePath;
|
|
143
|
-
if (typeof c.args.path === "string") return c.args.path;
|
|
144
|
-
}
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
6-gate 개발 워크플로우 적용:
|
|
2
|
-
|
|
3
|
-
```
|
|
4
|
-
Define(/uzys:spec) -> Plan(/uzys:plan) -> Build(/uzys:build) -> Verify(/uzys:test) -> Review(/uzys:review) -> Ship(/uzys:ship)
|
|
5
|
-
```
|
|
6
|
-
|
|
7
|
-
- 각 게이트를 순서대로 통과해야 다음 단계 진행 가능.
|
|
8
|
-
- Hotfix 단축: Build -> Verify -> Ship (긴급 수정에 한함).
|
|
9
|
-
- 탐색적 분석(EDA)은 Build 게이트에서 노트북 기반 진행 허용.
|