phasegate 0.91.0 → 0.107.0

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 (68) hide show
  1. package/CHANGELOG.md +169 -0
  2. package/README.ja.md +15 -7
  3. package/README.md +24 -4
  4. package/docs/ADR/ADR-015-architecture-preset.md +183 -0
  5. package/docs/guide/codex-integration.md +7 -2
  6. package/docs/guide/installation.md +10 -2
  7. package/docs/guide/preset-selection.md +170 -0
  8. package/docs/guide/quick-vs-full-mode.md +3 -3
  9. package/docs/guide/retrofit-adoption.md +19 -2
  10. package/docs/guide/skills-overview.md +1 -1
  11. package/package.json +7 -1
  12. package/scripts/harness/agent-integration/application/usecases/handle-pre-tool-use-usecase.ts +108 -100
  13. package/scripts/harness/agent-integration/domain/ports/phase-gate-query-port.ts +3 -3
  14. package/scripts/harness/agent-integration/domain/value-objects/write-target-scope.ts +26 -30
  15. package/scripts/harness/agent-integration/infrastructure/adapters/file-system-story-reflection-query-adapter.ts +6 -2
  16. package/scripts/harness/biome-ast-engine/application/dto/analyze-import-graph-input.ts +3 -0
  17. package/scripts/harness/biome-ast-engine/application/dto/resolve-enabled-rules-output.ts +2 -0
  18. package/scripts/harness/biome-ast-engine/application/mappers/resolve-enabled-rules-output-mapper.ts +4 -1
  19. package/scripts/harness/biome-ast-engine/application/usecases/analyze-import-graph-usecase.ts +4 -1
  20. package/scripts/harness/biome-ast-engine/application/usecases/execute-lint-usecase.ts +2 -0
  21. package/scripts/harness/biome-ast-engine/application/usecases/resolve-enabled-rules-usecase.ts +31 -3
  22. package/scripts/harness/biome-ast-engine/composition-root.ts +10 -2
  23. package/scripts/harness/biome-ast-engine/domain/ports/rule-config-provider-port.ts +16 -0
  24. package/scripts/harness/biome-ast-engine/domain/ports/source-module-analyzer-port.ts +5 -1
  25. package/scripts/harness/biome-ast-engine/domain/services/lint-runner.ts +5 -1
  26. package/scripts/harness/biome-ast-engine/domain/value-objects/architecture-spec.ts +38 -0
  27. package/scripts/harness/biome-ast-engine/domain/value-objects/layer-boundary.ts +7 -8
  28. package/scripts/harness/biome-ast-engine/domain/value-objects/layer-name.ts +15 -23
  29. package/scripts/harness/biome-ast-engine/domain/value-objects/source-module-snapshot.ts +11 -4
  30. package/scripts/harness/biome-ast-engine/infrastructure/adapters/harness-config-provider-adapter.ts +29 -3
  31. package/scripts/harness/biome-ast-engine/infrastructure/adapters/typescript-source-module-analyzer-adapter.ts +22 -15
  32. package/scripts/harness/biome-ast-engine/infrastructure/mappers/source-module-snapshot-mapper.ts +26 -17
  33. package/scripts/harness/config-foundation/application/dto/resolved-config-output.ts +1 -0
  34. package/scripts/harness/config-foundation/application/usecases/load-resolved-config-use-case.ts +34 -2
  35. package/scripts/harness/config-foundation/application/usecases/migrate-schema-use-case.ts +89 -0
  36. package/scripts/harness/config-foundation/composition-root.ts +8 -0
  37. package/scripts/harness/config-foundation/domain/harness-config.ts +6 -0
  38. package/scripts/harness/config-foundation/domain/services/architecture-resolution-service.ts +257 -0
  39. package/scripts/harness/config-foundation/domain/value-objects/architecture-config.ts +66 -0
  40. package/scripts/harness/config-foundation/domain/value-objects/architecture-preset-catalog.ts +75 -0
  41. package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v3.schema.json +546 -0
  42. package/scripts/harness/config-foundation/infrastructure/validators/ajv-config-schema-validator.ts +18 -6
  43. package/scripts/harness/config-foundation/presentation/cli/migrate-schema-command-handler.ts +83 -0
  44. package/scripts/harness/integrations/pre-commit.ts +211 -52
  45. package/scripts/harness/main.ts +460 -340
  46. package/scripts/harness/phase-dependency-model/domain/ports/story-reflection-file-system-port.ts +2 -4
  47. package/scripts/harness/phase-dependency-model/domain/services/story-reflection-checker.ts +54 -17
  48. package/scripts/harness/phase-dependency-model/infrastructure/filesystem/file-system-story-reflection-adapter.ts +154 -36
  49. package/scripts/harness/setup/skill-deployer.ts +140 -102
  50. package/scripts/harness/skill-quality/domain/errors/skill-quality-error.ts +24 -23
  51. package/scripts/harness/skill-quality/domain/value-objects/commit-message.ts +23 -7
  52. package/scripts/harness/traceability-model/application/usecases/apply-work-item-migration-usecase.ts +52 -0
  53. package/scripts/harness/traceability-model/application/usecases/plan-work-item-migration-usecase.ts +29 -0
  54. package/scripts/harness/traceability-model/application/usecases/validate-design-story-annotations-usecase.ts +83 -18
  55. package/scripts/harness/traceability-model/composition-root.ts +48 -30
  56. package/scripts/harness/traceability-model/domain/ports/design-document-port.ts +9 -15
  57. package/scripts/harness/traceability-model/domain/ports/work-item-migration-apply-port.ts +11 -0
  58. package/scripts/harness/traceability-model/domain/ports/work-item-migration-source-port.ts +9 -0
  59. package/scripts/harness/traceability-model/domain/services/work-item-migration-planner.ts +162 -0
  60. package/scripts/harness/traceability-model/domain/value-objects/work-item-frontmatter.ts +57 -0
  61. package/scripts/harness/traceability-model/domain/value-objects/work-item-migration-candidate.ts +47 -0
  62. package/scripts/harness/traceability-model/infrastructure/gateways/file-system-work-item-migration-apply-gateway.ts +110 -0
  63. package/scripts/harness/traceability-model/infrastructure/gateways/file-system-work-item-migration-source-gateway.ts +182 -0
  64. package/scripts/harness/traceability-model/infrastructure/gateways/markdown-design-document-gateway.ts +29 -43
  65. package/scripts/harness/traceability-model/infrastructure/parsers/work-item-frontmatter-parser.ts +136 -0
  66. package/scripts/harness/traceability-model/presentation/cli/migrate-work-items-command-handler.ts +186 -0
  67. package/skills/quick-implementor/SKILL.md +17 -1
  68. package/templates/.husky/commit-msg +1 -0
