qfai 1.0.3 → 1.0.5

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 (99) hide show
  1. package/README.md +53 -74
  2. package/assets/init/.qfai/README.md +17 -82
  3. package/assets/init/.qfai/assistant/README.md +9 -0
  4. package/assets/init/.qfai/assistant/agents/README.md +34 -0
  5. package/assets/init/.qfai/assistant/agents/architect.md +73 -0
  6. package/assets/init/.qfai/assistant/agents/backend-engineer.md +73 -0
  7. package/assets/init/.qfai/assistant/agents/code-reviewer.md +73 -0
  8. package/assets/init/.qfai/assistant/agents/contract-designer.md +73 -0
  9. package/assets/init/.qfai/assistant/agents/devops-ci-engineer.md +73 -0
  10. package/assets/init/.qfai/assistant/agents/facilitator.md +74 -0
  11. package/assets/init/.qfai/assistant/agents/frontend-engineer.md +73 -0
  12. package/assets/init/.qfai/assistant/agents/interviewer.md +72 -0
  13. package/assets/init/.qfai/assistant/agents/planner.md +73 -0
  14. package/assets/init/.qfai/assistant/agents/qa-engineer.md +73 -0
  15. package/assets/init/.qfai/assistant/agents/requirements-analyst.md +73 -0
  16. package/assets/init/.qfai/assistant/agents/test-engineer.md +73 -0
  17. package/assets/init/.qfai/assistant/instructions/README.md +6 -0
  18. package/assets/init/.qfai/assistant/instructions/constitution.md +131 -0
  19. package/assets/init/.qfai/assistant/instructions/workflow.md +75 -0
  20. package/assets/init/.qfai/assistant/prompts/README.md +19 -0
  21. package/assets/init/.qfai/assistant/prompts/qfai-discuss.md +173 -0
  22. package/assets/init/.qfai/assistant/prompts/qfai-implement.md +239 -0
  23. package/assets/init/.qfai/assistant/prompts/qfai-pr.md +218 -0
  24. package/assets/init/.qfai/assistant/prompts/qfai-require.md +273 -0
  25. package/assets/init/.qfai/assistant/prompts/qfai-scenario-test.md +229 -0
  26. package/assets/init/.qfai/assistant/prompts/qfai-spec.md +287 -0
  27. package/assets/init/.qfai/assistant/prompts/qfai-unit-test.md +202 -0
  28. package/assets/init/.qfai/assistant/prompts/qfai-verify.md +231 -0
  29. package/assets/init/.qfai/assistant/prompts.local/README.md +6 -0
  30. package/assets/init/.qfai/assistant/steering/README.md +33 -0
  31. package/assets/init/.qfai/assistant/steering/product.md +32 -0
  32. package/assets/init/.qfai/assistant/steering/structure.md +34 -0
  33. package/assets/init/.qfai/assistant/steering/tech.md +37 -0
  34. package/assets/init/.qfai/contracts/README.md +7 -87
  35. package/assets/init/.qfai/contracts/api/README.md +8 -0
  36. package/assets/init/.qfai/contracts/db/README.md +8 -0
  37. package/assets/init/.qfai/contracts/ui/README.md +8 -0
  38. package/assets/init/.qfai/report/README.md +13 -0
  39. package/assets/init/.qfai/require/README.md +4 -26
  40. package/assets/init/.qfai/require/require.md +74 -0
  41. package/assets/init/.qfai/specs/README.md +6 -57
  42. package/assets/init/root/.github/workflows/qfai.yml +1 -1
  43. package/assets/init/root/qfai.config.yaml +3 -4
  44. package/dist/cli/index.cjs +313 -472
  45. package/dist/cli/index.cjs.map +1 -1
  46. package/dist/cli/index.mjs +295 -454
  47. package/dist/cli/index.mjs.map +1 -1
  48. package/dist/index.cjs +37 -63
  49. package/dist/index.cjs.map +1 -1
  50. package/dist/index.d.cts +0 -1
  51. package/dist/index.d.ts +0 -1
  52. package/dist/index.mjs +37 -63
  53. package/dist/index.mjs.map +1 -1
  54. package/package.json +1 -1
  55. package/assets/init/.qfai/contracts/api/api-0001-sample.yaml +0 -15
  56. package/assets/init/.qfai/contracts/db/db-0001-sample.sql +0 -7
  57. package/assets/init/.qfai/contracts/ui/assets/thema-001-facebook-like/assets.yaml +0 -6
  58. package/assets/init/.qfai/contracts/ui/assets/thema-001-facebook-like/palette.png +0 -0
  59. package/assets/init/.qfai/contracts/ui/assets/ui-0001-sample/assets.yaml +0 -6
  60. package/assets/init/.qfai/contracts/ui/assets/ui-0001-sample/snapshots/login__desktop__light__default.png +0 -0
  61. package/assets/init/.qfai/contracts/ui/thema-001-facebook-like.yml +0 -13
  62. package/assets/init/.qfai/contracts/ui/ui-0001-sample.yaml +0 -17
  63. package/assets/init/.qfai/out/README.md +0 -17
  64. package/assets/init/.qfai/promptpack/commands/implement.md +0 -8
  65. package/assets/init/.qfai/promptpack/commands/plan.md +0 -11
  66. package/assets/init/.qfai/promptpack/commands/release.md +0 -6
  67. package/assets/init/.qfai/promptpack/commands/review.md +0 -7
  68. package/assets/init/.qfai/promptpack/constitution.md +0 -15
  69. package/assets/init/.qfai/promptpack/modes/change.md +0 -5
  70. package/assets/init/.qfai/promptpack/modes/compatibility.md +0 -6
  71. package/assets/init/.qfai/promptpack/roles/qa.md +0 -4
  72. package/assets/init/.qfai/promptpack/roles/spec.md +0 -4
  73. package/assets/init/.qfai/promptpack/roles/test.md +0 -4
  74. package/assets/init/.qfai/promptpack/steering/compatibility-vs-change.md +0 -42
  75. package/assets/init/.qfai/promptpack/steering/naming.md +0 -7
  76. package/assets/init/.qfai/promptpack/steering/traceability.md +0 -25
  77. package/assets/init/.qfai/prompts/README.md +0 -70
  78. package/assets/init/.qfai/prompts/analyze/README.md +0 -21
  79. package/assets/init/.qfai/prompts/analyze/scenario_test_consistency.md +0 -8
  80. package/assets/init/.qfai/prompts/analyze/scenario_to_test.md +0 -56
  81. package/assets/init/.qfai/prompts/analyze/spec_contract_consistency.md +0 -8
  82. package/assets/init/.qfai/prompts/analyze/spec_scenario_consistency.md +0 -8
  83. package/assets/init/.qfai/prompts/analyze/spec_to_contract.md +0 -54
  84. package/assets/init/.qfai/prompts/analyze/spec_to_scenario.md +0 -56
  85. package/assets/init/.qfai/prompts/makeBusinessFlow.md +0 -34
  86. package/assets/init/.qfai/prompts/makeOverview.md +0 -27
  87. package/assets/init/.qfai/prompts/qfai-classify-change.md +0 -33
  88. package/assets/init/.qfai/prompts/qfai-generate-test-globs.md +0 -29
  89. package/assets/init/.qfai/prompts/qfai-maintain-contracts.md +0 -35
  90. package/assets/init/.qfai/prompts/qfai-maintain-traceability.md +0 -36
  91. package/assets/init/.qfai/prompts/require-to-spec.md +0 -41
  92. package/assets/init/.qfai/prompts.local/README.md +0 -31
  93. package/assets/init/.qfai/rules/conventions.md +0 -27
  94. package/assets/init/.qfai/rules/pnpm.md +0 -29
  95. package/assets/init/.qfai/samples/analyze/analysis.md +0 -38
  96. package/assets/init/.qfai/samples/analyze/input_bundle.md +0 -54
  97. package/assets/init/.qfai/specs/spec-0001/delta.md +0 -30
  98. package/assets/init/.qfai/specs/spec-0001/scenario.feature +0 -11
  99. package/assets/init/.qfai/specs/spec-0001/spec.md +0 -40
@@ -23,231 +23,24 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
  mod
24
24
  ));
25
25
 
26
- // src/cli/commands/analyze.ts
27
- var import_promises2 = require("fs/promises");
28
- var import_node_path2 = __toESM(require("path"), 1);
29
-
30
- // src/core/fs.ts
31
- var import_promises = require("fs/promises");
32
- var import_node_path = __toESM(require("path"), 1);
33
- var import_fast_glob = __toESM(require("fast-glob"), 1);
34
- var DEFAULT_IGNORE_DIRS = /* @__PURE__ */ new Set([
35
- "node_modules",
36
- ".git",
37
- "dist",
38
- ".pnpm",
39
- "tmp",
40
- ".mcp-tools"
41
- ]);
42
- var DEFAULT_GLOB_FILE_LIMIT = 2e4;
43
- async function collectFiles(root, options = {}) {
44
- const entries = [];
45
- if (!await exists(root)) {
46
- return entries;
47
- }
48
- const ignoreDirs = /* @__PURE__ */ new Set([
49
- ...DEFAULT_IGNORE_DIRS,
50
- ...options.ignoreDirs ?? []
51
- ]);
52
- const extensions = options.extensions?.map((ext) => ext.toLowerCase()) ?? [];
53
- await walk(root, root, ignoreDirs, extensions, entries);
54
- return entries;
55
- }
56
- async function collectFilesByGlobs(root, options) {
57
- const limit = normalizeLimit(options.limit);
58
- if (options.globs.length === 0) {
59
- return { files: [], truncated: false, matchedFileCount: 0, limit };
60
- }
61
- const stream = import_fast_glob.default.stream(options.globs, {
62
- cwd: root,
63
- ignore: options.ignore ?? [],
64
- onlyFiles: true,
65
- absolute: true,
66
- unique: true
67
- });
68
- const files = [];
69
- let truncated = false;
70
- for await (const entry of stream) {
71
- if (files.length >= limit) {
72
- truncated = true;
73
- destroyStream(stream);
74
- break;
75
- }
76
- files.push(String(entry));
77
- }
78
- const matchedFileCount = files.length;
79
- return { files, truncated, matchedFileCount, limit };
80
- }
81
- async function walk(base, current, ignoreDirs, extensions, out) {
82
- const items = await (0, import_promises.readdir)(current, { withFileTypes: true });
83
- for (const item of items) {
84
- const fullPath = import_node_path.default.join(current, item.name);
85
- if (item.isDirectory()) {
86
- if (ignoreDirs.has(item.name)) {
87
- continue;
88
- }
89
- await walk(base, fullPath, ignoreDirs, extensions, out);
90
- continue;
91
- }
92
- if (item.isFile()) {
93
- if (extensions.length > 0) {
94
- const ext = import_node_path.default.extname(item.name).toLowerCase();
95
- if (!extensions.includes(ext)) {
96
- continue;
97
- }
98
- }
99
- out.push(fullPath);
100
- }
101
- }
102
- }
103
- async function exists(target) {
104
- try {
105
- await (0, import_promises.access)(target);
106
- return true;
107
- } catch {
108
- return false;
109
- }
110
- }
111
- function normalizeLimit(value) {
112
- if (typeof value !== "number" || Number.isNaN(value)) {
113
- return DEFAULT_GLOB_FILE_LIMIT;
114
- }
115
- const flooredValue = Math.floor(value);
116
- if (flooredValue <= 0) {
117
- return DEFAULT_GLOB_FILE_LIMIT;
118
- }
119
- return flooredValue;
120
- }
121
- function destroyStream(stream) {
122
- if (!stream || typeof stream !== "object") {
123
- return;
124
- }
125
- const record2 = stream;
126
- if (typeof record2.destroy === "function") {
127
- record2.destroy();
128
- }
129
- }
130
-
131
- // src/cli/commands/analyze.ts
132
- async function runAnalyze(options) {
133
- const root = import_node_path2.default.resolve(options.root);
134
- const localDir = import_node_path2.default.join(root, ".qfai", "prompts.local", "analyze");
135
- const standardDir = import_node_path2.default.join(root, ".qfai", "prompts", "analyze");
136
- const available = await listPromptNames([localDir, standardDir]);
137
- const promptName = normalizePromptName(options.prompt);
138
- if (!promptName || options.list) {
139
- emitList(available);
140
- return 0;
141
- }
142
- const resolved = await resolvePromptPath(promptName, [localDir, standardDir]);
143
- if (!resolved) {
144
- emitPromptNotFound(promptName, available);
145
- return 1;
146
- }
147
- const content = await (0, import_promises2.readFile)(resolved, "utf-8");
148
- process.stdout.write(content);
149
- if (!content.endsWith("\n")) {
150
- process.stdout.write("\n");
151
- }
152
- return 0;
153
- }
154
- function normalizePromptName(value) {
155
- const trimmed = (value ?? "").trim();
156
- if (!trimmed) {
157
- return null;
158
- }
159
- return trimmed.endsWith(".md") ? trimmed.slice(0, -3) : trimmed;
160
- }
161
- async function listPromptNames(dirs) {
162
- const byName = /* @__PURE__ */ new Map();
163
- for (const dir of dirs) {
164
- const files = await collectFiles(dir, { extensions: [".md"] });
165
- for (const abs of files) {
166
- const base = import_node_path2.default.basename(abs);
167
- if (base.toLowerCase() === "readme.md") {
168
- continue;
169
- }
170
- const name = base.slice(0, -3);
171
- if (byName.has(name)) {
172
- continue;
173
- }
174
- if (await isDeprecatedPrompt(abs)) {
175
- continue;
176
- }
177
- byName.set(name, abs);
178
- }
179
- }
180
- return [...byName.keys()].sort((a, b) => a.localeCompare(b));
181
- }
182
- function emitList(names) {
183
- process.stdout.write("# qfai analyze: prompts\n\n");
184
- if (names.length === 0) {
185
- process.stdout.write(
186
- "\u5229\u7528\u53EF\u80FD\u306A\u30D7\u30ED\u30F3\u30D7\u30C8\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3002\u307E\u305A `qfai init` \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002\n"
187
- );
188
- return;
189
- }
190
- process.stdout.write("\u5229\u7528\u53EF\u80FD\u306A\u30D7\u30ED\u30F3\u30D7\u30C8\u4E00\u89A7:\n\n");
191
- for (const name of names) {
192
- process.stdout.write(`- ${name}
193
- `);
194
- }
195
- }
196
- async function resolvePromptPath(promptName, dirs) {
197
- const filename = `${promptName}.md`;
198
- for (const dir of dirs) {
199
- const full = import_node_path2.default.join(dir, filename);
200
- try {
201
- await (0, import_promises2.readFile)(full, "utf-8");
202
- return full;
203
- } catch {
204
- }
205
- }
206
- return null;
207
- }
208
- async function isDeprecatedPrompt(filePath) {
209
- try {
210
- const content = await (0, import_promises2.readFile)(filePath, "utf-8");
211
- const firstLine = firstLineOf(content);
212
- return firstLine.trim() === "# Deprecated";
213
- } catch {
214
- return false;
215
- }
216
- }
217
- function firstLineOf(content) {
218
- return content.match(/^[^\r\n]*/)?.[0] ?? "";
219
- }
220
- function emitPromptNotFound(promptName, candidates) {
221
- process.stderr.write(`qfai analyze: prompt not found: ${promptName}
222
- `);
223
- if (candidates.length > 0) {
224
- process.stderr.write("candidates:\n");
225
- for (const c of candidates) {
226
- process.stderr.write(`- ${c}
227
- `);
228
- }
229
- }
230
- }
231
-
232
26
  // src/cli/commands/doctor.ts
