refacil-sdd-ai 5.0.0 → 5.0.1
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 +37 -5
- package/agents/proposer.md +12 -0
- package/bin/cli.js +28 -5
- package/lib/commands/sdd.js +28 -9
- package/lib/config.js +59 -2
- package/package.json +1 -1
- package/skills/propose/SKILL.md +5 -0
package/README.md
CHANGED
|
@@ -29,8 +29,8 @@ refacil-sdd-ai init
|
|
|
29
29
|
# whose folder already exists. Use --all to install for all three without prompting.
|
|
30
30
|
# Copies skills and sub-agents to the selected IDEs, configures hooks,
|
|
31
31
|
# and creates/updates .claudeignore, .cursorignore and .opencodeignore.
|
|
32
|
-
# Also prompts for global branch config (baseBranch, protectedBranches)
|
|
33
|
-
# from ~/.refacil-sdd-ai/config.yaml. Skipped with --yes or --defaults.
|
|
32
|
+
# Also prompts for global branch config (baseBranch, protectedBranches, artifactLanguage)
|
|
33
|
+
# pre-filled from ~/.refacil-sdd-ai/config.yaml. Skipped with --yes or --defaults.
|
|
34
34
|
|
|
35
35
|
# 3. Restart your IDE session
|
|
36
36
|
# (new skills are not detected until you restart)
|
|
@@ -102,11 +102,43 @@ Native CLI for **`refacil-sdd/`** (no separate OpenSpec skill layer). Used by sk
|
|
|
102
102
|
| `refacil-sdd-ai sdd tasks-update <name>` | Mark a task done (`--task N --done`) |
|
|
103
103
|
| `refacil-sdd-ai sdd archive <name>` | Move a regular change to `refacil-sdd/changes/archive/` |
|
|
104
104
|
| `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
|
|
106
|
-
| `refacil-sdd-ai sdd write-config [--global] [--base-branch <v>] [--protected-branches <csv>]` | Write or merge
|
|
105
|
+
| `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`). |
|
|
106
|
+
| `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
107
|
|
|
108
108
|
Run **`refacil-sdd-ai help`** for the full list including `bus` and `compact` subcommands.
|
|
109
109
|
|
|
110
|
+
### Artifact Language
|
|
111
|
+
|
|
112
|
+
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.
|
|
113
|
+
|
|
114
|
+
**Supported values**: `english` (default) · `spanish`
|
|
115
|
+
|
|
116
|
+
**Configure globally** — applies to all repos for this user:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
refacil-sdd-ai sdd write-config --global --artifact-language spanish
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Configure per project** — overrides the global value (commit `refacil-sdd/config.yaml` for team-wide effect):
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
refacil-sdd-ai sdd write-config --artifact-language spanish
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**Check the active value**:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
refacil-sdd-ai sdd config
|
|
132
|
+
# artifactLanguage [global]: spanish
|
|
133
|
+
|
|
134
|
+
refacil-sdd-ai sdd config --json
|
|
135
|
+
# { ..., "artifactLanguage": "spanish", "sources": { "artifactLanguage": "global" } }
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Cascade**: project `refacil-sdd/config.yaml` → global `~/.refacil-sdd-ai/config.yaml` → default `english`.
|
|
139
|
+
|
|
140
|
+
`refacil-sdd-ai init` also prompts for this preference and writes to the global config. Skip with `--yes` to keep the current value.
|
|
141
|
+
|
|
110
142
|
### Command rewrite control (`compact-bash`)
|
|
111
143
|
|
|
112
144
|
| Command | Description |
|
|
@@ -380,7 +412,7 @@ Defined in `skills/prereqs/METHODOLOGY-CONTRACT.md`:
|
|
|
380
412
|
- **Multi-stack tests**: detects the real test command (does not hardcode `npm test`).
|
|
381
413
|
- **`AGENTS.md` by profile** (`sdd` vs `agents`): the methodology respects both.
|
|
382
414
|
- **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
|
|
415
|
+
- **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
416
|
|
|
385
417
|
---
|
|
386
418
|
|
package/agents/proposer.md
CHANGED
|
@@ -153,6 +153,18 @@ Effort estimate: **S** (< 1h), **M** (1-4h), **L** (> 4h).
|
|
|
153
153
|
|
|
154
154
|
### Step 1: Explore the codebase
|
|
155
155
|
|
|
156
|
+
#### Step 1a: Language resolution (run FIRST, before any exploration)
|
|
157
|
+
|
|
158
|
+
Run: `refacil-sdd-ai sdd config --json`
|
|
159
|
+
|
|
160
|
+
Read the `artifactLanguage` field from the JSON output. Prepend the following instruction to your working context for this session:
|
|
161
|
+
|
|
162
|
+
> 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.
|
|
163
|
+
|
|
164
|
+
Fallback rule: if the command fails, produces invalid JSON, or returns an unknown/missing `artifactLanguage` value, use `english` and continue without interruption.
|
|
165
|
+
|
|
166
|
+
#### Step 1b: Codebase exploration
|
|
167
|
+
|
|
156
168
|
Before generating artifacts, explore the project so that `design.md` is realistic and not invented:
|
|
157
169
|
- Read `AGENTS.md` to understand the current architecture.
|
|
158
170
|
- Identify files and modules relevant to the described change.
|
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
|
|
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
|
-
//
|
|
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
|
package/lib/commands/sdd.js
CHANGED
|
@@ -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 --
|
|
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
|
|
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
|
|
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
package/skills/propose/SKILL.md
CHANGED
|
@@ -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.
|