refacil-sdd-ai 5.0.0 → 5.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/README.md CHANGED
@@ -6,6 +6,8 @@ Installs **skills** and **sub-agents** for **Claude Code**, **Cursor**, and **Op
6
6
 
7
7
  ---
8
8
 
9
+ **npm:** [refacil-sdd-ai](https://www.npmjs.com/package/refacil-sdd-ai) | **GitHub:** [Erikole21/refacil-sdd-ai](https://github.com/Erikole21/refacil-sdd-ai)
10
+
9
11
  ## Requirements
10
12
 
11
13
  - **Node.js >= 20.0.0**
@@ -29,8 +31,8 @@ refacil-sdd-ai init
29
31
  # whose folder already exists. Use --all to install for all three without prompting.
30
32
  # Copies skills and sub-agents to the selected IDEs, configures hooks,
31
33
  # and creates/updates .claudeignore, .cursorignore and .opencodeignore.
32
- # Also prompts for global branch config (baseBranch, protectedBranches) pre-filled
33
- # from ~/.refacil-sdd-ai/config.yaml. Skipped with --yes or --defaults.
34
+ # Also prompts for global branch config (baseBranch, protectedBranches, artifactLanguage)
35
+ # pre-filled from ~/.refacil-sdd-ai/config.yaml. Skipped with --yes or --defaults.
34
36
 
35
37
  # 3. Restart your IDE session
36
38
  # (new skills are not detected until you restart)
@@ -102,11 +104,43 @@ Native CLI for **`refacil-sdd/`** (no separate OpenSpec skill layer). Used by sk
102
104
  | `refacil-sdd-ai sdd tasks-update <name>` | Mark a task done (`--task N --done`) |
103
105
  | `refacil-sdd-ai sdd archive <name>` | Move a regular change to `refacil-sdd/changes/archive/` |
104
106
  | `refacil-sdd-ai sdd validate-name <name>` | Validate change folder name (must start with a letter) |
105
- | `refacil-sdd-ai sdd config [--json]` | Show effective branch configuration (protectedBranches, baseBranch) after cascade: project `refacil-sdd/config.yaml` → global `~/.refacil-sdd-ai/config.yaml` → built-in defaults |
106
- | `refacil-sdd-ai sdd write-config [--global] [--base-branch <v>] [--protected-branches <csv>]` | Write or merge branch config into `refacil-sdd/config.yaml` (project) or `~/.refacil-sdd-ai/config.yaml` (`--global`). Performs a semantic no-op check — skips rewrite if values are already set. Directory is auto-created if absent. |
107
+ | `refacil-sdd-ai sdd config [--json]` | Show effective configuration (protectedBranches, baseBranch, artifactLanguage) after cascade: project `refacil-sdd/config.yaml` → global `~/.refacil-sdd-ai/config.yaml` → built-in defaults. `--json` also includes a `sources` field indicating the resolution level for each value (`project`, `global`, or `default`). |
108
+ | `refacil-sdd-ai sdd write-config [--global] [--base-branch <v>] [--protected-branches <csv>] [--artifact-language <lang>]` | Write or merge config into `refacil-sdd/config.yaml` (project) or `~/.refacil-sdd-ai/config.yaml` (`--global`). Performs a semantic no-op check — skips rewrite if values are already set. Directory is auto-created if absent. |
107
109
 
108
110
  Run **`refacil-sdd-ai help`** for the full list including `bus` and `compact` subcommands.
109
111
 
112
+ ### Artifact Language
113
+
114
+ By default, `/refacil:propose` generates proposal, specs, design, and tasks in **English**. Set `artifactLanguage` to have the artifacts produced in your team's preferred language so developers can review them in their natural language.
115
+
116
+ **Supported values**: `english` (default) · `spanish`
117
+
118
+ **Configure globally** — applies to all repos for this user:
119
+
120
+ ```bash
121
+ refacil-sdd-ai sdd write-config --global --artifact-language spanish
122
+ ```
123
+
124
+ **Configure per project** — overrides the global value (commit `refacil-sdd/config.yaml` for team-wide effect):
125
+
126
+ ```bash
127
+ refacil-sdd-ai sdd write-config --artifact-language spanish
128
+ ```
129
+
130
+ **Check the active value**:
131
+
132
+ ```bash
133
+ refacil-sdd-ai sdd config
134
+ # artifactLanguage [global]: spanish
135
+
136
+ refacil-sdd-ai sdd config --json
137
+ # { ..., "artifactLanguage": "spanish", "sources": { "artifactLanguage": "global" } }
138
+ ```
139
+
140
+ **Cascade**: project `refacil-sdd/config.yaml` → global `~/.refacil-sdd-ai/config.yaml` → default `english`.
141
+
142
+ `refacil-sdd-ai init` also prompts for this preference and writes to the global config. Skip with `--yes` to keep the current value.
143
+
110
144
  ### Command rewrite control (`compact-bash`)
111
145
 
112
146
  | Command | Description |
@@ -380,7 +414,7 @@ Defined in `skills/prereqs/METHODOLOGY-CONTRACT.md`:
380
414
  - **Multi-stack tests**: detects the real test command (does not hardcode `npm test`).
381
415
  - **`AGENTS.md` by profile** (`sdd` vs `agents`): the methodology respects both.
382
416
  - **Output mode**: concise by default, detailed on demand.
383
- - **Language policy**: internal agent and skill instructions are in **English**. Responses to the user are in the **user's language** (default: Spanish). SDD artifacts are in the **team's agreed language**.
417
+ - **Language policy**: internal agent and skill instructions are in **English**. Responses to the user are in the **user's language** (default: Spanish). SDD artifact language (proposal, specs, design, tasks) defaults to **English** and is configurable via `artifactLanguage` — see [Artifact Language](#artifact-language).
384
418
 
385
419
  ---
386
420
 
@@ -48,6 +48,7 @@ If you prefer to continue here, provide:
48
48
  - **In mode=fix: you have Edit and Write** to implement the fix, generate tests, and create `summary.md`.
49
49
  - **The fix must be MINIMAL** — do not refactor anything beyond the bug.
50
50
  - **Return ONE final message** with the report + JSON block corresponding to the mode.
51
+ - **Language policy for written files**: any source/tests/comments/identifiers and file/folder names written in mode=fix must be English-only. Only user-facing narrative may follow the user's language.
51
52
 
52
53
  ---
53
54
 
@@ -59,6 +59,7 @@ Apply these 4 rules in each implementation task:
59
59
  - **Do NOT generate SDD artifacts** (proposal, specs, design, tasks) — that is `/refacil:propose`'s responsibility.
60
60
  - **Do NOT change branches or make commits** — the skill wrapper handles that before invoking you.
61
61
  - **Return ONE final message** with the report + JSON block.
62
+ - **Language policy for implementation output**: all created/modified code artifacts must be in English (file/folder names, identifiers, test descriptions, and code comments), regardless of user language or SDD artifact language.
62
63
 
63
64
  ## Flow
64
65
 
@@ -48,6 +48,7 @@ Exploration is necessary in this agent but must be **directed**, not exhaustive.
48
48
  - **NEVER write, modify, or generate source code** — only planning artifacts: `proposal.md`, `design.md`, `tasks.md`, specifications in `specs.md` and/or `specs/**/*.md`.
49
49
  - **Return ONE final message** with the summary + JSON block.
50
50
  - Your session context is isolated: explore with focus — depth in relevant modules, not breadth across the whole codebase.
51
+ - **Language boundary**: `artifactLanguage` applies only to SDD artifact prose. If you include example identifiers/paths/snippets in artifacts, keep them in English and never generate real source code.
51
52
 
52
53
  ## Artifact templates
53
54
 
@@ -153,6 +154,18 @@ Effort estimate: **S** (< 1h), **M** (1-4h), **L** (> 4h).
153
154
 
154
155
  ### Step 1: Explore the codebase
155
156
 
157
+ #### Step 1a: Language resolution (run FIRST, before any exploration)
158
+
159
+ Run: `refacil-sdd-ai sdd config --json`
160
+
161
+ Read the `artifactLanguage` field from the JSON output. Prepend the following instruction to your working context for this session:
162
+
163
+ > Generate ALL artifact content (proposal.md, specs.md, design.md, tasks.md) in **<artifactLanguage>** language. This applies to all prose, comments, labels, and descriptions inside the artifact files.
164
+
165
+ Fallback rule: if the command fails, produces invalid JSON, or returns an unknown/missing `artifactLanguage` value, use `english` and continue without interruption.
166
+
167
+ #### Step 1b: Codebase exploration
168
+
156
169
  Before generating artifacts, explore the project so that `design.md` is realistic and not invented:
157
170
  - Read `AGENTS.md` to understand the current architecture.
158
171
  - Identify files and modules relevant to the described change.
package/agents/tester.md CHANGED
@@ -46,6 +46,7 @@ If you prefer to continue here, provide:
46
46
  - **You do NOT modify source code** — only generate test files.
47
47
  - **You do NOT create SDD planning artifacts** (proposal/specs/design/tasks) — that is `/refacil:propose`'s responsibility.
48
48
  - **Return ONE final message** with the report + JSON block.
49
+ - **Language policy for tests**: generated test files must be English-only (file names, test names/descriptions, identifiers, and comments), regardless of user language or SDD artifact language.
49
50
 
50
51
  ## Stack detection (minimum focus)
51
52
 
package/bin/cli.js CHANGED
@@ -416,19 +416,22 @@ async function promptBranchConfig() {
416
416
  if (skipFlags.some((f) => process.argv.includes(f))) return;
417
417
  if (!process.stdout.isTTY) return;
418
418
 
419
- const { readConfigFile, DEFAULT_PROTECTED_BRANCHES, DEFAULT_BASE_BRANCH } = require('../lib/config');
419
+ const { readConfigFile, DEFAULT_PROTECTED_BRANCHES, DEFAULT_BASE_BRANCH, SUPPORTED_LANGUAGES, DEFAULT_ARTIFACT_LANGUAGE } = require('../lib/config');
420
420
  const globalConfigPath = path.join(os.homedir(), '.refacil-sdd-ai', 'config.yaml');
421
421
  const globalConfig = readConfigFile(globalConfigPath) || {};
422
422
  const currentBaseBranch = (typeof globalConfig.baseBranch === 'string' && globalConfig.baseBranch.trim()) ? globalConfig.baseBranch.trim() : DEFAULT_BASE_BRANCH;
423
423
  const currentProtected = (Array.isArray(globalConfig.protectedBranches) && globalConfig.protectedBranches.length > 0) ? globalConfig.protectedBranches : DEFAULT_PROTECTED_BRANCHES;
424
+ const currentArtifactLanguage = (typeof globalConfig.artifactLanguage === 'string' && SUPPORTED_LANGUAGES.includes(globalConfig.artifactLanguage.trim())) ? globalConfig.artifactLanguage.trim() : DEFAULT_ARTIFACT_LANGUAGE;
424
425
 
425
426
  console.log('\n Branch configuration (global, stored in ~/.refacil-sdd-ai/config.yaml)');
426
427
  console.log(` Current base branch: ${currentBaseBranch}`);
427
428
  console.log(` Current protected branches: ${currentProtected.join(', ')}`);
429
+ console.log(` Current artifact language: ${currentArtifactLanguage}`);
428
430
  console.log(' Press Enter to keep current values, or type new ones.\n');
429
431
 
430
432
  let baseBranch;
431
433
  let protectedBranches;
434
+ let artifactLanguage;
432
435
 
433
436
  try {
434
437
  const clack = require('@clack/prompts');
@@ -455,8 +458,20 @@ async function promptBranchConfig() {
455
458
  }
456
459
  protectedBranches = parseBranchList((pbResult && pbResult.trim()) ? pbResult.trim() : currentProtected.join(', '), currentProtected);
457
460
 
461
+ const alResult = await clack.text({
462
+ message: `Artifact language — ${SUPPORTED_LANGUAGES.join(' | ')} (current: ${currentArtifactLanguage}):`,
463
+ placeholder: currentArtifactLanguage,
464
+ validate: () => undefined,
465
+ });
466
+ if (clack.isCancel(alResult)) {
467
+ console.log(' Branch config prompt cancelled. Keeping existing values.\n');
468
+ return;
469
+ }
470
+ const alRaw = (alResult && alResult.trim()) ? alResult.trim() : currentArtifactLanguage;
471
+ artifactLanguage = SUPPORTED_LANGUAGES.includes(alRaw) ? alRaw : currentArtifactLanguage;
472
+
458
473
  const confirm = await clack.confirm({
459
- message: `Save global config — base: "${baseBranch}", protected: [${protectedBranches.join(', ')}]?`,
474
+ message: `Save global config — base: "${baseBranch}", protected: [${protectedBranches.join(', ')}], language: ${artifactLanguage}?`,
460
475
  initialValue: true,
461
476
  });
462
477
  if (clack.isCancel(confirm) || !confirm) {
@@ -475,7 +490,11 @@ async function promptBranchConfig() {
475
490
  const pbAnswer = await ask(` Protected branches [${currentProtected.join(', ')}]: `);
476
491
  protectedBranches = parseBranchList((pbAnswer && pbAnswer.trim()) ? pbAnswer.trim() : currentProtected.join(', '), currentProtected);
477
492
 
478
- const confirmAnswer = await ask(` Save global config — base: "${baseBranch}", protected: [${protectedBranches.join(', ')}]? (Y/n): `);
493
+ const alAnswer = await ask(` Artifact language [${currentArtifactLanguage}] (${SUPPORTED_LANGUAGES.join('/')}): `);
494
+ const alRaw = (alAnswer && alAnswer.trim()) ? alAnswer.trim() : currentArtifactLanguage;
495
+ artifactLanguage = SUPPORTED_LANGUAGES.includes(alRaw) ? alRaw : currentArtifactLanguage;
496
+
497
+ const confirmAnswer = await ask(` Save global config — base: "${baseBranch}", protected: [${protectedBranches.join(', ')}], language: ${artifactLanguage}? (Y/n): `);
479
498
  rl.close();
480
499
  if (confirmAnswer.trim().toLowerCase() === 'n') {
481
500
  console.log(' Branch config not saved.\n');
@@ -483,19 +502,22 @@ async function promptBranchConfig() {
483
502
  }
484
503
  }
485
504
 
486
- // Fix 2: pre-check to avoid process.exit(0) from cmdWriteConfig no-op path when called programmatically
505
+ // Pre-check to avoid process.exit(0) from cmdWriteConfig no-op path when called programmatically
487
506
  const valuesUnchanged = baseBranch === currentBaseBranch &&
488
- JSON.stringify(protectedBranches.slice().sort()) === JSON.stringify(currentProtected.slice().sort());
507
+ JSON.stringify(protectedBranches.slice().sort()) === JSON.stringify(currentProtected.slice().sort()) &&
508
+ artifactLanguage === currentArtifactLanguage;
489
509
  if (valuesUnchanged) {
490
510
  console.log(' Branch config unchanged. Keeping existing values.\n');
491
511
  return;
492
512
  }
493
513
 
494
514
  // Build argv-style array and call cmdWriteConfig directly
515
+ // Only write artifactLanguage if user chose a non-default value
495
516
  const writeArgv = [
496
517
  '--global',
497
518
  '--base-branch', baseBranch,
498
519
  '--protected-branches', protectedBranches.join(','),
520
+ '--artifact-language', artifactLanguage,
499
521
  ];
500
522
  try {
501
523
  cmdWriteConfig(writeArgv, projectRoot);
@@ -798,6 +820,7 @@ function help() {
798
820
  [--global] Write to ~/.refacil-sdd-ai/config.yaml (global level)
799
821
  [--base-branch <branch>] Base branch for new changes
800
822
  [--protected-branches <csv>] Protected branches (comma-separated)
823
+ [--artifact-language <lang>] Artifact language: english (default) or spanish
801
824
  clean Remove skills and SDD-AI hooks from all detected IDEs
802
825
  (.claude/settings.json, .cursor/hooks.json, .opencode/plugins/)
803
826
  help Show this help
@@ -3,7 +3,7 @@
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
5
  const os = require('os');
6
- const { loadBranchConfigWithSources, parseYaml, readConfigFile } = require('../config');
6
+ const { loadBranchConfigWithSources, parseYaml, readConfigFile, SUPPORTED_LANGUAGES } = require('../config');
7
7
 
8
8
  function findProjectRoot() {
9
9
  let dir = process.cwd();
@@ -634,13 +634,14 @@ function cmdConfig(argv, projectRoot) {
634
634
  const args = parseArgs(argv);
635
635
  const wantJson = args.json === true;
636
636
 
637
- const { protectedBranches, baseBranch, sources } = loadBranchConfigWithSources(projectRoot);
637
+ const { protectedBranches, baseBranch, artifactLanguage, sources } = loadBranchConfigWithSources(projectRoot);
638
638
 
639
639
  if (wantJson) {
640
- process.stdout.write(JSON.stringify({ protectedBranches, baseBranch }) + '\n');
640
+ process.stdout.write(JSON.stringify({ protectedBranches, baseBranch, artifactLanguage, sources }) + '\n');
641
641
  } else {
642
642
  console.log(`protectedBranches [${sources.protectedBranches}]: ${protectedBranches.join(', ')}`);
643
643
  console.log(`baseBranch [${sources.baseBranch}]: ${baseBranch}`);
644
+ console.log(`artifactLanguage [${sources.artifactLanguage}]: ${artifactLanguage}`);
644
645
  }
645
646
  }
646
647
 
@@ -651,11 +652,12 @@ function cmdWriteConfig(argv, projectRoot) {
651
652
  const isGlobal = args.global === true;
652
653
  const rawBaseBranch = args['base-branch'];
653
654
  const rawProtectedBranches = args['protected-branches'];
655
+ const rawArtifactLanguage = args['artifact-language'];
654
656
 
655
657
  // CR-03: no flags provided
656
- if (rawBaseBranch === undefined && rawProtectedBranches === undefined) {
657
- console.error('Uso: refacil-sdd-ai sdd write-config [--global] [--base-branch <branch>] [--protected-branches <csv>]');
658
- console.error('Debe especificar al menos --base-branch o --protected-branches.');
658
+ if (rawBaseBranch === undefined && rawProtectedBranches === undefined && rawArtifactLanguage === undefined) {
659
+ console.error('Uso: refacil-sdd-ai sdd write-config [--global] [--base-branch <branch>] [--protected-branches <csv>] [--artifact-language <language>]');
660
+ console.error('Debe especificar al menos --base-branch, --protected-branches o --artifact-language.');
659
661
  process.exit(1);
660
662
  }
661
663
 
@@ -675,6 +677,18 @@ function cmdWriteConfig(argv, projectRoot) {
675
677
  }
676
678
  }
677
679
 
680
+ // --artifact-language: must be non-empty and in SUPPORTED_LANGUAGES
681
+ if (rawArtifactLanguage !== undefined) {
682
+ if (typeof rawArtifactLanguage !== 'string' || rawArtifactLanguage.trim() === '') {
683
+ console.error('Error: --artifact-language no puede estar vacío.');
684
+ process.exit(1);
685
+ }
686
+ if (!SUPPORTED_LANGUAGES.includes(rawArtifactLanguage.trim())) {
687
+ console.error(`Error: --artifact-language "${rawArtifactLanguage.trim()}" no es un lenguaje soportado. Valores válidos: ${SUPPORTED_LANGUAGES.join(', ')}.`);
688
+ process.exit(1);
689
+ }
690
+ }
691
+
678
692
  const targetPath = isGlobal
679
693
  ? path.join(os.homedir(), '.refacil-sdd-ai', 'config.yaml')
680
694
  : path.join(projectRoot, 'refacil-sdd', 'config.yaml');
@@ -690,13 +704,17 @@ function cmdWriteConfig(argv, projectRoot) {
690
704
  if (protectedBranchesList !== undefined) {
691
705
  merged.protectedBranches = protectedBranchesList;
692
706
  }
707
+ if (rawArtifactLanguage !== undefined) {
708
+ merged.artifactLanguage = rawArtifactLanguage.trim();
709
+ }
693
710
 
694
711
  // CA-03: no-op when all provided keys already match existing config (semantic comparison)
695
712
  const isNoOp = Object.keys(existing).length > 0 &&
696
713
  (rawBaseBranch === undefined || existing.baseBranch === rawBaseBranch.trim()) &&
697
714
  (protectedBranchesList === undefined ||
698
715
  (Array.isArray(existing.protectedBranches) &&
699
- JSON.stringify(existing.protectedBranches.slice().sort()) === JSON.stringify(protectedBranchesList.slice().sort())));
716
+ JSON.stringify(existing.protectedBranches.slice().sort()) === JSON.stringify(protectedBranchesList.slice().sort()))) &&
717
+ (rawArtifactLanguage === undefined || existing.artifactLanguage === rawArtifactLanguage.trim());
700
718
  if (isNoOp) {
701
719
  console.log(`Sin cambios: ${targetPath} ya tiene los valores indicados.`);
702
720
  process.exit(0);
@@ -709,7 +727,7 @@ function cmdWriteConfig(argv, projectRoot) {
709
727
  fs.writeFileSync(targetPath, proposed, 'utf8');
710
728
 
711
729
  const level = isGlobal ? 'global' : 'proyecto';
712
- console.log(`Configuración de ramas escrita en ${targetPath} (nivel: ${level})`);
730
+ console.log(`Configuración escrita en ${targetPath} (nivel: ${level})`);
713
731
  }
714
732
 
715
733
  function sddHelp() {
@@ -745,11 +763,12 @@ function sddHelp() {
745
763
  sdd config [--json] Muestra la configuración efectiva de ramas
746
764
  (project > global > defaults)
747
765
  [--json] Salida en JSON (útil para agentes)
748
- sdd write-config Escribe la configuración de ramas en el archivo de config
766
+ sdd write-config Escribe la configuración en el archivo de config
749
767
  [--global] Escribe en ~/.refacil-sdd-ai/config.yaml (global)
750
768
  Sin --global: escribe en refacil-sdd/config.yaml (proyecto)
751
769
  [--base-branch <branch>] Rama base para nuevos cambios
752
770
  [--protected-branches <csv>] Ramas protegidas (separadas por coma)
771
+ [--artifact-language <language>] Idioma para los artefactos SDD generados (english, spanish)
753
772
 
754
773
  Notas:
755
774
  - Los nombres de cambio deben empezar con minúscula y usar solo [a-z0-9-]
package/lib/config.js CHANGED
@@ -6,6 +6,8 @@ const os = require('os');
6
6
 
7
7
  const DEFAULT_PROTECTED_BRANCHES = ['master', 'main', 'develop', 'dev', 'testing', 'qa'];
8
8
  const DEFAULT_BASE_BRANCH = 'develop';
9
+ const SUPPORTED_LANGUAGES = ['english', 'spanish'];
10
+ const DEFAULT_ARTIFACT_LANGUAGE = 'english';
9
11
 
10
12
  // Minimal YAML parser — supports string scalars and string-array values only.
11
13
  function parseYaml(content) {
@@ -86,6 +88,31 @@ function extractProtectedBranches(cfg, src) {
86
88
  return val;
87
89
  }
88
90
 
91
+ /**
92
+ * Validate `artifactLanguage` from a parsed config object.
93
+ * Returns the value if valid, or null + emits a warning if unknown.
94
+ * @param {object} cfg — parsed YAML object
95
+ * @param {string} src — source label for the warning ('project' | 'global')
96
+ */
97
+ function extractArtifactLanguage(cfg, src) {
98
+ if (!('artifactLanguage' in cfg)) return null;
99
+ const val = cfg.artifactLanguage;
100
+ if (typeof val !== 'string' || val.trim() === '') {
101
+ process.stderr.write(
102
+ `[refacil-sdd-ai] warning: artifactLanguage in ${src} config must be a non-empty string — ignoring.\n`,
103
+ );
104
+ return null;
105
+ }
106
+ const trimmed = val.trim();
107
+ if (!SUPPORTED_LANGUAGES.includes(trimmed)) {
108
+ process.stderr.write(
109
+ `[refacil-sdd-ai] warning: artifactLanguage "${trimmed}" in ${src} config is not a supported language (${SUPPORTED_LANGUAGES.join(', ')}) — ignoring.\n`,
110
+ );
111
+ return null;
112
+ }
113
+ return trimmed;
114
+ }
115
+
89
116
  /**
90
117
  * Validate `baseBranch` from a parsed config object.
91
118
  * Returns the value if valid, or null + emits a warning if invalid.
@@ -184,12 +211,39 @@ function loadBranchConfigWithSources(projectRoot) {
184
211
  baseBranchSource = 'default';
185
212
  }
186
213
 
214
+ // --- artifactLanguage ---
215
+ let artifactLanguage = null;
216
+ let artifactLanguageSource = 'default';
217
+
218
+ if (projectCfg !== null) {
219
+ const val = extractArtifactLanguage(projectCfg, 'project');
220
+ if (val !== null) {
221
+ artifactLanguage = val;
222
+ artifactLanguageSource = 'project';
223
+ }
224
+ }
225
+
226
+ if (artifactLanguage === null && globalCfg !== null) {
227
+ const val = extractArtifactLanguage(globalCfg, 'global');
228
+ if (val !== null) {
229
+ artifactLanguage = val;
230
+ artifactLanguageSource = 'global';
231
+ }
232
+ }
233
+
234
+ if (artifactLanguage === null) {
235
+ artifactLanguage = DEFAULT_ARTIFACT_LANGUAGE;
236
+ artifactLanguageSource = 'default';
237
+ }
238
+
187
239
  return {
188
240
  protectedBranches,
189
241
  baseBranch,
242
+ artifactLanguage,
190
243
  sources: {
191
244
  protectedBranches: protectedBranchesSource,
192
245
  baseBranch: baseBranchSource,
246
+ artifactLanguage: artifactLanguageSource,
193
247
  },
194
248
  };
195
249
  }
@@ -202,8 +256,8 @@ function loadBranchConfigWithSources(projectRoot) {
202
256
  * @param {string} projectRoot — absolute path to the project root
203
257
  */
204
258
  function loadBranchConfig(projectRoot) {
205
- const { protectedBranches, baseBranch } = loadBranchConfigWithSources(projectRoot);
206
- return { protectedBranches, baseBranch };
259
+ const { protectedBranches, baseBranch, artifactLanguage } = loadBranchConfigWithSources(projectRoot);
260
+ return { protectedBranches, baseBranch, artifactLanguage };
207
261
  }
208
262
 
209
263
  module.exports = {
@@ -211,6 +265,9 @@ module.exports = {
211
265
  readConfigFile,
212
266
  loadBranchConfig,
213
267
  loadBranchConfigWithSources,
268
+ extractArtifactLanguage,
214
269
  DEFAULT_PROTECTED_BRANCHES,
215
270
  DEFAULT_BASE_BRANCH,
271
+ SUPPORTED_LANGUAGES,
272
+ DEFAULT_ARTIFACT_LANGUAGE,
216
273
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "refacil-sdd-ai",
3
- "version": "5.0.0",
3
+ "version": "5.0.2",
4
4
  "description": "SDD-AI: Specification-Driven Development with AI — development methodology using AI with Claude Code, Cursor and OpenCode",
5
5
  "bin": {
6
6
  "refacil-sdd-ai": "./bin/cli.js"
@@ -182,4 +182,5 @@ If the sub-agent returned `result: "PARTIAL"` or `"FAILED"`, present the `issues
182
182
  - Meet the preconditions of Step 0 (complete artifacts) and Step 1 (valid working branch) **before delegating**.
183
183
  - **Always build the briefing (Step 1.5) before delegating** — it is the key piece that reduces the sub-agent cost.
184
184
  - **Always delegate implementation to the sub-agent**. Do not replicate implementation logic or SDD artifact-apply logic here.
185
+ - Even when artifacts are Spanish, implementation output is English-only: created file/folder names, source code, test code, identifiers, and code comments.
185
186
  - **Flow continuity**: if the user confirms affirmatively ("yes", "ok", "go", "continue", etc.) the continuity question in Step 3, immediately invoke the **Skill tool** with `skill: "refacil:test"`. Do not describe it in text or wait for the user to type `/refacil:test`. (See `METHODOLOGY-CONTRACT.md §5`.)
@@ -165,5 +165,6 @@ If the sub-agent returned `result: "FAILED"` (tests not passing), present the fa
165
165
  - **NEVER implement without explicit user approval** (Step 3).
166
166
  - **Always validate the branch** (Step 4) before delegating the fix.
167
167
  - **Do not replicate investigation or implementation logic here** — that lives in `refacil-debugger`.
168
+ - Bugfix implementation output is English-only: source/test file names, identifiers, test descriptions, and code comments, regardless of the language used in user-facing text or SDD artifacts.
168
169
  - Step 3 (bus cross-repo) is **optional** — only applies if the sub-agent reported `crossRepo: true`.
169
170
  - **Flow continuity**: if the user confirms affirmatively ("yes", "ok", "go", "continue", etc.) the continuity question in Step 6, immediately invoke the **Skill tool** with `skill: "refacil:review"`. Do not describe it in text or wait for the user to type `/refacil:review`. (See `METHODOLOGY-CONTRACT.md §5`.)
@@ -152,4 +152,9 @@ If the user does not request detail, use concise mode.
152
152
  - **Agent and skill internal instructions**: always in **English** (reduces token cost, improves LLM performance).
153
153
  - **Responses to the user**: in the **user's language**. If the user writes in Spanish, respond in Spanish. If in English, respond in English. Default: Spanish.
154
154
  - **SDD artifacts** (proposal.md, specs, design.md, tasks.md): in the **user's language** (or the language the team agreed on for the project).
155
- - Technical terms, code identifiers, and proper nouns stay in their canonical language regardless.
155
+ - **Source code and generated files are always English-only**, regardless of `artifactLanguage`:
156
+ - code identifiers (variables, functions, classes, types, interfaces, enums)
157
+ - test code and test names/descriptions
158
+ - source file and folder names created during implementation
159
+ - code comments and commit/PR technical text produced by the agent
160
+ - Never translate existing canonical API names, library symbols, or protocol/domain terms.
@@ -45,9 +45,14 @@ Communicate the final agreed slug to the user before generating.
45
45
 
46
46
  ### Step 2: Delegate to the refacil-proposer sub-agent
47
47
 
48
+ Before delegating, resolve the artifact language:
49
+
50
+ Run `refacil-sdd-ai sdd config --json` and read the `artifactLanguage` field. If the command fails or the field is missing/unknown, use `english`.
51
+
48
52
  Invoke the `refacil-proposer` sub-agent passing it:
49
53
  - `changeName`: the valid slug agreed in Step 1.5.
50
54
  - `description`: complete description of the change (from Step 1 or from `$ARGUMENTS`).
55
+ - `artifactLanguage`: the resolved language (e.g. `english` or `spanish`). Pass it explicitly so the sub-agent uses it immediately, before it reads AGENTS.md.
51
56
 
52
57
  The sub-agent:
53
58
  - Explores the codebase (reads `AGENTS.md`, detects relevant files and conventions) before generating.
@@ -100,4 +105,5 @@ Do you want me to continue with /refacil:apply?
100
105
 
101
106
  - **Change folder name**: always validate with `refacil-sdd-ai sdd validate-name <slug>` before delegating. Do not proceed if it exits 1.
102
107
  - **Always delegate generation to the sub-agent**. Do not replicate the codebase exploration or artifact generation logic here.
108
+ - `artifactLanguage` affects **only SDD artifacts**. Any code snippets, file/folder names, identifiers, and technical comments that may appear during proposal work must stay in **English**.
103
109
  - **Flow continuity**: if the user confirms affirmatively ("yes", "ok", "go", "continue", etc.) the continuity question in Step 4, immediately invoke the **Skill tool** with `skill: "refacil:apply"`. Do not describe it in text or wait for the user to type `/refacil:apply`. (See `METHODOLOGY-CONTRACT.md §5`.)
@@ -100,4 +100,5 @@ Do you want me to continue with /refacil:verify?
100
100
  - **Always build the briefing in change mode (Step 1) before delegating** — reduces the sub-agent tool calls.
101
101
  - **Always delegate to the sub-agent**. Do not replicate stack detection or generation logic here.
102
102
  - **Do not invoke with ambiguous scope**. If there are multiple active changes, ask for selection first.
103
+ - Test implementation is English-only (test file names, test cases/descriptions, identifiers, and comments), regardless of the SDD artifact language.
103
104
  - **Flow continuity**: if the user confirms affirmatively ("yes", "ok", "go", "continue", etc.) the continuity question **and tests passed (`passed: true`)**, immediately invoke the **Skill tool** with `skill: "refacil:verify"`. Do not describe it in text or wait for the user to type `/refacil:verify`. (See `METHODOLOGY-CONTRACT.md §5`.)