@dynamicworks/br-openspec 1.3.1 → 2.0.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 (59) hide show
  1. package/LICENSE +22 -22
  2. package/README.md +210 -210
  3. package/README.pt-BR.md +212 -212
  4. package/bin/openspec.js +2 -2
  5. package/dist/commands/feedback.js +4 -4
  6. package/dist/commands/schema.js +60 -60
  7. package/dist/core/command-generation/adapters/amazon-q.js +5 -5
  8. package/dist/core/command-generation/adapters/antigravity.js +5 -5
  9. package/dist/core/command-generation/adapters/auggie.js +6 -6
  10. package/dist/core/command-generation/adapters/bob.js +6 -6
  11. package/dist/core/command-generation/adapters/claude.js +8 -8
  12. package/dist/core/command-generation/adapters/cline.js +5 -5
  13. package/dist/core/command-generation/adapters/codebuddy.js +7 -7
  14. package/dist/core/command-generation/adapters/codex.js +6 -6
  15. package/dist/core/command-generation/adapters/continue.js +7 -7
  16. package/dist/core/command-generation/adapters/costrict.js +6 -6
  17. package/dist/core/command-generation/adapters/crush.js +8 -8
  18. package/dist/core/command-generation/adapters/cursor.js +8 -8
  19. package/dist/core/command-generation/adapters/factory.js +6 -6
  20. package/dist/core/command-generation/adapters/gemini.js +5 -5
  21. package/dist/core/command-generation/adapters/github-copilot.js +5 -5
  22. package/dist/core/command-generation/adapters/iflow.js +8 -8
  23. package/dist/core/command-generation/adapters/junie.js +5 -5
  24. package/dist/core/command-generation/adapters/kilocode.js +1 -1
  25. package/dist/core/command-generation/adapters/kiro.js +5 -5
  26. package/dist/core/command-generation/adapters/lingma.js +8 -8
  27. package/dist/core/command-generation/adapters/opencode.js +5 -5
  28. package/dist/core/command-generation/adapters/pi.js +5 -5
  29. package/dist/core/command-generation/adapters/qoder.js +8 -8
  30. package/dist/core/command-generation/adapters/qwen.js +5 -5
  31. package/dist/core/command-generation/adapters/roocode.js +5 -5
  32. package/dist/core/command-generation/adapters/windsurf.js +8 -8
  33. package/dist/core/completions/generators/bash-generator.js +41 -41
  34. package/dist/core/completions/generators/fish-generator.js +7 -7
  35. package/dist/core/completions/generators/powershell-generator.js +29 -29
  36. package/dist/core/completions/generators/zsh-generator.js +33 -33
  37. package/dist/core/completions/templates/bash-templates.js +18 -18
  38. package/dist/core/completions/templates/fish-templates.js +32 -32
  39. package/dist/core/completions/templates/powershell-templates.js +19 -19
  40. package/dist/core/completions/templates/zsh-templates.js +30 -30
  41. package/dist/core/shared/skill-generation.js +12 -12
  42. package/dist/core/templates/workflows/apply-change.js +288 -288
  43. package/dist/core/templates/workflows/archive-change.js +251 -251
  44. package/dist/core/templates/workflows/bulk-archive-change.js +472 -472
  45. package/dist/core/templates/workflows/continue-change.js +212 -212
  46. package/dist/core/templates/workflows/explore.js +443 -443
  47. package/dist/core/templates/workflows/feedback.js +97 -97
  48. package/dist/core/templates/workflows/ff-change.js +178 -178
  49. package/dist/core/templates/workflows/propose.js +196 -196
  50. package/dist/core/templates/workflows/sync-specs.js +252 -252
  51. package/dist/core/templates/workflows/upstream-sync.js +93 -93
  52. package/dist/messages/index.js +977 -977
  53. package/package.json +82 -84
  54. package/schemas/spec-driven/schema.yaml +153 -153
  55. package/schemas/spec-driven/templates/design.md +19 -19
  56. package/schemas/spec-driven/templates/proposal.md +23 -23
  57. package/schemas/spec-driven/templates/spec.md +8 -8
  58. package/schemas/spec-driven/templates/tasks.md +9 -9
  59. package/scripts/postinstall.js +83 -83
