codexspec 0.6.2__tar.gz → 0.6.3__tar.gz
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.
- {codexspec-0.6.2 → codexspec-0.6.3}/PKG-INFO +41 -16
- {codexspec-0.6.2 → codexspec-0.6.3}/README.md +40 -15
- {codexspec-0.6.2 → codexspec-0.6.3}/pyproject.toml +1 -1
- {codexspec-0.6.2 → codexspec-0.6.3}/src/codexspec/__init__.py +134 -70
- {codexspec-0.6.2 → codexspec-0.6.3}/src/codexspec/i18n.py +53 -117
- {codexspec-0.6.2 → codexspec-0.6.3}/src/codexspec/translator.py +6 -0
- codexspec-0.6.3/templates/translations/de.json +151 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/translations/en.json +2 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/translations/es.json +2 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/translations/fr.json +2 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/translations/ja.json +2 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/translations/ko.json +2 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/translations/pt-BR.json +2 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/translations/zh-CN.json +2 -0
- codexspec-0.6.2/templates/translations/de.json +0 -149
- {codexspec-0.6.2 → codexspec-0.6.3}/.gitignore +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/LICENSE +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/codexspec-icon.svg +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/codexspec-logo-dark.svg +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/codexspec-logo-light.svg +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/scripts/bash/check-i18n-completeness.sh +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/scripts/bash/check-i18n-structure.sh +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/scripts/bash/check-prerequisites.sh +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/scripts/bash/common.sh +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/scripts/bash/create-new-feature.sh +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/scripts/powershell/check-prerequisites.ps1 +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/scripts/powershell/common.ps1 +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/scripts/powershell/create-new-feature.ps1 +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/src/codexspec/commands/__init__.py +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/src/codexspec/commands/installer.py +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/src/codexspec/idea.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/commands/analyze.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/commands/checklist.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/commands/clarify.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/commands/commit-staged.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/commands/config.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/commands/constitution.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/commands/generate-spec.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/commands/implement-tasks.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/commands/plan-to-tasks.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/commands/pr.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/commands/quick.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/commands/review-code.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/commands/review-plan.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/commands/review-spec.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/commands/review-tasks.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/commands/spec-to-plan.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/commands/specify.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/commands/tasks-to-issues.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/docs/checklist-template.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/docs/constitution-template.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/docs/plan-template-detailed.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/docs/plan-template-simple.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/docs/requirements-template.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/docs/spec-template-detailed.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/docs/spec-template-simple.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/docs/tasks-template-detailed.md +0 -0
- {codexspec-0.6.2 → codexspec-0.6.3}/templates/docs/tasks-template-simple.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codexspec
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.3
|
|
4
4
|
Summary: CodexSpec - A Requirements-First SDD toolkit for Claude Code
|
|
5
5
|
Project-URL: Homepage, https://github.com/Zts0hg/codexspec
|
|
6
6
|
Project-URL: Repository, https://github.com/Zts0hg/codexspec
|
|
@@ -528,12 +528,15 @@ Implementation follows **conditional TDD workflow**:
|
|
|
528
528
|
|
|
529
529
|
| Option | Description |
|
|
530
530
|
| --------------- | ------------------------------------- |
|
|
531
|
-
| `PROJECT_NAME` | Project directory name
|
|
532
|
-
| `--here`, `-h` | Initialize in current directory
|
|
531
|
+
| `PROJECT_NAME` | Project directory name (`.` or `--here` for current dir) |
|
|
532
|
+
| `--here`, `-h` | Initialize in the current directory |
|
|
533
533
|
| `--ai`, `-a` | AI assistant to use (default: claude) |
|
|
534
|
-
| `--lang`, `-l` | Output language (e.g., en, zh-CN, ja) |
|
|
535
|
-
| `--
|
|
536
|
-
| `--
|
|
534
|
+
| `--lang`, `-l` | Output (base) language; interaction/document/commit fall back to it (e.g., en, zh-CN, ja) |
|
|
535
|
+
| `--interaction-lang` | Interaction language (LLM dialogue + CLI output); overrides `--lang` |
|
|
536
|
+
| `--document-lang` | Document language (generated spec/plan/tasks); overrides `--lang` |
|
|
537
|
+
| `--commit-lang` | Commit-message language; overrides `--lang` |
|
|
538
|
+
| `--force`, `-f` | Overwrite files + auto-confirm prompts; never regenerates `config.yml` |
|
|
539
|
+
| `--no-git` | Skip git repository initialization |
|
|
537
540
|
| `--debug`, `-d` | Enable debug output |
|
|
538
541
|
|
|
539
542
|
</details>
|
|
@@ -543,8 +546,10 @@ Implementation follows **conditional TDD workflow**:
|
|
|
543
546
|
|
|
544
547
|
| Option | Description |
|
|
545
548
|
| ------------------------- | ---------------------------- |
|
|
546
|
-
| `--set-lang`, `-l` | Set output language
|
|
547
|
-
| `--set-
|
|
549
|
+
| `--set-lang`, `-l` | Set the output (base) language |
|
|
550
|
+
| `--set-interaction-lang` | Set the interaction language |
|
|
551
|
+
| `--set-document-lang` | Set the document language |
|
|
552
|
+
| `--set-commit-lang`, `-c` | Set the commit-message language |
|
|
548
553
|
| `--list-langs` | List all supported languages |
|
|
549
554
|
|
|
550
555
|
</details>
|
|
@@ -628,28 +633,46 @@ CodexSpec is inspired by GitHub spec-kit with key differences:
|
|
|
628
633
|
|
|
629
634
|
CodexSpec supports multiple languages through **LLM dynamic translation**. No translation templates to maintain - Claude translates content at runtime based on your language configuration.
|
|
630
635
|
|
|
636
|
+
### Language Dimensions
|
|
637
|
+
|
|
638
|
+
CodexSpec splits language into four independently-configurable dimensions. `output` is the base; the others override it and fall back to it (then `en`) when unset — so you can converse with Claude in one language while keeping generated artifacts or commit messages in another.
|
|
639
|
+
|
|
640
|
+
| Dimension | `config.yml` key | Set at init | Set later | Controls | Falls back to |
|
|
641
|
+
|-----------|------------------|-------------|-----------|----------|---------------|
|
|
642
|
+
| Output (base) | `output` | `--lang` | `config --set-lang` | base for the other three | `en` |
|
|
643
|
+
| Interaction | `interaction` | `--interaction-lang` | `config --set-interaction-lang` | LLM dialogue + CLI output | output → `en` |
|
|
644
|
+
| Document | `document` | `--document-lang` | `config --set-document-lang` | generated spec/plan/tasks | output → `en` |
|
|
645
|
+
| Commit | `commit` | `--commit-lang` | `config --set-commit-lang` | git commit messages | output → `en` |
|
|
646
|
+
| Templates | `templates` | — | — | template source (always `en`) | — |
|
|
647
|
+
|
|
631
648
|
### Setting Language
|
|
632
649
|
|
|
633
650
|
**During initialization:**
|
|
634
651
|
|
|
635
652
|
```bash
|
|
636
|
-
#
|
|
653
|
+
# Chinese output (sets the output base)
|
|
637
654
|
codexspec init my-project --lang zh-CN
|
|
638
655
|
|
|
639
|
-
#
|
|
640
|
-
codexspec init my-project --lang
|
|
656
|
+
# Fully non-interactive: zh-CN base, English commit messages
|
|
657
|
+
codexspec init my-project --lang zh-CN --commit-lang en
|
|
658
|
+
|
|
659
|
+
# Set every dimension explicitly (scriptable, no prompts)
|
|
660
|
+
codexspec init my-project \
|
|
661
|
+
--interaction-lang zh-CN --document-lang en --commit-lang en
|
|
641
662
|
```
|
|
642
663
|
|
|
664
|
+
First-time init in a TTY without `--lang` (and without all three dimension flags) prompts for a base language; in a non-TTY (CI/scripts) it defaults to `en`. Re-running `init` preserves any language key you did not specify.
|
|
665
|
+
|
|
643
666
|
**After initialization:**
|
|
644
667
|
|
|
645
668
|
```bash
|
|
646
669
|
# View current configuration
|
|
647
670
|
codexspec config
|
|
648
671
|
|
|
649
|
-
# Change
|
|
672
|
+
# Change a single dimension
|
|
650
673
|
codexspec config --set-lang zh-CN
|
|
651
|
-
|
|
652
|
-
|
|
674
|
+
codexspec config --set-interaction-lang zh-CN
|
|
675
|
+
codexspec config --set-document-lang en
|
|
653
676
|
codexspec config --set-commit-lang en
|
|
654
677
|
```
|
|
655
678
|
|
|
@@ -680,8 +703,10 @@ codexspec config --set-commit-lang en
|
|
|
680
703
|
version: "1.0"
|
|
681
704
|
|
|
682
705
|
language:
|
|
683
|
-
output: "zh-CN" #
|
|
684
|
-
|
|
706
|
+
output: "zh-CN" # Base language; the three below fall back to it, then "en"
|
|
707
|
+
interaction: "zh-CN" # LLM dialogue + codexspec CLI output (optional → defaults to output)
|
|
708
|
+
document: "en" # Generated requirements/spec/plan/tasks (optional → defaults to output)
|
|
709
|
+
commit: "en" # Git commit messages (optional → defaults to output)
|
|
685
710
|
templates: "en" # Keep as "en"
|
|
686
711
|
|
|
687
712
|
project:
|
|
@@ -483,12 +483,15 @@ Implementation follows **conditional TDD workflow**:
|
|
|
483
483
|
|
|
484
484
|
| Option | Description |
|
|
485
485
|
| --------------- | ------------------------------------- |
|
|
486
|
-
| `PROJECT_NAME` | Project directory name
|
|
487
|
-
| `--here`, `-h` | Initialize in current directory
|
|
486
|
+
| `PROJECT_NAME` | Project directory name (`.` or `--here` for current dir) |
|
|
487
|
+
| `--here`, `-h` | Initialize in the current directory |
|
|
488
488
|
| `--ai`, `-a` | AI assistant to use (default: claude) |
|
|
489
|
-
| `--lang`, `-l` | Output language (e.g., en, zh-CN, ja) |
|
|
490
|
-
| `--
|
|
491
|
-
| `--
|
|
489
|
+
| `--lang`, `-l` | Output (base) language; interaction/document/commit fall back to it (e.g., en, zh-CN, ja) |
|
|
490
|
+
| `--interaction-lang` | Interaction language (LLM dialogue + CLI output); overrides `--lang` |
|
|
491
|
+
| `--document-lang` | Document language (generated spec/plan/tasks); overrides `--lang` |
|
|
492
|
+
| `--commit-lang` | Commit-message language; overrides `--lang` |
|
|
493
|
+
| `--force`, `-f` | Overwrite files + auto-confirm prompts; never regenerates `config.yml` |
|
|
494
|
+
| `--no-git` | Skip git repository initialization |
|
|
492
495
|
| `--debug`, `-d` | Enable debug output |
|
|
493
496
|
|
|
494
497
|
</details>
|
|
@@ -498,8 +501,10 @@ Implementation follows **conditional TDD workflow**:
|
|
|
498
501
|
|
|
499
502
|
| Option | Description |
|
|
500
503
|
| ------------------------- | ---------------------------- |
|
|
501
|
-
| `--set-lang`, `-l` | Set output language
|
|
502
|
-
| `--set-
|
|
504
|
+
| `--set-lang`, `-l` | Set the output (base) language |
|
|
505
|
+
| `--set-interaction-lang` | Set the interaction language |
|
|
506
|
+
| `--set-document-lang` | Set the document language |
|
|
507
|
+
| `--set-commit-lang`, `-c` | Set the commit-message language |
|
|
503
508
|
| `--list-langs` | List all supported languages |
|
|
504
509
|
|
|
505
510
|
</details>
|
|
@@ -583,28 +588,46 @@ CodexSpec is inspired by GitHub spec-kit with key differences:
|
|
|
583
588
|
|
|
584
589
|
CodexSpec supports multiple languages through **LLM dynamic translation**. No translation templates to maintain - Claude translates content at runtime based on your language configuration.
|
|
585
590
|
|
|
591
|
+
### Language Dimensions
|
|
592
|
+
|
|
593
|
+
CodexSpec splits language into four independently-configurable dimensions. `output` is the base; the others override it and fall back to it (then `en`) when unset — so you can converse with Claude in one language while keeping generated artifacts or commit messages in another.
|
|
594
|
+
|
|
595
|
+
| Dimension | `config.yml` key | Set at init | Set later | Controls | Falls back to |
|
|
596
|
+
|-----------|------------------|-------------|-----------|----------|---------------|
|
|
597
|
+
| Output (base) | `output` | `--lang` | `config --set-lang` | base for the other three | `en` |
|
|
598
|
+
| Interaction | `interaction` | `--interaction-lang` | `config --set-interaction-lang` | LLM dialogue + CLI output | output → `en` |
|
|
599
|
+
| Document | `document` | `--document-lang` | `config --set-document-lang` | generated spec/plan/tasks | output → `en` |
|
|
600
|
+
| Commit | `commit` | `--commit-lang` | `config --set-commit-lang` | git commit messages | output → `en` |
|
|
601
|
+
| Templates | `templates` | — | — | template source (always `en`) | — |
|
|
602
|
+
|
|
586
603
|
### Setting Language
|
|
587
604
|
|
|
588
605
|
**During initialization:**
|
|
589
606
|
|
|
590
607
|
```bash
|
|
591
|
-
#
|
|
608
|
+
# Chinese output (sets the output base)
|
|
592
609
|
codexspec init my-project --lang zh-CN
|
|
593
610
|
|
|
594
|
-
#
|
|
595
|
-
codexspec init my-project --lang
|
|
611
|
+
# Fully non-interactive: zh-CN base, English commit messages
|
|
612
|
+
codexspec init my-project --lang zh-CN --commit-lang en
|
|
613
|
+
|
|
614
|
+
# Set every dimension explicitly (scriptable, no prompts)
|
|
615
|
+
codexspec init my-project \
|
|
616
|
+
--interaction-lang zh-CN --document-lang en --commit-lang en
|
|
596
617
|
```
|
|
597
618
|
|
|
619
|
+
First-time init in a TTY without `--lang` (and without all three dimension flags) prompts for a base language; in a non-TTY (CI/scripts) it defaults to `en`. Re-running `init` preserves any language key you did not specify.
|
|
620
|
+
|
|
598
621
|
**After initialization:**
|
|
599
622
|
|
|
600
623
|
```bash
|
|
601
624
|
# View current configuration
|
|
602
625
|
codexspec config
|
|
603
626
|
|
|
604
|
-
# Change
|
|
627
|
+
# Change a single dimension
|
|
605
628
|
codexspec config --set-lang zh-CN
|
|
606
|
-
|
|
607
|
-
|
|
629
|
+
codexspec config --set-interaction-lang zh-CN
|
|
630
|
+
codexspec config --set-document-lang en
|
|
608
631
|
codexspec config --set-commit-lang en
|
|
609
632
|
```
|
|
610
633
|
|
|
@@ -635,8 +658,10 @@ codexspec config --set-commit-lang en
|
|
|
635
658
|
version: "1.0"
|
|
636
659
|
|
|
637
660
|
language:
|
|
638
|
-
output: "zh-CN" #
|
|
639
|
-
|
|
661
|
+
output: "zh-CN" # Base language; the three below fall back to it, then "en"
|
|
662
|
+
interaction: "zh-CN" # LLM dialogue + codexspec CLI output (optional → defaults to output)
|
|
663
|
+
document: "en" # Generated requirements/spec/plan/tasks (optional → defaults to output)
|
|
664
|
+
commit: "en" # Git commit messages (optional → defaults to output)
|
|
640
665
|
templates: "en" # Keep as "en"
|
|
641
666
|
|
|
642
667
|
project:
|
|
@@ -29,15 +29,12 @@ from .commands.installer import (
|
|
|
29
29
|
)
|
|
30
30
|
from .i18n import (
|
|
31
31
|
generate_config_content,
|
|
32
|
-
get_commit_language,
|
|
33
32
|
get_interaction_language,
|
|
34
33
|
get_language_name,
|
|
35
34
|
get_supported_languages,
|
|
36
35
|
is_supported_language,
|
|
37
36
|
normalize_locale,
|
|
38
|
-
update_config_language,
|
|
39
37
|
update_language_field,
|
|
40
|
-
update_output_language,
|
|
41
38
|
)
|
|
42
39
|
from .translator import translate
|
|
43
40
|
|
|
@@ -445,13 +442,35 @@ def init(
|
|
|
445
442
|
None,
|
|
446
443
|
"--lang",
|
|
447
444
|
"-l",
|
|
448
|
-
help=
|
|
445
|
+
help=(
|
|
446
|
+
"Output (base) language (e.g., en, zh-CN, ja). interaction/document/commit "
|
|
447
|
+
"fall back to it. Prompted on first-time init if not given in a TTY."
|
|
448
|
+
),
|
|
449
|
+
),
|
|
450
|
+
interaction_lang: Optional[str] = typer.Option(
|
|
451
|
+
None,
|
|
452
|
+
"--interaction-lang",
|
|
453
|
+
help=("Interaction language (LLM dialogue + codexspec CLI output); overrides --lang for this dimension."),
|
|
454
|
+
),
|
|
455
|
+
document_lang: Optional[str] = typer.Option(
|
|
456
|
+
None,
|
|
457
|
+
"--document-lang",
|
|
458
|
+
help="Document language (generated requirements/spec/plan/tasks); overrides --lang.",
|
|
459
|
+
),
|
|
460
|
+
commit_lang: Optional[str] = typer.Option(
|
|
461
|
+
None,
|
|
462
|
+
"--commit-lang",
|
|
463
|
+
help="Commit-message language; overrides --lang.",
|
|
449
464
|
),
|
|
450
465
|
force: bool = typer.Option(
|
|
451
466
|
False,
|
|
452
467
|
"--force",
|
|
453
468
|
"-f",
|
|
454
|
-
help=
|
|
469
|
+
help=(
|
|
470
|
+
"Overwrite existing files and auto-confirm prompts (skips the language "
|
|
471
|
+
"prompt and command-update/migration confirms). Language config is updated "
|
|
472
|
+
"surgically, never fully regenerated."
|
|
473
|
+
),
|
|
455
474
|
),
|
|
456
475
|
no_git: bool = typer.Option(
|
|
457
476
|
False,
|
|
@@ -478,37 +497,85 @@ def init(
|
|
|
478
497
|
codexspec init . --ai claude
|
|
479
498
|
codexspec init --here --ai claude
|
|
480
499
|
codexspec init . --force --ai claude
|
|
500
|
+
codexspec init my-project --interaction-lang en --document-lang zh-CN --commit-lang en
|
|
481
501
|
"""
|
|
482
|
-
#
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
else:
|
|
493
|
-
# Non-TTY environment: use default
|
|
494
|
-
lang = "en"
|
|
495
|
-
|
|
496
|
-
# Normalize language code early for use throughout the function
|
|
497
|
-
normalized_lang = normalize_locale(lang)
|
|
498
|
-
|
|
499
|
-
# Determine target directory
|
|
502
|
+
# When init() is invoked directly (not via the Typer CLI), typer.Option defaults
|
|
503
|
+
# arrive as OptionInfo sentinels rather than None. Coerce the language params to
|
|
504
|
+
# Optional[str] so the resolution logic below is robust in both call paths.
|
|
505
|
+
lang = lang if isinstance(lang, str) else None
|
|
506
|
+
interaction_lang = interaction_lang if isinstance(interaction_lang, str) else None
|
|
507
|
+
document_lang = document_lang if isinstance(document_lang, str) else None
|
|
508
|
+
commit_lang = commit_lang if isinstance(commit_lang, str) else None
|
|
509
|
+
|
|
510
|
+
# Determine target directory first — needed to detect an existing config.yml
|
|
511
|
+
# before resolving the language base (REQ-007).
|
|
500
512
|
if here or project_name == ".":
|
|
501
513
|
target_dir = Path.cwd()
|
|
502
514
|
elif project_name:
|
|
503
515
|
target_dir = Path.cwd() / project_name
|
|
504
516
|
else:
|
|
505
|
-
console.print(f"[red]{translate('cli.init.error_no_project_name',
|
|
517
|
+
console.print(f"[red]{translate('cli.init.error_no_project_name', 'en')}[/red]")
|
|
506
518
|
raise typer.Exit(1)
|
|
507
519
|
|
|
520
|
+
config_file = target_dir / ".codexspec" / "config.yml"
|
|
521
|
+
config_exists = config_file.exists()
|
|
522
|
+
|
|
523
|
+
def _normalize_lang_option(raw: str) -> str:
|
|
524
|
+
"""Normalize a language flag value; warn (do not error) if unsupported."""
|
|
525
|
+
normalized = normalize_locale(raw)
|
|
526
|
+
if not is_supported_language(normalized):
|
|
527
|
+
console.print(f"[yellow]Warning: '{raw}' is not in the list of commonly supported languages.[/yellow]")
|
|
528
|
+
console.print(
|
|
529
|
+
"It may still work if Claude supports it. "
|
|
530
|
+
"Run [cyan]codexspec config --list-langs[/cyan] to see supported languages."
|
|
531
|
+
)
|
|
532
|
+
return normalized
|
|
533
|
+
|
|
534
|
+
# Per-dimension overrides: each flag maps to exactly one config key, with no
|
|
535
|
+
# CLI-level precedence between them (DEC-001).
|
|
536
|
+
lang_overrides: dict[str, str] = {}
|
|
537
|
+
if interaction_lang is not None:
|
|
538
|
+
lang_overrides["interaction"] = _normalize_lang_option(interaction_lang)
|
|
539
|
+
if document_lang is not None:
|
|
540
|
+
lang_overrides["document"] = _normalize_lang_option(document_lang)
|
|
541
|
+
if commit_lang is not None:
|
|
542
|
+
lang_overrides["commit"] = _normalize_lang_option(commit_lang)
|
|
543
|
+
|
|
544
|
+
# The output base is determinable if --lang was given OR all three specific
|
|
545
|
+
# dimensions are explicit (output is then irrelevant). Otherwise it must be
|
|
546
|
+
# prompted (first-time, TTY) or defaulted (first-time, non-TTY); on an
|
|
547
|
+
# existing config with no flag, everything is preserved (REQ-007).
|
|
548
|
+
output_value: Optional[str] = None
|
|
549
|
+
if lang is not None:
|
|
550
|
+
output_value = _normalize_lang_option(lang)
|
|
551
|
+
base_determinable = output_value is not None or (
|
|
552
|
+
"interaction" in lang_overrides and "document" in lang_overrides and "commit" in lang_overrides
|
|
553
|
+
)
|
|
554
|
+
prompted_base = False
|
|
555
|
+
if base_determinable:
|
|
556
|
+
normalized_lang = normalize_locale(output_value) if output_value else "en"
|
|
557
|
+
elif config_exists:
|
|
558
|
+
normalized_lang = get_interaction_language(config_file)
|
|
559
|
+
elif sys.stdin.isatty():
|
|
560
|
+
try:
|
|
561
|
+
output_value = normalize_locale(prompt_language_selection())
|
|
562
|
+
prompted_base = True
|
|
563
|
+
normalized_lang = output_value
|
|
564
|
+
except KeyboardInterrupt:
|
|
565
|
+
console.print()
|
|
566
|
+
console.print("[yellow]Selection cancelled, using default language (en)[/yellow]")
|
|
567
|
+
output_value = "en"
|
|
568
|
+
normalized_lang = "en"
|
|
569
|
+
else:
|
|
570
|
+
output_value = "en"
|
|
571
|
+
normalized_lang = "en"
|
|
572
|
+
|
|
508
573
|
if debug:
|
|
509
574
|
console.print(f"[dim]Target directory: {target_dir}[/dim]")
|
|
510
575
|
console.print(f"[dim]AI assistant: {ai}[/dim]")
|
|
511
|
-
console.print(
|
|
576
|
+
console.print(
|
|
577
|
+
f"[dim]Language base: {output_value} (messages: {normalized_lang}); overrides: {lang_overrides}[/dim]"
|
|
578
|
+
)
|
|
512
579
|
|
|
513
580
|
# Check if directory exists and handle accordingly
|
|
514
581
|
if target_dir.exists() and not here and project_name != ".":
|
|
@@ -591,7 +658,7 @@ def init(
|
|
|
591
658
|
console.print(f"[dim]{translate('cli.init.migration_old_structure', normalized_lang)}[/dim]")
|
|
592
659
|
console.print(f"[dim]{translate('cli.init.migration_new_structure', normalized_lang)}[/dim]")
|
|
593
660
|
|
|
594
|
-
if Confirm.ask(translate("cli.init.migration_confirm", normalized_lang), default=True):
|
|
661
|
+
if force or Confirm.ask(translate("cli.init.migration_confirm", normalized_lang), default=True):
|
|
595
662
|
if migrate_old_commands(claude_dir, old_files):
|
|
596
663
|
console.print(f"[green]{translate('cli.init.migration_complete', normalized_lang)}[/green]")
|
|
597
664
|
migration_happened = True
|
|
@@ -603,14 +670,14 @@ def init(
|
|
|
603
670
|
# Install or update commands (translate after migration if user wants)
|
|
604
671
|
if migration_happened:
|
|
605
672
|
# Migration moved files, ask if user wants to update/translate them
|
|
606
|
-
if Confirm.ask(translate("cli.init.update_confirm", normalized_lang), default=True):
|
|
673
|
+
if force or Confirm.ask(translate("cli.init.update_confirm", normalized_lang), default=True):
|
|
607
674
|
count = install_commands_to_subdir(
|
|
608
675
|
codexspec_commands_dir, templates_dir, force=True, language=normalized_lang
|
|
609
676
|
)
|
|
610
677
|
console.print(f"[green]{translate('cli.init.commands_updated', normalized_lang, count=count)}[/green]")
|
|
611
678
|
elif should_update_commands(codexspec_dir):
|
|
612
679
|
console.print()
|
|
613
|
-
if Confirm.ask(translate("cli.init.update_confirm", normalized_lang), default=True):
|
|
680
|
+
if force or Confirm.ask(translate("cli.init.update_confirm", normalized_lang), default=True):
|
|
614
681
|
count = install_commands_to_subdir(
|
|
615
682
|
codexspec_commands_dir, templates_dir, force=True, language=normalized_lang
|
|
616
683
|
)
|
|
@@ -636,53 +703,50 @@ def init(
|
|
|
636
703
|
msg = translate("cli.init.created_file", normalized_lang, file=".codexspec/memory/constitution.md")
|
|
637
704
|
console.print(f"[green]{msg}[/green]")
|
|
638
705
|
|
|
639
|
-
#
|
|
706
|
+
# Apply language settings surgically (DEC-001 / CON-005 / REQ-005 / REQ-010).
|
|
707
|
+
# Build the full {key: value} map to write: the output base (if resolved) plus
|
|
708
|
+
# the per-dimension overrides. config.yml is never fully regenerated -- not
|
|
709
|
+
# even under --force -- and keys the user did not specify are always preserved.
|
|
640
710
|
config_file = codexspec_dir / "config.yml"
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
711
|
+
keys_to_write: dict[str, str] = {}
|
|
712
|
+
if output_value is not None:
|
|
713
|
+
keys_to_write["output"] = output_value
|
|
714
|
+
keys_to_write.update(lang_overrides)
|
|
715
|
+
|
|
716
|
+
wrote_keys: list[str] = []
|
|
717
|
+
if keys_to_write:
|
|
718
|
+
if not config_exists:
|
|
719
|
+
# Fresh project: emit only the chosen keys (sparse config).
|
|
720
|
+
config_content = generate_config_content(
|
|
721
|
+
output=keys_to_write.get("output"),
|
|
722
|
+
interaction=keys_to_write.get("interaction"),
|
|
723
|
+
document=keys_to_write.get("document"),
|
|
724
|
+
commit=keys_to_write.get("commit"),
|
|
725
|
+
created=datetime.now().strftime("%Y-%m-%d"),
|
|
726
|
+
)
|
|
727
|
+
config_file.write_text(config_content, encoding="utf-8")
|
|
728
|
+
wrote_keys = list(keys_to_write.keys())
|
|
729
|
+
lang_name = get_language_name(normalized_lang)
|
|
659
730
|
msg = translate(
|
|
660
|
-
"cli.init.
|
|
731
|
+
"cli.init.created_file",
|
|
661
732
|
normalized_lang,
|
|
662
|
-
|
|
663
|
-
selected=normalized_lang,
|
|
733
|
+
file=f".codexspec/config.yml (language: {lang_name})",
|
|
664
734
|
)
|
|
665
|
-
|
|
666
|
-
update_config_language(config_file, normalized_lang)
|
|
667
|
-
console.print(
|
|
668
|
-
f"[green]{translate('cli.init.commit_lang_updated', normalized_lang, lang=normalized_lang)}[/green]"
|
|
669
|
-
)
|
|
670
|
-
else:
|
|
671
|
-
# Update only output language, keep commit language
|
|
672
|
-
update_output_language(config_file, normalized_lang)
|
|
673
|
-
console.print(
|
|
674
|
-
f"[dim]{translate('cli.init.commit_lang_kept', normalized_lang, lang=current_commit_lang)}[/dim]"
|
|
675
|
-
)
|
|
735
|
+
console.print(f"[green]{msg}[/green]")
|
|
676
736
|
else:
|
|
677
|
-
#
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
737
|
+
# Existing project: update each chosen key in place, preserving the rest.
|
|
738
|
+
for key, value in keys_to_write.items():
|
|
739
|
+
if update_language_field(config_file, key, value):
|
|
740
|
+
wrote_keys.append(key)
|
|
741
|
+
|
|
742
|
+
# Non-blocking notice of which language keys were set (REQ-010).
|
|
743
|
+
if wrote_keys:
|
|
744
|
+
details = ", ".join(f"{k}={keys_to_write[k]}" for k in wrote_keys)
|
|
745
|
+
console.print(f"[dim]{translate('cli.init.language_key_set', normalized_lang, details=details)}[/dim]")
|
|
746
|
+
|
|
747
|
+
# Discoverability hint after a first-time interactive base selection (REQ-009).
|
|
748
|
+
if prompted_base:
|
|
749
|
+
console.print(f"[dim]{translate('cli.init.language_dimensions_hint', normalized_lang)}[/dim]")
|
|
686
750
|
|
|
687
751
|
# Create CLAUDE.md
|
|
688
752
|
claude_md = target_dir / "CLAUDE.md"
|