deuk-agent-flow 5.0.2 → 5.0.7

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 (102) hide show
  1. package/CHANGELOG.ko.md +45 -0
  2. package/CHANGELOG.md +48 -0
  3. package/bundled/deuk-agent-flow.vsix +0 -0
  4. package/core-rules/AGENTS.md +5 -5
  5. package/package.json +20 -2
  6. package/scripts/bundle-vscode-vsix.ts +1 -1
  7. package/scripts/cli-args.ts +46 -1
  8. package/scripts/cli-context-commands.ts +35 -0
  9. package/scripts/cli-init-claude.ts +179 -0
  10. package/scripts/cli-init-commands.ts +21 -8
  11. package/scripts/cli-init-core.ts +89 -0
  12. package/scripts/cli-init-instructions.ts +489 -0
  13. package/scripts/cli-init-migrate.ts +504 -0
  14. package/scripts/cli-init-workspace.ts +63 -0
  15. package/scripts/cli-locales.ts +85 -0
  16. package/scripts/cli-skill-commands.ts +3 -1
  17. package/scripts/cli-ticket-commands.ts +68 -2
  18. package/scripts/cli-ticket-docmeta.ts +103 -0
  19. package/scripts/cli-ticket-document.ts +153 -0
  20. package/scripts/cli-ticket-evidence.ts +312 -0
  21. package/scripts/cli-ticket-home.ts +449 -0
  22. package/scripts/cli-ticket-index.ts +8 -0
  23. package/scripts/cli-ticket-scan.ts +102 -0
  24. package/scripts/cli-ticket-surface.ts +56 -0
  25. package/scripts/cli.ts +10 -1
  26. package/scripts/oss-prepack.js +32 -0
  27. package/scripts/out/scripts/bundle-vscode-vsix.js +68 -0
  28. package/scripts/out/scripts/bundle-vscode-vsix.js.map +1 -0
  29. package/scripts/out/scripts/cli-args.js +411 -0
  30. package/scripts/out/scripts/cli-args.js.map +1 -0
  31. package/scripts/out/scripts/cli-context-commands.js +31 -0
  32. package/scripts/out/scripts/cli-context-commands.js.map +1 -0
  33. package/scripts/out/scripts/cli-init-claude.js +176 -0
  34. package/scripts/out/scripts/cli-init-claude.js.map +1 -0
  35. package/scripts/out/scripts/cli-init-commands.js +98 -0
  36. package/scripts/out/scripts/cli-init-commands.js.map +1 -0
  37. package/scripts/out/scripts/cli-init-core.js +89 -0
  38. package/scripts/out/scripts/cli-init-core.js.map +1 -0
  39. package/scripts/out/scripts/cli-init-instructions.js +460 -0
  40. package/scripts/out/scripts/cli-init-instructions.js.map +1 -0
  41. package/scripts/out/scripts/cli-init-logic.js +41 -0
  42. package/scripts/out/scripts/cli-init-logic.js.map +1 -0
  43. package/scripts/out/scripts/cli-init-migrate.js +497 -0
  44. package/scripts/out/scripts/cli-init-migrate.js.map +1 -0
  45. package/scripts/out/scripts/cli-init-workspace.js +57 -0
  46. package/scripts/out/scripts/cli-init-workspace.js.map +1 -0
  47. package/scripts/out/scripts/cli-locales.js +83 -0
  48. package/scripts/out/scripts/cli-locales.js.map +1 -0
  49. package/scripts/out/scripts/cli-prompts.js +101 -0
  50. package/scripts/out/scripts/cli-prompts.js.map +1 -0
  51. package/scripts/out/scripts/cli-rule-compiler.js +121 -0
  52. package/scripts/out/scripts/cli-rule-compiler.js.map +1 -0
  53. package/scripts/out/scripts/cli-skill-commands.js +708 -0
  54. package/scripts/out/scripts/cli-skill-commands.js.map +1 -0
  55. package/scripts/out/scripts/cli-telemetry-commands.js +604 -0
  56. package/scripts/out/scripts/cli-telemetry-commands.js.map +1 -0
  57. package/scripts/out/scripts/cli-ticket-command-shared.js +2 -0
  58. package/scripts/out/scripts/cli-ticket-command-shared.js.map +1 -0
  59. package/scripts/out/scripts/cli-ticket-commands.js +3538 -0
  60. package/scripts/out/scripts/cli-ticket-commands.js.map +1 -0
  61. package/scripts/out/scripts/cli-ticket-docmeta.js +90 -0
  62. package/scripts/out/scripts/cli-ticket-docmeta.js.map +1 -0
  63. package/scripts/out/scripts/cli-ticket-document.js +121 -0
  64. package/scripts/out/scripts/cli-ticket-document.js.map +1 -0
  65. package/scripts/out/scripts/cli-ticket-evidence.js +286 -0
  66. package/scripts/out/scripts/cli-ticket-evidence.js.map +1 -0
  67. package/scripts/out/scripts/cli-ticket-home.js +440 -0
  68. package/scripts/out/scripts/cli-ticket-home.js.map +1 -0
  69. package/scripts/out/scripts/cli-ticket-index.js +280 -0
  70. package/scripts/out/scripts/cli-ticket-index.js.map +1 -0
  71. package/scripts/out/scripts/cli-ticket-migration.js +261 -0
  72. package/scripts/out/scripts/cli-ticket-migration.js.map +1 -0
  73. package/scripts/out/scripts/cli-ticket-parser.js +90 -0
  74. package/scripts/out/scripts/cli-ticket-parser.js.map +1 -0
  75. package/scripts/out/scripts/cli-ticket-scan.js +93 -0
  76. package/scripts/out/scripts/cli-ticket-scan.js.map +1 -0
  77. package/scripts/out/scripts/cli-ticket-surface.js +53 -0
  78. package/scripts/out/scripts/cli-ticket-surface.js.map +1 -0
  79. package/scripts/out/scripts/cli-usage-commands.js +310 -0
  80. package/scripts/out/scripts/cli-usage-commands.js.map +1 -0
  81. package/scripts/out/scripts/cli-utils.js +1544 -0
  82. package/scripts/out/scripts/cli-utils.js.map +1 -0
  83. package/scripts/out/scripts/cli.js +705 -0
  84. package/scripts/out/scripts/cli.js.map +1 -0
  85. package/scripts/out/scripts/lint-md.js +238 -0
  86. package/scripts/out/scripts/lint-md.js.map +1 -0
  87. package/scripts/out/scripts/lint-rules.js +193 -0
  88. package/scripts/out/scripts/lint-rules.js.map +1 -0
  89. package/scripts/out/scripts/merge-logic.js +38 -0
  90. package/scripts/out/scripts/merge-logic.js.map +1 -0
  91. package/scripts/out/scripts/plan-parser.js +52 -0
  92. package/scripts/out/scripts/plan-parser.js.map +1 -0
  93. package/scripts/out/scripts/ticket-machine.js +94 -0
  94. package/scripts/out/scripts/ticket-machine.js.map +1 -0
  95. package/scripts/out/scripts/ticket-workflow.js +498 -0
  96. package/scripts/out/scripts/ticket-workflow.js.map +1 -0
  97. package/scripts/ticket-machine.ts +99 -0
  98. package/scripts/ticket-workflow.ts +544 -0
  99. package/templates/skills/role-closer/SKILL.md +27 -0
  100. package/templates/skills/role-implementer/SKILL.md +30 -0
  101. package/templates/skills/role-planner/SKILL.md +29 -0
  102. package/templates/skills/role-qa-verifier/SKILL.md +30 -0
