Files
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

113 lines
3.9 KiB
Go

package main
import (
"fmt"
"io"
"strings"
tea "github.com/charmbracelet/bubbletea"
"github.com/zzet/gortex/internal/agents"
)
// installWizardSelectedDashboard mirrors wizardSelectedDashboard but for the
// install command — kept separate so a wizard run for `gortex init` in one
// shell doesn't influence a subsequent `gortex install` in the same process
// (which never happens in real usage, but matters for tests that exercise
// both wizards in one binary).
var installWizardSelectedDashboard bool
// runInstallWizard launches the same wizard model as `gortex init` but seeds
// it from the install* globals (home-rooted setup vs per-repo) and writes
// picks back into them. The dashboard surface is then driven from runInstall
// via selectInstallProgress.
//
// home is passed in so the underlying Detect calls see the right Env without
// the wizard having to re-derive ${HOME}.
func runInstallWizard(cmd interface {
ErrOrStderr() io.Writer
}, home string) (bool, error) {
registry := buildRegistry()
registered := registry.All()
env := agents.Env{
Root: mustAbs(installTrackPath),
Home: home,
Mode: agents.ModeGlobal,
InstallHooks: installHooks,
HookMode: installHookMode,
InstallGlobalInstructions: installClaudeMd,
}
detected := detectAdapters(registered, env)
defaults := initDefaults{
hooks: installHooks,
hookMode: firstNonEmpty(installHookMode, "deny"),
// install doesn't index — leave analyze/skills off in the wizard so
// the toggles still render but reflect that the global install path
// won't touch the project.
analyze: false,
skills: false,
// Machine-global anonymous telemetry — install is the place to choose
// it. Seeded from the current setting (installTelemetry was primed from
// the persisted choice in runInstall).
telemetry: installTelemetry,
showTelemetry: true,
}
model := newInstallWizardModel(home, registered, detected, defaults)
prog := tea.NewProgram(model,
tea.WithOutput(cmd.ErrOrStderr()),
tea.WithAltScreen(),
tea.WithoutSignalHandler(),
)
finalModel, err := prog.Run()
if err != nil {
return false, fmt.Errorf("wizard: %w", err)
}
m, ok := finalModel.(*initWizardModel)
if !ok || m.cancelled || !m.confirmed {
return true, nil
}
// Pour wizard picks back into install* globals.
installHooks = m.hooks
installHookMode = m.hookMode
installTelemetry = m.telemetry
if len(m.pickedAgents) > 0 {
installAgents = strings.Join(m.pickedAgents, ",")
}
installWizardSelectedDashboard = true
return false, nil
}
// newInstallWizardModel builds the wizard with install-specific copy on the
// banner title and subtitle. The widget tree is identical to
// newInitWizardModel; we just swap the title to "gortex install" and the
// rootPath to a friendly "your machine" so the subtitle reads sensibly.
func newInstallWizardModel(home string, registered []agents.Adapter, detected map[string]bool, defaults initDefaults) *initWizardModel {
m := newInitWizardModel(home, registered, detected, defaults)
m.title = "gortex install"
m.rootPath = "your machine"
return m
}
// selectInstallProgress returns the right initProgress surface for the
// install run. Same precedence as init: --no-progress → plain line tracker;
// wizard ran → dashboard; otherwise the banner tracker.
func selectInstallProgress(w io.Writer) initProgress {
stages := []string{stageAdapters}
if noProgress {
return newTrackerProgress(w, stages, true)
}
if installWizardSelectedDashboard {
// Install has exactly one high-level stage (adapters); the dashboard
// is still valuable because it shows the per-adapter sub-status as a
// framed live view instead of a single line that scrolls past.
if s := startInitDashboard(w, stages); s != nil {
return newDashboardProgress(s)
}
}
return newTrackerProgress(w, stages, false)
}