233
- var import_promises10 = require("fs/promises");
234
- var import_node_path12 = __toESM(require("path"), 1);
235
-
236
- // src/core/doctor.ts
237
27
  var import_promises9 = require("fs/promises");
238
28
  var import_node_path11 = __toESM(require("path"), 1);
239
29
 
30
+ // src/core/doctor.ts
31
+ var import_promises8 = require("fs/promises");
32
+ var import_node_path10 = __toESM(require("path"), 1);
33
+
240
34
  // src/core/config.ts
241
- var import_promises3 = require("fs/promises");
242
- var import_node_path3 = __toESM(require("path"), 1);
35
+ var import_promises = require("fs/promises");
36
+ var import_node_path = __toESM(require("path"), 1);
243
37
  var import_yaml = require("yaml");
244
38
  var defaultConfig = {
245
39
  paths: {
246
40
  contractsDir: ".qfai/contracts",
247
41
  specsDir: ".qfai/specs",
248
- rulesDir: ".qfai/rules",
249
- outDir: ".qfai/out",
250
- promptsDir: ".qfai/prompts",
42
+ outDir: ".qfai/report",
43
+ promptsDir: ".qfai/assistant/prompts",
251
44
  srcDir: "src",
252
45
  testsDir: "tests"
253
46
  },
@@ -275,21 +68,21 @@ var defaultConfig = {
275
68
  }
276
69
  },
277
70
  output: {
278
- validateJsonPath: ".qfai/out/validate.json"
71
+ validateJsonPath: ".qfai/report/validate.json"
279
72
  }
280
73
  };
281
74
  function getConfigPath(root) {
282
- return import_node_path3.default.join(root, "qfai.config.yaml");
75
+ return import_node_path.default.join(root, "qfai.config.yaml");
283
76
  }
