@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.
Files changed (33) hide show
  1. package/README.md +63 -67
  2. package/bin/install.js +141 -194
  3. package/bin/lib/copy-utils.js +61 -0
  4. package/bin/lib/opencode-install.js +866 -0
  5. package/package.json +4 -1
  6. package/src/claude/CLAUDE.md +2 -2
  7. package/src/claude/migration-manifest.json +1 -0
  8. package/src/claude/rules/skill-domain-routing.md +2 -0
  9. package/src/claude/rules/skill-workflow-routing.md +3 -1
  10. package/src/claude/skills/qs/SKILL.md +177 -0
  11. package/src/claude/skills/qs/templates/qs.md +30 -0
  12. package/src/opencode/AGENTS.md +140 -0
  13. package/src/opencode/plugins/docs-sync.ts +181 -0
  14. package/src/opencode/plugins/inspect-block.ts +164 -0
  15. package/src/opencode/plugins/privacy-block.ts +182 -0
  16. package/src/opencode/plugins/rules.ts +163 -0
  17. package/src/opencode/plugins/session.ts +179 -0
  18. package/src/opencode/plugins/state.ts +253 -0
  19. package/src/opencode/plugins/usage.ts +178 -0
  20. package/src/antigravity/GEMINI.md +0 -162
  21. package/src/antigravity/workflows/code.md +0 -16
  22. package/src/antigravity/workflows/docs-init.md +0 -432
  23. package/src/antigravity/workflows/docs-update.md +0 -245
  24. package/src/antigravity/workflows/impact-analysis-output-example.md +0 -313
  25. package/src/antigravity/workflows/impact-analysis.md +0 -730
  26. package/src/antigravity/workflows/review.md +0 -15
  27. package/src/antigravity/workflows/spec-design.md +0 -220
  28. package/src/antigravity/workflows/spec-init.md +0 -78
  29. package/src/antigravity/workflows/spec-requirements.md +0 -122
  30. package/src/antigravity/workflows/spec-status.md +0 -95
  31. package/src/antigravity/workflows/spec-tasks.md +0 -156
  32. package/src/antigravity/workflows/spec-validate.md +0 -106
  33. package/src/antigravity/workflows/test.md +0 -13
