deuk-agent-rule 2.2.1 → 2.2.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.
@@ -1,7 +1,7 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from "fs";
2
- import { basename, join } from "path";
3
- import { toSlug, toRepoRelativePath, inferRefTitleAndTopic, resolveReferencedTicketPath } from "./cli-utils.mjs";
4
- import { TICKET_DIR_NAME, appendTicketEntry, rebuildTicketIndexFromTopicFilesIfNeeded, detectConsumerTicketDir } from "./cli-ticket-logic.mjs";
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync, copyFileSync, readdirSync, rmSync, statSync } from "fs";
2
+ import { basename, join, dirname, relative, resolve } from "path";
3
+ import { toSlug, toRepoRelativePath, inferRefTitleAndTopic, resolveReferencedTicketPath, toPosixPath } from "./cli-utils.mjs";
4
+ import { TICKET_DIR_NAME, appendTicketEntry, rebuildTicketIndexFromTopicFilesIfNeeded, detectConsumerTicketDir, readTicketIndexJson, writeTicketIndexJson, writeTicketListFile } from "./cli-ticket-logic.mjs";
5
5
 
6
6
  import { createInterface } from "readline";
7
7
  import { selectOne } from "./cli-prompts.mjs";
@@ -118,7 +118,6 @@ export async function runTicketUse(opts) {
118
118
  }
119
119
 
120
120
  import { getLegacyMigrationCandidate, parseLegacyTicketMeta } from "./cli-ticket-logic.mjs";
121
- import { dirname } from "path";
122
121
 
123
122
  export async function runTicketMigrate(opts) {
124
123
  const candidate = getLegacyMigrationCandidate(opts.cwd);
@@ -157,3 +156,114 @@ export async function runTicketMigrate(opts) {
157
156
  }
158
157
  }
159
158
  }
159
+
160
+ export function pickTicketEntry(opts, indexJson) {
161
+ const rows = [...indexJson.entries].sort((a, b) => String(b.createdAt || "").localeCompare(String(a.createdAt || "")));
162
+ if (rows.length === 0) return null;
163
+ if (opts.topic) {
164
+ const key = String(opts.topic).toLowerCase();
165
+ return rows.find(e => String(e.topic || "").toLowerCase().includes(key)) || null;
166
+ }
167
+ return rows[0];
168
+ }
169
+
170
+ export async function runTicketArchive(opts) {
171
+ if (!opts.latest && !opts.topic) {
172
+ if (process.stdout.isTTY) {
173
+ const index = rebuildTicketIndexFromTopicFilesIfNeeded(opts.cwd, opts);
174
+ const choices = index.entries
175
+ .filter(e => e.status !== "archived")
176
+ .map(e => ({ label: `[${e.group}] ${e.title}`, value: e.topic }));
177
+ if (choices.length > 0) {
178
+ const { createInterface } = await import("readline");
179
+ const { selectOne } = await import("./cli-prompts.mjs");
180
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
181
+ try {
182
+ opts.topic = await selectOne(rl, "Choose a ticket to archive (this will move the file to archive/):", choices);
183
+ } finally {
184
+ rl.close();
185
+ }
186
+ } else {
187
+ throw new Error("No active tickets found to archive.");
188
+ }
189
+ } else {
190
+ throw new Error("ticket archive requires --latest or --topic <prefix>");
191
+ }
192
+ }
193
+
194
+ const indexJson = rebuildTicketIndexFromTopicFilesIfNeeded(opts.cwd, opts);
195
+ const found = pickTicketEntry(opts, indexJson);
196
+ if (!found) throw new Error("ticket archive: no matching entry");
197
+
198
+ const absPath = join(opts.cwd, found.path);
199
+ if (!existsSync(absPath)) {
200
+ throw new Error("ticket archive: file not found " + found.path);
201
+ }
202
+
203
+ const archiveDir = join(opts.cwd, TICKET_DIR_NAME, "archive", found.group || "sub");
204
+ if (!opts.dryRun) mkdirSync(archiveDir, { recursive: true });
205
+
206
+ const fileName = found.path.split(/[/\\]/).pop();
207
+ const newAbsPath = join(archiveDir, fileName);
208
+ const bodyLines = readFileSync(absPath, "utf8").trimEnd().split(/\r?\n/);
209
+
210
+ if (opts.report) {
211
+ const reportSrc = resolve(opts.cwd, opts.report);
212
+ if (!existsSync(reportSrc)) {
213
+ throw new Error("ticket archive: report file not found " + opts.report);
214
+ }
215
+ const reportDir = join(opts.cwd, TICKET_DIR_NAME, "reports");
216
+ if (!opts.dryRun) mkdirSync(reportDir, { recursive: true });
217
+
218
+ const reportDest = join(reportDir, `REPORT-${fileName}`);
219
+ if (!opts.dryRun) copyFileSync(reportSrc, reportDest);
220
+ console.log("ticket archive: copied report to " + toRepoRelativePath(opts.cwd, reportDest));
221
+
222
+ bodyLines.push("");
223
+ bodyLines.push("## šŸ“„ Attached Report");
224
+ const relativeLink = toPosixPath(relative(dirname(newAbsPath), reportDest));
225
+ bodyLines.push(`- [View Report](${relativeLink})`);
226
+ }
227
+
228
+ if (opts.dryRun) {
229
+ console.log("ticket archive: would move " + toRepoRelativePath(opts.cwd, absPath) + " to " + toRepoRelativePath(opts.cwd, newAbsPath));
230
+ return;
231
+ }
232
+
233
+ writeFileSync(newAbsPath, bodyLines.join("\n") + "\n", "utf8");
234
+ rmSync(absPath);
235
+ console.log("ticket archive: moved ticket to " + toRepoRelativePath(opts.cwd, newAbsPath));
236
+
237
+ const entryIdx = indexJson.entries.findIndex(e => e.id === found.id);
238
+ if (entryIdx >= 0) {
239
+ indexJson.entries[entryIdx].status = "archived";
240
+ indexJson.entries[entryIdx].path = toRepoRelativePath(opts.cwd, newAbsPath);
241
+ indexJson.entries[entryIdx].updatedAt = new Date().toISOString();
242
+ }
243
+
244
+ writeTicketIndexJson(opts.cwd, indexJson, opts);
245
+ writeTicketListFile(opts.cwd, indexJson.entries, opts);
246
+ }
247
+
248
+ export async function runTicketReports(opts) {
249
+ const reportDir = join(opts.cwd, TICKET_DIR_NAME, "reports");
250
+ console.log("\nšŸ“„ Agent Reports:");
251
+ if (!existsSync(reportDir)) {
252
+ console.log(" No reports found.");
253
+ return;
254
+ }
255
+ const files = readdirSync(reportDir).filter(f => f.startsWith("REPORT-") && f.endsWith(".md"));
256
+ if (files.length === 0) {
257
+ console.log(" No reports found.");
258
+ return;
259
+ }
260
+
261
+ const sorted = files.sort((a, b) => {
262
+ return statSync(join(reportDir, b)).mtime.getTime() - statSync(join(reportDir, a)).mtime.getTime();
263
+ });
264
+
265
+ sorted.slice(0, opts.limit || 30).forEach(f => {
266
+ console.log(` - [${f}]`);
267
+ });
268
+ console.log("");
269
+ }
package/scripts/cli.mjs CHANGED
@@ -4,7 +4,7 @@ import { dirname, join } from "path";
4
4
  import { fileURLToPath } from "url";
