@guilhermefsousa/open-spec-kit 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guilhermefsousa/open-spec-kit",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "CLI para spec-driven development com suporte a Claude Code e GitHub Copilot",
5
5
  "type": "module",
6
6
  "bin": {
@@ -130,8 +130,12 @@ export async function updateCommand() {
130
130
  } else {
131
131
  skillsSpinner.succeed('Skills Copilot já estão sincronizados');
132
132
  }
133
- } catch {
134
- skillsSpinner.warn('Diretório .agents/skills/ não encontrado — skills não sincronizados');
133
+ } catch (err) {
134
+ if (err.code === 'ENOENT') {
135
+ skillsSpinner.warn('Diretório .agents/skills/ não encontrado — skills não sincronizados');
136
+ } else {
137
+ skillsSpinner.warn(`Erro ao sincronizar skills: ${err.message}`);
138
+ }
135
139
  }
136
140
  }
137
141
 
@@ -13,7 +13,6 @@ import { execSync } from 'child_process';
13
13
  import {
14
14
  parseSections, findSection, findAllSections,
15
15
  parseTable, extractUniqueMatches, getSectionFullContent,
16
- buildCodeFenceMask,
17
16
  } from '../parsers/markdown-sections.js';
18
17
  import { parseAndValidateProjects } from '../schemas/projects.schema.js';
19
18
  import * as rules from '../schemas/spec.schema.js';
@@ -496,7 +495,7 @@ export async function validateCommand(options = {}) {
496
495
  // Rules 34-37: Semantic linting
497
496
  const semanticContents = [briefRaw, scenariosRaw].filter(Boolean);
498
497
  if (semanticContents.length > 0) {
499
- results.push(rules.rule34_noVagueTerms(semanticContents, buildCodeFenceMask));
498
+ results.push(rules.rule34_noVagueTerms(semanticContents));
500
499
  }
501
500
  if (scenarios) {
502
501
  results.push(rules.rule35_thenHasMetric(scenarios, scenariosRaw));
@@ -4,7 +4,7 @@
4
4
  * Parses markdown into a hierarchical section tree with heading hierarchy,
5
5
  * code fence awareness, and table extraction.
6
6
  *
7
- * This is the foundation for all 32 Zod validation rules in osk validate.
7
+ * This is the foundation for all 37 validation rules in osk validate.
8
8
  */
9
9
 
10
10
  // --- Code Fence Mask ---
@@ -1,3 +1,5 @@
1
+ import { buildCodeFenceMask } from '../parsers/markdown-sections.js';
2
+
1
3
  /**
2
4
  * Zod schemas + 37 validation rules for spec artifacts.
3
5
  *
@@ -646,9 +648,8 @@ const VAGUE_TERMS_RE = /\b(rápido|rápida|lento|lenta|grande|pequeno|pequena|mu
646
648
  * Rule 34: No vague terms in brief/scenarios.
647
649
  * Detects adjectives that should be replaced by quantifiable metrics.
648
650
  * @param {string[]} contents - raw content of brief and scenarios
649
- * @param {function} buildCodeFenceMask - from markdown-sections.js, marks lines inside fences
650
651
  */
651
- export function rule34_noVagueTerms(contents, buildCodeFenceMask) {
652
+ export function rule34_noVagueTerms(contents) {
652
653
  const allFound = [];
653
654
  for (const content of contents) {
654
655
  const lines = content.split('\n');
@@ -695,6 +696,12 @@ export function rule35_thenHasMetric(parsed, rawContent) {
695
696
  );
696
697
  }
697
698
 
699
+ // Matches PascalCase domain terms (entity/concept names) in Portuguese text.
700
+ // Uses lookbehind/lookahead instead of \b — JS \b is ASCII-only and would
701
+ // truncate words with accented chars (e.g., Café→"Caf", Índice skipped entirely).
702
+ const LETTER = '[a-zA-ZáéíóúãõçêàâôûüÁÉÍÓÚÃÕÇÊÀÂÔÛÜ]';
703
+ const DOMAIN_TERM_RE = new RegExp(`(?<!${LETTER})([A-ZÁÉÍÓÚÃÕÇÊÀÂÔÛÜ]${LETTER}+)(?!${LETTER})`, 'g');
704
+
698
705
  const NOISE_TERMS = new Set([
699
706
  'given', 'when', 'then', 'and', 'but', 'dado', 'quando', 'então', 'entao',
700
707
  'post', 'get', 'put', 'patch', 'delete', 'head', 'options',
@@ -716,9 +723,8 @@ export function rule36_ubiquitousLanguage(scenariosRaw, briefRaw) {
716
723
  return result(36, true, 'WARNING', 'Missing brief or scenarios — rule not applicable');
717
724
  }
718
725
 
719
- // Extract PascalCase terms from scenarios (at least 3 chars, starts uppercase)
720
726
  const scenarioTerms = new Set(
721
- [...scenariosRaw.matchAll(/\b([A-Z][a-zA-ZáéíóúãõçêÁÉÍÓÚÃÕÇÊ]{1,})\b/g)]
727
+ [...scenariosRaw.matchAll(DOMAIN_TERM_RE)]
722
728
  .map(m => m[1])
723
729
  .filter(t => !NOISE_TERMS.has(t.toLowerCase()) && t.length > 2),
724
730
  );