Commit graph

3806 commits

Author SHA1 Message Date
Jeremy
5b959648f9 test(gsd): add wrapText tests for notification overlay wrapping
Tests cover: short text, long wrapping, single-word truncation,
empty string, exact-fit, and word preservation across lines.
2026-04-06 22:52:46 -05:00
Jeremy
073a6dc546 fix(gsd): wrap long notification messages and fit overlay to content
Long messages now word-wrap onto continuation lines aligned with the
message start instead of being truncated with ellipsis. Overlay box
sizes to content height instead of padding to fill the viewport.
2026-04-06 22:49:14 -05:00
Tibsfox
f65f92cf76 fix(gsd): import all-done milestones as complete during DB migration
migrateHierarchyToDb imported milestones with all-done roadmap slices
as "active" when SUMMARY.md was missing. This let plan-milestone
overwrite already-completed work.

Now checks parsed roadmap slices — if all are done, imports as
"complete" even without SUMMARY.md.

Closes #3390
Closes #3379

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 20:07:42 -07:00
Tibsfox
5affaaf734 fix(gsd): allow milestone completion when validation skipped by preference
The completing-milestone dispatch guard blocked completion when
operational verification was planned but the validation was
intentionally skipped by a budget profile preference. The guard
now detects skip-by-preference markers in the validation content
and allows completion to proceed.

Closes #3399
Closes #3344

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:52:55 -07:00
Tibsfox
2d3723691a fix(gsd): set slice sequence at all three insertion sites
All slices got sequence=0 because the three code paths that insert
slices never set the sequence column. This made positional ordering
degenerate to alphabetical-by-ID, causing deadlocks when dependency-
free slices were ordered after blocked ones.

Now passes sequence at:
- plan-milestone: array index from agent-ordered params.slices
- reassess-roadmap: existingCount + index for newly added slices
- md-importer: parse order from roadmap content