@@ -0,0 +1,253 @@
1
+ /**
2
+ * Copyright (c) 2026 Haposoft. MIT License.
3
+ *
4
+ * OpenCode Plugin — state.ts
5
+ *
6
+ * Port of .claude/hooks/state.cjs (partial).
7
+ *
8
+ * Behavior:
9
+ * - On session.created: read .opencode/session-state/latest.md (if fresh)
10
+ * and surface it via stderr + banner file so the assistant sees prior
11
+ * execution context.
12
+ * - On tool.execute.after for state-shaping tools (todowrite, task,
13
+ * taskcreate, taskupdate): refresh snapshot.
14
+ * - On session.idle (≈ Claude Stop): persist snapshot + archive.
15
+ *
16
+ * Dropped:
17
+ * - SubagentStop branch (no equivalent in OpenCode).
18
+ * - Transcript-based todo extraction (OpenCode plugin context lacks
19
+ * transcript_path). Snapshot now captures modifiedFiles only.
20
+ *
21
+ * Storage: .opencode/session-state/latest.md + archive/.
22
+ */
23
+
24
+ import type { Plugin } from "@opencode-ai/plugin";
25
+ import {
26
+ existsSync,
27
+ readFileSync,
28
+ writeFileSync,
29
+ mkdirSync,
30
+ copyFileSync,
31
+ readdirSync,
32
+ unlinkSync,
33
+ renameSync,
34
+ appendFileSync,
35
+ } from "node:fs";
36
+ import { join, dirname } from "node:path";
37
+ import { fileURLToPath } from "node:url";
38
+ import { execSync } from "node:child_process";
39
+
40
+ const PLUGIN_DIR = dirname(fileURLToPath(import.meta.url));
41
+ const EXPIRY_DAYS = 7;
42
+ const MAX_ARCHIVES = 5;
43
+ const STATE_REFRESH_TOOLS = new Set(["todowrite", "task", "taskcreate", "taskupdate"]);
44
+ const STATE_SECTION_START = "<!-- CAFEKIT STATE START -->";
45
+ const STATE_SECTION_END = "<!-- CAFEKIT STATE END -->";
46
+
47
+ interface SnapshotData {
48
+ timestamp: string;
49
+ branch: string;
50
+ modifiedFiles: string[];
51
+ }
52
+
53
+ function stateDir(cwd: string): string | null {
54
+ try {
55
+ const dir = join(cwd, ".opencode", "session-state");
56
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
57
+ return dir;
58
+ } catch {
59
+ return null;
60
+ }
61
+ }
62
+
63
+ function loadLatest(dir: string): string | null {
64
+ try {
65
+ const file = join(dir, "latest.md");
66
+ if (!existsSync(file)) return null;
67
+ const text = readFileSync(file, "utf8");
68
+ const match = text.match(/<!-- Generated: (.+?) -->/);
69
+ if (match) {
70
+ const generatedAt = new Date(match[1]).getTime();
71
+ if (Number.isNaN(generatedAt)) return null;
72
+ if (Date.now() - generatedAt > EXPIRY_DAYS * 24 * 60 * 60 * 1000) return null;
73
+ }
74
+ return text;
75
+ } catch {
76
+ return null;
77
+ }
78
+ }
79
+
80
+ function writeAtomic(filePath: string, content: string): void {
81
+ const tempFile = `${filePath}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
82
+ writeFileSync(tempFile, content);
83
+ renameSync(tempFile, filePath);
84
+ }
85
+
86
+ function archive(dir: string): void {
87
+ try {
88
+ const latestFile = join(dir, "latest.md");
89
+ if (!existsSync(latestFile)) return;
90
+
91
+ const archiveDir = join(dir, "archive");
92
+ if (!existsSync(archiveDir)) mkdirSync(archiveDir);
93
+
94
+ const now = new Date();
95
+ const pad = (value: number) => String(value).padStart(2, "0");
96
+ const stamp = `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}`;
97
+
98
+ copyFileSync(latestFile, join(archiveDir, `${stamp}.md`));
99
+
100
+ const files = readdirSync(archiveDir)
101
+ .filter((file) => file.endsWith(".md"))
102
+ .sort();
103
+ while (files.length > MAX_ARCHIVES) {
104
+ const oldest = files.shift();
105
+ if (oldest) {
106
+ try {
107
+ unlinkSync(join(archiveDir, oldest));
108
+ } catch {
109
+ // fail-open
110
+ }
111
+ }
112
+ }
113
+ } catch {
114
+ // fail-open
115
+ }
116
+ }
117
+
118
+ function extractSnapshot(cwd: string): SnapshotData {
119
+ const data: SnapshotData = {
120
+ timestamp: new Date().toISOString(),
121
+ branch: "",
122
+ modifiedFiles: [],
123
+ };
124
+
125
+ try {
126
+ data.branch = execSync("git branch --show-current", {
127
+ cwd,
128
+ encoding: "utf8",
129
+ timeout: 3000,
130
+ stdio: ["pipe", "pipe", "pipe"],
131
+ }).trim();
132
+ } catch {
133
+ // fail-open
134
+ }
135
+
136
+ try {
137
+ const diff = execSync("git diff --name-only HEAD", {
138
+ cwd,
139
+ encoding: "utf8",
140
+ timeout: 3000,
141
+ stdio: ["pipe", "pipe", "pipe"],
142
+ }).trim();
143
+ if (diff) data.modifiedFiles = diff.split("\n").slice(0, 20);
144
+ } catch {
145
+ // fail-open
146
+ }
147
+
148
+ return data;
149
+ }
150
+
151
+ function buildStateContent(data: SnapshotData): string {
152
+ return [
153
+ "# Session State",
154
+ `<!-- Generated: ${data.timestamp} -->`,
155
+ `<!-- Branch: ${data.branch || "unknown"} -->`,
156
+ "",
157
+ "## Key Files Modified",
158
+ ...(data.modifiedFiles.length
159
+ ? data.modifiedFiles.map((file) => `- ${file}`)
160
+ : ["- (No file changes detected)"]),
161
+ "",
162
+ ].join("\n");
163
+ }
164
+
165
+ function writeBannerSection(cwd: string, content: string | null): void {
166
+ const target = join(cwd, ".opencode", "session-banner.md");
167
+ const dir = dirname(target);
168
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
169
+
170
+ const existing = existsSync(target) ? readFileSync(target, "utf8") : "";
171
+ const pattern = new RegExp(`${STATE_SECTION_START}[\\s\\S]*?${STATE_SECTION_END}\\n?`);
172
+ const cleaned = existing.replace(pattern, "").trimEnd();
173
+
174
+ if (!content) {
175
+ if (cleaned !== existing.trimEnd()) {
176
+ writeFileSync(target, cleaned ? `${cleaned}\n` : "");
177
+ }
178
+ return;
179
+ }
180
+
181
+ const block = [STATE_SECTION_START, content, STATE_SECTION_END].join("\n");
182
+ const next = cleaned ? `${cleaned}\n\n${block}\n` : `${block}\n`;
183
+ writeFileSync(target, next);
184
+ }
185
+
186
+ function persistSnapshot(dir: string, data: SnapshotData, options: { archive?: boolean } = {}): void {
187
+ const file = join(dir, "latest.md");
188
+ writeAtomic(file, buildStateContent(data));
189
+ if (options.archive) archive(dir);
190
+ }
191
+
192
+ function logCrash(error: unknown): void {
193
+ try {
194
+ const logDir = join(PLUGIN_DIR, ".logs");
195
+ if (!existsSync(logDir)) mkdirSync(logDir, { recursive: true });
196
+ appendFileSync(
197
+ join(logDir, "hook-log.jsonl"),
198
+ JSON.stringify({
199
+ ts: new Date().toISOString(),
200
+ hook: "state",
201
+ status: "crash",
202
+ error: error instanceof Error ? error.message : String(error),
203
+ }) + "\n",
204
+ );
205
+ } catch {
206
+ // fail-open
207
+ }
208
+ }
209
+
210
+ export const State: Plugin = async ({ directory }) => ({
211
+ event: async ({ event }) => {
212
+ try {
213
+ const dir = stateDir(directory);
214
+ if (!dir) return;
215
+
216
+ if (event.type === "session.created") {
217
+ const previous = loadLatest(dir);
218
+ if (previous) {
219
+ const banner = [
220
+ "=== Prior Execution Context ===",
221
+ previous.trim(),
222
+ "=== End of Prior Context ===",
223
+ ].join("\n");
224
+ writeBannerSection(directory, banner);
225
+ console.error(banner);
226
+ } else {
227
+ writeBannerSection(directory, null);
228
+ }
229
+ return;
230
+ }
231
+
232
+ if (event.type === "session.idle") {
233
+ const snapshot = extractSnapshot(directory);
234
+ persistSnapshot(dir, snapshot, { archive: true });
235
+ return;
236
+ }
237
+ } catch (error) {
238
+ logCrash(error);
239
+ }
240
+ },
241
+
242
+ "tool.execute.after": async (input) => {
243
+ try {
244
+ if (!STATE_REFRESH_TOOLS.has(input.tool)) return;
245
+ const dir = stateDir(directory);
246
+ if (!dir) return;
247
+ const snapshot = extractSnapshot(directory);
248
+ persistSnapshot(dir, snapshot);
249
+ } catch (error) {
250
+ logCrash(error);
251
+ }
252
+ },
253
+ });
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Copyright (c) 2026 Haposoft. MIT License.
3
+ *
4
+ * OpenCode Plugin — usage.ts
5
+ *
6
+ * Port of .claude/hooks/usage.cjs adapted to OpenCode's plugin surface.
7
+ *
8
+ * Claude's version polls the Anthropic OAuth API for plan usage so the
9
+ * statusline can render quota. OpenCode has no statusline injection point
10
+ * and no OAuth plumbing, so this port instead tracks per-session token
11
+ * usage by inspecting `message.updated` payloads and writing the rolling
12
+ * totals to `.opencode/session-state/usage.json` for downstream tooling.
13
+ *
14
+ * Disable via .opencode/runtime.json: { "usage": { "enabled": false } }.
15
+ */
16
+
17
+ import type { Plugin } from "@opencode-ai/plugin";
18
+ import {
19
+ existsSync,
20
+ readFileSync,
21
+ writeFileSync,
22
+ mkdirSync,
23
+ } from "node:fs";
24
+ import { join, dirname } from "node:path";
25
+ import { fileURLToPath } from "node:url";
26
+
27
+ const PLUGIN_DIR = dirname(fileURLToPath(import.meta.url));
28
+
29
+ interface UsageTotals {
30
+ inputTokens: number;
31
+ outputTokens: number;
32
+ cacheReadTokens: number;
33
+ cacheWriteTokens: number;
34
+ messages: number;
35
+ lastUpdated: string;
36
+ }
37
+
38
+ interface UsageFile {
39
+ sessionId: string;
40
+ startedAt: string;
41
+ totals: UsageTotals;
42
+ }
43
+
44
+ function resolveProjectDir(directory?: string): string {
45
+ if (directory && existsSync(directory)) return directory;
46
+ // Plugin installed under <project>/.opencode/plugins/, so go up twice.
47
+ return dirname(dirname(PLUGIN_DIR));
48
+ }
49
+
50
+ function readRuntime(cwd: string): Record<string, any> {
51
+ try {
52
+ const file = join(cwd, ".opencode", "runtime.json");
53
+ if (existsSync(file)) {
54
+ return JSON.parse(readFileSync(file, "utf8"));
55
+ }
56
+ } catch {
57
+ /* fail-open */
58
+ }
59
+ return {};
60
+ }
61
+
62
+ function isEnabled(cwd: string): boolean {
63
+ const runtime = readRuntime(cwd);
64
+ return runtime?.usage?.enabled !== false;
65
+ }
66
+
67
+ function usagePath(cwd: string): string {
68
+ return join(cwd, ".opencode", "session-state", "usage.json");
69
+ }
70
+
71
+ function readUsage(file: string): UsageFile | null {
72
+ try {
73
+ if (!existsSync(file)) return null;
74
+ return JSON.parse(readFileSync(file, "utf8"));
75
+ } catch {
76
+ return null;
77
+ }
78
+ }
79
+
80
+ function writeUsage(file: string, payload: UsageFile): void {
81
+ try {
82
+ mkdirSync(dirname(file), { recursive: true });
83
+ writeFileSync(file, JSON.stringify(payload, null, 2));
84
+ } catch {
85
+ /* fail-open */
86
+ }
87
+ }
88
+
89
+ // Defensive extractor: OpenCode message payloads may expose usage either
90
+ // directly on the message or nested under metadata/usage. Accept both.
91
+ function extractUsage(message: any): {
92
+ input: number;
93
+ output: number;
94
+ cacheRead: number;
95
+ cacheWrite: number;
96
+ } | null {
97
+ const candidates = [
98
+ message?.usage,
99
+ message?.metadata?.usage,
100
+ message?.tokens,
101
+ message?.metadata?.tokens,
102
+ ].filter(Boolean);
103
+
104
+ for (const c of candidates) {
105
+ const input =
106
+ Number(c.input_tokens ?? c.inputTokens ?? c.prompt_tokens ?? 0) || 0;
107
+ const output =
108
+ Number(c.output_tokens ?? c.outputTokens ?? c.completion_tokens ?? 0) ||
109
+ 0;
110
+ const cacheRead =
111
+ Number(
112
+ c.cache_read_input_tokens ??
113
+ c.cacheReadInputTokens ??
114
+ c.cache_read_tokens ??
115
+ 0,
116
+ ) || 0;
117
+ const cacheWrite =
118
+ Number(
119
+ c.cache_creation_input_tokens ??
120
+ c.cacheCreationInputTokens ??
121
+ c.cache_write_tokens ??
122
+ 0,
123
+ ) || 0;
124
+ if (input || output || cacheRead || cacheWrite) {
125
+ return { input, output, cacheRead, cacheWrite };
126
+ }
127
+ }
128
+ return null;
129
+ }
130
+
131
+ export const UsagePlugin: Plugin = async ({ directory }) => {
132
+ const cwd = resolveProjectDir(directory);
133
+
134
+ return {
135
+ event: async ({ event }) => {
136
+ if (event.type !== "message.updated") return;
137
+ if (!isEnabled(cwd)) return;
138
+
139
+ const message = (event as any).properties?.info ?? (event as any).properties?.message;
140
+ if (!message) return;
141
+
142
+ const tokens = extractUsage(message);
143
+ if (!tokens) return;
144
+
145
+ const sessionId = message.sessionID ?? message.sessionId ?? "default";
146
+ const file = usagePath(cwd);
147
+ const now = new Date().toISOString();
148
+ const existing = readUsage(file);
149
+
150
+ const sameSession = existing && existing.sessionId === sessionId;
151
+ const totals: UsageTotals = sameSession
152
+ ? existing!.totals
153
+ : {
154
+ inputTokens: 0,
155
+ outputTokens: 0,
156
+ cacheReadTokens: 0,
157
+ cacheWriteTokens: 0,
158
+ messages: 0,
159
+ lastUpdated: now,
160
+ };
161
+
162
+ totals.inputTokens += tokens.input;
163
+ totals.outputTokens += tokens.output;
164
+ totals.cacheReadTokens += tokens.cacheRead;
165
+ totals.cacheWriteTokens += tokens.cacheWrite;
166
+ totals.messages += 1;
167
+ totals.lastUpdated = now;
168
+
169
+ writeUsage(file, {
170
+ sessionId,
171
+ startedAt: sameSession ? existing!.startedAt : now,
172
+ totals,
173
+ });
174
+ },
175
+ };
176
+ };
177
+
178
+ export default UsagePlugin;
@@ -1,162 +0,0 @@
1
- ---
2
- trigger: always_on
3
- ---
4
-
5
- # GEMINI.md - Antigravity Kit
6
-
7
- > This file defines how the AI behaves in this workspace.
8
-
9
- ---
10
-
11
- ## CRITICAL: AGENT & SKILL PROTOCOL (START HERE)
12
-
13
- > **MANDATORY:** You MUST read the appropriate agent file and its skills BEFORE performing any implementation. This is the highest priority rule.
14
-
15
- ### 1. Modular Skill Loading Protocol
16
-
17
- Agent activated → Check frontmatter "skills:" → Read SKILL.md (INDEX) → Read specific sections.
18
-
19
- - **Selective Reading:** DO NOT read ALL files in a skill folder. Read `SKILL.md` first, then only read sections matching the user's request.
20
- - **Rule Priority:** P0 (GEMINI.md) > P1 (Agent .md) > P2 (SKILL.md). All rules are binding.
21
-
22
- ### 2. Enforcement Protocol
23
-
24
- 1. **When agent is activated:**
25
- - ✅ Activate: Read Rules → Check Frontmatter → Load SKILL.md → Apply All.
26
- 2. **Forbidden:** Never skip reading agent rules or skill instructions. "Read → Understand → Apply" is mandatory.
27
- 3. **Artifact Ban:** DO NOT create "Implementation Plan" artifacts (sidebar artifacts) unless the user EXPLICITLY asks for them. Use standard markdown files in `docs/` or text responses instead.
28
-
29
- ---
30
-
31
- ## 📥 REQUEST CLASSIFIER (STEP 1)
32
-
33
- **Before ANY action, classify the request:**
34
-
35
- | Request Type | Trigger Keywords | Active Tiers | Result |
36
- | ---------------- | ------------------------------------------ | ------------------------------ | --------------------------- |
37
- | **QUESTION** | "what is", "how does", "explain" | TIER 0 only | Text Response |
38
- | **SURVEY/INTEL** | "analyze", "list files", "overview" | TIER 0 + Explorer | Session Intel (No File) |
39
- | **SIMPLE CODE** | "fix", "add", "change" (single file) | TIER 0 + TIER 1 (lite) | Inline Edit |
40
- | **COMPLEX CODE** | "build", "create", "implement", "refactor" | TIER 0 + TIER 1 (full) + Agent | **{task-slug}.md Required** |
41
- | **DESIGN/UI** | "design", "UI", "page", "dashboard" | TIER 0 + TIER 1 + Agent | **{task-slug}.md Required** |
42
- | **SLASH CMD** | /spec-init, /spec-requirements, /spec-design, /spec-tasks, /spec-status, /code, /test, /review, /docs-init, /docs-update | Command-specific flow | Variable |
43
-
44
- ---
45
-
46
- ## TIER 0: UNIVERSAL RULES (Always Active)
47
-
48
- ### 💬 Response Format
49
-
50
- All responses must generally follow this structure:
51
- 1. **Explanation**: Brief context/problem/solution.
52
- 2. **Implementation**: Code/Action with clear comments.
53
- 3. **Usage/Caveats**: (If applicable)
54
- 4. **Next Action:** (MANDATORY) Specific proposed next step.
55
- - Example: "Use `/spec-init` to start", "Review `docs/PLAN-x.md`", "Run `pytest`".
56
-
57
- ### 🌐 Language Handling
58
-
59
- When user's prompt is NOT in English:
60
-
61
- 1. **Internally translate** for better comprehension
62
- 2. **Respond in user's language** - match their communication
63
- 3. **Code comments/variables** remain in English
64
-
65
- ### 🧹 Clean Code (Global Mandatory)
66
-
67
- - **Code**: Concise, direct, no over-engineering. Self-documenting.
68
- - **Testing**: Mandatory. Pyramid (Unit > Int > E2E) + AAA Pattern.
69
- - **Performance**: Measure first. Adhere to 2025 standards (Core Web Vitals).
70
- - **Infra/Safety**: 5-Phase Deployment. Verify secrets security.
71
- - Concise, direct, solution-focused
72
- - No verbose explanations
73
- - No over-commenting
74
- - No over-engineering
75
- - **Artifact Control:** DO NOT create "Implementation Plan" artifacts (sidebar artifacts) unless the user EXPLICITLY asks for them. Use standard markdown files in `docs/` or text responses instead.
76
- - **Self-Documentation:** Every agent is responsible for documenting their own changes in relevant `.md` files.
77
-
78
- ### 🗺️ System Map Read
79
-
80
- **Path Awareness:**
81
-
82
- - Skills: `.agent/skills/` (Project)
83
- - Workflows: `.agent/workflows/` (Project)
84
- - Models: `.agent/models/` (Project)
85
- - Specs: `.specs/` (Project)
86
-
87
- ### 🧠 Read → Understand → Apply
88
-
89
- ```
90
- ❌ WRONG: Read agent file → Start coding
91
- ✅ CORRECT: Read → Understand WHY → Apply PRINCIPLES → Code
92
- ```
93
-
94
- **Before coding, answer:**
95
-
96
- 1. What is the GOAL of this agent/skill?
97
- 2. What PRINCIPLES must I apply?
98
- 3. How does this DIFFER from generic output?
99
-
100
- ---
101
-
102
- ## TIER 1: CODE RULES (When Writing Code)
103
-
104
- ### 🛑 GLOBAL SOCRATIC GATE (TIER 0)
105
-
106
- **MANDATORY: Every user request must pass through the Socratic Gate before ANY tool use or implementation.**
107
-
108
- | Request Type | Strategy | Required Action |
109
- | ----------------------- | -------------- | ----------------------------------------------------------------- |
110
- | **New Feature / Build** | Deep Discovery | ASK minimum 3 strategic questions |
111
- | **Code Edit / Bug Fix** | Context Check | Confirm understanding + ask impact questions |
112
- | **Vague / Simple** | Clarification | Ask Purpose, Users, and Scope |
113
- | **Full Orchestration** | Gatekeeper | **STOP** subagents until user confirms plan details |
114
- | **Direct "Proceed"** | Validation | **STOP** → Even if answers are given, ask 2 "Edge Case" questions |
115
-
116
- **Protocol:**
117
-
118
- 1. **Never Assume:** If even 1% is unclear, ASK.
119
- 2. **Handle Spec-heavy Requests:** When user gives a list (Answers 1, 2, 3...), do NOT skip the gate. Instead, ask about **Trade-offs** or **Edge Cases** (e.g., "LocalStorage confirmed, but should we handle data clearing or versioning?") before starting.
120
- 3. **Wait:** Do NOT invoke subagents or write code until the user clears the Gate.
121
-
122
- ---
123
-
124
- ## 📁 AVAILABLE WORKFLOWS
125
-
126
- ### Spec-Driven Development
127
-
128
- | Command | Mô tả |
129
- |---------|-------|
130
- | `/spec-init <mô tả>` | Khởi tạo spec mới từ ý tưởng |
131
- | `/spec-requirements <feature>` | Sinh requirements (EARS format) |
132
- | `/spec-design <feature>` | Sinh design doc + research |
133
- | `/spec-tasks <feature>` | Sinh task list |
134
- | `/code <feature>` | Implement task từ spec và chuyển qua test/review |
135
- | `/spec-status <feature>` | Xem trạng thái hiện tại |
136
-
137
- ### Documentation
138
-
139
- | Command | Mô tả |
140
- |---------|-------|
141
- | `/docs-init` | Initialize project documentation |
142
- | `/docs-update` | Update existing documentation |
143
-
144
- **Usage:**
145
- - Read `.agent/skills/specs/SKILL.md` for detailed workflow information
146
- - Each workflow has its own file in `.agent/workflows/` with specific instructions
147
-
148
- ---
149
-
150
- ## 📁 QUICK REFERENCE
151
-
152
- ### Skills
153
-
154
- - **specs**: Complete SDD workflow from idea to implementation
155
-
156
- ### Workflows Location
157
-
158
- - Workflows: `.agent/workflows/`
159
- - Skill definitions: `.agent/skills/`
160
- - Spec data: `.specs/<feature-name>/`
161
-
162
- ---
@@ -1,16 +0,0 @@
1
- ---
2
- description: Implement approved work from specification tasks and then hand off to test and review.
3
- allowed-tools: Read, Glob, Grep, Edit, Write, Bash
4
- argument-hint: <feature-name>
5
- ---
6
-
7
- # /code - Implement from spec tasks
8
-
9
- Use this workflow after `/spec-tasks`.
10
-
11
- 1. Read `.specs/$ARGUMENTS/tasks.md` and identify the next pending task.
12
- 2. Implement only that task following project standards.
13
- 3. Run `/test`.
14
- 4. Run `/review`.
15
-
16
- Preferred flow: `/spec-init` - `/spec-requirements` - `/spec-design` - `/spec-tasks` - `/code` - `/test` - `/review`