deuk-agent-rule 2.5.13 → 3.3.2

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 (44) hide show
  1. package/CHANGELOG.ko.md +74 -0
  2. package/CHANGELOG.md +138 -316
  3. package/README.ko.md +134 -154
  4. package/README.md +121 -153
  5. package/package.json +29 -7
  6. package/scripts/cli-args.mjs +87 -3
  7. package/scripts/cli-init-commands.mjs +1382 -223
  8. package/scripts/cli-init-logic.mjs +28 -16
  9. package/scripts/cli-prompts.mjs +13 -4
  10. package/scripts/cli-rule-compiler.mjs +44 -34
  11. package/scripts/cli-skill-commands.mjs +172 -0
  12. package/scripts/cli-telemetry-commands.mjs +429 -0
  13. package/scripts/cli-ticket-commands.mjs +1934 -161
  14. package/scripts/cli-ticket-index.mjs +298 -0
  15. package/scripts/cli-ticket-migration.mjs +320 -0
  16. package/scripts/cli-ticket-parser.mjs +207 -0
  17. package/scripts/cli-utils.mjs +381 -59
  18. package/scripts/cli.mjs +99 -19
  19. package/scripts/lint-md.mjs +247 -0
  20. package/scripts/lint-rules.mjs +143 -0
  21. package/scripts/merge-logic.mjs +13 -306
  22. package/scripts/plan-parser.mjs +53 -0
  23. package/templates/MODULE_RULE_TEMPLATE.md +11 -0
  24. package/templates/PROJECT_RULE.md +47 -0
  25. package/templates/TICKET_TEMPLATE.ko.md +21 -0
  26. package/templates/TICKET_TEMPLATE.md +21 -0
  27. package/templates/rules.d/deukcontext-mcp.md +31 -0
  28. package/templates/rules.d/platform-coexistence.md +29 -0
  29. package/templates/skills/context-recall/SKILL.md +25 -0
  30. package/templates/skills/generated-file-guard/SKILL.md +25 -0
  31. package/templates/skills/safe-refactor/SKILL.md +25 -0
  32. package/bundle/.cursorrules +0 -11
  33. package/bundle/AGENTS.md +0 -146
  34. package/bundle/gemini.md +0 -26
  35. package/bundle/rules/delivery-and-parallel-work.mdc +0 -26
  36. package/bundle/rules/git-commit.mdc +0 -24
  37. package/bundle/rules/multi-ai-workflow.mdc +0 -104
  38. package/bundle/rules.d/core-workflow.md +0 -48
  39. package/bundle/rules.d/deukrag-mcp.md +0 -37
  40. package/bundle/templates/MODULE_RULE_TEMPLATE.md +0 -24
  41. package/bundle/templates/TICKET_TEMPLATE.md +0 -58
  42. package/scripts/cli-ticket-logic.mjs +0 -568
  43. package/scripts/sync-bundle.mjs +0 -77
  44. package/scripts/sync-oss.mjs +0 -126
@@ -1,258 +1,35 @@
1
1
  import {
2
- copyFileSync,
3
2
  existsSync,
4
- mkdirSync,
5
3
  readFileSync,
6
- readdirSync,
7
- unlinkSync,
8
- writeFileSync,
9
4
  } from "fs";
10
5
  import { join } from "path";
11
6
 