@@ -36,14 +36,14 @@ export const claudeAdapter = {
36
36
  return path.join('.claude', 'commands', 'opsx', `${commandId}.md`);
37
37
  },
38
38
  formatFile(content) {
39
- return `---
40
- name: ${escapeYamlValue(content.name)}
41
- description: ${escapeYamlValue(content.description)}
42
- category: ${escapeYamlValue(content.category)}
43
- tags: ${formatTagsArray(content.tags)}
44
- ---
45
-
46
- ${content.body}
39
+ return `---
40
+ name: ${escapeYamlValue(content.name)}
41
+ description: ${escapeYamlValue(content.description)}
42
+ category: ${escapeYamlValue(content.category)}
43
+ tags: ${formatTagsArray(content.tags)}
44
+ ---
45
+
46
+ ${content.body}
47
47
  `;
48
48
  },
49
49
  };
@@ -16,11 +16,11 @@ export const clineAdapter = {
16
16
  return path.join('.clinerules', 'workflows', `opsx-${commandId}.md`);
17
17
  },
18
18
  formatFile(content) {
19
- return `# ${content.name}
20
-
21
- ${content.description}
22
-
23
- ${content.body}
19
+ return `# ${content.name}
20
+
21
+ ${content.description}
22
+
23
+ ${content.body}
24
24
  `;
25
25
  },
26
26
  };
@@ -15,13 +15,13 @@ export const codebuddyAdapter = {
15
15
  return path.join('.codebuddy', 'commands', 'opsx', `${commandId}.md`);
16
16
  },
17
17
  formatFile(content) {
18
- return `---
19
- name: ${content.name}
20
- description: "${content.description}"
21
- argument-hint: "[command arguments]"
22
- ---
23
-
24
- ${content.body}
18
+ return `---
19
+ name: ${content.name}
20
+ description: "${content.description}"
21
+ argument-hint: "[command arguments]"
22
+ ---
23
+
24
+ ${content.body}
25
25
  `;
26
26
  },
27
27
  };
@@ -27,12 +27,12 @@ export const codexAdapter = {
27
27
  return path.join(getCodexHome(), 'prompts', `opsx-${commandId}.md`);
28
28
  },
29
29
  formatFile(content) {
30
- return `---
31
- description: ${content.description}
32
- argument-hint: command arguments
33
- ---
34
-
35
- ${content.body}
30
+ return `---
31
+ description: ${content.description}
32
+ argument-hint: command arguments
33
+ ---
34
+
35
+ ${content.body}
36
36
  `;
37
37
  },
38
38
  };
@@ -15,13 +15,13 @@ export const continueAdapter = {
15
15
  return path.join('.continue', 'prompts', `opsx-${commandId}.prompt`);
16
16
  },
17
17
  formatFile(content) {
18
- return `---
19
- name: opsx-${content.id}
20
- description: ${content.description}
21
- invokable: true
22
- ---
23
-
24
- ${content.body}
18
+ return `---
19
+ name: opsx-${content.id}
20
+ description: ${content.description}
21
+ invokable: true
22
+ ---
23
+
24
+ ${content.body}
25
25
  `;
26
26
  },
27
27
  };
@@ -15,12 +15,12 @@ export const costrictAdapter = {
15
15
  return path.join('.cospec', 'openspec', 'commands', `opsx-${commandId}.md`);
16
16
  },
17
17
  formatFile(content) {
18
- return `---
19
- description: "${content.description}"
20
- argument-hint: command arguments
21
- ---
22
-
23
- ${content.body}
18
+ return `---
19
+ description: "${content.description}"
20
+ argument-hint: command arguments
21
+ ---
22
+
23
+ ${content.body}
24
24
  `;
25
25
  },
26
26
  };
@@ -16,14 +16,14 @@ export const crushAdapter = {
16
16
  },
