deuk-agent-rule 1.0.13 → 2.2.1
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/CHANGELOG.md +139 -85
- package/README.ko.md +125 -106
- package/README.ko.pdf +0 -0
- package/README.md +123 -106
- package/bundle/.cursorrules +7 -0
- package/bundle/AGENTS.md +87 -96
- package/bundle/rules/delivery-and-parallel-work.mdc +26 -26
- package/bundle/rules/git-commit.mdc +18 -24
- package/bundle/rules/multi-ai-workflow.mdc +76 -26
- package/package.json +4 -3
- package/scripts/cli-args.mjs +43 -0
- package/scripts/cli-init-commands.mjs +65 -0
- package/scripts/cli-init-logic.mjs +21 -0
- package/scripts/cli-prompts.mjs +123 -0
- package/scripts/cli-ticket-commands.mjs +159 -0
- package/scripts/cli-ticket-logic.mjs +229 -0
- package/scripts/cli-utils.mjs +82 -0
- package/scripts/cli.mjs +110 -441
- package/scripts/merge-logic.mjs +365 -195
- package/scripts/sync-bundle.mjs +50 -44
- package/scripts/sync-oss.mjs +10 -9
package/scripts/cli.mjs
CHANGED
|
@@ -1,441 +1,110 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
/** Survey only today; merge/init does not branch on these yet (future tool-specific templates). */
|
|
112
|
-
const AGENT_TOOLS = [
|
|
113
|
-
{ label: "Cursor", value: "cursor" },
|
|
114
|
-
{ label: "GitHub Copilot", value: "copilot" },
|
|
115
|
-
{ label: "Gemini / Antigravity", value: "gemini" },
|
|
116
|
-
{ label: "Claude (Cursor / Claude Code)", value: "claude" },
|
|
117
|
-
{ label: "Windsurf", value: "windsurf" },
|
|
118
|
-
{ label: "JetBrains AI Assistant", value: "jetbrains" },
|
|
119
|
-
{ label: "All of the above", value: "all" },
|
|
120
|
-
{ label: "Other / skip", value: "other" },
|
|
121
|
-
];
|
|
122
|
-
|
|
123
|
-
/** Written after first interactive init; reused on later inits unless --interactive or schema mismatch. */
|
|
124
|
-
const INIT_CONFIG_VERSION = 1;
|
|
125
|
-
const INIT_CONFIG_FILENAME = ".deuk-agent-rule.config.json";
|
|
126
|
-
|
|
127
|
-
function loadInitConfig(cwd) {
|
|
128
|
-
const p = join(cwd, INIT_CONFIG_FILENAME);
|
|
129
|
-
if (!existsSync(p)) return null;
|
|
130
|
-
try {
|
|
131
|
-
const j = JSON.parse(readFileSync(p, "utf8"));
|
|
132
|
-
if (j.version !== INIT_CONFIG_VERSION) return null;
|
|
133
|
-
const allowedStack = new Set(STACKS.map((s) => s.value));
|
|
134
|
-
if (!allowedStack.has(j.stack)) return null;
|
|
135
|
-
const allowedTools = new Set(AGENT_TOOLS.map((t) => t.value));
|
|
136
|
-
if (!Array.isArray(j.agentTools) || !j.agentTools.every((t) => allowedTools.has(t))) return null;
|
|
137
|
-
if (!["inject", "skip", "overwrite"].includes(j.agentsMode)) return null;
|
|
138
|
-
return {
|
|
139
|
-
stack: j.stack,
|
|
140
|
-
agentTools: j.agentTools,
|
|
141
|
-
agentsMode: j.agentsMode,
|
|
142
|
-
};
|
|
143
|
-
} catch {
|
|
144
|
-
return null;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function writeInitConfig(cwd, opts) {
|
|
149
|
-
const p = join(cwd, INIT_CONFIG_FILENAME);
|
|
150
|
-
const body = {
|
|
151
|
-
version: INIT_CONFIG_VERSION,
|
|
152
|
-
stack: opts.stack,
|
|
153
|
-
agentTools: opts.agentTools,
|
|
154
|
-
agentsMode: opts.agents ?? "inject",
|
|
155
|
-
updatedAt: new Date().toISOString(),
|
|
156
|
-
};
|
|
157
|
-
writeFileSync(p, JSON.stringify(body, null, 2) + "\n", "utf8");
|
|
158
|
-
console.log("saved: " + INIT_CONFIG_FILENAME);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
async function runInteractive(opts) {
|
|
162
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
163
|
-
try {
|
|
164
|
-
console.log("\nDeukAgentRules init — let's configure your workspace.\n");
|
|
165
|
-
|
|
166
|
-
const stack = await selectOne(rl, "What is your primary tech stack?", STACKS);
|
|
167
|
-
const tools = await selectMany(rl, "Which agent tools do you use?", AGENT_TOOLS);
|
|
168
|
-
|
|
169
|
-
const targetAgents = join(opts.cwd, "AGENTS.md");
|
|
170
|
-
let agentsDefault = "inject";
|
|
171
|
-
if (!existsSync(targetAgents)) {
|
|
172
|
-
agentsDefault = "inject"; // will append markers
|
|
173
|
-
console.log("\n No AGENTS.md found — will create with markers.");
|
|
174
|
-
} else {
|
|
175
|
-
const content = readFileSync(targetAgents, "utf8");
|
|
176
|
-
const hasMarkers = content.includes("deuk-agent-rule:begin");
|
|
177
|
-
if (!hasMarkers) {
|
|
178
|
-
const choice = await selectOne(rl, "AGENTS.md exists but has no markers. How to apply?", [
|
|
179
|
-
{ label: "Append managed block at the end (safe)", value: "inject" },
|
|
180
|
-
{ label: "Overwrite entire AGENTS.md", value: "overwrite" },
|
|
181
|
-
{ label: "Skip AGENTS.md", value: "skip" },
|
|
182
|
-
]);
|
|
183
|
-
agentsDefault = choice;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
opts.agents = opts.agents ?? agentsDefault;
|
|
188
|
-
opts.stack = stack;
|
|
189
|
-
opts.agentTools = tools;
|
|
190
|
-
|
|
191
|
-
console.log("\n Stack : " + stack);
|
|
192
|
-
console.log(" Tools : " + (tools.join(", ") || "none"));
|
|
193
|
-
console.log(" AGENTS: " + opts.agents + "\n");
|
|
194
|
-
} finally {
|
|
195
|
-
rl.close();
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// ---------------------------------------------------------------------------
|
|
200
|
-
// Help / arg parsing
|
|
201
|
-
// ---------------------------------------------------------------------------
|
|
202
|
-
|
|
203
|
-
function printHelp() {
|
|
204
|
-
console.log(
|
|
205
|
-
`DeukAgentRules (npm: deuk-agent-rule) — AGENTS.md + .cursor/rules templates
|
|
206
|
-
|
|
207
|
-
Usage:
|
|
208
|
-
npx deuk-agent-rule init [options] # interactive by default
|
|
209
|
-
npx deuk-agent-rule merge [options]
|
|
210
|
-
|
|
211
|
-
Options:
|
|
212
|
-
--cwd <path> Target repo root (default: current directory)
|
|
213
|
-
--dry-run Print actions; do not write files
|
|
214
|
-
--non-interactive CI/scripts: no prompts; use --agents/--rules (no saved config read)
|
|
215
|
-
--interactive Ask questions even if .deuk-agent-rule.config.json exists
|
|
216
|
-
--tag <id> Marker id (default: deuk-agent-rule)
|
|
217
|
-
--agents <mode> inject | skip | overwrite
|
|
218
|
-
--rules <mode> prefix | skip | overwrite
|
|
219
|
-
--backup Write *.bak before overwrite
|
|
220
|
-
--append-if-no-markers
|
|
221
|
-
--marker-begin / --marker-end Custom marker strings (both required)
|
|
222
|
-
|
|
223
|
-
init also creates .deuk-agent-handoff/ and appends it to .gitignore (local handoffs).
|
|
224
|
-
After npm update, run init again: deuk-agent-rule-*.mdc rules refresh from the bundle (no separate merge needed).
|
|
225
|
-
|
|
226
|
-
Korean: package README.ko.md
|
|
227
|
-
`,
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
function parseArgs(argv) {
|
|
232
|
-
const out = {
|
|
233
|
-
cwd: process.cwd(),
|
|
234
|
-
dryRun: false,
|
|
235
|
-
backup: false,
|
|
236
|
-
tag: undefined,
|
|
237
|
-
markerBegin: undefined,
|
|
238
|
-
markerEnd: undefined,
|
|
239
|
-
agents: undefined,
|
|
240
|
-
rules: undefined,
|
|
241
|
-
appendIfNoMarkers: false,
|
|
242
|
-
nonInteractive: false,
|
|
243
|
-
interactive: false,
|
|
244
|
-
};
|
|
245
|
-
for (let i = 0; i < argv.length; i++) {
|
|
246
|
-
const a = argv[i];
|
|
247
|
-
if (a === "--cwd") {
|
|
248
|
-
out.cwd = argv[++i];
|
|
249
|
-
if (!out.cwd) throw new Error("--cwd requires a path");
|
|
250
|
-
} else if (a === "--dry-run") out.dryRun = true;
|
|
251
|
-
else if (a === "--backup") out.backup = true;
|
|
252
|
-
else if (a === "--non-interactive") out.nonInteractive = true;
|
|
253
|
-
else if (a === "--interactive") out.interactive = true;
|
|
254
|
-
else if (a === "--tag") {
|
|
255
|
-
out.tag = argv[++i];
|
|
256
|
-
if (out.tag == null) throw new Error("--tag requires a value");
|
|
257
|
-
} else if (a === "--marker-begin") {
|
|
258
|
-
out.markerBegin = argv[++i];
|
|
259
|
-
if (out.markerBegin == null) throw new Error("--marker-begin requires a value");
|
|
260
|
-
} else if (a === "--marker-end") {
|
|
261
|
-
out.markerEnd = argv[++i];
|
|
262
|
-
if (out.markerEnd == null) throw new Error("--marker-end requires a value");
|
|
263
|
-
} else if (a === "--agents") {
|
|
264
|
-
out.agents = argv[++i];
|
|
265
|
-
if (!out.agents) throw new Error("--agents requires skip|overwrite|inject");
|
|
266
|
-
} else if (a === "--rules") {
|
|
267
|
-
out.rules = argv[++i];
|
|
268
|
-
if (!out.rules) throw new Error("--rules requires skip|overwrite|prefix");
|
|
269
|
-
} else if (a === "--append-if-no-markers") out.appendIfNoMarkers = true;
|
|
270
|
-
else if (a === "-h" || a === "--help") {
|
|
271
|
-
printHelp();
|
|
272
|
-
process.exit(0);
|
|
273
|
-
} else {
|
|
274
|
-
throw new Error("Unknown argument: " + a);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
return out;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
function validateMode(name, v, allowed) {
|
|
281
|
-
if (!allowed.includes(v)) {
|
|
282
|
-
throw new Error("Invalid " + name + ": " + v + " (allowed: " + allowed.join(", ") + ")");
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// ---------------------------------------------------------------------------
|
|
287
|
-
// init / merge runners
|
|
288
|
-
// ---------------------------------------------------------------------------
|
|
289
|
-
|
|
290
|
-
function runInit(opts) {
|
|
291
|
-
const markers = resolveMarkers({
|
|
292
|
-
tag: opts.tag,
|
|
293
|
-
markerBegin: opts.markerBegin,
|
|
294
|
-
markerEnd: opts.markerEnd,
|
|
295
|
-
});
|
|
296
|
-
const agentsMode = opts.agents ?? "inject";
|
|
297
|
-
validateMode("agents", agentsMode, ["skip", "overwrite", "inject"]);
|
|
298
|
-
|
|
299
|
-
const rulesMode = opts.rules ?? "prefix";
|
|
300
|
-
validateMode("rules", rulesMode, ["skip", "overwrite", "prefix"]);
|
|
301
|
-
|
|
302
|
-
const bundleContent = readBundleAgents(bundleRoot);
|
|
303
|
-
const targetAgents = join(opts.cwd, "AGENTS.md");
|
|
304
|
-
const targetRules = join(opts.cwd, ".cursor", "rules");
|
|
305
|
-
|
|
306
|
-
const agentsResult = applyAgents({
|
|
307
|
-
targetPath: targetAgents,
|
|
308
|
-
bundleContent,
|
|
309
|
-
markers,
|
|
310
|
-
flavor: "init",
|
|
311
|
-
appendIfNoMarkers: opts.appendIfNoMarkers,
|
|
312
|
-
dryRun: opts.dryRun,
|
|
313
|
-
backup: opts.backup,
|
|
314
|
-
agentsMode,
|
|
315
|
-
});
|
|
316
|
-
console.log("AGENTS.md: " + agentsResult.action + (agentsResult.mode ? " (" + agentsResult.mode + ")" : ""));
|
|
317
|
-
|
|
318
|
-
const ruleActions = applyRules({
|
|
319
|
-
bundleRulesDir: join(bundleRoot, "rules"),
|
|
320
|
-
targetRulesDir: targetRules,
|
|
321
|
-
rulesMode,
|
|
322
|
-
dryRun: opts.dryRun,
|
|
323
|
-
backup: opts.backup,
|
|
324
|
-
});
|
|
325
|
-
for (const r of ruleActions) {
|
|
326
|
-
console.log("rule " + r.action + ": " + (r.dest || r.src) + (r.reason ? " (" + r.reason + ")" : ""));
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
ensureHandoffDirAndGitignore(opts);
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
function runMerge(opts) {
|
|
333
|
-
const markers = resolveMarkers({
|
|
334
|
-
tag: opts.tag,
|
|
335
|
-
markerBegin: opts.markerBegin,
|
|
336
|
-
markerEnd: opts.markerEnd,
|
|
337
|
-
});
|
|
338
|
-
const agentsMode = opts.agents ?? "inject";
|
|
339
|
-
validateMode("agents", agentsMode, ["skip", "overwrite", "inject"]);
|
|
340
|
-
|
|
341
|
-
const rulesMode = opts.rules ?? "skip";
|
|
342
|
-
validateMode("rules", rulesMode, ["skip", "overwrite", "prefix"]);
|
|
343
|
-
|
|
344
|
-
const bundleContent = readBundleAgents(bundleRoot);
|
|
345
|
-
const targetAgents = join(opts.cwd, "AGENTS.md");
|
|
346
|
-
const targetRules = join(opts.cwd, ".cursor", "rules");
|
|
347
|
-
|
|
348
|
-
const agentsResult = applyAgents({
|
|
349
|
-
targetPath: targetAgents,
|
|
350
|
-
bundleContent,
|
|
351
|
-
markers,
|
|
352
|
-
flavor: "merge",
|
|
353
|
-
appendIfNoMarkers: opts.appendIfNoMarkers,
|
|
354
|
-
dryRun: opts.dryRun,
|
|
355
|
-
backup: opts.backup,
|
|
356
|
-
agentsMode,
|
|
357
|
-
});
|
|
358
|
-
console.log("AGENTS.md: " + agentsResult.action + (agentsResult.mode ? " (" + agentsResult.mode + ")" : ""));
|
|
359
|
-
|
|
360
|
-
const ruleActions = applyRules({
|
|
361
|
-
bundleRulesDir: join(bundleRoot, "rules"),
|
|
362
|
-
targetRulesDir: targetRules,
|
|
363
|
-
rulesMode,
|
|
364
|
-
dryRun: opts.dryRun,
|
|
365
|
-
backup: opts.backup,
|
|
366
|
-
});
|
|
367
|
-
for (const r of ruleActions) {
|
|
368
|
-
console.log("rule " + r.action + ": " + (r.dest || r.src) + (r.reason ? " (" + r.reason + ")" : ""));
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// ---------------------------------------------------------------------------
|
|
373
|
-
// Entry point
|
|
374
|
-
// ---------------------------------------------------------------------------
|
|
375
|
-
|
|
376
|
-
async function main() {
|
|
377
|
-
const argv = process.argv.slice(2);
|
|
378
|
-
const sub = argv[0];
|
|
379
|
-
if (!sub || sub === "-h" || sub === "--help") {
|
|
380
|
-
printHelp();
|
|
381
|
-
process.exit(0);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
const rest = argv.slice(1);
|
|
385
|
-
if (sub === "help") {
|
|
386
|
-
printHelp();
|
|
387
|
-
process.exit(0);
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
let opts;
|
|
391
|
-
try {
|
|
392
|
-
opts = parseArgs(rest);
|
|
393
|
-
} catch (e) {
|
|
394
|
-
console.error(e.message || e);
|
|
395
|
-
printHelp();
|
|
396
|
-
process.exit(1);
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
if (!existsSync(bundleRoot)) {
|
|
400
|
-
console.error(
|
|
401
|
-
"Missing bundle/ (run from published package or run npm run sync in DeukAgentRules when developing).",
|
|
402
|
-
);
|
|
403
|
-
process.exit(1);
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
try {
|
|
407
|
-
if (sub === "init") {
|
|
408
|
-
if (!isNonInteractive(opts)) {
|
|
409
|
-
const saved = loadInitConfig(opts.cwd);
|
|
410
|
-
if (saved && !opts.interactive) {
|
|
411
|
-
opts.agents = opts.agents !== undefined ? opts.agents : saved.agentsMode;
|
|
412
|
-
opts.stack = saved.stack;
|
|
413
|
-
opts.agentTools = saved.agentTools;
|
|
414
|
-
const stackL = STACKS.find((s) => s.value === saved.stack)?.label || saved.stack;
|
|
415
|
-
console.log("\nDeukAgentRules init — using saved choices from " + INIT_CONFIG_FILENAME);
|
|
416
|
-
console.log(" Stack : " + saved.stack + " (" + stackL + ")");
|
|
417
|
-
console.log(" Tools : " + (saved.agentTools.join(", ") || "none"));
|
|
418
|
-
console.log(" AGENTS: " + opts.agents);
|
|
419
|
-
console.log(" (`--interactive` to change, or edit/delete " + INIT_CONFIG_FILENAME + ")\n");
|
|
420
|
-
} else {
|
|
421
|
-
await runInteractive(opts);
|
|
422
|
-
if (!opts.dryRun) {
|
|
423
|
-
writeInitConfig(opts.cwd, opts);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
runInit(opts);
|
|
428
|
-
} else if (sub === "merge") {
|
|
429
|
-
runMerge(opts);
|
|
430
|
-
} else {
|
|
431
|
-
console.error("Unknown command: " + sub);
|
|
432
|
-
printHelp();
|
|
433
|
-
process.exit(1);
|
|
434
|
-
}
|
|
435
|
-
} catch (e) {
|
|
436
|
-
console.error(e.message || e);
|
|
437
|
-
process.exit(1);
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
main();
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { existsSync } from "fs";
|
|
3
|
+
import { dirname, join } from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
import { parseArgs, parseTicketArgs } from "./cli-args.mjs";
|
|
6
|
+
import { runInit, runMerge } from "./cli-init-commands.mjs";
|
|
7
|
+
import { runTicketCreate, runTicketList, runTicketUse, runTicketClose } from "./cli-ticket-commands.mjs";
|
|
8
|
+
import { loadInitConfig, writeInitConfig } from "./cli-prompts.mjs";
|
|
9
|
+
import { runInteractive } from "./cli-prompts.mjs";
|
|
10
|
+
|
|
11
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const pkgRoot = join(__dirname, "..");
|
|
13
|
+
const bundleRoot = join(pkgRoot, "bundle");
|
|
14
|
+
async function main() {
|
|
15
|
+
const argv = process.argv.slice(2);
|
|
16
|
+
const sub = argv[0];
|
|
17
|
+
if (!sub || sub === "-h" || sub === "--help" || sub === "help") {
|
|
18
|
+
printHelp();
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const rest = argv.slice(1);
|
|
23
|
+
|
|
24
|
+
if (sub === "ticket") {
|
|
25
|
+
const action = rest[0];
|
|
26
|
+
const opts = parseTicketArgs(rest.slice(1));
|
|
27
|
+
if (action === "create") await runTicketCreate(opts);
|
|
28
|
+
else if (action === "list") await runTicketList(opts);
|
|
29
|
+
else if (action === "use") await runTicketUse(opts);
|
|
30
|
+
else if (action === "close") await runTicketClose(opts);
|
|
31
|
+
else if (action === "migrate") await runTicketMigrate(opts);
|
|
32
|
+
else {
|
|
33
|
+
console.error("Unknown ticket action: " + action);
|
|
34
|
+
printHelp();
|
|
35
|
+
}
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (sub === "init" || sub === "merge") {
|
|
40
|
+
const opts = parseArgs(rest);
|
|
41
|
+
if (opts.help) {
|
|
42
|
+
printHelp();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const saved = loadInitConfig(opts.cwd);
|
|
47
|
+
if (saved && !opts.interactive) {
|
|
48
|
+
// CLI flags (opts) take precedence over saved config
|
|
49
|
+
for (const key in saved) {
|
|
50
|
+
if (opts[key] === undefined) opts[key] = saved[key];
|
|
51
|
+
}
|
|
52
|
+
console.log(`Using saved config from .deuk-agent-rule.config.json (CLI overrides applied)`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (sub === "init") {
|
|
56
|
+
await handleInit(opts);
|
|
57
|
+
} else {
|
|
58
|
+
runMerge(opts, bundleRoot);
|
|
59
|
+
}
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
console.error("Unknown command: " + sub);
|
|
64
|
+
printHelp();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
import { runTicketMigrate } from "./cli-ticket-commands.mjs";
|
|
68
|
+
|
|
69
|
+
async function handleInit(opts) {
|
|
70
|
+
if (!opts.interactive && !opts.nonInteractive && !loadInitConfig(opts.cwd)) {
|
|
71
|
+
// If no config and not interactive, prompt unless non-interactive
|
|
72
|
+
await runInteractive(opts);
|
|
73
|
+
if (!opts.dryRun) writeInitConfig(opts.cwd, opts);
|
|
74
|
+
} else if (opts.interactive) {
|
|
75
|
+
await runInteractive(opts);
|
|
76
|
+
if (!opts.dryRun) writeInitConfig(opts.cwd, opts);
|
|
77
|
+
}
|
|
78
|
+
await runInit(opts, bundleRoot);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function printHelp() {
|
|
82
|
+
console.log(`DeukAgentRules CLI - Generalization Rules & Ticket Management
|
|
83
|
+
|
|
84
|
+
Usage:
|
|
85
|
+
npx deuk-agent-rule init [options]
|
|
86
|
+
npx deuk-agent-rule merge [options]
|
|
87
|
+
npx deuk-agent-rule ticket <create|list|use|close|migrate> [options]
|
|
88
|
+
|
|
89
|
+
Options:
|
|
90
|
+
--cwd <path> Target repo root
|
|
91
|
+
--dry-run Print actions without writing
|
|
92
|
+
--non-interactive CI/scripts mode: no prompts
|
|
93
|
+
--tag <id> Custom marker ID (default: deuk-agent-rule)
|
|
94
|
+
--agents <mode> inject | skip | overwrite
|
|
95
|
+
--rules <mode> prefix | skip | overwrite
|
|
96
|
+
--cursorrules <mode> inject | skip | overwrite
|
|
97
|
+
|
|
98
|
+
Ticket Options:
|
|
99
|
+
--topic <name> Ticket topic slug
|
|
100
|
+
--group <name> Ticket group (sub|main|discussion)
|
|
101
|
+
--project <name> Project filter (DeukUI|DeukAgentRules)
|
|
102
|
+
--latest Use most recent ticket
|
|
103
|
+
--path-only Print only the file path
|
|
104
|
+
`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
main().catch(err => {
|
|
108
|
+
console.error(err.message || err);
|
|
109
|
+
process.exit(1);
|
|
110
|
+
});
|