Closes #3356

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:51:16 -07:00
Tibsfox
994fc15c9d fix(gsd): four prompt/runtime fixes for completion and session stability
1. complete-milestone: move gsd_requirement_update before
   gsd_complete_milestone so agents don't exit before updating
   requirement status (#3155)
2. complete-slice: use gsd_requirement_update instead of
   gsd_save_decision for requirement status transitions (#3154)
3. uncaughtException handler: log instead of re-throwing to prevent
   fatal double-fault that kills the session (#3163)
4. session_before_compact: only cancel during active auto-mode, not
   when paused — allows compaction during interactive work (#3165)

Closes #3155
Closes #3154
Closes #3163
Closes #3165

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:47:38 -07:00
Tibsfox
947ff2ba0a fix(gsd): default insertMilestone status to queued instead of active
Hallucinated tool calls could auto-create phantom milestones as
"active", hijacking the state machine. Observed: complete-slice issued
a stray gsd_task_complete for M000, which was auto-created as active
and promoted over the real M028.

Changing the default from "active" to "queued" means phantom milestones
from stray tool calls won't be promoted as active. Combined with the
ghost detection fix (#3645), they'll be cleaned up automatically.

Legitimate callers (plan-milestone, state reconciliation, md-importer)
already pass status explicitly.

Closes #3380

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:36:01 -07:00
Tibsfox
db19c2e67a fix(gsd): suppress repeated frontmatter YAML parse warnings
logWarning fired on every preferences load when YAML was malformed,
flooding the TUI. Now warns at most once per session with a suppression
notice.

Closes #3376

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:33:55 -07:00
Tibsfox
09acec6dce fix(gsd): normalize list inputs in complete-task + fix roadmap dep parsing
Two fixes:
1. gsd_complete_task now normalizes keyFiles/keyDecisions from strings
   (newline-delimited bullet lists) into arrays at the tool boundary,
   preventing type mismatch rejections on first call (#3361)
2. Legacy roadmap table parser now detects the dependency column from
   the header and only parses deps from that column or cells with
   explicit depends/deps keywords — prevents false deps from slice
   titles that mention other S-IDs (#3383, #3336)

Closes #3361
Closes #3383
Closes #3336

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:32:17 -07:00
Tibsfox
05130b41ad fix(gsd): open DB before status derivation + respect isolation:none in quick
Two fixes:
1. handleStatus now calls ensureDbOpen() before deriveState so cold
   sessions use DB-backed state instead of filesystem fallback (#3385)
2. /gsd quick now checks getIsolationMode() and skips branch creation
   when isolation is "none", consistent with milestone behavior (#3337)

Closes #3385
Closes #3337

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:30:05 -07:00
Tibsfox
34049b4a7e fix(gsd): add .bg-shell/ to baseline gitignore patterns
The bg-shell process manifest directory is ephemeral runtime state that
should never be committed, but ensureGitignore() was not including it.

Closes #3389
Closes #3388

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:27:06 -07:00
Tibsfox
771a729eb7 fix(tui): prevent Enter key infinite loop in interview notes mode
When "None of the above" was selected and the notes field was already
visible but empty, pressing Enter re-opened the notes field endlessly
because the guard only checked !notes (empty string is falsy).

Add !notesVisible guard so auto-open only triggers on the initial
selection, not when the user is confirming from an already-open notes
field.

Closes #3450
Closes #3449

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:25:52 -07:00
Tibsfox
f121d6f170 fix(provider): handle Enter key to initiate auth setup in provider manager
The provider manager let users navigate with arrow keys but pressing
Enter did nothing. Users had no way to set up authentication from within
the /provider command.

Adds selectConfirm (Enter) handler that routes to showLoginDialog for
the selected provider, with a hint in the status bar.

Closes #3579
Closes #3567

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:23:14 -07:00
Tibsfox
03328e04e8 fix(gsd): cap run-uat dispatch attempts to prevent infinite replay loop
When verification commands fail before writing an ASSESSMENT verdict,
checkNeedsRunUat keeps returning the same slice, causing infinite
re-dispatch until the provider throttles the session.

Adds a per-slice disk-persisted counter (survives crash/restart) that
caps run-uat at 3 attempts. After the cap, stops auto-mode with an
actionable message instead of looping.

Closes #3624

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:19:20 -07:00
Tibsfox
8fbb0cd1eb fix(mcp): use createRequire to resolve SDK wildcard subpath imports
Node ESM can't resolve wildcard export patterns without .js extension.
The MCP SDK's server/stdio and types subpaths use wildcard exports that
fail at runtime with ERR_MODULE_NOT_FOUND.

Use createRequire (CJS resolver) to resolve physical file paths before
passing to dynamic import(), since CJS auto-appends .js.

Closes #3603

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:17:26 -07:00
Tibsfox
a3d0b66836 fix(gsd): mark note captures as executed in executeTriageResolutions
Note captures (informational-only, no action needed) were never marked
as Executed because loadActionableCaptures excluded them and there was
no dedicated handler. They stayed in "resolved but not executed" limbo.

Now marks note captures as executed immediately since the triage
classification is their complete lifecycle.

Closes #3578

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:14:18 -07:00
Tibsfox
902e3be6d8 fix(gsd): validate main_branch preference exists before using in merge
mergeMilestoneToMain used prefs.main_branch without checking if the
branch exists in the repo. A stale preference (e.g. "master" when repo
uses "main") caused merge failure.

Now validates with nativeBranchExists before using the preference,
falling through to nativeDetectMainBranch if invalid.

Closes #3589

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:12:54 -07:00
Tibsfox
5cc2e24800 fix(gsd): handle deleted cwd in projectRoot to prevent ENOENT crash
process.cwd() throws ENOENT when the worktree directory was deleted
during a failed merge. Every /gsd command calls projectRoot(), causing
the entire extension to crash.

Now catches the ENOENT and falls back to HOME directory.

Closes #3598

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:12:48 -07:00
Tibsfox
16b61a7789 fix(gsd): skip current milestone in syncWorktreeStateBack to prevent merge conflicts
syncWorktreeStateBack copied all milestone directories including the one
being merged. This caused dirty-tree conflicts when mergeMilestoneToMain
ran because the files already existed from the copy-back.

Now skips the current milestoneId in the sync loop since its files are
already in the milestone branch being merged.

Closes #3641

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:11:14 -07:00
Tibsfox
dd527ce08e fix(gsd): add structuredQuestionsAvailable conditional to slice discuss
The slice discuss template hardcoded ask_user_questions references with
no fallback for providers that don't have the tool. The milestone
discuss template was already fixed with a conditional.

Now buildDiscussSlicePrompt accepts and passes structuredQuestionsAvailable,
and the prompt template uses the same conditional pattern as the milestone
discuss template.

Closes #3604

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:09:41 -07:00
Tibsfox
69eb369675 fix(gsd): restore full tool set after discuss flow scoping
dispatchWorkflow scoped tools down for discuss-* flows but never
restored them. The narrowed set persisted into subsequent dispatches,
making GSD execution tools permanently unavailable for the session.

Now saves the full tool list before scoping and restores it immediately
after sendMessage queues the turn. The LLM turn has already captured
the scoped set so it's unaffected.

Closes #3628

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:06:59 -07:00
Tibsfox
8f2e120a29 fix(gsd): tighten verifyExpectedArtifact to prevent rogue-write false positives
Three fixes to fail-closed when gsd_complete_task didn't actually run:

1. Legacy branch: require checked checkbox (- [x] **T01:) instead of
   accepting heading-style matches that only prove the task was planned
2. No plan file: return false instead of falling through
3. DB available but task row missing: return false instead of treating
   as verified — if the DB is up and the task isn't there, the
   completion tool never ran

Closes #3607

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:04:25 -07:00
Tibsfox
b9baf42a47 fix(gsd): add verification gate to complete-slice tool
complete-slice had no check on the provided verification/UAT content,
allowing agents to mark slices complete even when verification clearly
failed. The prompt told agents to always call the tool, but the tool
blindly accepted.

Now rejects completion when verification or UAT content contains
blocked/failed signals (status: blocked, verification_result: failed,
etc.), forcing agents to address blockers before advancing.

Closes #3580

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:02:53 -07:00
Jeremy McSpadden
bd574d412e Merge pull request #3666 from jeremymcs/fix/notification-overlay-backdrop
fix(gsd): notification overlay backdrop and truncation fixes
2026-04-06 21:01:17 -05:00
Tibsfox
08a79875bb fix(gsd): fix pre-execution-checks false positives from backticks and task.files
Three fixes:
1. Strip backtick wrapping in normalizeFilePath — LLM-generated paths
   like \`src/foo.ts\` resolve to nonexistent paths, causing false blocks
2. Exclude task.files from existence checks — it includes files the task
   will create, so they legitimately don't pre-exist
3. Lower minimum task count from 2 to 1 — single-task slices are valid
   per the planning prompt

Closes #3649
Closes #3626

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:00:47 -07:00
Tibsfox
bf0e3fb0e4 fix(gsd): stop renderAllProjections from overwriting authoritative PLAN.md
renderAllProjections called renderPlanProjection which overwrote the
complete PLAN.md (from markdown-renderer.js) with a simplified projection
missing Must-Haves, Verification, Files Likely Touched sections and
corrupting multi-line task descriptions.

Remove the plan projection call from renderAllProjections — the
authoritative renderer in plan-slice/replan-slice tools is the sole
writer. The renderIfMissing recovery path is preserved for when the
file is actually missing.

Closes #3651

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 18:59:00 -07:00
Tibsfox
432cb79097 fix(gsd): auto-checkout to main when isolation:none finds stale milestone branch
When switching from isolation:branch/worktree to isolation:none, HEAD
could remain on a milestone/<MID> branch from the prior session. All
subsequent auto-mode commits would silently land on the wrong branch.

Now auto-start checks for stale milestone branches when isolation:none
and auto-checks out to the integration branch (main/master).

Closes #3613

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 18:55:33 -07:00
Tibsfox
89fe6c3bdb fix(gsd): auto-remediate stale slice DB status when SUMMARY exists on disk
When complete-slice unit fails after writing SUMMARY.md but before
calling updateSliceStatus(), the DB stays out of sync. The post-unit
check previously reported this as a "rogue" artifact, leading to
infinite re-dispatch of the same complete-slice unit.

Now auto-remediates by calling updateSliceStatus() to sync the DB when
SUMMARY exists on disk but status != "complete". Falls back to rogue
detection if the DB update fails.

Closes #3633

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 18:51:49 -07:00
Tibsfox
745865f1c6 fix(gsd): open DB on demand in gsd_milestone_status for non-auto sessions
gsd_milestone_status checked isDbAvailable() but never called
ensureDbOpen(), making it always fail outside auto-mode sessions where
the DB is pre-opened during bootstrap.

Replace with ensureDbOpen() which safely opens existing DB files without
side effects when .gsd/ content exists.

Closes #3644

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 18:49:50 -07:00
Tibsfox
cbd705202b fix(gsd): detect phantom milestones from abandoned gsd_milestone_generate_id
gsd_milestone_generate_id inserts a DB row with status "queued" as a
side effect. If the milestone is never planned, this phantom row blocks
the state machine — isGhostMilestone returned false for any milestone
with a DB row, regardless of status.

Now isGhostMilestone treats a "queued" DB row with no disk artifacts
(CONTEXT, ROADMAP, SUMMARY) as a ghost, allowing the state machine to
skip phantom milestones.

Closes #3645

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 18:48:22 -07:00
Tibsfox
3e5bce5dbd fix(gsd): force re-validation when verdict is needs-remediation
When validation returns needs-remediation, remediation slices are added
and executed. But the state machine treated any terminal verdict as ready
for completing-milestone, while dispatch correctly blocked completion for
needs-remediation — creating a permanent deadlock.

Now all three derivation paths (deriveStateFromDb, _deriveStateImpl
registry loop, and _deriveStateImpl completion check) treat
needs-remediation as requiring re-validation, routing back to
validating-milestone instead of completing-milestone.

Closes #3596

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 18:46:42 -07:00
Tibsfox
236e9f1367 fix(gsd): exclude closed slices from findMissingSummaries check
Skip slices with status skipped/complete/done when checking for missing
SUMMARY files. Skipped slices never produce SUMMARYs by design, and
legacy-complete slices may lack them after worktree merge failures.
The DB status is authoritative — missing SUMMARY is a cosmetic gap,
not evidence the slice was incomplete.

Fixes #3620

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 18:35:59 -07:00
Tibsfox
7790808a29 fix(gsd): recover from stale lockfile after crash or SIGKILL
Add pre-flight stale lock cleanup before proper-lockfile acquisition:
if the .lock/ directory exists but no auto.lock metadata is present
(or the owning PID is dead), remove it proactively instead of waiting
for the 30-min stale window. Also improve the error message when
recovery fails to include the rm command for manual cleanup.

Fixes #3218

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 18:33:27 -07:00
Tibsfox
7e9434dec1 fix(gsd): add createdAt timestamp and 30s age guard to staleness check
Prevent race where a freshly-set pending entry (before LLM writes
artifacts) could be falsely detected as stale. Only clear entries
older than 30 seconds with no manifest or CONTEXT.md on disk.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 18:30:29 -07:00
Tibsfox
af2bd4d45f fix(gsd): clear stale pendingAutoStart after /clear interrupts discussion
When the pending auto-start guard fires, check if the discussion is
actually still in progress by verifying the discussion manifest or
milestone context exists on disk. If neither exists, the entry is stale
from an interrupted session — clear it and allow re-entry.

Fixes #3274

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 18:27:45 -07:00
Tibsfox
f93123cdbb fix(gsd): suppress misleading warnings for expected ENOENT/EISDIR conditions
Skip ENOENT warnings in clearProjectRootStateFiles and untracked file
cleanup since missing files are expected. Check if .git is a directory
before attempting readFileSync in resolveGitDir to avoid EISDIR warning
in normal (non-worktree) repos.

Fixes #3597

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 18:23:54 -07:00
Tibsfox
0b6dfd0bbf fix(gsd): extract real error from message content when errorMessage is useless
When errorMessage is uninformative (e.g. "success", "ok"), fall back
to the assistant message text content for display while keeping
rawErrorMsg for classification to avoid prose false-positives.

Fixes #3588

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 18:22:02 -07:00
Tibsfox
eaeced4774 fix(gsd): extract real error from message content when errorMessage is useless
When errorMessage is uninformative (e.g. "success", "ok", "error"),
fall back to the assistant message text content to surface the real
provider error like "Invalid API key · Please run /login".

Fixes #3588

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 18:20:11 -07:00
Tibsfox
c159844b05 fix(gsd): show accurate pause message for queued-user-message skip
Distinguish between malformed-JSON pauses and queued-user-message
pauses in the notification so operators see the correct root cause.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 18:18:44 -07:00
Tibsfox
1859cb0d1a fix(gsd): treat queued-user-message skip as non-retryable interruption
Add isQueuedUserMessageSkip() predicate and extend recordToolInvocationError
to catch "Skipped due to queued user message." so auto-mode pauses instead
of retrying the same unit until the provider aborts with 3 consecutive
validation failures.

Fixes #3595

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 18:16:32 -07:00
Tibsfox
c2c5f80f79 fix(gsd): recognize "Not provided." default in isVerificationNotApplicable
Strip trailing punctuation before matching and add "provided" to the
alternation so the plan-milestone default value no longer deadlocks
completing-milestone dispatch. Also change plan-milestone verification
defaults from "Not provided." to empty string to prevent recurrence.
Update JSDoc comments to reflect new defaults.

Fixes #3634

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 18:13:25 -07:00
Iouri Goussev
4b07f24d86 fix(gsd): discoverManifests skips symlinked extension directories
Dirent.isDirectory() returns false for symbolic links, so extensions
installed as directory symlinks under ~/.gsd/agent/extensions/ were
invisible to all management commands (list, enable, disable, info).

Apply the same guard already used in loader.ts discoverExtensionsInDir:
  entry.isDirectory() || entry.isSymbolicLink()

Closes igouss/gsd-2#20
2026-04-06 21:13:08 -04:00
Tibsfox
c138cca078 fix(gsd): recognize "Not provided." default in isVerificationNotApplicable
Strip trailing punctuation before matching and add "provided" to the
alternation so the plan-milestone default value no longer deadlocks
completing-milestone dispatch. Also change plan-milestone verification
defaults from "Not provided." to empty string to prevent recurrence.

Fixes #3634

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 18:12:06 -07:00
Jeremy
af158235eb fix(gsd): remove background color from backdrop, fix message truncation
Backdrop was painting empty lines with dark gray background (48;5;233),
making the entire screen go black. Now uses dim + gray foreground only.

Message truncation now measures actual prefix width with visibleWidth()
instead of hardcoded 20-char estimate, and uses truncateToWidth() for
proper Unicode handling.
2026-04-06 20:11:07 -05:00
Tibsfox
b1d9798e30 fix(gsd): reconcile plan-file tasks into DB when planner skips persistence (#3600)
When the planning agent writes S##-PLAN.md with task entries but never
calls the gsd_plan_slice persistence tool, the DB has zero task rows
even though the plan file on disk contains valid tasks. This causes
deriveState to return phase='planning' forever — the auto-mode
dispatcher re-dispatches plan-slice in an infinite loop.

Add a reconciliation step in deriveStateFromDb: when the DB returns zero
tasks but the plan file exists and contains parsed tasks, import them
into the DB so the state machine can advance past planning into
execution. This mirrors the existing #2514 reconciliation pattern for
stale task status.

Fixes #3600

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 17:51:33 -07:00
Tibsfox
77788a1b7e fix(gsd): classify plain connection-error as transient
Fixes #3594 — CONNECTION_RE required specific suffixes after connection, so plain Connection error fell through to unknown causing indefinite auto-mode pause.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 17:51:19 -07:00
Tibsfox
e1801f967f fix(gsd): use isClosedStatus() in dispatch guard instead of raw complete check
Replaces `r.status === "complete"` with `isClosedStatus(r.status)` in
dispatch-guard.ts so slices completed via the reconciliation replay path
(which writes "done") or skipped slices are correctly recognized as
closed. This was causing auto-mode to block on dependencies that were
actually complete.

Fixes #3601

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 17:50:02 -07:00
Jeremy
41d5189c4c fix(gsd): restore consistent overlay height to prevent ghost artifacts
Differential renderer can't clear old overlay positions when height
changes between filter cycles. Pad to maxVisibleRows so the overlay
stays the same size regardless of filter state.
2026-04-06 19:31:32 -05:00
Jeremy McSpadden
b4c6229360 Merge pull request #3646 from jeremymcs/fix/notification-overlay-backdrop
fix(gsd): notification overlay backdrop and sizing
2026-04-06 19:09:22 -05:00
Jeremy
2c91b8c6d8 test(tui): add test for 256-color backdrop codes 2026-04-06 18:57:02 -05:00