@clawplays/ospec-cli 0.3.7 → 0.3.9

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 (166) hide show
  1. package/README.md +9 -1
  2. package/SKILL.md +1 -1
  3. package/assets/git-hooks/post-merge +4 -2
  4. package/assets/git-hooks/pre-commit +4 -2
  5. package/dist/advanced/BatchOperations.d.ts +1 -2
  6. package/dist/advanced/BatchOperations.js +1 -2
  7. package/dist/advanced/CachingLayer.d.ts +1 -2
  8. package/dist/advanced/CachingLayer.js +1 -2
  9. package/dist/advanced/FeatureUpdater.d.ts +1 -2
  10. package/dist/advanced/FeatureUpdater.js +1 -2
  11. package/dist/advanced/PerformanceMonitor.d.ts +1 -2
  12. package/dist/advanced/PerformanceMonitor.js +1 -2
  13. package/dist/advanced/StatePersistence.d.ts +1 -2
  14. package/dist/advanced/StatePersistence.js +1 -2
  15. package/dist/advanced/index.d.ts +1 -2
  16. package/dist/advanced/index.js +1 -2
  17. package/dist/cli/commands/config.d.ts +1 -2
  18. package/dist/cli/commands/config.js +1 -2
  19. package/dist/cli/commands/feature.d.ts +1 -2
  20. package/dist/cli/commands/feature.js +1 -2
  21. package/dist/cli/commands/index.d.ts +1 -2
  22. package/dist/cli/commands/index.js +1 -2
  23. package/dist/cli/commands/project.d.ts +1 -2
  24. package/dist/cli/commands/project.js +1 -2
  25. package/dist/cli/commands/validate.d.ts +1 -2
  26. package/dist/cli/commands/validate.js +1 -2
  27. package/dist/cli/index.d.ts +1 -2
  28. package/dist/cli/index.js +1 -2
  29. package/dist/cli.d.ts +1 -2
  30. package/dist/cli.js +1 -2
  31. package/dist/commands/ArchiveCommand.d.ts +1 -2
  32. package/dist/commands/ArchiveCommand.js +1 -1
  33. package/dist/commands/BaseCommand.d.ts +1 -2
  34. package/dist/commands/BaseCommand.js +1 -2
  35. package/dist/commands/BatchCommand.d.ts +1 -2
  36. package/dist/commands/BatchCommand.js +1 -2
  37. package/dist/commands/ChangesCommand.js +0 -1
  38. package/dist/commands/DocsCommand.d.ts +1 -2
  39. package/dist/commands/DocsCommand.js +0 -1
  40. package/dist/commands/IndexCommand.d.ts +1 -2
  41. package/dist/commands/IndexCommand.js +1 -2
  42. package/dist/commands/InitCommand.d.ts +1 -2
  43. package/dist/commands/InitCommand.js +0 -1
  44. package/dist/commands/NewCommand.d.ts +0 -1
  45. package/dist/commands/NewCommand.js +19 -12
  46. package/dist/commands/PluginsCommand.d.ts +0 -1
  47. package/dist/commands/PluginsCommand.js +0 -1
  48. package/dist/commands/ProgressCommand.d.ts +1 -2
  49. package/dist/commands/ProgressCommand.js +1 -2
  50. package/dist/commands/QueueCommand.d.ts +0 -1
  51. package/dist/commands/QueueCommand.js +0 -1
  52. package/dist/commands/RunCommand.d.ts +0 -1
  53. package/dist/commands/RunCommand.js +0 -1
  54. package/dist/commands/SkillCommand.d.ts +0 -1
  55. package/dist/commands/SkillCommand.js +1 -2
  56. package/dist/commands/SkillsCommand.d.ts +1 -2
  57. package/dist/commands/SkillsCommand.js +1 -2
  58. package/dist/commands/StatusCommand.d.ts +1 -2
  59. package/dist/commands/StatusCommand.js +0 -1
  60. package/dist/commands/UpdateCommand.d.ts +0 -1
  61. package/dist/commands/UpdateCommand.js +37 -2
  62. package/dist/commands/VerifyCommand.d.ts +1 -2
  63. package/dist/commands/VerifyCommand.js +4 -41
  64. package/dist/commands/WorkflowCommand.d.ts +0 -1
  65. package/dist/commands/WorkflowCommand.js +0 -1
  66. package/dist/commands/index.d.ts +0 -1
  67. package/dist/commands/index.js +0 -1
  68. package/dist/core/constants.d.ts +1 -2
  69. package/dist/core/constants.js +1 -2
  70. package/dist/core/errors.d.ts +1 -2
  71. package/dist/core/errors.js +1 -2
  72. package/dist/core/index.d.ts +1 -2
  73. package/dist/core/index.js +1 -2
  74. package/dist/core/types.d.ts +0 -1
  75. package/dist/core/types.js +1 -2
  76. package/dist/index.d.ts +1 -2
  77. package/dist/index.js +1 -2
  78. package/dist/presets/ProjectPresets.d.ts +0 -1
  79. package/dist/presets/ProjectPresets.js +0 -1
  80. package/dist/scaffolds/ProjectScaffoldPresets.d.ts +1 -2
  81. package/dist/scaffolds/ProjectScaffoldPresets.js +1 -2
  82. package/dist/services/ConfigManager.d.ts +1 -2
  83. package/dist/services/ConfigManager.js +0 -1
  84. package/dist/services/FeatureManager.d.ts +1 -2
  85. package/dist/services/FeatureManager.js +1 -2
  86. package/dist/services/FileService.d.ts +1 -2
  87. package/dist/services/FileService.js +0 -1
  88. package/dist/services/IndexBuilder.d.ts +1 -2
  89. package/dist/services/IndexBuilder.js +1 -2
  90. package/dist/services/Logger.d.ts +1 -2
  91. package/dist/services/Logger.js +1 -2
  92. package/dist/services/ProjectAssetRegistry.d.ts +0 -1
  93. package/dist/services/ProjectAssetRegistry.js +1 -2
  94. package/dist/services/ProjectAssetService.d.ts +0 -1
  95. package/dist/services/ProjectAssetService.js +4 -2
  96. package/dist/services/ProjectScaffoldCommandService.d.ts +1 -2
  97. package/dist/services/ProjectScaffoldCommandService.js +0 -1
  98. package/dist/services/ProjectScaffoldService.d.ts +1 -2
  99. package/dist/services/ProjectScaffoldService.js +0 -1
  100. package/dist/services/ProjectService.d.ts +1 -1
  101. package/dist/services/ProjectService.js +267 -411
  102. package/dist/services/QueueService.d.ts +0 -1
  103. package/dist/services/QueueService.js +1 -1
  104. package/dist/services/RunService.d.ts +0 -1
  105. package/dist/services/RunService.js +0 -1
  106. package/dist/services/SkillParser.d.ts +1 -2
  107. package/dist/services/SkillParser.js +0 -1
  108. package/dist/services/StateManager.d.ts +0 -1
  109. package/dist/services/StateManager.js +0 -1
  110. package/dist/services/TemplateEngine.d.ts +1 -2
  111. package/dist/services/TemplateEngine.js +1 -2
  112. package/dist/services/TemplateGenerator.d.ts +1 -2
  113. package/dist/services/TemplateGenerator.js +6 -7
  114. package/dist/services/ValidationService.d.ts +1 -2
  115. package/dist/services/ValidationService.js +1 -2
  116. package/dist/services/Validator.d.ts +1 -2
  117. package/dist/services/Validator.js +1 -2
  118. package/dist/services/index.d.ts +0 -1
  119. package/dist/services/index.js +0 -1
  120. package/dist/services/templates/ExecutionTemplateBuilder.d.ts +1 -2
  121. package/dist/services/templates/ExecutionTemplateBuilder.js +52 -29
  122. package/dist/services/templates/ProjectTemplateBuilder.d.ts +1 -2
  123. package/dist/services/templates/ProjectTemplateBuilder.js +0 -1
  124. package/dist/services/templates/TemplateBuilderBase.d.ts +5 -1
  125. package/dist/services/templates/TemplateBuilderBase.js +31 -3
  126. package/dist/services/templates/TemplateInputFactory.d.ts +1 -2
  127. package/dist/services/templates/TemplateInputFactory.js +4 -1
  128. package/dist/services/templates/templateTypes.d.ts +4 -1
  129. package/dist/services/templates/templateTypes.js +1 -2
  130. package/dist/tools/build-index.js +128 -36
  131. package/dist/utils/DateUtils.d.ts +1 -2
  132. package/dist/utils/DateUtils.js +1 -2
  133. package/dist/utils/PathUtils.d.ts +0 -1
  134. package/dist/utils/PathUtils.js +0 -1
  135. package/dist/utils/StringUtils.d.ts +1 -2
  136. package/dist/utils/StringUtils.js +1 -2
  137. package/dist/utils/helpers.d.ts +0 -1
  138. package/dist/utils/helpers.js +0 -1
  139. package/dist/utils/index.d.ts +1 -2
  140. package/dist/utils/index.js +1 -2
  141. package/dist/utils/logger.d.ts +1 -2
  142. package/dist/utils/logger.js +1 -2
  143. package/dist/utils/path.d.ts +1 -2
  144. package/dist/utils/path.js +1 -2
  145. package/dist/utils/subcommandHelp.d.ts +0 -1
  146. package/dist/utils/subcommandHelp.js +0 -1
  147. package/dist/workflow/ArchiveGate.d.ts +1 -2
  148. package/dist/workflow/ArchiveGate.js +1 -2
  149. package/dist/workflow/ConfigurableWorkflow.d.ts +1 -2
  150. package/dist/workflow/ConfigurableWorkflow.js +1 -2
  151. package/dist/workflow/HookSystem.d.ts +1 -2
  152. package/dist/workflow/HookSystem.js +1 -2
  153. package/dist/workflow/IndexRegenerator.d.ts +1 -2
  154. package/dist/workflow/IndexRegenerator.js +1 -2
  155. package/dist/workflow/PluginWorkflowComposer.d.ts +0 -1
  156. package/dist/workflow/PluginWorkflowComposer.js +0 -1
  157. package/dist/workflow/SkillUpdateEngine.d.ts +1 -2
  158. package/dist/workflow/SkillUpdateEngine.js +1 -2
  159. package/dist/workflow/VerificationSystem.d.ts +1 -2
  160. package/dist/workflow/VerificationSystem.js +1 -2
  161. package/dist/workflow/WorkflowEngine.d.ts +1 -2
  162. package/dist/workflow/WorkflowEngine.js +1 -2
  163. package/dist/workflow/index.d.ts +0 -1
  164. package/dist/workflow/index.js +0 -1
  165. package/package.json +17 -8
  166. package/skill.yaml +2 -2
