Add full shell, replaceable Omics adapter and bilingual interaction

Implement approved specification #32 and tickets #33-#37. Keep host authentication server-verified and pin session interaction language. Compile scoped base selectors for browser compatibility and retain full gutters during CSS pruning.
This commit is contained in:
Codex
2026-09-13 14:26:39 +02:00
parent 2d1b714ebe
commit d8a29bfbdd
207 changed files with 8570 additions and 2164 deletions
+17
View File
@@ -36,6 +36,7 @@ var atomicWriteNewFile = writeNewFileAtomically
var effectiveUID = currentEffectiveUID
type answers struct {
shell config.Shell
installationID, profile string
workspaceRemote, workspaceBranch string
workspaceAccess string
@@ -65,6 +66,7 @@ type generatedDescriptor struct {
} `yaml:"runtimeProjection,omitempty"`
} `yaml:"authentication"`
ModelCatalog config.ModelCatalog `yaml:"modelCatalog"`
Shell config.Shell `yaml:"shell,omitempty"`
Overrides []string `yaml:"overrides"`
}
@@ -226,6 +228,11 @@ func collectAnswers(request Request, input io.Reader, output io.Writer, root str
func answersFromRequest(request Request) answers {
answer := request.Answers
return answers{
shell: config.Shell{
Mode: firstNonEmpty(answer.ShellMode, os.Getenv("THT_SETUP_SHELL_MODE")),
DefaultLocale: firstNonEmpty(answer.ShellDefaultLocale, os.Getenv("THT_SETUP_SHELL_DEFAULT_LOCALE")),
Adapter: firstNonEmpty(answer.ShellAdapter, os.Getenv("THT_SETUP_SHELL_ADAPTER")),
},
workspaceRemote: firstNonEmpty(answer.WorkspaceRemote, os.Getenv("THT_SETUP_WORKSPACE_REMOTE")),
workspaceBranch: firstNonEmpty(answer.WorkspaceBranch, os.Getenv("THT_SETUP_WORKSPACE_BRANCH")),
workspaceAccess: firstNonEmpty(answer.WorkspaceAccess, os.Getenv("THT_SETUP_WORKSPACE_ACCESS")),
@@ -272,6 +279,9 @@ func prompt(scanner *bufio.Scanner, output io.Writer, question, defaultValue str
}
func validateAnswers(value answers) error {
if err := value.shell.NormalizeDefaults(); err != nil {
return err
}
if !installationIDPattern.MatchString(value.installationID) {
return errors.New("installation ID must contain only letters, numbers, dashes, and underscores")
}
@@ -322,6 +332,13 @@ func installationDirectory(root, id string) (string, error) {
func render(root, descriptorPath string, value answers) ([]byte, []byte, error) {
descriptor := generatedDescriptor{SchemaVersion: 2, Profile: value.profile, ProjectDirectory: root, EnvFile: filepath.Join(filepath.Dir(descriptorPath), environmentName), ModelCatalog: defaultModelCatalog()}
// Preserve the legacy descriptor bytes when no shell setting was requested.
if value.shell != (config.Shell{}) {
if err := value.shell.NormalizeDefaults(); err != nil {
return nil, nil, err
}
descriptor.Shell = value.shell
}
descriptor.Workspace.Remote, descriptor.Workspace.Branch, descriptor.Workspace.Access = value.workspaceRemote, value.workspaceBranch, value.workspaceAccess
descriptor.Authentication.ConfigDirectory = filepath.Join(filepath.Dir(descriptorPath), "auth")
if value.profile == "server" {