@@ -0,0 +1,546 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "type": "object",
4
+ "additionalProperties": false,
5
+ "required": [
6
+ "project",
7
+ "layers",
8
+ "quickMode",
9
+ "phaseDependencies",
10
+ "planningMode",
11
+ "harnesses",
12
+ "paths",
13
+ "reporting"
14
+ ],
15
+ "properties": {
16
+ "project": {
17
+ "type": "object",
18
+ "additionalProperties": false,
19
+ "required": [
20
+ "name",
21
+ "preset"
22
+ ],
23
+ "properties": {
24
+ "name": {
25
+ "type": "string",
26
+ "minLength": 1
27
+ },
28
+ "preset": {
29
+ "type": "string",
30
+ "enum": [
31
+ "minimal",
32
+ "standard",
33
+ "strict"
34
+ ]
35
+ },
36
+ "paths": {
37
+ "type": "object",
38
+ "additionalProperties": false,
39
+ "properties": {
40
+ "source": {
41
+ "type": "array",
42
+ "items": {
43
+ "type": "string",
44
+ "minLength": 1
45
+ },
46
+ "minItems": 1,
47
+ "uniqueItems": true
48
+ },
49
+ "docs": {
50
+ "type": "object",
51
+ "additionalProperties": false,
52
+ "properties": {
53
+ "construction": {
54
+ "type": "string",
55
+ "minLength": 1
56
+ },
57
+ "inception": {
58
+ "type": "string",
59
+ "minLength": 1
60
+ }
61
+ }
62
+ }
63
+ }
64
+ }
65
+ }
66
+ },
67
+ "layers": {
68
+ "type": "object",
69
+ "additionalProperties": false,
70
+ "properties": {
71
+ "L0": {
72
+ "type": "object",
73
+ "additionalProperties": false,
74
+ "properties": {
75
+ "enabled": {
76
+ "type": "boolean"
77
+ },
78
+ "validators": {
79
+ "type": "array",
80
+ "items": {
81
+ "type": "string"
82
+ },
83
+ "uniqueItems": true
84
+ }
85
+ }
86
+ },
87
+ "L1": {
88
+ "type": "object",
89
+ "additionalProperties": false,
90
+ "properties": {
91
+ "enabled": {
92
+ "type": "boolean"
93
+ },
94
+ "rules": {
95
+ "type": "object",
96
+ "additionalProperties": {
97
+ "type": "string"
98
+ }
99
+ }
100
+ }
101
+ },
102
+ "L2": {
103
+ "type": "object",
104
+ "additionalProperties": false,
105
+ "properties": {
106
+ "enabled": {
107
+ "type": "boolean"
108
+ },
109
+ "validators": {
110
+ "type": "array",
111
+ "items": {
112
+ "type": "string"
113
+ },
114
+ "uniqueItems": true
115
+ }
116
+ }
117
+ },
118
+ "L3": {
119
+ "type": "object",
120
+ "additionalProperties": false,
121
+ "properties": {
122
+ "enabled": {
123
+ "type": "boolean"
124
+ },
125
+ "validators": {
126
+ "type": "array",
127
+ "items": {
128
+ "type": "string"
129
+ },
130
+ "uniqueItems": true
131
+ },
132
+ "coverageThreshold": {
133
+ "type": "number",
134
+ "minimum": 0,
135
+ "maximum": 100
136
+ }
137
+ }
138
+ },
139
+ "L4": {
140
+ "type": "object",
141
+ "additionalProperties": false,
142
+ "properties": {
143
+ "enabled": {
144
+ "type": "boolean"
145
+ },
146
+ "validators": {
147
+ "type": "array",
148
+ "items": {
149
+ "type": "string"
150
+ },
151
+ "uniqueItems": true
152
+ },
153
+ "schedule": {
154
+ "type": "string",
155
+ "minLength": 1
156
+ }
157
+ }
158
+ }
159
+ }
160
+ },
161
+ "quickMode": {
162
+ "type": "object",
163
+ "additionalProperties": false,
164
+ "properties": {
165
+ "allowedCategories": {
166
+ "type": "array",
167
+ "items": {
168
+ "type": "string"
169
+ },
170
+ "uniqueItems": true
171
+ },
172
+ "maintainedLayers": {
173
+ "type": "array",
174
+ "items": {
175
+ "type": "string"
176
+ },
177
+ "uniqueItems": true
178
+ },
179
+ "relaxedGates": {
180
+ "type": "array",
181
+ "items": {
182
+ "type": "string"
183
+ },
184
+ "uniqueItems": true
185
+ },
186
+ "fullModeRequiredWhen": {
187
+ "type": "object",
188
+ "additionalProperties": false,
189
+ "properties": {
190
+ "mixedCategories": {
191
+ "type": "boolean"
192
+ },
193
+ "newDomainFile": {
194
+ "type": "boolean"
195
+ },
196
+ "apiContractChange": {
197
+ "type": "boolean"
198
+ }
199
+ }
200
+ }
201
+ }
202
+ },
203
+ "phaseDependencies": {
204
+ "type": "object",
205
+ "additionalProperties": false,
206
+ "required": [
207
+ "preset"
208
+ ],
209
+ "properties": {
210
+ "preset": {
211
+ "type": "string",
212
+ "enum": [
213
+ "default",
214
+ "full",
215
+ "standard",
216
+ "minimal",
217
+ "custom"
218
+ ]
219
+ },
220
+ "override": {
221
+ "type": "boolean"
222
+ },
223
+ "customRules": {
224
+ "type": "array",
225
+ "items": {
226
+ "type": "object",
227
+ "additionalProperties": false,
228
+ "required": [
229
+ "phase",
230
+ "requires"
231
+ ],
232
+ "properties": {
233
+ "phase": {
234
+ "type": "string",
235
+ "minLength": 1
236
+ },
237
+ "requires": {
238
+ "type": "array",
239
+ "items": {
240
+ "type": "string"
241
+ }
242
+ }
243
+ }
244
+ }
245
+ },
246
+ "gates": {
247
+ "type": "array",
248
+ "items": {
249
+ "type": "object",
250
+ "additionalProperties": false,
251
+ "required": [
252
+ "name",
253
+ "level",
254
+ "requires",
255
+ "blocks",
256
+ "dependsOn"
257
+ ],
258
+ "properties": {
259
+ "name": {
260
+ "type": "string",
261
+ "pattern": "^[a-z][a-z0-9-]*$"
262
+ },
263
+ "level": {
264
+ "type": "integer",
265
+ "enum": [
266
+ 1,
267
+ 2,
268
+ 3
269
+ ]
270
+ },
271
+ "requires": {
272
+ "type": "array",
273
+ "items": {
274
+ "type": "object",
275
+ "additionalProperties": false,
276
+ "required": [
277
+ "path",
278
+ "required"
279
+ ],
280
+ "properties": {
281
+ "path": {
282
+ "type": "string",
283
+ "minLength": 1
284
+ },
285
+ "required": {
286
+ "type": "boolean"
287
+ }
288
+ }
289
+ }
290
+ },
291
+ "blocks": {
292
+ "type": "array",
293
+ "items": {
294
+ "type": "string",
295
+ "minLength": 1
296
+ }
297
+ },
298
+ "dependsOn": {
299
+ "type": "array",
300
+ "items": {
301
+ "type": "string",
302
+ "pattern": "^[a-z][a-z0-9-]*$"
303
+ }
304
+ },
305
+ "storyAnnotation": {
306
+ "type": "object",
307
+ "additionalProperties": false,
308
+ "required": [
309
+ "required",
310
+ "tag"
311
+ ],
312
+ "properties": {
313
+ "required": {
314
+ "type": "boolean"
315
+ },
316
+ "tag": {
317
+ "type": "string",
318
+ "minLength": 1
319
+ }
320
+ }
321
+ }
322
+ },
323
+ "allOf": [
324
+ {
325
+ "if": {
326
+ "required": [
327
+ "storyAnnotation"
328
+ ]
329
+ },
330
+ "then": {
331
+ "properties": {
332
+ "level": {
333
+ "const": 3
334
+ }
335
+ }
336
+ }
337
+ }
338
+ ]
339
+ }
340
+ },
341
+ "storyReflection": {
342
+ "type": "object",
343
+ "additionalProperties": false,
344
+ "properties": {
345
+ "enabled": {
346
+ "type": "boolean"
347
+ },
348
+ "mappings": {
349
+ "type": "array",
350
+ "items": {
351
+ "type": "object",
352
+ "additionalProperties": false,
353
+ "required": [
354
+ "unitId",
355
+ "artifacts"
356
+ ],
357
+ "properties": {
358
+ "unitId": {
359
+ "type": "string",
360
+ "minLength": 1
361
+ },
362
+ "artifacts": {
363
+ "type": "array",
364
+ "items": {
365
+ "type": "string",
366
+ "minLength": 1
367
+ }
368
+ }
369
+ }
370
+ }
371
+ }
372
+ }
373
+ }
374
+ }
375
+ },
376
+ "planningMode": {
377
+ "type": "object",
378
+ "additionalProperties": false,
379
+ "required": [
380
+ "default",
381
+ "perPhase"
382
+ ],
383
+ "properties": {
384
+ "default": {
385
+ "type": "string",
386
+ "enum": [
387
+ "interactive",
388
+ "embedded-qa"
389
+ ]
390
+ },
391
+ "perPhase": {
392
+ "type": "object",
393
+ "additionalProperties": {
394
+ "type": "string",
395
+ "enum": [
396
+ "interactive",
397
+ "embedded-qa"
398
+ ]
399
+ }
400
+ }
401
+ }
402
+ },
403
+ "harnesses": {
404
+ "type": "object",
405
+ "additionalProperties": false,
406
+ "properties": {
407
+ "agentLessonCollection": {
408
+ "type": "boolean"
409
+ },
410
+ "cascadeUpdate": {
411
+ "type": "boolean"
412
+ },
413
+ "bundleSizeLimit": {
414
+ "type": "number",
415
+ "minimum": 0
416
+ },
417
+ "deadCodeGC": {
418
+ "type": "boolean"
419
+ }
420
+ }
421
+ },
422
+ "paths": {
423
+ "type": "object",
424
+ "additionalProperties": false,
425
+ "required": [
426
+ "designDocs",
427
+ "inceptionDocs"
428
+ ],
429
+ "properties": {
430
+ "designDocs": {
431
+ "type": "string",
432
+ "minLength": 1
433
+ },
434
+ "inceptionDocs": {
435
+ "type": "string",
436
+ "minLength": 1
437
+ }
438
+ }
439
+ },
440
+ "reporting": {
441
+ "type": "object",
442
+ "additionalProperties": false,
443
+ "required": [
444
+ "format",
445
+ "outputDir"
446
+ ],
447
+ "properties": {
448
+ "format": {
449
+ "type": "string",
450
+ "minLength": 1
451
+ },
452
+ "outputDir": {
453
+ "type": "string",
454
+ "minLength": 1
455
+ }
456
+ }
457
+ },
458
+ "protectedFiles": {
459
+ "type": "object",
460
+ "additionalProperties": false,
461
+ "properties": {
462
+ "exclude": {
463
+ "type": "array",
464
+ "items": {
465
+ "type": "string",
466
+ "minLength": 1
467
+ },
468
+ "uniqueItems": true
469
+ }
470
+ }
471
+ },
472
+ "baseline": {
473
+ "type": "object",
474
+ "additionalProperties": false,
475
+ "properties": {
476
+ "enabled": {
477
+ "type": "boolean"
478
+ },
479
+ "path": {
480
+ "type": "string",
481
+ "minLength": 1
482
+ }
483
+ }
484
+ },
485
+ "architecture": {
486
+ "type": "object",
487
+ "additionalProperties": false,
488
+ "required": ["preset"],
489
+ "properties": {
490
+ "preset": {
491
+ "type": "string",
492
+ "enum": ["clean", "strict-ddd", "onion", "hexagonal", "layered", "flat", "custom"]
493
+ },
494
+ "layers": {
495
+ "type": "array",
496
+ "items": {
497
+ "type": "string",
498
+ "pattern": "^[a-z][a-z0-9-]*$",
499
+ "minLength": 1
500
+ },
501
+ "uniqueItems": true,
502
+ "minItems": 1
503
+ },
504
+ "allowedDependencies": {
505
+ "type": "object",
506
+ "additionalProperties": {
507
+ "type": "array",
508
+ "items": {
509
+ "type": "string",
510
+ "pattern": "^[a-z][a-z0-9-]*$"
511
+ },
512
+ "uniqueItems": true
513
+ }
514
+ },
515
+ "metadataTags": {
516
+ "type": "object",
517
+ "additionalProperties": false,
518
+ "properties": {
519
+ "layer": {
520
+ "type": "string",
521
+ "pattern": "^@[a-z][a-zA-Z0-9]*$"
522
+ },
523
+ "unit": {
524
+ "type": "string",
525
+ "pattern": "^@[a-z][a-zA-Z0-9]*$"
526
+ }
527
+ }
528
+ },
529
+ "layerDetection": {
530
+ "type": "object",
531
+ "additionalProperties": false,
532
+ "properties": {
533
+ "byPath": { "type": "boolean" },
534
+ "byTag": { "type": "boolean" }
535
+ }
536
+ }
537
+ },
538
+ "allOf": [
539
+ {
540
+ "if": { "properties": { "preset": { "const": "custom" } }, "required": ["preset"] },
541
+ "then": { "required": ["preset", "layers", "allowedDependencies"] }
542
+ }
543
+ ]
544
+ }
545
+ }
546
+ }
@@ -18,19 +18,28 @@ type HarnessErrorWithPath = HarnessError & {
18
18
  };