17
17
  formatFile(content) {
18
18
  const tagsStr = content.tags.join(', ');
19
- return `---
20
- name: ${content.name}
21
- description: ${content.description}
22
- category: ${content.category}
23
- tags: [${tagsStr}]
24
- ---
25
-
26
- ${content.body}
19
+ return `---
20
+ name: ${content.name}
21
+ description: ${content.description}
22
+ category: ${content.category}
23
+ tags: [${tagsStr}]
24
+ ---
25
+
26
+ ${content.body}
27
27
  `;
28
28
  },
29
29
  };
@@ -30,14 +30,14 @@ export const cursorAdapter = {
30
30
  return path.join('.cursor', 'commands', `opsx-${commandId}.md`);
31
31
  },
32
32
  formatFile(content) {
33
- return `---
34
- name: /opsx-${content.id}
35
- id: opsx-${content.id}
36
- category: ${escapeYamlValue(content.category)}
37
- description: ${escapeYamlValue(content.description)}
38
- ---
39
-
40
- ${content.body}
33
+ return `---
34
+ name: /opsx-${content.id}
35
+ id: opsx-${content.id}
36
+ category: ${escapeYamlValue(content.category)}
37
+ description: ${escapeYamlValue(content.description)}
38
+ ---
39
+
40
+ ${content.body}
41
41
  `;
42
42
  },
43
43
  };
@@ -15,12 +15,12 @@ export const factoryAdapter = {
15
15
  return path.join('.factory', 'commands', `opsx-${commandId}.md`);
16
16
  },
17
17
  formatFile(content) {
18
- return `---
19
- description: ${content.description}
20
- argument-hint: command arguments
21
- ---
22
-
23
- ${content.body}
18
+ return `---
19
+ description: ${content.description}
20
+ argument-hint: command arguments
21
+ ---
22
+
23
+ ${content.body}
24
24
  `;
25
25
  },
26
26
  };
@@ -15,11 +15,11 @@ export const geminiAdapter = {
15
15
  return path.join('.gemini', 'commands', 'opsx', `${commandId}.toml`);
16
16
  },
17
17
  formatFile(content) {
18
- return `description = "${content.description}"
19
-
20
- prompt = """
21
- ${content.body}
22
- """
18
+ return `description = "${content.description}"
19
+
20
+ prompt = """
21
+ ${content.body}
22
+ """
23
23
  `;
24
24
  },
25
25
  };
@@ -15,11 +15,11 @@ export const githubCopilotAdapter = {
15
15
  return path.join('.github', 'prompts', `opsx-${commandId}.prompt.md`);
16
16
  },
17
17
  formatFile(content) {
18
- return `---
19
- description: ${content.description}
20
- ---
21
-
22
- ${content.body}
18
+ return `---
19
+ description: ${content.description}
20
+ ---
21
+
22
+ ${content.body}
23
23
  `;
24
24
  },
25
25
  };
@@ -15,14 +15,14 @@ export const iflowAdapter = {
15
15
  return path.join('.iflow', 'commands', `opsx-${commandId}.md`);
16
16
  },
17
17
  formatFile(content) {
18
- return `---
19
- name: /opsx-${content.id}
20
- id: opsx-${content.id}
21
- category: ${content.category}
22
- description: ${content.description}
23
- ---
24
-
25
- ${content.body}
18
+ return `---
19
+ name: /opsx-${content.id}
20
+ id: opsx-${content.id}
21
+ category: ${content.category}
22
+ description: ${content.description}
23
+ ---
24
+
25
+ ${content.body}
26
26
  `;
27
27
  },
28
28
  };
@@ -15,11 +15,11 @@ export const junieAdapter = {
15
15
  return path.join('.junie', 'commands', `opsx-${commandId}.md`);
16
16
  },