@@ -0,0 +1,440 @@
1
+ // ─── 티켓 홈 이전 + self-healing 레지스트리 (#622) ──────────────────────────
2
+ //
3
+ // 티켓 데이터(.md/INDEX.json/claim/archive)는 워크스페이스 git 저장소가 아니라
4
+ // ~/.deuk-agent/tickets/{ticketKey}/ 에만 존재한다. 워크스페이스에는 git-ignore되는
5
+ // 불변 ID 마커(.deuk-agent/workspace-id) 1개만 남아 "주소록 열쇠" 역할을 한다.
6
+ //
7
+ // 매 명령 진입 시 reconcileWorkspace()가:
8
+ // 1. 마커(UUID) 읽기 — 없으면 발급·생성
9
+ // 2. 레지스트리 조회 (id → {path, ticketKey, migratedAt})
10
+ // 3. path 불일치(경로 이동/rename) → 자동 갱신(self-heal)
11
+ // 4. 구 위치(.deuk-agent/tickets)에 잔재 있으면 홈으로 흡수 + 삭제 + .gitignore
12
+ // 모두 idempotent — 여러 번 실행해도 안전하고 데이터 손실 0.
13
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync, renameSync, rmSync, statSync, copyFileSync } from "fs";
14
+ import { randomUUID, createHash } from "crypto";
15
+ import { LEGACY_DEUK, DEUK_ROOT_DIR, TICKET_SUBDIR, WORKSPACE_MARKER_FILE, basenameAnyOS, hasWorkspaceMarker, isHomeDirectChild, makePath, normalizeRegistryPath, registerTicketHomeModule, resolveUserHome } from "./cli-utils.js";
16
+ import { collectTicketMarkdownFiles } from "./cli-ticket-scan.js";
17
+ const WORKSPACE_ID_FILE = "workspace-id";
18
+ // ─── 홈 경로 ────────────────────────────────────────────────────────────────
19
+ export function homeTicketRoot(opts = {}) {
20
+ return makePath([resolveUserHome(opts), DEUK_ROOT_DIR, "tickets"], opts);
21
+ }
22
+ export function resolveHomeTicketDir(ticketKey, opts = {}) {
23
+ return makePath(homeTicketRoot(opts), ticketKey);
24
+ }
25
+ // ─── 불변 ID 마커 ───────────────────────────────────────────────────────────
26
+ function workspaceIdMarkerPath(workspaceRoot) {
27
+ // New: .deuk-workspace-id file at workspace root. Fall back to legacy path for
28
+ // read-only callers (readWorkspaceId) so old workspaces still resolve until migration.
29
+ // #736: normalizeRegistryPath converts backslash Windows paths (D:\workspace\X) to
30
+ // a consistent form so makePath does not mangle escape sequences (\w, \D etc.)
31
+ // when running under POSIX node (Git Bash / WSL).
32
+ return makePath(normalizeRegistryPath(workspaceRoot), WORKSPACE_MARKER_FILE);
33
+ }
34
+ function legacyWorkspaceIdMarkerPath(workspaceRoot) {
35
+ return makePath(normalizeRegistryPath(workspaceRoot), LEGACY_DEUK.rootDir, WORKSPACE_ID_FILE);
36
+ }
37
+ // Reads the workspace's immutable id WITHOUT creating one (pure read). Returns null
38
+ // if no marker exists yet (workspace not migrated).
39
+ // Checks new .deuk-workspace-id first, then falls back to legacy .deuk-agent/workspace-id.
40
+ export function readWorkspaceId(workspaceRoot) {
41
+ for (const markerPath of [workspaceIdMarkerPath(workspaceRoot), legacyWorkspaceIdMarkerPath(workspaceRoot)]) {
42
+ try {
43
+ const existing = String(readFileSync(markerPath, "utf8") || "").trim();
44
+ if (existing)
45
+ return existing;
46
+ }
47
+ catch { /* try next */ }
48
+ }
49
+ return null;
50
+ }
51
+ // Reads the workspace's immutable id. The id survives path moves and renames, so
52
+ // it — not the path — is the stable key for tickets.
53
+ //
54
+ // #645: minting a NEW id (and thus a marker) is gated behind opts.allowCreate.
55
+ // Only `deuk-agent-flow init` passes it. Every other entry point (ticket commands
56
+ // running in some cwd) reads an EXISTING marker or gets null — it must never mint
57
+ // a workspace just because a command ran in a directory. Auto-registration on cwd
58
+ // is exactly what spawned the ghost workspaces; the only way in is an explicit init.
59
+ export function readOrCreateWorkspaceId(workspaceRoot, opts = {}) {
60
+ // Never materialize anything under a path that doesn't exist (a stale-cookie
61
+ // JOIN can fabricate <parentWS>\<childName>).
62
+ if (!existsSync(workspaceRoot))
63
+ return null;
64
+ // readWorkspaceId checks new .deuk-workspace-id then legacy .deuk-agent/workspace-id.
65
+ const existing = readWorkspaceId(workspaceRoot);
66
+ if (existing)
67
+ return existing;
68
+ // No marker yet: this workspace was never initialized. Mint one ONLY when an
69
+ // explicit init asked for it; otherwise return null so callers skip cleanly.
70
+ if (!opts.allowCreate)
71
+ return null;
72
+ const id = randomUUID();
73
+ if (!opts.dryRun) {
74
+ writeFileSync(workspaceIdMarkerPath(workspaceRoot), id + "\n", "utf8");
75
+ }
76
+ return id;
77
+ }
78
+ // ─── ticketKey: basename 우선, 동명 충돌만 id suffix ──────────────────────────
79
+ function shortIdSuffix(id) {
80
+ return createHash("sha256").update(String(id), "utf8").digest("hex").slice(0, 8);
81
+ }
82
+ // Picks a folder name under the home tickets root. Prefers the bare basename for
83
+ // readability; only when another workspace already owns that name (different id)
84
+ // does it disambiguate with an id-derived suffix.
85
+ export function computeTicketKey(workspaceId, workspaceRoot, registry, opts = {}) {
86
+ // #632: normalizeRegistryPath returns a Windows-style path (e.g. D:\workspace\DeukPack)
87
+ // even when this code runs under a POSIX node (WSL / Git Bash), where path.basename
88
+ // does NOT treat "\\" as a separator — basename("D:\\workspace\\DeukPack") wrongly
89
+ // yields "workspaceDeukPack". That bogus key spawns ~/.deuk-agent/tickets/workspaceDeukPack/
90
+ // and, because the derived id never matches the registry, makes reconcile fire on every
91
+ // command. Split on BOTH separators so the last real path segment is taken.
92
+ const base = basenameAnyOS(normalizeRegistryPath(workspaceRoot)) || "workspace";
93
+ const owner = registry.byKey?.[base];
94
+ if (!owner || owner === workspaceId)
95
+ return base;
96
+ return `${base}-${shortIdSuffix(workspaceId)}`;
97
+ }
98
+ // ─── .gitignore 보강 ─────────────────────────────────────────────────────────
99
+ function ensureGitignored(workspaceRoot, opts = {}) {
100
+ if (opts.dryRun)
101
+ return;
102
+ // .deuk-workspace-id is committed (not ignored). Remove any stale .deuk-agent/ entry.
103
+ const giPath = makePath(workspaceRoot, ".gitignore");
104
+ if (!existsSync(giPath))
105
+ return;
106
+ const gi = readFileSync(giPath, "utf8");
107
+ const legacyLine = `${LEGACY_DEUK.rootDir}/`;
108
+ const cleaned = gi.split(/\r?\n/).filter(l => l.trim() !== legacyLine && l.trim() !== LEGACY_DEUK.rootDir).join("\n");
109
+ if (cleaned !== gi) {
110
+ writeFileSync(giPath, cleaned.replace(/\n*$/, "\n"), "utf8");
111
+ }
112
+ }
113
+ // ─── 잔재 흡수: 구 위치 tickets → 홈 ─────────────────────────────────────────
114
+ // rename fails across drives (Windows D:\ → C:\ raises EXDEV). Fall back to
115
+ // copy+unlink so workspaces on a different volume than home still migrate.
116
+ function moveFile(src, dest) {
117
+ try {
118
+ renameSync(src, dest);
119
+ }
120
+ catch (err) {
121
+ if (err && err.code === "EXDEV") {
122
+ copyFileSync(src, dest);
123
+ rmSync(src, { force: true });
124
+ }
125
+ else {
126
+ throw err;
127
+ }
128
+ }
129
+ }
130
+ function moveTreeInto(srcDir, destDir) {
131
+ mkdirSync(destDir, { recursive: true });
132
+ for (const ent of readdirSync(srcDir, { withFileTypes: true })) {
133
+ const src = makePath(srcDir, ent.name);
134
+ const dest = makePath(destDir, ent.name);
135
+ if (ent.isDirectory()) {
136
+ moveTreeInto(src, dest);
137
+ }
138
+ else {
139
+ // Don't clobber a home file that already exists (home is source of truth).
140
+ if (!existsSync(dest))
141
+ moveFile(src, dest);
142
+ else
143
+ rmSync(src, { force: true });
144
+ }
145
+ }
146
+ rmSync(srcDir, { recursive: true, force: true });
147
+ }
148
+ // #727: the workspace must end with ONLY the .deuk-workspace-id file — no .deuk or
149
+ // .deuk-agent directory may survive. The two names are handled DIFFERENTLY:
150
+ // - .deuk-agent (LEGACY_DEUK.rootDir): a legitimate former ticket location. Its
151
+ // tickets/ subtree is absorbed into the home (uuid) store first (no data loss),
152
+ // then the whole dir is removed.
153
+ // - .deuk (DEUK_ROOT_DIR): must NEVER exist in a workspace; any occurrence is a
154
+ // BUG artifact (report/knowledge/defrag wrote here by mistake). Delete it whole
155
+ // — there is no real data to preserve (언니 지시).
156
+ // `homeDir` is the only out-of-workspace write target; the workspace itself is only
157
+ // ever DELETED here (migration sync) — never written with new content.
158
+ function absorbWorkspaceResidue(workspaceRoot, homeDir, opts = {}) {
159
+ let absorbed = false;
160
+ // Legacy .deuk-agent: preserve tickets into home, then remove the dir.
161
+ const legacyDir = makePath(workspaceRoot, LEGACY_DEUK.rootDir);
162
+ try {
163
+ if (existsSync(legacyDir) && statSync(legacyDir).isDirectory()) {
164
+ absorbed = true;
165
+ if (!opts.dryRun) {
166
+ const legacyTickets = makePath(legacyDir, TICKET_SUBDIR);
167
+ try {
168
+ if (existsSync(legacyTickets) && statSync(legacyTickets).isDirectory()) {
169
+ moveTreeInto(legacyTickets, homeDir);
170
+ }
171
+ }
172
+ catch { /* tolerate; dir removed next regardless */ }
173
+ rmSync(legacyDir, { recursive: true, force: true });
174
+ }
175
+ }
176
+ }
177
+ catch { /* not a dir / inaccessible — skip */ }
178
+ // Bug-produced .deuk: delete whole, no preservation.
179
+ const bugDir = makePath(workspaceRoot, DEUK_ROOT_DIR);
180
+ try {
181
+ if (existsSync(bugDir) && statSync(bugDir).isDirectory()) {
182
+ absorbed = true;
183
+ if (!opts.dryRun)
184
+ rmSync(bugDir, { recursive: true, force: true });
185
+ }
186
+ }
187
+ catch { /* not a dir / inaccessible — skip */ }
188
+ return absorbed;
189
+ }
190
+ // The user home itself (~/.deuk-agent) is the ticket STORE, not a workspace. If a
191
+ // command runs with cwd at/above home, detect must NOT treat home as a workspace —
192
+ // reconciling it would try to absorb the home tickets into themselves (infinite
193
+ // recursion). Returns true when workspaceRoot is the home dir or an ancestor of the
194
+ // home ticket store.
195
+ export function isHomeStoreRoot(workspaceRoot, opts = {}) {
196
+ const home = normalizeRegistryPath(resolveUserHome(opts));
197
+ const root = normalizeRegistryPath(workspaceRoot);
198
+ if (root === home)
199
+ return true;
200
+ // home tickets live under <home>/.deuk-agent/tickets — guard that whole subtree.
201
+ const store = normalizeRegistryPath(makePath([resolveUserHome(opts), DEUK_ROOT_DIR], opts));
202
+ return root === store || store.startsWith(root + "/") || root.startsWith(store + "/");
203
+ }
204
+ // ─── uuid 스토어: workspace.json + wp-{name} 더미 (#638) ──────────────────────
205
+ //
206
+ // 홈 스토어 폴더명을 불변 UUID로 쓰면 사람이 폴더를 못 읽는다. 두 가지 단서를 둔다:
207
+ // - workspace.json: { uuid, path, name, aliases } — 기계가 읽는 권위 메타데이터
208
+ // - wp-{name} : 빈 더미 파일 — `ls`만 해도 사람이 워크스페이스를 식별
209
+ // 둘 다 reconcile 시 멱등하게 갱신한다(이름/경로 변경에도 폴더 rename 불필요).
210
+ const WORKSPACE_META_FILE = "workspace.json";
211
+ function readWorkspaceMeta(homeDir) {
212
+ try {
213
+ return JSON.parse(readFileSync(makePath(homeDir, WORKSPACE_META_FILE), "utf8"));
214
+ }
215
+ catch {
216
+ return null;
217
+ }
218
+ }
219
+ function writeWorkspaceStoreMarkers(homeDir, { uuid, path, name }, opts = {}) {
220
+ if (opts.dryRun)
221
+ return;
222
+ mkdirSync(homeDir, { recursive: true });
223
+ const meta = { uuid, path, name, updatedAt: new Date().toISOString() };
224
+ writeFileSync(makePath(homeDir, WORKSPACE_META_FILE), JSON.stringify(meta, null, 2) + "\n", "utf8");
225
+ // Refresh the human-readable wp-{name} dummy: remove stale wp-* then write the
226
+ // current one, so a rename leaves exactly one correct label.
227
+ for (const ent of readdirSync(homeDir, { withFileTypes: true })) {
228
+ if (ent.isFile() && ent.name.startsWith("wp-") && ent.name !== `wp-${name}`) {
229
+ rmSync(makePath(homeDir, ent.name), { force: true });
230
+ }
231
+ }
232
+ if (name)
233
+ writeFileSync(makePath(homeDir, `wp-${name}`), "", "utf8");
234
+ }
235
+ // One-time, idempotent relocation of a legacy name-keyed folder to the uuid folder.
236
+ // If the uuid folder already exists, migration is already done → no-op. Otherwise,
237
+ // if the legacy {ticketKey}/ folder exists, move its whole tree under {uuid}/.
238
+ function migrateLegacyKeyFolderToUuid(uuid, ticketKey, opts = {}) {
239
+ const uuidDir = resolveHomeTicketDir(uuid, opts);
240
+ if (existsSync(uuidDir))
241
+ return uuidDir; // already on uuid layout
242
+ const legacyDir = resolveHomeTicketDir(ticketKey, opts);
243
+ if (ticketKey && ticketKey !== uuid && existsSync(legacyDir) && !opts.dryRun) {
244
+ moveTreeInto(legacyDir, uuidDir); // {ticketKey}/* → {uuid}/*
245
+ }
246
+ return uuidDir;
247
+ }
248
+ // ─── reconcile: 매 명령 진입 훅 ──────────────────────────────────────────────
249
+ //
250
+ // 마커 → 레지스트리 → 보정 → 잔재 흡수. 홈 티켓 디렉토리 절대경로를 반환한다.
251
+ export function reconcileWorkspace(workspaceRoot, opts = {}) {
252
+ // Never treat the home ticket store as a workspace (would recurse / pollute the
253
+ // registry with a "home" entry). Callers should guard too, but enforce here.
254
+ if (isHomeStoreRoot(workspaceRoot, opts)) {
255
+ return {
256
+ id: null, ticketKey: null,
257
+ homeDir: homeTicketRoot(opts),
258
+ pathChanged: false, absorbed: false, skipped: true,
259
+ };
260
+ }
261
+ const id = readOrCreateWorkspaceId(workspaceRoot, opts);
262
+ // #645: readOrCreateWorkspaceId returns null when workspaceRoot does not exist
263
+ // (a fabricated ghost path). Bail out before touching the registry so we never
264
+ // register a phantom workspace under a non-existent path.
265
+ if (id == null) {
266
+ return {
267
+ id: null, ticketKey: null,
268
+ homeDir: homeTicketRoot(opts),
269
+ pathChanged: false, absorbed: false, skipped: true,
270
+ };
271
+ }
272
+ const normPath = normalizeRegistryPath(workspaceRoot);
273
+ // #645: registry.json is retired. The SSOT is the uuid folder's workspace.json.
274
+ // Prefer the name already recorded there; otherwise derive it from the path.
275
+ // computeTicketKey is called with an empty registry — the folder is uuid-keyed,
276
+ // so there is no name collision to disambiguate; it just yields the basename.
277
+ const uuidDir = resolveHomeTicketDir(id, opts);
278
+ const priorMeta = readWorkspaceMeta(uuidDir);
279
+ const name = priorMeta?.name
280
+ || computeTicketKey(id, workspaceRoot, { workspaces: {}, byKey: {} }, opts);
281
+ // Idempotent: move a legacy {name}/ folder onto {uuid}/ exactly once. After this
282
+ // the uuid folder exists and subsequent runs short-circuit inside the helper.
283
+ const homeDir = migrateLegacyKeyFolderToUuid(id, name, opts);
284
+ // self-heal: path moved/renamed since workspace.json was last written.
285
+ const pathChanged = !priorMeta || priorMeta.path !== normPath;
286
+ // Write the in-folder clues (workspace.json + wp-{name}) so the uuid folder is
287
+ // self-describing — this IS the registration record (single source of truth).
288
+ writeWorkspaceStoreMarkers(homeDir, { uuid: id, path: normPath, name }, opts);
289
+ // Absorb any in-workspace residue (.deuk / .deuk-agent) into the (uuid) home dir
290
+ // and delete the residue dirs, so the workspace keeps only .deuk-workspace-id.
291
+ const absorbed = absorbWorkspaceResidue(workspaceRoot, homeDir, opts);
292
+ if (absorbed)
293
+ ensureGitignored(workspaceRoot, opts);
294
+ if (!opts.dryRun)
295
+ mkdirSync(homeDir, { recursive: true });
296
+ return { id, ticketKey: name, uuid: id, homeDir, pathChanged, absorbed };
297
+ }
298
+ // PURE READ resolver used by detectConsumerTicketDir (#623). Resolves the home
299
+ // ticket dir for a workspace using only existing state — never creates a marker,
300
+ // moves files, or writes anything. #645: registry.json is retired; the uuid
301
+ // folder's workspace.json is the only record. Resolution order:
302
+ // 1. existing marker id → {uuid}/ folder (the migrated, authoritative location)
303
+ // 2. existing marker id but uuid folder absent → legacy {name}/ folder if present
304
+ // 3. no marker yet (not migrated) → basename (matches what reconcile will pick)
305
+ export function resolveHomeTicketDirForWorkspace(workspaceRoot, opts = {}) {
306
+ const id = readWorkspaceId(workspaceRoot);
307
+ if (id) {
308
+ // #638: uuid-keyed layout. If the {uuid}/ folder exists (migrated), that IS the
309
+ // home dir. Otherwise resolve the legacy {name}/ folder so reads keep working
310
+ // until reconcile relocates it — this read NEVER creates or moves anything.
311
+ const uuidDir = resolveHomeTicketDir(id, opts);
312
+ if (existsSync(uuidDir))
313
+ return uuidDir;
314
+ const name = readWorkspaceMeta(uuidDir)?.name
315
+ || computeTicketKey(id, workspaceRoot, { workspaces: {}, byKey: {} }, opts);
316
+ const legacyDir = resolveHomeTicketDir(name, opts);
317
+ return existsSync(legacyDir) ? legacyDir : uuidDir;
318
+ }
319
+ // Not migrated yet (no marker): mirror what reconcile will pick. Pure read.
320
+ // #632: basenameAnyOS — a POSIX runtime would turn D:\workspace\DeukPack into
321
+ // "workspaceDeukPack" with path.basename.
322
+ const name = basenameAnyOS(normalizeRegistryPath(workspaceRoot)) || "workspace";
323
+ return resolveHomeTicketDir(name, opts);
324
+ }
325
+ // Idempotent migration entry point (#623). Called once on ticket-command entry and
326
+ // on init — NOT from detect. Skips quickly when already migrated (marker present,
327
+ // registry current, no residue). Returns the reconcile result (or a skip marker).
328
+ export function ensureWorkspaceMigrated(workspaceRoot, opts = {}) {
329
+ if (!workspaceRoot)
330
+ return { skipped: true };
331
+ if (isHomeStoreRoot(workspaceRoot, opts))
332
+ return { skipped: true };
333
+ return reconcileWorkspace(workspaceRoot, opts);
334
+ }
335
+ // ─── ghost 워크스페이스 청소 (#638) ──────────────────────────────────────────
336
+ //
337
+ // 이름 기반 ticketKey 폴더는 동명 워크스페이스 충돌 시 {name}-{idSuffix} 폴더를
338
+ // 양산했고(computeTicketKey), 그 중 다수가 .md 0개인 빈 껍데기로 남았다. 이들은
339
+ // 손으로 rm 하지 않고(메모리 무결성 게이트) 이 함수로 안전하게 제거한다.
340
+ //
341
+ // ghost 판정(보수적, 2조건 모두 충족):
342
+ // 1. 폴더명이 computeTicketKey의 동명 충돌 suffix 패턴 {name}-{8hex} 이고
343
+ // 2. .md 파일이 하나도 없음
344
+ // 즉 "동명 충돌로 생긴 빈 중복 폴더"만 ghost로 본다. suffix 없는 빈 폴더는 티켓이
345
+ // 없을 뿐인 실재 워크스페이스이므로(사용자 지시: 빈 거라도 존재하면 유지) 건드리지
346
+ // 않는다. 데이터가 한 줄이라도 있으면 당연히 제외.
347
+ const GHOST_SUFFIX_RE = /-[0-9a-f]{8}$/;
348
+ // #645: a path is a nested ghost when it lives strictly UNDER another workspace's
349
+ // path (parent + separator + child). The real workspaces are never prefixes of one
350
+ // another, so any path that is a child of another's path was fabricated by a
351
+ // stale-cookie JOIN / cwd auto-registration — never a real workspace.
352
+ function isNestedUnderAnotherWorkspace(targetPath, allPaths) {
353
+ const target = normalizeRegistryPath(String(targetPath || "")).replace(/[\\/]+$/, "");
354
+ if (!target)
355
+ return false;
356
+ for (const other of allPaths) {
357
+ const parent = normalizeRegistryPath(String(other || "")).replace(/[\\/]+$/, "");
358
+ if (!parent || parent === target)
359
+ continue;
360
+ // case-insensitive: Windows paths. target must start with parent + a separator.
361
+ const t = target.toLowerCase();
362
+ const p = parent.toLowerCase();
363
+ if (t.startsWith(p + "\\") || t.startsWith(p + "/"))
364
+ return true;
365
+ }
366
+ return false;
367
+ }
368
+ // #645: SSOT is each uuid folder's workspace.json — registry.json is retired. A
369
+ // folder is a ghost when it carries NO ticket data (.md) AND its workspace.json
370
+ // path is not a real, top-level workspace. The classification is two-pass because
371
+ // "nested under another workspace" needs the full set of legitimate paths first.
372
+ function listGhostTicketFolders(opts = {}) {
373
+ const root = homeTicketRoot(opts);
374
+ if (!existsSync(root))
375
+ return [];
376
+ // Pass 1: read every folder's workspace.json + data-bearing flag.
377
+ const entries = [];
378
+ for (const ent of readdirSync(root, { withFileTypes: true })) {
379
+ if (!ent.isDirectory())
380
+ continue;
381
+ const dir = makePath(root, ent.name);
382
+ const hasMarkdown = collectTicketMarkdownFiles(dir).length > 0;
383
+ const meta = readWorkspaceMeta(dir);
384
+ const path = meta?.path ? normalizeRegistryPath(String(meta.path)) : "";
385
+ entries.push({ key: ent.name, dir, hasMarkdown, path });
386
+ }
387
+ // The set of paths that look like genuine top-level workspaces: they exist on
388
+ // disk with a .deuk-agent marker, are not under the home store, and are not a
389
+ // direct child of the home dir. These anchor the nested-ghost predicate.
390
+ const legitPaths = entries
391
+ .map(e => e.path)
392
+ .filter(p => p && hasWorkspaceMarker(p) && !isHomeDirectChild(p, opts));
393
+ const ghosts = [];
394
+ for (const e of entries) {
395
+ if (e.hasMarkdown)
396
+ continue; // data-bearing — never a ghost
397
+ // (a) legacy: collision-suffix folder ({name}-{8hex}) with no workspace.json
398
+ // and no .md — a pre-#638 leftover.
399
+ const suffixGhost = GHOST_SUFFIX_RE.test(e.key) && !e.path;
400
+ // (b) #645: a folder describing a path that is NOT a real workspace.
401
+ let pathGhost = false;
402
+ if (e.path) {
403
+ const absent = !hasWorkspaceMarker(e.path);
404
+ const homeChild = isHomeDirectChild(e.path, opts);
405
+ const nested = isNestedUnderAnotherWorkspace(e.path, legitPaths);
406
+ pathGhost = absent || homeChild || nested;
407
+ }
408
+ if (suffixGhost || pathGhost)
409
+ ghosts.push({ key: e.key, dir: e.dir });
410
+ }
411
+ return ghosts;
412
+ }
413
+ // Remove empty ghost workspace folders from the home store. Dry-run by default;
414
+ // pass { apply: true } to delete. Returns a summary. Data-bearing folders (any
415
+ // .md) are never touched. #645: registry.json is no longer consulted or written —
416
+ // the uuid folder's workspace.json IS the registration record.
417
+ export function pruneGhostWorkspaces(opts = {}) {
418
+ const apply = Boolean(opts.apply);
419
+ const ghosts = listGhostTicketFolders(opts);
420
+ const removed = [];
421
+ for (const { key, dir } of ghosts) {
422
+ if (apply)
423
+ rmSync(dir, { recursive: true, force: true });
424
+ removed.push(key);
425
+ }
426
+ return { ghosts: ghosts.map(g => g.key), removed, apply };
427
+ }
428
+ // Register with cli-utils so detectConsumerTicketDir can route to the home dir
429
+ // without a static circular import.
430
+ registerTicketHomeModule({
431
+ reconcileWorkspace,
432
+ ensureWorkspaceMigrated,
433
+ resolveHomeTicketDirForWorkspace,
434
+ readOrCreateWorkspaceId,
435
+ readWorkspaceId,
436
+ computeTicketKey,
437
+ resolveHomeTicketDir,
438
+ isHomeStoreRoot,
439
+ });
440
+ //# sourceMappingURL=cli-ticket-home.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-ticket-home.js","sourceRoot":"","sources":["../../cli-ticket-home.ts"],"names":[],"mappings":"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"}