12
- export const DEFAULT_TAG = "deuk-agent-rule";
13
-
14
- /** HTML-style markers in `.cursorrules` (separate from AGENTS.md markers). */
15
- export const CURSORRULES_TAG = "deuk-agent-rule-cursorrules";
16
-
17
- export function resolveCursorrulesMarkers(o = {}) {
18
- return resolveMarkers({
19
- tag: o.tag && String(o.tag).trim() ? String(o.tag).trim() : CURSORRULES_TAG,
20
- markerBegin: o.markerBegin,
21
- markerEnd: o.markerEnd,
22
- });
23
- }
24
-
25
- export function resolveMarkers(o) {
26
- const hasBegin = o.markerBegin != null && o.markerBegin !== "";
27
- const hasEnd = o.markerEnd != null && o.markerEnd !== "";
28
- if (hasBegin !== hasEnd) {
29
- throw new Error("Use both --marker-begin and --marker-end, or neither.");
30
- }
31
- if (hasBegin && hasEnd) {
32
- if (o.markerBegin === o.markerEnd) {
33
- throw new Error("--marker-begin and --marker-end must differ.");
34
- }
35
- return { begin: o.markerBegin, end: o.markerEnd };
36
- }
37
- const id = o.tag && o.tag.trim() ? o.tag.trim() : DEFAULT_TAG;
38
- return {
39
- begin: "<!-- " + id + ":begin -->",
40
- end: "<!-- " + id + ":end -->",
41
- };
42
- }
43
-
44
- export function findMarkerRegion(content, begin, end) {
45
- const i = content.indexOf(begin);
46
- if (i === -1) return null;
47
- const j = content.indexOf(end, i + begin.length);
48
- if (j === -1) {
49
- throw new Error(
50
- `[MARKER ERROR] Found begin marker "${begin}" but no matching end marker "${end}" after it.\n` +
51
- ` This usually happens if one marker was deleted or renamed manually. Please verify the target file.`
52
- );
53
- }
54
- const innerStart = i + begin.length;
55
- const innerEnd = j;
56
- return { innerStart, innerEnd };
57
- }
58
-
59
- export function applyAgents(opts) {
60
- const { agentsMode, targetPath } = opts;
61
-
62
- if (agentsMode === "skip") {
63
- return {
64
- action: "skip",
65
- reason: existsSync(targetPath) ? "agents mode skip (file exists)" : "agents mode skip",
66
- };
67
- }
68
-
69
- if (agentsMode === "overwrite") {
70
- return handleAgentOverwrite(opts);
71
- }
72
-
73
- const existing = existsSync(targetPath) ? readFileSync(targetPath, "utf8") : "";
74
-
75
- // Workflow Safety Check: warn about different tags and error on case-mismatch
76
- const markerRegex = /<!--\s*([a-zA-Z0-9_-]+):begin\s*-->/gi;
77
- const currentTagMatch = opts.markers.begin.match(/<!--\s*([a-zA-Z0-9_-]+):begin\s*-->/i);
78
- const currentTag = currentTagMatch ? currentTagMatch[1] : null;
79
-
80
- const foundTags = [];
81
- let m;
82
- while ((m = markerRegex.exec(existing)) !== null) {
83
- if (currentTag && m[1].toLowerCase() === currentTag.toLowerCase()) {
84
- if (m[1] !== currentTag) {
85
- throw new Error(
86
- `[CRITICAL ERROR] Case mismatch for tag "${currentTag}". Found "${m[1]}" in ${targetPath}.\n` +
87
- ` Please unify casing to avoid duplicate managed blocks.`
88
- );
89
- }
90
- } else {
91
- foundTags.push(m[1]);
92
- }
93
- }
94
-
95
- if (foundTags.length > 0) {
96
- console.warn(`[WARNING] Foreign markers in ${targetPath}: ${[...new Set(foundTags)].join(", ")}`);
97
- console.warn(` Current tag is "${currentTag}". This might lead to duplicate managed blocks.`);
98
- }
99
-
100
- const region = findMarkerRegion(existing, opts.markers.begin, opts.markers.end);
101
-
102
- if (region) {
103
- return handleAgentInject(opts, existing, region);
104
- }
105
-
106
- return handleAgentAppend(opts, existing);
107
- }
108
-
109
- function handleAgentOverwrite(opts) {
110
- const { targetPath, bundleContent, dryRun, backup } = opts;
111
- const prev = existsSync(targetPath) ? readFileSync(targetPath, "utf8") : "";
112
- if (dryRun) {
113
- return { action: "would-write", path: targetPath, mode: "overwrite" };
114
- }
115
- if (backup && existsSync(targetPath)) {
116
- copyFileSync(targetPath, targetPath + ".bak");
117
- }
118
- writeFileSync(targetPath, bundleContent, "utf8");
119
- return { action: "write", path: targetPath, mode: "overwrite", hadPrevious: !!prev };
120
- }
121
-
122
- function handleAgentInject(opts, existing, region) {
123
- const { targetPath, bundleContent, dryRun, backup } = opts;
124
- const inner = bundleContent.trimEnd() + "\n";
125
- const next = existing.slice(0, region.innerStart) + "\n" + inner + existing.slice(region.innerEnd);
126
- if (dryRun) {
127
- return { action: "would-write", path: targetPath, mode: "inject-region" };
128
- }
129
- if (backup && existsSync(targetPath)) {
130
- copyFileSync(targetPath, targetPath + ".bak");
131
- }
132
- writeFileSync(targetPath, next, "utf8");
133
- return { action: "write", path: targetPath, mode: "inject-region" };
134
- }
135
-
136
- function handleAgentAppend(opts, existing) {
137
- const { targetPath, bundleContent, markers, flavor, appendIfNoMarkers, dryRun, backup } = opts;
138
- const allowAppend = appendIfNoMarkers || flavor === "init";
139
-
140
- if (!allowAppend) {
141
- const hint = [
142
- "",
143
- "No marker region found. Add a pair like:",
144
- "",
145
- markers.begin,
146
- "",
147
- markers.end,
148
- "",
149
- "Or run: npx deuk-agent-rule init (appends markers once)",
150
- "Or pass: --append-if-no-markers",
151
- "",
152
- ].join("\n");
153
- throw new Error(
154
- "Inject mode requires markers in " + targetPath + " or use --append-if-no-markers." + hint,
155
- );
156
- }
157
-
158
- const inner = bundleContent.trimEnd() + "\n";
159
- const block = "\n" + markers.begin + "\n\n" + inner + "\n" + markers.end + "\n";
160
- const next = existing ? existing.replace(/\s*$/, "") + block : markers.begin + "\n\n" + inner + "\n" + markers.end + "\n";
161
-
162
- if (dryRun) {
163
- return {
164
- action: "would-write",
165
- path: targetPath,
166
- mode: flavor === "init" ? "append-markers-init" : "append-markers",
167
- };
168
- }
169
- if (backup && existsSync(targetPath)) {
170
- copyFileSync(targetPath, targetPath + ".bak");
171
- }
172
- writeFileSync(targetPath, next, "utf8");
173
- return {
174
- action: "write",
175
- path: targetPath,
176
- mode: flavor === "init" ? "append-markers-init" : "append-markers",
177
- };
178
- }
179
-
180
- export function applyRules(opts) {
181
- const {
182
- bundleRulesDir,
183
- targetRulesDir,
184
- rulesMode,
185
- filePrefix = "deuk-agent-rule-",
186
- dryRun,
187
- backup,
188
- } = opts;
189
-
190
- if (!existsSync(bundleRulesDir)) {
191
- throw new Error("Bundle rules directory missing: " + bundleRulesDir);
192
- }
193
-
194
- const actions = [];
195
- mkdirSync(targetRulesDir, { recursive: true });
196
-
197
- for (const name of readdirSync(bundleRulesDir)) {
198
- if (!name.endsWith(".mdc")) continue;
199
- const src = join(bundleRulesDir, name);
200
- let destPath = join(targetRulesDir, name);
201
-
202
- if (rulesMode === "skip" && existsSync(destPath)) {
203
- actions.push({ action: "skip", src, dest: destPath, reason: "exists" });
204
- continue;
205
- }
206
-
207
- if (rulesMode === "prefix" && existsSync(destPath)) {
208
- destPath = join(targetRulesDir, filePrefix + name);
209
- // If prefixed file exists (repeat init after npm update), overwrite from bundle — do not skip.
210
- }
211
-
212
- if (dryRun) {
213
- actions.push({ action: "would-copy", src, dest: destPath });
214
- continue;
215
- }
216
-
217
- if (backup && existsSync(destPath)) {
218
- copyFileSync(destPath, destPath + ".bak");
219
- }
220
- copyFileSync(src, destPath);
221
- actions.push({ action: "copy", src, dest: destPath });
222
- }
223
-
224
- return actions;
225
- }
7
+ export const DEFAULT_TAG = "DeukAgentRules";
226
8
 
