@haposoft/cafekit 0.8.16 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -67
- package/bin/install.js +141 -194
- package/bin/lib/copy-utils.js +61 -0
- package/bin/lib/opencode-install.js +866 -0
- package/package.json +4 -1
- package/src/claude/CLAUDE.md +2 -2
- package/src/claude/migration-manifest.json +1 -0
- package/src/claude/rules/skill-domain-routing.md +2 -0
- package/src/claude/rules/skill-workflow-routing.md +3 -1
- package/src/claude/skills/qs/SKILL.md +177 -0
- package/src/claude/skills/qs/templates/qs.md +30 -0
- package/src/opencode/AGENTS.md +140 -0
- package/src/opencode/plugins/docs-sync.ts +181 -0
- package/src/opencode/plugins/inspect-block.ts +164 -0
- package/src/opencode/plugins/privacy-block.ts +182 -0
- package/src/opencode/plugins/rules.ts +163 -0
- package/src/opencode/plugins/session.ts +179 -0
- package/src/opencode/plugins/state.ts +253 -0
- package/src/opencode/plugins/usage.ts +178 -0
- package/src/antigravity/GEMINI.md +0 -162
- package/src/antigravity/workflows/code.md +0 -16
- package/src/antigravity/workflows/docs-init.md +0 -432
- package/src/antigravity/workflows/docs-update.md +0 -245
- package/src/antigravity/workflows/impact-analysis-output-example.md +0 -313
- package/src/antigravity/workflows/impact-analysis.md +0 -730
- package/src/antigravity/workflows/review.md +0 -15
- package/src/antigravity/workflows/spec-design.md +0 -220
- package/src/antigravity/workflows/spec-init.md +0 -78
- package/src/antigravity/workflows/spec-requirements.md +0 -122
- package/src/antigravity/workflows/spec-status.md +0 -95
- package/src/antigravity/workflows/spec-tasks.md +0 -156
- package/src/antigravity/workflows/spec-validate.md +0 -106
- package/src/antigravity/workflows/test.md +0 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@haposoft/cafekit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Claude Code-first spec-driven workflow for AI coding assistants. Bundles CafeKit hapo: skills, runtime hooks, agents, and installer scaffolding.",
|
|
5
5
|
"author": "Haposoft <nghialt@haposoft.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -43,5 +43,8 @@
|
|
|
43
43
|
],
|
|
44
44
|
"engines": {
|
|
45
45
|
"node": ">=18.0.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@opencode-ai/plugin": "1.15.11"
|
|
46
49
|
}
|
|
47
50
|
}
|
package/src/claude/CLAUDE.md
CHANGED
|
@@ -15,7 +15,7 @@ These rules reduce common agent coding failures: hidden assumptions, overbuilt s
|
|
|
15
15
|
- Do not assume silently. State assumptions when they affect the work.
|
|
16
16
|
- If multiple interpretations are plausible, surface them before implementation.
|
|
17
17
|
- If the simpler option is likely better, say so and push back.
|
|
18
|
-
- If the task/spec is too vague to verify,
|
|
18
|
+
- If the task/spec is too vague to verify, use `/hapo:qs` or ask one grounded clarification before planning.
|
|
19
19
|
- Before feature planning or coding, read `./README.md` for project context.
|
|
20
20
|
|
|
21
21
|
### 2. Simplicity First
|
|
@@ -46,7 +46,7 @@ These rules reduce common agent coding failures: hidden assumptions, overbuilt s
|
|
|
46
46
|
Use this loop for non-trivial work:
|
|
47
47
|
|
|
48
48
|
1. **Understand** — read README, relevant docs, active spec/task, and existing code.
|
|
49
|
-
2. **Plan** — choose the smallest coherent path; use `/hapo:specs` for feature specs when
|
|
49
|
+
2. **Plan** — choose the smallest coherent path; use `/hapo:qs` when requirements are unclear and `/hapo:specs` for feature specs when ready.
|
|
50
50
|
3. **Execute** — implement only the active task/scope; no placeholder completion.
|
|
51
51
|
4. **Verify** — run exact task commands first, then repo-level lint/test/build as needed.
|
|
52
52
|
5. **Sync** — mark task state only after proof exists.
|
|
@@ -29,6 +29,7 @@ User wants to...
|
|
|
29
29
|
|
|
30
30
|
```text
|
|
31
31
|
User wants to...
|
|
32
|
+
├── clarify missing requirements or acceptance criteria -> /hapo:qs
|
|
32
33
|
├── find files, locate code, scan project structure -> /hapo:inspect
|
|
33
34
|
├── diagnose an error or failing check -> /hapo:debug
|
|
34
35
|
├── understand possible side effects -> /hapo:impact-analysis
|
|
@@ -41,6 +42,7 @@ Local source truth comes from `/hapo:inspect`; external/current knowledge comes
|
|
|
41
42
|
|
|
42
43
|
```text
|
|
43
44
|
User wants to...
|
|
45
|
+
├── prepare stakeholder/customer questions before docs -> /hapo:qs --batch
|
|
44
46
|
├── create missing project docs -> /hapo:docs --init
|
|
45
47
|
├── update docs after source changes -> /hapo:docs --update
|
|
46
48
|
├── summarize codebase quickly -> /hapo:docs --summarize
|
|
@@ -7,11 +7,12 @@ Do not inject or force a skill when the user explicitly asks for a direct answer
|
|
|
7
7
|
## Core Specification Workflow
|
|
8
8
|
|
|
9
9
|
```text
|
|
10
|
-
/hapo:brainstorm -> /hapo:specs -> /hapo:develop -> /hapo:test -> /hapo:code-review -> /hapo:git
|
|
10
|
+
/hapo:qs -> /hapo:brainstorm -> /hapo:specs -> /hapo:develop -> /hapo:test -> /hapo:code-review -> /hapo:git
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
| User intent | Suggested start |
|
|
14
14
|
|---|---|
|
|
15
|
+
| vague request, missing acceptance criteria, unclear scope, stakeholder questions | `/hapo:qs` |
|
|
15
16
|
| unclear idea, possible approaches, scope tradeoffs | `/hapo:brainstorm` |
|
|
16
17
|
| create requirements, design, task breakdown, validate spec | `/hapo:specs` |
|
|
17
18
|
| implement an approved spec or a specific task file | `/hapo:develop` |
|
|
@@ -81,4 +82,5 @@ Use `/hapo:research` for external knowledge. Use `/hapo:inspect` for local sourc
|
|
|
81
82
|
- Add a secondary skill only when it materially changes execution.
|
|
82
83
|
- Prefer explicit user commands over this table.
|
|
83
84
|
- If two workflows conflict, ask one concise clarification.
|
|
85
|
+
- If missing information blocks workflow selection, use `/hapo:qs` before choosing brainstorm/specs/develop.
|
|
84
86
|
- If the user asks to "fix" and root cause is unknown, start with `/hapo:debug` unless the issue is trivial and local.
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hapo:qs
|
|
3
|
+
description: "Clarify vague requests before planning or implementation. Use when requirements, acceptance criteria, scope, constraints, stakeholder decisions, or next workflow readiness are unclear."
|
|
4
|
+
argument-hint: "<request_or_context> [--batch|--spec-ready|--stakeholder]"
|
|
5
|
+
version: 1.0.0
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# QS Skill
|
|
9
|
+
|
|
10
|
+
`hapo:qs` turns unclear intent into answerable questions and a readiness verdict. It is a clarification gate before `hapo:brainstorm`, `hapo:specs`, `hapo:docs --reconstruct`, `hapo:debug`, or `hapo:develop`.
|
|
11
|
+
|
|
12
|
+
## Core Stance
|
|
13
|
+
|
|
14
|
+
- Context before questions. Read the useful project/spec/docs/source context before asking.
|
|
15
|
+
- Questions are work products. Make them specific, prioritized, and easy to answer.
|
|
16
|
+
- One thing at a time in interactive mode.
|
|
17
|
+
- Prefer multiple-choice options with a recommended default when the context supports it.
|
|
18
|
+
- Do not design the solution unless the user explicitly moves to `hapo:brainstorm`.
|
|
19
|
+
- Do not create specs or write code from this skill.
|
|
20
|
+
|
|
21
|
+
<CLARIFICATION-ONLY-GATE>
|
|
22
|
+
Do NOT implement, scaffold, edit product code, generate full specs, or make architecture decisions as final.
|
|
23
|
+
The output is questions, assumptions, readiness, and next-step guidance.
|
|
24
|
+
</CLARIFICATION-ONLY-GATE>
|
|
25
|
+
|
|
26
|
+
## When To Use
|
|
27
|
+
|
|
28
|
+
Use `hapo:qs` when:
|
|
29
|
+
- The request is too vague to verify.
|
|
30
|
+
- Acceptance criteria are missing.
|
|
31
|
+
- Scope boundary is unclear.
|
|
32
|
+
- Stakeholder/customer input is needed before specs.
|
|
33
|
+
- The user asks "what should I ask?", "what is missing?", "can this go to specs?", or "is this clear enough?"
|
|
34
|
+
- A spec/task has ambiguity that would make `hapo:develop` risky.
|
|
35
|
+
- A legacy reconstruction or bug report lacks enough scope to start the correct workflow.
|
|
36
|
+
|
|
37
|
+
Do not use it when:
|
|
38
|
+
- The user asks for a direct factual answer that can be answered safely.
|
|
39
|
+
- The user already gave exact output, acceptance criteria, scope, constraints, and target files.
|
|
40
|
+
- The right action is clearly `hapo:debug`, `hapo:inspect`, `hapo:research`, or `hapo:docs --reconstruct`.
|
|
41
|
+
|
|
42
|
+
## Modes
|
|
43
|
+
|
|
44
|
+
- Default interactive mode: ask one highest-value question, then wait.
|
|
45
|
+
- `--batch`: produce a grouped question list for a stakeholder/customer/team.
|
|
46
|
+
- `--spec-ready`: audit whether the request can move to `hapo:specs`.
|
|
47
|
+
- `--stakeholder`: write business-friendly questions with minimal implementation jargon.
|
|
48
|
+
|
|
49
|
+
If multiple modes appear, use the most restrictive mode in this order: `--spec-ready`, `--batch`, `--stakeholder`, default.
|
|
50
|
+
|
|
51
|
+
## Workflow
|
|
52
|
+
|
|
53
|
+
### 1. Context Scout
|
|
54
|
+
|
|
55
|
+
Read only enough context to make the questions concrete:
|
|
56
|
+
- `README.md`
|
|
57
|
+
- relevant `docs/`
|
|
58
|
+
- relevant `specs/`
|
|
59
|
+
- relevant source files when the request names a feature, module, API, UI, or bug
|
|
60
|
+
|
|
61
|
+
Use `hapo:inspect` or focused search when the location is unclear. Do not scan the whole repo unless the question is about the whole repo.
|
|
62
|
+
|
|
63
|
+
### 2. Build The Clarification Map
|
|
64
|
+
|
|
65
|
+
Create a private map with these fields:
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
Known facts:
|
|
69
|
+
Assumptions:
|
|
70
|
+
Missing decisions:
|
|
71
|
+
Blocking unknowns:
|
|
72
|
+
Non-blocking unknowns:
|
|
73
|
+
Possible next workflow:
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Classify each unknown:
|
|
77
|
+
- `P0`: blocks correct next action.
|
|
78
|
+
- `P1`: high-risk ambiguity; should answer before implementation.
|
|
79
|
+
- `P2`: useful detail; can defer.
|
|
80
|
+
|
|
81
|
+
### 3. Ask Or Report
|
|
82
|
+
|
|
83
|
+
Default interactive mode:
|
|
84
|
+
- Ask exactly one `P0` question.
|
|
85
|
+
- Make it concrete and grounded in observed context.
|
|
86
|
+
- If possible, provide 2-3 options.
|
|
87
|
+
- Put the recommended option first and explain the tradeoff in one sentence.
|
|
88
|
+
|
|
89
|
+
`--batch` or `--stakeholder`:
|
|
90
|
+
- Produce grouped questions by priority.
|
|
91
|
+
- Keep each question answerable.
|
|
92
|
+
- Include recommended options only when they are justified by context.
|
|
93
|
+
|
|
94
|
+
`--spec-ready`:
|
|
95
|
+
- Return a readiness checklist and verdict.
|
|
96
|
+
- Do not ask a long question list unless verdict is `not-ready`.
|
|
97
|
+
|
|
98
|
+
### 4. Readiness Verdict
|
|
99
|
+
|
|
100
|
+
End with one of:
|
|
101
|
+
- `not-ready`: missing P0 decisions.
|
|
102
|
+
- `brainstorm-ready`: enough to explore solution options, but not enough for specs.
|
|
103
|
+
- `specs-ready`: enough to run `/hapo:specs <request>`.
|
|
104
|
+
- `develop-ready`: an approved spec/task exists and no blocking ambiguity remains.
|
|
105
|
+
|
|
106
|
+
### 5. Next Step
|
|
107
|
+
|
|
108
|
+
Suggest exactly one next command:
|
|
109
|
+
- `/hapo:qs ...` when another clarification round is required.
|
|
110
|
+
- `/hapo:brainstorm ...` when design/options are still open.
|
|
111
|
+
- `/hapo:specs ...` when requirements are clear enough.
|
|
112
|
+
- `/hapo:debug ...` when the issue is a bug with unknown root cause.
|
|
113
|
+
- `/hapo:docs --reconstruct <scope>` when the task is legacy/as-is docs.
|
|
114
|
+
- `/hapo:develop <feature>` only when an approved spec/task is already clear.
|
|
115
|
+
|
|
116
|
+
## Output Formats
|
|
117
|
+
|
|
118
|
+
### Default Interactive Output
|
|
119
|
+
|
|
120
|
+
```markdown
|
|
121
|
+
**Context Read**
|
|
122
|
+
- ...
|
|
123
|
+
|
|
124
|
+
**Known**
|
|
125
|
+
- ...
|
|
126
|
+
|
|
127
|
+
**Blocking Unknown**
|
|
128
|
+
- P0: ...
|
|
129
|
+
|
|
130
|
+
**Question**
|
|
131
|
+
...
|
|
132
|
+
|
|
133
|
+
**Options**
|
|
134
|
+
- A. ... (Recommended) - ...
|
|
135
|
+
- B. ... - ...
|
|
136
|
+
- C. ... - ...
|
|
137
|
+
|
|
138
|
+
**Readiness**
|
|
139
|
+
not-ready | brainstorm-ready | specs-ready | develop-ready
|
|
140
|
+
|
|
141
|
+
**Next**
|
|
142
|
+
/hapo:qs ...
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Batch Output
|
|
146
|
+
|
|
147
|
+
Use `templates/qs.md` when the user asks to save or document the question set.
|
|
148
|
+
|
|
149
|
+
```markdown
|
|
150
|
+
**Question Set**
|
|
151
|
+
|
|
152
|
+
**P0 - Must Answer**
|
|
153
|
+
1. ...
|
|
154
|
+
|
|
155
|
+
**P1 - Should Answer**
|
|
156
|
+
1. ...
|
|
157
|
+
|
|
158
|
+
**P2 - Can Defer**
|
|
159
|
+
1. ...
|
|
160
|
+
|
|
161
|
+
**Assumptions To Confirm**
|
|
162
|
+
- ...
|
|
163
|
+
|
|
164
|
+
**Readiness**
|
|
165
|
+
...
|
|
166
|
+
|
|
167
|
+
**Next**
|
|
168
|
+
...
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Quality Bar
|
|
172
|
+
|
|
173
|
+
- Every P0 question must explain what decision it unlocks.
|
|
174
|
+
- No generic "please clarify" questions.
|
|
175
|
+
- No more than one interactive question per response.
|
|
176
|
+
- No implementation plan unless the next command is `hapo:brainstorm` or `hapo:specs`.
|
|
177
|
+
- If no P0/P1 unknown exists, do not invent questions. Say it is ready and name the next command.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Question Set: {{TITLE}}
|
|
2
|
+
|
|
3
|
+
## Context Read
|
|
4
|
+
- {{CONTEXT_ITEM}}
|
|
5
|
+
|
|
6
|
+
## Known Facts
|
|
7
|
+
- {{KNOWN_FACT}}
|
|
8
|
+
|
|
9
|
+
## Assumptions
|
|
10
|
+
- {{ASSUMPTION}}
|
|
11
|
+
|
|
12
|
+
## P0 - Must Answer
|
|
13
|
+
1. **Question:** {{P0_QUESTION}}
|
|
14
|
+
- **Why it matters:** {{WHY_IT_MATTERS}}
|
|
15
|
+
- **Recommended answer:** {{RECOMMENDED_ANSWER}}
|
|
16
|
+
- **Other options:** {{OTHER_OPTIONS}}
|
|
17
|
+
|
|
18
|
+
## P1 - Should Answer
|
|
19
|
+
1. **Question:** {{P1_QUESTION}}
|
|
20
|
+
- **Risk if unanswered:** {{RISK}}
|
|
21
|
+
|
|
22
|
+
## P2 - Can Defer
|
|
23
|
+
1. **Question:** {{P2_QUESTION}}
|
|
24
|
+
- **Can defer until:** {{DEFER_POINT}}
|
|
25
|
+
|
|
26
|
+
## Readiness Verdict
|
|
27
|
+
`not-ready | brainstorm-ready | specs-ready | develop-ready`
|
|
28
|
+
|
|
29
|
+
## Next Command
|
|
30
|
+
`/hapo:qs ... | /hapo:brainstorm ... | /hapo:specs ... | /hapo:debug ... | /hapo:docs --reconstruct ... | /hapo:develop ...`
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Primary operating instructions for OpenCode using the CafeKit runtime.
|
|
4
|
+
|
|
5
|
+
## OpenCode Runtime Mapping
|
|
6
|
+
|
|
7
|
+
- Project instructions live in `AGENTS.md`.
|
|
8
|
+
- CafeKit commands live in `.opencode/commands/` and use OpenCode-native slash names without the `hapo:` prefix.
|
|
9
|
+
- CafeKit subagents live in `.opencode/agents/` using OpenCode frontmatter.
|
|
10
|
+
- CafeKit skills live in `.opencode/skills/` and are read natively by OpenCode.
|
|
11
|
+
- Shared CafeKit support files live in `.opencode/rules/`, `.opencode/scripts/`, `.opencode/references/`, and `.opencode/runtime.json`.
|
|
12
|
+
- OpenCode config is merged into `opencode.json`; keep project-specific model/provider choices there.
|
|
13
|
+
|
|
14
|
+
## Command Surface
|
|
15
|
+
|
|
16
|
+
Use these OpenCode commands:
|
|
17
|
+
|
|
18
|
+
- `/brainstorm <idea-or-problem>`: scout and narrow an unclear idea before specs.
|
|
19
|
+
- `/qs <request-or-context> [--batch|--spec-ready|--stakeholder]`: clarify requirements, missing decisions, and next workflow readiness.
|
|
20
|
+
- `/specs <feature-or-spec-command>`: create, update, validate, or approve specs.
|
|
21
|
+
- `/develop <feature> [task-file] [--flash]`: implement approved spec tasks.
|
|
22
|
+
- `/test [scope|--full]`: verify implementation and collect evidence.
|
|
23
|
+
- `/code-review [scope|--pending]`: review for correctness, regressions, and scope drift.
|
|
24
|
+
- `/debug <issue>`: diagnose root cause without product-code edits.
|
|
25
|
+
- `/hotfix <issue>`: apply a narrow, scout-first production fix.
|
|
26
|
+
- `/docs [--init|--update|--summarize|--reconstruct]`: maintain or reconstruct project docs.
|
|
27
|
+
- `/inspect <target>`: inspect source, artifacts, or external context.
|
|
28
|
+
- `/generate-graph <request>`: generate technical diagrams.
|
|
29
|
+
|
|
30
|
+
The underlying CafeKit skills are still named `hapo:*` in their documentation. In OpenCode, use the commands above; each command reads the matching skill from `.opencode/skills/<skill>/SKILL.md`.
|
|
31
|
+
|
|
32
|
+
## Core Objective
|
|
33
|
+
|
|
34
|
+
Act as the project orchestrator: understand the request, keep scope tight, use the right CafeKit skill/agent, and deliver verified work that follows the project's architecture.
|
|
35
|
+
|
|
36
|
+
## Core Behavior
|
|
37
|
+
|
|
38
|
+
These rules reduce common agent coding failures: hidden assumptions, overbuilt solutions, unrelated edits, and unverified completion claims. They take priority over speed-oriented shortcuts.
|
|
39
|
+
|
|
40
|
+
### 1. Think Before Coding
|
|
41
|
+
|
|
42
|
+
- Do not assume silently. State assumptions when they affect the work.
|
|
43
|
+
- If multiple interpretations are plausible, surface them before implementation.
|
|
44
|
+
- If the simpler option is likely better, say so and push back.
|
|
45
|
+
- If the task/spec is too vague to verify, use `/qs` or ask one grounded clarification before planning.
|
|
46
|
+
- Before feature planning or coding, read `./README.md` for project context.
|
|
47
|
+
|
|
48
|
+
### 2. Simplicity First
|
|
49
|
+
|
|
50
|
+
- Solve the requested problem with the smallest maintainable change.
|
|
51
|
+
- Do not add speculative features, future-proofing, or single-use abstractions.
|
|
52
|
+
- Reuse existing modules before creating new ones.
|
|
53
|
+
- If code grows past 200 lines and could be materially simpler, consider splitting it by real boundaries.
|
|
54
|
+
- Prefer YAGNI, KISS, and DRY in that order.
|
|
55
|
+
|
|
56
|
+
### 3. Surgical Changes
|
|
57
|
+
|
|
58
|
+
- Touch only files required by the task.
|
|
59
|
+
- Do not refactor adjacent code, comments, or formatting unless needed for the requested change.
|
|
60
|
+
- Match existing style even if you would choose another style in a new project.
|
|
61
|
+
- Remove only dead code/imports created by your own change.
|
|
62
|
+
- Mention unrelated issues instead of fixing them opportunistically.
|
|
63
|
+
|
|
64
|
+
### 4. Goal-Driven Execution
|
|
65
|
+
|
|
66
|
+
- Convert requests into verifiable success criteria.
|
|
67
|
+
- For spec tasks, use `Completion Criteria` and `Evidence` as the source of truth. Existing task files may use `Task Test Plan & Verification Evidence` or legacy `Verification & Evidence`.
|
|
68
|
+
- For bugs, reproduce with a failing test or concrete evidence when feasible before fixing.
|
|
69
|
+
- Loop until verification passes or a real blocker is recorded.
|
|
70
|
+
|
|
71
|
+
## CafeKit Operating Loop
|
|
72
|
+
|
|
73
|
+
Use this loop for non-trivial work:
|
|
74
|
+
|
|
75
|
+
1. Understand: read README, relevant docs, active spec/task, and existing code.
|
|
76
|
+
2. Plan: choose the smallest coherent path; use `/qs` when requirements are unclear and `/specs` for feature specs when ready.
|
|
77
|
+
3. Execute: implement only the active task/scope; no placeholder completion.
|
|
78
|
+
4. Verify: run exact task commands first, then repo-level lint/test/build as needed.
|
|
79
|
+
5. Sync: mark task state only after proof exists.
|
|
80
|
+
|
|
81
|
+
## OpenCode Runtime Limits And Replacements
|
|
82
|
+
|
|
83
|
+
- Claude Code hooks/statusline/settings do not run in OpenCode.
|
|
84
|
+
- Treat `.claude/rules/*` as explicit reference material, not injected hook context.
|
|
85
|
+
- When a skill says to use unavailable Claude-specific tools such as `Task`, `TodoWrite`, or `AskUserQuestion`, use OpenCode's agent/subtask flow, a concise markdown checklist, or ask the user directly.
|
|
86
|
+
- Privacy and inspect gates are instruction-level gates in OpenCode unless a project-specific OpenCode plugin adds hard enforcement.
|
|
87
|
+
|
|
88
|
+
## Operating Discipline
|
|
89
|
+
|
|
90
|
+
- If a CafeKit skill may apply, read and use that skill before acting.
|
|
91
|
+
- No completion claim without fresh evidence from the current run: command output, artifact inspection, runtime proof, or an explicitly recorded blocker.
|
|
92
|
+
- For bugs, CI failures, and regressions, diagnose root cause before editing. Symptom patches are not completion.
|
|
93
|
+
- For implementation work, keep each task scoped to one clear owner/context. Reviewers should receive task files, diffs, and acceptance criteria, not chat history.
|
|
94
|
+
- For branch closeout, verify first, then choose an explicit finish action: merge, push/PR, keep branch/worktree, or discard with confirmation.
|
|
95
|
+
|
|
96
|
+
## Definition Of Done
|
|
97
|
+
|
|
98
|
+
A task is done only when all apply:
|
|
99
|
+
|
|
100
|
+
- implementation satisfies `Completion Criteria`
|
|
101
|
+
- `Evidence` is satisfied with concrete proof
|
|
102
|
+
- preflight/build/test outcomes are passing or an explicit blocker is recorded
|
|
103
|
+
- code review has no critical issues
|
|
104
|
+
- a verification receipt exists before task state is synced to `done`
|
|
105
|
+
|
|
106
|
+
`NO_TESTS` and `0 tests + exit 0` are not passing outcomes when the task requires automated tests.
|
|
107
|
+
|
|
108
|
+
## Rule References
|
|
109
|
+
|
|
110
|
+
Consult these when the task touches the relevant area:
|
|
111
|
+
|
|
112
|
+
- Primary workflow: `./.claude/rules/workflow.md`
|
|
113
|
+
- Development rules: `./.claude/rules/ai-dev-rules.md`
|
|
114
|
+
- Subagent coordination: `./.claude/rules/orchestrator.md`
|
|
115
|
+
- Docs maintenance: `./.claude/rules/manage-docs.md`
|
|
116
|
+
- State sync: `./.claude/rules/state-sync.md`
|
|
117
|
+
- Hook handling reference: `./.claude/rules/hook-protocols.md`
|
|
118
|
+
- Other protocols: `./.claude/rules/*`
|
|
119
|
+
|
|
120
|
+
## Skill And Script Use
|
|
121
|
+
|
|
122
|
+
- Evaluate the installed skill catalog before work and activate the relevant skill(s).
|
|
123
|
+
- If there is a reasonable chance a skill applies, prefer the skill workflow over ad hoc execution.
|
|
124
|
+
- If modifying skills, edit the current project/runtime files, not `~/.claude/skills` directly.
|
|
125
|
+
- Run Python skill scripts with the skill venv:
|
|
126
|
+
- macOS/Linux: `.claude/skills/.venv/bin/python3 scripts/<script>.py`
|
|
127
|
+
- Windows: `.claude\skills\.venv\Scripts\python.exe scripts\<script>.py`
|
|
128
|
+
- If a skill script fails, diagnose and fix the script or environment instead of abandoning the task.
|
|
129
|
+
|
|
130
|
+
## Git And Reporting
|
|
131
|
+
|
|
132
|
+
- Use conventional commits.
|
|
133
|
+
- Do not add AI attribution by default.
|
|
134
|
+
- Lint before commit and run the full required verification before push.
|
|
135
|
+
- Keep commits focused on actual changes.
|
|
136
|
+
- Reports should be concise; list unresolved questions or blockers at the end.
|
|
137
|
+
|
|
138
|
+
## Language Consistency
|
|
139
|
+
|
|
140
|
+
When generating specs or structured project output, use the user's preferred language consistently across the whole spec workspace. Technical terms, code samples, and file paths may remain English.
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 Haposoft. MIT License.
|
|
3
|
+
*
|
|
4
|
+
* OpenCode Plugin — docs-sync.ts
|
|
5
|
+
*
|
|
6
|
+
* Port of .claude/hooks/docs-sync.cjs.
|
|
7
|
+
*
|
|
8
|
+
* Behavior:
|
|
9
|
+
* - On session.created: detect if project has source code but no docs/, or if
|
|
10
|
+
* docs/.sync_hash is stale relative to current source-only git hash.
|
|
11
|
+
* - Write banner to `.opencode/session-banner.md` so AGENTS.md / skills can
|
|
12
|
+
* surface it (OpenCode event console.log does not flow into assistant
|
|
13
|
+
* context, only the server log).
|
|
14
|
+
* - Also print to stderr so the OpenCode server log records it.
|
|
15
|
+
*
|
|
16
|
+
* Disable via `.opencode/runtime.json` { "docsSync": false }.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type { Plugin } from "@opencode-ai/plugin";
|
|
20
|
+
import {
|
|
21
|
+
existsSync,
|
|
22
|
+
readFileSync,
|
|
23
|
+
writeFileSync,
|
|
24
|
+
mkdirSync,
|
|
25
|
+
appendFileSync,
|
|
26
|
+
} from "node:fs";
|
|
27
|
+
import { join, dirname } from "node:path";
|
|
28
|
+
import { fileURLToPath } from "node:url";
|
|
29
|
+
import { execSync } from "node:child_process";
|
|
30
|
+
|
|
31
|
+
const PLUGIN_DIR = dirname(fileURLToPath(import.meta.url));
|
|
32
|
+
const BANNER_SECTION_START = "<!-- CAFEKIT DOCS SYNC START -->";
|
|
33
|
+
const BANNER_SECTION_END = "<!-- CAFEKIT DOCS SYNC END -->";
|
|
34
|
+
|
|
35
|
+
function readRuntime(cwd: string): Record<string, any> {
|
|
36
|
+
try {
|
|
37
|
+
const file = join(cwd, ".opencode", "runtime.json");
|
|
38
|
+
return existsSync(file) ? JSON.parse(readFileSync(file, "utf8")) : {};
|
|
39
|
+
} catch {
|
|
40
|
+
return {};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function resolveDocsDir(cwd: string, runtime: Record<string, any>): string {
|
|
45
|
+
const configured = runtime.paths?.docs;
|
|
46
|
+
return join(cwd, typeof configured === "string" && configured ? configured : "docs");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function hasSourceCode(cwd: string): boolean {
|
|
50
|
+
return (
|
|
51
|
+
existsSync(join(cwd, "src")) ||
|
|
52
|
+
existsSync(join(cwd, "app")) ||
|
|
53
|
+
existsSync(join(cwd, "lib")) ||
|
|
54
|
+
existsSync(join(cwd, "package.json")) ||
|
|
55
|
+
existsSync(join(cwd, "index.js")) ||
|
|
56
|
+
existsSync(join(cwd, "main.py"))
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function currentSourceHash(cwd: string): string {
|
|
61
|
+
try {
|
|
62
|
+
return execSync('git log -1 --format="%H" -- . ":(exclude)docs"', {
|
|
63
|
+
cwd,
|
|
64
|
+
encoding: "utf8",
|
|
65
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
66
|
+
}).trim();
|
|
67
|
+
} catch {
|
|
68
|
+
return "";
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function buildMissingDocsBanner(): string {
|
|
73
|
+
return [
|
|
74
|
+
"### 🔴 URGENT SYSTEM ACTION: MISSING DOCUMENTATION 🔴",
|
|
75
|
+
"> BẮT BUỘC (MANDATORY): Hệ thống phát hiện dự án đã có Source Code nhưng thư mục `docs/` chưa tồn tại.",
|
|
76
|
+
"> Nhiệm vụ ĐẦU TIÊN của bạn trong session này là đọc hiểu mã nguồn hiện tại và tạo ra các tài liệu tiêu chuẩn:",
|
|
77
|
+
"> 1. `docs/system-architecture.md` (Kiến trúc hệ thống, phân tích flow)",
|
|
78
|
+
"> 2. `docs/project-overview-pdr.md` (Tổng quan, mục tiêu, tính năng)",
|
|
79
|
+
"> 3. Khởi tạo file hidden `docs/.sync_hash` để theo dõi cập nhật.",
|
|
80
|
+
"> ",
|
|
81
|
+
'> LƯU Ý BẮT BUỘC: Bạn phải chạy lệnh Git này trong Terminal để lấy Hash Code mới nhất: `git log -1 --format="%H" -- . ":(exclude)docs"`',
|
|
82
|
+
"> Sau đó ghi chuẩn giá trị Hash đó vào file `docs/.sync_hash`.",
|
|
83
|
+
].join("\n");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function buildStaleDocsBanner(currentHash: string, lastSyncHash: string): string {
|
|
87
|
+
return [
|
|
88
|
+
"### 🔄 CONTINUOUS DOCS SYNC REQUIRED 🔄",
|
|
89
|
+
`> Source Code vừa có sự thay đổi mới (Git Hash: \`${currentHash}\`) kể từ lần đồng bộ Docs cuối cùng (\`${lastSyncHash || "Chưa gán"}\`).`,
|
|
90
|
+
"> YÊU CẦU TRƯỚC KHI LÀM THÊM TÍNH NĂNG:",
|
|
91
|
+
`> 1. Rà soát file bị thay đổi gần đây (dùng \`git diff ${lastSyncHash} ${currentHash}\` hoặc \`git log\`).`,
|
|
92
|
+
"> 2. Cập nhật lại `docs/system-architecture.md` hoặc các chuẩn code nếu cần thiết.",
|
|
93
|
+
"> 3. Cập nhật Changelog (nhật ký thay đổi).",
|
|
94
|
+
`> 4. KHI HOÀN TẤT, BẠN PHẢI GHI ĐÈ GIÁ TRỊ SAU: \`${currentHash}\` VÀO FILE \`docs/.sync_hash\` ĐỂ CHỐT TRẠNG THÁI HIỆN TẠI.`,
|
|
95
|
+
].join("\n");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function writeBanner(cwd: string, banner: string | null): void {
|
|
99
|
+
const target = join(cwd, ".opencode", "session-banner.md");
|
|
100
|
+
const dir = dirname(target);
|
|
101
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
102
|
+
|
|
103
|
+
const existing = existsSync(target) ? readFileSync(target, "utf8") : "";
|
|
104
|
+
const pattern = new RegExp(`${BANNER_SECTION_START}[\\s\\S]*?${BANNER_SECTION_END}\\n?`);
|
|
105
|
+
const cleaned = existing.replace(pattern, "").trimEnd();
|
|
106
|
+
|
|
107
|
+
if (!banner) {
|
|
108
|
+
if (cleaned !== existing.trimEnd()) {
|
|
109
|
+
writeFileSync(target, cleaned ? `${cleaned}\n` : "");
|
|
110
|
+
}
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const block = [BANNER_SECTION_START, banner, BANNER_SECTION_END].join("\n");
|
|
115
|
+
const next = cleaned ? `${cleaned}\n\n${block}\n` : `${block}\n`;
|
|
116
|
+
writeFileSync(target, next);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function logCrash(error: unknown): void {
|
|
120
|
+
try {
|
|
121
|
+
const logDir = join(PLUGIN_DIR, ".logs");
|
|
122
|
+
if (!existsSync(logDir)) mkdirSync(logDir, { recursive: true });
|
|
123
|
+
appendFileSync(
|
|
124
|
+
join(logDir, "hook-log.jsonl"),
|
|
125
|
+
JSON.stringify({
|
|
126
|
+
ts: new Date().toISOString(),
|
|
127
|
+
hook: "docs-sync",
|
|
128
|
+
status: "crash",
|
|
129
|
+
error: error instanceof Error ? error.message : String(error),
|
|
130
|
+
}) + "\n",
|
|
131
|
+
);
|
|
132
|
+
} catch {
|
|
133
|
+
// fail-open
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export const DocsSync: Plugin = async ({ directory }) => ({
|
|
138
|
+
event: async ({ event }) => {
|
|
139
|
+
try {
|
|
140
|
+
if (event.type !== "session.created") return;
|
|
141
|
+
|
|
142
|
+
const cwd = directory;
|
|
143
|
+
const runtime = readRuntime(cwd);
|
|
144
|
+
if (runtime.docsSync === false) return;
|
|
145
|
+
|
|
146
|
+
if (!hasSourceCode(cwd)) {
|
|
147
|
+
writeBanner(cwd, null);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const docsDir = resolveDocsDir(cwd, runtime);
|
|
152
|
+
|
|
153
|
+
if (!existsSync(docsDir)) {
|
|
154
|
+
const banner = buildMissingDocsBanner();
|
|
155
|
+
writeBanner(cwd, banner);
|
|
156
|
+
console.error(banner);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const currentHash = currentSourceHash(cwd);
|
|
161
|
+
if (!currentHash) {
|
|
162
|
+
writeBanner(cwd, null);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const syncFile = join(docsDir, ".sync_hash");
|
|
167
|
+
const lastSyncHash = existsSync(syncFile) ? readFileSync(syncFile, "utf8").trim() : "";
|
|
168
|
+
|
|
169
|
+
if (lastSyncHash === currentHash) {
|
|
170
|
+
writeBanner(cwd, null);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const banner = buildStaleDocsBanner(currentHash, lastSyncHash);
|
|
175
|
+
writeBanner(cwd, banner);
|
|
176
|
+
console.error(banner);
|
|
177
|
+
} catch (error) {
|
|
178
|
+
logCrash(error);
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
});
|