17
17
  formatFile(content) {
18
- return `---
19
- description: ${content.description}
20
- ---
21
-
22
- ${content.body}
18
+ return `---
19
+ description: ${content.description}
20
+ ---
21
+
22
+ ${content.body}
23
23
  `;
24
24
  },
25
25
  };
@@ -16,7 +16,7 @@ export const kilocodeAdapter = {
16
16
  return path.join('.kilocode', 'workflows', `opsx-${commandId}.md`);
17
17
  },
18
18
  formatFile(content) {
19
- return `${content.body}
19
+ return `${content.body}
20
20
  `;
21
21
  },
22
22
  };
@@ -15,11 +15,11 @@ export const kiroAdapter = {
15
15
  return path.join('.kiro', 'prompts', `opsx-${commandId}.prompt.md`);
16
16
  },
17
17
  formatFile(content) {
18
- return `---
19
- description: ${content.description}
20
- ---
21
-
22
- ${content.body}
18
+ return `---
19
+ description: ${content.description}
20
+ ---
21
+
22
+ ${content.body}
23
23
  `;
24
24
  },
25
25
  };
@@ -16,14 +16,14 @@ export const lingmaAdapter = {
16
16
  },
17
17
  formatFile(content) {
18
18
  const tagsStr = content.tags.join(', ');
19
- return `---
20
- name: ${content.name}
21
- description: ${content.description}
22
- category: ${content.category}
23
- tags: [${tagsStr}]
24
- ---
25
-
26
- ${content.body}
19
+ return `---
20
+ name: ${content.name}
21
+ description: ${content.description}
22
+ category: ${content.category}
23
+ tags: [${tagsStr}]
24
+ ---
25
+
26
+ ${content.body}
27
27
  `;
28
28
  },
29
29
  };
@@ -18,11 +18,11 @@ export const opencodeAdapter = {
18
18
  formatFile(content) {
19
19
  // Transform command references from colon to hyphen format for OpenCode
20
20
  const transformedBody = transformToHyphenCommands(content.body);
21
- return `---
22
- description: ${content.description}
23
- ---
24
-
25
- ${transformedBody}
21
+ return `---
22
+ description: ${content.description}
23
+ ---
24
+
25
+ ${transformedBody}
26
26
  `;
27
27
  },
28
28
  };
@@ -44,11 +44,11 @@ export const piAdapter = {
44
44
  formatFile(content) {
45
45
  // Transform /opsx: references to /opsx- and inject $@ for template args
46
46
  const transformedBody = transformToHyphenCommands(content.body);
47
- return `---
48
- description: ${escapeYamlValue(content.description)}
49
- ---
50
-
51
- ${injectPiArgs(transformedBody)}
47
+ return `---
48
+ description: ${escapeYamlValue(content.description)}
49
+ ---
50
+
51
+ ${injectPiArgs(transformedBody)}
52
52
  `;
53
53
  },
54
54
  };
@@ -16,14 +16,14 @@ export const qoderAdapter = {
16
16
  },
17
17
  formatFile(content) {
18
18
  const tagsStr = content.tags.join(', ');
19
- return `---
20
- name: ${content.name}
21
- description: ${content.description}
22
- category: ${content.category}
23
- tags: [${tagsStr}]
24
- ---
25
-
26
- ${content.body}
19
+ return `---
20
+ name: ${content.name}
21
+ description: ${content.description}
22
+ category: ${content.category}
23
+ tags: [${tagsStr}]
24
+ ---
25
+
26
+ ${content.body}
27
27
  `;
28
28
  },
29
29
  };
@@ -15,11 +15,11 @@ export const qwenAdapter = {
15
15
  return path.join('.qwen', 'commands', `opsx-${commandId}.toml`);
16
16
  },
17
17
  formatFile(content) {
18
- return `description = "${content.description}"
19
-
20
- prompt = """
21
- ${content.body}
22
- """
18
+ return `description = "${content.description}"
19
+
20
+ prompt = """
21
+ ${content.body}
22
+ """
23
23
  `;
24
24
  },
25
25
  };
@@ -16,11 +16,11 @@ export const roocodeAdapter = {
16
16
  return path.join('.roo', 'commands', `opsx-${commandId}.md`);
17
17
  },
