Documentation
¶
Overview ¶
Production permission-authorizer assembly: binds the landed permission seams — the in-memory grant table, the turn-scoped approval cache, the gated prompt, persistence-with-degradation, and the event emitters — into one dispatch.Authorizer that drives permissions.Authorize for every production tool/shell permission check. It carries the prompt display command text separately from the matching subject (so a structured tool matches on its registered name yet displays its full call with arguments) and serializes shared grant-table/cache access — per seam call for race safety (syncGrants) and per request identity so concurrent *identical* checks resolve from the first's recorded grant/cache instead of re-prompting (keyedMutex) — so scheduler-driven work units authorize safely in parallel behind one shared prompt gate.
Operation-neutral prepared-child activation lifecycle: creates a child session from the active parent and transitions the running app onto it.
Production implementations of the /clear capability interfaces, bound to the running app + bootstrap result. They live in internal/bootstrap (not internal/tui) so the write-failure sink can delegate to sessionfailures without re-introducing the sessionfailures -> tui import cycle.
First-run (global) and project-open scaffolding of the commented codemeldignore starter templates: both writes create the file only when absent and never overwrite an existing one.
Production tui.ConnectDeps for /connect <provider>: it turns a validated, connectable provider id into a durable global provider.<name> settings entry through the byte-preserving config.Persist writer, so /connect adds no ad-hoc credential write of its own. It lives in internal/bootstrap because internal/tui cannot import internal/config or internal/provider (that edge would cycle).
Dev-debug gate: a development-only switch that turns on the ordered suggest_followup trace (events.SuggestFollowupDebug). Off by default and never on in a normal session, so normal sessions stay byte-free of the debug events.
Production implementations of tui.EffortModel and tui.EffortApplier, plus the shared picker-apply transaction reused by the /model applier. They live in internal/bootstrap because internal/tui cannot import internal/model or internal/provider (the model -> tui persist-notice edge makes the reverse a cycle).
Production implementation of tui.ExitController (the production binding deferred to the registry assembly). It lives in internal/bootstrap so FlushOnExit can delegate to sessionfailures.CleanShutdownFlush without the sessionfailures -> tui import cycle.
First-run creation of the ~/.codemeld directory tree.
First-run stdout messages: the created-settings message and the settings-to-review section.
First-run generation and atomic write of ~/.codemeld/global/settings.yaml.
First-run materialization of the built-in VCS templates into ~/.codemeld/global/vcs/.
Headless one-shot run: the `codemeld run` driver that reuses the shared fresh-launch bootstrap core and runs exactly one agentic turn with a fail-closed permission posture.
Package bootstrap assembles codemeld's runtime dependencies.
Production implementation of the /mode + shift+tab mode-switch seam, bound to the run-scoped interaction-mode state and the running app. It lives in internal/bootstrap (not internal/tui) so the durable interaction_mode emit can route an atomic-write failure through sessionfailures without re-introducing the sessionfailures -> tui import cycle, exactly like clearModeState.
Production implementations of tui.ModelCatalog/tui.ModelApplier (the model-only /model path) and the provider-aware tui.ProviderModelCatalog/ tui.ProviderModelApplier (the CTRL-M model picker, which spans the provider×model cross-product and may switch providers). All share the picker-apply transaction with effortdeps.go and live in internal/bootstrap for the same import-direction reason: internal/tui cannot import internal/model or internal/provider.
Launch-time config→model.Context bridge: assembles the provider diagnostics and active model selection for both bootstrap launch paths.
Fresh-launch bootstrap orchestration enforcing the step order (steps 0a-8).
Gated permission-prompt adapter: maps a permissions.MatchRequest plus caller/run-scoped display data to the tui prompt, drives the real prompt UI behind a single-slot gate so only one permission prompt is ever on screen, and maps the user's tui.PromptDecision back to a permissions.PromptOutcome. It lives in internal/bootstrap because it must import both internal/tui (App.PromptUser) and internal/permissions (PromptOutcome) — a binding neither internal/agent nor internal/dispatch can make without an import cycle.
Picker-triggered background refresh of a provider's models.yaml catalog: stale-check, per-provider request coalescing, sanitized discovery, atomic store write, and live-cache rebuild — with secret-safe result delivery and no internal/tui import (the picker owns its wiring and notices).
Background retention-prune wiring for the launch paths: starts the background pruner and appends its session_prune_summary to whichever session is active when the pass completes.
Resume-launch bootstrap orchestration enforcing the resume sub-sequence for `--resume <id>` and the no-id `--resume` picker form.
OlderSchemaForker remains a documented no-op seam (see each type below).
Production step-8 launch: build the runtime command registry over the bootstrap result's session + model/config state, wire the registry-backed submit adapter (the first non-test caller of DispatchSlashInput), and run the tview event loop (bootstrap step 8).
Production tool-call dispatch wiring: the deferred tool-registry factory and the turn.ToolDispatcher binding that routes the model's assembled tool calls to the landed dispatch backbone — bash to DispatchShell, every other structured name to DispatchTool — through the shared authorizer, real runner, and real registry.
Production wiring for the provider turn: the bootstrap-owned controller that builds a turn.Runner per accepted prompt, runs it off the tview event loop, streams its deltas into the transcript, and exposes cancellation to the ESC/CTRL-C path.
Production VCS detection-to-registry wiring for bootstrap steps 4-6: load templates, cross-reference-validate vcs.preferred, and run detection into the *ActiveVCS handoff the tool-registry factory (step 6c) consumes.
Index ¶
- Constants
- Variables
- func EnsureFirstRunDirs(home string) (failedPath string, cat fserrors.Category, err error)
- func FirstRunDirs(home string) []string
- func GeneratedSettingsBytes() []byte
- func MaterializeBuiltinTemplates(home string) (failedPath string, cat fserrors.Category, err error)
- func PrintFirstRunMessage(w io.Writer, settingsPath string)
- func PrintSettingsToReview(w io.Writer)
- func RunEnsureFirstRunDirs(home string, stderr io.Writer) int
- func RunMaterializeBuiltinTemplates(home string, stderr io.Writer) int
- func RunScaffoldGlobalCodemeldignore(home string, stderr io.Writer) int
- func RunWriteSettings(home string, stdout, stderr io.Writer) int
- func ScaffoldProjectCodemeldignore(projectRoot string, stderr io.Writer) error
- func SettingsPath(home string) string
- func StartTUI(ctx context.Context, result *BootstrapResult, stdout io.Writer) (retErr error)
- func VCSTemplateDir(home string) string
- func VCSTemplatePath(home, name string) string
- func WriteFirstRunSettings(home string) (path string, step fsutil.AtomicWriteStep, cat fserrors.Category, err error)
- type ActiveVCS
- type BootstrapResult
- type ConfigComposition
- type DeniedCall
- type FreshSteps
- type HeadlessDriver
- func (d *HeadlessDriver) DeclaredFileScopes() (write, remove []string)
- func (d *HeadlessDriver) DeniedSubjects() []DeniedCall
- func (d *HeadlessDriver) DevDebugRequested() bool
- func (d *HeadlessDriver) EnableDevDebug()
- func (d *HeadlessDriver) EnableExperiment(exp HeadlessExperiment) error
- func (d *HeadlessDriver) EnablePromptForApproval(stdin io.Reader)
- func (d *HeadlessDriver) PromptForApprovalEnabled() bool
- func (d *HeadlessDriver) Run(ctx context.Context, result *BootstrapResult) (retErr error)
- func (d *HeadlessDriver) SessionTitle() string
- func (d *HeadlessDriver) SetDeclaredFileScopes(write, remove []string)
- func (d *HeadlessDriver) SetSessionTitle(title string)
- func (d *HeadlessDriver) SetTimeLimit(deadline time.Time, limit time.Duration)
- func (d *HeadlessDriver) TimeLimit() (deadline time.Time, limit time.Duration)
- type HeadlessExperiment
- type HeadlessExtraTool
- type HomeResolveError
- type PromptDisplay
- type PromptGateBuilder
- type ProviderCatalogRefresher
- type RefreshOutcome
- type RefreshResult
- type ResumeSteps
- type WithheldCategory
- type WithheldInput
Constants ¶
const EnvDevDebug = "CODEMELD_DEV_DEBUG"
EnvDevDebug enables the suggest_followup development trace when set to "1". It is documented in docs/environment-variables.md and the TUI /help panel; the headless `codemeld run` also accepts a --dev-debug flag that ORs with it.
const EnvShellToolHint = "CODEMELD_SHELL_TOOL_HINT"
Variables ¶
var ErrFirstRunFailed = errors.New("bootstrap: first-run generation failed")
ErrFirstRunFailed reports that step 0 first-run generation failed. The failing runner has already written its OP_FAIL line to stderr, so the CLI maps this to a silent exit-1 rather than re-rendering it.
var ErrHeadlessExperiment = errors.New("bootstrap: invalid headless experiment binding")
var ErrModelNotInCatalog = errors.New("bootstrap: --model selection is not in the run's model catalog")
ErrModelNotInCatalog reports that an explicit `--model` selection names a provider/model the run's resolved catalog does not offer (model.Validate failed). It is a usage error: the CLI maps it to exit 2, not a bootstrap/provider failure.
var ErrModelPickerRequired = errors.New("bootstrap: no model determined for a headless run; pass --model")
ErrModelPickerRequired reports that a headless run resolved no active model and no `--model` was given — the path-4 picker-required outcome. The interactive launch opens the model picker here; a headless run cannot, so the CLI maps this to a usage exit 2 telling the user to pass `--model` (Architecture Review).
var ErrResumeListPreflight = errors.New("resume list preflight failed")
ErrResumeListPreflight signals that sessions.RunResumeListPreflight already wrote its exact terminal-failure line (non-tty stdin/stderr) and reported exit status 1. The no-id ListAndSelect step returns it so the CLI maps it to a quiet status-1 exit (mapBootstrapError) instead of printing a second wrapped error line.
var ErrSessionWriteOnExit = errors.New("bootstrap: session write on exit failed")
ErrSessionWriteOnExit reports that a pre-TUI clean-shutdown flush already wrote its OP_FAIL line and should map to a quiet status-1 exit.
Functions ¶
func EnsureFirstRunDirs ¶
EnsureFirstRunDirs creates each FirstRunDirs target in order, stopping at the first failure and returning its path, category, and error. Directories created before a failure are left in place.
func FirstRunDirs ¶
FirstRunDirs returns the three first-run target directories in creation order. Order is load-bearing: each entry is the parent of the next.
func GeneratedSettingsBytes ¶
func GeneratedSettingsBytes() []byte
GeneratedSettingsBytes returns the canonical first-run settings.yaml bytes.
func MaterializeBuiltinTemplates ¶
MaterializeBuiltinTemplates writes each built-in template that is not already present under ~/.codemeld/global/vcs/, at mode 0644. Existing files are preserved so the operation is idempotent and never overwrites a user-edited template; since WriteAtomic overwrites, existence is checked first. On the first failure it returns the target path, category, and error and stops; templates written before the failure are left in place.
func PrintFirstRunMessage ¶
PrintFirstRunMessage emits the created-settings stdout message directing ChatGPT subscribers to `codemeld auth login openai-chatgpt` and Platform users to configure an OpenAI Platform API key (supersedes the single-line "configure a provider and API key" wording). The exact wording is pinned by a snapshot test; do not edit without updating the snapshots.
func PrintSettingsToReview ¶
PrintSettingsToReview emits the "settings to review" section. The wording may evolve; only the set of listed keys is pinned.
func RunEnsureFirstRunDirs ¶
RunEnsureFirstRunDirs creates the first-run directories, mapping any failure to the OP_FAIL stderr line with operation "create-dir" and exit code 1.
func RunMaterializeBuiltinTemplates ¶
RunMaterializeBuiltinTemplates materializes the built-in templates, mapping any failure to the OP_FAIL stderr line with operation "write-vcs-template" and exit code 1.
func RunScaffoldGlobalCodemeldignore ¶
RunScaffoldGlobalCodemeldignore writes the commented ~/.codemeld/global/codemeldignore on first run, alongside the other first-run files. The parent ~/.codemeld/global directory is created by EnsureFirstRunDirs earlier in first-run generation. A failure maps to the OP_FAIL stderr line and exit code 1, mirroring the other first-run write runners.
func RunWriteSettings ¶
RunWriteSettings writes settings.yaml, then on success prints the first-run message and the settings-to-review section. On failure it prints the OP_FAIL stderr line with operation "write-settings" and returns exit code 1.
func ScaffoldProjectCodemeldignore ¶
ScaffoldProjectCodemeldignore ensures <project-root>/.codemeld exists and writes a commented <project-root>/.codemeld/codemeldignore when absent, never overwriting an existing file. It is the project bootstrap step that runs after project-root resolution and before config/VCS/tool setup, on both fresh and cold-start resume launches. It is best-effort: an empty projectRoot is a no-op, and a directory or write failure is reported to stderr and swallowed so an optional template can never block a launch in a read-only project. The returned error is therefore always nil; the type matches the injected bootstrap step contract so the step can be faked in tests.
func SettingsPath ¶
SettingsPath returns the absolute path to the generated global settings file.
func StartTUI ¶
StartTUI is the step-8 launch. It narrows the bootstrap result's active session + composed config + run-scoped model state, assembles the production command registry through the shared tui.BuildRegistry builder (binding the real handlers that make /clear, /status, /effort, /model, /exit, and /resume reachable at runtime), wires the dispatch-backed submit adapter, and runs the event loop. It owns the submit-path wiring for the first five commands and /resume, the adapter and the injection point, not the provider turn loop: a plain prompt is routed through the pre-turn persistence and an as-yet-empty dispatch seam later tasks fill in. stdout carries the clean-exit resume hint.
Missing upstream state degrades rather than panics: the model-determination, config-composition, and AGENTS.md steps are still bootstrap stubs owned by other tasks, so an absent active model yields a "no model selected" state and an absent config yields an empty cache. The wiring is real; the inputs fill in as those steps land.
func VCSTemplateDir ¶
VCSTemplateDir returns ~/.codemeld/global/vcs, the directory built-in VCS templates are materialized into.
func VCSTemplatePath ¶
VCSTemplatePath returns the on-disk path for the built-in template named name (e.g. "git" -> ~/.codemeld/global/vcs/git.yaml).
func WriteFirstRunSettings ¶
func WriteFirstRunSettings(home string) (path string, step fsutil.AtomicWriteStep, cat fserrors.Category, err error)
WriteFirstRunSettings atomically writes settings.yaml at mode 0600 so the plaintext API key is not group/world-readable. The parent directories must already exist. On failure it returns the failing step and error category.
Types ¶
type ActiveVCS ¶
ActiveVCS is the step-6 active-VCS detection result the registry factory consumes to register vcs_<action> tools: the selected template and the bound repo root. Both are required — vcs.RegisterActions resolves each action's cwd against the repo root — so the factory registers VCS tools only when both are present. DetectVCS returns nil when no template matched, which the factory treats as the degraded no-VCS path.
type BootstrapResult ¶
type BootstrapResult struct {
Home string // step 0a
LaunchDir string // launch cwd (item 4 / status overlay)
ProjectRoot string // step 2
ConfigLayerPaths []string // step 2 (ordered settings.yaml sources, global-first/project-last; item 10)
Config map[string]any // step 3 (composed config)
VCSTemplate any // step 6 (active template; nil when none detected)
ToolRegistry any // step 6c
Model any // step 7 (active model selection; *model.ActiveState)
Mode any // step 7b2 (active interaction mode; *mode.ActiveState)
// ModelPickerRequired is the path-4 outcome (step 7): a selectable model
// exists but none was determined, so StartTUI must open the provider-aware model
// picker once the picker deps are installed. It is distinct from Model holding an empty
// active state, which alone only means "no active selection".
ModelPickerRequired bool
Session *sessions.Store // step 7b (active session)
AgentInstructions []agentinstr.LoadEntry // step 7c (in-memory AGENTS.md load record, for /status + /clear replay)
// TrustDecision is the step-2b gate's run-fixed outcome, consumed by the interactive
// project-grant prompt. A headless run retains it from its own non-prompting evaluator.
TrustDecision trust.Decision
// WithheldInputs is the structured record of the project inputs a degraded launch did
// not load, including the reason when the gate could not inspect one.
WithheldInputs []WithheldInput
// SettingsLayers holds each admitted settings layer copied independently of Config, so
// composition's merging and deduplication cannot erase what a layer itself held. A
// configured project path the trust gate refused is carried as an ignored layer.
SettingsLayers []securitystate.LayerSnapshot
// BackgroundPrune marks a launch that must kick off the background
// retention prune in StartTUI once the active session is installed. Only a fresh
// launch sets it: pruning is fresh-launch-only. Every resume
// path — `--resume <id>`, the no-id `--resume` picker, and in-TUI `/resume` —
// leaves it false, so shared TUI assembly never prunes for a resumed run.
BackgroundPrune bool
ResumeLockRelease func()
// ResumeReplay marks a cold-start resume launch (both `--resume <id>` and the no-id
// picker form) so StartTUI re-renders the loaded session's prior conversation into
// the transcript after the launch banner and before the event loop runs. It
// stays false on a fresh launch, whose empty session has no prior conversation to
// replay, so fresh-launch transcript behavior is unchanged.
ResumeReplay bool
}
BootstrapResult carries the state a completed fresh launch produces, in the order fills it. Fields owned by pending leaf tasks (VCS template, tool registry, model selection) are typed as any until their owning task lands a concrete type.
func RunFresh ¶
func RunFresh(ctx context.Context, cwd string, steps FreshSteps) (*BootstrapResult, error)
RunFresh runs the fresh-launch bootstrap, invoking steps in the exact order (0a, 0, 1-8). Each step runs only when every preceding step returned nil. Step 0 short-circuits the whole sequence when first-run generation runs. RunFresh never prints; it returns errors for the CLI layer to render.
On the first-run branch it returns (nil, nil): the launch is complete and the caller exits 0. On any step failure it returns (nil, err). On a full launch it returns the populated result.
RunFresh is the interactive (TUI) launch: it runs the shared bootstrap core (steps 0a–7c) and then step 8, StartTUI. The headless run reuses the same runFreshCore and substitutes its own one-shot driver for StartTUI, so the two launch paths share identical bootstrap state assembly.
func RunResumePicker ¶
func RunResumePicker(ctx context.Context, cwd string, steps ResumeSteps) (*BootstrapResult, error)
RunResumePicker runs the no-id `codemeld --resume` launch. Mirroring RunFresh it resolves home as step 0a (wrapping a failure in HomeResolveError), then runs step 0, step 1, and the listing. When the user picks a session it transitions into the resume sub-sequence; when the user dismisses without picking it returns (nil, nil). No retention prune runs on this path — pruning is fresh-launch-only, so the listing may surface expired sessions that a later fresh launch has not yet pruned. cwd is the launch directory and steps is the injected leaf-operation set. It never prints; the listing's own IO lives in the ListAndSelect step.
func RunResumeWithID ¶
func RunResumeWithID(ctx context.Context, cwd, id string, steps ResumeSteps) (*BootstrapResult, error)
RunResumeWithID runs the cold-start `codemeld --resume <id>` launch. Mirroring RunFresh, it resolves home as step 0a (wrapping a failure in HomeResolveError), then runs step 0 (first-run check) and step 1 (load global settings) before entering the resume sub-sequence with no deferred prune summary. cwd is the launch directory and steps is the injected leaf-operation set (production wires DefaultResumeSteps). It never prints; it returns errors for the CLI layer to render and an exit code to apply.
On the first-run branch it returns (nil, nil): first-run generation ran and the caller exits 0. On any failure it returns (nil, err). On a full launch it returns the populated result.
type ConfigComposition ¶
type ConfigComposition struct {
Config map[string]any
ProjectLayer map[string]any
// ProjectPresent distinguishes an admitted project layer that exists from one whose
// file was absent, which ProjectLayer alone cannot: both leave it nil.
ProjectPresent bool
// LocalPresent distinguishes an admitted local layer that exists from one whose file was
// absent, which LocalLayer alone cannot: both leave it nil.
LocalLayer map[string]any
LocalPresent bool
}
ConfigComposition is the step-3 result. ProjectLayer is the parsed project settings map that actually contributed to Config, retained so vcs.preferred attribution reuses this launch's one verified read instead of reopening the file.
type DeniedCall ¶
DeniedCall is one refusal the run recorded: the subject label the caller sees, the reason the model was given, and the permission outcome source that decided it. Source is what lets the exit summary tell a declared-scope refusal from an ordinary fail-closed one without reading the reason text or checking which flags the run was started with.
func RunHeadless ¶
func RunHeadless(ctx context.Context, cwd string, steps FreshSteps, driver *HeadlessDriver) ([]DeniedCall, error)
func (DeniedCall) DeclaredScope ¶
func (d DeniedCall) DeclaredScope() bool
DeclaredScope reports whether the run's declared file scopes produced this denial — the one class no permission grant and no --prompt-for-approval can widen.
type FreshSteps ¶
type FreshSteps struct {
// ResolveHome resolves the user's home directory (step 0a).
ResolveHome func() (home string, err error)
// RunFirstRun reports ran=true when global settings were absent and first-run
// generation ran (step 0); RunFresh then exits before step 1.
RunFirstRun func(home string) (ran bool, err error)
// LoadGlobalSettings loads ~/.codemeld/global/settings.yaml (step 1).
LoadGlobalSettings func(home string) (global map[string]any, err error)
// ResolveProjectRoot walks for the project root from the launch cwd and returns
// the project-side settings.yaml layer paths discovered there (at most one, per
// config.LocateProjectRoot); RunFresh prepends the global path to build the
// global-first/project-last /status source list (step 2).
ResolveProjectRoot func(cwd string, global map[string]any) (projectRoot string, projectLayers []string, err error)
// GateTrust decides whether the repository at projectRoot may contribute its settings
// layer to this run (step 2b), prompting and recording the answer on an interactive
// launch. It runs before the layer paths are published and before composition, so an
// untrusted repository's settings reach neither.
GateTrust func(home, projectRoot, launchDir string) trust.Decision
// ScaffoldProjectIgnore scaffolds the commented <project-root>/.codemeld/codemeldignore
// template, creating it only when absent. It runs immediately after
// project-root resolution and before config/VCS/tool setup (step 2.5) so the project
// .codemeld directory and starter file exist before any later step reads the project
// tree. The production step is best-effort (it never aborts the launch).
ScaffoldProjectIgnore func(projectRoot string) error
// RecoverJournals puts back the writes of a child agent whose codemeld process was killed
// before it could unwind them, for the project folder being opened (step 2.6). It returns
// nothing because recovery must never block a launch: what it could not do is reported and the
// launch continues.
RecoverJournals func(home, projectRoot string)
// ComposeConfig composes the config layers (step 3).
ComposeConfig func(global map[string]any, projectRoot string) (composition ConfigComposition, err error)
// LoadVCSTemplates loads built-in and project VCS templates (step 4). projectLayer is
// step 3's verified project settings map (nil when none was composed), carried here so
// vcs.preferred source attribution reuses it rather than reading the file again.
// approved is the launch's trust outcome; the step derives no trust of its own.
LoadVCSTemplates func(home, projectRoot string, projectLayer map[string]any, approved bool) (templates any, err error)
// ValidatePreferredVCS cross-reference-validates vcs.preferred (step 5).
ValidatePreferredVCS func(composed map[string]any, templates any) error
// DetectVCS runs auto-detection, returning the active template or nil (step 6).
DetectVCS func(cwd string, composed map[string]any, templates any) (active any, err error)
// BuildToolRegistry builds the tool registry (step 6c).
BuildToolRegistry func(active any) (registry any, err error)
// DetermineModel determines the active model (steps 7/7a) through the config→
// model bridge: it builds a config.Cache from the composed config, the project
// root, and the global-first/project-last layer paths (using global to attribute
// each path-4 provider diagnostic to its source settings file), calls
// model.DetermineSelection, and returns the run-scoped *model.ActiveState. It also
// reports pickerRequired=true for the path-4 selectable-model outcome (a
// model picker must open) and returns the path-4 *NoSelectableModelError
// when no model is installed.
DetermineModel func(composed, global map[string]any, projectRoot string, layerPaths []string) (selection any, pickerRequired bool, err error)
// EnsureFreshSession ensures the sessions dir, mints the id, and writes the
// folder file (step 7b).
EnsureFreshSession func(home, projectRoot string) (session *sessions.Store, err error)
// FlushSessionTitle persists a caller-supplied session name (codemeld run --title)
// as soon as the session exists and before any launch record is appended, so an
// interrupt anywhere in the rest of the launch still leaves the session named on
// disk. It returns nothing because losing the name must not kill the run: the
// headless adapter routes a write failure through the metadata-notice path and
// discards it. nil for launches that carry no title, which is every interactive one.
FlushSessionTitle func(ctx context.Context, session *sessions.Store)
AcquireLock func(sessionPath, id string) (release func(), err error)
// AppendLaunchBegan appends exactly one launch_began event, source: fresh
// (step 7b1) — after session creation and before AGENTS.md load.
AppendLaunchBegan func(ctx context.Context, session *sessions.Store) error
// InitMode resolves mode.default from the composed config, appends the
// session-start interaction_mode{trigger:"launch"} durably (same write-failure
// policy as launch_began), and returns the run-scoped *mode.ActiveState (step
// 7b2) — after launch_began and before AGENTS.md load. The active mode is never
// inherited from a prior session: launch always starts from mode.default.
// projectRoot/layerPaths feed the config.Cache mode.default is read
// from, the same source the model and AGENTS.md steps use.
InitMode func(ctx context.Context, session *sessions.Store, composed map[string]any, projectRoot string, layerPaths []string) (modeState any, err error)
// LoadAgentInstructions discovers AGENTS.md files, replays one
// agent_instructions_loaded event per file into the session stream, flushes so
// the records are durable, and returns the in-memory load record (step 7c). The
// walk anchor is launchDir (the launch CWD), not projectRoot: the AGENTS.md loader
// always walks from the launch directory to the filesystem root, independent of
// discovery.boundary, so the resolved project root must not be substituted here.
// composed/projectRoot/layerPaths feed the config.Cache the per-file size cap is
// read from. The returned record is surfaced on BootstrapResult so the /status
// overlay and /clear replay reuse it without re-walking the disk.
LoadAgentInstructions func(ctx context.Context, session *sessions.Store, home, launchDir string, composed map[string]any, projectRoot string, layerPaths []string) ([]agentinstr.LoadEntry, error)
// StartTUI starts the TUI (step 8).
StartTUI func(ctx context.Context, result *BootstrapResult) error
}
FreshSteps is the injected leaf-operation set for the fresh-launch path. Each field maps to one step (named in its comment). RunFresh owns the ordering and short-circuiting; the steps own the work. Production wires DefaultFreshSteps; tests inject fakes that record invocation order and return controlled errors so ordering can be asserted without real leaf packages.
func DefaultFreshSteps ¶
func DefaultFreshSteps(stdout, stderr io.Writer) FreshSteps
DefaultFreshSteps returns the production step set. The steps owned by landed tasks are wired: ResolveHome, step-0 first-run, global-settings load, project-root resolution, config composition, the step-4 through step-6 VCS detection chain (LoadVCSTemplates, ValidatePreferredVCS, DetectVCS), the step-6c registry factory, model determination, fresh-session creation, the step-7b1 launch_began event, the step-7c AGENTS.md load, and the step-8 production launch. stdout/stderr are threaded into the first-run runner (which prints its own first-run message and OP_FAIL lines) and into the VCS detection step (which prints skipped-directory and ambiguity warnings to stderr before the TUI starts), plus launch_began write-failure notices before the TUI exists.
func HeadlessFreshSteps ¶
func HeadlessFreshSteps(stderr io.Writer, modelOverride *model.Selection, modeKey string) FreshSteps
HeadlessFreshSteps builds the fresh-launch step set for a headless run. It starts from the production DefaultFreshSteps, always substitutes a non-prompting trust gate that can honor a record already made for the project root and a non-prompting journal recovery step (a headless run has no one to answer, so a path changed since the crash is reported and deferred rather than waited on from stdin) and, when given, substitutes a `--model` override (a DetermineModel step that builds and catalog-validates the explicit selection) and a `--mode` override (an InitMode step pinning the run's interaction mode). Every bootstrap-phase message — first-run notices, VCS warnings, and the path-4 model diagnostics — is routed to stderr so the run's stdout carries only the assistant reply (Done-when 2). StartTUI is never invoked on this path (RunHeadless runs the one-shot driver in place of step 8), so its bound writer is unused.
type HeadlessDriver ¶
type HeadlessDriver struct {
// contains filtered or unexported fields
}
func NewHeadlessDriver ¶
func NewHeadlessDriver(prompt string, stdout, stderr io.Writer) *HeadlessDriver
func (*HeadlessDriver) DeclaredFileScopes ¶
func (d *HeadlessDriver) DeclaredFileScopes() (write, remove []string)
DeclaredFileScopes returns the raw declarations bound onto this driver, in the order the flags supplied them. Run reads them through it, and the CLI's run test uses the same accessor to confirm each repeated flag value reached the real driver unsplit.
func (*HeadlessDriver) DeniedSubjects ¶
func (d *HeadlessDriver) DeniedSubjects() []DeniedCall
DeniedSubjects returns the distinct denials the run's turn recorded, in first-seen order, with the subject label, reason, and classification the CLI's denial summary needs. It is empty before Run executes or when nothing was denied.
func (*HeadlessDriver) DevDebugRequested ¶
func (d *HeadlessDriver) DevDebugRequested() bool
DevDebugRequested reports whether --dev-debug was bound onto this driver (EnableDevDebug). It is the observable form of that wiring for the CLI's run test, which confirms the flag reached the real driver. intentional: test-only seam (no production caller by design) — production reads d.devDebug directly in Run.
func (*HeadlessDriver) EnableDevDebug ¶
func (d *HeadlessDriver) EnableDevDebug()
EnableDevDebug turns on the suggest_followup development trace for this run (the `codemeld run --dev-debug` opt-in). Run ORs it with CODEMELD_DEV_DEBUG, so either source enables the trace; without it the run stays byte-free of suggest_followup_debug events.
func (*HeadlessDriver) EnableExperiment ¶
func (d *HeadlessDriver) EnableExperiment(exp HeadlessExperiment) error
A shipped-surface name collision is only visible once the registry is realized, so Run checks for one and fails there rather than here. intentional: no production caller by design — the only caller is the local E2 harness, and `codemeld run` keeps the shipped advertised set.
func (*HeadlessDriver) EnablePromptForApproval ¶
func (d *HeadlessDriver) EnablePromptForApproval(stdin io.Reader)
EnablePromptForApproval switches the run from fail-closed default-deny to interactive terminal escalation: a tool call the active mode does not auto-allow and no grant authorizes pauses and asks on the terminal — the request renders to stderr, one choice is read from stdin — instead of being denied in-band. The caller (internal/cli/run.go) must gate this on stdin being a real terminal before enabling it.
func (*HeadlessDriver) PromptForApprovalEnabled ¶
func (d *HeadlessDriver) PromptForApprovalEnabled() bool
PromptForApprovalEnabled reports whether interactive terminal escalation was enabled on this driver (EnablePromptForApproval). It is the observable form of that wiring, so the CLI's run test can confirm the --prompt-for-approval flag bound the terminal prompt onto the real driver (the production wiring this task owns). intentional: test-only seam (no production caller by design) — production reads d.promptForApproval directly in Run.
func (*HeadlessDriver) Run ¶
func (d *HeadlessDriver) Run(ctx context.Context, result *BootstrapResult) (retErr error)
Run assembles the production turn collaborators over the bootstrap result — reusing StartTUI's assembly patterns (config cache, realized tool registry, system- prompt and advertised-tool assemblers, production tool dispatcher) — but binds the fail-closed headless authorizer instead of the interactive prompt gate, persists the prompt through the pre-turn durability boundary, and runs exactly one turn.NewToolLoop.
A user interrupt (Ctrl-C, surfaced as context cancellation) or the turn deadline is not a failure *provided* the final WithoutCancel flush durably persists the partial work: only then does Run return nil. If that final flush fails, the run is not durably resumable, so the failure is surfaced (routed through the notice path for a real write reason) rather than masked as a clean interrupt. Any other turn error is returned for the CLI to map to a non-zero exit.
func (*HeadlessDriver) SessionTitle ¶
func (d *HeadlessDriver) SessionTitle() string
func (*HeadlessDriver) SetDeclaredFileScopes ¶
func (d *HeadlessDriver) SetDeclaredFileScopes(write, remove []string)
SetDeclaredFileScopes binds the run's declared write and delete path lists, the ceiling that becomes the sole authorization for every write tool in the run. Run canonicalizes them once the bootstrap has produced the home and launch directory they resolve against, and before the first turn. It follows EnablePromptForApproval's shape so NewHeadlessDriver keeps its signature.
func (*HeadlessDriver) SetSessionTitle ¶
func (d *HeadlessDriver) SetSessionTitle(title string)
SetSessionTitle binds the name `codemeld run --title` gives this run's session, or "" to leave it unnamed. It follows EnablePromptForApproval's shape so NewHeadlessDriver keeps its signature.
func (*HeadlessDriver) SetTimeLimit ¶
func (d *HeadlessDriver) SetTimeLimit(deadline time.Time, limit time.Duration)
type HeadlessExperiment ¶
type HeadlessExperiment struct {
ExtraTools []HeadlessExtraTool
DenyCall func(call turn.AssembledToolCall) (reason string, deny bool)
}
type HeadlessExtraTool ¶
type HeadlessExtraTool struct {
Definition provider.ToolDefinition
Handle func(ctx context.Context, arguments string) (turn.ToolResult, error)
}
type HomeResolveError ¶
type HomeResolveError struct{ Err error }
HomeResolveError wraps a step-0a home-resolution failure so the CLI can render the stderr line (`codemeld: cannot resolve home directory: <reason>`) without inspecting which step failed.
func (*HomeResolveError) Error ¶
func (e *HomeResolveError) Error() string
func (*HomeResolveError) Unwrap ¶
func (e *HomeResolveError) Unwrap() error
type PromptDisplay ¶
type PromptDisplay struct {
// Action is the prompt's action header ("Create file" / "Edit file" /
// "Run command" / "Run tool"), produced by dispatch from the subject kind and tool.
Action string
// For shell subjects, Subject is effective source text, not MatchRequest.Subject.
Subject string
// Body is the payload shown verbatim with no truncation and nothing added: the file
// content for a create, an old→new snippet for an edit, the full structured-tool
// call for any other tool. It is empty for a shell subject (the whole command is the
// Subject).
Body string
// OutOfRootFileWrite marks a structured edit/create prompt whose resolved target lies
// outside the project root. It is copied verbatim from
// dispatch.PromptDisplay and mapped onto tui.PromptRequest so the prompt offers the
// folder option for that out-of-root write only; false for every other prompt.
OutOfRootFileWrite bool
// OutOfRootReadScope marks a read-only navigation tool prompt whose resolved scope lies
// outside the project root. It is copied verbatim from dispatch.PromptDisplay and
// mapped onto tui.PromptRequest so the prompt offers the folder option for that out-of-root
// read-only scope too; false for every other prompt.
OutOfRootReadScope bool
// GrantStoredSubject is the capability subject (write/read*) a grant should store when this
// structured-tool prompt is approved with a grant-creating option. It is copied verbatim
// from dispatch.PromptDisplay and mapped onto tui.PromptRequest, where the grant-creating choice
// returns it as the stored subject so the grant folds the sibling member tools. Empty for every
// prompt whose grant should store the concrete request subject.
GrantStoredSubject string
// Pipeline mirrors dispatch.PromptDisplay.Pipeline: the full pipeline source text carried through
// for a direct pipeline-stage prompt so the prompt can show the approved stage is one stage of a
// larger pipeline. Empty for a single direct command, a literal route, and every structured tool. It
// is display-only, never consulted for matching, and mapped straight onto tui.PromptRequest.Pipeline
// by buildPromptRequest.
Pipeline string
// WholeCommand mirrors dispatch.PromptDisplay.WholeCommand: true on a literal-route prompt to mark a
// whole-command approval (the Subject is the entire command, not one stage of a direct pipeline).
// Display-only and mapped straight onto tui.PromptRequest.WholeCommand by buildPromptRequest.
WholeCommand bool
// RequestedTarget mirrors dispatch.PromptDisplay.RequestedTarget and feeds only the prompt
// summary; it is never a matching or grant input.
RequestedTarget string
// ProjectRoot is the resolved project root shown alongside the run folder.
ProjectRoot string
// LaunchDir is the resolved directory codemeld was launched in; with Boundary
// and WouldCreateSettingsFile it gates the launch-dir-only cross-mode notice.
LaunchDir string
// Boundary is the resolved discovery boundary mode ("launch-dir-only" or
// "project-root").
Boundary string
// FolderSettingsPath is the absolute path a folder grant would be written to,
// shown for the folder option.
FolderSettingsPath string
// FolderCoverage is the one-line statement of what the folder grant covers.
FolderCoverage string
// WouldCreateSettingsFile reports whether persisting a folder grant would newly
// create the project settings file.
WouldCreateSettingsFile bool
// ProjectUntrusted is !BootstrapResult.TrustDecision.Trusted, fixed for the run. It must
// come from that decision and never be inferred from the config layers: a project with no
// settings file has the same layer shape as an untrusted one and is trusted.
ProjectUntrusted bool
HostRequest string
DirectHTTPFallback bool
ExceptionalAuthority string
}
PromptDisplay carries the caller/run-scoped display data a permission prompt shows that permissions.MatchRequest deliberately does not hold. Matching keys on MatchRequest.Subject (the registered tool name for a structured tool, the canonical command otherwise); Action/Subject/Body are the human-readable prompt payload supplied per call by the dispatch producer (dispatch.PromptDisplay), not the bare matching subject. The remaining fields are resolved once per run from bootstrap/config state. Keeping them out of internal/permissions preserves the split between matching data and prompt display.
type PromptGateBuilder ¶
type PromptGateBuilder struct {
// contains filtered or unexported fields
}
PromptGateBuilder produces per-request permissions.AuthorizeDeps.Prompt closures that all serialize through one shared single-slot gate, so the non-overlap guarantee is app-wide and not per-caller. The production authorizer builds one per run and calls Build for each authorization.
func NewPromptGateBuilder ¶
func NewPromptGateBuilder(app *tui.App) *PromptGateBuilder
NewPromptGateBuilder returns a builder whose closures drive the real prompt UI (app.PromptUser) behind a fresh shared gate. Exactly one builder — one gate — is created per run and shared across every prompt source so only one permission prompt is ever on screen.
func (*PromptGateBuilder) Build ¶
func (b *PromptGateBuilder) Build(req permissions.MatchRequest, display PromptDisplay) func(context.Context, permissions.ScopeEscalation) (permissions.PromptOutcome, error)
Build returns the AuthorizeDeps.Prompt closure for one authorization. The closure maps req + display + the orchestrator's display-only ScopeEscalation to a tui.PromptRequest, acquires the shared gate (context-aware), shows the prompt, releases the gate, and maps the returned tui.PromptDecision to a permissions.PromptOutcome. The request is built before the gate is acquired so a malformed request fails without occupying the single prompt slot, and the gate is released with defer so a prompt error never strands it. ctx gates only the wait for the slot; once the prompt is on screen (*tui.App).PromptUser blocks until the user decides (it takes no ctx), matching the permissions.Authorize contract that the permission prompt resolves regardless of later cancellation.
type ProviderCatalogRefresher ¶
type ProviderCatalogRefresher struct {
// contains filtered or unexported fields
}
ProviderCatalogRefresher runs picker-triggered background refreshes of the shared models.yaml catalog for configured API-key providers and, when forced, for openai-chatgpt. It is bootstrap- only: the picker wiring installs its Refresh method as the picker's refresh callback and marshals the result into the event loop. One refresh per provider runs at a time; concurrent requests for the same provider share it.
func NewProviderCatalogRefresher ¶
func NewProviderCatalogRefresher(cache *config.Cache) *ProviderCatalogRefresher
NewProviderCatalogRefresher binds the refresher to the run's live config cache and derives the shared models.yaml store path from the cache's global settings layer. It constructs no TUI dependency. When no store path can be derived every Refresh returns RefreshRefused before any network work.
func (*ProviderCatalogRefresher) Refresh ¶
func (r *ProviderCatalogRefresher) Refresh(providerID string, force bool, onComplete func(RefreshResult))
Refresh schedules a background catalog refresh for providerID and never blocks the caller. force bypasses the freshness window but not eligibility. onComplete receives one secret-safe result. Concurrent requests for the same provider share a single discovery attempt and each receives the shared result; different providers proceed independently.
type RefreshOutcome ¶
type RefreshOutcome int
RefreshOutcome is the static, secret-free classification of one refresh request. It carries no endpoint, key, body, or raw upstream error — the picker maps it to its own user-facing notice text.
const ( // RefreshRefused means no discovery and no write happened: the id is not a // configured API-key provider, is an unforced or unbound openai-chatgpt request, // or no models.yaml path could be derived. Nothing changed. RefreshRefused RefreshOutcome = iota // RefreshSkippedFresh means the cache was within the freshness window and the // request was not forced, so no discovery ran. Nothing changed. RefreshSkippedFresh // RefreshUpdated means discovery, the atomic store write, and the live-catalog // rebuild all succeeded; the picker's live rows now reflect the new catalog. RefreshUpdated // RefreshFailed means a discovery, platform-filter, persistence, or rebuild // step failed; the prior on-disk and live catalog are retained unchanged. RefreshFailed // so no discovery ran. Nothing changed. RefreshCredentialUnavailable )
func (RefreshOutcome) String ¶
func (o RefreshOutcome) String() string
type RefreshResult ¶
type RefreshResult struct {
ProviderID string
Outcome RefreshOutcome
}
RefreshResult is the secret-safe value delivered to every completion callback: the provider it concerns and the static outcome. It never carries credentials or raw provider content.
type ResumeSteps ¶
type ResumeSteps struct {
// ResolveHome resolves the user's home directory (step 0a), mirroring the fresh
// path's first step. RunResumeWithID / RunResumePicker wrap a failure here in a
// HomeResolveError so the CLI renders the step-0a stderr line.
ResolveHome func() (home string, err error)
// RunFirstRun reports ran=true when global settings were absent and first-run
// generation ran (step 0); the resume entry points then exit before listing or
// resolving, exactly as RunFresh exits before step 1.
RunFirstRun func(home string) (ran bool, err error)
// LoadGlobalSettings loads ~/.codemeld/global/settings.yaml and the keys the
// resume paths need (discovery.boundary, sessions.retention_days) (step 1).
LoadGlobalSettings func(home string) (global map[string]any, err error)
// ListAndSelect renders the listing (after the tty/skipped-id
// preflight) and reports the chosen session id. picked is false when the user
// dismisses without selecting, in which case the caller exits normally without
// entering the resume sub-sequence. No retention prune runs on this path: pruning
// is fresh-launch-only.
ListAndSelect func(home, cwd string, global map[string]any) (id string, picked bool, err error)
// ResolveResume resolves <id> to its session file and runs the
// folder-file check and the CWD-match check. A failure
// here fires before the record stream is available, so it is stderr-only and
// emits no event (the returned error's text is the exact stderr line).
ResolveResume func(id, cwd, home string) (sessionPath string, sess *sessions.Session, err error)
// AcquireLock takes the per-session advisory lock on the session file's sidecar
// (sub-step 1) and returns the release held for the lifetime of the
// run. A failure here is also pre-stream and stderr-only.
AcquireLock func(sessionPath, id string) (release func(), err error)
// AppendLaunchBegan appends the launch_began (source: resume) event as the first
// event of this launch (sub-step 2) and flushes. The record
// stream is available at this point because resolve and lock have completed.
AppendLaunchBegan func(ctx context.Context, store *sessions.Store) error
// RefreshUpdatedAt refreshes the loaded session's updated_at and flushes
// (sub-step 3). A write failure here fires after the record stream is
// available, so the step routes it through the per-turn write-failure protocol
// and the run continues; it returns a non-nil error only for a fatal
// condition (e.g. context cancellation), which aborts the launch.
RefreshUpdatedAt func(ctx context.Context, store *sessions.Store) error
// ResolveProjectRoot walks for the project root from the launch cwd and returns
// the project-side settings.yaml layer paths discovered there (step 2), mirroring
// the fresh path's contract so a resumed launch shows the same global-first/
// project-last /status config sources (item 10).
ResolveProjectRoot func(cwd string, global map[string]any) (projectRoot string, projectLayers []string, err error)
// GateTrust decides whether the repository at projectRoot may contribute its settings
// layer (step 2b), mirroring the fresh path: it runs before the layer paths are
// published and before composition.
GateTrust func(home, projectRoot, launchDir string) trust.Decision
// ScaffoldProjectIgnore scaffolds the commented <project-root>/.codemeld/codemeldignore
// template, creating it only when absent. It runs immediately after project-root
// resolution and before config/VCS/tool setup (step 2.5), mirroring the fresh path so a
// cold-start resume scaffolds the project starter file too. The production step is
// best-effort (it never aborts the launch).
ScaffoldProjectIgnore func(projectRoot string) error
// RecoverJournals puts back the writes of a child agent whose codemeld process was killed
// before it could unwind them, for the project folder being opened (step 2.6), mirroring the
// fresh path: a resumed launch is a launch for that folder too. It returns nothing because
// recovery must never block a launch.
RecoverJournals func(home, projectRoot string)
// ComposeConfig composes the config layers (step 3), mirroring the fresh path.
ComposeConfig func(global map[string]any, projectRoot string) (composition ConfigComposition, err error)
// LoadVCSTemplates loads built-in and project VCS templates (step 4), mirroring the fresh
// path: projectLayer is step 3's verified project settings map (nil when none was
// composed) and approved is the launch's trust outcome.
LoadVCSTemplates func(home, projectRoot string, projectLayer map[string]any, approved bool) (templates any, err error)
// ValidatePreferredVCS cross-reference-validates vcs.preferred (step 5).
ValidatePreferredVCS func(composed map[string]any, templates any) error
// DetectVCS runs auto-detection, returning the active template or nil (step 6).
DetectVCS func(cwd string, composed map[string]any, templates any) (active any, err error)
// BuildToolRegistry builds the tool registry (step 6c).
BuildToolRegistry func(active any) (registry any, err error)
// DetermineModel determines the active model (steps 7/7a) through the same config→
// model bridge as the fresh path, taking the composed config, the global layer
// (to attribute path-4 provider diagnostics to their source settings file), the
// project root, and the global-first/project-last layer paths. On a resumed run it
// follows step 1 (recover from the loaded record stream) before the fresh
// paths 2–4, so it also takes the loaded store. It returns the run-scoped
// *model.ActiveState, reports pickerRequired=true for the path-4
// selectable-model outcome, and returns the path-4 *NoSelectableModelError when no
// model is installed.
DetermineModel func(composed, global map[string]any, projectRoot string, layerPaths []string, store *sessions.Store) (selection any, pickerRequired bool, err error)
// InitMode resolves mode.default from the composed config, durably appends the
// session-start interaction_mode{trigger:"resume"}, and returns the run-scoped
// *mode.ActiveState (step 7b2). A resumed session starts from mode.default, never
// from the mode active when the prior session ended, so this mirrors
// the fresh path's InitMode with a "resume" trigger. It runs after step 7's model
// determination — so a path-4 no-selectable-model abort suppresses it —
// and before AGENTS.md load, since the composed config (step 3) it reads is not
// available until after the resume sub-sequence's launch_began.
InitMode func(ctx context.Context, store *sessions.Store, composed map[string]any, projectRoot string, layerPaths []string) (modeState any, err error)
// LoadAgentInstructions discovers AGENTS.md files, replays one
// agent_instructions_loaded event per file into the resumed store, flushes so
// the records are durable, and returns the in-memory load record for the live
// system prompt, /status, and /clear replay (step 7c). The walk anchor is the launch CWD on a
// resumed run, which the CWD-match check has already proven equal to
// metadata.folder. composed/projectRoot/layerPaths feed the config.Cache the
// per-file size cap is read from.
LoadAgentInstructions func(ctx context.Context, store *sessions.Store, home, launchDir string, composed map[string]any, projectRoot string, layerPaths []string) ([]agentinstr.LoadEntry, error)
// StartTUI starts the TUI (step 8). It blocks for the lifetime of the run, so
// the resume lock acquired above stays held until it returns.
StartTUI func(ctx context.Context, result *BootstrapResult) error
}
ResumeSteps is the injected leaf-operation set for the resume-launch paths, the resume analogue of FreshSteps. RunResumeWithID / RunResumePicker own the ordering and short-circuiting; the steps own the work. Production wires DefaultResumeSteps; tests inject fakes that record invocation order and return controlled errors so the resume sub-sequence ordering can be asserted exactly the way orchestrate_test.go asserts the fresh path.
The fields are grouped by the bootstrap phase they serve: the shared preamble (steps 0 and 1), the no-id listing phase, the resume sub-sequence (the load/lock/launch_began/refresh block placed between step 1 and step 2 on a resumed run), and the standard steps 2–8 that both launch paths share with the fresh path.
func DefaultResumeSteps ¶
func DefaultResumeSteps(stdin io.Reader, stdout, stderr io.Writer) ResumeSteps
DefaultResumeSteps returns the production step set for the resume paths. As with DefaultFreshSteps, the steps owned by landed tasks are wired here: step 0a home resolution (paths.ResolveHome), step 0 first-run (defaultRunFirstRun), global-settings load, the id resolver, the per-session lock, project-root resolution, config composition, the step-4 through step-6 VCS detection chain (LoadVCSTemplates, ValidatePreferredVCS, DetectVCS) — wired to the same production functions the fresh path uses so a resumed run runs the same real steps 4-6 — the step-6c registry factory and step-7/7a model bridge, the step-7c AGENTS.md replay (wired to the same loadAgentInstructions adapter the fresh path uses), and the step-8 production launch, wired to the same StartTUI wrapper the fresh path uses so a resumed run follows the same registry/dispatcher path, and the session-stream append/refresh sub-steps with write-failure routing, and the no-id listing/selection step wired through resumeListAndSelect. No resume path prunes, so no prune step is wired here. stdout/stderr feed the first-run runner, resume write-failure notices, and the VCS detection step's stderr warnings; stdin drives the no-id listing's tty/keypress preflight and the cold-start selector.
type WithheldCategory ¶
type WithheldCategory string
const ( WithheldSettings WithheldCategory = "settings" WithheldVCSTemplates WithheldCategory = "vcs_templates" )
type WithheldInput ¶
type WithheldInput struct {
Category WithheldCategory
Path string
}
Source Files
¶
- authdeps.go
- blockeddefaults.go
- blockeddeps.go
- blockedpaths.go
- childdeps.go
- cleardeps.go
- codemeldignore_scaffold.go
- confinedrunner.go
- confinetmp.go
- connectdeps.go
- devdebug.go
- effortdeps.go
- exitdeps.go
- firstrun_dirs.go
- firstrun_message.go
- firstrun_settings.go
- firstrun_vcs.go
- headless.go
- headlessprompt.go
- modedeps.go
- modeldeps.go
- modeldetermine.go
- orchestrate.go
- promptgate.go
- provider_refresh.go
- prunedeps.go
- resume.go
- resumedeps.go
- starttui.go
- tooldispatch.go
- tooldispatch_askuser.go
- tooldispatch_shell.go
- tooldispatch_web.go
- trust.go
- turndeps.go
- vcs_bootstrap.go