@@ -4545,6 +4545,7 @@ class ProjectService {
4545
4545
 
4546
4546
 
4547
4547
 
4548
+ await this.rebaseMovedChangeMarkdownLinks(resolvedFeaturePath, archivePath);
4548
4549
  await this.rebuildIndex(projectRoot);
4549
4550
 
4550
4551
 
@@ -4593,6 +4594,51 @@ class ProjectService {
4593
4594
 
4594
4595
 
4595
4596
 
4597
+ async rebaseMovedChangeMarkdownLinks(previousChangePath, nextChangePath) {
4598
+ const previousRoot = path_1.default.resolve(previousChangePath);
4599
+ const nextRoot = path_1.default.resolve(nextChangePath);
4600
+ const markdownFiles = [
4601
+ constants_1.FILE_NAMES.PROPOSAL,
4602
+ constants_1.FILE_NAMES.TASKS,
4603
+ constants_1.FILE_NAMES.VERIFICATION,
4604
+ constants_1.FILE_NAMES.REVIEW,
4605
+ ];
4606
+ for (const fileName of markdownFiles) {
4607
+ const nextFilePath = path_1.default.join(nextRoot, fileName);
4608
+ if (!(await this.fileService.exists(nextFilePath))) {
4609
+ continue;
4610
+ }
4611
+ const previousFilePath = path_1.default.join(previousRoot, fileName);
4612
+ const originalContent = await this.fileService.readFile(nextFilePath);
4613
+ const previousDir = path_1.default.dirname(previousFilePath);
4614
+ const nextDir = path_1.default.dirname(nextFilePath);
4615
+ const rewrittenContent = originalContent.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, label, rawHref) => {
4616
+ const href = String(rawHref || '').trim();
4617
+ if (!this.isRelativeMarkdownHref(href)) {
4618
+ return match;
4619
+ }
4620
+ const previousTargetPath = path_1.default.resolve(previousDir, href);
4621
+ if (this.isPathWithin(previousTargetPath, previousRoot)) {
4622
+ return match;
4623
+ }
4624
+ const rebasedHref = path_1.default.relative(nextDir, previousTargetPath).replace(/\\/g, '/');
4625
+ return `[${label}](${rebasedHref || '.'})`;
4626
+ });
4627
+ if (rewrittenContent !== originalContent) {
4628
+ await this.fileService.writeFile(nextFilePath, rewrittenContent);
4629
+ }
4630
+ }
4631
+ }
4632
+ isRelativeMarkdownHref(href) {
4633
+ return Boolean(href) &&
4634
+ !href.startsWith('#') &&
4635
+ !href.startsWith('//') &&
4636
+ !/^[a-z][a-z0-9+.-]*:/i.test(href);
4637
+ }
4638
+ isPathWithin(targetPath, parentPath) {
4639
+ const relativePath = path_1.default.relative(parentPath, targetPath);
4640
+ return relativePath === '' || (!relativePath.startsWith('..') && !path_1.default.isAbsolute(relativePath));
4641
+ }
4596
4642
  async getFeatureProjectContext(rootDir, affects = []) {
4597
4643
 
4598
4644
 
@@ -5275,7 +5321,8 @@ class ProjectService {
5275
5321
  }
5276
5322
  async syncConfigDocumentLanguage(rootDir, config, documentLanguage) {
5277
5323
  const normalized = this.normalizeDocumentLanguage(documentLanguage);
5278
- if (!normalized || config?.documentLanguage === normalized) {
5324
+ const configured = this.normalizeDocumentLanguage(config?.documentLanguage);
5325
+ if (!normalized || configured) {
5279
5326
  return false;
5280
5327
  }
5281
5328
  config.documentLanguage = normalized;
@@ -5284,13 +5331,28 @@ class ProjectService {
5284
5331
  }
5285
5332
 
5286
5333
  detectDocumentLanguageFromTexts(contents) {
5287
- for (const content of contents) {
5334
+ const detectionCounts = new Map();
5335
+ const firstSeenOrder = new Map();
5336
+ for (const [index, content] of contents.entries()) {
5288
5337
  const detected = this.detectDocumentLanguageFromText(content);
5289
5338
  if (detected) {
5290
- return detected;
5339
+ detectionCounts.set(detected, (detectionCounts.get(detected) || 0) + 1);
5340
+ if (!firstSeenOrder.has(detected)) {
5341
+ firstSeenOrder.set(detected, index);
5342
+ }
5291
5343
  }
5292
5344
  }
5293
- return undefined;
5345
+ if (detectionCounts.size === 0) {
5346
+ return undefined;
5347
+ }
5348
+ return Array.from(detectionCounts.entries())
5349
+ .sort((left, right) => {
5350
+ if (right[1] !== left[1]) {
5351
+ return right[1] - left[1];
5352
+ }
5353
+ return (firstSeenOrder.get(left[0]) ?? Number.MAX_SAFE_INTEGER) -
5354
+ (firstSeenOrder.get(right[0]) ?? Number.MAX_SAFE_INTEGER);
5355
+ })[0][0];
5294
5356
  }
5295
5357
  detectDocumentLanguageFromText(content) {
5296
5358
  if (typeof content !== 'string' || content.trim().length === 0) {
@@ -5299,28 +5361,28 @@ class ProjectService {
5299
5361
  if (/[\u0600-\u06FF]/.test(content)) {
5300
5362
  return 'ar';
5301
5363
  }
5302
- if (/[ぁ-ゟ゠-ヿ]/.test(content)) {
5303
- return 'ja-JP';
5304
- }
5305
- if (this.isLikelyJapaneseKanjiContent(content)) {
5364
+ if (this.hasJapaneseKana(content)) {
5306
5365
  return 'ja-JP';
5307
5366
  }
5308
- if (/[一-龥]/.test(content)) {
5309
- return 'zh-CN';
5367
+ if (this.hasCjkIdeographs(content)) {
5368
+ return this.isLikelyJapaneseKanjiContent(content) ? 'ja-JP' : 'zh-CN';
5310
5369
  }
5311
5370
  if (/[A-Za-z]/.test(content)) {
5312
5371
  return 'en-US';
5313
5372
  }
5314
5373
  return undefined;
5315
5374
  }
5375
+ hasJapaneseKana(content) {
5376
+ return /[\u3040-\u30FF]/.test(content);
5377
+ }
5378
+ hasCjkIdeographs(content) {
5379
+ return /[\u3400-\u9FFF]/.test(content);
5380
+ }
5316
5381
  isLikelyJapaneseKanjiContent(content) {
5317
- if (!/[一-龥]/.test(content)) {
5382
+ if (!this.hasCjkIdeographs(content)) {
5318
5383
  return false;
5319
5384
  }
5320
- if (/[々〆ヵヶ「」『』]/.test(content)) {
5321
- return true;
5322
- }
5323
- return /(一覧|詳細|設定|権限|検索|構成|変更|確認|対応|連携|承認|申請|手順|履歴|機能|実装|設計|運用|画面|帳票|組織|拠点|区分|種別|完了|開始|終了|表示|取得|追加|削除|更新|登録)/.test(content);
5385
+ return /[\u3005\u3006\u300C-\u300F\u30F5\u30F6]/.test(content);
5324
5386
  }
5325
5387
 
5326
5388
 
@@ -7395,10 +7457,16 @@ class ProjectService {
7395
7457
 
7396
7458
  let exists = await this.fileService.exists(filePath);
7397
7459
  if (!exists && definition.key === constants_1.FILE_NAMES.BUILD_INDEX_SCRIPT) {
7398
- const legacyBuildIndexScriptPath = path_1.default.join(rootDir, 'build-index-auto.js');
7399
- if (await this.fileService.exists(legacyBuildIndexScriptPath)) {
7400
- filePath = legacyBuildIndexScriptPath;
7401
- exists = true;
7460
+ const legacyBuildIndexScriptPaths = [
7461
+ path_1.default.join(rootDir, 'build-index-auto.cjs'),
7462
+ path_1.default.join(rootDir, 'build-index-auto.js'),
7463
+ ];
7464
+ for (const legacyBuildIndexScriptPath of legacyBuildIndexScriptPaths) {
7465
+ if (await this.fileService.exists(legacyBuildIndexScriptPath)) {
7466
+ filePath = legacyBuildIndexScriptPath;
7467
+ exists = true;
7468
+ break;
7469
+ }
7402
7470
  }
7403
7471
  }
7404
7472
 
@@ -11034,197 +11102,103 @@ ${formatSuggestion()}
11034
11102
 
11035
11103
 
11036
11104
  const content = await this.fileService.readFile(filePath);
11037
-
11038
-
11039
-
11040
-
11041
-
11042
-
11043
-
11044
- const parsed = (0, gray_matter_1.default)(content);
11045
-
11046
-
11047
-
11048
-
11049
-
11050
-
11051
-
11052
- const optionalSteps = Array.isArray(parsed.data.optional_steps) ? parsed.data.optional_steps : [];
11053
-
11054
-
11055
-
11056
-
11057
-
11058
-
11059
-
11060
- const missing = activatedSteps.filter(step => !optionalSteps.includes(step));
11061
-
11062
-
11063
-
11064
-
11065
-
11066
-
11067
-
11068
- const checklistComplete = !/- \[ \]/.test(content);
11069
-
11070
-
11071
-
11072
-
11073
-
11074
-
11075
-
11105
+ const hasFrontmatter = /^---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/.test(content);
11106
+ let parsed = null;
11107
+ let parseError = null;
11108
+ if (hasFrontmatter) {
11109
+ try {
11110
+ parsed = (0, gray_matter_1.default)(content);
11111
+ }
11112
+ catch (error) {
11113
+ parseError = error;
11114
+ }
11115
+ }
11116
+ const data = parsed?.data ?? {};
11117
+ const optionalStepsFieldValid = Array.isArray(data.optional_steps);
11118
+ const optionalSteps = optionalStepsFieldValid ? data.optional_steps : [];
11119
+ const createdFieldValid = (typeof data.created === 'string' && data.created.trim().length > 0) ||
11120
+ (data.created instanceof Date && !Number.isNaN(data.created.getTime()));
11121
+ const missingRequiredFields = [];
11122
+ if (typeof data.feature !== 'string' || data.feature.trim().length === 0) {
11123
+ missingRequiredFields.push('feature');
11124
+ }
11125
+ if (!createdFieldValid) {
11126
+ missingRequiredFields.push('created');
11127
+ }
11128
+ if (!optionalStepsFieldValid) {
11129
+ missingRequiredFields.push('optional_steps');
11130
+ }
11131
+ const missing = optionalStepsFieldValid
11132
+ ? activatedSteps.filter(step => !optionalSteps.includes(step))
11133
+ : [...activatedSteps];
11134
+ const checklistItems = parsed?.content.match(/^\s*-\s+\[(?: |x|X)\]\s+.+$/gm) ?? [];
11135
+ const uncheckedItems = parsed?.content.match(/^\s*-\s+\[ \]\s+.+$/gm) ?? [];
11136
+ const checklistStructureValid = checklistItems.length > 0;
11137
+ const checklistComplete = hasFrontmatter &&
11138
+ parseError === null &&
11139
+ missingRequiredFields.length === 0 &&
11140
+ checklistStructureValid &&
11141
+ uncheckedItems.length === 0;
11142
+ let frontmatterMessage = `${name} frontmatter parsed successfully`;
11143
+ if (!hasFrontmatter) {
11144
+ frontmatterMessage = `${name} is missing a valid frontmatter block`;
11145
+ }
11146
+ else if (parseError) {
11147
+ frontmatterMessage = `${name} frontmatter cannot be parsed: ${parseError.message}`;
11148
+ }
11149
+ let requiredFieldsMessage = `${name} has all required frontmatter fields`;
11150
+ if (!hasFrontmatter || parseError) {
11151
+ requiredFieldsMessage = `Cannot validate required fields in ${name} because frontmatter is invalid`;
11152
+ }
11153
+ else if (missingRequiredFields.length > 0) {
11154
+ requiredFieldsMessage = `Missing or invalid required fields in ${name}: ${missingRequiredFields.join(', ')}`;
11155
+ }
11156
+ let optionalStepsMessage = `All activated optional steps are present in ${name}`;
11157
+ if (!optionalStepsFieldValid) {
11158
+ optionalStepsMessage = `${name} frontmatter field optional_steps must be an array`;
11159
+ }
11160
+ else if (missing.length > 0) {
11161
+ optionalStepsMessage = `Missing optional steps in ${name}: ${missing.join(', ')}`;
11162
+ }
11163
+ let checklistStatus = 'pass';
11164
+ let checklistMessage = `${name} checklist is complete`;
11165
+ if (!hasFrontmatter || parseError) {
11166
+ checklistStatus = 'fail';
11167
+ checklistMessage = `${name} checklist cannot be validated because frontmatter is invalid`;
11168
+ }
11169
+ else if (!checklistStructureValid) {
11170
+ checklistStatus = 'fail';
11171
+ checklistMessage = `${name} must contain at least one Markdown checklist item`;
11172
+ }
11173
+ else if (uncheckedItems.length > 0) {
11174
+ checklistStatus = 'warn';
11175
+ checklistMessage = `${name} still has unchecked items`;
11176
+ }
11076
11177
  return {
11077
-
11078
-
11079
-
11080
-
11081
-
11082
-
11083
-
11084
11178
  optionalSteps,
11085
-
11086
-
11087
-
11088
-
11089
-
11090
-
11091
-
11092
11179
  checklistComplete,
11093
-
11094
-
11095
-
11096
-
11097
-
11098
-
11099
-
11100
11180
  checks: [
11101
-
11102
-
11103
-
11104
-
11105
-
11106
-
11107
-
11108
11181
  {
11109
-
11110
-
11111
-
11112
-
11113
-
11114
-
11115
-
11182
+ name: `${name}.frontmatter`,
11183
+ status: hasFrontmatter && parseError === null ? 'pass' : 'fail',
11184
+ message: frontmatterMessage,
11185
+ },
11186
+ {
11187
+ name: `${name}.required_fields`,
11188
+ status: hasFrontmatter && parseError === null && missingRequiredFields.length === 0 ? 'pass' : 'fail',
11189
+ message: requiredFieldsMessage,
11190
+ },
11191
+ {
11116
11192
  name: `${name}.optional_steps`,
11117
-
11118
-
11119
-
11120
-
11121
-
11122
-
11123
-
11124
- status: missing.length === 0 ? 'pass' : 'fail',
11125
-
11126
-
11127
-
11128
-
11129
-
11130
-
11131
-
11132
- message: missing.length === 0
11133
-
11134
-
11135
-
11136
-
11137
-
11138
-
11139
-
11140
- ? `All activated optional steps are present in ${name}`
11141
-
11142
-
11143
-
11144
-
11145
-
11146
-
11147
-
11148
- : `Missing optional steps in ${name}: ${missing.join(', ')}`,
11149
-
11150
-
11151
-
11152
-
11153
-
11154
-
11155
-
11193
+ status: optionalStepsFieldValid && missing.length === 0 ? 'pass' : 'fail',
11194
+ message: optionalStepsMessage,
11156
11195
  },
11157
-
11158
-
11159
-
11160
-
11161
-
11162
-
11163
-
11164
11196
  {
11165
-
11166
-
11167
-
11168
-
11169
-
11170
-
11171
-
11172
11197
  name: `${name}.checklist`,
11173
-
11174
-
11175
-
11176
-
11177
-
11178
-
11179
-
11180
- status: checklistComplete ? 'pass' : 'warn',
11181
-
11182
-
11183
-
11184
-
11185
-
11186
-
11187
-
11188
- message: checklistComplete
11189
-
11190
-
11191
-
11192
-
11193
-
11194
-
11195
-
11196
- ? `${name} checklist is complete`
11197
-
11198
-
11199
-
11200
-
11201
-
11202
-
11203
-
11204
- : `${name} still has unchecked items`,
11205
-
11206
-
11207
-
11208
-
11209
-
11210
-
11211
-
11198
+ status: checklistStatus,
11199
+ message: checklistMessage,
11212
11200
  },
11213
-
11214
-
11215
-
11216
-
11217
-
11218
-
11219
-
11220
11201
  ],
11221
-
11222
-
11223
-
11224
-
11225
-
11226
-
11227
-
11228
11202
  };
11229
11203
 
11230
11204
 
@@ -11250,229 +11224,112 @@ ${formatSuggestion()}
11250
11224
 
11251
11225
 
11252
11226
  const content = await this.fileService.readFile(filePath);
11253
-
11254
-
11255
-
11256
-
11257
-
11258
-
11259
-
11260
- const parsed = (0, gray_matter_1.default)(content);
11261
-
11262
-
11263
-
11264
-
11265
-
11266
-
11267
-
11268
- const optionalSteps = Array.isArray(parsed.data.optional_steps) ? parsed.data.optional_steps : [];
11269
-
11270
-
11271
-
11272
-
11273
-
11274
-
11275
-
11276
- const passedOptionalSteps = Array.isArray(parsed.data.passed_optional_steps)
11277
-
11278
-
11279
-
11280
-
11281
-
11282
-
11283
-
11284
- ? parsed.data.passed_optional_steps
11285
-
11286
-
11287
-
11288
-
11289
-
11290
-
11291
-
11292
- : [];
11293
-
11294
-
11295
-
11296
-
11297
-
11298
-
11299
-
11300
- const missing = activatedSteps.filter(step => !optionalSteps.includes(step));
11301
-
11302
-
11303
-
11304
-
11305
-
11306
-
11307
-
11308
- const checklistComplete = !/- \[ \]/.test(content);
11309
-
11310
-
11311
-
11312
-
11313
-
11314
-
11315
-
11227
+ const hasFrontmatter = /^---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/.test(content);
11228
+ let parsed = null;
11229
+ let parseError = null;
11230
+ if (hasFrontmatter) {
11231
+ try {
11232
+ parsed = (0, gray_matter_1.default)(content);
11233
+ }
11234
+ catch (error) {
11235
+ parseError = error;
11236
+ }
11237
+ }
11238
+ const data = parsed?.data ?? {};
11239
+ const optionalStepsFieldValid = Array.isArray(data.optional_steps);
11240
+ const passedOptionalStepsFieldValid = Array.isArray(data.passed_optional_steps);
11241
+ const optionalSteps = optionalStepsFieldValid ? data.optional_steps : [];
11242
+ const passedOptionalSteps = passedOptionalStepsFieldValid ? data.passed_optional_steps : [];
11243
+ const createdFieldValid = (typeof data.created === 'string' && data.created.trim().length > 0) ||
11244
+ (data.created instanceof Date && !Number.isNaN(data.created.getTime()));
11245
+ const missingRequiredFields = [];
11246
+ if (typeof data.feature !== 'string' || data.feature.trim().length === 0) {
11247
+ missingRequiredFields.push('feature');
11248
+ }
11249
+ if (!createdFieldValid) {
11250
+ missingRequiredFields.push('created');
11251
+ }
11252
+ if (typeof data.status !== 'string' || data.status.trim().length === 0) {
11253
+ missingRequiredFields.push('status');
11254
+ }
11255
+ if (!optionalStepsFieldValid) {
11256
+ missingRequiredFields.push('optional_steps');
11257
+ }
11258
+ if (!passedOptionalStepsFieldValid) {
11259
+ missingRequiredFields.push('passed_optional_steps');
11260
+ }
11261
+ const missing = optionalStepsFieldValid
11262
+ ? activatedSteps.filter(step => !optionalSteps.includes(step))
11263
+ : [...activatedSteps];
11264
+ const checklistItems = parsed?.content.match(/^\s*-\s+\[(?: |x|X)\]\s+.+$/gm) ?? [];
11265
+ const uncheckedItems = parsed?.content.match(/^\s*-\s+\[ \]\s+.+$/gm) ?? [];
11266
+ const checklistStructureValid = checklistItems.length > 0;
11267
+ const checklistComplete = hasFrontmatter &&
11268
+ parseError === null &&
11269
+ missingRequiredFields.length === 0 &&
11270
+ checklistStructureValid &&
11271
+ uncheckedItems.length === 0;
11272
+ let frontmatterMessage = 'verification.md frontmatter parsed successfully';
11273
+ if (!hasFrontmatter) {
11274
+ frontmatterMessage = 'verification.md is missing a valid frontmatter block';
11275
+ }
11276
+ else if (parseError) {
11277
+ frontmatterMessage = `verification.md frontmatter cannot be parsed: ${parseError.message}`;
11278
+ }
11279
+ let requiredFieldsMessage = 'verification.md has all required frontmatter fields';
11280
+ if (!hasFrontmatter || parseError) {
11281
+ requiredFieldsMessage = 'Cannot validate required fields in verification.md because frontmatter is invalid';
11282
+ }
11283
+ else if (missingRequiredFields.length > 0) {
11284
+ requiredFieldsMessage = `Missing or invalid required fields in verification.md: ${missingRequiredFields.join(', ')}`;
11285
+ }
11286
+ let optionalStepsMessage = 'All activated optional steps are present in verification.md';
11287
+ if (!optionalStepsFieldValid) {
11288
+ optionalStepsMessage = 'verification.md frontmatter field optional_steps must be an array';
11289
+ }
11290
+ else if (missing.length > 0) {
11291
+ optionalStepsMessage = `Missing optional steps in verification.md: ${missing.join(', ')}`;
11292
+ }
11293
+ let checklistStatus = 'pass';
11294
+ let checklistMessage = 'verification.md checklist is complete';
11295
+ if (!hasFrontmatter || parseError) {
11296
+ checklistStatus = 'fail';
11297
+ checklistMessage = 'verification.md checklist cannot be validated because frontmatter is invalid';
11298
+ }
11299
+ else if (!checklistStructureValid) {
11300
+ checklistStatus = 'fail';
11301
+ checklistMessage = 'verification.md must contain at least one Markdown checklist item';
11302
+ }
11303
+ else if (uncheckedItems.length > 0) {
11304
+ checklistStatus = 'warn';
11305
+ checklistMessage = 'verification.md still has unchecked items';
11306
+ }
11316
11307
  return {
11317
-
11318
-
11319
-
11320
-
11321
-
11322
-
11323
-
11324
11308
  optionalSteps,
11325
-
11326
-
11327
-
11328
-
11329
-
11330
-
11331
-
11332
11309
  passedOptionalSteps,
11333
-
11334
-
11335
-
11336
-
11337
-
11338
-
11339
-
11340
11310
  checklistComplete,
11341
-
11342
-
11343
-
11344
-
11345
-
11346
-
11347
-
11348
11311
  checks: [
11349
-
11350
-
11351
-
11352
-
11353
-
11354
-
11355
-
11356
11312
  {
11357
-
11358
-
11359
-
11360
-
11361
-
11362
-
11363
-
11313
+ name: 'verification.md.frontmatter',
11314
+ status: hasFrontmatter && parseError === null ? 'pass' : 'fail',
11315
+ message: frontmatterMessage,
11316
+ },
11317
+ {
11318
+ name: 'verification.md.required_fields',
11319
+ status: hasFrontmatter && parseError === null && missingRequiredFields.length === 0 ? 'pass' : 'fail',
11320
+ message: requiredFieldsMessage,
11321
+ },
11322
+ {
11364
11323
  name: 'verification.md.optional_steps',
11365
-
11366
-
11367
-
11368
-
11369
-
11370
-
11371
-
11372
- status: missing.length === 0 ? 'pass' : 'fail',
11373
-
11374
-
11375
-
11376
-
11377
-
11378
-
11379
-
11380
- message: missing.length === 0
11381
-
11382
-
11383
-
11384
-
11385
-
11386
-
11387
-
11388
- ? 'All activated optional steps are present in verification.md'
11389
-
11390
-
11391
-
11392
-
11393
-
11394
-
11395
-
11396
- : `Missing optional steps in verification.md: ${missing.join(', ')}`,
11397
-
11398
-
11399
-
11400
-
11401
-
11402
-
11403
-
11324
+ status: optionalStepsFieldValid && missing.length === 0 ? 'pass' : 'fail',
11325
+ message: optionalStepsMessage,
11404
11326
  },
11405
-
11406
-
11407
-
11408
-
11409
-
11410
-
11411
-
11412
11327
  {
11413
-
11414
-
11415
-
11416
-
11417
-
11418
-
11419
-
11420
11328
  name: 'verification.md.checklist',
11421
-
11422
-
11423
-
11424
-
11425
-
11426
-
11427
-
11428
- status: checklistComplete ? 'pass' : 'warn',
11429
-
11430
-
11431
-
11432
-
11433
-
11434
-
11435
-
11436
- message: checklistComplete
11437
-
11438
-
11439
-
11440
-
11441
-
11442
-
11443
-
11444
- ? 'verification.md checklist is complete'
11445
-
11446
-
11447
-
11448
-
11449
-
11450
-
11451
-
11452
- : 'verification.md still has unchecked items',
11453
-
11454
-
11455
-
11456
-
11457
-
11458
-
11459
-
11329
+ status: checklistStatus,
11330
+ message: checklistMessage,
11460
11331
  },
11461
-
11462
-
11463
-
11464
-
11465
-
11466
-
11467
-
11468
11332
  ],
11469
-
11470
-
11471
-
11472
-
11473
-
11474
-
11475
-
11476
11333
  };
11477
11334
 
11478
11335
 
@@ -12911,4 +12768,3 @@ exports.createProjectService = createProjectService;
12911
12768
 
12912
12769
 
12913
12770
 
12914
- //# sourceMappingURL=ProjectService.js.map