19
19
 
20
20
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
21
- const SCHEMA_PATH = path.resolve(__dirname, '../schemas/harness-config-v2.schema.json');
21
+ const SCHEMA_V2_PATH = path.resolve(__dirname, '../schemas/harness-config-v2.schema.json');
22
+ const SCHEMA_V3_PATH = path.resolve(__dirname, '../schemas/harness-config-v3.schema.json');
22
23
 
23
- function loadSchema(): object {
24
- const raw = fs.readFileSync(SCHEMA_PATH, 'utf8');
24
+ function loadSchemaFromPath(schemaPath: string): object {
25
+ const raw = fs.readFileSync(schemaPath, 'utf8');
25
26
  return JSON.parse(raw) as object;
26
27
  }
27
28
 
28
- function createValidateFunction(): ValidateFunction {
29
+ function createValidateFunction(schemaPath: string): ValidateFunction {
29
30
  const ajv = new Ajv({
30
31
  allErrors: true,
31
32
  });
32
33
 
33
- return ajv.compile(loadSchema());
34
+ return ajv.compile(loadSchemaFromPath(schemaPath));
35
+ }
36
+
37
+ function detectSchemaVersion(document: unknown): 'v2' | 'v3' {
38
+ if (typeof document === 'object' && document !== null && 'architecture' in document) {
39
+ return 'v3';
40
+ }
41
+
42
+ return 'v2';
34
43
  }
35
44
 
36
45
  function buildPath(error: ErrorObject): string {
@@ -100,10 +109,13 @@ function toHarnessError(error: ErrorObject): HarnessErrorWithPath {
100
109
  });
101
110
  }
102
111
 
103
- const validateSchema = createValidateFunction();
112
+ const validateSchemaV2 = createValidateFunction(SCHEMA_V2_PATH);
113
+ const validateSchemaV3 = createValidateFunction(SCHEMA_V3_PATH);
104
114
 
105
115
  export class AjvConfigSchemaValidator implements ConfigSchemaValidatorPort {
106
116
  validate(document: unknown): readonly HarnessError[] {
117
+ const schemaVersion = detectSchemaVersion(document);
118
+ const validateSchema = schemaVersion === 'v3' ? validateSchemaV3 : validateSchemaV2;
107
119
  const valid = validateSchema(document);
108
120
 
109
121
  if (valid) {
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @layer presentation
3
+ * @unit config-foundation
4
+ *
5
+ * `phasegate migrate --schema v3` のハンドラー。
6
+ * phasegate.config.json に `architecture` キーが無い v2 config を検出したら
7
+ * `architecture: { preset: "clean" }` を追記して v3 化する。既に v3 の場合は no-op。
8
+ */
9
+
10
+ import type { MigrateSchemaOutput } from '../../application/usecases/migrate-schema-use-case.js';
11
+
12
+ export interface MigrateSchemaCommandInput {
13
+ readonly targetVersion: string;
14
+ readonly configPath?: string;
15
+ }
16
+
17
+ export interface MigrateSchemaCommandOutput {
18
+ readonly exitCode: number;
19
+ readonly output: string;
20
+ }
21
+
22
+ export interface MigrateSchemaPort {
23
+ execute(input: {
24
+ targetVersion: 'v3';
25
+ configPath?: string;
26
+ }): Promise<Readonly<MigrateSchemaOutput>>;
27
+ }
28
+
29
+ export interface MigrateSchemaCommandHandlerDeps {
30
+ readonly migrateSchemaUseCase: MigrateSchemaPort;
31
+ }
32
+
33
+ export class MigrateSchemaCommandHandler {
34
+ private readonly migrateSchemaUseCase: MigrateSchemaPort;
35
+
36
+ constructor(deps: MigrateSchemaCommandHandlerDeps) {
37
+ this.migrateSchemaUseCase = deps.migrateSchemaUseCase;
38
+ }
39
+
40
+ async execute(
41
+ input: MigrateSchemaCommandInput,
42
+ ): Promise<MigrateSchemaCommandOutput> {
43
+ if (input.targetVersion !== 'v3') {
44
+ return {
45
+ exitCode: 2,
46
+ output:
47
+ `Error: unsupported --schema version "${input.targetVersion}". Only "v3" is supported.`,
48
+ };
49
+ }
50
+
51
+ try {
52
+ const result = await this.migrateSchemaUseCase.execute({
53
+ targetVersion: 'v3',
54
+ configPath: input.configPath,
55
+ });
56
+
57
+ if (result.alreadyUpToDate) {
58
+ return {
59
+ exitCode: 0,
60
+ output: `✓ ${result.configPath} is already schema v3 (architecture key present). No changes applied.`,
61
+ };
62
+ }
63
+
64
+ const changes = result.appliedChanges.map((c) => ` - ${c}`).join('\n');
65
+ return {
66
+ exitCode: 0,
67
+ output: [
68
+ `✓ Migrated ${result.configPath} to schema v3.`,
69
+ 'Applied changes:',
70
+ changes,
71
+ '',
72
+ '補足: `architecture.preset` の既定値は "clean"。onion / hexagonal / layered / flat 等を採用している場合は手動で変更してください(docs/guide/preset-selection.md 参照)。',
73
+ ].join('\n'),
74
+ };
75
+ } catch (error: unknown) {
76
+ const message = error instanceof Error ? error.message : String(error);
77
+ return {
78
+ exitCode: 1,
79
+ output: `Error: ${message}`,
80
+ };
81
+ }
82
+ }
83
+ }