227
9
  export function readBundleAgents(bundleRoot) {
228
- const p = join(bundleRoot, "AGENTS.md");
10
+ const p = join(bundleRoot, "core-rules", "AGENTS.md");
229
11
  if (!existsSync(p)) {
230
12
  throw new Error("Bundle AGENTS.md missing: " + p);
231
13
  }
232
14
  return readFileSync(p, "utf8");
233
15
  }
234
16
 
235
- /**
236
- * Optional bundle file: Cursor root rules pointer to AGENTS.md.
237
- * @returns {string|null} file contents, or null if missing
238
- */
239
- export function readBundleCursorrules(bundleRoot) {
240
- const p = join(bundleRoot, ".cursorrules");
241
- if (!existsSync(p)) {
242
- return null;
243
- }
244
- return readFileSync(p, "utf8");
245
- }
246
-
247
- /**
248
- * Remove one tagged block (markers inclusive). Returns ok:false if begin marker not found.
249
- * @returns {{ ok: true, content: string } | { ok: false, reason: string }}
250
- */
251
17
  export function removeTaggedBlock(content, begin, end) {
252
18
  const i = content.indexOf(begin);
253
19
  if (i === -1) {
254
20
  return { ok: false, reason: "begin not found" };
255
21
  }
22
+ if (end === null) {
23
+ let blockStart = i;
24
+ const prevText = content.slice(0, i);
25
+ const hrIndex = prevText.lastIndexOf("---");
26
+ if (hrIndex !== -1 && prevText.slice(hrIndex).trim() === "") {
27
+ blockStart = hrIndex;
28
+ }
29
+ let next = content.slice(0, blockStart).trimEnd() + "\n";
30
+ return { ok: true, content: next };
31
+ }
32
+
256
33
  const j = content.indexOf(end, i + begin.length);
257
34
  if (j === -1) {
258
35
  return { ok: false, reason: "end not found" };
@@ -265,73 +42,3 @@ export function removeTaggedBlock(content, begin, end) {
265
42
  }
266
43
  return { ok: true, content: next };
267
44
  }
268
-
269
-
270
- /**
271
- * @param {{
272
- * bundleRoot: string,
273
- * cwd: string,
274
- * markers: { begin: string, end: string },
275
- * cursorrulesMode: "skip" | "inject" | "overwrite",
276
- * dryRun?: boolean,
277
- * backup?: boolean,
278
- * }} opts
279
- */
280
- export function applyCursorrules(opts) {
281
- const { bundleRoot, cwd, markers, cursorrulesMode, dryRun, backup } = opts;
282
- const raw = readBundleCursorrules(bundleRoot);
283
- if (!raw) {
284
- return { action: "skip", reason: "bundle .cursorrules missing" };
285
- }
286
- const inner = raw.trimEnd();
287
- const targetPath = join(cwd, ".cursorrules");
288
-
289
- if (cursorrulesMode === "skip") {
290
- return { action: "skip", reason: "cursorrules mode skip" };
291
- }
292
-
293
- const writeTaggedOnly = (bodyInner) =>
294
- markers.begin + "\n\n" + bodyInner + "\n\n" + markers.end + "\n";
295
-
296
- if (cursorrulesMode === "overwrite") {
297
- const next = writeTaggedOnly(inner);
298
- if (dryRun) {
299
- return { action: "would-write", path: targetPath, mode: "overwrite" };
300
- }
301
- if (backup && existsSync(targetPath)) {
302
- copyFileSync(targetPath, targetPath + ".bak");
303
- }
304
- writeFileSync(targetPath, next, "utf8");
305
- return { action: "write", path: targetPath, mode: "overwrite" };
306
- }
307
-
308
- // inject: update tagged region, or prepend tagged block above existing content
309
- const existing = existsSync(targetPath) ? readFileSync(targetPath, "utf8") : "";
310
- const region = findMarkerRegion(existing, markers.begin, markers.end);
311
-
312
- if (region) {
313
- const next =
314
- existing.slice(0, region.innerStart) + "\n" + inner + "\n" + existing.slice(region.innerEnd);
315
- if (dryRun) {
316
- return { action: "would-write", path: targetPath, mode: "inject-region" };
317
- }
318
- if (backup && existsSync(targetPath)) {
319
- copyFileSync(targetPath, targetPath + ".bak");
320
- }
321
- writeFileSync(targetPath, next, "utf8");
322
- return { action: "write", path: targetPath, mode: "inject-region" };
323
- }
324
-
325
- const block = writeTaggedOnly(inner) + "\n";
326
- const rest = existing.replace(/^\uFEFF/, "").trimStart();
327
- const next = rest.length ? block + rest : block.trimEnd() + "\n";
328
-
329
- if (dryRun) {
330
- return { action: "would-write", path: targetPath, mode: "prepend-tagged" };
331
- }
332
- if (backup && existsSync(targetPath)) {
333
- copyFileSync(targetPath, targetPath + ".bak");
334
- }
335
- writeFileSync(targetPath, next, "utf8");
336
- return { action: "write", path: targetPath, mode: "prepend-tagged" };
337
- }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Generic Markdown Plan Parser
3
+ *
4
+ * Supports various AI Agent Plan formats (Antigravity, Copilot, etc.)
5
+ * Extracts basic ticket fields (title, summary, tasks) and body.
6
+ */
7
+
8
+ export function parseGenericMarkdownPlan(content) {
9
+ const lines = content.split('\n');
10
+
11
+ // 1. Title: First H1
12
+ const h1Line = lines.find(l => /^# /.test(l));
13
+ const title = h1Line ? h1Line.replace(/^# /, '').trim() : '';
14
+
15
+ // 2. Summary: Text between H1 and the first --- or ##
16
+ const h1Idx = h1Line ? lines.indexOf(h1Line) : -1;
17
+ let summaryLines = [];
18
+ for (let i = h1Idx + 1; i < lines.length; i++) {
19
+ if (/^---$/.test(lines[i].trim()) || /^## /.test(lines[i])) break;
20
+ if (lines[i].trim()) summaryLines.push(lines[i].trim());
21
+ }
22
+ const summary = summaryLines.join(' ').slice(0, 200);
23
+
24
+ // 3. Tasks: Collect all checklist items
25
+ const tasks = lines
26
+ .filter(l => /^\s*- \[[ x/]\]/.test(l))
27
+ .map(l => l.replace(/^\s*- \[[ x/]\]\s*/, '').trim());
28
+
29
+ return { title, summary, tasks, body: content };
30
+ }
31
+
32
+ /**
33
+ * Detect agent type from plan path
34
+ */
35
+ export function detectAgentFromPath(planPath) {
36
+ if (planPath.includes('.gemini')) return 'antigravity';
37
+ if (planPath.includes('copilot') || planPath.includes('.codex')) return 'copilot';
38
+ if (planPath.includes('.cursor')) return 'cursor';
39
+ if (planPath.includes('.claude')) return 'claude';
40
+ return 'generic';
41
+ }
42
+
43
+ export const PLAN_PARSERS = {
44
+ 'antigravity': parseGenericMarkdownPlan,
45
+ 'copilot': parseGenericMarkdownPlan,
46
+ 'generic': parseGenericMarkdownPlan
47
+ };
48
+
49
+ export function parsePlan(planPath, content) {
50
+ const agent = detectAgentFromPath(planPath);
51
+ const parser = PLAN_PARSERS[agent] || parseGenericMarkdownPlan;
52
+ return parser(content);
53
+ }
@@ -0,0 +1,11 @@
1
+ # Submodule Rules: [Module Name]
2
+
3
+ - **Path Root:** `[Path]`
4
+ - **Tech Stack:** `[Tech]`
5
+
6
+ ## Architecture & Conventions
7
+ - [Add module-specific conventions here]
8
+
9
+ ## Build & Test
10
+ - Build: `[Command]`
11
+ - Test: `[Command]`
@@ -0,0 +1,47 @@
1
+ ---
2
+ architecture_docs: ""
3
+ ---
4
+
5
+ # Project Rules
6
+
7
+ ## Architecture Boundaries
8
+
9
+ > [!NOTE] **To AI Agents**
10
+ > If `architecture_docs` is empty and no rules are defined below,
11
+ > this project has no architecture rules yet.
12
+ > → Ask user to define them, or analyze codebase and propose a draft.
13
+ > → Do NOT make assumptions about project architecture.
14
+
15
+ ### Module Ownership
16
+ <!-- Define which modules exist and who owns them -->
17
+ | Module | Owner | Editable |
18
+ |--------|-------|----------|
19
+ | `src/` | Core source | Yes |
20
+
21
+ ### Dependency Direction
22
+ <!-- Define allowed dependency directions between modules -->
23
+
24
+ ## DC-CODEGEN: Generated File Mapping
25
+
26
+ > [!IMPORTANT] **REQUIRED**
27
+ > Agents use this table to decide which files are safe to edit.
28
+ > Files not listed here → agent MUST ask user before editing.
29
+
30
+ | Generated (DO NOT EDIT) | Source (edit here) | Build command |
31
+ |-------------------------|-------------------|---------------|
32
+ | `dist/` | `src/` | `npm run build` |
33
+
34
+ ## DC-* Guards (project-specific)
35
+
36
+ | Guard | Condition → Action |
37
+ |-------|-------------------|
38
+ | DC-HALT | Infrastructure error → stop, no bypass, report to user. |
39
+ | DC-INFRA | Bootstrap/transport/DB/routing code → separate ticket + approval. |
40
+
41
+ ## Build & Test
42
+
43
+ | Action | Command |
44
+ |--------|---------|
45
+ | Build | `npm run build` |
46
+ | Test | `npm test` |
47
+ | Lint | `npx deuk-agent-rule lint:md` |
@@ -0,0 +1,21 @@
1
+ ---
2
+ <%- frontmatter %>
3
+ ---
4
+ # <%= meta.title %>
5
+
6
+ ## Compact Plan
7
+
8
+ - **찾은 점:** 이 티켓이 다루는 문제를 한두 줄로 적습니다.
9
+ - **방향:** 가장 작은 수정으로 해결하고, 큰 범위는 다른 티켓으로 분리합니다.
10
+ - **검증:** 실패 가능성을 잘 드러내는 최소 검증만 적습니다.
11
+ - **메모:** 상세 근거는 꼭 필요한 곳에만 둡니다.
12
+
13
+ ## Tasks
14
+
15
+ - [ ] 계획 정리
16
+ - [ ] 변경 적용
17
+ - [ ] 검증 기록
18
+
19
+ ## Done When
20
+
21
+ - 티켓이 짧고, 바뀐 점과 실패 가능성이 분명하다.
@@ -0,0 +1,21 @@
1
+ ---
2
+ <%- frontmatter %>
3
+ ---
4
+ # <%= meta.title %>
5
+
6
+ ## Compact Plan
7
+
8
+ - **Finding:** Keep the ticket focused on the concrete problem and the minimum change needed.
9
+ - **Approach:** Use the narrowest safe fix; split new scope into another ticket.
10
+ - **Verification:** Record the smallest check that exposes the main risk, not a success parade.
11
+ - **Notes:** Put detailed evidence only where the problem actually needs it.
12
+
13
+ ## Tasks
14
+
15
+ - [ ] Complete compact plan.
16
+ - [ ] Execute changes.
17
+ - [ ] Record verification outcome.
18
+
19
+ ## Done When
20
+
21
+ - Ticket is scoped, implemented, and verified.
@@ -0,0 +1,31 @@
1
+ ---
2
+ id: deukcontext-mcp
3
+ condition:
4
+ mcp: deuk-agent-context
5
+ inject_target: ["AGENTS.md", "GEMINI.md"]
6
+ ---
7
+ ## DeukContext RAG Protocol
8
+
9
+ ### RAG Usage
10
+ - Start with local source-of-truth files: current source code, tests, project rules, and CLI ticket state.
11
+ - Use `mcp_deukcontext_search_*` when local evidence is insufficient, prior decisions may matter, the task crosses old tickets, or the user asks for historical/deep analysis.
12
+ - Use RAG as advisory memory. Current source code, tests, and ticket state remain the source of truth.
13
+ - Treat DeukAgentContext as an online-only memory layer. Do not rely on offline snapshots or local mirrors as the primary context source.
14
+ - Choose the narrowest MCP tool: `search_code` for symbols, `search_rules` for policy, `search_tickets` for prior outcomes, and `synthesize_knowledge` only for cross-collection questions.
15
+ - Search narrowly: include the concrete project plus symbol, file, command, rule id, or failure mode.
16
+ - Stop after 2 MCP calls for the same question. Do not broaden repeatedly.
17
+ - **Do NOT use RAG for Ticket Navigation.** Ticket lookup is a direct CLI operation, not a search task.
18
+
19
+ ### RAG Quality Gate
20
+ - Treat placeholder summaries, duplicate ticket/report chunks, stale archive-only hits, unrelated projects, or summaries with no usable fact as a miss.
21
+ - When a result only says to read the file, read the current file locally before deciding.
22
+ - Prefer `search_code` for implementation questions and request evidence only when the extra context is likely to be useful.
23
+ - Record hit/weak-hit/miss/stale evidence in the ticket when it changes confidence, plan, or follow-up direction.
24
+ - For investigation, regression, quality, or root-cause tasks, write confirmed facts, hypotheses, improvement direction, and open questions into the active ticket before asking the user for clarification. Then point the user to the ticket instead of keeping the analysis only in chat.
25
+
26
+ ### RAG Failure Handling
27
+ - **Error** (2+ failures): Switch to local search (`grep_search`/`view_file`). Do not retry in a loop.
28
+ - **Miss or weak hit** (`[RAG-MISS]`, placeholder, duplicate, stale): Fall back to local search. If local analysis finds reusable current-code knowledge, inject it once via `mcp_deukcontext_add_knowledge` with project, source path, code status, and applicability.
29
+ - **Stale indexed doc**: If an indexed document is wrong or incomplete, use `mcp_deukcontext_refresh_document` instead of adding a competing fragment.
30
+ - **Archive boundary**: Completed work should be preserved through ticket archive and knowledge distillation so the active context does not accumulate stale live-state references.
31
+ - **Docs vs knowledge**: `.deuk-agent/docs/` holds human-readable source artifacts (all plans and reports under `docs/plan`, archived originals in `docs/archive`). `.deuk-agent/knowledge/` holds only distilled machine-readable retrieval JSON generated from archived tickets/plans.
@@ -0,0 +1,29 @@
1
+ ---
2
+ id: platform-coexistence
3
+ inject_target: ["AGENTS.md"]
4
+ ---
5
+ ## Platform MCP Bridge
6
+
7
+ ### MCP Configuration per Platform
8
+
9
+ Each platform uses a different MCP config file. Ensure `deuk-agent-context` is registered in the appropriate location:
10
+
11
+ | Platform | MCP Config Path | Registration |
12
+ |----------|----------------|--------------|
13
+ | Antigravity | `.mcp.json` (project root) | Auto-detected by IDE |
14
+ | Claude Code | `.mcp.json` (project root) | `claude mcp add --transport sse deuk-agent-context <url>` |
15
+ | Copilot | `.vscode/mcp.json` | VS Code settings or manual JSON edit |
16
+ | Codex | `.mcp.json` (project root) | Manual JSON edit |
17
+ | Cursor | `.cursor/mcp.json` | Cursor Settings > MCP |
18
+
19
+ ### Artifact Path Self-Check
20
+
21
+ Before saving any artifact, verify the platform's native path is NOT the only copy:
22
+
23
+ | Platform Native Path | RAG-Indexed? | Action Required |
24
+ |---------------------|:------------:|-----------------|
25
+ | `brain/<conv>/` (Antigravity) | NO | Copy to `.deuk-agent/docs/` |
26
+ | `.cursor/plans/` (Cursor) | NO | Copy to `.deuk-agent/docs/plan/` |
27
+ | Terminal output (Claude/Codex) | NO | Save directly to `.deuk-agent/docs/` |
28
+ | VS Code diff (Copilot) | NO | Save plan text to `.deuk-agent/docs/plan/` |
29
+ | `.deuk-agent/docs/` | **YES** | ✓ Correct path |
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: context-recall
3
+ summary: Reuse prior ticket and rule memory without turning RAG into the source of truth.
4
+ ---
5
+
6
+ # Context Recall
7
+
8
+ Authority: follow `core-rules/AGENTS.md`, the active ticket APC, Phase Gate, and `PROJECT_RULE.md`.
9
+
10
+ Use this skill when a task repeats a failure family, references prior decisions, asks why something happened, or crosses old tickets/rules.
11
+
12
+ ## Micro-Protocol
13
+
14
+ 1. Read current local source, project rules, and active ticket first.
15
+ 2. Ask DeukAgentContext one narrow query naming the project, symbol, file, command, or failure mode.
16
+ 3. Treat stale, duplicate, placeholder, or unrelated hits as weak evidence.
17
+ 4. Put useful recall into the ticket as evidence, not chat narration.
18
+ 5. If local analysis produces reusable current knowledge after a miss, add one knowledge record.
19
+
20
+ ## Stop Conditions
21
+
22
+ - Two weak or stale recall attempts for the same question.
23
+ - RAG conflicts with current local source.
24
+ - Recall would expand scope beyond the active ticket.
25
+ - The remembered fix path bypasses current generated/source, parity, or verification rules.
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: generated-file-guard
3
+ summary: Prevent direct generated artifact edits and route changes to their source.
4
+ ---
5
+
6
+ # Generated File Guard
7
+
8
+ Authority: follow `core-rules/AGENTS.md`, the active ticket APC, Phase Gate, and `PROJECT_RULE.md`.
9
+
10
+ Use this skill when a task mentions generated files, `dist`, `gen`, codegen, reports, benchmark outputs, or synchronized spokes.
11
+
12
+ ## Micro-Protocol
13
+
14
+ 1. Check `PROJECT_RULE.md` generated/source mapping.
15
+ 2. Check target files for `@generated`, `DO NOT EDIT`, generated directories, or report artifact paths.
16
+ 3. If the target is generated, identify the source file or generator command.
17
+ 4. Prefer dry-run or `/tmp` output when probing generators.
18
+ 5. Record the source-of-truth owner and verification command in the ticket before edits.
19
+
20
+ ## Stop Conditions
21
+
22
+ - The source-of-truth file cannot be identified after bounded lookup.
23
+ - A broad regeneration would modify outputs outside ticket scope.
24
+ - The proposed fix hides, relabels, or narrows failing generated/report rows.
25
+ - The change would edit both generated output and source in the same patch.
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: safe-refactor
3
+ summary: Keep refactors small, scoped, and test-backed inside DeukAgentRules TDW.
4
+ ---
5
+
6
+ # Safe Refactor
7
+
8
+ Authority: follow `core-rules/AGENTS.md`, the active ticket APC, Phase Gate, and `PROJECT_RULE.md`.
9
+
10
+ Use this skill when the user asks for refactor, cleanup, simplification, or restructuring.
11
+
12
+ ## Micro-Protocol
13
+
14
+ 1. Confirm the active ticket allows refactoring of the target module.
15
+ 2. Name the smallest behavior-preserving change that satisfies the request.
16
+ 3. Inspect current tests or the smallest verification command before editing.
17
+ 4. Avoid unrelated renames, formatting sweeps, dependency changes, and style churn.
18
+ 5. After edits, run the narrowest relevant test or lint gate and record the result in the ticket.
19
+
20
+ ## Stop Conditions
21
+
22
+ - No active ticket or APC boundary for the refactor.
23
+ - Target crosses unrelated modules.
24
+ - The feature has no meaningful verification path.
25
+ - The change would alter generated output or shared interfaces without explicit approval.
@@ -1,11 +0,0 @@
1
- <!-- deuk-agent-rule-cursorrules:begin -->
2
- # 💎 RAG-FIRST HARD LOCK IS AUTHORITATIVE
3
-
4
- For Antigravity (Gemini), the **RAG-FIRST ACTION [ACTION 0]** and **CONTINUOUS RAG POLICY** defined in **AGENTS.md** and **gemini.md** are the absolute Single Source of Truth.
5
-
6
- 1. **[ABSOLUTE PRIORITY]**: Every request MUST begin with `mcp_deukrag_search_*`.
7
- 2. **[gemini.md]**: You MUST read and follow the specific hard locks in `gemini.md` at the root.
8
- 3. **[TICKET SYSTEM]**: Follow the TDD workflow in `AGENTS.md` strictly.
9
-
10
- Do not skip RAG research by relying on local file reads (`view_file`, `grep_search`). Local files are for details; RAG is for architectural truth and zero-regression.
11
- <!-- deuk-agent-rule-cursorrules:end -->