18
18
  formatFile(content) {
19
- return `# ${content.name}
20
-
21
- ${content.description}
22
-
23
- ${content.body}
19
+ return `# ${content.name}
20
+
21
+ ${content.description}
22
+
23
+ ${content.body}
24
24
  `;
25
25
  },
26
26
  };
@@ -37,14 +37,14 @@ export const windsurfAdapter = {
37
37
  return path.join('.windsurf', 'workflows', `opsx-${commandId}.md`);
38
38
  },
39
39
  formatFile(content) {
40
- return `---
41
- name: ${escapeYamlValue(content.name)}
42
- description: ${escapeYamlValue(content.description)}
43
- category: ${escapeYamlValue(content.category)}
44
- tags: ${formatTagsArray(content.tags)}
45
- ---
46
-
47
- ${content.body}
40
+ return `---
41
+ name: ${escapeYamlValue(content.name)}
42
+ description: ${escapeYamlValue(content.description)}
43
+ category: ${escapeYamlValue(content.category)}
44
+ tags: ${formatTagsArray(content.tags)}
45
+ ---
46
+
47
+ ${content.body}
48
48
  `;
49
49
  },
50
50
  };
@@ -25,47 +25,47 @@ export class BashGenerator {
25
25
  // Dynamic completion helpers from template
26
26
  const helpers = BASH_DYNAMIC_HELPERS;
27
27
  // Assemble final script with template literal
28
- return `# Bash completion script for BR-OpenSpec CLI
29
- # Auto-generated - do not edit manually
30
-
31
- _openspec_completion() {
32
- local cur prev words cword
33
-
34
- # Use _init_completion if available (from bash-completion package)
35
- # The -n : option prevents colons from being treated as word separators
36
- # (important for spec/change IDs that may contain colons)
37
- # Otherwise, fall back to manual initialization
38
- if declare -F _init_completion >/dev/null 2>&1; then
39
- _init_completion -n : || return
40
- else
41
- # Manual fallback when bash-completion is not installed
42
- COMPREPLY=()
43
- cur="\${COMP_WORDS[COMP_CWORD]}"
44
- prev="\${COMP_WORDS[COMP_CWORD-1]}"
45
- words=("\${COMP_WORDS[@]}")
46
- cword=$COMP_CWORD
47
- fi
48
-
49
- local cmd="\${words[1]}"
50
- local subcmd="\${words[2]}"
51
-
52
- # Top-level commands
53
- if [[ $cword -eq 1 ]]; then
54
- local commands="${commandList}"
55
- COMPREPLY=($(compgen -W "$commands" -- "$cur"))
56
- return 0
57
- fi
58
-
59
- # Command-specific completion
60
- case "$cmd" in
61
- ${commandCases}
62
- esac
63
-
64
- return 0
65
- }
66
-
67
- ${helpers}
68
- complete -F _openspec_completion openspec
28
+ return `# Bash completion script for BR-OpenSpec CLI
29
+ # Auto-generated - do not edit manually
30
+
31
+ _openspec_completion() {
32
+ local cur prev words cword
33
+
34
+ # Use _init_completion if available (from bash-completion package)
35
+ # The -n : option prevents colons from being treated as word separators
36
+ # (important for spec/change IDs that may contain colons)
37
+ # Otherwise, fall back to manual initialization
38
+ if declare -F _init_completion >/dev/null 2>&1; then
39
+ _init_completion -n : || return
40
+ else
41
+ # Manual fallback when bash-completion is not installed
42
+ COMPREPLY=()
43
+ cur="\${COMP_WORDS[COMP_CWORD]}"
44
+ prev="\${COMP_WORDS[COMP_CWORD-1]}"
45
+ words=("\${COMP_WORDS[@]}")
46
+ cword=$COMP_CWORD
47
+ fi
48
+
49
+ local cmd="\${words[1]}"
50
+ local subcmd="\${words[2]}"
51
+
52
+ # Top-level commands
53
+ if [[ $cword -eq 1 ]]; then
54
+ local commands="${commandList}"
55
+ COMPREPLY=($(compgen -W "$commands" -- "$cur"))
56
+ return 0
57
+ fi
58
+
59
+ # Command-specific completion
60
+ case "$cmd" in
61
+ ${commandCases}
62
+ esac
63
+
64
+ return 0
65
+ }
66
+
67
+ ${helpers}
68
+ complete -F _openspec_completion openspec
69
69
  `;
70
70
  }
71
71
  /**
@@ -31,13 +31,13 @@ export class FishGenerator {
31
31
  // Dynamic completion helpers from template
32
32
  const dynamicHelpers = FISH_DYNAMIC_HELPERS;
33
33
  // Assemble final script with template literal
34
- return `# Fish completion script for BR-OpenSpec CLI
35
- # Auto-generated - do not edit manually
36
-
37
- ${helperFunctions}
38
- ${dynamicHelpers}
39
- ${topLevelCommands}
40
-
34
+ return `# Fish completion script for BR-OpenSpec CLI
35
+ # Auto-generated - do not edit manually
36
+
37
+ ${helperFunctions}
38
+ ${dynamicHelpers}
39
+ ${topLevelCommands}
40
+
41
41
  ${commandCompletions}`;
42
42
  }