284
77
  async function findConfigRoot(startDir) {
285
- const resolvedStart = import_node_path3.default.resolve(startDir);
78
+ const resolvedStart = import_node_path.default.resolve(startDir);
286
79
  let current = resolvedStart;
287
80
  while (true) {
288
81
  const configPath = getConfigPath(current);
289
- if (await exists2(configPath)) {
82
+ if (await exists(configPath)) {
290
83
  return { root: current, configPath, found: true };
291
84
  }
292
- const parent = import_node_path3.default.dirname(current);
85
+ const parent = import_node_path.default.dirname(current);
293
86
  if (parent === current) {
294
87
  break;
295
88
  }
@@ -306,7 +99,7 @@ async function loadConfig(root) {
306
99
  const issues = [];
307
100
  let parsed;
308
101
  try {
309
- const raw = await (0, import_promises3.readFile)(configPath, "utf-8");
102
+ const raw = await (0, import_promises.readFile)(configPath, "utf-8");
310
103
  parsed = (0, import_yaml.parse)(raw);
311
104
  } catch (error2) {
312
105
  if (isMissingFile(error2)) {
@@ -319,7 +112,7 @@ async function loadConfig(root) {
319
112
  return { config: normalized, issues, configPath };
320
113
  }
321
114
  function resolvePath(root, config, key) {
322
- return import_node_path3.default.resolve(root, config.paths[key]);
115
+ return import_node_path.default.resolve(root, config.paths[key]);
323
116
  }
324
117
  function normalizeConfig(raw, configPath, issues) {
325
118
  if (!isRecord(raw)) {
@@ -358,13 +151,6 @@ function normalizePaths(raw, configPath, issues) {
358
151
  configPath,
359
152
  issues
360
153
  ),
361
- rulesDir: readString(
362
- raw.rulesDir,
363
- base.rulesDir,
364
- "paths.rulesDir",
365
- configPath,
366
- issues
367
- ),
368
154
  outDir: readString(
369
155
  raw.outDir,
370
156
  base.outDir,
@@ -619,9 +405,9 @@ function isMissingFile(error2) {
619
405
  }
620
406
  return false;
621
407
  }
622
- async function exists2(target) {
408
+ async function exists(target) {
623
409
  try {
624
- await (0, import_promises3.access)(target);
410
+ await (0, import_promises.access)(target);
625
411
  return true;
626
412
  } catch {
627
413
  return false;
@@ -638,27 +424,128 @@ function isRecord(value) {
638
424
  }
639
425
 
640
426
  // src/core/discovery.ts
641
- var import_promises5 = require("fs/promises");
642
- var import_node_path5 = __toESM(require("path"), 1);
643
-
644
- // src/core/specLayout.ts
645
427
  var import_promises4 = require("fs/promises");
646
428
  var import_node_path4 = __toESM(require("path"), 1);
429
+
430
+ // src/core/fs.ts
431
+ var import_promises2 = require("fs/promises");
432
+ var import_node_path2 = __toESM(require("path"), 1);
433
+ var import_fast_glob = __toESM(require("fast-glob"), 1);
434
+ var DEFAULT_IGNORE_DIRS = /* @__PURE__ */ new Set([
435
+ "node_modules",
436
+ ".git",
437
+ "dist",
438
+ ".pnpm",
439
+ "tmp",
440
+ ".mcp-tools"
441
+ ]);
442
+ var DEFAULT_GLOB_FILE_LIMIT = 2e4;
443
+ async function collectFiles(root, options = {}) {
444
+ const entries = [];
445
+ if (!await exists2(root)) {
446
+ return entries;
447
+ }
448
+ const ignoreDirs = /* @__PURE__ */ new Set([
449
+ ...DEFAULT_IGNORE_DIRS,
450
+ ...options.ignoreDirs ?? []
451
+ ]);
452
+ const extensions = options.extensions?.map((ext) => ext.toLowerCase()) ?? [];
453
+ await walk(root, root, ignoreDirs, extensions, entries);
454
+ return entries;
455
+ }
456
+ async function collectFilesByGlobs(root, options) {
457
+ const limit = normalizeLimit(options.limit);
458
+ if (options.globs.length === 0) {
459
+ return { files: [], truncated: false, matchedFileCount: 0, limit };
460
+ }
461
+ const stream = import_fast_glob.default.stream(options.globs, {
462
+ cwd: root,
463
+ ignore: options.ignore ?? [],
464
+ onlyFiles: true,
465
+ absolute: true,
466
+ unique: true
467
+ });
468
+ const files = [];
469
+ let truncated = false;
470
+ for await (const entry of stream) {
471
+ if (files.length >= limit) {
472
+ truncated = true;
473
+ destroyStream(stream);
474
+ break;
475
+ }
476
+ files.push(String(entry));
477
+ }
478
+ const matchedFileCount = files.length;
479
+ return { files, truncated, matchedFileCount, limit };
480
+ }
481
+ async function walk(base, current, ignoreDirs, extensions, out) {
482
+ const items = await (0, import_promises2.readdir)(current, { withFileTypes: true });
483
+ for (const item of items) {
484
+ const fullPath = import_node_path2.default.join(current, item.name);
485
+ if (item.isDirectory()) {
486
+ if (ignoreDirs.has(item.name)) {
487
+ continue;
488
+ }
489
+ await walk(base, fullPath, ignoreDirs, extensions, out);
490
+ continue;
491
+ }
492
+ if (item.isFile()) {
493
+ if (extensions.length > 0) {
494
+ const ext = import_node_path2.default.extname(item.name).toLowerCase();
495
+ if (!extensions.includes(ext)) {
496
+ continue;
497
+ }
498
+ }
499
+ out.push(fullPath);
500
+ }
501
+ }
502
+ }
503
+ async function exists2(target) {
504
+ try {
505
+ await (0, import_promises2.access)(target);
506
+ return true;
507
+ } catch {
508
+ return false;
509
+ }
510
+ }
511
+ function normalizeLimit(value) {
512
+ if (typeof value !== "number" || Number.isNaN(value)) {
513
+ return DEFAULT_GLOB_FILE_LIMIT;
514
+ }
515
+ const flooredValue = Math.floor(value);
516
+ if (flooredValue <= 0) {
517
+ return DEFAULT_GLOB_FILE_LIMIT;
518
+ }
519
+ return flooredValue;
520
+ }
521
+ function destroyStream(stream) {
522
+ if (!stream || typeof stream !== "object") {
523
+ return;
524
+ }
525
+ const record2 = stream;
526
+ if (typeof record2.destroy === "function") {
527
+ record2.destroy();
528
+ }
529
+ }
530
+
531
+ // src/core/specLayout.ts
532
+ var import_promises3 = require("fs/promises");
533
+ var import_node_path3 = __toESM(require("path"), 1);
647
534
  var SPEC_DIR_RE = /^spec-\d{4}$/;
648
535
  async function collectSpecEntries(specsRoot) {
649
536
  const dirs = await listSpecDirs(specsRoot);
650
537
  const entries = dirs.map((dir) => ({
651
538
  dir,
652
- specPath: import_node_path4.default.join(dir, "spec.md"),
653
- deltaPath: import_node_path4.default.join(dir, "delta.md"),
654
- scenarioPath: import_node_path4.default.join(dir, "scenario.feature")
539
+ specPath: import_node_path3.default.join(dir, "spec.md"),
540
+ deltaPath: import_node_path3.default.join(dir, "delta.md"),
541
+ scenarioPath: import_node_path3.default.join(dir, "scenario.feature")
655
542
  }));
656
543
  return entries.sort((a, b) => a.dir.localeCompare(b.dir));
657
544
  }
658
545
  async function listSpecDirs(specsRoot) {
659
546
  try {
660
- const items = await (0, import_promises4.readdir)(specsRoot, { withFileTypes: true });
661
- return items.filter((item) => item.isDirectory()).map((item) => item.name).filter((name) => SPEC_DIR_RE.test(name.toLowerCase())).map((name) => import_node_path4.default.join(specsRoot, name));
547
+ const items = await (0, import_promises3.readdir)(specsRoot, { withFileTypes: true });
548
+ return items.filter((item) => item.isDirectory()).map((item) => item.name).filter((name) => SPEC_DIR_RE.test(name.toLowerCase())).map((name) => import_node_path3.default.join(specsRoot, name));
662
549
  } catch (error2) {
663
550
  if (isMissingFileError(error2)) {
664
551
  return [];
@@ -720,7 +607,7 @@ async function filterExisting(files) {
720
607
  }
721
608
  async function exists3(target) {
722
609
  try {
723
- await (0, import_promises5.access)(target);
610
+ await (0, import_promises4.access)(target);
724
611
  return true;
725
612
  } catch {
726
613
  return false;
@@ -729,20 +616,20 @@ async function exists3(target) {
729
616
  function filterByBasenamePrefix(files, prefix) {
730
617
  const lowerPrefix = prefix.toLowerCase();
731
618
  return files.filter(
732
- (file) => import_node_path5.default.basename(file).toLowerCase().startsWith(lowerPrefix)
619
+ (file) => import_node_path4.default.basename(file).toLowerCase().startsWith(lowerPrefix)
733
620
  );
734
621
  }
735
622
 
736
623
  // src/core/paths.ts
737
- var import_node_path6 = __toESM(require("path"), 1);
624
+ var import_node_path5 = __toESM(require("path"), 1);
738
625
  function toRelativePath(root, target) {
739
626
  if (!target) {
740
627
  return target;
741
628
  }
742
- if (!import_node_path6.default.isAbsolute(target)) {
629
+ if (!import_node_path5.default.isAbsolute(target)) {
743
630
  return toPosixPath(target);
744
631
  }
745
- const relative = import_node_path6.default.relative(root, target);
632
+ const relative = import_node_path5.default.relative(root, target);
746
633
  if (!relative) {
747
634
  return ".";
748
635
  }
@@ -753,8 +640,8 @@ function toPosixPath(value) {
753
640
  }
754
641
 
755
642
  // src/core/traceability.ts
756
- var import_promises6 = require("fs/promises");
757
- var import_node_path7 = __toESM(require("path"), 1);
643
+ var import_promises5 = require("fs/promises");
644
+ var import_node_path6 = __toESM(require("path"), 1);
758
645
 
759
646
  // src/core/gherkin/parse.ts
760
647
  var import_gherkin = require("@cucumber/gherkin");
@@ -906,7 +793,7 @@ function extractAnnotatedScIds(text) {
906
793
  async function collectScIdsFromScenarioFiles(scenarioFiles) {
907
794
  const scIds = /* @__PURE__ */ new Set();
908
795
  for (const file of scenarioFiles) {
909
- const text = await (0, import_promises6.readFile)(file, "utf-8");
796
+ const text = await (0, import_promises5.readFile)(file, "utf-8");
910
797
  const { document, errors } = parseScenarioDocument(text, file);
911
798
  if (!document || errors.length > 0) {
912
799
  continue;
@@ -924,7 +811,7 @@ async function collectScIdsFromScenarioFiles(scenarioFiles) {
924
811
  async function collectScIdSourcesFromScenarioFiles(scenarioFiles) {
925
812
  const sources = /* @__PURE__ */ new Map();
926
813
  for (const file of scenarioFiles) {
927
- const text = await (0, import_promises6.readFile)(file, "utf-8");
814
+ const text = await (0, import_promises5.readFile)(file, "utf-8");
928
815
  const { document, errors } = parseScenarioDocument(text, file);
929
816
  if (!document || errors.length > 0) {
930
817
  continue;
@@ -982,10 +869,10 @@ async function collectScTestReferences(root, globs, excludeGlobs) {
982
869
  };
983
870
  }
984
871
  const normalizedFiles = Array.from(
985
- new Set(scanResult.files.map((file) => import_node_path7.default.normalize(file)))
872
+ new Set(scanResult.files.map((file) => import_node_path6.default.normalize(file)))
986
873
  );
987
874
  for (const file of normalizedFiles) {
988
- const text = await (0, import_promises6.readFile)(file, "utf-8");
875
+ const text = await (0, import_promises5.readFile)(file, "utf-8");
989
876
  const scIds = extractAnnotatedScIds(text);
990
877
  if (scIds.length === 0) {
991
878
  continue;
@@ -1044,20 +931,20 @@ function formatError3(error2) {
1044
931
  }
1045
932
 
1046
933
  // src/core/promptsIntegrity.ts
1047
- var import_promises7 = require("fs/promises");
1048
- var import_node_path9 = __toESM(require("path"), 1);
934
+ var import_promises6 = require("fs/promises");
935
+ var import_node_path8 = __toESM(require("path"), 1);
1049
936
 
1050
937
  // src/shared/assets.ts
1051
938
  var import_node_fs = require("fs");
1052
- var import_node_path8 = __toESM(require("path"), 1);
939
+ var import_node_path7 = __toESM(require("path"), 1);
1053
940
  var import_node_url = require("url");
1054
941
  function getInitAssetsDir() {
1055
942
  const base = __filename;
1056
943
  const basePath = base.startsWith("file:") ? (0, import_node_url.fileURLToPath)(base) : base;
1057
- const baseDir = import_node_path8.default.dirname(basePath);
944
+ const baseDir = import_node_path7.default.dirname(basePath);
1058
945
  const candidates = [
1059
- import_node_path8.default.resolve(baseDir, "../../../assets/init"),
1060
- import_node_path8.default.resolve(baseDir, "../../assets/init")
946
+ import_node_path7.default.resolve(baseDir, "../../../assets/init"),
947
+ import_node_path7.default.resolve(baseDir, "../../assets/init")
1061
948
  ];
1062
949
  for (const candidate of candidates) {
1063
950
  if ((0, import_node_fs.existsSync)(candidate)) {
@@ -1074,11 +961,25 @@ function getInitAssetsDir() {
1074
961
  }
1075
962
 
1076
963
  // src/core/promptsIntegrity.ts
1077
- async function diffProjectPromptsAgainstInitAssets(root) {
1078
- const promptsDir = import_node_path9.default.resolve(root, ".qfai", "prompts");
964
+ var LEGACY_OK_EXTRA = /* @__PURE__ */ new Set(["qfai-classify-change.md"]);
965
+ async function diffProjectPromptsAgainstInitAssets(root, config) {
966
+ const promptsDirConfig = config.paths.promptsDir;
967
+ const promptsDir = import_node_path8.default.isAbsolute(promptsDirConfig) ? promptsDirConfig : import_node_path8.default.resolve(root, promptsDirConfig);
1079
968
  let templateDir;
1080
969
  try {
1081
- templateDir = import_node_path9.default.join(getInitAssetsDir(), ".qfai", "prompts");
970
+ const rel = import_node_path8.default.isAbsolute(promptsDirConfig) ? import_node_path8.default.relative(root, promptsDirConfig) : promptsDirConfig;
971
+ const normalized = rel.replace(/^[\\/]+/, "");
972
+ if (normalized.length === 0 || normalized.startsWith("..")) {
973
+ return {
974
+ status: "skipped_missing_assets",
975
+ promptsDir,
976
+ templateDir: "",
977
+ missing: [],
978
+ extra: [],
979
+ changed: []
980
+ };
981
+ }
982
+ templateDir = import_node_path8.default.join(getInitAssetsDir(), normalized);
1082
983
  } catch {
1083
984
  return {
1084
985
  status: "skipped_missing_assets",
@@ -1122,6 +1023,7 @@ async function diffProjectPromptsAgainstInitAssets(root) {
1122
1023
  extra.push(rel);
1123
1024
  }
1124
1025
  }
1026
+ const filteredExtra = extra.filter((rel) => !LEGACY_OK_EXTRA.has(rel));
1125
1027
  const common = intersectKeys(templateByRel, projectByRel);
1126
1028
  for (const rel of common) {
1127
1029
  const templateAbs = templateByRel.get(rel);
@@ -1131,8 +1033,8 @@ async function diffProjectPromptsAgainstInitAssets(root) {
1131
1033
  }
1132
1034
  try {
1133
1035
  const [a, b] = await Promise.all([
1134
- (0, import_promises7.readFile)(templateAbs, "utf-8"),
1135
- (0, import_promises7.readFile)(projectAbs, "utf-8")
1036
+ (0, import_promises6.readFile)(templateAbs, "utf-8"),
1037
+ (0, import_promises6.readFile)(projectAbs, "utf-8")
1136
1038
  ]);
1137
1039
  if (normalizeNewlines(a) !== normalizeNewlines(b)) {
1138
1040
  changed.push(rel);
@@ -1141,13 +1043,13 @@ async function diffProjectPromptsAgainstInitAssets(root) {
1141
1043
  changed.push(rel);
1142
1044
  }
1143
1045
  }
1144
- const status = missing.length > 0 || extra.length > 0 || changed.length > 0 ? "modified" : "ok";
1046
+ const status = missing.length > 0 || filteredExtra.length > 0 || changed.length > 0 ? "modified" : "ok";
1145
1047
  return {
1146
1048
  status,
1147
1049
  promptsDir,
1148
1050
  templateDir,
1149
1051
  missing: missing.sort(),
1150
- extra: extra.sort(),
1052
+ extra: filteredExtra.sort(),
1151
1053
  changed: changed.sort()
1152
1054
  };
1153
1055
  }
@@ -1155,7 +1057,7 @@ function normalizeNewlines(text) {
1155
1057
  return text.replace(/\r\n/g, "\n");
1156
1058
  }
1157
1059
  function toRel(base, abs) {
1158
- const rel = import_node_path9.default.relative(base, abs);
1060
+ const rel = import_node_path8.default.relative(base, abs);
1159
1061
  return rel.replace(/[\\/]+/g, "/");
1160
1062
  }
1161
1063
  function intersectKeys(a, b) {
@@ -1169,16 +1071,16 @@ function intersectKeys(a, b) {
1169
1071
  }
1170
1072
 
1171
1073
  // src/core/version.ts
1172
- var import_promises8 = require("fs/promises");
1173
- var import_node_path10 = __toESM(require("path"), 1);
1074
+ var import_promises7 = require("fs/promises");
1075
+ var import_node_path9 = __toESM(require("path"), 1);
1174
1076
  var import_node_url2 = require("url");
1175
1077
  async function resolveToolVersion() {
1176
- if ("1.0.3".length > 0) {
1177
- return "1.0.3";
1078
+ if ("1.0.5".length > 0) {
1079
+ return "1.0.5";
1178
1080
  }
1179
1081
  try {
1180
1082
  const packagePath = resolvePackageJsonPath();
1181
- const raw = await (0, import_promises8.readFile)(packagePath, "utf-8");
1083
+ const raw = await (0, import_promises7.readFile)(packagePath, "utf-8");
1182
1084
  const parsed = JSON.parse(raw);
1183
1085
  const version = typeof parsed.version === "string" ? parsed.version : "";
1184
1086
  return version.length > 0 ? version : "unknown";
@@ -1189,13 +1091,13 @@ async function resolveToolVersion() {
1189
1091
  function resolvePackageJsonPath() {
1190
1092
  const base = __filename;
1191
1093
  const basePath = base.startsWith("file:") ? (0, import_node_url2.fileURLToPath)(base) : base;
1192
- return import_node_path10.default.resolve(import_node_path10.default.dirname(basePath), "../../package.json");
1094
+ return import_node_path9.default.resolve(import_node_path9.default.dirname(basePath), "../../package.json");
1193
1095
  }
1194
1096
 
1195
1097
  // src/core/doctor.ts
1196
1098
  async function exists4(target) {
1197
1099
  try {
1198
- await (0, import_promises9.access)(target);
1100
+ await (0, import_promises8.access)(target);
1199
1101
  return true;
1200
1102
  } catch {
1201
1103
  return false;
@@ -1215,7 +1117,7 @@ function normalizeGlobs2(values) {
1215
1117
  return values.map((glob) => glob.trim()).filter((glob) => glob.length > 0);
1216
1118
  }
1217
1119
  async function createDoctorData(options) {
1218
- const startDir = import_node_path11.default.resolve(options.startDir);
1120
+ const startDir = import_node_path10.default.resolve(options.startDir);
1219
1121
  const checks = [];
1220
1122
  const configPath = getConfigPath(startDir);
1221
1123
  const search = options.rootExplicit ? {
@@ -1264,7 +1166,6 @@ async function createDoctorData(options) {
1264
1166
  "outDir",
1265
1167
  "srcDir",
1266
1168
  "testsDir",
1267
- "rulesDir",
1268
1169
  "promptsDir"
1269
1170
  ];
1270
1171
  for (const key of pathKeys) {
@@ -1278,9 +1179,9 @@ async function createDoctorData(options) {
1278
1179
  details: { path: toRelativePath(root, resolved) }
1279
1180
  });
1280
1181
  if (key === "promptsDir") {
1281
- const promptsLocalDir = import_node_path11.default.join(
1282
- import_node_path11.default.dirname(resolved),
1283
- `${import_node_path11.default.basename(resolved)}.local`
1182
+ const promptsLocalDir = import_node_path10.default.join(
1183
+ import_node_path10.default.dirname(resolved),
1184
+ `${import_node_path10.default.basename(resolved)}.local`
1284
1185
  );
1285
1186
  const found = await exists4(promptsLocalDir);
1286
1187
  addCheck(checks, {
@@ -1290,12 +1191,12 @@ async function createDoctorData(options) {
1290
1191
  message: found ? "prompts.local exists (overlay can be used)" : "prompts.local is optional (create it to override prompts)",
1291
1192
  details: { path: toRelativePath(root, promptsLocalDir) }
1292
1193
  });
1293
- const diff = await diffProjectPromptsAgainstInitAssets(root);
1194
+ const diff = await diffProjectPromptsAgainstInitAssets(root, config);
1294
1195
  if (diff.status === "skipped_missing_prompts") {
1295
1196
  addCheck(checks, {
1296
1197
  id: "prompts.integrity",
1297
1198
  severity: "info",
1298
- title: "Prompts integrity (.qfai/prompts)",
1199
+ title: "Prompts integrity (.qfai/assistant/prompts)",
1299
1200
  message: "prompts \u304C\u672A\u4F5C\u6210\u306E\u305F\u3081\u691C\u67FB\u3092\u30B9\u30AD\u30C3\u30D7\u3057\u307E\u3057\u305F\uFF08'qfai init' \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\uFF09",
1300
1201
  details: { promptsDir: toRelativePath(root, diff.promptsDir) }
1301
1202
  });
@@ -1303,7 +1204,7 @@ async function createDoctorData(options) {
1303
1204
  addCheck(checks, {
1304
1205
  id: "prompts.integrity",
1305
1206
  severity: "info",
1306
- title: "Prompts integrity (.qfai/prompts)",
1207
+ title: "Prompts integrity (.qfai/assistant/prompts)",
1307
1208
  message: "init assets \u304C\u898B\u3064\u304B\u3089\u306A\u3044\u305F\u3081\u691C\u67FB\u3092\u30B9\u30AD\u30C3\u30D7\u3057\u307E\u3057\u305F\uFF08\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u72B6\u614B\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\uFF09",
1308
1209
  details: { promptsDir: toRelativePath(root, diff.promptsDir) }
1309
1210
  });
@@ -1311,7 +1212,7 @@ async function createDoctorData(options) {
1311
1212
  addCheck(checks, {
1312
1213
  id: "prompts.integrity",
1313
1214
  severity: "ok",
1314
- title: "Prompts integrity (.qfai/prompts)",
1215
+ title: "Prompts integrity (.qfai/assistant/prompts)",
1315
1216
  message: "\u6A19\u6E96 assets \u3068\u4E00\u81F4\u3057\u3066\u3044\u307E\u3059",
1316
1217
  details: { promptsDir: toRelativePath(root, diff.promptsDir) }
1317
1218
  });
@@ -1319,15 +1220,15 @@ async function createDoctorData(options) {
1319
1220
  addCheck(checks, {
1320
1221
  id: "prompts.integrity",
1321
1222
  severity: "error",
1322
- title: "Prompts integrity (.qfai/prompts)",
1323
- message: "\u6A19\u6E96\u8CC7\u7523 '.qfai/prompts/**' \u304C\u6539\u5909\u3055\u308C\u3066\u3044\u307E\u3059\u3002prompts \u306E\u76F4\u7DE8\u96C6\u306F\u975E\u63A8\u5968\u3067\u3059\uFF08\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8/\u518D init \u3067\u4E0A\u66F8\u304D\u3055\u308C\u5F97\u307E\u3059\uFF09\u3002",
1223
+ title: "Prompts integrity (.qfai/assistant/prompts)",
1224
+ message: "\u6A19\u6E96\u8CC7\u7523 '.qfai/assistant/prompts/**' \u304C\u6539\u5909\u3055\u308C\u3066\u3044\u307E\u3059\u3002prompts \u306E\u76F4\u7DE8\u96C6\u306F\u975E\u63A8\u5968\u3067\u3059\uFF08\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8/\u518D init \u3067\u4E0A\u66F8\u304D\u3055\u308C\u5F97\u307E\u3059\uFF09\u3002",
1324
1225
  details: {
1325
1226
  promptsDir: toRelativePath(root, diff.promptsDir),
1326
1227
  missing: diff.missing,
1327
1228
  extra: diff.extra,
1328
1229
  changed: diff.changed,
1329
1230
  nextActions: [
1330
- "\u5909\u66F4\u5185\u5BB9\u3092 .qfai/prompts.local/** \u306B\u79FB\u3059\uFF08\u540C\u4E00\u76F8\u5BFE\u30D1\u30B9\u3067\u914D\u7F6E\uFF09",
1231
+ "\u5909\u66F4\u5185\u5BB9\u3092 .qfai/assistant/prompts.local/** \u306B\u79FB\u3059\uFF08\u540C\u4E00\u76F8\u5BFE\u30D1\u30B9\u3067\u914D\u7F6E\uFF09",
1331
1232
  "\u5FC5\u8981\u306A\u3089 qfai init --force \u3067 prompts \u3092\u6A19\u6E96\u72B6\u614B\u3078\u623B\u3059\uFF08prompts.local \u306F\u4FDD\u8B77\u3055\u308C\u307E\u3059\uFF09"
1332
1233
  ]
1333
1234
  }
@@ -1353,7 +1254,7 @@ async function createDoctorData(options) {
1353
1254
  message: missingFiles === 0 ? `All spec packs have required files (count=${entries.length})` : `Missing required files in spec packs (missingFiles=${missingFiles})`,
1354
1255
  details: { specPacks: entries.length, missingFiles }
1355
1256
  });
1356
- const validateJsonAbs = import_node_path11.default.isAbsolute(config.output.validateJsonPath) ? config.output.validateJsonPath : import_node_path11.default.resolve(root, config.output.validateJsonPath);
1257
+ const validateJsonAbs = import_node_path10.default.isAbsolute(config.output.validateJsonPath) ? config.output.validateJsonPath : import_node_path10.default.resolve(root, config.output.validateJsonPath);
1357
1258
  const validateJsonExists = await exists4(validateJsonAbs);
1358
1259
  addCheck(checks, {
1359
1260
  id: "output.validateJson",
@@ -1363,8 +1264,8 @@ async function createDoctorData(options) {
1363
1264
  details: { path: toRelativePath(root, validateJsonAbs) }
1364
1265
  });
1365
1266
  const outDirAbs = resolvePath(root, config, "outDir");
1366
- const rel = import_node_path11.default.relative(outDirAbs, validateJsonAbs);
1367
- const inside = rel !== "" && !rel.startsWith("..") && !import_node_path11.default.isAbsolute(rel);
1267
+ const rel = import_node_path10.default.relative(outDirAbs, validateJsonAbs);
1268
+ const inside = rel !== "" && !rel.startsWith("..") && !import_node_path10.default.isAbsolute(rel);
1368
1269
  addCheck(checks, {
1369
1270
  id: "output.pathAlignment",
1370
1271
  severity: inside ? "ok" : "warning",
@@ -1487,12 +1388,12 @@ async function detectOutDirCollisions(root) {
1487
1388
  });
1488
1389
  const configPaths = configScan.files;
1489
1390
  const configRoots = Array.from(
1490
- new Set(configPaths.map((configPath) => import_node_path11.default.dirname(configPath)))
1391
+ new Set(configPaths.map((configPath) => import_node_path10.default.dirname(configPath)))
1491
1392
  ).sort((a, b) => a.localeCompare(b));
1492
1393
  const outDirToRoots = /* @__PURE__ */ new Map();
1493
1394
  for (const configRoot of configRoots) {
1494
1395
  const { config } = await loadConfig(configRoot);
1495
- const outDir = import_node_path11.default.normalize(resolvePath(configRoot, config, "outDir"));
1396
+ const outDir = import_node_path10.default.normalize(resolvePath(configRoot, config, "outDir"));
1496
1397
  const roots = outDirToRoots.get(outDir) ?? /* @__PURE__ */ new Set();
1497
1398
  roots.add(configRoot);
1498
1399
  outDirToRoots.set(outDir, roots);
@@ -1518,20 +1419,20 @@ async function detectOutDirCollisions(root) {
1518
1419
  };
1519
1420
  }
1520
1421
  async function findMonorepoRoot(startDir) {
1521
- let current = import_node_path11.default.resolve(startDir);
1422
+ let current = import_node_path10.default.resolve(startDir);
1522
1423
  while (true) {
1523
- const gitPath = import_node_path11.default.join(current, ".git");
1524
- const workspacePath = import_node_path11.default.join(current, "pnpm-workspace.yaml");
1424
+ const gitPath = import_node_path10.default.join(current, ".git");
1425
+ const workspacePath = import_node_path10.default.join(current, "pnpm-workspace.yaml");
1525
1426
  if (await exists4(gitPath) || await exists4(workspacePath)) {
1526
1427
  return current;
1527
1428
  }
1528
- const parent = import_node_path11.default.dirname(current);
1429
+ const parent = import_node_path10.default.dirname(current);
1529
1430
  if (parent === current) {
1530
1431
  break;
1531
1432
  }
1532
1433
  current = parent;
1533
1434
  }
1534
- return import_node_path11.default.resolve(startDir);
1435
+ return import_node_path10.default.resolve(startDir);
1535
1436
  }
1536
1437
 
1537
1438
  // src/cli/lib/logger.ts
@@ -1573,9 +1474,9 @@ async function runDoctor(options) {
1573
1474
  const output = options.format === "json" ? formatDoctorJson(data) : formatDoctorText(data);
1574
1475
  const exitCode = shouldFailDoctor(data.summary, options.failOn) ? 1 : 0;
1575
1476
  if (options.outPath) {
1576
- const outAbs = import_node_path12.default.isAbsolute(options.outPath) ? options.outPath : import_node_path12.default.resolve(process.cwd(), options.outPath);
1577
- await (0, import_promises10.mkdir)(import_node_path12.default.dirname(outAbs), { recursive: true });
1578
- await (0, import_promises10.writeFile)(outAbs, `${output}
1477
+ const outAbs = import_node_path11.default.isAbsolute(options.outPath) ? options.outPath : import_node_path11.default.resolve(process.cwd(), options.outPath);
1478
+ await (0, import_promises9.mkdir)(import_node_path11.default.dirname(outAbs), { recursive: true });
1479
+ await (0, import_promises9.writeFile)(outAbs, `${output}
1579
1480
  `, "utf-8");
1580
1481
  info(`doctor: wrote ${outAbs}`);
1581
1482
  return exitCode;
@@ -1594,11 +1495,11 @@ function shouldFailDoctor(summary, failOn) {
1594
1495
  }
1595
1496
 
1596
1497
  // src/cli/commands/init.ts
1597
- var import_node_path14 = __toESM(require("path"), 1);
1498
+ var import_node_path13 = __toESM(require("path"), 1);
1598
1499
 
1599
1500
  // src/cli/lib/fs.ts
1600
- var import_promises11 = require("fs/promises");
1601
- var import_node_path13 = __toESM(require("path"), 1);
1501
+ var import_promises10 = require("fs/promises");
1502
+ var import_node_path12 = __toESM(require("path"), 1);
1602
1503
  async function copyTemplateTree(sourceRoot, destRoot, options) {
1603
1504
  const files = await collectTemplateFiles(sourceRoot);
1604
1505
  return copyFiles(files, sourceRoot, destRoot, options);
@@ -1606,7 +1507,7 @@ async function copyTemplateTree(sourceRoot, destRoot, options) {
1606
1507
  async function copyTemplatePaths(sourceRoot, destRoot, relativePaths, options) {
1607
1508
  const allFiles = [];
1608
1509
  for (const relPath of relativePaths) {
1609
- const fullPath = import_node_path13.default.join(sourceRoot, relPath);
1510
+ const fullPath = import_node_path12.default.join(sourceRoot, relPath);
1610
1511
  const files = await collectTemplateFiles(fullPath);
1611
1512
  allFiles.push(...files);
1612
1513
  }
@@ -1616,13 +1517,13 @@ async function copyFiles(files, sourceRoot, destRoot, options) {
1616
1517
  const copied = [];
1617
1518
  const skipped = [];
1618
1519
  const conflicts = [];
1619
- const protectPrefixes = (options.protect ?? []).map((p) => p.replace(/^[\\/]+/, "").replace(/[\\/]+$/, "")).filter((p) => p.length > 0).map((p) => p + import_node_path13.default.sep);
1620
- const excludePrefixes = (options.exclude ?? []).map((p) => p.replace(/^[\\/]+/, "").replace(/[\\/]+$/, "")).filter((p) => p.length > 0).map((p) => p + import_node_path13.default.sep);
1520
+ const protectPrefixes = (options.protect ?? []).map((p) => p.replace(/^[\\/]+/, "").replace(/[\\/]+$/, "")).filter((p) => p.length > 0).map((p) => p + import_node_path12.default.sep);
1521
+ const excludePrefixes = (options.exclude ?? []).map((p) => p.replace(/^[\\/]+/, "").replace(/[\\/]+$/, "")).filter((p) => p.length > 0).map((p) => p + import_node_path12.default.sep);
1621
1522
  const isProtectedRelative = (relative) => {
1622
1523
  if (protectPrefixes.length === 0) {
1623
1524
  return false;
1624
1525
  }
1625
- const normalized = relative.replace(/[\\/]+/g, import_node_path13.default.sep);
1526
+ const normalized = relative.replace(/[\\/]+/g, import_node_path12.default.sep);
1626
1527
  return protectPrefixes.some(
1627
1528
  (prefix) => normalized === prefix.slice(0, -1) || normalized.startsWith(prefix)
1628
1529
  );
@@ -1631,7 +1532,7 @@ async function copyFiles(files, sourceRoot, destRoot, options) {
1631
1532
  if (excludePrefixes.length === 0) {
1632
1533
  return false;
1633
1534
  }
1634
- const normalized = relative.replace(/[\\/]+/g, import_node_path13.default.sep);
1535
+ const normalized = relative.replace(/[\\/]+/g, import_node_path12.default.sep);
1635
1536
  return excludePrefixes.some(
1636
1537
  (prefix) => normalized === prefix.slice(0, -1) || normalized.startsWith(prefix)
1637
1538
  );
@@ -1639,14 +1540,14 @@ async function copyFiles(files, sourceRoot, destRoot, options) {
1639
1540
  const conflictPolicy = options.conflictPolicy ?? "error";
1640
1541
  if (!options.force && conflictPolicy === "error") {
1641
1542
  for (const file of files) {
1642
- const relative = import_node_path13.default.relative(sourceRoot, file);
1543
+ const relative = import_node_path12.default.relative(sourceRoot, file);
1643
1544
  if (isExcludedRelative(relative)) {
1644
1545
  continue;
1645
1546
  }
1646
1547
  if (isProtectedRelative(relative)) {
1647
1548
  continue;
1648
1549
  }
1649
- const dest = import_node_path13.default.join(destRoot, relative);
1550
+ const dest = import_node_path12.default.join(destRoot, relative);
1650
1551
  if (!await shouldWrite(dest, options.force)) {
1651
1552
  conflicts.push(dest);
1652
1553
  }
@@ -1656,19 +1557,19 @@ async function copyFiles(files, sourceRoot, destRoot, options) {
1656
1557
  }
1657
1558
  }
1658
1559
  for (const file of files) {
1659
- const relative = import_node_path13.default.relative(sourceRoot, file);
1560
+ const relative = import_node_path12.default.relative(sourceRoot, file);
1660
1561
  if (isExcludedRelative(relative)) {
1661
1562
  continue;
1662
1563
  }
1663
- const dest = import_node_path13.default.join(destRoot, relative);
1564
+ const dest = import_node_path12.default.join(destRoot, relative);
1664
1565
  const forceForThisFile = isProtectedRelative(relative) ? false : options.force;
1665
1566
  if (!await shouldWrite(dest, forceForThisFile)) {
1666
1567
  skipped.push(dest);
1667
1568
  continue;
1668
1569
  }
1669
1570
  if (!options.dryRun) {
1670
- await (0, import_promises11.mkdir)(import_node_path13.default.dirname(dest), { recursive: true });
1671
- await (0, import_promises11.copyFile)(file, dest);
1571
+ await (0, import_promises10.mkdir)(import_node_path12.default.dirname(dest), { recursive: true });
1572
+ await (0, import_promises10.copyFile)(file, dest);
1672
1573
  }
1673
1574
  copied.push(dest);
1674
1575
  }
@@ -1689,9 +1590,9 @@ async function collectTemplateFiles(root) {
1689
1590
  if (!await exists5(root)) {
1690
1591
  return entries;
1691
1592
  }
1692
- const items = await (0, import_promises11.readdir)(root, { withFileTypes: true });
1593
+ const items = await (0, import_promises10.readdir)(root, { withFileTypes: true });
1693
1594
  for (const item of items) {
1694
- const fullPath = import_node_path13.default.join(root, item.name);
1595
+ const fullPath = import_node_path12.default.join(root, item.name);
1695
1596
  if (item.isDirectory()) {
1696
1597
  const nested = await collectTemplateFiles(fullPath);
1697
1598
  entries.push(...nested);
@@ -1711,7 +1612,7 @@ async function shouldWrite(target, force) {
1711
1612
  }
1712
1613
  async function exists5(target) {
1713
1614
  try {
1714
- await (0, import_promises11.access)(target);
1615
+ await (0, import_promises10.access)(target);
1715
1616
  return true;
1716
1617
  } catch {
1717
1618
  return false;
@@ -1721,13 +1622,13 @@ async function exists5(target) {
1721
1622
  // src/cli/commands/init.ts
1722
1623
  async function runInit(options) {
1723
1624
  const assetsRoot = getInitAssetsDir();
1724
- const rootAssets = import_node_path14.default.join(assetsRoot, "root");
1725
- const qfaiAssets = import_node_path14.default.join(assetsRoot, ".qfai");
1726
- const destRoot = import_node_path14.default.resolve(options.dir);
1727
- const destQfai = import_node_path14.default.join(destRoot, ".qfai");
1625
+ const rootAssets = import_node_path13.default.join(assetsRoot, "root");
1626
+ const qfaiAssets = import_node_path13.default.join(assetsRoot, ".qfai");
1627
+ const destRoot = import_node_path13.default.resolve(options.dir);
1628
+ const destQfai = import_node_path13.default.join(destRoot, ".qfai");
1728
1629
  if (options.force) {
1729
1630
  info(
1730
- "NOTE: --force \u306F .qfai/prompts/** \u306E\u307F\u4E0A\u66F8\u304D\u3057\u307E\u3059\uFF08prompts.local \u306F\u4FDD\u8B77\u3055\u308C\u3001specs/contracts \u7B49\u306F\u4E0A\u66F8\u304D\u3057\u307E\u305B\u3093\uFF09\u3002"
1631
+ "NOTE: --force \u306F .qfai/assistant/prompts/** \u306E\u307F\u4E0A\u66F8\u304D\u3057\u307E\u3059\uFF08prompts.local \u306F\u4FDD\u8B77\u3055\u308C\u3001specs/contracts \u7B49\u306F\u4E0A\u66F8\u304D\u3057\u307E\u305B\u3093\uFF09\u3002"
1731
1632
  );
1732
1633
  }
1733
1634
  const rootResult = await copyTemplateTree(rootAssets, destRoot, {
@@ -1739,18 +1640,18 @@ async function runInit(options) {
1739
1640
  force: false,
1740
1641
  dryRun: options.dryRun,
1741
1642
  conflictPolicy: "skip",
1742
- protect: ["prompts.local"],
1743
- exclude: ["prompts"]
1643
+ protect: ["assistant/prompts.local"],
1644
+ exclude: ["assistant/prompts"]
1744
1645
  });
1745
1646
  const promptsResult = await copyTemplatePaths(
1746
1647
  qfaiAssets,
1747
1648
  destQfai,
1748
- ["prompts"],
1649
+ ["assistant/prompts"],
1749
1650
  {
1750
1651
  force: options.force,
1751
1652
  dryRun: options.dryRun,
1752
1653
  conflictPolicy: "skip",
1753
- protect: ["prompts.local"]
1654
+ protect: ["assistant/prompts.local"]
1754
1655
  }
1755
1656
  );
1756
1657
  report(
@@ -1771,8 +1672,8 @@ function report(copied, skipped, dryRun, label) {
1771
1672
  }
1772
1673
 
1773
1674
  // src/cli/commands/report.ts
1774
- var import_promises20 = require("fs/promises");
1775
- var import_node_path22 = __toESM(require("path"), 1);
1675
+ var import_promises19 = require("fs/promises");
1676
+ var import_node_path21 = __toESM(require("path"), 1);
1776
1677
 
1777
1678
  // src/core/normalize.ts
1778
1679
  function normalizeIssuePaths(root, issues) {
@@ -1812,12 +1713,12 @@ function normalizeValidationResult(root, result) {
1812
1713
  }
1813
1714
 
1814
1715
  // src/core/report.ts
1815
- var import_promises19 = require("fs/promises");
1816
- var import_node_path21 = __toESM(require("path"), 1);
1716
+ var import_promises18 = require("fs/promises");
1717
+ var import_node_path20 = __toESM(require("path"), 1);
1817
1718
 
1818
1719
  // src/core/contractIndex.ts
1819
- var import_promises12 = require("fs/promises");
1820
- var import_node_path15 = __toESM(require("path"), 1);
1720
+ var import_promises11 = require("fs/promises");
1721
+ var import_node_path14 = __toESM(require("path"), 1);
1821
1722
 
1822
1723
  // src/core/contractsDecl.ts
1823
1724
  var CONTRACT_DECLARATION_RE = /^\s*(?:#|\/\/|--|\/\*+|\*+)?\s*QFAI-CONTRACT-ID:\s*((?:API|UI|DB)-\d{4}|THEMA-\d{3})\s*(?:\*\/)?\s*$/gm;
@@ -1839,9 +1740,9 @@ function stripContractDeclarationLines(text) {
1839
1740
  // src/core/contractIndex.ts
1840
1741
  async function buildContractIndex(root, config) {
1841
1742
  const contractsRoot = resolvePath(root, config, "contractsDir");
1842
- const uiRoot = import_node_path15.default.join(contractsRoot, "ui");
1843
- const apiRoot = import_node_path15.default.join(contractsRoot, "api");
1844
- const dbRoot = import_node_path15.default.join(contractsRoot, "db");
1743
+ const uiRoot = import_node_path14.default.join(contractsRoot, "ui");
1744
+ const apiRoot = import_node_path14.default.join(contractsRoot, "api");
1745
+ const dbRoot = import_node_path14.default.join(contractsRoot, "db");
1845
1746
  const [uiFiles, themaFiles, apiFiles, dbFiles] = await Promise.all([
1846
1747
  collectUiContractFiles(uiRoot),
1847
1748
  collectThemaContractFiles(uiRoot),
@@ -1861,7 +1762,7 @@ async function buildContractIndex(root, config) {
1861
1762
  }
1862
1763
  async function indexContractFiles(files, index) {
1863
1764
  for (const file of files) {
1864
- const text = await (0, import_promises12.readFile)(file, "utf-8");
1765
+ const text = await (0, import_promises11.readFile)(file, "utf-8");
1865
1766
  extractDeclaredContractIds(text).forEach((id) => record(index, id, file));
1866
1767
  }
1867
1768
  }
@@ -2106,14 +2007,14 @@ function parseSpec(md, file) {
2106
2007
  }
2107
2008
 
2108
2009
  // src/core/validators/contracts.ts
2109
- var import_promises13 = require("fs/promises");
2110
- var import_node_path17 = __toESM(require("path"), 1);
2010
+ var import_promises12 = require("fs/promises");
2011
+ var import_node_path16 = __toESM(require("path"), 1);
2111
2012
 
2112
2013
  // src/core/contracts.ts
2113
- var import_node_path16 = __toESM(require("path"), 1);
2014
+ var import_node_path15 = __toESM(require("path"), 1);
2114
2015
  var import_yaml2 = require("yaml");
2115
2016
  function parseStructuredContract(file, text) {
2116
- const ext = import_node_path16.default.extname(file).toLowerCase();
2017
+ const ext = import_node_path15.default.extname(file).toLowerCase();
2117
2018
  if (ext === ".json") {
2118
2019
  return JSON.parse(text);
2119
2020
  }
@@ -2135,14 +2036,14 @@ async function validateContracts(root, config) {
2135
2036
  const issues = [];
2136
2037
  const contractIndex = await buildContractIndex(root, config);
2137
2038
  const contractsRoot = resolvePath(root, config, "contractsDir");
2138
- const uiRoot = import_node_path17.default.join(contractsRoot, "ui");
2039
+ const uiRoot = import_node_path16.default.join(contractsRoot, "ui");
2139
2040
  const themaIds = new Set(
2140
2041
  Array.from(contractIndex.ids).filter((id) => id.startsWith("THEMA-"))
2141
2042
  );
2142
2043
  issues.push(...await validateUiContracts(uiRoot, themaIds));
2143
2044
  issues.push(...await validateThemaContracts(uiRoot));
2144
- issues.push(...await validateApiContracts(import_node_path17.default.join(contractsRoot, "api")));
2145
- issues.push(...await validateDbContracts(import_node_path17.default.join(contractsRoot, "db")));
2045
+ issues.push(...await validateApiContracts(import_node_path16.default.join(contractsRoot, "api")));
2046
+ issues.push(...await validateDbContracts(import_node_path16.default.join(contractsRoot, "db")));
2146
2047
  issues.push(...validateDuplicateContractIds(contractIndex));
2147
2048
  return issues;
2148
2049
  }
@@ -2161,7 +2062,7 @@ async function validateUiContracts(uiRoot, themaIds) {
2161
2062
  }
2162
2063
  const issues = [];
2163
2064
  for (const file of files) {
2164
- const text = await (0, import_promises13.readFile)(file, "utf-8");
2065
+ const text = await (0, import_promises12.readFile)(file, "utf-8");
2165
2066
  const declaredIds = extractDeclaredContractIds(text);
2166
2067
  issues.push(...validateDeclaredContractIds(declaredIds, file, "UI"));
2167
2068
  let doc = null;
@@ -2215,7 +2116,7 @@ async function validateThemaContracts(uiRoot) {
2215
2116
  }
2216
2117
  const issues = [];
2217
2118
  for (const file of files) {
2218
- const text = await (0, import_promises13.readFile)(file, "utf-8");
2119
+ const text = await (0, import_promises12.readFile)(file, "utf-8");
2219
2120
  const invalidIds = extractInvalidIds(text, [
2220
2121
  "SPEC",
2221
2122
  "BR",
@@ -2349,7 +2250,7 @@ async function validateApiContracts(apiRoot) {
2349
2250
  }
2350
2251
  const issues = [];
2351
2252
  for (const file of files) {
2352
- const text = await (0, import_promises13.readFile)(file, "utf-8");
2253
+ const text = await (0, import_promises12.readFile)(file, "utf-8");
2353
2254
  const invalidIds = extractInvalidIds(text, [
2354
2255
  "SPEC",
2355
2256
  "BR",
@@ -2418,7 +2319,7 @@ async function validateDbContracts(dbRoot) {
2418
2319
  }
2419
2320
  const issues = [];
2420
2321
  for (const file of files) {
2421
- const text = await (0, import_promises13.readFile)(file, "utf-8");
2322
+ const text = await (0, import_promises12.readFile)(file, "utf-8");
2422
2323
  const invalidIds = extractInvalidIds(text, [
2423
2324
  "SPEC",
2424
2325
  "BR",
@@ -2615,9 +2516,9 @@ async function validateUiAssets(assets, file, uiRoot) {
2615
2516
  );
2616
2517
  return issues;
2617
2518
  }
2618
- const packDir = import_node_path17.default.resolve(uiRoot, packValue);
2619
- const packRelative = import_node_path17.default.relative(uiRoot, packDir);
2620
- if (packRelative.startsWith("..") || import_node_path17.default.isAbsolute(packRelative)) {
2519
+ const packDir = import_node_path16.default.resolve(uiRoot, packValue);
2520
+ const packRelative = import_node_path16.default.relative(uiRoot, packDir);
2521
+ if (packRelative.startsWith("..") || import_node_path16.default.isAbsolute(packRelative)) {
2621
2522
  issues.push(
2622
2523
  issue(
2623
2524
  "QFAI-ASSET-001",
@@ -2643,7 +2544,7 @@ async function validateUiAssets(assets, file, uiRoot) {
2643
2544
  );
2644
2545
  return issues;
2645
2546
  }
2646
- const assetsYamlPath = import_node_path17.default.join(packDir, "assets.yaml");
2547
+ const assetsYamlPath = import_node_path16.default.join(packDir, "assets.yaml");
2647
2548
  if (!await exists6(assetsYamlPath)) {
2648
2549
  issues.push(
2649
2550
  issue(
@@ -2658,7 +2559,7 @@ async function validateUiAssets(assets, file, uiRoot) {
2658
2559
  }
2659
2560
  let manifest;
2660
2561
  try {
2661
- const manifestText = await (0, import_promises13.readFile)(assetsYamlPath, "utf-8");
2562
+ const manifestText = await (0, import_promises12.readFile)(assetsYamlPath, "utf-8");
2662
2563
  manifest = parseStructuredContract(assetsYamlPath, manifestText);
2663
2564
  } catch (error2) {
2664
2565
  issues.push(
@@ -2731,9 +2632,9 @@ async function validateUiAssets(assets, file, uiRoot) {
2731
2632
  );
2732
2633
  continue;
2733
2634
  }
2734
- const assetPath = import_node_path17.default.resolve(packDir, entry.path);
2735
- const assetRelative = import_node_path17.default.relative(packDir, assetPath);
2736
- if (assetRelative.startsWith("..") || import_node_path17.default.isAbsolute(assetRelative)) {
2635
+ const assetPath = import_node_path16.default.resolve(packDir, entry.path);
2636
+ const assetRelative = import_node_path16.default.relative(packDir, assetPath);
2637
+ if (assetRelative.startsWith("..") || import_node_path16.default.isAbsolute(assetRelative)) {
2737
2638
  issues.push(
2738
2639
  issue(
2739
2640
  "QFAI-ASSET-004",
@@ -2774,7 +2675,7 @@ function shouldIgnoreInvalidId(value, doc) {
2774
2675
  return false;
2775
2676
  }
2776
2677
  const normalized = packValue.replace(/\\/g, "/");
2777
- const basename = import_node_path17.default.posix.basename(normalized);
2678
+ const basename = import_node_path16.default.posix.basename(normalized);
2778
2679
  if (!basename) {
2779
2680
  return false;
2780
2681
  }
@@ -2784,7 +2685,7 @@ function isSafeRelativePath(value) {
2784
2685
  if (!value) {
2785
2686
  return false;
2786
2687
  }
2787
- if (import_node_path17.default.isAbsolute(value)) {
2688
+ if (import_node_path16.default.isAbsolute(value)) {
2788
2689
  return false;
2789
2690
  }
2790
2691
  const normalized = value.replace(/\\/g, "/");
@@ -2799,7 +2700,7 @@ function isSafeRelativePath(value) {
2799
2700
  }
2800
2701
  async function exists6(target) {
2801
2702
  try {
2802
- await (0, import_promises13.access)(target);
2703
+ await (0, import_promises12.access)(target);
2803
2704
  return true;
2804
2705
  } catch {
2805
2706
  return false;
@@ -2834,13 +2735,8 @@ function issue(code, message, severity, file, rule, refs, category = "compatibil
2834
2735
  }
2835
2736
 
2836
2737
  // src/core/validators/delta.ts
2837
- var import_promises14 = require("fs/promises");
2838
- var import_node_path18 = __toESM(require("path"), 1);
2839
- var SECTION_RE = /^##\s+変更区分/m;
2840
- var COMPAT_LINE_RE = /^\s*-\s*\[[ xX]\]\s*Compatibility\b/m;
2841
- var CHANGE_LINE_RE = /^\s*-\s*\[[ xX]\]\s*Change\/Improvement\b/m;
2842
- var COMPAT_CHECKED_RE = /^\s*-\s*\[[xX]\]\s*Compatibility\b/m;
2843
- var CHANGE_CHECKED_RE = /^\s*-\s*\[[xX]\]\s*Change\/Improvement\b/m;
2738
+ var import_promises13 = require("fs/promises");
2739
+ var import_node_path17 = __toESM(require("path"), 1);
2844
2740
  async function validateDeltas(root, config) {
2845
2741
  const specsRoot = resolvePath(root, config, "specsDir");
2846
2742
  const packs = await collectSpecPackDirs(specsRoot);
@@ -2849,10 +2745,9 @@ async function validateDeltas(root, config) {
2849
2745
  }
2850
2746
  const issues = [];
2851
2747
  for (const pack of packs) {
2852
- const deltaPath = import_node_path18.default.join(pack, "delta.md");
2853
- let text;
2748
+ const deltaPath = import_node_path17.default.join(pack, "delta.md");
2854
2749
  try {
2855
- text = await (0, import_promises14.readFile)(deltaPath, "utf-8");
2750
+ await (0, import_promises13.readFile)(deltaPath, "utf-8");
2856
2751
  } catch (error2) {
2857
2752
  if (isMissingFileError2(error2)) {
2858
2753
  issues.push(
@@ -2861,41 +2756,16 @@ async function validateDeltas(root, config) {
2861
2756
  "delta.md \u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3002",
2862
2757
  "error",
2863
2758
  deltaPath,
2864
- "delta.exists"
2759
+ "delta.exists",
2760
+ void 0,
2761
+ "change",
2762
+ "spec-xxxx/delta.md \u3092\u4F5C\u6210\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u30C6\u30F3\u30D7\u30EC\u306F init \u751F\u6210\u7269\u3092\u53C2\u7167\u3057\u3066\u304F\u3060\u3055\u3044\uFF09\u3002"
2865
2763
  )
2866
2764
  );
2867
2765
  continue;
2868
2766
  }
2869
2767
  throw error2;
2870
2768
  }
2871
- const hasSection = SECTION_RE.test(text);
2872
- const hasCompatibility = COMPAT_LINE_RE.test(text);
2873
- const hasChange = CHANGE_LINE_RE.test(text);
2874
- if (!hasSection || !hasCompatibility || !hasChange) {
2875
- issues.push(
2876
- issue2(
2877
- "QFAI-DELTA-002",
2878
- "delta.md \u306E\u5909\u66F4\u533A\u5206\u304C\u4E0D\u8DB3\u3057\u3066\u3044\u307E\u3059\u3002`## \u5909\u66F4\u533A\u5206` \u3068\u30C1\u30A7\u30C3\u30AF\u30DC\u30C3\u30AF\u30B9\uFF08Compatibility / Change/Improvement\uFF09\u3092\u8FFD\u52A0\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
2879
- "error",
2880
- deltaPath,
2881
- "delta.section"
2882
- )
2883
- );
2884
- continue;
2885
- }
2886
- const compatibilityChecked = COMPAT_CHECKED_RE.test(text);
2887
- const changeChecked = CHANGE_CHECKED_RE.test(text);
2888
- if (compatibilityChecked === changeChecked) {
2889
- issues.push(
2890
- issue2(
2891
- "QFAI-DELTA-003",
2892
- "delta.md \u306E\u5909\u66F4\u533A\u5206\u306F\u3069\u3061\u3089\u304B1\u3064\u3060\u3051\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u4E21\u65B9ON/\u4E21\u65B9OFF\u306F\u7121\u52B9\u3067\u3059\uFF09\u3002",
2893
- "error",
2894
- deltaPath,
2895
- "delta.classification"
2896
- )
2897
- );
2898
- }
2899
2769
  }
2900
2770
  return issues;
2901
2771
  }
@@ -2928,8 +2798,8 @@ function issue2(code, message, severity, file, rule, refs, category = "change",
2928
2798
  }
2929
2799
 
2930
2800
  // src/core/validators/ids.ts
2931
- var import_promises15 = require("fs/promises");
2932
- var import_node_path19 = __toESM(require("path"), 1);
2801
+ var import_promises14 = require("fs/promises");
2802
+ var import_node_path18 = __toESM(require("path"), 1);
2933
2803
  var SC_TAG_RE3 = /^SC-\d{4}$/;
2934
2804
  async function validateDefinedIds(root, config) {
2935
2805
  const issues = [];
@@ -2964,7 +2834,7 @@ async function validateDefinedIds(root, config) {
2964
2834
  }
2965
2835
  async function collectSpecDefinitionIds(files, out) {
2966
2836
  for (const file of files) {
2967
- const text = await (0, import_promises15.readFile)(file, "utf-8");
2837
+ const text = await (0, import_promises14.readFile)(file, "utf-8");
2968
2838
  const parsed = parseSpec(text, file);
2969
2839
  if (parsed.specId) {
2970
2840
  recordId(out, parsed.specId, file);
@@ -2974,7 +2844,7 @@ async function collectSpecDefinitionIds(files, out) {
2974
2844
  }
2975
2845
  async function collectScenarioDefinitionIds(files, out) {
2976
2846
  for (const file of files) {
2977
- const text = await (0, import_promises15.readFile)(file, "utf-8");
2847
+ const text = await (0, import_promises14.readFile)(file, "utf-8");
2978
2848
  const { document, errors } = parseScenarioDocument(text, file);
2979
2849
  if (!document || errors.length > 0) {
2980
2850
  continue;
@@ -2995,7 +2865,7 @@ function recordId(out, id, file) {
2995
2865
  }
2996
2866
  function formatFileList(files, root) {
2997
2867
  return files.map((file) => {
2998
- const relative = import_node_path19.default.relative(root, file);
2868
+ const relative = import_node_path18.default.relative(root, file);
2999
2869
  return relative.length > 0 ? relative : file;
3000
2870
  }).join(", ");
3001
2871
  }
@@ -3022,8 +2892,8 @@ function issue3(code, message, severity, file, rule, refs, category = "compatibi
3022
2892
  }
3023
2893
 
3024
2894
  // src/core/validators/promptsIntegrity.ts
3025
- async function validatePromptsIntegrity(root) {
3026
- const diff = await diffProjectPromptsAgainstInitAssets(root);
2895
+ async function validatePromptsIntegrity(root, config) {
2896
+ const diff = await diffProjectPromptsAgainstInitAssets(root, config);
3027
2897
  if (diff.status !== "modified") {
3028
2898
  return [];
3029
2899
  }
@@ -3040,11 +2910,11 @@ async function validatePromptsIntegrity(root) {
3040
2910
  code: "QFAI-PROMPTS-001",
3041
2911
  severity: "error",
3042
2912
  category: "change",
3043
- message: `\u6A19\u6E96\u8CC7\u7523 '.qfai/prompts/**' \u304C\u6539\u5909\u3055\u308C\u3066\u3044\u307E\u3059\uFF08${hints || `\u5DEE\u5206=${total}`}\uFF09\u3002${sampleText}`,
2913
+ message: `\u6A19\u6E96\u8CC7\u7523 '.qfai/assistant/prompts/**' \u304C\u6539\u5909\u3055\u308C\u3066\u3044\u307E\u3059\uFF08${hints || `\u5DEE\u5206=${total}`}\uFF09\u3002${sampleText}`,
3044
2914
  suggested_action: [
3045
2915
  "prompts \u306E\u76F4\u7DE8\u96C6\u306F\u975E\u63A8\u5968\u3067\u3059\uFF08\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8/\u518D init \u3067\u4E0A\u66F8\u304D\u3055\u308C\u5F97\u307E\u3059\uFF09\u3002",
3046
2916
  "\u6B21\u306E\u3044\u305A\u308C\u304B\u3092\u5B9F\u65BD\u3057\u3066\u304F\u3060\u3055\u3044:",
3047
- "- \u5909\u66F4\u3057\u305F\u3044\u5834\u5408: \u540C\u4E00\u76F8\u5BFE\u30D1\u30B9\u3067 '.qfai/prompts.local/**' \u306B\u7F6E\u3044\u3066 overlay",
2917
+ "- \u5909\u66F4\u3057\u305F\u3044\u5834\u5408: \u540C\u4E00\u76F8\u5BFE\u30D1\u30B9\u3067 '.qfai/assistant/prompts.local/**' \u306B\u7F6E\u3044\u3066 overlay",
3048
2918
  "- \u6A19\u6E96\u72B6\u614B\u3078\u623B\u3059\u5834\u5408: 'qfai init --force' \u3092\u5B9F\u884C\uFF08prompts \u306E\u307F\u4E0A\u66F8\u304D\u3001prompts.local \u306F\u4FDD\u8B77\uFF09"
3049
2919
  ].join("\n"),
3050
2920
  rule: "prompts.integrity"
@@ -3053,8 +2923,8 @@ async function validatePromptsIntegrity(root) {
3053
2923
  }
3054
2924
 
3055
2925
  // src/core/validators/scenario.ts
3056
- var import_promises16 = require("fs/promises");
3057
- var import_node_path20 = __toESM(require("path"), 1);
2926
+ var import_promises15 = require("fs/promises");
2927
+ var import_node_path19 = __toESM(require("path"), 1);
3058
2928
  var GIVEN_PATTERN = /\bGiven\b/;
3059
2929
  var WHEN_PATTERN = /\bWhen\b/;
3060
2930
  var THEN_PATTERN = /\bThen\b/;
@@ -3077,7 +2947,7 @@ async function validateScenarios(root, config) {
3077
2947
  }
3078
2948
  const issues = [];
3079
2949
  for (const entry of entries) {
3080
- const legacyScenarioPath = import_node_path20.default.join(entry.dir, "scenario.md");
2950
+ const legacyScenarioPath = import_node_path19.default.join(entry.dir, "scenario.md");
3081
2951
  if (await fileExists(legacyScenarioPath)) {
3082
2952
  issues.push(
3083
2953
  issue4(
@@ -3091,7 +2961,7 @@ async function validateScenarios(root, config) {
3091
2961
  }
3092
2962
  let text;
3093
2963
  try {
3094
- text = await (0, import_promises16.readFile)(entry.scenarioPath, "utf-8");
2964
+ text = await (0, import_promises15.readFile)(entry.scenarioPath, "utf-8");
3095
2965
  } catch (error2) {
3096
2966
  if (isMissingFileError3(error2)) {
3097
2967
  issues.push(
@@ -3266,7 +3136,7 @@ function isMissingFileError3(error2) {
3266
3136
  }
3267
3137
  async function fileExists(target) {
3268
3138
  try {
3269
- await (0, import_promises16.access)(target);
3139
+ await (0, import_promises15.access)(target);
3270
3140
  return true;
3271
3141
  } catch {
3272
3142
  return false;
@@ -3274,7 +3144,7 @@ async function fileExists(target) {
3274
3144
  }
3275
3145
 
3276
3146
  // src/core/validators/spec.ts
3277
- var import_promises17 = require("fs/promises");
3147
+ var import_promises16 = require("fs/promises");
3278
3148
  async function validateSpecs(root, config) {
3279
3149
  const specsRoot = resolvePath(root, config, "specsDir");
3280
3150
  const entries = await collectSpecEntries(specsRoot);
@@ -3295,7 +3165,7 @@ async function validateSpecs(root, config) {
3295
3165
  for (const entry of entries) {
3296
3166
  let text;
3297
3167
  try {
3298
- text = await (0, import_promises17.readFile)(entry.specPath, "utf-8");
3168
+ text = await (0, import_promises16.readFile)(entry.specPath, "utf-8");
3299
3169
  } catch (error2) {
3300
3170
  if (isMissingFileError4(error2)) {
3301
3171
  issues.push(
@@ -3449,7 +3319,7 @@ function isMissingFileError4(error2) {
3449
3319
  }
3450
3320
 
3451
3321
  // src/core/validators/traceability.ts
3452
- var import_promises18 = require("fs/promises");
3322
+ var import_promises17 = require("fs/promises");
3453
3323
  var SPEC_TAG_RE3 = /^SPEC-\d{4}$/;
3454
3324
  var BR_TAG_RE2 = /^BR-\d{4}$/;
3455
3325
  async function validateTraceability(root, config) {
@@ -3469,7 +3339,7 @@ async function validateTraceability(root, config) {
3469
3339
  const contractIndex = await buildContractIndex(root, config);
3470
3340
  const contractIds = contractIndex.ids;
3471
3341
  for (const file of specFiles) {
3472
- const text = await (0, import_promises18.readFile)(file, "utf-8");
3342
+ const text = await (0, import_promises17.readFile)(file, "utf-8");
3473
3343
  extractAllIds(text).forEach((id) => upstreamIds.add(id));
3474
3344
  const parsed = parseSpec(text, file);
3475
3345
  if (parsed.specId) {
@@ -3542,7 +3412,7 @@ async function validateTraceability(root, config) {
3542
3412
  }
3543
3413
  }
3544
3414
  for (const file of scenarioFiles) {
3545
- const text = await (0, import_promises18.readFile)(file, "utf-8");
3415
+ const text = await (0, import_promises17.readFile)(file, "utf-8");
3546
3416
  extractAllIds(text).forEach((id) => upstreamIds.add(id));
3547
3417
  const scenarioContractRefs = parseContractRefs(text, {
3548
3418
  allowCommentPrefix: true
@@ -3864,7 +3734,7 @@ async function validateCodeReferences(upstreamIds, srcRoot, testsRoot) {
3864
3734
  const pattern = buildIdPattern(Array.from(upstreamIds));
3865
3735
  let found = false;
3866
3736
  for (const file of targetFiles) {
3867
- const text = await (0, import_promises18.readFile)(file, "utf-8");
3737
+ const text = await (0, import_promises17.readFile)(file, "utf-8");
3868
3738
  if (pattern.test(text)) {
3869
3739
  found = true;
3870
3740
  break;
@@ -3915,7 +3785,7 @@ async function validateProject(root, configResult) {
3915
3785
  const { config, issues: configIssues } = resolved;
3916
3786
  const issues = [
3917
3787
  ...configIssues,
3918
- ...await validatePromptsIntegrity(root),
3788
+ ...await validatePromptsIntegrity(root, config),
3919
3789
  ...await validateSpecs(root, config),
3920
3790
  ...await validateDeltas(root, config),
3921
3791
  ...await validateScenarios(root, config),
@@ -3964,15 +3834,15 @@ var ID_PREFIXES2 = [
3964
3834
  "THEMA"
3965
3835
  ];
3966
3836
  async function createReportData(root, validation, configResult) {
3967
- const resolvedRoot = import_node_path21.default.resolve(root);
3837
+ const resolvedRoot = import_node_path20.default.resolve(root);
3968
3838
  const resolved = configResult ?? await loadConfig(resolvedRoot);
3969
3839
  const config = resolved.config;
3970
3840
  const configPath = resolved.configPath;
3971
3841
  const specsRoot = resolvePath(resolvedRoot, config, "specsDir");
3972
3842
  const contractsRoot = resolvePath(resolvedRoot, config, "contractsDir");
3973
- const apiRoot = import_node_path21.default.join(contractsRoot, "api");
3974
- const uiRoot = import_node_path21.default.join(contractsRoot, "ui");
3975
- const dbRoot = import_node_path21.default.join(contractsRoot, "db");
3843
+ const apiRoot = import_node_path20.default.join(contractsRoot, "api");
3844
+ const uiRoot = import_node_path20.default.join(contractsRoot, "ui");
3845
+ const dbRoot = import_node_path20.default.join(contractsRoot, "db");
3976
3846
  const srcRoot = resolvePath(resolvedRoot, config, "srcDir");
3977
3847
  const testsRoot = resolvePath(resolvedRoot, config, "testsDir");
3978
3848
  const specFiles = await collectSpecFiles(specsRoot);
@@ -4437,11 +4307,9 @@ function formatReportMarkdown(data, options = {}) {
4437
4307
  "- issue \u306F\u691C\u51FA\u3055\u308C\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u904B\u7528\u30C6\u30F3\u30D7\u30EC\u306B\u6CBF\u3063\u3066\u7D99\u7D9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
4438
4308
  );
4439
4309
  }
4310
+ lines.push("- \u5909\u66F4\u5185\u5BB9\u30FB\u53D7\u5165\u89B3\u70B9\u306F `.qfai/specs/*/delta.md` \u306B\u8A18\u9332\u3057\u307E\u3059\u3002");
4440
4311
  lines.push(
4441
- "- \u5909\u66F4\u533A\u5206\uFF08Compatibility / Change/Improvement\uFF09\u306F `.qfai/specs/*/delta.md` \u306B\u8A18\u9332\u3057\u307E\u3059\u3002"
4442
- );
4443
- lines.push(
4444
- "- \u53C2\u7167\u30EB\u30FC\u30EB\u306E\u6B63\u672C: `.qfai/promptpack/steering/traceability.md` / `.qfai/promptpack/steering/compatibility-vs-change.md`"
4312
+ "- \u53C2\u7167\u30EB\u30FC\u30EB\u306E\u6B63\u672C: `.qfai/assistant/instructions/constitution.md`"
4445
4313
  );
4446
4314
  return lines.join("\n");
4447
4315
  }
@@ -4456,7 +4324,7 @@ async function collectSpecContractRefs(specFiles, contractIdList) {
4456
4324
  idToSpecs.set(contractId, /* @__PURE__ */ new Set());
4457
4325
  }
4458
4326
  for (const file of specFiles) {
4459
- const text = await (0, import_promises19.readFile)(file, "utf-8");
4327
+ const text = await (0, import_promises18.readFile)(file, "utf-8");
4460
4328
  const parsed = parseSpec(text, file);
4461
4329
  const specKey = parsed.specId;
4462
4330
  if (!specKey) {
@@ -4498,7 +4366,7 @@ async function collectIds(files) {
4498
4366
  THEMA: /* @__PURE__ */ new Set()
4499
4367
  };
4500
4368
  for (const file of files) {
4501
- const text = await (0, import_promises19.readFile)(file, "utf-8");
4369
+ const text = await (0, import_promises18.readFile)(file, "utf-8");
4502
4370
  for (const prefix of ID_PREFIXES2) {
4503
4371
  const ids = extractIds(text, prefix);
4504
4372
  ids.forEach((id) => result[prefix].add(id));
@@ -4517,7 +4385,7 @@ async function collectIds(files) {
4517
4385
  async function collectUpstreamIds(files) {
4518
4386
  const ids = /* @__PURE__ */ new Set();
4519
4387
  for (const file of files) {
4520
- const text = await (0, import_promises19.readFile)(file, "utf-8");
4388
+ const text = await (0, import_promises18.readFile)(file, "utf-8");
4521
4389
  extractAllIds(text).forEach((id) => ids.add(id));
4522
4390
  }
4523
4391
  return ids;
@@ -4538,7 +4406,7 @@ async function evaluateTraceability(upstreamIds, srcRoot, testsRoot) {
4538
4406
  }
4539
4407
  const pattern = buildIdPattern2(Array.from(upstreamIds));
4540
4408
  for (const file of targetFiles) {
4541
- const text = await (0, import_promises19.readFile)(file, "utf-8");
4409
+ const text = await (0, import_promises18.readFile)(file, "utf-8");
4542
4410
  if (pattern.test(text)) {
4543
4411
  return true;
4544
4412
  }
@@ -4675,7 +4543,7 @@ function warnIfTruncated(scan, context) {
4675
4543
 
4676
4544
  // src/cli/commands/report.ts
4677
4545
  async function runReport(options) {
4678
- const root = import_node_path22.default.resolve(options.root);
4546
+ const root = import_node_path21.default.resolve(options.root);
4679
4547
  const configResult = await loadConfig(root);
4680
4548
  let validation;
4681
4549
  if (options.runValidate) {
@@ -4692,7 +4560,7 @@ async function runReport(options) {
4692
4560
  validation = normalized;
4693
4561
  } else {
4694
4562
  const input = options.inputPath ?? configResult.config.output.validateJsonPath;
4695
- const inputPath = import_node_path22.default.isAbsolute(input) ? input : import_node_path22.default.resolve(root, input);
4563
+ const inputPath = import_node_path21.default.isAbsolute(input) ? input : import_node_path21.default.resolve(root, input);
4696
4564
  try {
4697
4565
  validation = await readValidationResult(inputPath);
4698
4566
  } catch (err) {
@@ -4703,7 +4571,7 @@ async function runReport(options) {
4703
4571
  "",
4704
4572
  "\u307E\u305A qfai validate \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u4F8B:",
4705
4573
  " qfai validate",
4706
- "\uFF08\u30C7\u30D5\u30A9\u30EB\u30C8\u306E\u51FA\u529B\u5148: .qfai/out/validate.json\uFF09",
4574
+ "\uFF08\u30C7\u30D5\u30A9\u30EB\u30C8\u306E\u51FA\u529B\u5148: .qfai/report/validate.json\uFF09",
4707
4575
  "",
4708
4576
  "\u307E\u305F\u306F report \u306B --run-validate \u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
4709
4577
  "GitHub Actions \u30C6\u30F3\u30D7\u30EC\u3092\u4F7F\u3063\u3066\u3044\u308B\u5834\u5408\u306F\u3001workflow \u306E validate \u30B8\u30E7\u30D6\u3092\u5148\u306B\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
@@ -4719,11 +4587,11 @@ async function runReport(options) {
4719
4587
  warnIfTruncated(data.traceability.testFiles, "report");
4720
4588
  const output = options.format === "json" ? formatReportJson(data) : options.baseUrl ? formatReportMarkdown(data, { baseUrl: options.baseUrl }) : formatReportMarkdown(data);
4721
4589
  const outRoot = resolvePath(root, configResult.config, "outDir");
4722
- const defaultOut = options.format === "json" ? import_node_path22.default.join(outRoot, "report.json") : import_node_path22.default.join(outRoot, "report.md");
4590
+ const defaultOut = options.format === "json" ? import_node_path21.default.join(outRoot, "report.json") : import_node_path21.default.join(outRoot, "report.md");
4723
4591
  const out = options.outPath ?? defaultOut;
4724
- const outPath = import_node_path22.default.isAbsolute(out) ? out : import_node_path22.default.resolve(root, out);
4725
- await (0, import_promises20.mkdir)(import_node_path22.default.dirname(outPath), { recursive: true });
4726
- await (0, import_promises20.writeFile)(outPath, `${output}
4592
+ const outPath = import_node_path21.default.isAbsolute(out) ? out : import_node_path21.default.resolve(root, out);
4593
+ await (0, import_promises19.mkdir)(import_node_path21.default.dirname(outPath), { recursive: true });
4594
+ await (0, import_promises19.writeFile)(outPath, `${output}
4727
4595
  `, "utf-8");
4728
4596
  info(
4729
4597
  `report: info=${validation.counts.info} warning=${validation.counts.warning} error=${validation.counts.error}`
@@ -4731,7 +4599,7 @@ async function runReport(options) {
4731
4599
  info(`wrote report: ${outPath}`);
4732
4600
  }
4733
4601
  async function readValidationResult(inputPath) {
4734
- const raw = await (0, import_promises20.readFile)(inputPath, "utf-8");
4602
+ const raw = await (0, import_promises19.readFile)(inputPath, "utf-8");
4735
4603
  const parsed = JSON.parse(raw);
4736
4604
  if (!isValidationResult(parsed)) {
4737
4605
  throw new Error(`validate.json \u306E\u5F62\u5F0F\u304C\u4E0D\u6B63\u3067\u3059: ${inputPath}`);
@@ -4787,15 +4655,15 @@ function isMissingFileError5(error2) {
4787
4655
  return record2.code === "ENOENT";
4788
4656
  }
4789
4657
  async function writeValidationResult(root, outputPath, result) {
4790
- const abs = import_node_path22.default.isAbsolute(outputPath) ? outputPath : import_node_path22.default.resolve(root, outputPath);
4791
- await (0, import_promises20.mkdir)(import_node_path22.default.dirname(abs), { recursive: true });
4792
- await (0, import_promises20.writeFile)(abs, `${JSON.stringify(result, null, 2)}
4658
+ const abs = import_node_path21.default.isAbsolute(outputPath) ? outputPath : import_node_path21.default.resolve(root, outputPath);
4659
+ await (0, import_promises19.mkdir)(import_node_path21.default.dirname(abs), { recursive: true });
4660
+ await (0, import_promises19.writeFile)(abs, `${JSON.stringify(result, null, 2)}
4793
4661
  `, "utf-8");
4794
4662
  }
4795
4663
 
4796
4664
  // src/cli/commands/validate.ts
4797
- var import_promises21 = require("fs/promises");
4798
- var import_node_path23 = __toESM(require("path"), 1);
4665
+ var import_promises20 = require("fs/promises");
4666
+ var import_node_path22 = __toESM(require("path"), 1);
4799
4667
 
4800
4668
  // src/cli/lib/failOn.ts
4801
4669
  function shouldFail(result, failOn) {
@@ -4810,7 +4678,7 @@ function shouldFail(result, failOn) {
4810
4678
 
4811
4679
  // src/cli/commands/validate.ts
4812
4680
  async function runValidate(options) {
4813
- const root = import_node_path23.default.resolve(options.root);
4681
+ const root = import_node_path22.default.resolve(options.root);
4814
4682
  const configResult = await loadConfig(root);
4815
4683
  const result = await validateProject(root, configResult);
4816
4684
  const normalized = normalizeValidationResult(root, result);
@@ -4935,12 +4803,12 @@ function issueKey(issue7) {
4935
4803
  }
4936
4804
  async function emitJson(result, root, jsonPath) {
4937
4805
  const abs = resolveJsonPath(root, jsonPath);
4938
- await (0, import_promises21.mkdir)(import_node_path23.default.dirname(abs), { recursive: true });
4939
- await (0, import_promises21.writeFile)(abs, `${JSON.stringify(result, null, 2)}
4806
+ await (0, import_promises20.mkdir)(import_node_path22.default.dirname(abs), { recursive: true });
4807
+ await (0, import_promises20.writeFile)(abs, `${JSON.stringify(result, null, 2)}
4940
4808
  `, "utf-8");
4941
4809
  }
4942
4810
  function resolveJsonPath(root, jsonPath) {
4943
- return import_node_path23.default.isAbsolute(jsonPath) ? jsonPath : import_node_path23.default.resolve(root, jsonPath);
4811
+ return import_node_path22.default.isAbsolute(jsonPath) ? jsonPath : import_node_path22.default.resolve(root, jsonPath);
4944
4812
  }
4945
4813
  var GITHUB_ANNOTATION_LIMIT = 100;
4946
4814
 
@@ -4953,7 +4821,6 @@ function parseArgs(argv, cwd) {
4953
4821
  force: false,
4954
4822
  yes: false,
4955
4823
  dryRun: false,
4956
- analyzeList: false,
4957
4824
  reportFormat: "md",
4958
4825
  reportRunValidate: false,
4959
4826
  doctorFormat: "text",
@@ -5005,18 +4872,6 @@ function parseArgs(argv, cwd) {
5005
4872
  case "--dry-run":
5006
4873
  options.dryRun = true;
5007
4874
  break;
5008
- case "--list":
5009
- options.analyzeList = true;
5010
- break;
5011
- case "--prompt":
5012
- {
5013
- const next = readOptionValue(args, i);
5014
- if (next) {
5015
- options.analyzePrompt = next;
5016
- i += 1;
5017
- }
5018
- }
5019
- break;
5020
4875
  case "--format": {
5021
4876
  const next = readOptionValue(args, i);
5022
4877
  if (next === null) {
@@ -5150,17 +5005,6 @@ async function run(argv, cwd) {
5150
5005
  yes: options.yes
5151
5006
  });
5152
5007
  return;
5153
- case "analyze":
5154
- {
5155
- const resolvedRoot = await resolveRoot(options);
5156
- const exitCode = await runAnalyze({
5157
- root: resolvedRoot,
5158
- list: options.analyzeList,
5159
- ...options.analyzePrompt !== void 0 ? { prompt: options.analyzePrompt } : {}
5160
- });
5161
- process.exitCode = exitCode;
5162
- }
5163
- return;
5164
5008
  case "validate":
5165
5009
  {
5166
5010
  const resolvedRoot = await resolveRoot(options);
@@ -5208,7 +5052,6 @@ function usage() {
5208
5052
 
5209
5053
  Commands:
5210
5054
  init \u30C6\u30F3\u30D7\u30EC\u3092\u751F\u6210
5211
- analyze \u610F\u5473\u30EC\u30D9\u30EB\u306E\u30EC\u30D3\u30E5\u30FC\u88DC\u52A9\uFF08\u30D7\u30ED\u30F3\u30D7\u30C8\u51FA\u529B\uFF09
5212
5055
  validate \u4ED5\u69D8/\u5951\u7D04/\u53C2\u7167\u306E\u691C\u67FB
5213
5056
  report \u691C\u8A3C\u7D50\u679C\u3068\u96C6\u8A08\u3092\u51FA\u529B
5214
5057
  doctor \u8A2D\u5B9A/\u30D1\u30B9/\u51FA\u529B\u524D\u63D0\u306E\u8A3A\u65AD
@@ -5216,11 +5059,9 @@ Commands:
5216
5059
  Options:
5217
5060
  --root <path> \u5BFE\u8C61\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA
5218
5061
  --dir <path> init \u306E\u51FA\u529B\u5148
5219
- --force init: .qfai/prompts \u306E\u307F\u4E0A\u66F8\u304D\uFF08\u305D\u308C\u4EE5\u5916\u306F\u65E2\u5B58\u304C\u3042\u308C\u3070\u30B9\u30AD\u30C3\u30D7\uFF09
5062
+ --force init: .qfai/assistant/prompts \u306E\u307F\u4E0A\u66F8\u304D\uFF08\u305D\u308C\u4EE5\u5916\u306F\u65E2\u5B58\u304C\u3042\u308C\u3070\u30B9\u30AD\u30C3\u30D7\uFF09
5220
5063
  --yes init: \u4E88\u7D04\u30D5\u30E9\u30B0\uFF08\u73FE\u72B6\u306F\u975E\u5BFE\u8A71\u306E\u305F\u3081\u6319\u52D5\u5DEE\u306A\u3057\u3002\u5C06\u6765\u306E\u5BFE\u8A71\u5C0E\u5165\u6642\u306B\u81EA\u52D5Yes\uFF09
5221
5064
  --dry-run \u5909\u66F4\u3092\u884C\u308F\u305A\u8868\u793A\u306E\u307F
5222
- --list analyze: \u5229\u7528\u53EF\u80FD\u306A\u30D7\u30ED\u30F3\u30D7\u30C8\u4E00\u89A7\u3092\u8868\u793A
5223
- --prompt <name> analyze: \u6307\u5B9A\u30D7\u30ED\u30F3\u30D7\u30C8\uFF08.md\u7701\u7565\u53EF\uFF09\u3092\u51FA\u529B
5224
5065
  --format <text|github> validate \u306E\u51FA\u529B\u5F62\u5F0F
5225
5066
  --format <md|json> report \u306E\u51FA\u529B\u5F62\u5F0F
5226
5067
  --format <text|json> doctor \u306E\u51FA\u529B\u5F62\u5F0F