feat(env): supporter-binary resolver — explicit override → PATH → well-known (T-495)

SupporterBinaries resolves claude/d2/etc. to absolute paths (D-104): an
explicit override map first, then the login-shell/process PATH, then the
well-known bin dirs incl. Homebrew-on-Linux — the dir the standard PATH
expansion omits and a .bashrc-only brew shellenv misses (the D-104 gap).
detect() probes those to seed the override map (pinned, not re-probed each
launch); isStalePin flags a moved tool. Pure Dart, dart test (11 cases).
Settings storage + first-run detect wire on next.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-28 23:03:12 +02:00
co-authored by Claude Opus 4.8
parent b1ec4afe15
commit dab0b3194e
4 changed files with 213 additions and 0 deletions
+25
View File
@@ -8827,3 +8827,28 @@ RESCOPED (D-103, 2026-06-28): the primitive layer is now SVG and the SVG rendere
PROGRESS (2026-06-28): drawing-card core built bottom-up + tested (24 cases across dart/flutter test): DrawingCardDoc envelope + parser (lib/src/draw/draw_doc.dart); template dispatch (draw_dispatch.dart resolveDrawingSvg + DrawingRegistry, primitive svg/svgPath now, handlers for d2/icon/compare/image plug in); DrawingCard widget (lib/widgets/src/draw/ SvgView + themed caption, display-only); and the CLI command (draw_commands.dart reads+parses the doc, lowers to SVG, publishes {svg,label,description} on the ''draw'' MessageBus channel). REMAINING: (1) the Claude-extension subscriber that consumes the ''draw'' channel buildSvgDocument(svg) injects a DrawingCard message into the primary session (mirror image.show''s consumer); (2) per-object data-* overlay (captions/lightbox anchored to SVG elements) advanced follow-on.
EXTENSION WIRE DONE + PUSHED (2026-06-28): item (1) complete DrawingMessage + the Claude-extension subscriber on the draw channel + the conversation renderer + boot registration; clide draw --file doc.json renders end-to-end (commit 2beb4b9, pushed in 75f378ff). REMAINING (this session): the per-object data-* overlay — data-label / data-description / data-lightbox anchored to individual SVG elements, the last piece of T-318 scope.', NULL, '2026-06-28 20:25:50', '2026-06-28 20:25:50.683', '2026-06-28 20:25:50.683', NULL, 'e8481d8539f90b8d5fd2dddb1932e2a0', 2) ON CONFLICT(hash) DO NOTHING;
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ERREMEEF26KKHGNZBWW64', 'description', 'Foundational build for the unified drawing card (epic T-317, decision D-91). A clide-owned canvas (CustomPaint) that renders from a JSON document: a PRIMITIVE scene-graph layer (rect/line/text/glyph/image at coordinates) plus a TEMPLATE-dispatch layer that maps a named component in the JSON to a predefined renderer. Templates lower onto the same primitive scene (hybrid model). Per drawn object, an optional label + description widget renders beneath it, only when those fields are present in the JSON. Display-only (D-78) — no inline selection. Driven via the clide CLI (D-6 parity), consuming the JSON input plumbing (T-315 / --file); mirror image.show''s Flutter-free handler + MessageBus publish + Claude-extension injection pattern. THIS ticket = the engine, the JSON schema, the primitive renderer, the dispatch mechanism, and the shared per-object label/description widget. Individual templates (image, icon, compare, svg, graph) are separate children. Acceptance: a JSON doc with raw primitives draws; a JSON doc naming a template dispatches to it; an object with label/description renders the caption widget; unknown template/primitive fails with a clear userError.
SCHEMA DRAFTED (2026-06-28): docs/design/drawing-card-schema.md declarative JSON scene-graph (document envelope, primitive types rect/line/text/glyph/image, template envelope, shared label/description, arbitrary-hex color, CLI ''clide draw --file'', error contract). Refined from the T-317 wireframe set.
MODEL CLARIFICATION (user): we build clide''s OWN native Flutter CustomPaint interpreting a declarative scene-graph document. We do NOT port the HTML Canvas 2D API ''HTML canvas'' in D-91 is only the mental model (a general drawing surface, chosen to reject Obsidian''s .canvas schema), not an API to implement. The declarative model is closer to SVG/a retained scene-graph than to canvas''s imperative 2D context.
RESCOPED (D-103, 2026-06-28): the primitive layer is now SVG and the SVG renderer (T-320) is the engine so T-318 is NO LONGER a primitive renderer. T-318 = the document envelope ({template? | svg/svgPath}, card metadata), the template DISPATCH, and the clide FLUTTER OVERLAY: per-object label/description caption widgets + lightbox affordance, anchored to SVG elements via data-label / data-description / data-lightbox. Now blocked by T-320 (engine first). Schema: docs/design/drawing-card-schema.md.
PROGRESS (2026-06-28): drawing-card core built bottom-up + tested (24 cases across dart/flutter test): DrawingCardDoc envelope + parser (lib/src/draw/draw_doc.dart); template dispatch (draw_dispatch.dart resolveDrawingSvg + DrawingRegistry, primitive svg/svgPath now, handlers for d2/icon/compare/image plug in); DrawingCard widget (lib/widgets/src/draw/ SvgView + themed caption, display-only); and the CLI command (draw_commands.dart reads+parses the doc, lowers to SVG, publishes {svg,label,description} on the ''draw'' MessageBus channel). REMAINING: (1) the Claude-extension subscriber that consumes the ''draw'' channel buildSvgDocument(svg) injects a DrawingCard message into the primary session (mirror image.show''s consumer); (2) per-object data-* overlay (captions/lightbox anchored to SVG elements) advanced follow-on.
EXTENSION WIRE DONE + PUSHED (2026-06-28): item (1) complete DrawingMessage + the Claude-extension subscriber on the draw channel + the conversation renderer + boot registration; clide draw --file doc.json renders end-to-end (commit 2beb4b9, pushed in 75f378ff). REMAINING (this session): the per-object data-* overlay — data-label / data-description / data-lightbox anchored to individual SVG elements, the last piece of T-318 scope.', 'Foundational build for the unified drawing card (epic T-317, decision D-91). A clide-owned canvas (CustomPaint) that renders from a JSON document: a PRIMITIVE scene-graph layer (rect/line/text/glyph/image at coordinates) plus a TEMPLATE-dispatch layer that maps a named component in the JSON to a predefined renderer. Templates lower onto the same primitive scene (hybrid model). Per drawn object, an optional label + description widget renders beneath it, only when those fields are present in the JSON. Display-only (D-78) — no inline selection. Driven via the clide CLI (D-6 parity), consuming the JSON input plumbing (T-315 / --file); mirror image.show''s Flutter-free handler + MessageBus publish + Claude-extension injection pattern. THIS ticket = the engine, the JSON schema, the primitive renderer, the dispatch mechanism, and the shared per-object label/description widget. Individual templates (image, icon, compare, svg, graph) are separate children. Acceptance: a JSON doc with raw primitives draws; a JSON doc naming a template dispatches to it; an object with label/description renders the caption widget; unknown template/primitive fails with a clear userError.
SCHEMA DRAFTED (2026-06-28): docs/design/drawing-card-schema.md declarative JSON scene-graph (document envelope, primitive types rect/line/text/glyph/image, template envelope, shared label/description, arbitrary-hex color, CLI ''clide draw --file'', error contract). Refined from the T-317 wireframe set.
MODEL CLARIFICATION (user): we build clide''s OWN native Flutter CustomPaint interpreting a declarative scene-graph document. We do NOT port the HTML Canvas 2D API ''HTML canvas'' in D-91 is only the mental model (a general drawing surface, chosen to reject Obsidian''s .canvas schema), not an API to implement. The declarative model is closer to SVG/a retained scene-graph than to canvas''s imperative 2D context.
RESCOPED (D-103, 2026-06-28): the primitive layer is now SVG and the SVG renderer (T-320) is the engine so T-318 is NO LONGER a primitive renderer. T-318 = the document envelope ({template? | svg/svgPath}, card metadata), the template DISPATCH, and the clide FLUTTER OVERLAY: per-object label/description caption widgets + lightbox affordance, anchored to SVG elements via data-label / data-description / data-lightbox. Now blocked by T-320 (engine first). Schema: docs/design/drawing-card-schema.md.
PROGRESS (2026-06-28): drawing-card core built bottom-up + tested (24 cases across dart/flutter test): DrawingCardDoc envelope + parser (lib/src/draw/draw_doc.dart); template dispatch (draw_dispatch.dart resolveDrawingSvg + DrawingRegistry, primitive svg/svgPath now, handlers for d2/icon/compare/image plug in); DrawingCard widget (lib/widgets/src/draw/ SvgView + themed caption, display-only); and the CLI command (draw_commands.dart reads+parses the doc, lowers to SVG, publishes {svg,label,description} on the ''draw'' MessageBus channel). REMAINING: (1) the Claude-extension subscriber that consumes the ''draw'' channel buildSvgDocument(svg) injects a DrawingCard message into the primary session (mirror image.show''s consumer); (2) per-object data-* overlay (captions/lightbox anchored to SVG elements) advanced follow-on.
EXTENSION WIRE DONE + PUSHED (2026-06-28): item (1) complete DrawingMessage + the Claude-extension subscriber on the draw channel + the conversation renderer + boot registration; clide draw --file doc.json renders end-to-end (commit 2beb4b9, pushed in 75f378ff). REMAINING (this session): the per-object data-* overlay — data-label / data-description / data-lightbox anchored to individual SVG elements, the last piece of T-318 scope.
COMPLETE (2026-06-28): per-object overlay done captions (data-label/data-description) + lightbox (data-lightbox tap-to-zoom), positioned via the shared svgViewportFit so they track the painted SVG. Full T-318 scope built + tested: document envelope (draw_doc), template dispatch (draw_dispatch), DrawingCard widget, the draw CLI command (draw_commands), the extension wire (DrawingMessage + subscriber + renderer + boot registration), and the per-object overlay. ~40 tests across dart + flutter test. All acceptance met (raw SVG draws; a template dispatches; objects render captions; unknown template/primitive userError). Templates d2/icon/compare/image are separate children under T-317; T-494 (d2) is next, gated on T-495.', NULL, '2026-06-28 20:40:54', '2026-06-28 20:40:54.751', '2026-06-28 20:40:54.751', NULL, '3c1694be81a3d05e22c8c5a2221e99fd', 2) ON CONFLICT(hash) DO NOTHING;
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ERREMEEF26KKHGNZBWW64', 'status', 'in_progress', 'done', NULL, '2026-06-28 20:40:54', '2026-06-28 20:40:54.785', '2026-06-28 20:40:54.785', NULL, '389acc78ce89d7225e268e20f3822fee', 2) ON CONFLICT(hash) DO NOTHING;
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGYPJ6FTEPP4JK3D7D01ZSMM', 'status', 'backlog', 'in_progress', NULL, '2026-06-28 21:00:18', '2026-06-28 21:00:18.364', '2026-06-28 21:00:18.364', NULL, '00fa58dcedc18f6ce827b5a0ef6ad928', 2) ON CONFLICT(hash) DO NOTHING;
+33
View File
@@ -10614,3 +10614,36 @@ RESCOPED (D-103, 2026-06-28): the primitive layer is now SVG and the SVG rendere
PROGRESS (2026-06-28): drawing-card core built bottom-up + tested (24 cases across dart/flutter test): DrawingCardDoc envelope + parser (lib/src/draw/draw_doc.dart); template dispatch (draw_dispatch.dart resolveDrawingSvg + DrawingRegistry, primitive svg/svgPath now, handlers for d2/icon/compare/image plug in); DrawingCard widget (lib/widgets/src/draw/ SvgView + themed caption, display-only); and the CLI command (draw_commands.dart reads+parses the doc, lowers to SVG, publishes {svg,label,description} on the ''draw'' MessageBus channel). REMAINING: (1) the Claude-extension subscriber that consumes the ''draw'' channel buildSvgDocument(svg) injects a DrawingCard message into the primary session (mirror image.show''s consumer); (2) per-object data-* overlay (captions/lightbox anchored to SVG elements) advanced follow-on.
EXTENSION WIRE DONE + PUSHED (2026-06-28): item (1) complete DrawingMessage + the Claude-extension subscriber on the draw channel + the conversation renderer + boot registration; clide draw --file doc.json renders end-to-end (commit 2beb4b9, pushed in 75f378ff). REMAINING (this session): the per-object data-* overlay — data-label / data-description / data-lightbox anchored to individual SVG elements, the last piece of T-318 scope.', 'in_progress', 'medium', NULL, NULL, NULL, '2026-06-10 11:11:40', '2026-06-28 20:25:50.683', NULL, 'a5a8e71c0e31375e52004b37b181b484', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ERREMEEF26KKHGNZBWW64', 'story', '06FB2EDCBYRBDSV9V1PJ1KE3CM', 'Drawing card core: canvas engine + JSON schema + template dispatch', 'Foundational build for the unified drawing card (epic T-317, decision D-91). A clide-owned canvas (CustomPaint) that renders from a JSON document: a PRIMITIVE scene-graph layer (rect/line/text/glyph/image at coordinates) plus a TEMPLATE-dispatch layer that maps a named component in the JSON to a predefined renderer. Templates lower onto the same primitive scene (hybrid model). Per drawn object, an optional label + description widget renders beneath it, only when those fields are present in the JSON. Display-only (D-78) — no inline selection. Driven via the clide CLI (D-6 parity), consuming the JSON input plumbing (T-315 / --file); mirror image.show''s Flutter-free handler + MessageBus publish + Claude-extension injection pattern. THIS ticket = the engine, the JSON schema, the primitive renderer, the dispatch mechanism, and the shared per-object label/description widget. Individual templates (image, icon, compare, svg, graph) are separate children. Acceptance: a JSON doc with raw primitives draws; a JSON doc naming a template dispatches to it; an object with label/description renders the caption widget; unknown template/primitive fails with a clear userError.
SCHEMA DRAFTED (2026-06-28): docs/design/drawing-card-schema.md declarative JSON scene-graph (document envelope, primitive types rect/line/text/glyph/image, template envelope, shared label/description, arbitrary-hex color, CLI ''clide draw --file'', error contract). Refined from the T-317 wireframe set.
MODEL CLARIFICATION (user): we build clide''s OWN native Flutter CustomPaint interpreting a declarative scene-graph document. We do NOT port the HTML Canvas 2D API ''HTML canvas'' in D-91 is only the mental model (a general drawing surface, chosen to reject Obsidian''s .canvas schema), not an API to implement. The declarative model is closer to SVG/a retained scene-graph than to canvas''s imperative 2D context.
RESCOPED (D-103, 2026-06-28): the primitive layer is now SVG and the SVG renderer (T-320) is the engine so T-318 is NO LONGER a primitive renderer. T-318 = the document envelope ({template? | svg/svgPath}, card metadata), the template DISPATCH, and the clide FLUTTER OVERLAY: per-object label/description caption widgets + lightbox affordance, anchored to SVG elements via data-label / data-description / data-lightbox. Now blocked by T-320 (engine first). Schema: docs/design/drawing-card-schema.md.
PROGRESS (2026-06-28): drawing-card core built bottom-up + tested (24 cases across dart/flutter test): DrawingCardDoc envelope + parser (lib/src/draw/draw_doc.dart); template dispatch (draw_dispatch.dart resolveDrawingSvg + DrawingRegistry, primitive svg/svgPath now, handlers for d2/icon/compare/image plug in); DrawingCard widget (lib/widgets/src/draw/ SvgView + themed caption, display-only); and the CLI command (draw_commands.dart reads+parses the doc, lowers to SVG, publishes {svg,label,description} on the ''draw'' MessageBus channel). REMAINING: (1) the Claude-extension subscriber that consumes the ''draw'' channel buildSvgDocument(svg) injects a DrawingCard message into the primary session (mirror image.show''s consumer); (2) per-object data-* overlay (captions/lightbox anchored to SVG elements) advanced follow-on.
EXTENSION WIRE DONE + PUSHED (2026-06-28): item (1) complete DrawingMessage + the Claude-extension subscriber on the draw channel + the conversation renderer + boot registration; clide draw --file doc.json renders end-to-end (commit 2beb4b9, pushed in 75f378ff). REMAINING (this session): the per-object data-* overlay — data-label / data-description / data-lightbox anchored to individual SVG elements, the last piece of T-318 scope.
COMPLETE (2026-06-28): per-object overlay done captions (data-label/data-description) + lightbox (data-lightbox tap-to-zoom), positioned via the shared svgViewportFit so they track the painted SVG. Full T-318 scope built + tested: document envelope (draw_doc), template dispatch (draw_dispatch), DrawingCard widget, the draw CLI command (draw_commands), the extension wire (DrawingMessage + subscriber + renderer + boot registration), and the per-object overlay. ~40 tests across dart + flutter test. All acceptance met (raw SVG draws; a template dispatches; objects render captions; unknown template/primitive userError). Templates d2/icon/compare/image are separate children under T-317; T-494 (d2) is next, gated on T-495.', 'in_progress', 'medium', NULL, NULL, NULL, '2026-06-10 11:11:40', '2026-06-28 20:40:54.751', NULL, 'aad56f10912aec6041ae4e4a749196cb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2ERREMEEF26KKHGNZBWW64', 'story', '06FB2EDCBYRBDSV9V1PJ1KE3CM', 'Drawing card core: canvas engine + JSON schema + template dispatch', 'Foundational build for the unified drawing card (epic T-317, decision D-91). A clide-owned canvas (CustomPaint) that renders from a JSON document: a PRIMITIVE scene-graph layer (rect/line/text/glyph/image at coordinates) plus a TEMPLATE-dispatch layer that maps a named component in the JSON to a predefined renderer. Templates lower onto the same primitive scene (hybrid model). Per drawn object, an optional label + description widget renders beneath it, only when those fields are present in the JSON. Display-only (D-78) — no inline selection. Driven via the clide CLI (D-6 parity), consuming the JSON input plumbing (T-315 / --file); mirror image.show''s Flutter-free handler + MessageBus publish + Claude-extension injection pattern. THIS ticket = the engine, the JSON schema, the primitive renderer, the dispatch mechanism, and the shared per-object label/description widget. Individual templates (image, icon, compare, svg, graph) are separate children. Acceptance: a JSON doc with raw primitives draws; a JSON doc naming a template dispatches to it; an object with label/description renders the caption widget; unknown template/primitive fails with a clear userError.
SCHEMA DRAFTED (2026-06-28): docs/design/drawing-card-schema.md declarative JSON scene-graph (document envelope, primitive types rect/line/text/glyph/image, template envelope, shared label/description, arbitrary-hex color, CLI ''clide draw --file'', error contract). Refined from the T-317 wireframe set.
MODEL CLARIFICATION (user): we build clide''s OWN native Flutter CustomPaint interpreting a declarative scene-graph document. We do NOT port the HTML Canvas 2D API ''HTML canvas'' in D-91 is only the mental model (a general drawing surface, chosen to reject Obsidian''s .canvas schema), not an API to implement. The declarative model is closer to SVG/a retained scene-graph than to canvas''s imperative 2D context.
RESCOPED (D-103, 2026-06-28): the primitive layer is now SVG and the SVG renderer (T-320) is the engine so T-318 is NO LONGER a primitive renderer. T-318 = the document envelope ({template? | svg/svgPath}, card metadata), the template DISPATCH, and the clide FLUTTER OVERLAY: per-object label/description caption widgets + lightbox affordance, anchored to SVG elements via data-label / data-description / data-lightbox. Now blocked by T-320 (engine first). Schema: docs/design/drawing-card-schema.md.
PROGRESS (2026-06-28): drawing-card core built bottom-up + tested (24 cases across dart/flutter test): DrawingCardDoc envelope + parser (lib/src/draw/draw_doc.dart); template dispatch (draw_dispatch.dart resolveDrawingSvg + DrawingRegistry, primitive svg/svgPath now, handlers for d2/icon/compare/image plug in); DrawingCard widget (lib/widgets/src/draw/ SvgView + themed caption, display-only); and the CLI command (draw_commands.dart reads+parses the doc, lowers to SVG, publishes {svg,label,description} on the ''draw'' MessageBus channel). REMAINING: (1) the Claude-extension subscriber that consumes the ''draw'' channel buildSvgDocument(svg) injects a DrawingCard message into the primary session (mirror image.show''s consumer); (2) per-object data-* overlay (captions/lightbox anchored to SVG elements) advanced follow-on.
EXTENSION WIRE DONE + PUSHED (2026-06-28): item (1) complete DrawingMessage + the Claude-extension subscriber on the draw channel + the conversation renderer + boot registration; clide draw --file doc.json renders end-to-end (commit 2beb4b9, pushed in 75f378ff). REMAINING (this session): the per-object data-* overlay — data-label / data-description / data-lightbox anchored to individual SVG elements, the last piece of T-318 scope.
COMPLETE (2026-06-28): per-object overlay done captions (data-label/data-description) + lightbox (data-lightbox tap-to-zoom), positioned via the shared svgViewportFit so they track the painted SVG. Full T-318 scope built + tested: document envelope (draw_doc), template dispatch (draw_dispatch), DrawingCard widget, the draw CLI command (draw_commands), the extension wire (DrawingMessage + subscriber + renderer + boot registration), and the per-object overlay. ~40 tests across dart + flutter test. All acceptance met (raw SVG draws; a template dispatches; objects render captions; unknown template/primitive userError). Templates d2/icon/compare/image are separate children under T-317; T-494 (d2) is next, gated on T-495.', 'done', 'medium', NULL, NULL, NULL, '2026-06-10 11:11:40', '2026-06-28 20:40:54.785', NULL, '61c3c704be2b8282530d1459ec1655f6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGYPJ6FTEPP4JK3D7D01ZSMM', 'task', NULL, 'Supporter-binary path resolution: explicit user-scope overrides + first-run auto-detect', 'Implement D-104. clide resolves external supporter binaries (claude, d2, future supporter tools) via an explicit user-scope ''tools:'' map (name → absolute path), consulted FIRST.
Resolution order: (1) explicit settings path use it; honest error + fallback-with-warning if missing/non-exec. (2) bundled/pinned (pql D-58, git D-59). (3) login-shell PATH (T-439). (4) bare PATH.
First run: auto-detect each tool ONCE probe the login-shell PATH + well-known dirs (~/.local/bin, /usr/local/bin, /opt/homebrew, /home/linuxbrew/.linuxbrew/bin) and WRITE the discovered absolute paths into the map (pinned, not re-probed each launch). Provide a re-detect action.
Storage: user-scope SettingsStore keyed by machine (D-93) never committed. Surface in the Config tab (T-414) + flag unresolved tools in the Problems panel (echoes D-58''s soft floor). Generalizes D-58''s CLIDE_PQL_BIN override to all supporter tools. First consumer: the d2 template (T-494).', 'in_progress', 'medium', NULL, NULL, 'D-104', '2026-06-28 17:50:02.366', '2026-06-28 21:00:18.364', NULL, 'de1818996b3226c6df2516d1aff9cfad', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);