@dynamicworks/br-openspec 2.0.1 → 2.1.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.
- package/README.md +11 -2
- package/README.pt-BR.md +11 -2
- package/dist/commands/config.js +4 -0
- package/dist/commands/schema.js +21 -21
- package/dist/core/completions/installers/zsh-installer.d.ts +0 -8
- package/dist/core/completions/installers/zsh-installer.js +3 -31
- package/dist/core/config.js +3 -2
- package/dist/core/global-config.d.ts +6 -1
- package/dist/core/global-config.js +15 -16
- package/dist/core/parsers/requirement-blocks.js +5 -5
- package/dist/core/parsers/spec-structure.js +1 -1
- package/dist/core/profile-sync-drift.js +1 -0
- package/dist/core/profiles.d.ts +2 -2
- package/dist/core/profiles.js +2 -1
- package/dist/core/shared/skill-generation.js +3 -1
- package/dist/core/shared/tool-detection.d.ts +2 -2
- package/dist/core/shared/tool-detection.js +2 -0
- package/dist/core/specs-apply.js +1 -1
- package/dist/core/templates/skill-templates.d.ts +1 -1
- package/dist/core/templates/skill-templates.js +1 -1
- package/dist/core/templates/workflows/code-review.d.ts +10 -0
- package/dist/core/templates/workflows/code-review.js +21 -0
- package/dist/core/templates/workflows/sync-specs.js +2 -2
- package/dist/core/tools-manager.js +1 -0
- package/dist/core/update.d.ts +6 -0
- package/dist/core/update.js +21 -0
- package/dist/core/validation/validator.js +2 -2
- package/dist/messages/index.d.ts +34 -2
- package/dist/messages/index.js +182 -12
- package/package.json +1 -1
- package/schemas/spec-driven/schema.yaml +78 -78
- package/schemas/spec-driven/templates/design.md +5 -5
- package/schemas/spec-driven/templates/proposal.md +9 -9
- package/schemas/spec-driven/templates/spec.md +5 -5
- package/schemas/spec-driven/templates/tasks.md +6 -6
- package/dist/core/templates/workflows/upstream-sync.d.ts +0 -10
- package/dist/core/templates/workflows/upstream-sync.js +0 -116
package/README.md
CHANGED
|
@@ -97,7 +97,7 @@ openspec init
|
|
|
97
97
|
|
|
98
98
|
Now tell your AI: `/opsx:propose <what-you-want-to-build>`
|
|
99
99
|
|
|
100
|
-
If you want the expanded workflow (`/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/opsx:verify`, `/opsx:
|
|
100
|
+
If you want the expanded workflow (`/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/opsx:verify`, `/opsx:bulk-archive`, `/opsx:onboard`), select it with `openspec config profile` and apply with `openspec update`.
|
|
101
101
|
|
|
102
102
|
> [!NOTE]
|
|
103
103
|
> Not sure if your tool is supported? [View the full list](docs/supported-tools.md) – we support 25+ tools and growing.
|
|
@@ -116,6 +116,13 @@ If you want the expanded workflow (`/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/
|
|
|
116
116
|
→ **[Customization](docs/customization.md)**: make it yours
|
|
117
117
|
|
|
118
118
|
|
|
119
|
+
## Community schemas
|
|
120
|
+
|
|
121
|
+
Third-party schema bundles distributed via standalone repositories — these provide opinionated workflows that integrate BR-OpenSpec with other tools, similar to how [github/spec-kit's community extension catalog](https://github.com/github/spec-kit/tree/main/extensions) handles tool integrations.
|
|
122
|
+
|
|
123
|
+
→ **[Browse the catalog](docs/customization.md#community-schemas)** in the customization docs.
|
|
124
|
+
|
|
125
|
+
|
|
119
126
|
## Why BR-OpenSpec?
|
|
120
127
|
|
|
121
128
|
AI coding assistants are powerful but unpredictable when requirements live only in chat history. BR-OpenSpec adds a lightweight spec layer so you agree on what to build before any code is written.
|
|
@@ -161,10 +168,12 @@ openspec tools --remove windsurf
|
|
|
161
168
|
|
|
162
169
|
## Usage Notes
|
|
163
170
|
|
|
164
|
-
**Model selection**: BR-OpenSpec works best with high-reasoning models. We recommend
|
|
171
|
+
**Model selection**: BR-OpenSpec works best with high-reasoning models. We recommend Codex 5.5 and Opus 4.8 for both planning and implementation.
|
|
165
172
|
|
|
166
173
|
**Context hygiene**: BR-OpenSpec benefits from a clean context window. Clear your context before starting implementation and maintain good context hygiene throughout your session.
|
|
167
174
|
|
|
175
|
+
**Spec keywords stay in English**: BR-OpenSpec is PT-BR first, but the spec format is a protocol read by the tooling. Structural markers (`## ADDED Requirements`, `### Requirement:`, `#### Scenario:`) and normative/scenario keywords (RFC 2119 — `MUST`, `SHALL`, `SHOULD`, `MAY`, … — plus `WHEN`, `THEN`, `AND`, `GIVEN`, `ELSE`) are always written in English and UPPERCASE; only the descriptive text is in Portuguese. Translating these keywords breaks `openspec validate`. See the full list in [AGENTS.md](AGENTS.md#reserved-english-terms-never-translate).
|
|
176
|
+
|
|
168
177
|
## Contributing
|
|
169
178
|
|
|
170
179
|
**Small fixes** — Bug fixes, typo corrections, and minor improvements can be submitted directly as PRs.
|
package/README.pt-BR.md
CHANGED
|
@@ -97,7 +97,7 @@ openspec init
|
|
|
97
97
|
|
|
98
98
|
Agora diga à sua IA: `/opsx:propose <o-que-você-quer-construir>`
|
|
99
99
|
|
|
100
|
-
Se você quiser o fluxo de trabalho expandido (`/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/opsx:verify`, `/opsx:
|
|
100
|
+
Se você quiser o fluxo de trabalho expandido (`/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/opsx:verify`, `/opsx:bulk-archive`, `/opsx:onboard`), selecione-o com `openspec config profile` e aplique com `openspec update`.
|
|
101
101
|
|
|
102
102
|
> [!NOTE]
|
|
103
103
|
> Não tem certeza se sua ferramenta é suportada? [Veja a lista completa](docs/pt-BR/supported-tools.md) – suportamos mais de 25 ferramentas e crescendo.
|
|
@@ -116,6 +116,13 @@ Se você quiser o fluxo de trabalho expandido (`/opsx:new`, `/opsx:continue`, `/
|
|
|
116
116
|
→ **[Personalização](docs/pt-BR/customization.md)**: faça do seu jeito
|
|
117
117
|
|
|
118
118
|
|
|
119
|
+
## Schemas da comunidade
|
|
120
|
+
|
|
121
|
+
Bundles de schema de terceiros distribuídos em repositórios independentes — oferecem fluxos de trabalho opinativos que integram o BR-OpenSpec a outras ferramentas, de forma semelhante a como o [catálogo de extensões da comunidade do github/spec-kit](https://github.com/github/spec-kit/tree/main/extensions) trata integrações de ferramentas.
|
|
122
|
+
|
|
123
|
+
→ **[Veja o catálogo](docs/pt-BR/customization.md#schemas-da-comunidade)** na documentação de personalização.
|
|
124
|
+
|
|
125
|
+
|
|
119
126
|
## Por que o BR-OpenSpec?
|
|
120
127
|
|
|
121
128
|
Assistentes de codificação com IA são poderosos, mas imprevisíveis quando os requisitos vivem apenas no histórico do chat. O BR-OpenSpec adiciona uma camada leve de especificação para que você concorde sobre o que construir antes de qualquer código ser escrito.
|
|
@@ -163,10 +170,12 @@ openspec tools --remove windsurf
|
|
|
163
170
|
|
|
164
171
|
## Notas de Uso
|
|
165
172
|
|
|
166
|
-
**Seleção de modelo**: O BR-OpenSpec funciona melhor com modelos de alto raciocínio. Recomendamos
|
|
173
|
+
**Seleção de modelo**: O BR-OpenSpec funciona melhor com modelos de alto raciocínio. Recomendamos Codex 5.5 e Opus 4.8 tanto para planejamento quanto para implementação.
|
|
167
174
|
|
|
168
175
|
**Higiene de contexto**: O BR-OpenSpec se beneficia de uma janela de contexto limpa. Limpe seu contexto antes de iniciar a implementação e mantenha uma boa higiene de contexto ao longo da sua sessão.
|
|
169
176
|
|
|
177
|
+
**Palavras-chave do formato de spec ficam em inglês**: O BR-OpenSpec é PT-BR first, mas o formato de spec é um protocolo lido pelas ferramentas. Os marcadores estruturais (`## ADDED Requirements`, `### Requirement:`, `#### Scenario:`) e as palavras-chave normativas/de cenário (RFC 2119 — `MUST`, `SHALL`, `SHOULD`, `MAY`, … — além de `WHEN`, `THEN`, `AND`, `GIVEN`, `ELSE`) são sempre escritas em inglês e em CAIXA ALTA; apenas o texto descritivo fica em português. Traduzir essas palavras-chave quebra o `openspec validate`. Veja a lista completa em [AGENTS.md](AGENTS.md#reserved-english-terms-never-translate).
|
|
178
|
+
|
|
170
179
|
## Contribuindo
|
|
171
180
|
|
|
172
181
|
**Pequenas correções** — Correções de bugs, erros de digitação e melhorias menores podem ser enviadas diretamente como PRs.
|
package/dist/commands/config.js
CHANGED
|
@@ -48,6 +48,10 @@ const WORKFLOW_PROMPT_META = {
|
|
|
48
48
|
name: CONFIG_MESSAGES.workflowVerifyName,
|
|
49
49
|
description: CONFIG_MESSAGES.workflowVerifyDesc,
|
|
50
50
|
},
|
|
51
|
+
'code-review': {
|
|
52
|
+
name: CONFIG_MESSAGES.workflowCodeReviewName,
|
|
53
|
+
description: CONFIG_MESSAGES.workflowCodeReviewDesc,
|
|
54
|
+
},
|
|
51
55
|
onboard: {
|
|
52
56
|
name: CONFIG_MESSAGES.workflowOnboardName,
|
|
53
57
|
description: CONFIG_MESSAGES.workflowOnboardDesc,
|
package/dist/commands/schema.js
CHANGED
|
@@ -797,72 +797,72 @@ function createDefaultTemplate(artifactId) {
|
|
|
797
797
|
case 'proposal':
|
|
798
798
|
return `## Why
|
|
799
799
|
|
|
800
|
-
<!--
|
|
800
|
+
<!-- Descreva a motivação para esta mudança -->
|
|
801
801
|
|
|
802
802
|
## What Changes
|
|
803
803
|
|
|
804
|
-
<!--
|
|
804
|
+
<!-- Descreva o que vai mudar -->
|
|
805
805
|
|
|
806
806
|
## Capabilities
|
|
807
807
|
|
|
808
808
|
### New Capabilities
|
|
809
|
-
<!--
|
|
809
|
+
<!-- Liste as novas capabilities -->
|
|
810
810
|
|
|
811
811
|
### Modified Capabilities
|
|
812
|
-
<!--
|
|
812
|
+
<!-- Liste as capabilities modificadas -->
|
|
813
813
|
|
|
814
814
|
## Impact
|
|
815
815
|
|
|
816
|
-
<!--
|
|
816
|
+
<!-- Descreva o impacto sobre a funcionalidade existente -->
|
|
817
817
|
`;
|
|
818
818
|
case 'specs':
|
|
819
819
|
return `## ADDED Requirements
|
|
820
820
|
|
|
821
|
-
### Requirement:
|
|
821
|
+
### Requirement: Requisito de exemplo
|
|
822
822
|
|
|
823
|
-
|
|
823
|
+
Descrição do requisito.
|
|
824
824
|
|
|
825
|
-
#### Scenario:
|
|
826
|
-
- **WHEN**
|
|
827
|
-
- **THEN**
|
|
825
|
+
#### Scenario: Cenário de exemplo
|
|
826
|
+
- **WHEN** alguma condição
|
|
827
|
+
- **THEN** algum resultado
|
|
828
828
|
`;
|
|
829
829
|
case 'design':
|
|
830
830
|
return `## Context
|
|
831
831
|
|
|
832
|
-
<!--
|
|
832
|
+
<!-- Contexto e antecedentes -->
|
|
833
833
|
|
|
834
834
|
## Goals / Non-Goals
|
|
835
835
|
|
|
836
836
|
**Goals:**
|
|
837
|
-
<!--
|
|
837
|
+
<!-- Liste os objetivos -->
|
|
838
838
|
|
|
839
839
|
**Non-Goals:**
|
|
840
|
-
<!--
|
|
840
|
+
<!-- Liste os não-objetivos -->
|
|
841
841
|
|
|
842
842
|
## Decisions
|
|
843
843
|
|
|
844
|
-
### 1.
|
|
844
|
+
### 1. Nome da Decisão
|
|
845
845
|
|
|
846
|
-
|
|
846
|
+
Descrição e justificativa.
|
|
847
847
|
|
|
848
848
|
**Alternatives considered:**
|
|
849
|
-
-
|
|
849
|
+
- Alternativa 1: Rejeitada porque...
|
|
850
850
|
|
|
851
851
|
## Risks / Trade-offs
|
|
852
852
|
|
|
853
|
-
<!--
|
|
853
|
+
<!-- Liste os riscos e trade-offs -->
|
|
854
854
|
`;
|
|
855
855
|
case 'tasks':
|
|
856
856
|
return `## Implementation Tasks
|
|
857
857
|
|
|
858
|
-
- [ ]
|
|
859
|
-
- [ ]
|
|
860
|
-
- [ ]
|
|
858
|
+
- [ ] Tarefa 1
|
|
859
|
+
- [ ] Tarefa 2
|
|
860
|
+
- [ ] Tarefa 3
|
|
861
861
|
`;
|
|
862
862
|
default:
|
|
863
863
|
return `## ${artifactId}
|
|
864
864
|
|
|
865
|
-
<!--
|
|
865
|
+
<!-- Adicione o conteúdo aqui -->
|
|
866
866
|
`;
|
|
867
867
|
}
|
|
868
868
|
}
|
|
@@ -59,14 +59,6 @@ export declare class ZshInstaller {
|
|
|
59
59
|
* @returns true if .zshrc exists and has markers
|
|
60
60
|
*/
|
|
61
61
|
private hasZshrcConfig;
|
|
62
|
-
/**
|
|
63
|
-
* Check if fpath configuration is needed for a given directory
|
|
64
|
-
* Used to verify if Oh My Zsh (or other) completions directory is already in fpath
|
|
65
|
-
*
|
|
66
|
-
* @param completionsDir - Directory to check for in fpath
|
|
67
|
-
* @returns true if configuration is needed, false if directory is already referenced
|
|
68
|
-
*/
|
|
69
|
-
private needsFpathConfig;
|
|
70
62
|
/**
|
|
71
63
|
* Remove .zshrc configuration
|
|
72
64
|
* Used during uninstallation
|
|
@@ -148,26 +148,6 @@ export class ZshInstaller {
|
|
|
148
148
|
return false;
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
|
-
/**
|
|
152
|
-
* Check if fpath configuration is needed for a given directory
|
|
153
|
-
* Used to verify if Oh My Zsh (or other) completions directory is already in fpath
|
|
154
|
-
*
|
|
155
|
-
* @param completionsDir - Directory to check for in fpath
|
|
156
|
-
* @returns true if configuration is needed, false if directory is already referenced
|
|
157
|
-
*/
|
|
158
|
-
async needsFpathConfig(completionsDir) {
|
|
159
|
-
try {
|
|
160
|
-
const zshrcPath = this.getZshrcPath();
|
|
161
|
-
const content = await fs.readFile(zshrcPath, 'utf-8');
|
|
162
|
-
// Check if fpath already includes this directory
|
|
163
|
-
return !content.includes(completionsDir);
|
|
164
|
-
}
|
|
165
|
-
catch (error) {
|
|
166
|
-
// If we can't read .zshrc, assume config is needed
|
|
167
|
-
console.debug(`Unable to read .zshrc to check fpath config: ${error instanceof Error ? error.message : String(error)}`);
|
|
168
|
-
return true;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
151
|
/**
|
|
172
152
|
* Remove .zshrc configuration
|
|
173
153
|
* Used during uninstallation
|
|
@@ -256,18 +236,10 @@ export class ZshInstaller {
|
|
|
256
236
|
const backupPath = isUpdate ? await this.backupExistingFile(targetPath) : undefined;
|
|
257
237
|
// Write the completion script
|
|
258
238
|
await fs.writeFile(targetPath, completionScript, 'utf-8');
|
|
259
|
-
// Auto-configure .zshrc
|
|
239
|
+
// Auto-configure .zshrc for standard Zsh only.
|
|
240
|
+
// Oh My Zsh loads custom/completions and runs compinit itself.
|
|
260
241
|
let zshrcConfigured = false;
|
|
261
|
-
if (isOhMyZsh) {
|
|
262
|
-
// For Oh My Zsh, verify that custom/completions is in fpath
|
|
263
|
-
// If not, add it to .zshrc
|
|
264
|
-
const needsConfig = await this.needsFpathConfig(targetDir);
|
|
265
|
-
if (needsConfig) {
|
|
266
|
-
zshrcConfigured = await this.configureZshrc(targetDir);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
else {
|
|
270
|
-
// Standard Zsh always needs .zshrc configuration
|
|
242
|
+
if (!isOhMyZsh) {
|
|
271
243
|
zshrcConfigured = await this.configureZshrc(targetDir);
|
|
272
244
|
}
|
|
273
245
|
// Generate instructions (only if .zshrc wasn't auto-configured)
|
package/dist/core/config.js
CHANGED
|
@@ -23,12 +23,13 @@ export const AI_TOOLS = [
|
|
|
23
23
|
{ name: 'iFlow', value: 'iflow', available: true, successLabel: 'iFlow', skillsDir: '.iflow' },
|
|
24
24
|
{ name: 'Junie', value: 'junie', available: true, successLabel: 'Junie', skillsDir: '.junie' },
|
|
25
25
|
{ name: 'Kilo Code', value: 'kilocode', available: true, successLabel: 'Kilo Code', skillsDir: '.kilocode' },
|
|
26
|
-
{ name: 'Kimi
|
|
26
|
+
{ name: 'Kimi CLI', value: 'kimi', available: true, successLabel: 'Kimi CLI', skillsDir: '.kimi' },
|
|
27
27
|
{ name: 'Kiro', value: 'kiro', available: true, successLabel: 'Kiro', skillsDir: '.kiro' },
|
|
28
|
+
{ name: 'Lingma', value: 'lingma', available: true, successLabel: 'Lingma', skillsDir: '.lingma' },
|
|
29
|
+
{ name: 'Mistral Vibe', value: 'vibe', available: true, successLabel: 'Mistral Vibe', skillsDir: '.vibe' },
|
|
28
30
|
{ name: 'OpenCode', value: 'opencode', available: true, successLabel: 'OpenCode', skillsDir: '.opencode' },
|
|
29
31
|
{ name: 'Pi', value: 'pi', available: true, successLabel: 'Pi', skillsDir: '.pi' },
|
|
30
32
|
{ name: 'Qoder', value: 'qoder', available: true, successLabel: 'Qoder', skillsDir: '.qoder' },
|
|
31
|
-
{ name: 'Lingma', value: 'lingma', available: true, successLabel: 'Lingma', skillsDir: '.lingma' },
|
|
32
33
|
{ name: 'Qwen Code', value: 'qwen', available: true, successLabel: 'Qwen Code', skillsDir: '.qwen' },
|
|
33
34
|
{ name: 'RooCode', value: 'roocode', available: true, successLabel: 'RooCode', skillsDir: '.roo' },
|
|
34
35
|
{ name: 'Trae', value: 'trae', available: true, successLabel: 'Trae', skillsDir: '.trae' },
|
|
@@ -25,7 +25,12 @@ export declare function getGlobalConfigDir(): string;
|
|
|
25
25
|
* - Unix/macOS fallback: ~/.local/share/openspec/
|
|
26
26
|
* - Windows fallback: %LOCALAPPDATA%/openspec/
|
|
27
27
|
*/
|
|
28
|
-
export
|
|
28
|
+
export interface GlobalDataDirOptions {
|
|
29
|
+
env?: NodeJS.ProcessEnv;
|
|
30
|
+
platform?: NodeJS.Platform;
|
|
31
|
+
homedir?: string;
|
|
32
|
+
}
|
|
33
|
+
export declare function getGlobalDataDir(options?: GlobalDataDirOptions): string;
|
|
29
34
|
/**
|
|
30
35
|
* Gets the path to the global config file.
|
|
31
36
|
*/
|
|
@@ -36,32 +36,31 @@ export function getGlobalConfigDir() {
|
|
|
36
36
|
// Unix/macOS fallback: ~/.config
|
|
37
37
|
return path.join(os.homedir(), '.config', GLOBAL_CONFIG_DIR_NAME);
|
|
38
38
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
export function getGlobalDataDir() {
|
|
39
|
+
function joinGlobalDataPath(platform, ...segments) {
|
|
40
|
+
return platform === 'win32'
|
|
41
|
+
? path.win32.join(...segments)
|
|
42
|
+
: path.posix.join(...segments);
|
|
43
|
+
}
|
|
44
|
+
export function getGlobalDataDir(options = {}) {
|
|
45
|
+
const env = options.env ?? process.env;
|
|
46
|
+
const platform = options.platform ?? os.platform();
|
|
48
47
|
// XDG_DATA_HOME takes precedence on all platforms when explicitly set
|
|
49
|
-
const xdgDataHome =
|
|
48
|
+
const xdgDataHome = env.XDG_DATA_HOME;
|
|
50
49
|
if (xdgDataHome) {
|
|
51
|
-
return
|
|
50
|
+
return joinGlobalDataPath(platform, xdgDataHome, GLOBAL_DATA_DIR_NAME);
|
|
52
51
|
}
|
|
53
|
-
const
|
|
52
|
+
const homedir = options.homedir ?? os.homedir();
|
|
54
53
|
if (platform === 'win32') {
|
|
55
54
|
// Windows: use %LOCALAPPDATA%
|
|
56
|
-
const localAppData =
|
|
55
|
+
const localAppData = env.LOCALAPPDATA;
|
|
57
56
|
if (localAppData) {
|
|
58
|
-
return
|
|
57
|
+
return joinGlobalDataPath(platform, localAppData, GLOBAL_DATA_DIR_NAME);
|
|
59
58
|
}
|
|
60
59
|
// Fallback for Windows if LOCALAPPDATA is not set
|
|
61
|
-
return
|
|
60
|
+
return joinGlobalDataPath(platform, homedir, 'AppData', 'Local', GLOBAL_DATA_DIR_NAME);
|
|
62
61
|
}
|
|
63
62
|
// Unix/macOS fallback: ~/.local/share
|
|
64
|
-
return
|
|
63
|
+
return joinGlobalDataPath(platform, homedir, '.local', 'share', GLOBAL_DATA_DIR_NAME);
|
|
65
64
|
}
|
|
66
65
|
/**
|
|
67
66
|
* Gets the path to the global config file.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export function normalizeRequirementName(name) {
|
|
2
2
|
return name.trim();
|
|
3
3
|
}
|
|
4
|
-
const REQUIREMENT_HEADER_REGEX = /^###\s*Requirement:\s*(.+)\s
|
|
4
|
+
const REQUIREMENT_HEADER_REGEX = /^###\s*Requirement:\s*(.+)\s*$/i;
|
|
5
5
|
/**
|
|
6
6
|
* Extracts the Requirements section from a spec file and parses requirement blocks.
|
|
7
7
|
*/
|
|
@@ -37,7 +37,7 @@ export function extractRequirementsSection(content) {
|
|
|
37
37
|
let cursor = 0;
|
|
38
38
|
let preambleLines = [];
|
|
39
39
|
// Collect preamble lines until first requirement header
|
|
40
|
-
while (cursor < sectionBodyLines.length &&
|
|
40
|
+
while (cursor < sectionBodyLines.length && !REQUIREMENT_HEADER_REGEX.test(sectionBodyLines[cursor])) {
|
|
41
41
|
preambleLines.push(sectionBodyLines[cursor]);
|
|
42
42
|
cursor++;
|
|
43
43
|
}
|
|
@@ -54,7 +54,7 @@ export function extractRequirementsSection(content) {
|
|
|
54
54
|
cursor++;
|
|
55
55
|
// Gather lines until next requirement header or end of section
|
|
56
56
|
const bodyLines = [headerLineCandidate];
|
|
57
|
-
while (cursor < sectionBodyLines.length &&
|
|
57
|
+
while (cursor < sectionBodyLines.length && !REQUIREMENT_HEADER_REGEX.test(sectionBodyLines[cursor]) && !/^##\s+/.test(sectionBodyLines[cursor])) {
|
|
58
58
|
bodyLines.push(sectionBodyLines[cursor]);
|
|
59
59
|
cursor++;
|
|
60
60
|
}
|
|
@@ -136,7 +136,7 @@ function parseRequirementBlocksFromSection(sectionBody) {
|
|
|
136
136
|
let i = 0;
|
|
137
137
|
while (i < lines.length) {
|
|
138
138
|
// Seek next requirement header
|
|
139
|
-
while (i < lines.length &&
|
|
139
|
+
while (i < lines.length && !REQUIREMENT_HEADER_REGEX.test(lines[i]))
|
|
140
140
|
i++;
|
|
141
141
|
if (i >= lines.length)
|
|
142
142
|
break;
|
|
@@ -149,7 +149,7 @@ function parseRequirementBlocksFromSection(sectionBody) {
|
|
|
149
149
|
const name = normalizeRequirementName(m[1]);
|
|
150
150
|
const buf = [headerLine];
|
|
151
151
|
i++;
|
|
152
|
-
while (i < lines.length &&
|
|
152
|
+
while (i < lines.length && !REQUIREMENT_HEADER_REGEX.test(lines[i]) && !/^##\s+/.test(lines[i])) {
|
|
153
153
|
buf.push(lines[i]);
|
|
154
154
|
i++;
|
|
155
155
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const REQUIREMENTS_SECTION_HEADER = /^##\s+Requirements\s*$/i;
|
|
2
2
|
const TOP_LEVEL_SECTION_HEADER = /^##\s+/;
|
|
3
3
|
const DELTA_HEADER = /^##\s+(ADDED|MODIFIED|REMOVED|RENAMED)\s+Requirements\s*$/i;
|
|
4
|
-
const REQUIREMENT_HEADER = /^###\s+Requirement:\s*(.+)\s
|
|
4
|
+
const REQUIREMENT_HEADER = /^###\s+Requirement:\s*(.+)\s*$/i;
|
|
5
5
|
export function findMainSpecStructureIssues(content) {
|
|
6
6
|
const normalized = content.replace(/\r\n?/g, '\n');
|
|
7
7
|
const stripped = stripFencedCodeBlocksPreservingLines(normalized);
|
|
@@ -17,6 +17,7 @@ export const WORKFLOW_TO_SKILL_DIR = {
|
|
|
17
17
|
'archive': 'openspec-archive-change',
|
|
18
18
|
'bulk-archive': 'openspec-bulk-archive-change',
|
|
19
19
|
'verify': 'openspec-verify-change',
|
|
20
|
+
'code-review': 'openspec-code-review',
|
|
20
21
|
'onboard': 'openspec-onboard',
|
|
21
22
|
'propose': 'openspec-propose',
|
|
22
23
|
};
|
package/dist/core/profiles.d.ts
CHANGED
|
@@ -9,11 +9,11 @@ import type { Profile } from './global-config.js';
|
|
|
9
9
|
* Core workflows included in the 'core' profile.
|
|
10
10
|
* These provide the streamlined experience for new users.
|
|
11
11
|
*/
|
|
12
|
-
export declare const CORE_WORKFLOWS: readonly ["propose", "explore", "apply", "archive"];
|
|
12
|
+
export declare const CORE_WORKFLOWS: readonly ["propose", "explore", "apply", "sync", "archive"];
|
|
13
13
|
/**
|
|
14
14
|
* All available workflows in the system.
|
|
15
15
|
*/
|
|
16
|
-
export declare const ALL_WORKFLOWS: readonly ["propose", "explore", "new", "continue", "apply", "ff", "sync", "archive", "bulk-archive", "verify", "onboard"];
|
|
16
|
+
export declare const ALL_WORKFLOWS: readonly ["propose", "explore", "new", "continue", "apply", "ff", "sync", "archive", "bulk-archive", "verify", "code-review", "onboard"];
|
|
17
17
|
export type WorkflowId = (typeof ALL_WORKFLOWS)[number];
|
|
18
18
|
export type CoreWorkflowId = (typeof CORE_WORKFLOWS)[number];
|
|
19
19
|
/**
|
package/dist/core/profiles.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Core workflows included in the 'core' profile.
|
|
9
9
|
* These provide the streamlined experience for new users.
|
|
10
10
|
*/
|
|
11
|
-
export const CORE_WORKFLOWS = ['propose', 'explore', 'apply', 'archive'];
|
|
11
|
+
export const CORE_WORKFLOWS = ['propose', 'explore', 'apply', 'sync', 'archive'];
|
|
12
12
|
/**
|
|
13
13
|
* All available workflows in the system.
|
|
14
14
|
*/
|
|
@@ -23,6 +23,7 @@ export const ALL_WORKFLOWS = [
|
|
|
23
23
|
'archive',
|
|
24
24
|
'bulk-archive',
|
|
25
25
|
'verify',
|
|
26
|
+
'code-review',
|
|
26
27
|
'onboard',
|
|
27
28
|
];
|
|
28
29
|
/**
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Shared utilities for generating skill and command files.
|
|
5
5
|
*/
|
|
6
|
-
import { getExploreSkillTemplate, getNewChangeSkillTemplate, getContinueChangeSkillTemplate, getApplyChangeSkillTemplate, getFfChangeSkillTemplate, getSyncSpecsSkillTemplate, getArchiveChangeSkillTemplate, getBulkArchiveChangeSkillTemplate, getVerifyChangeSkillTemplate, getOnboardSkillTemplate, getOpsxProposeSkillTemplate, getOpsxExploreCommandTemplate, getOpsxNewCommandTemplate, getOpsxContinueCommandTemplate, getOpsxApplyCommandTemplate, getOpsxFfCommandTemplate, getOpsxSyncCommandTemplate, getOpsxArchiveCommandTemplate, getOpsxBulkArchiveCommandTemplate, getOpsxVerifyCommandTemplate, getOpsxOnboardCommandTemplate, getOpsxProposeCommandTemplate, } from '../templates/skill-templates.js';
|
|
6
|
+
import { getExploreSkillTemplate, getNewChangeSkillTemplate, getContinueChangeSkillTemplate, getApplyChangeSkillTemplate, getFfChangeSkillTemplate, getSyncSpecsSkillTemplate, getArchiveChangeSkillTemplate, getBulkArchiveChangeSkillTemplate, getVerifyChangeSkillTemplate, getCodeReviewSkillTemplate, getOnboardSkillTemplate, getOpsxProposeSkillTemplate, getOpsxExploreCommandTemplate, getOpsxNewCommandTemplate, getOpsxContinueCommandTemplate, getOpsxApplyCommandTemplate, getOpsxFfCommandTemplate, getOpsxSyncCommandTemplate, getOpsxArchiveCommandTemplate, getOpsxBulkArchiveCommandTemplate, getOpsxVerifyCommandTemplate, getOpsxCodeReviewCommandTemplate, getOpsxOnboardCommandTemplate, getOpsxProposeCommandTemplate, } from '../templates/skill-templates.js';
|
|
7
7
|
/**
|
|
8
8
|
* Gets skill templates with their directory names, optionally filtered by workflow IDs.
|
|
9
9
|
*
|
|
@@ -20,6 +20,7 @@ export function getSkillTemplates(workflowFilter) {
|
|
|
20
20
|
{ template: getArchiveChangeSkillTemplate(), dirName: 'openspec-archive-change', workflowId: 'archive' },
|
|
21
21
|
{ template: getBulkArchiveChangeSkillTemplate(), dirName: 'openspec-bulk-archive-change', workflowId: 'bulk-archive' },
|
|
22
22
|
{ template: getVerifyChangeSkillTemplate(), dirName: 'openspec-verify-change', workflowId: 'verify' },
|
|
23
|
+
{ template: getCodeReviewSkillTemplate(), dirName: 'openspec-code-review', workflowId: 'code-review' },
|
|
23
24
|
{ template: getOnboardSkillTemplate(), dirName: 'openspec-onboard', workflowId: 'onboard' },
|
|
24
25
|
{ template: getOpsxProposeSkillTemplate(), dirName: 'openspec-propose', workflowId: 'propose' },
|
|
25
26
|
];
|
|
@@ -44,6 +45,7 @@ export function getCommandTemplates(workflowFilter) {
|
|
|
44
45
|
{ template: getOpsxArchiveCommandTemplate(), id: 'archive' },
|
|
45
46
|
{ template: getOpsxBulkArchiveCommandTemplate(), id: 'bulk-archive' },
|
|
46
47
|
{ template: getOpsxVerifyCommandTemplate(), id: 'verify' },
|
|
48
|
+
{ template: getOpsxCodeReviewCommandTemplate(), id: 'code-review' },
|
|
47
49
|
{ template: getOpsxOnboardCommandTemplate(), id: 'onboard' },
|
|
48
50
|
{ template: getOpsxProposeCommandTemplate(), id: 'propose' },
|
|
49
51
|
];
|
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
/**
|
|
7
7
|
* Names of skill directories created by openspec init.
|
|
8
8
|
*/
|
|
9
|
-
export declare const SKILL_NAMES: readonly ["openspec-explore", "openspec-new-change", "openspec-continue-change", "openspec-apply-change", "openspec-ff-change", "openspec-sync-specs", "openspec-archive-change", "openspec-bulk-archive-change", "openspec-verify-change", "openspec-onboard", "openspec-propose"];
|
|
9
|
+
export declare const SKILL_NAMES: readonly ["openspec-explore", "openspec-new-change", "openspec-continue-change", "openspec-apply-change", "openspec-ff-change", "openspec-sync-specs", "openspec-archive-change", "openspec-bulk-archive-change", "openspec-verify-change", "openspec-code-review", "openspec-onboard", "openspec-propose"];
|
|
10
10
|
export type SkillName = (typeof SKILL_NAMES)[number];
|
|
11
11
|
/**
|
|
12
12
|
* IDs of command templates created by openspec init.
|
|
13
13
|
*/
|
|
14
|
-
export declare const COMMAND_IDS: readonly ["explore", "new", "continue", "apply", "ff", "sync", "archive", "bulk-archive", "verify", "onboard", "propose"];
|
|
14
|
+
export declare const COMMAND_IDS: readonly ["explore", "new", "continue", "apply", "ff", "sync", "archive", "bulk-archive", "verify", "code-review", "onboard", "propose"];
|
|
15
15
|
export type CommandId = (typeof COMMAND_IDS)[number];
|
|
16
16
|
/**
|
|
17
17
|
* Status of skill configuration for a tool.
|
|
@@ -19,6 +19,7 @@ export const SKILL_NAMES = [
|
|
|
19
19
|
'openspec-archive-change',
|
|
20
20
|
'openspec-bulk-archive-change',
|
|
21
21
|
'openspec-verify-change',
|
|
22
|
+
'openspec-code-review',
|
|
22
23
|
'openspec-onboard',
|
|
23
24
|
'openspec-propose',
|
|
24
25
|
];
|
|
@@ -35,6 +36,7 @@ export const COMMAND_IDS = [
|
|
|
35
36
|
'archive',
|
|
36
37
|
'bulk-archive',
|
|
37
38
|
'verify',
|
|
39
|
+
'code-review',
|
|
38
40
|
'onboard',
|
|
39
41
|
'propose',
|
|
40
42
|
];
|
package/dist/core/specs-apply.js
CHANGED
|
@@ -211,7 +211,7 @@ export async function buildUpdatedSpec(update, changeName) {
|
|
|
211
211
|
throw new Error(SPECS_APPLY_MESSAGES.modifiedFailedNotFound(specName, mod.name));
|
|
212
212
|
}
|
|
213
213
|
// Replace block with provided raw (ensure header line matches key)
|
|
214
|
-
const modHeaderMatch = mod.raw.split('\n')[0].match(/^###\s*Requirement:\s*(.+)\s*$/);
|
|
214
|
+
const modHeaderMatch = mod.raw.split('\n')[0].match(/^###\s*Requirement:\s*(.+)\s*$/i);
|
|
215
215
|
if (!modHeaderMatch || normalizeRequirementName(modHeaderMatch[1]) !== key) {
|
|
216
216
|
throw new Error(SPECS_APPLY_MESSAGES.modifiedFailedHeaderMismatch(specName, mod.name));
|
|
217
217
|
}
|
|
@@ -13,8 +13,8 @@ export { getSyncSpecsSkillTemplate, getOpsxSyncCommandTemplate } from './workflo
|
|
|
13
13
|
export { getArchiveChangeSkillTemplate, getOpsxArchiveCommandTemplate } from './workflows/archive-change.js';
|
|
14
14
|
export { getBulkArchiveChangeSkillTemplate, getOpsxBulkArchiveCommandTemplate } from './workflows/bulk-archive-change.js';
|
|
15
15
|
export { getVerifyChangeSkillTemplate, getOpsxVerifyCommandTemplate } from './workflows/verify-change.js';
|
|
16
|
+
export { getCodeReviewSkillTemplate, getOpsxCodeReviewCommandTemplate } from './workflows/code-review.js';
|
|
16
17
|
export { getOnboardSkillTemplate, getOpsxOnboardCommandTemplate } from './workflows/onboard.js';
|
|
17
18
|
export { getOpsxProposeSkillTemplate, getOpsxProposeCommandTemplate } from './workflows/propose.js';
|
|
18
19
|
export { getFeedbackSkillTemplate } from './workflows/feedback.js';
|
|
19
|
-
export { getUpstreamSyncSkillTemplate, getOpsxUpstreamSyncCommandTemplate } from './workflows/upstream-sync.js';
|
|
20
20
|
//# sourceMappingURL=skill-templates.d.ts.map
|
|
@@ -12,8 +12,8 @@ export { getSyncSpecsSkillTemplate, getOpsxSyncCommandTemplate } from './workflo
|
|
|
12
12
|
export { getArchiveChangeSkillTemplate, getOpsxArchiveCommandTemplate } from './workflows/archive-change.js';
|
|
13
13
|
export { getBulkArchiveChangeSkillTemplate, getOpsxBulkArchiveCommandTemplate } from './workflows/bulk-archive-change.js';
|
|
14
14
|
export { getVerifyChangeSkillTemplate, getOpsxVerifyCommandTemplate } from './workflows/verify-change.js';
|
|
15
|
+
export { getCodeReviewSkillTemplate, getOpsxCodeReviewCommandTemplate } from './workflows/code-review.js';
|
|
15
16
|
export { getOnboardSkillTemplate, getOpsxOnboardCommandTemplate } from './workflows/onboard.js';
|
|
16
17
|
export { getOpsxProposeSkillTemplate, getOpsxProposeCommandTemplate } from './workflows/propose.js';
|
|
17
18
|
export { getFeedbackSkillTemplate } from './workflows/feedback.js';
|
|
18
|
-
export { getUpstreamSyncSkillTemplate, getOpsxUpstreamSyncCommandTemplate } from './workflows/upstream-sync.js';
|
|
19
19
|
//# sourceMappingURL=skill-templates.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill Template Workflow Modules
|
|
3
|
+
*
|
|
4
|
+
* This file is generated by splitting the legacy monolithic
|
|
5
|
+
* templates file into workflow-focused modules.
|
|
6
|
+
*/
|
|
7
|
+
import type { SkillTemplate, CommandTemplate } from '../types.js';
|
|
8
|
+
export declare function getCodeReviewSkillTemplate(): SkillTemplate;
|
|
9
|
+
export declare function getOpsxCodeReviewCommandTemplate(): CommandTemplate;
|
|
10
|
+
//# sourceMappingURL=code-review.d.ts.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { CODE_REVIEW_TEMPLATE_MESSAGES } from '../../../messages/index.js';
|
|
2
|
+
export function getCodeReviewSkillTemplate() {
|
|
3
|
+
return {
|
|
4
|
+
name: 'openspec-code-review',
|
|
5
|
+
description: CODE_REVIEW_TEMPLATE_MESSAGES.skillDescription,
|
|
6
|
+
instructions: CODE_REVIEW_TEMPLATE_MESSAGES.instructions,
|
|
7
|
+
license: 'MIT',
|
|
8
|
+
compatibility: CODE_REVIEW_TEMPLATE_MESSAGES.skillCompatibility,
|
|
9
|
+
metadata: { author: 'openspec', version: '1.0' },
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export function getOpsxCodeReviewCommandTemplate() {
|
|
13
|
+
return {
|
|
14
|
+
name: 'OPSX: Code Review',
|
|
15
|
+
description: CODE_REVIEW_TEMPLATE_MESSAGES.opsxDescription,
|
|
16
|
+
category: 'Workflow',
|
|
17
|
+
tags: ['workflow', 'review', 'code-review', 'experimental'],
|
|
18
|
+
content: CODE_REVIEW_TEMPLATE_MESSAGES.instructions,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=code-review.js.map
|
|
@@ -75,7 +75,7 @@ Esta é uma operação **dirigida por agente** — você lerá os delta specs e
|
|
|
75
75
|
## ADDED Requirements
|
|
76
76
|
|
|
77
77
|
### Requirement: New Feature
|
|
78
|
-
|
|
78
|
+
The system SHALL do something new.
|
|
79
79
|
|
|
80
80
|
#### Scenario: Basic case
|
|
81
81
|
- **WHEN** user does X
|
|
@@ -213,7 +213,7 @@ Esta é uma operação **dirigida por agente** — você lerá os delta specs e
|
|
|
213
213
|
## ADDED Requirements
|
|
214
214
|
|
|
215
215
|
### Requirement: New Feature
|
|
216
|
-
|
|
216
|
+
The system SHALL do something new.
|
|
217
217
|
|
|
218
218
|
#### Scenario: Basic case
|
|
219
219
|
- **WHEN** user does X
|
|
@@ -29,6 +29,7 @@ const WORKFLOW_TO_SKILL_DIR = {
|
|
|
29
29
|
archive: 'openspec-archive-change',
|
|
30
30
|
'bulk-archive': 'openspec-bulk-archive-change',
|
|
31
31
|
verify: 'openspec-verify-change',
|
|
32
|
+
'code-review': 'openspec-code-review',
|
|
32
33
|
onboard: 'openspec-onboard',
|
|
33
34
|
propose: 'openspec-propose',
|
|
34
35
|
};
|
package/dist/core/update.d.ts
CHANGED
|
@@ -38,6 +38,12 @@ export declare class UpdateCommand {
|
|
|
38
38
|
* Displays a note about extra workflows installed that aren't in the current profile.
|
|
39
39
|
*/
|
|
40
40
|
private displayExtraWorkflowsNote;
|
|
41
|
+
/**
|
|
42
|
+
* Sugere voltar ao perfil core quando um perfil personalizado ainda
|
|
43
|
+
* corresponde ao conjunto core antigo (anterior ao sync). Mantém os perfis
|
|
44
|
+
* personalizados sob controle do usuário; não os altera.
|
|
45
|
+
*/
|
|
46
|
+
private displayOldCoreCustomProfileNote;
|
|
41
47
|
/**
|
|
42
48
|
* Removes skill directories for workflows when delivery changed to commands-only.
|
|
43
49
|
* Returns the number of directories removed.
|