dagql outer shell#416
Open
vito wants to merge 221 commits into
Open
Conversation
…ger#11949) * fixes needed for running integration tests with a generated client Signed-off-by: kpenfound <kyle@dagger.io> * fix go:lint Signed-off-by: kpenfound <kyle@dagger.io> * cleanup unneeded changes, thanks Erik Signed-off-by: kpenfound <kyle@dagger.io> * cleanup unneeded changes Signed-off-by: kpenfound <kyle@dagger.io> * fix for nested exec errors Signed-off-by: kpenfound <kyle@dagger.io> --------- Signed-off-by: kpenfound <kyle@dagger.io>
Signed-off-by: kpenfound <kyle@dagger.io>
…ees (dagger#11990) Running `git config -l -z` from a directory with a broken .git pointer (e.g. a git worktree mounted into a container) causes a fatal exit 128. Fix by running from a temp directory so only system/global config is read, and treat CONFIG_RETRIEVAL_FAILED as non-fatal since git config forwarding is best-effort (only used for url.*.insteadOf mappings). Signed-off-by: Yves Brissaud <yves@dagger.io>
* Fix CLI exiting 0 even when a failure occurred In some error paths, the CLI can already have a concrete error while the resolved exit code is still the default zero value. When that happens, exiting 0 is misleading and can cause CI to treat a failed call or run as successful. Harden the CLI exit handling so that if an error is present, an exit code of 0 is normalized to 1 instead of being treated as success. This keeps the current behavior for real nonzero exits while avoiding false-success outcomes when the exit code payload is missing or left at its zero value. Signed-off-by: Erik Sipsma <erik@sipsma.dev> * Avoid exiting 0 when the primary span failed Add another hardening layer so the CLI does not report success when the primary command span itself ended in a failed state. If the frontend is otherwise about to return nil, but the primary span is marked failed, we now convert that into a nonzero exit. This covers cases where the failure is clearly reflected in top-level span output, but the explicit error signal has been lost somewhere along the way. The intent is straightforward: there should not be a situation where the primary span is failed while the CLI still exits 0, because that can make CI treat a failed call or run as successful. Signed-off-by: Erik Sipsma <erik@sipsma.dev> * Move exit code normalization onto ExitError Follow up on review feedback by moving the zero-code hardening onto idtui.ExitError itself. ExitError already carries both the raw exit code and the originating error, so this keeps the normalization logic with the type instead of spreading it across CLI call sites. That keeps the behavior the same while making the callers simpler and less error-prone. Signed-off-by: Erik Sipsma <erik@sipsma.dev> --------- Signed-off-by: Erik Sipsma <erik@sipsma.dev>
Signed-off-by: Tibor Vass <teabee89@gmail.com>
…ger#12004) Bumps the sdk-java group with 4 updates in the /sdk/java directory: [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom), [com.palantir.javapoet:javapoet](https://github.com/palantir/javapoet), [org.mockito:mockito-core](https://github.com/mockito/mockito) and [io.opentelemetry:opentelemetry-bom](https://github.com/open-telemetry/opentelemetry-java). Updates `com.fasterxml.jackson:jackson-bom` from 2.18.6 to 2.21.1 - [Commits](FasterXML/jackson-bom@jackson-bom-2.18.6...jackson-bom-2.21.1) Updates `com.palantir.javapoet:javapoet` from 0.11.0 to 0.12.0 - [Release notes](https://github.com/palantir/javapoet/releases) - [Commits](palantir/javapoet@0.11.0...0.12.0) Updates `org.mockito:mockito-core` from 5.22.0 to 5.23.0 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](mockito/mockito@v5.22.0...v5.23.0) Updates `io.opentelemetry:opentelemetry-bom` from 1.59.0 to 1.60.1 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](open-telemetry/opentelemetry-java@v1.59.0...v1.60.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-version: 2.21.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: sdk-java - dependency-name: com.palantir.javapoet:javapoet dependency-version: 0.12.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: sdk-java - dependency-name: org.mockito:mockito-core dependency-version: 5.23.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: sdk-java - dependency-name: io.opentelemetry:opentelemetry-bom dependency-version: 1.60.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: sdk-java ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the docs group in /docs with 3 updates: [posthog-js](https://github.com/PostHog/posthog-js), [sass](https://github.com/sass/dart-sass) and [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node). Updates `posthog-js` from 1.359.1 to 1.360.2 - [Release notes](https://github.com/PostHog/posthog-js/releases) - [Changelog](https://github.com/PostHog/posthog-js/blob/main/CHANGELOG.md) - [Commits](https://github.com/PostHog/posthog-js/compare/posthog-js@1.359.1...posthog-js@1.360.2) Updates `sass` from 1.97.3 to 1.98.0 - [Release notes](https://github.com/sass/dart-sass/releases) - [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md) - [Commits](sass/dart-sass@1.97.3...1.98.0) Updates `@types/node` from 25.3.5 to 25.5.0 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: posthog-js dependency-version: 1.360.2 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: docs - dependency-name: sass dependency-version: 1.98.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: docs - dependency-name: "@types/node" dependency-version: 25.5.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: docs ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* refactor(core): introduce ModuleRuntime interface Abstract module execution behind a ModuleRuntime interface so that runtimes aren't required to use a Container. ContainerRuntime wraps the existing container-based execution path. The Runtime interface now returns ModuleRuntime instead of a container directly, and ModuleFunction.Call delegates to the runtime's Call method. * feat(sdk): add native Dang runtime Add the Dang SDK as a builtin SDK with a native runtime that executes directly in the engine process instead of in a container. The DangRuntime implements ModuleRuntime, sets up an HTTP listener for nested GraphQL clients, loads .dang files via dang.RunDir, and handles module init, constructor calls, and function dispatch natively. Includes: dang_sdk.go, SDK loader/consts registration, engine build integration, stub entrypoint binary, and a telemetry fix to prevent log pollution from native runtimes. * feat(sdk): add persistent caching for native Dang runtime The Dang runtime evaluates module functions in-process without containers, bypassing buildkit's LLB cache that container-based runtimes get for free via withExec. This meant every session re-evaluated Dang functions even when inputs hadn't changed. Introduce DangEvalOp, a Dang-specific buildkit custom op whose Exec method reconstructs the module infrastructure from the dagql server and runs the Dang interpreter. The op is fully JSON- serializable: it stores the module source ID, schema file ID, execution metadata, and function call data. On cache hit, buildkit returns the cached snapshot directly without calling Exec. * refactor(sdk): unify all Dang eval through DangEvalOp Move module initialization through the same DangEvalOp path as regular function calls, eliminating the special-case evalInit method. Move initModule and all typedef helpers (createFunction, createObjectTypeDef, dangTypeToTypeDef, etc.) from dang_sdk.go into dang_op.go. Now dang_sdk.go is pure SDK interface glue and dang_op.go contains all Dang evaluation logic. Signed-off-by: Alex Suraci <alex@dagger.io>
* fix: Handle non-SHA referenced module dependencies Fixes: dagger#11996 Signed-off-by: Mike Glazer <mike.glazer@gmail.com> * test: replace the synthetic named-pin regression with a real remote fixture The bug is in remote module dependency resolution. The previous regression test covered that path through a synthetic local Git service plus transport-specific setup, which made the failure mode noisier than it needed to be. Replace it with a regression test that uses github.com/dagger/dagger-test-modules/context-git, which we already maintain as part of our end-to-end Git/module coverage. This does introduce a network call, but that is the better tradeoff here. The bug only matters on the remote module path, and this fixture already matches the environment we rely on for real Git dependency tests. The new test covers both branch-name and tag-name pins, which is the actual behavior we need to preserve: a non-SHA pin is a named ref, not a commit. Signed-off-by: Guillaume de Rouville <guillaume@dagger.io> * core: resolve named dependency pins as refs instead of commits A dependency pin can be either: - a commit SHA - a named ref, such as a branch or a tag The bug was that modulerefs did not keep that distinction. For unversioned dependency sources, it resolved the repository through head() and still forwarded pinCommitRef through the commit override path even when the pin was a branch or tag name. That was already the wrong contract. A commit override is for an object id. A named pin should travel through ref(name: ...). The --no-tags change did not create this bug; it exposed it. Before that change, extra fetched tag state could sometimes hide the invalid commit-vs-ref conflation. Once that masking disappeared, the bug surfaced as checkout failures like "sha fetch unsupported by remote". Fix the problem at the source: - only treat the pin as commit when it is a real SHA - resolve non-SHA pins as named refs - keep the head() path only for the truly unversioned case That restores a clean contract: - SHA pin => exact commit - named pin => exact named ref - no pin and no explicit ref => repository HEAD Signed-off-by: Guillaume de Rouville <guillaume@dagger.io> * git: enforce the commit override contract The previous compatibility change made lower layers tolerant of invalid commit overrides by silently ignoring non-SHA values. I do not want that contract to be soft. Once modulerefs constructs the right state, lower layers should enforce their boundary instead of guessing what the caller meant: - ref(name: ...) resolves named refs - commit overrides are commit SHAs Make that explicit in the Git schema and in HEAD resolution. Invalid commit overrides now fail immediately instead of being dropped on the floor. This is intentionally stricter than the compatibility layer it replaces. I prefer an explicit contract to intertwined fallback behavior: the caller decides whether a pin is a ref or a SHA, and the lower layers reject invalid state. Signed-off-by: Guillaume de Rouville <guillaume@dagger.io> * test: drop branch pin case, keep only tag The branch-name test case ("context-git") relies on a branch in dagger-test-modules that could be pruned at any time. Tags are immutable and exercise the same ref(name: ...) code path, so keep only the v1.2.3 tag case. Signed-off-by: Guillaume de Rouville <guillaume@dagger.io> --------- Signed-off-by: Mike Glazer <mike.glazer@gmail.com> Signed-off-by: Guillaume de Rouville <guillaume@dagger.io> Co-authored-by: Guillaume de Rouville <guillaume@dagger.io>
…#10510) * feat(secretprovider): add Google Cloud Secret Manager support This adds support for using Google Cloud Secret Manager as a secret provider in Dagger, enabling secure secret retrieval from GCP environments. This was tested with the following command: ```shell DAGGER_TEST_GCP_SECRETS=1 GCP_PROJECT_ID=rawkode-academy-production GCP_TEST_SECRET_NAME=KNOWN_SECRET GCP_TEST_SECRET_VALUE=KNOWN_VALUE go test -v -timeout 30s -run "^TestSecretGCP$" github.com/dagger/dagger/core/integration ``` Key features: - Support for multiple authentication methods: - Service account key files (via GOOGLE_APPLICATION_CREDENTIALS) - Application Default Credentials (ADC) - Workload Identity (on GKE) - GCE metadata service (on Compute Engine) - Secret reference formats: - Short form: gcp://secret-name (requires GCP_PROJECT_ID env var) - Full form: gcp://projects/PROJECT/secrets/SECRET/versions/VERSION - Latest version: gcp://secret-name/versions/latest - Built-in caching with configurable TTL via query parameter (?ttl=5m) - Comprehensive error handling and validation Implementation details: - Uses official Google Cloud Go SDK (cloud.google.com/go/secretmanager) - Thread-safe with mutex protection for concurrent access - Efficient client reuse across multiple secret retrievals - Supports all standard GCP authentication flows Testing: - Unit tests for URL parsing and validation - Integration tests covering authentication and secret retrieval - Documentation with setup instructions and examples Signed-off-by: David Flanagan <david@rawkode.academy> * go fmt and remove deleted docs page Signed-off-by: kpenfound <kyle@dagger.io> --------- Signed-off-by: David Flanagan <david@rawkode.academy> Signed-off-by: kpenfound <kyle@dagger.io> Co-authored-by: kpenfound <kyle@dagger.io>
* initial tuist cutover
Signed-off-by: Alex Suraci <alex@dagger.io>
* idtui: migrate frontend_pretty to idiomatic tuist components
Restructure frontend_pretty.go from a monolithic component with manual
dirty tracking into idiomatic tuist components where dirty propagation
flows naturally through the tree. Net reduction of ~150 lines.
Phase 1: Eliminate fe.mu
- All exporter goroutines (spans, logs, metrics) now use tui.Dispatch()
to mutate state on the UI goroutine instead of locking fe.mu
- Copy OTel slices before dispatching (SDK reuses them after return)
- Use context.Background() in dispatched callbacks (caller ctx may expire)
- Metric exporter uses synchronous dispatch (ResourceMetrics is reused)
- All public methods (SetClient, SetVerbosity, SetPrimary, SetCloudURL,
SetSidebarContent, Shell, RevealAllSpans, Close) dispatch to UI goroutine
- Remove fe.mu, flush(), markExporterDirty(), exporterDirty map
Phase 2: Extract SpinnerView component
- Self-ticking component (33ms via OnMount goroutine, stopped on dismount)
- Only mounted when span is running; completed spans have zero cost
- SpanRowView.syncSpinner manages creation/removal based on span state
- RenderChild in SpanRowView.Render handles mount/dismount lifecycle
- Remove global frameLoop goroutine, fe.fps, fe.now fields
- statusIcon() uses per-span spinner with time.Now() fallback for effects
Phase 3: Focusable for focus tracking
- SpanRowView implements tuist.Focusable (SetFocused callback)
- focus() calls tui.SetFocus(spanRow) so old/new rows re-render
Phase 4: Eliminate viewport windowing
- renderProgress() iterates ALL rows instead of windowing around focus
- Remove renderLines() (100-line viewport algorithm)
- Tuist's diff renderer skips unchanged offscreen lines automatically
- Merge renderContent() into Render() directly
Phase 5: Clean up string-builder rendering
- Remove fe.view/fe.viewOut string builders; build directly in Render()
- Remove spanRowKey struct and spanRowKeyFor() (manual dirty tracking)
- Replace frameLoop with scheduleKeypressClear() one-shot timer
Requires tuist v0.0.0-20260303194803-b28414493014 which mounts all
RenderChild children (not just MouseEnabled ones).
Signed-off-by: Alex Suraci <alex@dagger.io>
* idtui: fix focus visibility and line wrapping artifacts
Two fixes for the interactive TUI:
1. Truncate lines to terminal width: Lines produced by renderCall
(especially string literals like execMD JSON) can far exceed the
terminal width. The terminal wraps them to multiple physical rows,
but tuist's diff renderer counts logical lines for cursor math.
The mismatch causes the cursor to land mid-line, corrupting the
display with repeated/garbled content. Fix: truncate every line
to ctx.Width using muesli/reflow/truncate (ANSI-aware) before
returning from Render().
2. Cap progress output after focus: When focus moves up, rows below
push the focused row offscreen, and re-rendering the keymap scrolls
the terminal back down, hiding the focus. Fix: renderProgress now
limits 'after' rows to ~50% of remaining screen budget. Rows above
focus scroll into terminal scrollback naturally (preserving history).
When everything fits on screen, nothing is removed.
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: refactor to tree-based rendering with SpanTreeView
Replace row-based rendering (SpanRowView) with tree-based rendering
(SpanTreeView) to fix stale parent ancestor prefixes (colorful line
guides).
Key changes:
- SpanTreeView renders a TraceTree node and its children recursively,
replacing the flat SpanRowView that rendered one row at a time.
- Prefixes (tree-line art like ├╴, │, ╰╴) are computed top-down by
parent SpanTreeViews, avoiding the stale-prefix problem where each
row independently walked up the TraceRow.Parent chain and could
cache outdated parent colors.
- All component state mutations (prefix, children, focus, spinners)
happen in syncSpanTreeState(), called from recalculateViewLocked()
during event handlers and Dispatch callbacks. Render() is a pure
function that only reads state and produces output.
- Added indentFunc override on renderer so SpanTreeView can inject
pre-computed prefixes without rewriting all rendering functions.
- FinalRender path unchanged: still uses flat renderRow with original
fancyIndent (no component caching needed post-TUI).
- TraceRow kept for focus/navigation (flat index, previous/next
pointers); rendering uses TraceTree hierarchy.
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: fix gap lines missing parent bar for last children
Gap lines between sibling children were using child.prefix.cont, which
for the last child omits the parent's bar column (showing spaces instead
of │). The gap is *above* the last child though, so the parent bar should
still be visible.
Fix: compute a childrenGapPrefix on each SpanTreeView during state sync
(parent's forChildren + parent's own colored │ column) and use that for
all gap lines between children.
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: fix indentation, scrolling, and debug logging
- Fix indentFunc to fall through to original fancyIndent for synthetic
rows (e.g. renderErrorCause), preventing double indentation. The
indentFunc now returns bool to signal whether it handled the row.
- Remove viewport windowing from renderProgressTree. Instead, render all
lines into scrollback and truncate below the focused item so it stays
onscreen. Focus line is found by walking the tree's render metadata.
- Move all SpanTreeView state sync (prefix, focus, children, spinners)
into syncSpanTreeState() called from recalculateViewLocked(), making
Render() stateless. Remove Invalidate() from tuist.
- Add TUIST_LOG env var to enable tuist render debug logging.
- Update tuist to v0.0.0-20260304010918-df8947963e5e for component
stats propagation through RenderChild.
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: remove dual focus tracking, add TODO.md
Remove Focusable interface from SpanTreeView. Focus state is now
solely managed by syncSpanTreeState (syncing st.focused from
fe.FocusedSpan). tui.SetFocus is kept for keyboard routing only.
Add TODO.md documenting remaining architectural improvements. Items
2 (scroll truncation) and 3 (indentFunc fallthrough) were reviewed
and found to be working correctly with tuist's design — marked as
KEEP.
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: restructure Render() to line-based composition
Replace the string-builder-then-split pattern in frontendPretty.Render()
with direct []string line assembly:
- renderProgressTree → renderProgressLines (returns []string)
- Extract renderLogsLines, renderEditlineLines, renderFormLines,
renderKeymapLines as line-returning helpers
- Render() assembles output via append, no string builder
- Remove dead finalRender branch from renderProgressLines
- Sidebar compositing still uses string join/split (lipgloss requires it)
This is phase 1 of TODO item 4. Phase 2 would extract these into proper
tuist components with their own Compo for render caching.
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: replace sidebar with notification bubble overlays
Replace the old sidebar system (string-based, steals content width via
lipgloss JoinHorizontal) with notification bubbles rendered as tuist
overlays.
Each SidebarSection becomes a NotificationBubble component displayed
as an overlay anchored to the bottom-right of the content. Multiple
sections stack upward. Bubbles have rounded-corner borders with the
title embedded in the top border:
╭─ Title ─── keymap ──╮
│ content here │
╰──────────────────────╯
Benefits:
- Content gets full terminal width (no sidebar width stealing)
- Each bubble is a tuist Component with its own render cache
- Overlays are composited by tuist's overlay system, not lipgloss
- Removes renderSidebar, viewSidebar, renderWithSidebar, haircut
- Removes sidebarWidth, sidebarBuf fields
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: update TODO.md — mark item 4 as done
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: decouple ShellHandler from tea.Cmd pattern
Replace tea.Cmd returns in ShellHandler interface with explicit
async work functions:
- ReactToInput: returns func() (async work) or nil (not handled),
instead of tea.Cmd. Caller runs async work in a goroutine.
- Prompt: returns (string, func()) instead of (string, tea.Cmd).
The func() is optional async init work.
The frontend runs async work via runShellAsync(), which spawns a
goroutine and dispatches updatePrompt + re-render when done.
This fixes a race condition where execTeaCmd ran shell operations
(h.runner.Run, h.llmSession.SyncToLocal, etc.) in background
goroutines that accessed shared state concurrently. Now the shell
handler returns the work as a value, and the frontend controls
execution.
Also removes UpdatePromptMsg — the dispatch callback handles prompt
updates directly.
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: note runner synchronization issue in TODO
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: fix stack overflow in updatePrompt/runShellAsync cycle
updatePrompt called runShellAsync which called updatePrompt, causing
infinite recursion. Fix by inlining the goroutine spawn for Prompt's
init function directly in updatePrompt, breaking the cycle.
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: make Prompt pure, rename updatePrompt to syncPrompt
Prompt() now returns just a string — no async init function. LLM
initialization is solely handled by ReactToInput (the '>' key),
which already returns the init work. Prompt just renders current
state: 'loading...' if not initialized, model name if ready.
Rename updatePrompt → syncPrompt to reflect that it's a pure state
sync with no side effects. runShellAsync calls syncPrompt before
and after async work.
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: replace editline with tuist TextInput, decouple from bubbletea
Hard cutover of the ShellHandler interface away from bubbletea types:
- ReactToInput: takes uv.KeyPressEvent directly instead of tea.KeyMsg
- Prompt: returns string only (no tea.Cmd)
- AutoComplete: returns tuist.CompletionResult instead of editline.Completions
- IsComplete: takes string instead of [][]rune
- Background: uses our own ExecCommand interface instead of tea.ExecCommand
- EncodeHistory/DecodeHistory: replaces editline.HistoryEncoder interface
Replace editline.Model with tuist.TextInput:
- TextInput handles its own key events natively (no UV→tea conversion)
- History navigation (up/down) implemented directly on frontendPretty
- CompletionMenu wired up via tuist.NewCompletionMenu
- Focus managed via tui.SetFocus instead of editline.Focus()/Blur()
Bubbletea remains only as an internal dependency for huh.Form, not
exposed in any interface.
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: TextInput as TUI sibling with KeyInterceptor for special keys
- TextInput added to TUI container as sibling of frontendPretty,
so cursor propagation works through tuist's container rendering
- TUI focus routes keys to TextInput when in insert mode
- KeyInterceptor handles ctrl+c/d, esc, history nav, mode switch
before TextInput processes the key
- HandleKeyPress on frontendPretty only handles form and nav modes
- DecodeHistory made pure (no mode side-effect) fixing shell starting
in prompt mode after history load
- go.mod: add replace directive for local tuist
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: enable hardware cursor when TextInput is added
SetShowHardwareCursor(true) is required for tuist to position and
show the terminal cursor. Without it, positionHardwareCursor always
hides the cursor even when a component returns a CursorPos.
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: route completion menu keys through KeyInterceptor
CompletionMenu.HandleKeyPress is called first in the interceptor,
before history navigation or other special keys. When the menu is
visible, it consumes up/down/esc; otherwise they fall through to
history or TextInput.
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: extract KeymapBar as a proper tuist component
KeymapBar is added to the TUI container after fe and before/after
the TextInput, so it renders at the bottom of the screen as a
sibling component rather than being manually concatenated in
fe.Render().
- New KeymapBar component in keymap.go with its own Render method
- Extracted RenderKeymap() as a standalone function (used by both
KeymapBar and NotificationBubble)
- KeymapBar.PressedKey/PressedKeyAt updated via recordKeyPress()
which also triggers keymapBar.Update() for re-render
- Removed renderKeymapLines, keymapView, renderKeymap from
frontend_pretty.go
- TUI child order: fe → textInput → keymapBar
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: add children in natural order — output, prompt, keymap
Create and add keymapBar in startShell after textInput, instead of
adding it early in startTUI and shuffling with RemoveChild/AddChild.
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: fix history round-trip — store raw encoded entries
History entries are stored with their mode prefix (e.g. '!' for shell,
'>' for prompt) throughout their lifecycle:
- Load: raw encoded entries from file, stored as-is
- Browse (up/down): DecodeHistory strips prefix for display
- Submit: EncodeHistory adds prefix before storing
- Save: written directly, already encoded
Previously, DecodeHistory was called at load time (stripping prefixes)
and EncodeHistory at save time (using current mode), which meant all
entries got re-encoded with whatever mode happened to be active at
save time, losing per-entry mode info.
Signed-off-by: Alex Suraci <alex@dagger.io>
* keymap: remove extra blank line between input and keymap
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: show keymap in all modes, not just shell
Create keymapBar in startTUI so it's visible for dagger call etc.
When startShell adds the textInput, it removes and re-adds the
keymapBar to maintain output → prompt → keymap order.
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: update keymapBar when mode changes
Call keymapBar.Update() after editlineFocused changes in startShell,
enterNavMode, and enterInsertMode so the keymap shows the correct
bindings immediately.
Signed-off-by: Alex Suraci <alex@dagger.io>
* rm old .mds
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: guard against stale tree metadata in focus search
The childGapCounts/childLineCounts slices are populated during
SpanTreeView.Render, but findFocusInSubtree and totalLineCount
may be called before the tree has been rendered in the current
frame (e.g. when children changed). Guard against the length
mismatch instead of panicking.
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: mark SpanTreeView dirty when children change
The root cause of the index-out-of-range panic: syncSpanTreeState
mutated st.children (via syncTreeNode) without calling st.Update(),
so tuist's renderComponent returned the cached result, skipping
Render() and leaving childGapCounts/childLineCounts stale from the
previous frame with a different children count.
Now syncTreeNode detects when children are added, removed, or
reordered and calls st.Update() to force a re-render. Also marks
dirty when collapsing (children cleared).
The length guard in findFocusInSubtree/totalLineCount is kept as
defense-in-depth.
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: create TUI at construction time so it's never nil
Dispatch calls like SetPrimary, SetClient, etc. can be called before
startTUI (e.g. in the reportOnly path). Creating the TUI in NewWithDB
ensures fe.tui is always valid. startTUI just configures and starts it.
Signed-off-by: Alex Suraci <alex@dagger.io>
* idtui: use teav1.Wrap for huh.Form instead of manual bubbletea bridge
Replace the hand-rolled bubbletea command executor, message router, and
UV-to-tea key conversion with tuist's teav1.Wrap component. The form is
now a proper TUI child component that receives focus and key events
through tuist's standard routing.
This removes ~200 lines of duplicated bridge code:
- execTeaCmd / handleTeaMsg command executor
- uvKeyToTeaKeyMsg and all key conversion maps (uvToV1Key, shiftedKey,
ctrlKeys, shiftKeys, ctrlShiftKeys)
- handleFormKey manual key forwarding
- promptDone message type
- Dead wrapCommand type (bubbletea era leftover)
Signed-off-by: Alex Suraci <alex@dagger.io>
* refactor(idtui): unify final render with tree-based rendering path
Replace renderProgressFinal's flat row loop with a recursive tree walk
that reuses renderTreeGap and renderRowContent with the SpanTreeView's
pre-computed prefixes. This eliminates the duplicate renderRowGap and
renderRow methods which duplicated the gap heuristic logic from
renderTreeGap.
Signed-off-by: Alex Suraci <alex@dagger.io>
* refactor(idtui): simplify notification overlays with a single Container
Replace per-notification overlay handles and manual stacking math with
a single tuist Container shown as one overlay. Notifications are added
as children of the container, and tuist handles vertical layout.
Also removes the sidebar background color and anchors notifications to
the top-right of the visible viewport instead of the bottom of the
content area.
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix revealed connectors
Signed-off-by: Alex Suraci <alex@dagger.io>
* update gold - trailing whitespace gone
Signed-off-by: Alex Suraci <alex@dagger.io>
* chore(idtui): fix lint warnings
Fix gofmt formatting, consistent receiver names, remove unused
params/functions (logsDone, eofMsg, debug.go, prefix param).
Signed-off-by: Alex Suraci <alex@dagger.io>
* bump testdata to go 1.25.6
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): hide keymap bar on final render
Remove the keymap bar from the TUI before quitting so it doesn't
appear in the last rendered frame left on screen.
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): add gap between huh form and keymap bar
Insert a blank line component between the form and the keymap bar
so they don't render flush against each other.
Signed-off-by: Alex Suraci <alex@dagger.io>
* switch to github tuist
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): use tuist Exec for background commands
Replace manual Stop/Start/pipe plumbing with a single tui.Exec call
that handles stdin passthrough and TUI lifecycle automatically.
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): use pointer receiver for blankLine to avoid copylocks
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): address PR review comments
- Restore h.mode assignments in DecodeHistory so history navigation
switches the input mode to match the history item.
- Restore LLM init in Prompt via async return value, matching the
ReactToInput pattern. syncPrompt runs it via runShellAsync.
- Use fe.Update() instead of fe.Compo.Update().
- Remove unnecessary uvKeyString wrapper, inline k.String().
- Restore removed/oversimplified comments throughout rendering code:
brailleDots descriptions, renderRollUpDots algorithm comments,
statusIcon/renderToggler/renderStatusIcon docs, extractSpanContext
explanations, findRollUpSpan walk comments, error origin guards,
message span notes, effect span filtering, and more.
Signed-off-by: Alex Suraci <alex@dagger.io>
* refactor(idtui): use fe.Update() instead of fe.Compo.Update()
Signed-off-by: Alex Suraci <alex@dagger.io>
* refactor(idtui): remove line truncation, now handled by tuist
Tuist now truncates lines exceeding terminal width in its render
pipeline, so components no longer need to do it themselves.
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): unfocus span highlight when editline is focused
When switching between nav and insert mode, recalculateViewLocked
so syncTreeNode detects the editlineFocused change and calls
st.Update() on the previously-focused span tree. Without this,
the span tree's cached render retains the focus highlight even
after the text input takes focus.
Also in shell mode, skip the below-focus truncation in
renderProgressLines so command output (inline logs) is not
clipped by the half-viewport afterBudget.
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): remove extra blank line after LLM user prompt spans
In shell mode, renderTreeGap inserts a blank line between every
top-level span. LLM user prompts (█ block) already have their own
visual separation, so skip the gap for LLMRoleUser spans.
Signed-off-by: Alex Suraci <alex@dagger.io>
* clear input + bubbles on exit
Signed-off-by: Alex Suraci <alex@dagger.io>
* bump tuist
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): fix --progress=report hanging on tui dispatch
In reportOnly mode, the TUI event loop never starts, so
fe.tui.Dispatch() queues callbacks that are never consumed. This
caused all OTel exporters to silently drop data, and the metric
exporter to deadlock on a synchronous done channel.
Add fe.dispatch() helper that runs callbacks directly under a mutex
in reportOnly mode, falling back to fe.tui.Dispatch() when the TUI
is running. Remove the unnecessary synchronous done channel from
FrontendMetricExporter.Export.
Signed-off-by: Alex Suraci <alex@dagger.io>
* bump tuist, update usage
Signed-off-by: Alex Suraci <alex@dagger.io>
* TODO(split): fetch logs in dagger trace
Signed-off-by: Alex Suraci <alex@dagger.io>
* perf(idtui): use tuist Focusable for O(1) focus changes
Replace the O(N) tree walk in syncTreeNode that checked every node's
focus state on every keypress. SpanTreeView now implements
tuist.Focusable, so SetFocus dispatches SetFocused to exactly the 2
affected components (old and new focus).
focus() no longer calls recalculateViewLocked(), eliminating the full
RowsView rebuild and tree sync on navigation. This removes ~15s of
CPU time from the keypress hot path.
Also consolidate all focus mutations through focus() for consistency,
including nil support for unfocusing.
Signed-off-by: Alex Suraci <alex@dagger.io>
* perf(idtui): skip RowsView rebuild on expand/collapse
Make syncTreeNode and syncSpinnerTree read expanded/running state
from rowsView (TraceTree) instead of rows (TraceRow), eliminating
the dependency on the flat row list for tree sync.
setExpanded is now a pure setter. closeOrGoOut and openOrGoIn use
syncAfterExpandToggle which rebuilds only the flat row list from
the existing rowsView and syncs just the affected subtree. This
skips the expensive RowsView rebuild (WalkSpans + ShouldShow) and
fixes double-recalculate bugs where setExpanded and its callers
both called recalculateViewLocked.
Signed-off-by: Alex Suraci <alex@dagger.io>
* perf(idtui): O(depth) focus line lookup via bottom-up walk
Replace findFocusInSubtree which searched the entire tree top-down
(O(nodes)) with findFocusLine which walks up from the focused
SpanTreeView to the root (O(depth × siblings)). This is enabled by
adding parent and indexInParent pointers to SpanTreeView, set during
syncTreeNode and syncSpanTreeState.
Signed-off-by: Alex Suraci <alex@dagger.io>
* perf(idtui): coalesce recalculate and fix DB hot paths
Three independent fixes for the UI lockup on large traces:
1. Coalesce recalculateViewLocked to once per render frame. ExportSpans
dispatch callbacks now set a viewDirty flag instead of calling
recalculateViewLocked. Render checks the flag and recalculates once
before drawing. This prevents N batches × 25s recalculate from
starving the UI goroutine.
2. Make Activity.updateEarliest O(1) for the common case. When adding
a running span, just compare against current earliest instead of
scanning all running spans. Only rescan when removing the earliest.
3. Add visited set to PropagateStatusToParentsAndLinks. The CausalSpans
iterator walks transitively, so the same parent/causal span could be
visited many times via different paths. The visited set deduplicates,
reducing O(C×D) to O(C+D).
Signed-off-by: Alex Suraci <alex@dagger.io>
* fmt
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): use "space" instead of " " for space key matching
Ultraviolet Key.String() returns "space" for the space key, not
" ". The old literal space never matched, so pressing space did
nothing in nav mode.
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): re-render span tree on expand/collapse toggle
When expanding a span with logs but no children, syncTreeNode
found no structural changes so the SpanTreeView was never marked
dirty. The logs (gated on row.Expanded) would not appear until
the next incidental re-render. Now syncAfterExpandToggle always
calls st.Update() on the toggled span.
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): never crop view to less than terminal height
When the focused line was near the top, the bottom-truncation
logic could crop the visible content well below the viewport
height, leaving the screen half-empty. Now end is floored at
viewportHeight so the full terminal is always used.
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: don't steal focus from input
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: fix moving through shell history
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: gap above assistant responses
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: center focused span in viewport
Rework progress cropping to keep the focused span fully visible
and fill remaining viewport space evenly above and below. This
prevents tall nodes (e.g. long LLM responses) from having their
bottom cut off when the top line was used as the anchor point.
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: only crop bottom, not top
Content above the viewport scrolls into terminal scrollback
naturally. Only crop the bottom to keep the focused span within
the visible screen area, with remaining space split evenly above
and below.
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: never crop bottom of focused span
Extract viewport cropping into a testable cropEnd function with
clear invariants: the focused span is always fully visible,
remaining viewport space is split evenly above and below, and
the viewport is filled when enough content exists.
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): clear stale topTrees when rows become empty
recalculateViewLocked returned early when rows were empty without
calling syncSpanTreeState, leaving fe.topTrees stale from the
previous view. When SetPrimary switched from the engine span to
the shell span, renderProgressLines iterated the old topTrees and
rendered ghost spans (e.g. connect) above the prompt.
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(dagui): race condition on TelemetryError field
TelemetryError was written from the OTel PeriodicReader error handler
goroutine and read from the render goroutine without synchronization.
Change it to atomic.Pointer[error] so access is safe across goroutines.
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(dagui): move TelemetryError off FrontendOpts to fix copylocks
TelemetryError was an atomic.Pointer on FrontendOpts, which made the
struct non-copyable. FrontendOpts has value-receiver methods (e.g.
ShouldShow), so every call triggered a copylocks vet error. Move the
field to each Frontend implementation as a private telemetryError and
expose it via a SetTelemetryError interface method instead.
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(dagui): print telemetry error warning in dots and logs frontends
Implement SetTelemetryError for the dots and logs frontends so they
store and print the warning on exit, matching the behavior of the
plain and pretty frontends. Also widen handleTelemetryErrorOutput to
accept TermOutput instead of *termenv.Output.
Signed-off-by: Alex Suraci <alex@dagger.io>
* feat(idtui): add Vim-style fulltext search
Add '/' search mode to the pretty TUI frontend. Searches span names
and vterm log content with case-insensitive substring matching. 'n'
and 'N' navigate forward/backward through matches (wrapping), 'Esc'
clears the active search.
Search matches are indicated with a yellow dot marker on matching
spans. Log matches scroll the vterm viewport to center the matched
line. Match state is refreshed automatically as new spans/logs arrive.
Includes SPEC.md with the full design rationale.
Signed-off-by: Alex Suraci <alex@dagger.io>
* feat(idtui): highlight all search matches with current-match indicator
Add ANSI-aware inline highlighting for search matches. All matches
get a yellow background, the current match gets bright yellow. Works
for both span name matches in tree lines and log content in vterms.
Vterm gains SearchQuery/SearchCurrentRow fields and SetSearchHighlight
to control per-line highlight rendering. SpanTreeView self-lines are
post-processed with highlightANSI after rendering.
dirtySearchTrees tracks previous vs current match spans and calls
Update on all affected SpanTreeViews so tuist repaints them when
search state changes (next/prev/clear/new query).
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): fix search highlight bleeding to end of line, swap colors
Two fixes:
1. The highlight was extending to end of line because hlEnd used a
full ANSI reset which cleared ALL formatting (faint, bold, etc.),
not just the highlight's bg/fg. After the reset, only the last
single ANSI sequence was restored, losing cumulative state like
faint text. Now we accumulate ALL ANSI sequences seen outside of
highlights and replay them all after hlEnd to fully restore the
prior formatting state.
2. Swap colors per feedback: non-current matches use white background,
current/focused match uses yellow background. Both use black fg.
Adds unit tests for the ANSI-aware highlighting logic covering plain
text, case insensitivity, formatting preservation across highlights,
multiple sequences, match-at-end, and multiple matches.
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): split title vs log rendering to prevent double-highlighting
SpanTreeView.Render was applying highlightANSI to ALL self lines,
including vterm log output that already had its own search highlights
applied. This caused double-highlighting with garbled ANSI output.
Split renderRowContent into renderStep (title) + renderRowContentRest
(logs/errors/debug). SpanTreeView.Render now highlights only the
title lines; log highlighting is handled by Vterm's SearchQuery.
Signed-off-by: Alex Suraci <alex@dagger.io>
* docs: update SPEC.md with midterm-native search plan
Document what's done, what's broken (ANSI post-processing for vterm
highlights), and the plan to move search highlighting into midterm
itself where it operates on structured rune content + format canvas
rather than post-processing ANSI byte streams.
Signed-off-by: Alex Suraci <alex@dagger.io>
* docs: update search SPEC with implementation progress
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): clone ResourceMetrics before async dispatch
The OTel PeriodicReader pools and reuses ResourceMetrics structs
via sync.Pool. FrontendMetricExporter.Export dispatches a closure
to the TUI goroutine asynchronously, so by the time it runs the
SDK may already be writing to the same struct for the next
collection cycle. Clone the data before dispatching, matching the
pattern already used for spans and logs.
Signed-off-by: Alex Suraci <alex@dagger.io>
* feat(idtui): use midterm native search highlighting
Replace ANSI post-processing in Vterm.Render with midterm's native
search overlay. SetSearchHighlight now delegates to midterm's Search()
and SearchSetCurrent() which operate on the rune/column canvas,
fixing byte-vs-rune drift with multi-byte characters.
searchVtermRows reads midterm's SearchMatchRows() instead of
independently scanning content, and syncVtermSearchHighlights runs
before buildSearchMatches so midterm has fresh results to read.
Signed-off-by: Alex Suraci <alex@dagger.io>
* feat(idtui): search all spans in tree, not just visible rows
Walk the full RowsView trace tree (subject to verbosity) when building
search matches, so collapsed/hidden spans are included. Vterm content
searches run in parallel. Navigating to a match in a collapsed span
expands its ancestors to reveal it.
Previously only fe.rows.Order (the flattened visible list) was searched,
so matches deep in the trace were invisible until manually expanded.
Signed-off-by: Alex Suraci <alex@dagger.io>
* feat(idtui): deselect search match on focus change
Moving focus (arrow keys, clicking) clears the current search match
selection so that n/N seek relative to the new focus position rather
than continuing from the old match. N seeks backward from focus.
Also: fix cropping behavior once again, this time to avoid placing the
parent flush with the top edge.
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): don't clear search selection during search navigation
goToSearchMatch calls focus() which was clearing searchIdx. Add a
searchNavigating guard so focus() only resets the search selection
on manual focus changes (arrow keys), not when search is driving
the navigation.
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): don't steal focus from search input
focus() now skips SetFocus when searchActive is true, preventing
autoFocus and recalculateViewLocked from stealing TUI input focus
away from the search prompt while the user is typing a query.
Also guard enterSearchMode against duplicate calls so a second /
keystroke during an active search doesn't install a second prompt.
Signed-off-by: Alex Suraci <alex@dagger.io>
* perf(idtui): simplify search refresh, drop goroutines
With midterm's incremental search, the per-tick cost is proportional
to new output, not total content. Drop the goroutine-per-span fan-out
(SearchMatchRows is just a slice read) and eliminate the redundant
double call to syncVtermSearchHighlights in the refresh path.
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): refresh search results on every frame
Search refresh was only triggered by recalculateViewLocked (gated on
viewDirty), which is set by ExportSpans but not by log writes. New
log output containing matches wouldn't appear until a span export or
manual focus change happened to trigger a recalculate.
Move the search refresh to Render, running every frame when a search
is active. With midterm's incremental search this is cheap — only
rows that received new Write() data since the last frame are
re-scanned.
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): update keymap bar when search matches change
refreshSearchMatches wasn't calling keymapBar.Update(), so the
match count display (e.g. '3/52') didn't update when new log
output added matches.
Signed-off-by: Alex Suraci <alex@dagger.io>
* fmt
Signed-off-by: Alex Suraci <alex@dagger.io>
* refactor(idtui): move debugged state to SpanTreeView
Migrate fe.debugged from a single SpanID on frontendPretty to a
per-component bool on SpanTreeView. The ? key handler now looks up
the focused SpanTreeView, toggles its debugged field, and calls
Update() to re-render. This also allows multiple spans to be
debugged simultaneously.
Signed-off-by: Alex Suraci <alex@dagger.io>
* cleanup SPEC
Signed-off-by: Alex Suraci <alex@dagger.io>
* fmt
Signed-off-by: Alex Suraci <alex@dagger.io>
* lint
Signed-off-by: Alex Suraci <alex@dagger.io>
* fixup linebreak
Signed-off-by: Alex Suraci <alex@dagger.io>
* bump module go.mods
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): save shell history before clearing shell state
stopShell() was setting fe.shell and fe.textInput to nil before Run()
had a chance to persist the history file. The save condition in Run()
always evaluated to false, so history was never written to disk. Move
the save into stopShell() where it runs before the state is cleared.
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): return correct byte count from multiprefixw Write
Write was returning len(p) after the loop consumed all bytes, so it
always returned 0. Return the original length instead.
Signed-off-by: Alex Suraci <alex@dagger.io>
* feat(idtui): show error message above prompt when prompt turns red
Add an ErrorLabel component that displays the underlying error message
when a shell command fails. Previously the only signal was the prompt
character turning red, with no indication of what went wrong. Now the
error text is rendered as a red line between the output area and the
prompt input, and cleared when the next command is submitted.
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(tui): fix janky focus
Signed-off-by: Alex Suraci <alex@dagger.io>
* feat(idtui): word-wrap ErrorLabel to fit terminal width
Long error messages now wrap at word boundaries instead of being
truncated or overflowing. Continuation lines are indented to align
with the text after the "Error: " prefix.
Signed-off-by: Alex Suraci <alex@dagger.io>
* refactor(idtui): migrate from lipgloss v1 to v2
Replace github.com/charmbracelet/lipgloss with charm.land/lipgloss/v2.
Use v2 named color constants (lipgloss.Red, lipgloss.BrightBlack, etc.)
instead of lipgloss.Color("1") or lipgloss.ANSIColor(termenv.ANSI*).
Replace removed SetHasDarkBackground/HasDarkBackground() with the v2
HasDarkBackground(in, out) API, keeping env-var overrides.
Signed-off-by: Alex Suraci <alex@dagger.io>
* fmt
Signed-off-by: Alex Suraci <alex@dagger.io>
* add tuist deps to go.mod/go.sum
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): break syncPrompt/runShellAsync mutual recursion
runShellAsync called syncPrompt synchronously before spawning its
goroutine. When the LLM session isn't loaded yet, syncPrompt returns
an init func, which calls runShellAsync, which calls syncPrompt
again, overflowing the stack. Remove the synchronous syncPrompt call
so the cycle is broken; the async goroutine still dispatches a
syncPrompt on completion.
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): sync prompt when cycling through shell history
DecodeHistory correctly updates the internal mode based on the !/>
prefix, but the UI prompt was never refreshed to reflect the mode
change. Now SaveBeforeHistory/RestoreAfterHistory are exposed on the
ShellHandler interface, and syncPrompt is called after each history
navigation so the prompt matches the history entry's mode.
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): replace stale focusedIdx with focusedIndex()
The focusedIdx field was set when focus() was called but never
updated when expand/collapse rebuilt the row list.
NOTE: the assumption was that this caused search next/prev to compare
against a stale index, jumping to matches before the focused item when
collapsed trees shifted indices. But it didn't help. This refactor is
still useful nonetheless, so keeping.
Signed-off-by: Alex Suraci <alex@dagger.io>
* fix(idtui): skip collapsed matches before cursor in search navigation
When pressing n to find the next search match, hidden spans inside
collapsed subtrees were treated as valid candidates regardless of
their position. A match nested inside a collapsed tree before the
cursor would be selected immediately. Now matchRowIndex resolves
hidden spans to their nearest visible ancestor's row index so the
forward/backward comparison works correctly.
Signed-off-by: Alex Suraci <alex@dagger.io>
* tui: rm wonky optimization
it's not clear this was needed
Signed-off-by: Alex Suraci <alex@dagger.io>
---------
Signed-off-by: Alex Suraci <alex@dagger.io>
* vault OIDC implementation Signed-off-by: Nipuna perera <nipuna.royal@gmail.com> * Copy skills for github copilot Signed-off-by: Nipuna perera <nipuna.royal@gmail.com> * add integration tests Signed-off-by: Nipuna perera <nipuna.royal@gmail.com> * Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Nipuna Perera <nipuna.royal@gmail.com> Signed-off-by: Nipuna perera <nipuna.royal@gmail.com> * add healthchecks for tests Signed-off-by: Nipuna perera <nipuna.royal@gmail.com> --------- Signed-off-by: Nipuna perera <nipuna.royal@gmail.com> Signed-off-by: Nipuna Perera <nipuna.royal@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
209c17a to
abfd53e
Compare
It seems that it's still possible in some cases for a contextual directory sourced from a private git repo to end up in function cache in a state where a client hitting the cache reloads it but with different credentials than before and then the engine complains it doesn't have the creds anymore (since the http auth secret becomes and explicit arg to the git operation). All these problems are going away in the new cache implementation, but in the meantime we can patch this by just checking whether the creds are valid and, if not, reloading them again as though they weren't set. Signed-off-by: Erik Sipsma <erik@sipsma.dev>
…ons (dagger#11981) When set to any non-empty value, DAGGER_NO_UPDATE_CHECK disables the automatic version check that runs on every CLI invocation. This is useful in CI environments and automated scripts where upgrading is managed externally (e.g., pinned versions in Dockerfiles, Nix, Homebrew) and the update notification is unnecessary noise on stderr. This follows the same pattern used by other CLI tools such as GH_NO_UPDATE_NOTIFIER (GitHub CLI) and CHECKPOINT_DISABLE (Terraform). Fixes dagger#11979 Signed-off-by: Jaredw2289-svg <Jaredw2289-svg@users.noreply.github.com> Signed-off-by: junyuw2289-svg <junyuw2289@gmail.com>
Bumps the sdk-python-docker group with 1 update in the /modules/ruff/build directory: [astral-sh/ruff](https://github.com/astral-sh/ruff). Updates `astral-sh/ruff` from 0.15.4 to 0.15.5 - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](astral-sh/ruff@0.15.4...0.15.5) --- updated-dependencies: - dependency-name: astral-sh/ruff dependency-version: 0.15.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: sdk-python-docker ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
dagger#12005) Bumps the sdk-typescript group in /sdk/typescript with 5 updates: | Package | From | To | | --- | --- | --- | | [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `25.3.5` | `25.5.0` | | [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) | `8.56.1` | `8.57.0` | | [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) | `8.56.1` | `8.57.0` | | [rollup-plugin-dts](https://github.com/Swatinem/rollup-plugin-dts) | `6.3.0` | `6.4.0` | | [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.56.1` | `8.57.0` | Updates `@types/node` from 25.3.5 to 25.5.0 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Updates `@typescript-eslint/eslint-plugin` from 8.56.1 to 8.57.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.57.0/packages/eslint-plugin) Updates `@typescript-eslint/parser` from 8.56.1 to 8.57.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.57.0/packages/parser) Updates `rollup-plugin-dts` from 6.3.0 to 6.4.0 - [Changelog](https://github.com/Swatinem/rollup-plugin-dts/blob/master/CHANGELOG.md) - [Commits](Swatinem/rollup-plugin-dts@v6.3.0...v6.4.0) Updates `typescript-eslint` from 8.56.1 to 8.57.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.57.0/packages/typescript-eslint) --- updated-dependencies: - dependency-name: "@types/node" dependency-version: 25.5.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: sdk-typescript - dependency-name: "@typescript-eslint/eslint-plugin" dependency-version: 8.57.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: sdk-typescript - dependency-name: "@typescript-eslint/parser" dependency-version: 8.57.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: sdk-typescript - dependency-name: rollup-plugin-dts dependency-version: 6.4.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: sdk-typescript - dependency-name: typescript-eslint dependency-version: 8.57.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: sdk-typescript ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* chore: bump google.golang.org/grpc v1.79.1 → v1.79.3 Fixes GHSA-p77j-4mvh-x3m3. Fixes dagger#12024 Signed-Off-By: Yves Brissaud <yves@dagger.io> * chore: bump github.com/buger/jsonparser v1.1.1 → v1.1.2 Signed-off-by: Yves Brissaud <yves@dagger.io> --------- Signed-off-by: Yves Brissaud <yves@dagger.io>
Signed-off-by: Alex Suraci <alex@dagger.io>
* chore: bump internal tooling to v0.20.3 Signed-off-by: Erik Sipsma <erik@sipsma.dev> * also run workaround on .dagger Signed-off-by: Erik Sipsma <erik@sipsma.dev> --------- Signed-off-by: Erik Sipsma <erik@sipsma.dev>
Update the go_sdk to send a pinned lib version to a commit from dagger-go-sdk.⚠️ This change the release process, now we will need to update the const in go_sdk to the latest commit of dagger-go-sdk, this commit will not be the one tagged because it's done before the release. At some point, it would be much better to release the SDKs before the engine so we can set the commit of the released instead of the one before. Signed-off-by: Tom Chauveau <tom@dagger.io>
* fix aws:// secrets uri in docs Signed-off-by: kpenfound <kyle@dagger.io> * generate Signed-off-by: kpenfound <kyle@dagger.io> --------- Signed-off-by: kpenfound <kyle@dagger.io>
* refresh on docs cloud page Signed-off-by: kpenfound <kyle@dagger.io> * improve phrasing in dagger cloud section on overview page Signed-off-by: kpenfound <kyle@dagger.io> * dont promote daggerverse as much until we improve it for modules v2 Signed-off-by: kpenfound <kyle@dagger.io> * remove unused screenshots Signed-off-by: kpenfound <kyle@dagger.io> --------- Signed-off-by: kpenfound <kyle@dagger.io>
Signed-off-by: Solomon Hykes <solomon@dagger.io> Signed-off-by: Alex Suraci <alex@dagger.io>
Signed-off-by: Solomon Hykes <solomon@dagger.io> Signed-off-by: Alex Suraci <alex@dagger.io>
When a module constructor has no doc comment, the constructor field on Query gets an empty description. Fall back to the module description so that dependency constructors carry a meaningful description in the shell and schema. Signed-off-by: Alex Suraci <alex@dagger.io>
With entrypoint proxying, missing constructor args are reported by dagql as 'missing required argument' instead of the shell's own positional argument validation. Signed-off-by: Alex Suraci <alex@dagger.io>
The shell now starts at Query, so all core functions are already accessible directly. The .stdlib namespace is redundant and can be removed along with all its supporting code: the stdlib command list, StdlibCommand/Stdlib/StdlibHelp methods, IsStdlib/NewStdlibState state helpers, completion handlers, and associated tests. Signed-off-by: Alex Suraci <alex@dagger.io>
Same reasoning as .stdlib: the shell starts at Query, so all core functions are already directly accessible. The .core namespace for accessing load-*-from-id and other unpromoted functions is no longer needed. Signed-off-by: Alex Suraci <alex@dagger.io>
These internal functions are still callable but are filtered from the help listing to reduce clutter. Signed-off-by: Alex Suraci <alex@dagger.io>
Now that the shell always reflects Query directly: - Remove GetCoreFunctions/GetCoreFunction/HasCoreFunction (dead code) - Remove CmdType/CmdFunction from CompletionContext (only used by .stdlib/.core namespace completion) - Remove GetModuleDef; callers use GetDef + HasModule() instead - Fix StateLookup and entrypointCall to find functions via GetDef so core functions work even without a module loaded - Fix root completions to use GetDef instead of GetModuleDef Signed-off-by: Alex Suraci <alex@dagger.io>
Functions are now grouped into sections: - Available Functions: core API functions - <module> — <description>: entrypoint module functions - Installed Modules: dependency module constructors - Builtins: shell builtins Signed-off-by: Alex Suraci <alex@dagger.io>
Signed-off-by: Alex Suraci <alex@dagger.io>
Signed-off-by: Alex Suraci <alex@dagger.io>
The entrypoint proxy's `with` field now carries the original constructor's doc comment instead of an auto-generated description. This is the user-facing constructor so it should have their docs. ModuleDoc and the type doc path also now resolve the module's named main object when entrypoint proxying is active, so `.help .` shows the original constructor info and `. | .help` shows the module's object type instead of Query. Signed-off-by: Alex Suraci <alex@dagger.io>
Merge ServedMods into ModDeps, eliminating the indirection between the two types. ModDeps now tracks per-module InstallOpts (SkipConstructor, Entrypoint) directly and handles the inner/outer server split for entrypoint proxies. The merged type is fully immutable: Append, Prepend, With, and Clone all return new instances. The mutable Add + invalidateCache pattern from ServedMods is replaced by immutable With + pointer reassignment in session.go. Schema caching is computed once per instance. The public Mods field is replaced by a Mods() accessor, and the Lookup method absorbs LookupDep. Signed-off-by: Alex Suraci <alex@dagger.io>
Rename NewModDeps to NewSchemaBuilder and update all call sites. Collapse the confusing .Schema() and .Server() methods into a single .Server() method. The old .Server() returned an inner dagql server without entrypoint proxies for ID loading, but the outer server already delegates ID loading via its IDLoader hook, making the separate method unnecessary. The lazilyLoadedInner field is removed. Signed-off-by: Alex Suraci <alex@dagger.io>
37d1edf to
4235057
Compare
Replace the public IDLoader func and Inner *Server fields on dagql.Server with a private canonical field and a Canonical() method. Canonical() returns the server without entrypoint sugar. For servers with entrypoint proxies, this is the underlying server where constructors and core fields live unshadowed. For all other servers it returns the receiver itself. Load and LoadType now delegate to Canonical() directly, eliminating the IDLoader indirection. Proxy resolvers and SDK plumbing use dag.Canonical() instead of checking dag.Inner. Signed-off-by: Alex Suraci <alex@dagger.io>
Signed-off-by: Alex Suraci <alex@dagger.io>
When installing an explicit constructor on the Query root, the engine skipped the object's description in its fallback chain, going straight from the constructor's doc comment to the module description. This left constructors with no description when only the object type had a doc comment, forcing a CLI-side workaround in functionListRun. Add objDef.Description to the explicit constructor fallback chain, matching the no-constructor path (constructor → object → module), and remove the now-unnecessary CLI workaround. Signed-off-by: Alex Suraci <alex@dagger.io>
Signed-off-by: Alex Suraci <alex@dagger.io>
Signed-off-by: Alex Suraci <alex@dagger.io>
Signed-off-by: Alex Suraci <alex@dagger.io>
now a client param Signed-off-by: Alex Suraci <alex@dagger.io>
…#11949 Restore the spirit of PR dagger#11949's changes to moddeps.go, adapted to the SchemaBuilder type: - buildSchema and lazilyLoadSchema no longer generate or cache the introspection JSON file. Only the dagql.Server is cached. - SchemaIntrospectionJSONFile generates JSON on-demand via dag.Select(__schemaJSONFile, ...). The dagql CachePerSchema mechanism handles per-args caching, so different hiddenTypes produce correctly different results without separate lazy caching. - SchemaIntrospectionJSONFileForModule now hides both TypesToIgnoreForModuleIntrospection and TypesHiddenFromModuleSDKs (Engine, EngineCache, etc.), since the caller decides what to hide. - New SchemaIntrospectionJSONFileForClient for standalone client generation, which passes no hidden types so Engine and other types remain visible. - getSchemaJSON in schema/query.go no longer unconditionally scrubs TypesHiddenFromModuleSDKs — that responsibility moves to the callers (SchemaIntrospectionJSONFileForModule passes them as hiddenTypes). Signed-off-by: Alex Suraci <alex@dagger.io>
Reflect the consolidation of ServedMods/ModDeps into SchemaBuilder, the replacement of IDLoader/Inner with Canonical(), and the on-demand introspection JSON generation. Signed-off-by: Alex Suraci <alex@dagger.io>
Signed-off-by: Alex Suraci <alex@dagger.io>
Instead of post-filtering in currentTypeDefs, the outer dagql server now genuinely omits core API fields from Query when HideCoreAPI is set. SchemaBuilder gains a hideCoreAPI flag that forces the inner/outer server split and strips core Query fields from the outer server after building. Core types (Container, Directory, etc.) remain in the schema for return-type resolution; only the Query-level entry points like container(), directory(), git(), etc. are removed. Bootstrapping fields (currentTypeDefs, currentModule, currentFunctionCall, version) are retained on the outer server. The CLI's ShouldSkipFunction list is updated to also hide currentTypeDefs and version from dagger functions output. Signed-off-by: Alex Suraci <alex@dagger.io>
The workspace module loader selects currentWorkspace from Query root during function resolution, so it must survive the HideCoreAPI strip. Signed-off-by: Alex Suraci <alex@dagger.io>
Resolvers that call CurrentDagqlServer(ctx) and select from Root need the full core schema, not the stripped outer server. Instead of fixing each call site individually (18+ sites select from Root), put the canonical server into context during field resolution. Canonical() returns self when no inner/outer split exists, so this is a no-op for single-server setups. This reverts the per-call-site .Canonical() calls in modfunc.go and the currentWorkspace bootstrap keep-list entry, replacing them with the structural fix. Signed-off-by: Alex Suraci <alex@dagger.io>
The CLI uses Query.address to resolve user-supplied flag values (containers, directories, files, secrets, services) via the Go SDK client, which sends GraphQL queries to the outer server. Signed-off-by: Alex Suraci <alex@dagger.io>
The version field is used by 'dagger core version' which doesn't set HideCoreAPI. Hiding it in ShouldSkipFunction broke command resolution. Remove it from both the bootstrap keep list and ShouldSkipFunction — it gets stripped from the outer server naturally (no Module set), and remains available on the core-only server where dagger core runs. Signed-off-by: Alex Suraci <alex@dagger.io>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
(comparing ci to
workspace-plumbing)