43
43
  /**
@@ -36,35 +36,35 @@ export class PowerShellGenerator {
36
36
  // Dynamic completion helpers from template
37
37
  const helpers = POWERSHELL_DYNAMIC_HELPERS;
38
38
  // Assemble final script with template literal
39
- return `${COMPLETION_MESSAGES.powershellCompletionHeader}
40
- ${COMPLETION_MESSAGES.powershellCompletionNote}
41
-
42
- ${helpers}
43
- $openspecCompleter = {
44
- param($wordToComplete, $commandAst, $cursorPosition)
45
-
46
- $tokens = $commandAst.ToString() -split "\\s+"
47
- $commandCount = ($tokens | Measure-Object).Count
48
-
49
- # Top-level commands
50
- if ($commandCount -eq 1 -or ($commandCount -eq 2 -and $wordToComplete)) {
51
- $commands = @(
52
- ${topLevelCommands}
53
- )
54
- $commands | Where-Object { $_.Name -like "$wordToComplete*" } | ForEach-Object {
55
- [System.Management.Automation.CompletionResult]::new($_.Name, $_.Name, "ParameterValue", $_.Description)
56
- }
57
- return
58
- }
59
-
60
- $command = $tokens[1]
61
-
62
- switch ($command) {
63
- ${commandCases}
64
- }
65
- }
66
-
67
- Register-ArgumentCompleter -CommandName openspec -ScriptBlock $openspecCompleter
39
+ return `${COMPLETION_MESSAGES.powershellCompletionHeader}
40
+ ${COMPLETION_MESSAGES.powershellCompletionNote}
41
+
42
+ ${helpers}
43
+ $openspecCompleter = {
44
+ param($wordToComplete, $commandAst, $cursorPosition)
45
+
46
+ $tokens = $commandAst.ToString() -split "\\s+"
47
+ $commandCount = ($tokens | Measure-Object).Count
48
+
49
+ # Top-level commands
50
+ if ($commandCount -eq 1 -or ($commandCount -eq 2 -and $wordToComplete)) {
51
+ $commands = @(
52
+ ${topLevelCommands}
53
+ )
54
+ $commands | Where-Object { $_.Name -like "$wordToComplete*" } | ForEach-Object {
55
+ [System.Management.Automation.CompletionResult]::new($_.Name, $_.Name, "ParameterValue", $_.Description)
56
+ }
57
+ return
58
+ }
59
+
60
+ $command = $tokens[1]
61
+
62
+ switch ($command) {
63
+ ${commandCases}
64
+ }
65
+ }
66
+
67
+ Register-ArgumentCompleter -CommandName openspec -ScriptBlock $openspecCompleter
68
68
  `;
69
69
  }
70
70
  /**