5
5
  import { parseArgs, parseTicketArgs } from "./cli-args.mjs";
6
6
  import { runInit, runMerge } from "./cli-init-commands.mjs";
7
- import { runTicketCreate, runTicketList, runTicketUse, runTicketClose } from "./cli-ticket-commands.mjs";
7
+ import { runTicketCreate, runTicketList, runTicketUse, runTicketClose, runTicketArchive, runTicketReports } from "./cli-ticket-commands.mjs";
8
8
  import { loadInitConfig, writeInitConfig } from "./cli-prompts.mjs";
9
9
  import { runInteractive } from "./cli-prompts.mjs";
10
10
 
@@ -28,6 +28,8 @@ async function main() {
28
28
  else if (action === "list") await runTicketList(opts);
29
29
  else if (action === "use") await runTicketUse(opts);
30
30
  else if (action === "close") await runTicketClose(opts);
31
+ else if (action === "archive") await runTicketArchive(opts);
32
+ else if (action === "reports") await runTicketReports(opts);
31
33
  else if (action === "migrate") await runTicketMigrate(opts);
32
34
  else {
33
35
  console.error("Unknown ticket action: " + action);
@@ -84,7 +86,7 @@ function printHelp() {
84
86
  Usage:
85
87
  npx deuk-agent-rule init [options]
86
88
  npx deuk-agent-rule merge [options]
87
- npx deuk-agent-rule ticket <create|list|use|close|migrate> [options]
89
+ npx deuk-agent-rule ticket <create|list|use|close|archive|reports|migrate> [options]
88
90
 
89
91
  Options:
90
92
  --cwd <path> Target repo root
File without changes
File without changes
@@ -2,7 +2,7 @@
2
2
  * Populates ../DeukAgentRulesOSS for the public GitHub repo.
3
3
  * Run: cd deuk-agent-rule && npm run sync:oss
4
4
  */
5
- import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from "fs";
5
+ import { cpSync, existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "fs";
6
6
  import { dirname, join } from "path";
7
7
  import { fileURLToPath } from "url";
8
8
 
@@ -39,14 +39,7 @@ cpSync(join(pkgRoot, "publish"), join(ossRoot, "publish"), { recursive: true, fo
39
39
  if (existsSync(join(pkgRoot, ".github"))) {
40
40
  cpSync(join(pkgRoot, ".github"), join(ossRoot, ".github"), { recursive: true, force: true });
41
41
  }
42
-
43
- // Modular CLI: Copy all runtime scripts, exclude internal sync tools
44
- const scriptsDir = join(pkgRoot, "scripts");
45
- for (const name of readdirSync(scriptsDir)) {
46
- if (!name.endsWith(".mjs")) continue;
47
- if (name === "sync-oss.mjs" || name === "sync-bundle.mjs") continue;
48
- cpSync(join(scriptsDir, name), join(ossRoot, "scripts", name), { force: true });
49
- }
42
+ cpSync(join(pkgRoot, "scripts"), join(ossRoot, "scripts"), { recursive: true, force: true });
50
43
 
51
44
  if (!existsSync(ossPublic)) {
52
45
  throw new Error("Missing oss-public/: " + ossPublic);
package/README.ko.pdf DELETED
Binary file