Commit Graph
1001 Commits
Author SHA1 Message Date
Tuan-TC 4d9c286aae fix(openai): normalize Mistral tool call IDs (#669)
Fix Mistral tool call ID formatting on the outbound OpenAI-compatible payload.

For provider `mistral` only, normalizes both `tool_calls[].id` and `tool`
message `tool_call_id` to a 9-character hex string (SHA-256 based) before
sending the request. Other providers keep the existing `truncateToolCallID`
behavior unchanged.

- Hash full ID via SHA-256 to avoid prefix-dependent collisions
- Detect Mistral via both provider name and providerType (DB-loaded support)
- Add collision uniqueness and DB provider detection tests
2026-04-04 07:26:04 +07:00
Duc Nguyen 2b1180f59d fix(http): allow localhost URLs for local provider types (Ollama, Claude CLI) (#674)
SSRF validation in validateProviderURL() blocked all localhost/loopback
addresses, preventing local providers like Ollama from being configured
with http://localhost:11434/v1. Introduce localProviderTypes map to skip
SSRF checks for inherently local provider types (ollama, claude_cli, acp).

Closes #673
2026-04-04 07:06:34 +07:00
viettranx bed309a364 fix(ui,kg): fix graph canvas sizing on agent selection
ForceGraph2D was rendering at wrong default dimensions when the
KG page first loaded after selecting an agent. Root cause: early
return for empty state removed the container div from DOM, so
useLayoutEffect couldn't read dimensions on first mount.

Fix: always render container div (flex-1 gives it height from
parent), show empty state inside it. Use useLayoutEffect for
synchronous initial measurement + ResizeObserver for ongoing
changes. Gate ForceGraph2D render behind `ready` flag.

Also extracted memory-documents-table from memory-page (gap closure).
2026-04-03 23:42:43 +07:00
viettranx 4b6538839f refactor(ui): gap closure Phase 2 — extract memory-documents-table
Split memory-page.tsx (314 → 244) by extracting the documents table
into memory-documents-table.tsx.

Remaining 14 files >300 lines assessed — no clean extraction
boundaries found (dense forms, tab routers, DnD contexts).
2026-04-03 23:32:16 +07:00
viettranx f6bca7003a refactor(ui): gap closure — extract form field groups from bloated RHF dialogs
Split 4 RHF form dialogs that grew after Phase 3 Zod refactoring:
- channel-instance-form-dialog: 445 → 292 (+ form-step 196)
- cli-credential-form-dialog: 417 → 277 (+ binary-fields 151, scope-fields 72)
- mcp-form-dialog: 359 → 209 (+ connection-fields 100, settings-fields 95)
- agent-create-dialog: 351 → 165 (+ identity-model-fields 166, description 90)

Skipped: heartbeat-config (already decomposed), provider-form (no 50+ line boundary).

Files >300 lines: 20 → 16. Build passes.
2026-04-03 23:26:26 +07:00
viettranx e962a8ec7a refactor(ui): Phase 5 — Zustand persist middleware + constants split
Stores:
- use-auth-store: manual localStorage → persist() with partialize
  (token, userId, senderID)
- use-ui-store: manual localStorage → persist() with partialize
  (theme, language, timezone, sidebarCollapsed)
- use-team-event-store: manual persist helpers → persist() with
  partialize (last 20 events), onRehydrateStorage seeds counter

Constants:
- Split lib/constants.ts (144 lines) into:
  - lib/routes.ts (46 lines) — route paths
  - lib/timezone-utils.ts (74 lines) — IANA timezone data
  - lib/constants.ts (30 lines) — barrel re-export

ForwardRef: skipped — all UI primitives already use React 19
ref-as-prop pattern.

No behavior changes. Build passes.
2026-04-03 23:08:34 +07:00
viettranx 2ed810b854 refactor(ui): Phase 4 complete — provider-pool adapter eliminates DRY violation
Create adapters/provider-pool.adapter.ts with 6 pure functions that
replace duplicated CodexPoolEntry construction in 3 files:
- provider-overview.tsx (inline poolEntries useMemo)
- agent-codex-pool-page.tsx (35-line buildEntries callback)
- provider-pool-activity-section.tsx (30-line entries useMemo)

Also centralizes resolveProviderAvailability (was copied in 3 places).
2026-04-03 22:59:25 +07:00
viettranx 1313f02cf4 refactor(ui): Phase 4 — adapter layer for data transformations
Create src/adapters/ with 3 adapter files:
- kg-graph.adapter.ts: KGEntity/KGRelation → GraphData (nodes, links,
  degree computation, color mapping, entity limiter)
- chat-message.adapter.ts: moved from chat/hooks/chat-message-transformer.ts
- trace.adapter.ts: buildSpanTree extracted from trace-span-tree-node

Skipped team-task (already in board-utils) and provider-pool (<10 lines,
single call site).

Inline transforms in kg-graph-view.tsx and trace-detail-dialog.tsx
replaced with adapter calls. No behavior changes.
2026-04-03 22:54:40 +07:00
viettranx 7e62623123 refactor(ui): Phase 3 complete — 5 more forms to RHF+Zod (11 total)
Add 5 more Zod schemas: mcp, mcp-credentials, memory,
cron-advanced, team-settings.

Refactor 5 more form dialogs:
- mcp-form-dialog: 15 → 4 useState
- mcp-user-credentials-dialog: 11 → 7 useState
- memory-create-dialog: 10 → 2 useState
- cron-advanced-dialog: 10 → 2 useState
- team-settings-tab: 22 → 1 useState

agent-advanced-dialog skipped (complex typed objects, no field
validation needed — RHF adds indirection with zero benefit).

Total Phase 3: 11 schemas, 11 forms refactored, ~120 useState removed.
2026-04-03 22:50:04 +07:00
viettranx 7a6a944622 refactor(ui): Phase 3 — Zod schemas + React Hook Form for 6 form dialogs
Add zod@4.3.6, react-hook-form@7.72.1, @hookform/resolvers@5.2.2.

Create src/schemas/ with 6 validation schemas:
- agent.schema.ts, provider.schema.ts, cron.schema.ts
- channel.schema.ts, credential.schema.ts, heartbeat.schema.ts

Refactor 6 form dialogs from manual useState chains to RHF + Zod:
- agent-create-dialog: 12 → 2 useState
- provider-form-dialog: 8 → 0 useState
- cron-form-dialog: 7 → 0 useState
- channel-instance-form-dialog: 11 → 6 useState
- cli-credential-form-dialog: 18 → 9 useState
- heartbeat-config-dialog: 19 → 4 useState

Total: 75 useState removed, replaced with type-safe form state.
Async side-effects kept as hooks. No behavior changes.
2026-04-03 22:35:06 +07:00
viettranx 1187146626 refactor(ui): modularize web UI components — Phase 1 & 2
Split 19 large files (300-874 lines) into 37 focused modules.
All files target ≤200 lines for optimal maintainability.

Phase 1 (>400 lines): provider-overview, use-chat-messages,
system-settings-modal, trace-detail-dialog, media-provider-chain-form,
cli-credential-form-dialog, team-settings-tab, skills-page,
heartbeat-config-dialog, mcp-grants-dialog.

Phase 2 (200-400 lines): builtin-tools-page, quota-section,
file-tree, rich-content, session-detail-page, ai-defaults-section,
markdown-renderer, file-viewers, channel-managers-tab.

Also fixed DRY violations: exported shared types (VerifyResult,
ReasoningCapability, ManualEnvEntry), resolved circular import
in media-provider-chain files.

No behavior changes — pure refactoring. Build passes.
2026-04-03 22:12:10 +07:00
viettranx b2fda38e90 feat(kg): node limit selector, remove auto-zoom, graph as default view
- Add node limit selector (100/200/300/500) in graph stats bar
- Graph API fetches 500 (server max), frontend clips by degree centrality
- Remove auto zoom-to-fit on engine stop (was overriding user zoom/pan)
- Keep manual zoom-to-fit button in stats bar
- Default view mode changed from table to graph
2026-04-03 20:09:24 +07:00
viettranx e00bfbc887 feat(kg): increase graph limit to 200 nodes (Canvas handles it) 2026-04-03 19:45:38 +07:00
viettranx 7850ccea01 feat(kg): replace ReactFlow SVG with react-force-graph-2d Canvas renderer
- Replace ReactFlow (SVG, lags at 80+ nodes) with react-force-graph-2d
  (Canvas/WebGL, handles 500+ nodes at 60fps)
- Custom nodeCanvasObject: colored circle by entity type + name label
- Single click: highlight node + neighbors + connected edges with
  directional particles; dim unconnected nodes to 20% opacity
- Double click (timer-based 280ms): open entity detail modal
- Edge labels shown only for selected node's connections (background pill)
- Increase GRAPH_LIMIT from 80 to 150 (Canvas renderer handles it)
- ResizeObserver for responsive container sizing
- Zoom-to-fit button in stats bar
- Auto zoom-to-fit on engine stop
- Dark/light theme support via isDark conditional colors
- Remove ReactFlow + D3 force imports (packages kept in package.json)
2026-04-03 19:41:44 +07:00
Viet Tran cfc69f6f70 fix(tracing): use per-request model/provider overrides in trace spans (#667) (#668)
Trace spans and cost calculations were recording the agent's default
model/provider instead of the effective overridden values from heartbeat
requests. Introduced functional options pattern (spanOption) so all span
emitters resolve the correct model/provider.
2026-04-03 19:38:51 +07:00
viettranx 9e037bca8a fix(kg): fix filter reload, graph perf, stats layout, double-click interaction
- Fix filter not reloading: remove placeholderData from entity list and
  graph queries so data clears immediately on filter change; add key prop
  to force remount on filter change
- Fix graph lag/crash: reduce GRAPH_LIMIT to 80, increase Barnes-Hut theta
  for faster approximation, increase alphaDecay for faster convergence
- Move entity type stats to separate line below toolbar (better readability)
- Change node click: single-click highlights edges, double-click opens detail
- Increase entity list limit to 200 (table view only, graph stays at 80)
2026-04-03 18:42:05 +07:00
viettranx c2bd5349e5 fix(ui,kg): fix credential user picker, KG filters, graph limits, and traversal depth
- Fix MCP/CLI credential dialogs: separate search text from selected user ID
  to prevent keystroke-as-selection bug (use onSelect pattern)
- Fix Combobox: suppress value-sync after selection to prevent label flicker
- Fix MCP dialog: prevent full-page spinner flash when switching users
- Fix KG page filter: replace session-based scope with stats-based user_ids
  from KG entities (more reliable user list)
- Increase KG graph visualization limit from 50 to 200 nodes with optimized
  D3 force layout breakpoints for 100+/150+ nodes
- Cap graph API server-side limit at 500 to prevent unbounded queries
- Increase KG traversal max_depth from 3 to 5 (HTTP API + agent tool)
- Add dedicated Zustand store for KG detail dialog (isolated from main graph)
- Add depth selector UI (2-5 hops) in entity detail dialog
2026-04-03 16:45:00 +07:00
Thieu Nguyen 929dcd20c2 fix(docs): correct team tools reference in README (#651)
- Replace `team_message` with `spawn` for subagent orchestration
- Update team communication description to reflect current implementation
- Align docs with actual tool capabilities

Related: Team coordination updates for agent orchestration
2026-04-03 16:05:04 +07:00
Huy Doan 72025698bb fix(sandbox): support write_file append in FsBridge (#650)
- Add appendMode bool param to FsBridge.WriteFile (>> vs >)
- Pass appendMode through sandbox path in WriteFileTool
- EditTool always uses overwrite mode (false)

Closes #650
2026-04-03 16:03:57 +07:00
viettranx 80c2c0e0ee fix(providers): normalize Ollama api_base URL to include /v1 suffix
- Write-time normalization via normalizeOllamaAPIBase() on create/update
- Read-time safety net in resolveAPIBase() for pre-existing DB records
- Covers both ProviderOllama and ProviderOllamaCloud
- Stop hardcoding +"/v1" in registerInMemory/startup registration

Closes #654
2026-04-03 15:44:39 +07:00
Kai (Tam Nhu) Tran 9050426840 fix(providers): add reasoning field alias for Ollama thinking models (#658)
- Add `reasoning` JSON alias to openAIMessage and openAIStreamDelta structs
- Coalesce reasoning/reasoning_content in streaming and non-streaming parse paths
- reasoning_content remains canonical; reasoning is Ollama-specific fallback

Closes #655
2026-04-03 15:31:46 +07:00
viettranx 78a2152053 refactor(http): split provider_models.go into focused modules
- provider_models.go (154L): types, handler, reasoning helpers
- provider_models_fetch.go (191L): remote API fetchers (Anthropic, Gemini, OpenAI, Ollama)
- provider_models_catalog.go (103L): hardcoded model lists

All files under 200-line guideline. No logic changes.
2026-04-03 15:18:54 +07:00
Kai (Tam Nhu) Tran e8579f5e1c feat(providers): add rich Ollama model listing via /api/tags (#659)
- Ollama/OllamaCloud providers now use native /api/tags for richer metadata
- Display name built from family + parameter_size + quantization_level
- Strips /v1 suffix, DockerLocalhost support, graceful fallback on error
- 7 comprehensive tests covering all edge cases

Closes #656
2026-04-03 15:17:08 +07:00
viettranx bde95b70c5 fix(providers): clamp max_tokens to 4096 for Fireworks non-streaming requests
Fireworks AI requires stream=true for max_tokens > 4096. Proactively
clamp non-streaming requests to avoid 400 errors (their error format
doesn't match the generic clampMaxTokensFromError retry regex).

Closes #660
2026-04-03 15:04:45 +07:00
viettranx 3206c266bf fix(docker): bump claude-code pin to ^2.1.91
Previous pin ^1.0.47 was stale — latest is 2.x series.
2026-04-03 14:55:44 +07:00
Duc Nguyen 532aab4387 fix(docker): pin Python/npm dependency versions (#663)
- Add docker/requirements-base.txt (edge-tts) and requirements-skills.txt (10 packages)
- Pin versions: pip ~= (patch only), npm ^, anthropic >=0.88<2.0
- Add .npmrc with supportedArchitectures for Alpine musl builds
- Restore --frozen-lockfile (lockfile regenerated with musl entries)
- Pin @anthropic-ai/claude-code@^1.0.47

Closes #662
2026-04-03 14:55:07 +07:00
ila 943b2eb3e5 feat(docker): make goclaw-ui stop instantly (#665) 2026-04-03 14:42:47 +07:00
viettranx 9472819334 fix(memory): skip user_id filter in shared memory queries
When share_memory is enabled, memory queries now remove the user_id
filter entirely instead of filtering by user_id IS NULL. This matches
the existing KG shared behavior and allows all users to see all memory
documents (global + per-user from everyone).
2026-04-03 14:34:29 +07:00
viettranx 1f85c73a39 fix(ui): resolve raw user IDs to display names across web UI
Extract shared formatUserLabel util and wire useContactResolver into
15 pages that previously showed raw numeric IDs (e.g. 386246614)
instead of human-readable names.

- Add formatUserLabel with display hierarchy: name > @username > #id
- Fix MultiUserPicker badges (covers all allow/deny lists)
- Fix permissions, tenant users, overview cards, traces, nodes
- Remove redundant raw ID spans from permissions and pending messages
- Delete duplicate formatScopeLabel/parseUserDisplay local functions
2026-04-02 23:30:14 +07:00
viettranx ade6c7ba33 fix(agent): preserve MediaRefs when merging consecutive same-role messages
sanitizeHistory now appends MediaRefs from dropped messages so compaction
summary retains knowledge of shared media files.
2026-04-02 22:58:35 +07:00
Michael Nguyen d79d738148 fix(agent): clear RawAssistantContent on dedup + merge consecutive same-role messages
sanitizeHistory dedup rewrites ToolCalls IDs but not RawAssistantContent.
Anthropic provider prefers RawAssistantContent → sends stale IDs → HTTP 400.
Fix: clear RawAssistantContent when dedup fires. Also merge consecutive
same-role messages (user↔user, assistant↔assistant) to fix role alternation
errors from session corruption.
2026-04-02 20:36:41 +07:00
viettranx 79cae648e4 fix(security): pairing expiry race, sender-ID validation, Slack senderID cleanup
- Add expires_at check to ApprovePairing SELECT (PG + SQLite) to close
  race between prune DELETE and code lookup
- Add isValidSenderID regex validation to handleRequest, handleRevoke,
  and handleBrowserPairingStatus (prevents log injection / bus poisoning)
- Add slog.Warn on decrypt fallback paths for downgrade detection
- Remove Slack compound senderID|displayName format; all channels now
  pass plain senderID with displayName in metadata
2026-04-02 20:29:44 +07:00
viettranx 7ba3a5115a fix(tools): hint model when shell commands target DB-backed memory files
Memory files (MEMORY.md, memory/*.md) are stored in PostgreSQL, not on
disk. When the model uses exec to run cat/ls/grep/find on memory paths,
short-circuit with a hint to use memory_search or memory_get instead.
Also append [Source: database, not filesystem] to read_file and
list_files results served from the memory interceptor.
2026-04-02 19:28:04 +07:00
viettranx 99720892a7 fix(storage): hide tenant roots from master storage API
Master tenant's base dir is the global data dir, which contains
the tenants/ cross-tenant isolation root. Without this fix, the
Storage page exposes tenant slugs, file names, and sizes.

- Extract topLevelPath() helper, remove dead code
- Add isHiddenPath() scoped to master tenant only
- Guard handleList, handleRead, handleSize with hidden path checks
- handleSize uses filepath.SkipDir to skip entire tenant subtree
- Add regression tests for list, read, size, subpath, and
  non-master tenant isolation
2026-04-02 19:05:46 +07:00
viettranx 484d434f6c fix(security): harden sandbox, auth, and shell deny patterns
Sandbox: add noexec/nosuid/nodev to tmpfs mounts, remove SETUID/SETGID/CHOWN
caps, add PidsLimit 256 default, keep no-new-privileges from base.

Auth: reject X-GoClaw-User-Id header spoofing in dev mode (no gateway token),
use full 32-byte HMAC for file tokens instead of truncated 16-byte.

Shell: add NFKC Unicode normalization + zero-width character stripping before
deny pattern matching, add 5 export-prefixed env var deny patterns, fix
exemption logic to check per-argument prefix instead of whole-command substring
(prevents bypass via comments while preserving skill store access).
2026-04-02 18:58:24 +07:00
viettranx 4c485d6fa1 fix(mcp): retry stdio transport initialization with exponential backoff
Heavy MCP servers (FastMCP with 80+ tools, OAuth servers) take 3-5s to
start their stdin read loop. Without retries, connectAndDiscover sends
the initialize request immediately after fork/exec, gets EOF, and
permanently fails with "transport closed".

Add a retry loop (4 attempts, 2s/4s/8s backoff) for stdio transports
only. SSE/HTTP transports fail immediately since connection-refused is
definitive. The retry respects context cancellation to avoid blocking
shutdown.

Closes #385
2026-04-02 18:43:41 +07:00
Huy DoanandViet Tran 1170a85eb4 Fix/brave search api key readonly (#648)
* fix(secure-cli): resolve ambiguous column in LookupByBinary JOIN query (#641)

LookupByBinary uses LEFT JOIN with secure_cli_user_credentials but
SELECT columns lacked table alias prefix, causing PostgreSQL error:
"column reference 'id' is ambiguous (SQLSTATE 42702)"

This silently broke ALL credentialed CLI exec — commands fell through
to regular shell exec without injected env vars.

Fix: use b.-prefixed column names for JOIN queries.
Also add diagnostic logging to lookupCredentialedBinary for future debugging.

* fix(agent): defer warning messages after parallel tool results (#644)

When parallel tool calls trigger loop detection warnings, the warning
messages (role="user") were inserted between tool result messages
(role="tool"). This breaks the Anthropic API when routed through
OpenAI-compatible proxies (e.g. LiteLLM): the proxy groups consecutive
tool messages into a single user message with tool_result blocks, but
an intervening user warning splits the group, causing orphaned
tool_results and HTTP 400 "tool_use ids without tool_result blocks".

Fix: accumulate warning messages during parallel result processing and
append them after all tool results, preserving the consecutive grouping.

Closes #642

* fix(web): allow editing Brave Search API key when masked

---------

Co-authored-by: Viet Tran <viettranx@gmail.com>
2026-04-02 18:39:30 +07:00
viettranx 7418cb62aa fix(agent): reduce system prompt size and fix team context injection (#613)
Prompt compression (Issue #613):
- Truncate skill descriptions to 200 runes in inline XML (matches mcpToolDescMaxLen)
- Lower skill inline token threshold from 5000 to 3000
- Compact tool descriptions (risk-audited: preserve behavioral hints)
- Compact boilerplate sections: media hint, safety, tool call style, spawn,
  self-evolve, skill creation, team workspace
- Fix token estimator to account for description truncation
- Restore safety anti-manipulation clauses dropped during compaction

Team context injection fix (found during prod audit):
- Add IsTeamLead field to LoopConfig/Loop, plumbed from resolver
- Gate team context (TEAM.md, workspace, members) on session type:
  leader inbound → team context; member-only inbound → spawn section;
  team dispatch → team context
- Filter TEAM.md from context files for member-only inbound chat
- Skip team member DB query when team context not needed
- Rename HasTeam → IsTeamContext for semantic clarity
- Add 8 table-driven tests for team context injection scenarios
2026-04-02 18:32:43 +07:00
viettranx cace4dcf31 fix(web): improve advanced settings dialog layout and width
Widen settings dialogs from sm:max-w-2xl (672px) to sm:max-w-3xl (768px)
to prevent cramped toggle groups. Move boolean field help text to a
separate line below the switch+label for cleaner readability.
2026-04-02 18:30:30 +07:00
viettranx 4e4a835795 fix(agent): defer warning messages after parallel tool results
When parallel tool calls trigger loop detection warnings, the warning
messages (role="user") were inserted between tool result messages
(role="tool"). This breaks the Anthropic API when routed through
OpenAI-compatible proxies (e.g. LiteLLM): the proxy groups consecutive
tool messages into a single user message with tool_result blocks, but
an intervening user warning splits the group, causing orphaned
tool_results and HTTP 400 "tool_use ids without tool_result blocks".

Fix: accumulate warning messages during parallel result processing and
append them after all tool results, preserving the consecutive grouping.

Closes #642
2026-04-02 16:43:53 +07:00
viettranx bfd65828a6 feat(web): add merge hint to CLI and MCP user credentials dialogs
Both dialogs now show an amber callout explaining that chat users
(Telegram, Discord, etc.) must be merged into a tenant user via
Contacts page before they can have per-user credentials.
i18n: en/vi/zh for both cli-credentials and mcp namespaces.
2026-04-02 15:18:06 +07:00
viettranx 5bad031908 fix(web): align CLI user credentials picker with MCP pattern
Replace raw Combobox + useUserPicker with UserPickerCombobox
component (source="tenant_user") to match MCP user credentials
dialog. Both systems use the same runtime user ID from context.
2026-04-02 15:15:36 +07:00
viettranx ddc5964b85 feat(web): replace user ID text input with Combobox user picker in CLI user credentials
Use existing useUserPicker hook + Combobox component to search
contacts + tenant_users instead of manual UUID entry.
Supports allowCustom for IDs not in the search results.
2026-04-02 15:10:30 +07:00
viettranx 79dce7e523 Merge branch 'hotfix/secure-cli-lookup-ambiguous-column' into dev 2026-04-02 15:02:43 +07:00
viettranx 9c92dead74 fix(web): force remount KG entity detail dialog on entity change
Add key={viewEntity?.id} to prevent stale relations/traversal data
when switching between entities without closing the dialog.
2026-04-02 15:01:20 +07:00
viettranx 19d8faf28f refactor(knowledge-graph): minor UI and handler adjustments 2026-04-02 14:58:03 +07:00
viettranx 3da84fcded fix(web): prevent tool card overflow during streaming
Add min-w-0 to ActiveRunZone flex content container.
Without it, long tool results (e.g. SQL output) push beyond viewport
creating horizontal scroll. MergedToolGroup already had this fix.
2026-04-02 14:57:58 +07:00
viettranx 10cd911dc7 feat(secure-cli): check-binary endpoint, agent select dropdown, fix ambiguous column
Backend:
- Add POST /v1/cli-credentials/check-binary to resolve binary via exec.LookPath
- Security: safeBinaryNameRe regex prevents filesystem probing
- Fix ambiguous column in LookupByBinary LEFT JOIN (secureCLISelectColsAliased)
- Add diagnostic logging to lookupCredentialedBinary

Frontend:
- Replace agent ID text input with Select dropdown (reuse useAgents hook)
- Add Check Binary button next to binary name (auto-fills resolved path)
- Add binary path hint explaining auto-detection from PATH
- Update i18n keys (en/vi/zh) for new UI elements
2026-04-02 14:57:50 +07:00
viettranx ec05c80e90 fix(secure-cli): resolve ambiguous column in LookupByBinary JOIN query
LookupByBinary uses LEFT JOIN with secure_cli_user_credentials but
SELECT columns lacked table alias prefix, causing PostgreSQL error:
"column reference 'id' is ambiguous (SQLSTATE 42702)"

This silently broke ALL credentialed CLI exec — commands fell through
to regular shell exec without injected env vars.

Fix: use b.-prefixed column names for JOIN queries.
Also add diagnostic logging to lookupCredentialedBinary for future debugging.
2026-04-02 14:56:49 +07:00
viettranx 0370cabdc9 chore: stabilize main branch with dev workflow + PR guidelines
- Set dev as default branch, protect main (owner-only merge)
- Add CI trigger for PRs targeting dev
- Add PR template with checklist and branch targeting guide
- Add CONTRIBUTING.md with branch strategy and review criteria
- Update README clone command to use -b main for stable
2026-04-02 12:36:30 +07:00