feat: add network, bridges and automations web pages#18
Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (42)
📒 Files selected for processing (121)
WalkthroughAdds bridge provider discovery/listing and last-success telemetry; implements a persisted network subsystem (channels, peers, messages) with DB schema, store APIs, new HTTP/UDS routes and handlers, core interfaces and handler wiring, web UI/hook surfaces for Bridges and Network, message/audit timeline persistence, manifest bridge metadata, and extensive tests. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant API_Router as API Router
participant Handlers as BaseHandlers
participant Runtime as Runtime (Sessions/Peers)
participant Store as NetworkStore / GlobalDB
participant Audit as AuditWriter
Client->>API_Router: HTTP GET/POST /api/network/... or /api/bridges/providers
API_Router->>Handlers: invoke handler (NetworkChannels/CreateNetworkChannel/ListBridgeProviders/...)
Handlers->>Runtime: query sessions/peers or create sessions
Runtime-->>Handlers: session/peer info
Handlers->>Store: ListNetworkMessages / WriteNetworkMessage (persist/read)
Store-->>Handlers: persisted messages / query results
Handlers->>Audit: RecordSent / RecordDelivered (emit audit + timeline)
Audit->>Store: WriteNetworkMessage (timeline persistence path)
Handlers-->>API_Router: JSON response (200/201 or error)
API_Router-->>Client: HTTP response
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
✨ Finishing Touches📝 Generate docstrings
|
There was a problem hiding this comment.
Actionable comments posted: 14
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
web/src/routes/_app/-automation.integration.test.tsx (1)
314-342:⚠️ Potential issue | 🟡 MinorWrap all post-mutation assertions in
waitFor()to prevent flaky tests.Both
handleSubmitJobandhandleTriggerNowproperly awaitmutateAsync()before calling side effects. However, the test assertions race those completions—user.click()returns when the event is processed, not when the async handler finishes. The create job test leaves the toast assertion outsidewaitFor(), and the trigger now test has nowaitFor()at all.💡 Suggested fix
await user.click(screen.getByTestId("submit-job-form")); await waitFor(() => { expect(mockCreateJobMutateAsync).toHaveBeenCalledWith( expect.objectContaining({ agent_name: "writer", name: "nightly-docs", scope: "workspace", workspace_id: "ws_test", }) ); + expect(toast.success).toHaveBeenCalledWith("Created job nightly-docs."); }); - - expect(toast.success).toHaveBeenCalledWith("Created job nightly-docs."); await user.click(screen.getByTestId("trigger-job-btn")); - expect(mockTriggerJobMutateAsync).toHaveBeenCalledWith({ id: "job_daily_review" }); - expect(toast.success).toHaveBeenCalledWith("Queued run run_queued."); - expect(screen.getByTestId("automation-run-run_queued")).toBeInTheDocument(); + await waitFor(() => { + expect(mockTriggerJobMutateAsync).toHaveBeenCalledWith({ id: "job_daily_review" }); + expect(toast.success).toHaveBeenCalledWith("Queued run run_queued."); + expect(screen.getByTestId("automation-run-run_queued")).toBeInTheDocument(); + });Also applies to: 373-381
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/routes/_app/-automation.integration.test.tsx` around lines 314 - 342, The tests are asserting side-effects before the async mutate handlers finish; wrap all post-mutation assertions in waitFor to avoid flakes: in the create-job test ensure the toast.success assertion is moved inside a waitFor that also checks mockCreateJobMutateAsync was called (referencing mockCreateJobMutateAsync and toast.success), and in the trigger-now test wrap its assertions similarly (referencing handleTriggerNow/mutateAsync and any mockTriggerMutateAsync/toast calls) so both the mutation and subsequent side-effect assertions wait for completion.
🟡 Minor comments (24)
web/src/systems/session/components/message-bubble.tsx-5-5 (1)
5-5:⚠️ Potential issue | 🟡 MinorUse path alias import for
MessageMarkdown.Line 5 uses a relative import; this should use the
@/*alias convention for web imports.Suggested change
-import { MessageMarkdown } from "./message-markdown"; +import { MessageMarkdown } from "@/systems/session/components/message-markdown";As per coding guidelines, "Use path alias
@/*to map to./src/*for all imports".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/session/components/message-bubble.tsx` at line 5, The import in message-bubble.tsx currently uses a relative path for MessageMarkdown; update the import to use the project path-alias (e.g., import MessageMarkdown from "@/systems/session/components/message-markdown") so it follows the `@/`* → ./src/* convention and keeps consistency with other web imports; ensure the imported symbol name MessageMarkdown remains unchanged.web/src/systems/bridges/components/bridge-provider-card.tsx-4-10 (1)
4-10:⚠️ Potential issue | 🟡 MinorConvert these relative imports to
@/aliases.Use the project alias consistently for imports under
web/src.
As per coding guidelines, "Use path alias@/*to map to./src/*for all imports".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/bridges/components/bridge-provider-card.tsx` around lines 4 - 10, Replace the relative imports in bridge-provider-card.tsx with the project path alias by changing imports that reference "../lib/bridge-formatters" and "../types" to use "@/systems/bridges/lib/bridge-formatters" and "@/systems/bridges/types" respectively; ensure the imported symbols bridgeProviderHealthTone, bridgeProviderStateTone, buildBridgeProviderKey, isBridgeProviderSelectable and the BridgeProvider type are preserved exactly and update any other similar relative imports in this file to use the `@/` alias consistently.web/src/systems/bridges/components/bridge-list-panel.tsx-7-13 (1)
7-13:⚠️ Potential issue | 🟡 MinorUse
@/alias imports for local modules.Please switch these relative imports to alias-based imports for consistency with project rules.
As per coding guidelines, "Use path alias@/*to map to./src/*for all imports".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/bridges/components/bridge-list-panel.tsx` around lines 7 - 13, Update the relative imports in bridge-list-panel.tsx to use the project path alias: replace the import of bridgeScopeTone, bridgeStatusTone, formatBridgeRelativeTime from "../lib/bridge-formatters" with "@/lib/bridge-formatters" and replace the type import of BridgeHealthMap and BridgeSummary from "../types" with "@/systems/bridges/types" (or the correct aliased path that maps to the original types location) so the component uses the `@/` alias for local modules consistently.web/src/systems/bridges/components/bridge-test-delivery-dialog.tsx-23-25 (1)
23-25:⚠️ Potential issue | 🟡 MinorSwitch local imports to the
@/alias.Please replace these relative imports with alias-based imports to match project conventions.
As per coding guidelines, "Use path alias@/*to map to./src/*for all imports".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/bridges/components/bridge-test-delivery-dialog.tsx` around lines 23 - 25, Update the two local imports to use the project path alias `@/` instead of relative paths: replace the import of bridgeProviderStateTone and describeBridgeTestTarget from "../lib/bridge-formatters" with the alias import from "@/systems/bridges/lib/bridge-formatters", and replace the types BridgeTestDeliveryDraft and TestBridgeDeliveryResponse imported from "../types" with "@/systems/bridges/types" (or the correct alias target matching those symbols) so they follow the project's `@/*` mapping; ensure the imported symbol names remain unchanged.web/src/systems/bridges/components/bridge-empty-state.tsx-13-16 (1)
13-16:⚠️ Potential issue | 🟡 MinorReplace relative imports with
@/aliases.Please align these imports with the project-wide alias rule.
As per coding guidelines, "Use path alias@/*to map to./src/*for all imports".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/bridges/components/bridge-empty-state.tsx` around lines 13 - 16, The imports in bridge-empty-state.tsx use relative paths; update them to the project alias form by replacing the relative import paths with "@/..." equivalents — specifically change imports referencing isBridgeProviderSelectable, the BridgeProvider type, and BridgeProviderCard to use the "@/..." alias (e.g., import { isBridgeProviderSelectable } from "@/systems/bridges/lib/bridge-formatters"; import type { BridgeProvider } from "@/systems/bridges/types"; import { BridgeProviderCard } from "@/systems/bridges/components/bridge-provider-card") so they follow the project's path-alias rule.web/src/systems/bridges/lib/bridge-formatters.ts-11-11 (1)
11-11:⚠️ Potential issue | 🟡 MinorAvoid returning a shared mutable defaults object.
Returning a module-level
{}can cause accidental cross-call state leakage if any consumer mutates the returned value.Proposed fix
-const EMPTY_DELIVERY_DEFAULTS: BridgeDeliveryDefaults = {}; - export function normalizeBridgeDeliveryDefaults(value: unknown): BridgeDeliveryDefaults { if (!value || typeof value !== "object" || Array.isArray(value)) { - return EMPTY_DELIVERY_DEFAULTS; + return {}; }Also applies to: 87-90
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/bridges/lib/bridge-formatters.ts` at line 11, The module-level EMPTY_DELIVERY_DEFAULTS constant exposes a shared mutable object (BridgeDeliveryDefaults) that can leak state across callers; replace returns of EMPTY_DELIVERY_DEFAULTS with a fresh empty object each time (e.g., return {} as BridgeDeliveryDefaults or use a factory like createEmptyDeliveryDefaults()), and apply the same change for the other defaults referenced around lines 87-90 (ensure any constants there are returned by value, not by reference, or replaced with small factory functions) so callers receive isolated objects instead of a shared mutable instance.web/src/systems/bridges/lib/bridge-formatters.ts-120-124 (1)
120-124:⚠️ Potential issue | 🟡 MinorExtract this inline object shape into an interface.
Defining the routing-policy object shape inline makes reuse harder and breaks the project TypeScript shape convention.
As per coding guidelines, "web/**/*.ts?(x): Useinterfacefor defining object shapes in TypeScript (pattern is in Zod schemas and types)".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/bridges/lib/bridge-formatters.ts` around lines 120 - 124, Extract the inline object shape used in describeBridgeRoutingPolicy into a named exported interface (e.g., BridgeRoutingPolicy) and replace the inline type annotation in the function signature with that interface; update the function signature export function describeBridgeRoutingPolicy(policy: BridgeRoutingPolicy): string and export the new interface so it can be reused elsewhere and conform to the project's TypeScript shape convention.web/src/systems/bridges/lib/bridge-formatters.ts-1-7 (1)
1-7:⚠️ Potential issue | 🟡 MinorUse
@/alias imports instead of relative paths.Please replace relative imports here with the project alias to keep module boundaries consistent.
As per coding guidelines, "Use path alias@/*to map to./src/*for all imports".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/bridges/lib/bridge-formatters.ts` around lines 1 - 7, The import of types (BridgeDeliveryDefaults, BridgeProvider, BridgeRoute, BridgeScope, BridgeStatus) uses a relative path; update the import source to use the project path alias (e.g. replace the relative "../types" with "@/systems/bridges/types") so the import reads from the "@/..." alias and keeps module boundaries consistent while retaining the same imported symbols.web/src/systems/bridges/components/bridge-test-delivery-dialog.tsx-56-59 (1)
56-59:⚠️ Potential issue | 🟡 MinorGuard against duplicate submit while pending.
The form handler should no-op when
isPendingto prevent repeated submission from keyboard/programmatic form submit paths.Proposed fix
onSubmit={event => { event.preventDefault(); + if (isPending) { + return; + } onSubmit(); }}Also applies to: 216-216
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/bridges/components/bridge-test-delivery-dialog.tsx` around lines 56 - 59, Guard the form submit handlers against duplicate submits by checking the isPending flag and returning early; update the inline onSubmit handler (the event => { event.preventDefault(); onSubmit(); } callback) to first if (isPending) { event.preventDefault(); return; } then proceed to call onSubmit(), and apply the same change to the other identical form submit handler in this file (the second onSubmit occurrence).web/src/systems/bridges/components/bridge-list-panel.tsx-24-34 (1)
24-34:⚠️ Potential issue | 🟡 MinorMove inline props object shape to an interface.
This props shape should be declared as an
interfaceand reused, rather than typed inline in the function signature.
As per coding guidelines, "web/**/*.ts?(x): Useinterfacefor defining object shapes in TypeScript (pattern is in Zod schemas and types)".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/bridges/components/bridge-list-panel.tsx` around lines 24 - 34, Declare a named interface (e.g., BridgeListItemProps) describing the props shape used by BridgeListItem with fields bridge: BridgeSummary; health?: BridgeHealthMap[string]; isSelected: boolean; onSelect: () => void; then update the BridgeListItem function signature to accept (props: BridgeListItemProps) or destructure with ({ bridge, health, isSelected, onSelect }: BridgeListItemProps) instead of the inline type; keep the interface adjacent to the component so it can be reused elsewhere.web/src/systems/bridges/lib/bridge-drafts.ts-1-13 (1)
1-13:⚠️ Potential issue | 🟡 MinorUse
@/aliases for these imports.Please switch relative imports in this module to the configured path alias.
As per coding guidelines, "Use path alias@/*to map to./src/*for all imports".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/bridges/lib/bridge-drafts.ts` around lines 1 - 13, Replace the relative imports with the project path alias: change the import of buildBridgeProviderKey, isBridgeProviderSelectable, normalizeBridgeDeliveryDefaults (currently imported from "./bridge-formatters") and the types BridgeCreateDraft, BridgeProvider, BridgeSummary, BridgeTestDeliveryDraft (currently from "../types") to use the configured "@/..." alias form per the coding guidelines so the same modules are imported via the alias instead of relative paths.web/src/systems/bridges/lib/bridge-formatters.ts-190-205 (1)
190-205:⚠️ Potential issue | 🟡 MinorRelative-time boundaries are rounded the wrong way.
Using
Math.roundcan overstate elapsed/remaining time near boundaries (e.g., ~30s becomes1m). Use floor-based bucketing for stable labels.Proposed fix
- const diffMinutes = Math.round(Math.abs(diffMs) / (1000 * 60)); + const diffMinutes = Math.floor(Math.abs(diffMs) / (1000 * 60)); @@ - const diffHours = Math.round(diffMinutes / 60); + const diffHours = Math.floor(diffMinutes / 60); @@ - const diffDays = Math.round(diffHours / 24); + const diffDays = Math.floor(diffHours / 24);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/bridges/lib/bridge-formatters.ts` around lines 190 - 205, The relative-time labels overstate near boundaries because diffMinutes/diffHours/diffDays use Math.round; change to floor-based bucketing: compute diffMinutes as Math.floor(Math.abs(diffMs) / (1000 * 60)) and treat "Just now" when Math.abs(diffMs) < 1000 * 60, then use diffMinutes for the minute branch, compute diffHours = Math.floor(diffMinutes / 60) and diffDays = Math.floor(diffHours / 24), and keep the existing sign checks (diffMs >= 0) when returning `In ...` vs `... ago` for the symbols diffMs, diffMinutes, diffHours, diffDays in this function.internal/api/httpapi/httpapi_integration_test.go-1017-1019 (1)
1017-1019:⚠️ Potential issue | 🟡 MinorReturn an empty providers list instead of
nil.
nilhere can surface as"providers": nullin API responses, while list endpoints should stay shape-stable as arrays. Prefer returning an empty slice.Proposed fix
func (s *integrationBridgeService) ListProviders(context.Context) ([]bridgepkg.BridgeProvider, error) { - return nil, nil + return []bridgepkg.BridgeProvider{}, nil }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/api/httpapi/httpapi_integration_test.go` around lines 1017 - 1019, The ListProviders method currently returns nil for the providers slice causing JSON "providers": null; update the function (integrationBridgeService.ListProviders) to return an empty slice instead of nil, e.g. return []bridgepkg.BridgeProvider{}, nil (or initialize a zero-length slice variable and return it) so API responses remain shape-stable arrays.web/src/systems/network/hooks/use-network-actions.ts-5-7 (1)
5-7:⚠️ Potential issue | 🟡 MinorUse
@/*aliases instead of relative imports.These imports violate the web import-path convention and can fail consistency checks.
Suggested fix
-import { createNetworkChannel } from "../adapters/network-api"; -import { networkKeys } from "../lib/query-keys"; -import type { CreateNetworkChannelRequest } from "../types"; +import { createNetworkChannel } from "@/systems/network/adapters/network-api"; +import { networkKeys } from "@/systems/network/lib/query-keys"; +import type { CreateNetworkChannelRequest } from "@/systems/network/types";As per coding guidelines, "Use path alias
@/*to map to./src/*for all imports."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/network/hooks/use-network-actions.ts` around lines 5 - 7, Replace the relative imports in use-network-actions.ts with path-alias imports rooted at `@/src`: change imports referencing "../adapters/network-api", "../lib/query-keys", and "../types" to use the corresponding alias paths (e.g., "@/systems/network/adapters/network-api", "@/systems/network/lib/query-keys", "@/systems/network/types") so that createNetworkChannel, networkKeys, and CreateNetworkChannelRequest are imported via the `@/`* mapping to ./src/*.web/src/systems/bridges/lib/query-options.test.ts-8-8 (1)
8-8:⚠️ Potential issue | 🟡 MinorSwitch this import to the project alias path.
Using a relative import here breaks the enforced web import convention.
Suggested fix
-import { - bridgeDetailOptions, - bridgeProvidersOptions, - bridgeRoutesOptions, - bridgesListOptions, -} from "./query-options"; +import { + bridgeDetailOptions, + bridgeProvidersOptions, + bridgeRoutesOptions, + bridgesListOptions, +} from "@/systems/bridges/lib/query-options";As per coding guidelines, "Use path alias
@/*to map to./src/*for all imports."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/bridges/lib/query-options.test.ts` at line 8, Replace the relative import of "./query-options" in the test file with the project path-alias import that starts with "@/". Locate the import statement that references "./query-options" and change it to the corresponding alias path (e.g., "@/systems/bridges/lib/query-options") so it follows the enforced web import convention and resolves from src via the `@/`* mapping; keep the imported symbol names unchanged.internal/api/core/network.go-259-267 (1)
259-267:⚠️ Potential issue | 🟡 MinorKeep the peer-id fallback when
display_nameis blank.A non-nil
PeerCard.DisplayNamecontaining only whitespace now produces an emptyDisplayNameinstead of falling back topeer.PeerID.💡 Suggested fix
displayName := peer.PeerID if peer.PeerCard.DisplayName != nil { - displayName = strings.TrimSpace(*peer.PeerCard.DisplayName) + if trimmed := strings.TrimSpace(*peer.PeerCard.DisplayName); trimmed != "" { + displayName = trimmed + } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/api/core/network.go` around lines 259 - 267, The current code trims PeerCard.DisplayName but unconditionally assigns that possibly-empty string to displayName; update the logic in the function that builds NetworkPeerPayload (the displayName variable assignment using peer.PeerCard.DisplayName) so that after calling strings.TrimSpace(*peer.PeerCard.DisplayName) you only use the trimmed value when it is non-empty, otherwise keep the fallback of peer.PeerID; ensure the condition references peer.PeerCard.DisplayName and the trimmed result before assigning DisplayName in the returned contract.NetworkPeerPayload.web/src/systems/automation/components/automation-job-form.tsx-357-360 (1)
357-360:⚠️ Potential issue | 🟡 MinorMake the enabled label mode-aware.
Enabled on createis accurate for new jobs, but misleading in edit mode where the checkbox is toggling the job's current state. A conditional label likemode === "create" ? "Enabled on create" : "Enabled"would avoid that mismatch.💡 Suggested fix
<AutomationCheckbox checked={draft.enabled ?? true} description="Disabled jobs stay visible but never dispatch on their schedule." - label="Enabled on create" + label={mode === "create" ? "Enabled on create" : "Enabled"} onCheckedChange={checked => onChange({ ...draft, enabled: checked })} />🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/automation/components/automation-job-form.tsx` around lines 357 - 360, Update the AutomationCheckbox label to be mode-aware: when the component is in create mode show "Enabled on create" and in edit mode show "Enabled". Locate the AutomationCheckbox usage (the one using draft.enabled) in automation-job-form.tsx and change the label to choose between "Enabled on create" and "Enabled" based on the component's mode prop/state (e.g., mode === "create" ? "Enabled on create" : "Enabled"), keeping the rest of the props (checked={draft.enabled ?? true}, description) unchanged.internal/store/globaldb/global_db_network_messages.go-17-18 (1)
17-18:⚠️ Potential issue | 🟡 MinorWrap the validation failures with store-specific context.
Both paths return raw
Validate()errors, which makes upstream failures harder to attribute once they bubble out of the store layer. Wrapping still preserveserrors.Is/errors.As.Proposed fix
if err := entry.Validate(); err != nil { - return err + return fmt.Errorf("store: validate network message entry: %w", err) } @@ if err := query.Validate(); err != nil { - return nil, err + return nil, fmt.Errorf("store: validate network message query: %w", err) }As per coding guidelines,
**/*.go: Use explicit error returns with wrapped context:fmt.Errorf("context: %w", err).Also applies to: 50-51
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/store/globaldb/global_db_network_messages.go` around lines 17 - 18, The raw returns of entry.Validate() should be wrapped with store-specific context; replace both plain "if err := entry.Validate(); err != nil { return err }" occurrences with code that wraps the error using fmt.Errorf, e.g. "if err := entry.Validate(); err != nil { return fmt.Errorf(\"global store: validate network entry: %w\", err) }" (and add fmt to imports if missing) so upstream callers get contextualized errors while preserving error unwrapping.internal/store/globaldb/global_db_network_messages.go-70-72 (1)
70-72:⚠️ Potential issue | 🟡 MinorDon't discard
rows.Close()errors.This introduces an
_-ignored error in a new store path. If the close is intentionally best-effort, please document that; otherwise propagate it.As per coding guidelines,
**/*.go: Never ignore errors with_— every error must be handled or have a written justification.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/store/globaldb/global_db_network_messages.go` around lines 70 - 72, The defer currently swallows the error from rows.Close() (defer func() { _ = rows.Close() }()), which violates the rule to never ignore errors; update the defer to capture and handle the error (e.g., assign err := rows.Close() and either log it with the package logger or propagate it by setting a named return error or wrapping it before returning) instead of discarding it, or add an explicit comment explaining why a best-effort close is acceptable; target the rows.Close() call in the same function in global_db_network_messages.go and ensure the chosen handling follows project logging/propagation conventions.internal/api/core/network_test.go-1013-1023 (1)
1013-1023:⚠️ Potential issue | 🟡 MinorAssert the created agent names explicitly.
Right now this only proves that two sessions were created for the right workspace/channel. It would still pass if the handler created the wrong two agents.
Suggested assertion tightening
if got, want := len(createCalls), 2; got != want { t.Fatalf("len(createCalls) = %d, want %d", got, want) } + expectedAgents := map[string]struct{}{ + "coder": {}, + "reviewer": {}, + } for _, call := range createCalls { + if _, ok := expectedAgents[call.AgentName]; !ok { + t.Fatalf("Create() agent = %q, want coder/reviewer", call.AgentName) + } + delete(expectedAgents, call.AgentName) if got, want := call.Workspace, "ws-1"; got != want { t.Fatalf("Create() workspace = %q, want %q", got, want) } if got, want := call.Channel, "builders"; got != want { t.Fatalf("Create() channel = %q, want %q", got, want) } } + if len(expectedAgents) != 0 { + t.Fatalf("missing Create() calls for agents: %#v", expectedAgents) + }As per coding guidelines,
**/*_test.go: MUST test meaningful business logic, not trivial operations.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/api/core/network_test.go` around lines 1013 - 1023, The test currently verifies createCalls length and Workspace/Channel but not which agents were created; update the loop over createCalls to also assert the agent name for each call (e.g., check call.AgentName or call.Agent) against the expected agent names list (two specific names), using t.Fatalf on mismatch so the test fails if the wrong agents were created while retaining the existing Workspace/Channel assertions for Create().internal/network/audit.go-193-201 (1)
193-201:⚠️ Potential issue | 🟡 MinorPreserve the original message text in the timeline.
strings.TrimSpace(sayBody.Text)strips leading/trailing whitespace and terminal newlines, so the stored transcript can differ from what was actually sent. That becomes user-visible in the read-only channel timeline.Suggested fix
- Text: strings.TrimSpace(sayBody.Text), + Text: sayBody.Text,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/network/audit.go` around lines 193 - 201, The stored timeline currently calls strings.TrimSpace(sayBody.Text) when building the store.NetworkMessageEntry, which strips the original leading/trailing whitespace and newlines; change the Text field to store the raw message by assigning sayBody.Text directly (keep trimming for other fields like MessageID/SessionID/Channel/PeerFrom/Kind/Intent if desired) so the NetworkMessageEntry.Text preserves the exact original content sent.web/src/systems/automation/lib/automation-formatters.ts-346-358 (1)
346-358:⚠️ Potential issue | 🟡 MinorScope summaries should use the filtered count.
The
"global"and"workspace"branches ignorevisibleCountand reporttotalCountinstead. IftotalCountis the full collection size, the summary overstates scoped views as soon as a scope filter is applied.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/automation/lib/automation-formatters.ts` around lines 346 - 358, The summary currently uses totalCount for scoped summaries causing overstatement; update the branches in the formatter (look for scopeFilter, visibleCount, totalCount, totalNoun, activeWorkspaceName) so that the "global" branch and the workspace branch(s) return strings using visibleCount instead of totalCount (keep the "all" branch using totalCount); ensure the template literals for `${...} ${totalNoun}` use visibleCount where a scope filter is applied and preserve the activeWorkspaceName interpolation for the workspace message.web/src/systems/automation/components/automation-detail-panel.tsx-159-166 (1)
159-166:⚠️ Potential issue | 🟡 MinorManual jobs render as cron jobs here.
When
job.scheduleis absent, this falls back to"cron"and shows"Cron schedule", whiledescribeSchedule(job.schedule)returns"Manual". Unscheduled jobs will look scheduled.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/automation/components/automation-detail-panel.tsx` around lines 159 - 166, The code defaults mode to "cron" when job.schedule is missing, causing unscheduled jobs to display as cron; update the logic so mode is computed from job.schedule presence (e.g., mode = job.schedule ? job.schedule.mode ?? "cron" : "manual"), adjust ScheduleIcon to handle a "manual" case, and make scheduleValue return a "Manual" label (or use describeSchedule(job.schedule)) when job.schedule is undefined so unscheduled jobs render correctly. Ensure you update references to mode, ScheduleIcon, and scheduleValue accordingly.web/src/systems/network/lib/network-formatters.ts-189-203 (1)
189-203:⚠️ Potential issue | 🟡 MinorGuard invalid timestamps in sort comparators to avoid
NaNordering behavior.Both
sortNetworkChannelsandsortNetworkPeersparse timestamps without validating the result. If a malformed string reaches these functions,new Date(malformed).getTime()returnsNaN, breaking sort determinism when used in comparisons. This pattern is already handled correctly ingetPeerPresenceTone(line 141) which checksNumber.isNaN(parsed.getTime()).Extract timestamp parsing into a helper function that returns
0for both missing and invalid timestamps:Proposed fix
+function parseTimestampOrZero(value?: string | null): number { + if (!value) { + return 0; + } + const parsed = new Date(value).getTime(); + return Number.isNaN(parsed) ? 0 : parsed; +} + export function sortNetworkChannels(channels: NetworkChannelSummary[]) { return [...channels].sort((left, right) => { - const leftMessageTime = left.last_message_at ? new Date(left.last_message_at).getTime() : 0; - const rightMessageTime = right.last_message_at ? new Date(right.last_message_at).getTime() : 0; + const leftMessageTime = parseTimestampOrZero(left.last_message_at); + const rightMessageTime = parseTimestampOrZero(right.last_message_at);Apply the same fix to
sortNetworkPeers(lines 215–230) forlast_seen.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/network/lib/network-formatters.ts` around lines 189 - 203, The sort comparators use new Date(...).getTime() without validating and can produce NaN; add a small helper (e.g., safeTimestampMillis or parseTimestampToMillis) that accepts a string | undefined, returns 0 for undefined or invalid dates (use Number.isNaN(parsed.getTime()) to detect), and replace the direct new Date(...).getTime() calls inside sortNetworkChannels (left.last_message_at/right.last_message_at) and sortNetworkPeers (left.last_seen/right.last_seen) to use this helper so sorting remains deterministic for malformed timestamps.
🧹 Nitpick comments (17)
web/src/systems/workspace/adapters/workspace-api.ts (1)
30-32: Consider using a typed error class for consistency with other adapters.Per coding guidelines, API adapters should use typed error classes (e.g.,
WorkspaceApiError) rather than rawError. While this follows the existing pattern in the file, newer adapters likebridges-api.tsuseBridgesApiErrorwhich allows consumers to inspectstatusfor error handling.This is a pre-existing pattern, so deferring to a follow-up refactor is reasonable.
As per coding guidelines: "Use typed error classes in API adapters — never throw raw errors"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/workspace/adapters/workspace-api.ts` around lines 30 - 32, Replace the raw throw new Error(...) with throwing the typed WorkspaceApiError: when apiRequestFailed(response, error) is true, construct and throw new WorkspaceApiError(...) using the same message from defaultApiErrorMessage("Failed to fetch workspace", response, error) and include the HTTP status (from response.status) and original error details so callers can inspect .status; update the throw site in workspace-api.ts to use WorkspaceApiError instead of Error and ensure WorkspaceApiError is imported/available.internal/cli/cli_integration_test.go (1)
1170-1172: Prefer returning an empty provider slice from the test stub.Using an empty slice keeps list responses array-shaped in integration flows.
Suggested change
func (s *integrationBridgeService) ListProviders(context.Context) ([]bridgepkg.BridgeProvider, error) { - return nil, nil + return []bridgepkg.BridgeProvider{}, nil }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/cli/cli_integration_test.go` around lines 1170 - 1172, The test stub integrationBridgeService.ListProviders currently returns (nil, nil) which yields a null in list responses; change it to return an empty slice and nil error by returning []bridgepkg.BridgeProvider{} , nil so callers receive an empty array instead of null—update the ListProviders method on integrationBridgeService accordingly.internal/api/core/bridges.go (1)
38-52: PreferStatusForBridgeError(err)for consistency.This handler currently hard-codes
500for provider listing failures; usingStatusForBridgeError(err)would keep bridge error mapping consistent across endpoints.Proposed tweak
providers, err := bridges.ListProviders(c.Request.Context()) if err != nil { - h.respondError(c, http.StatusInternalServerError, err) + h.respondError(c, StatusForBridgeError(err), err) return }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/api/core/bridges.go` around lines 38 - 52, In ListBridgeProviders, replace the hard-coded http.StatusInternalServerError path when bridges.ListProviders returns an error by calling StatusForBridgeError(err) and passing that status into h.respondError so bridge errors are mapped consistently; locate the ListBridgeProviders method, the bridges.ListProviders call, and the h.respondError invocation and swap the fixed 500 status for StatusForBridgeError(err).web/src/systems/workspace/adapters/workspace-api.test.ts (1)
53-64: Add abort-signal coverage forfetchWorkspaceas well.The new test covers the success path, but it doesn’t validate signal propagation to
fetch, which is part of your list-query test contract.✅ Suggested test addition
describe("fetchWorkspace", () => { it("loads the resolved workspace detail payload", async () => { mockJsonResponse(mockWorkspaceDetail); const result = await fetchWorkspace("ws_alpha"); expect(result).toEqual(mockWorkspaceDetail); await expectFetchRequest({ path: "/api/workspaces/ws_alpha", }); }); + + it("passes an abort signal to fetch", async () => { + mockJsonResponse(mockWorkspaceDetail); + + const controller = new AbortController(); + await fetchWorkspace("ws_alpha", controller.signal); + + await expectFetchRequest({ + path: "/api/workspaces/ws_alpha", + signal: controller.signal, + }); + }); });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/workspace/adapters/workspace-api.test.ts` around lines 53 - 64, Add a test that verifies abort-signal propagation for fetchWorkspace by calling fetchWorkspace("ws_alpha", { signal }) with an AbortController.signal (or similar) and asserting the underlying fetch received that signal; reuse mockJsonResponse(mockWorkspaceDetail) and the existing expectFetchRequest helper to assert path "/api/workspaces/ws_alpha" and that the request options include the provided signal (or that fetch was called with the same signal). Ensure the new test mirrors the success test structure but passes an AbortController.signal and checks signal propagation to fetchWorkspace.web/src/systems/workspace/hooks/use-workspaces.ts (2)
12-16: Extract hook options into an interface.Please replace the inline object-shape type with a named
interfacefor consistency.Proposed type shape refactor
+interface UseWorkspaceOptions { + enabled?: boolean; +} + -export function useWorkspace(workspaceID: string, options?: { enabled?: boolean }) { +export function useWorkspace(workspaceID: string, options?: UseWorkspaceOptions) {As per coding guidelines,
web/**/*.ts?(x): "Useinterfacefor defining object shapes in TypeScript".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/workspace/hooks/use-workspaces.ts` around lines 12 - 16, Replace the inline options object type in the useWorkspace hook with a named interface: define an interface (e.g., WorkspaceHookOptions) that declares optional enabled?: boolean, update the function signature to use options?: WorkspaceHookOptions, and ensure the call-site logic (enabled: options?.enabled ?? Boolean(workspaceID)) and existing references to workspaceDetailOptions and useQuery remain unchanged.
5-5: Use@/*alias imports in this updated hook module.The new import should follow the project alias convention instead of relative paths.
Proposed import cleanup
-import { resolveWorkspace, type ResolveWorkspaceParams } from "../adapters/workspace-api"; -import { workspaceKeys } from "../lib/query-keys"; -import { workspaceDetailOptions, workspacesListOptions } from "../lib/query-options"; +import { resolveWorkspace, type ResolveWorkspaceParams } from "@/systems/workspace/adapters/workspace-api"; +import { workspaceKeys } from "@/systems/workspace/lib/query-keys"; +import { workspaceDetailOptions, workspacesListOptions } from "@/systems/workspace/lib/query-options";As per coding guidelines,
web/src/**/*.{ts,tsx}: "Use path alias@/*to map to./src/*for all imports".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/workspace/hooks/use-workspaces.ts` at line 5, Replace the relative import in use-workspaces.ts so it uses the project path alias instead of a relative path: change the import of workspaceDetailOptions and workspacesListOptions (currently from "../lib/query-options") to use the "@/..." alias that maps to ./src (e.g. import from "@/systems/workspace/lib/query-options"). Update the import statement only; keep the imported symbols workspaceDetailOptions and workspacesListOptions unchanged.internal/api/core/bridges_test.go (1)
199-233: Prefer table-driven subtests for the new provider handler test.Please convert this new case to a
t.Run("Should...")table-driven shape to match the test suite standard.As per coding guidelines,
**/*_test.go: "Use table-driven tests with subtests (t.Run) as default".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/api/core/bridges_test.go` around lines 199 - 233, Convert the flat TestBridgeHandlersListProviders into a table-driven subtest using t.Run: wrap the existing setup (newBridgeHandlerFixture with the stubbed ListProvidersFn), request (performRequest to "/bridges/providers"), assertions (status check, DecodeJSONResponse, length and field checks) into a subtest entry (e.g., name "Should list providers") inside a table of test cases and iterate running each case with t.Run; keep the same assertions and use the existing identifiers TestBridgeHandlersListProviders, newBridgeHandlerFixture, performRequest, and contract.BridgeProvidersResponse so the behavior is unchanged but now follows the suite standard of table-driven subtests.internal/api/udsapi/bridges_test.go (1)
127-159: Align this new UDS handler test with table-driven subtests.Please wrap this in
t.Run("Should...")table-driven structure for consistency with the repository’s Go test policy.As per coding guidelines,
**/*_test.go: "Use table-driven tests with subtests (t.Run) as default in Go tests" and "MUST use t.Run("Should...") pattern for ALL test cases".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/api/udsapi/bridges_test.go` around lines 127 - 159, Wrap the existing TestListBridgeProvidersHandlerReturnsRequestedPayload into a table-driven subtest using t.Run with a "Should..." description (e.g., t.Run("Should return requested payload", func(t *testing.T) { ... })), so the test body (setup of homePaths, stubBridgeService, engine via newTestRouter/newTestHandlersWithBridges, performRequest, decodeJSONResponse and assertions) is executed inside the subtest closure; keep the original test name and contents but move them into a single-entry table-driven structure (if you want to demonstrate the table pattern, you may create a slice of test cases and iterate with t.Run for each, but at minimum wrap the existing scenario in t.Run) ensuring TestListBridgeProvidersHandlerReturnsRequestedPayload still calls t.Parallel() outside or inside the subtest as appropriate.internal/extension/manifest_test.go (1)
467-505: Please refactor this new validation test intot.Run("Should...")subtests.The assertions are useful, but this new case should follow the suite’s required table-driven/subtest pattern.
As per coding guidelines,
**/*_test.go: "Use table-driven tests with subtests (t.Run) as default" and "MUST use t.Run("Should...") pattern for ALL test cases".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/extension/manifest_test.go` around lines 467 - 505, Refactor TestManifestValidate_RequiresBridgeMetadataForBridgeAdapters into multiple t.Run("Should...") subtests that each isolate one assertion: e.g., t.Run("Should return ErrManifestInvalid when bridge metadata missing") to create a fresh manifest via expectedManifest(), set manifest.Capabilities.Provides to include extensionprotocol.CapabilityProvideBridgeAdapter, call manifest.Validate() and assert errors.Is(err, ErrManifestInvalid) and errors.As to *ManifestValidationError with Field == "bridge.platform"; t.Run("Should require bridge.display_name after platform set") to set manifest.Bridge.Platform = "telegram", call Validate and assert validationErr.Field == "bridge.display_name"; and t.Run("Should pass when bridge metadata complete") to set manifest.Bridge.DisplayName = "Telegram" and assert Validate() returns nil; keep withDaemonVersion(t, "0.6.0") either once outside or in each subtest as appropriate.web/src/systems/bridges/hooks/use-bridge-actions.ts (1)
27-43: Consider optimistic updates for improved UX.Both mutation hooks correctly use
onSettledfor cache invalidation per guidelines. ForuseCreateBridge, optimistic updates aren't applicable since there's no prior state. However,useTestBridgeDeliverycould potentially benefit from an optimistic loading indicator pattern viaonMutate/onErrorsnapshots if the UI shows delivery test status.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/bridges/hooks/use-bridge-actions.ts` around lines 27 - 43, Add optimistic update handling to useTestBridgeDelivery: implement an onMutate in useTestBridgeDelivery that uses the queryClient to snapshot and optionally set a temporary "testing" state for the bridge (keyed by the bridge id), return the snapshot for rollback, and implement onError to restore the snapshot if the mutation fails; keep the existing onSettled to call invalidateBridgeQueries(queryClient, id) to refresh from server. Reference useTestBridgeDelivery, testBridgeDelivery, invalidateBridgeQueries, and queryClient when locating where to add onMutate and onError.web/src/systems/network/components/network-channels-list-panel.tsx (2)
17-25: ExtractChannelListItemprops into an interface.The inline object type here is out of step with the repository’s TypeScript shape rule. A small
ChannelListItemPropsinterface keeps this consistent with the rest ofweb/.As per coding guidelines, "Use
interfacefor defining object shapes in TypeScript (pattern is in Zod schemas and types)".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/network/components/network-channels-list-panel.tsx` around lines 17 - 25, Create a ChannelListItemProps interface and use it as the component props type instead of the inline object type: define interface ChannelListItemProps { channel: NetworkChannelSummary; isSelected: boolean; onSelect: () => void; } and update the ChannelListItem function signature to accept (props: ChannelListItemProps) or ({ channel, isSelected, onSelect }: ChannelListItemProps). This keeps the component consistent with the repo’s TypeScript shape rule and references the existing NetworkChannelSummary, isSelected, onSelect, and ChannelListItem symbols.
50-96: Add loading and error states to the panel API.This component can only render a filled list or an empty state, so routes have to special-case loading and failure outside the panel. That breaks the “component owns all states” rule for UI components in
web/.As per coding guidelines, "Handle all loading, error, and empty states in components — never assume
dataexists".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/network/components/network-channels-list-panel.tsx` around lines 50 - 96, NetworkChannelsListPanel currently only handles populated or empty lists; extend its API and rendering to own loading and error states by updating NetworkChannelsListPanelProps to include isLoading:boolean and error?:string (or Error) alongside existing props (channels, searchQuery, selectedChannel, onSearchChange, onSelectChannel), then update NetworkChannelsListPanel to: when isLoading render a centered loading indicator (with data-testid), when error render a centered error message (with data-testid), otherwise keep the existing empty/filled-channel rendering; ensure ChannelListItem usage and selection behavior remain unchanged.web/src/systems/network/components/network-peers-list-panel.tsx (2)
22-30: MovePeerListItemprops into an interface.The inline object type here breaks the repository’s TypeScript shape convention. Defining a
PeerListItemPropsinterface would keep this aligned with the rest of theweb/codebase.As per coding guidelines, "Use
interfacefor defining object shapes in TypeScript (pattern is in Zod schemas and types)".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/network/components/network-peers-list-panel.tsx` around lines 22 - 30, Create an interface named PeerListItemProps that declares isSelected: boolean, onSelect: () => void, and peer: NetworkPeerSummary, then replace the inline prop type in the PeerListItem function signature with PeerListItemProps (i.e., function PeerListItem(props: PeerListItemProps) or destructure with ({ isSelected, onSelect, peer }: PeerListItemProps)). Ensure the new interface is defined in the same module (and exported if other files import it) and update any usages that referenced the inline type.
66-112: Let the panel render loading and error states too.Right now this component only knows how to render a list or an empty state, so routes have to branch around it for loading/failure. That pushes state ownership out of the component and conflicts with the UI-state rule for
web/components.As per coding guidelines, "Handle all loading, error, and empty states in components — never assume
dataexists".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/network/components/network-peers-list-panel.tsx` around lines 66 - 112, NetworkPeersListPanel currently only renders peers or an empty state; update the component signature (NetworkPeersListPanel props) to accept isLoading: boolean and error?: Error|string (or similar) and use them to render three additional states: when isLoading true show a loading placeholder/spinner (eg. data-testid="network-peers-list-loading"), when error is present show an error message UI (eg. data-testid="network-peers-list-error"), and only fall back to the existing "No peers found" empty message when not loading and no error. Make sure the Input/search area remains visible in all states, keep existing PeerListItem rendering (peers.map) unchanged, and add the new testids so callers and tests can target loading/error states.internal/store/globaldb/global_db_network_messages_test.go (1)
97-121: Convert the guard-clause matrix into table-driven subtests.These nil-receiver / nil-context / closed-store checks all follow the same pattern, so a
t.Run("Should...")table would remove duplication and make future guard cases cheaper to add. As per coding guidelines, "Use table-driven tests with subtests (t.Run) as default".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/store/globaldb/global_db_network_messages_test.go` around lines 97 - 121, The test TestGlobalDBNetworkMessageGuardClauses is repetitive; convert it to a table-driven set of subtests using t.Run by defining a slice of cases (e.g., name, setup function returning receiver and ctx, operation enum or func type for WriteNetworkMessage/ListNetworkMessages, expected error predicate) and iterate running each case as a subtest; for each case call the appropriate method (referencing WriteNetworkMessage, ListNetworkMessages and Close) on nilDB/globalDB with nilGlobalContext or after Close as needed and assert the expected non-nil or store.ErrClosed error accordingly so the nil-receiver, nil-context and closed-store checks become compact subtests.web/src/routes/_app/bridges.tsx (1)
33-34: ImportWorkspacePageShellthrough the workspace barrel.This route is reaching into another system’s internals. Please re-export the shell from
@/systems/workspaceand import it from there so the boundary stays stable.As per coding guidelines, "Only import from cross-system dependencies through the public barrel export (
@/systems/<domain>), never reach into another system's internals".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/routes/_app/bridges.tsx` around lines 33 - 34, The import reaches into workspace internals by importing WorkspacePageShell from "@/systems/workspace/components/workspace-page-shell"; instead re-export WorkspacePageShell from the workspace public barrel (add export { WorkspacePageShell } from "./components/workspace-page-shell" in the "@/systems/workspace" index) and update this file to import WorkspacePageShell from "@/systems/workspace" (keep useActiveWorkspace import as-is) so the route only uses the public barrel export.web/src/systems/network/lib/network-formatters.ts (1)
151-154: Prefer aninterfacefor the metric card shape instead of an inline object type.Use a named
interfacefor this return shape to align with project TS conventions.Proposed refactor
+interface NetworkMetricCard { + detail?: string; + label: string; + value: string; +} + export function getNetworkMetricCards( status: NetworkStatus | undefined, channelCount: number -): Array<{ detail?: string; label: string; value: string }> { +): NetworkMetricCard[] {As per coding guidelines,
web/**/*.ts?(x): Useinterfacefor defining object shapes in TypeScript (pattern is in Zod schemas and types).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/systems/network/lib/network-formatters.ts` around lines 151 - 154, The return type of getNetworkMetricCards currently uses an inline object type; replace that inline type with a named interface (e.g., NetworkMetricCard) declared near the top of the file and use it in getNetworkMetricCards's signature and any related code. Define interface NetworkMetricCard { detail?: string; label: string; value: string } and update the function signature to return Array<NetworkMetricCard> (or NetworkMetricCard[]) so the shape follows the project's TypeScript conventions.
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (1)
web/src/routes/_app/-network.test.tsx (1)
74-76:⚠️ Potential issue | 🟠 MajorReplace
React.ReactNodewith the importedReactNodetype.Lines 74 and 327 reference
React.ReactNodebut onlyReactNodeis imported (line 3), not theReactnamespace. This causes TypeScript errors that will failmake web-typecheck.Proposed fix
- createFileRoute: () => (opts: { component: () => React.ReactNode }) => ({ + createFileRoute: () => (opts: { component: () => ReactNode }) => ({ component: opts.component, }),-const NetworkPage = (Route as unknown as { component: () => React.ReactNode }).component; +const NetworkPage = (Route as unknown as { component: () => ReactNode }).component;,
Also applies to: 327-327
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/routes/_app/-network.test.tsx` around lines 74 - 76, The type reference React.ReactNode used in createFileRoute should be replaced with the imported ReactNode type; update the signature in createFileRoute (and the other occurrence around the second reference) to use ReactNode instead of React.ReactNode so it matches the import (ReactNode) and fixes the TypeScript error.
🧹 Nitpick comments (1)
internal/api/core/network.go (1)
115-129: UseStatusForNetworkError(err)directly here.This branch now mirrors the same network-error allowlist already centralized in
internal/api/core/errors.go. The next error added there can silently regress to a 500 here until both places are updated.Possible simplification
channels, err := h.networkChannelPayloads(c.Request.Context(), service) if err != nil { - status := http.StatusInternalServerError - if errors.Is(err, ErrNetworkValidation) || - errors.Is(err, network.ErrLocalPeerNotFound) || - errors.Is(err, network.ErrTargetPeerNotFound) || - errors.Is(err, network.ErrMissingField) || - errors.Is(err, network.ErrInvalidField) || - errors.Is(err, network.ErrInvalidKind) || - errors.Is(err, network.ErrInvalidBody) || - errors.Is(err, network.ErrExpired) || - errors.Is(err, network.ErrReplayTooOld) { - status = StatusForNetworkError(err) - } - h.respondError(c, status, err) + h.respondError(c, StatusForNetworkError(err), err) return }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/api/core/network.go` around lines 115 - 129, The error handling in networkChannelPayloads duplicates an allowlist of network errors; replace the manual errors.Is checks with a single call to StatusForNetworkError(err) to derive the HTTP status and call h.respondError(c, StatusForNetworkError(err), err). Locate the block around the call to networkChannelPayloads and remove the long errors.Is chain (references: networkChannelPayloads, ErrNetworkValidation, network.ErrLocalPeerNotFound, network.ErrTargetPeerNotFound, network.ErrMissingField, network.ErrInvalidField, network.ErrInvalidKind, network.ErrInvalidBody, network.ErrExpired, network.ErrReplayTooOld) so the code always uses StatusForNetworkError(err) for the status.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@internal/api/core/network_test.go`:
- Around line 354-427: The test
TestBaseHandlersNetworkPeersUseBestEffortSessionEnrichment (and the other
top-level tests noted) should be converted into t.Run subtests following the
"Should..." pattern: wrap each logical assertion or endpoint scenario inside
t.Run("Should ...", func(t *testing.T){ ... }) and keep the existing setup
(localSessionID, brokenSessionID, manager, fixture, ListPeersFn,
request/response assertions) inside the subtest body; ensure each assertion
becomes its own subtest name (e.g., "Should return enriched display name for
local session", "Should fall back to peer card display name when status lookup
fails"), move t.Parallel() into individual subtests if parallelism is desired,
and apply the same refactor to the other top-level tests referenced (the blocks
covering lines 429-497, 499-601, 812-1404) so each endpoint/contract assertion
is a table-driven or named t.Run("Should...") subtest for clearer failure
localization.
In `@internal/network/audit_test.go`:
- Around line 120-173: The tests should be converted into t.Run subtests so
failures are isolated: update TestAuditWriterRecordsDeliveredDirection and
TestAuditWriterPersistsTimelineMessagesForSayEnvelopesForSayEnvelopesOnly to use
t.Run("Should ...") subtests around each behavior (e.g., a subtest for recording
delivered direction that calls NewAuditWriter, writer.RecordDelivered and
asserts storeSink.entries[0].Direction; and separate subtests inside the
PersistsTimeline... test for persisting messages, deduplication between
RecordSent/RecordReceived calls, and ignoring non-say envelopes that call
writer.RecordSent/RecordReceived/now and assert storeSink.messages contents such
as MessageID, Intent and Text). Keep existing setup (recordingAuditStore,
NewAuditWriter, writer.now) but move each logical assertion block into its own
t.Run with descriptive "Should..." names and maintain t.Parallel() at the top of
each parent test.
In `@internal/network/audit.go`:
- Around line 124-131: normalizeTimelineMessageEntry is being called regardless
of w.messageStore and WriteNetworkMessage may run even if WriteNetworkAudit
failed, causing failures for file-only writers and orphan timeline rows; change
the sequence in RecordSent/RecordReceived so that you first attempt the audit
write via w.store.WriteNetworkAudit(ctx, entry) (keep existing join behavior),
then only if w.messageStore != nil proceed to call
normalizeTimelineMessageEntry(sessionID, direction, envelope, entry.Timestamp)
and handle its error, and only after normalize succeeds call
w.messageStore.WriteNetworkMessage(ctx, messageEntry); ensure that if the audit
write returns an error you skip the message write to avoid orphan rows and that
normalization is never invoked when w.messageStore == nil so normalization
errors cannot break audit-only flows.
In `@web/src/systems/bridges/components/bridge-create-dialog.test.tsx`:
- Around line 4-5: Replace the two relative imports with project path-alias
imports so the test uses the "@/..." alias convention: update the import for
BridgeCreateDraft (currently from "../types") to import from
"@/systems/bridges/types" and update the import for BridgeCreateDialog
(currently from "./bridge-create-dialog") to import from
"@/systems/bridges/components/bridge-create-dialog"; ensure the imported symbols
BridgeCreateDraft and BridgeCreateDialog remain unchanged.
---
Duplicate comments:
In `@web/src/routes/_app/-network.test.tsx`:
- Around line 74-76: The type reference React.ReactNode used in createFileRoute
should be replaced with the imported ReactNode type; update the signature in
createFileRoute (and the other occurrence around the second reference) to use
ReactNode instead of React.ReactNode so it matches the import (ReactNode) and
fixes the TypeScript error.
---
Nitpick comments:
In `@internal/api/core/network.go`:
- Around line 115-129: The error handling in networkChannelPayloads duplicates
an allowlist of network errors; replace the manual errors.Is checks with a
single call to StatusForNetworkError(err) to derive the HTTP status and call
h.respondError(c, StatusForNetworkError(err), err). Locate the block around the
call to networkChannelPayloads and remove the long errors.Is chain (references:
networkChannelPayloads, ErrNetworkValidation, network.ErrLocalPeerNotFound,
network.ErrTargetPeerNotFound, network.ErrMissingField, network.ErrInvalidField,
network.ErrInvalidKind, network.ErrInvalidBody, network.ErrExpired,
network.ErrReplayTooOld) so the code always uses StatusForNetworkError(err) for
the status.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 7da7840f-ccfb-4d52-9258-638fc32e9915
⛔ Files ignored due to path filters (95)
.agents/skills/compozy/SKILL.mdis excluded by!**/*.md,!.agents/**.agents/skills/compozy/references/cli-reference.mdis excluded by!**/*.md,!.agents/**.agents/skills/compozy/references/skills-reference.mdis excluded by!**/*.md,!.agents/**.agents/skills/compozy/references/workflow-guide.mdis excluded by!**/*.md,!.agents/**.agents/skills/karpathy-kb/SKILL.mdis excluded by!**/*.md,!.agents/**.agents/skills/karpathy-kb/assets/concept-index-template.mdis excluded by!**/*.md,!.agents/**.agents/skills/karpathy-kb/assets/dashboard-template.mdis excluded by!**/*.md,!.agents/**.agents/skills/karpathy-kb/assets/log-template.mdis excluded by!**/*.md,!.agents/**.agents/skills/karpathy-kb/assets/source-index-template.mdis excluded by!**/*.md,!.agents/**.agents/skills/karpathy-kb/assets/topic-claude-template.mdis excluded by!**/*.md,!.agents/**.agents/skills/karpathy-kb/assets/wiki-article-template.mdis excluded by!**/*.md,!.agents/**.agents/skills/karpathy-kb/scripts/lint-wiki.pyis excluded by!.agents/**.agents/skills/karpathy-kb/scripts/new-topic.shis excluded by!.agents/**.agents/skills/kb/SKILL.mdis excluded by!**/*.md,!.agents/**.agents/skills/kb/references/architecture.mdis excluded by!**/*.md,!.agents/**.agents/skills/kb/references/cli-ingest-codebase.mdis excluded by!**/*.md,!.agents/**.agents/skills/kb/references/cli-inspect.mdis excluded by!**/*.md,!.agents/**.agents/skills/kb/references/cli-search-index.mdis excluded by!**/*.md,!.agents/**.agents/skills/kb/references/compilation-guide.mdis excluded by!**/*.md,!.agents/**.agents/skills/kb/references/error-handling.mdis excluded by!**/*.md,!.agents/**.agents/skills/kb/references/frontmatter-schemas.mdis excluded by!**/*.md,!.agents/**.agents/skills/kb/references/lint-procedure.mdis excluded by!**/*.md,!.agents/**.agents/skills/kb/references/output-formats.mdis excluded by!**/*.md,!.agents/**.agents/skills/kb/references/tooling-tips.mdis excluded by!**/*.md,!.agents/**.codex/plans/2026-04-13-automation-bridges-paper-redesign.mdis excluded by!**/*.md.codex/plans/2026-04-13-network-paper-pages.mdis excluded by!**/*.md.compozy/tasks/core-tasks/_tasks.mdis excluded by!**/*.md.compozy/tasks/core-tasks/_techspec.mdis excluded by!**/*.md.compozy/tasks/core-tasks/adrs/adr-001.mdis excluded by!**/*.md.compozy/tasks/core-tasks/adrs/adr-002.mdis excluded by!**/*.md.compozy/tasks/core-tasks/adrs/adr-003.mdis excluded by!**/*.md.compozy/tasks/core-tasks/adrs/adr-004.mdis excluded by!**/*.md.compozy/tasks/core-tasks/adrs/adr-005.mdis excluded by!**/*.md.compozy/tasks/core-tasks/adrs/adr-006.mdis excluded by!**/*.md.compozy/tasks/core-tasks/analysis/analysis_agh-harness.mdis excluded by!**/*.md.compozy/tasks/core-tasks/analysis/analysis_goclaw.mdis excluded by!**/*.md.compozy/tasks/core-tasks/analysis/analysis_multica.mdis excluded by!**/*.md.compozy/tasks/core-tasks/analysis/analysis_paperclip.mdis excluded by!**/*.md.compozy/tasks/core-tasks/review-round-1.mdis excluded by!**/*.md.compozy/tasks/core-tasks/task_01.mdis excluded by!**/*.md.compozy/tasks/core-tasks/task_02.mdis excluded by!**/*.md.compozy/tasks/core-tasks/task_03.mdis excluded by!**/*.md.compozy/tasks/core-tasks/task_04.mdis excluded by!**/*.md.compozy/tasks/core-tasks/task_05.mdis excluded by!**/*.md.compozy/tasks/core-tasks/task_06.mdis excluded by!**/*.md.compozy/tasks/core-tasks/task_07.mdis excluded by!**/*.md.compozy/tasks/core-tasks/task_08.mdis excluded by!**/*.md.compozy/tasks/core-tasks/task_09.mdis excluded by!**/*.md.compozy/tasks/core-tasks/task_10.mdis excluded by!**/*.md.compozy/tasks/core-tasks/task_11.mdis excluded by!**/*.md.compozy/tasks/core-tasks/task_12.mdis excluded by!**/*.md.compozy/tasks/core-tasks/task_13.mdis excluded by!**/*.md.compozy/tasks/extension-registry/_tasks.mdis excluded by!**/*.md.compozy/tasks/extension-registry/_techspec.mdis excluded by!**/*.md.compozy/tasks/extension-registry/adrs/adr-001.mdis excluded by!**/*.md.compozy/tasks/extension-registry/adrs/adr-002.mdis excluded by!**/*.md.compozy/tasks/extension-registry/adrs/adr-003.mdis excluded by!**/*.md.compozy/tasks/extension-registry/adrs/adr-004.mdis excluded by!**/*.md.compozy/tasks/extension-registry/task_01.mdis excluded by!**/*.md.compozy/tasks/extension-registry/task_02.mdis excluded by!**/*.md.compozy/tasks/extension-registry/task_03.mdis excluded by!**/*.md.compozy/tasks/extension-registry/task_04.mdis excluded by!**/*.md.compozy/tasks/extension-registry/task_05.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/_meta.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_001.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_002.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_003.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_004.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_005.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_006.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_007.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_008.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_009.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_010.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_011.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_012.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_013.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_014.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_015.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_016.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_017.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_018.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_019.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_020.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_021.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_022.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_023.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_024.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_025.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_026.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_027.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_028.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_029.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_030.mdis excluded by!**/*.md.compozy/tasks/web-pages/reviews-001/issue_031.mdis excluded by!**/*.md
📒 Files selected for processing (47)
internal/api/core/bridges.gointernal/api/core/bridges_test.gointernal/api/core/network.gointernal/api/core/network_details.gointernal/api/core/network_test.gointernal/api/httpapi/httpapi_integration_test.gointernal/api/udsapi/bridges_test.gointernal/cli/cli_integration_test.gointernal/daemon/bridges.gointernal/daemon/bridges_test.gointernal/extension/manifest_test.gointernal/network/audit.gointernal/network/audit_test.gointernal/store/globaldb/global_db_network_messages.gointernal/store/globaldb/global_db_network_messages_test.goweb/src/routes/_app/-automation.integration.test.tsxweb/src/routes/_app/-bridges.test.tsxweb/src/routes/_app/-network.test.tsxweb/src/routes/_app/automation.tsxweb/src/routes/_app/bridges.tsxweb/src/routes/_app/network.tsxweb/src/systems/automation/components/automation-detail-panel.test.tsxweb/src/systems/automation/components/automation-detail-panel.tsxweb/src/systems/automation/components/automation-job-form.test.tsxweb/src/systems/automation/components/automation-job-form.tsxweb/src/systems/automation/lib/automation-formatters.test.tsweb/src/systems/automation/lib/automation-formatters.tsweb/src/systems/bridges/components/bridge-create-dialog.test.tsxweb/src/systems/bridges/components/bridge-create-dialog.tsxweb/src/systems/bridges/components/bridge-empty-state.tsxweb/src/systems/bridges/components/bridge-list-panel.tsxweb/src/systems/bridges/components/bridge-provider-card.tsxweb/src/systems/bridges/components/bridge-test-delivery-dialog.tsxweb/src/systems/bridges/lib/bridge-drafts.tsweb/src/systems/bridges/lib/bridge-formatters.tsweb/src/systems/bridges/lib/query-options.test.tsweb/src/systems/network/components/network-channels-list-panel.tsxweb/src/systems/network/components/network-create-channel-dialog.tsxweb/src/systems/network/components/network-peers-list-panel.tsxweb/src/systems/network/hooks/use-network-actions.tsweb/src/systems/network/lib/network-formatters.tsweb/src/systems/session/components/message-bubble.tsxweb/src/systems/workspace/adapters/workspace-api.test.tsweb/src/systems/workspace/adapters/workspace-api.tsweb/src/systems/workspace/hooks/use-workspaces.test.tsxweb/src/systems/workspace/hooks/use-workspaces.tsweb/src/systems/workspace/index.ts
✅ Files skipped from review due to trivial changes (3)
- web/src/systems/automation/components/automation-detail-panel.test.tsx
- web/src/routes/_app/-bridges.test.tsx
- web/src/systems/automation/lib/automation-formatters.ts
🚧 Files skipped from review as they are similar to previous changes (11)
- internal/cli/cli_integration_test.go
- web/src/systems/automation/components/automation-job-form.test.tsx
- internal/api/udsapi/bridges_test.go
- internal/extension/manifest_test.go
- internal/store/globaldb/global_db_network_messages_test.go
- web/src/systems/automation/lib/automation-formatters.test.ts
- internal/store/globaldb/global_db_network_messages.go
- web/src/routes/_app/-automation.integration.test.tsx
- internal/daemon/bridges.go
- web/src/routes/_app/automation.tsx
- internal/api/core/network_details.go
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
web/src/routes/_app/-network.test.tsx (2)
208-208: Use the@/path alias for this import.Line 208 uses a relative import (
"./network"), which violates the project import rule for web source files.Suggested change
-import { Route } from "./network"; +import { Route } from "@/routes/_app/network";As per coding guidelines, "Use path alias
@/*to map to./src/*for all imports".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/routes/_app/-network.test.tsx` at line 208, The test file -network.test.tsx imports Route via a relative path ("./network"); replace that with the project path alias so the import uses "@/routes/_app/network" (i.e., import { Route } from "@/routes/_app/network") to satisfy the web source file import rule and keep the reference to the Route symbol intact.
61-66: Replace inline object-shape type literals with interfaces.These segments define object shapes inline; this file should use
interfacedeclarations instead for object-shape types.Suggested change
+interface MockLinkProps { + children: ReactNode; + params?: { id?: string }; + to: string; + [key: string]: unknown; +} + +interface MockWorkspacePageShellProps { + children: ReactNode; + controls?: ReactNode; + meta?: ReactNode; + title: string; +} + +interface RouteWithComponent { + component: () => ReactNode; +} + vi.mock("@tanstack/react-router", () => ({ Link: ({ children, to, params, ...props - }: { - children: ReactNode; - params?: { id?: string }; - to: string; - [key: string]: unknown; - }) => { + }: MockLinkProps) => { @@ - createFileRoute: () => (opts: { component: () => ReactNode }) => ({ + createFileRoute: () => (opts: RouteWithComponent) => ({ component: opts.component, }), })); @@ WorkspacePageShell: ({ children, controls, meta, title, - }: { - children: ReactNode; - controls?: ReactNode; - meta?: ReactNode; - title: string; - }) => ( + }: MockWorkspacePageShellProps) => ( @@ -const NetworkPage = (Route as unknown as { component: () => ReactNode }).component; +const NetworkPage = (Route as unknown as RouteWithComponent).component;As per coding guidelines, "
web/**/*.ts?(x): Useinterfacefor defining object shapes in TypeScript (pattern is in Zod schemas and types)".Also applies to: 89-94, 327-327
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/routes/_app/-network.test.tsx` around lines 61 - 66, Replace the inline object-shape type literal used for the component props (the parameter typed in the block starting with "}: { children: ReactNode; params?: { id?: string }; to: string; [key: string]: unknown; }) => {") with a named interface (e.g., NetworkLinkProps) and use that interface for the parameter type; do the same for the other inline object-shape literals referenced (the shapes around lines 89-94 and at 327) by declaring appropriately named interfaces and swapping the inline types for those interface names so all object-shape types in this file use interface declarations.internal/api/core/network_test.go (1)
357-1438: Consider addingt.Parallel()inside independent new subtests.Most of these
t.Run("Should ...")cases build isolated fixtures and can run safely in parallel to keep suite runtime lower.As per coding guidelines, "Use
t.Parallel()for independent subtests in Go tests."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/api/core/network_test.go` around lines 357 - 1438, Many subtests (e.g. the "Should enrich local peers..." case, and subtests inside TestBaseHandlersNetworkErrorsAndDisabledMode like "ShouldReturnDisabledStatus", "ShouldReturnServiceUnavailableWhenNetworkServiceMissing", "ShouldMapNetworkStatusErrorTo500", etc.) are missing t.Parallel(), so they don't run concurrently; add t.Parallel() as the first line inside each independent t.Run closure (for examples see subtests with titles "Should enrich local peers and fall back to peer-card display names on lookup failures", and all "Should..." subtests within TestBaseHandlersNetworkErrorsAndDisabledMode, TestValidationErrorHelpersPreserveInnerErrorChain, TestBaseHandlersNetworkChannelEndpointsIgnoreStoppedSessions, TestBaseHandlersNetworkChannelMessagesPreserveRemoteAuthors, TestBaseHandlersCreateNetworkChannelCreatesSessionsPerAgent, TestBaseHandlersNetworkPeerDetailUsesAuditMetrics) to mark them parallel-safe and reduce overall test runtime.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@web/src/routes/_app/-network.test.tsx`:
- Around line 504-513: The toast.success assertion is currently synchronous and
can race with the mutation; change it to be asserted asynchronously by awaiting
a waitFor that checks toast.success was called with "Created channel
deployments." (i.e., replace the immediate
expect(toast.success).toHaveBeenCalledWith(...) with await waitFor(() =>
expect(toast.success).toHaveBeenCalledWith("Created channel deployments."))).
Keep the existing waitFor for mockCreateNetworkChannelMutateAsync and the
reference to mockCreateNetworkChannelMutateAsync and toast.success so the test
reliably waits for the toast dispatch.
---
Nitpick comments:
In `@internal/api/core/network_test.go`:
- Around line 357-1438: Many subtests (e.g. the "Should enrich local peers..."
case, and subtests inside TestBaseHandlersNetworkErrorsAndDisabledMode like
"ShouldReturnDisabledStatus",
"ShouldReturnServiceUnavailableWhenNetworkServiceMissing",
"ShouldMapNetworkStatusErrorTo500", etc.) are missing t.Parallel(), so they
don't run concurrently; add t.Parallel() as the first line inside each
independent t.Run closure (for examples see subtests with titles "Should enrich
local peers and fall back to peer-card display names on lookup failures", and
all "Should..." subtests within TestBaseHandlersNetworkErrorsAndDisabledMode,
TestValidationErrorHelpersPreserveInnerErrorChain,
TestBaseHandlersNetworkChannelEndpointsIgnoreStoppedSessions,
TestBaseHandlersNetworkChannelMessagesPreserveRemoteAuthors,
TestBaseHandlersCreateNetworkChannelCreatesSessionsPerAgent,
TestBaseHandlersNetworkPeerDetailUsesAuditMetrics) to mark them parallel-safe
and reduce overall test runtime.
In `@web/src/routes/_app/-network.test.tsx`:
- Line 208: The test file -network.test.tsx imports Route via a relative path
("./network"); replace that with the project path alias so the import uses
"@/routes/_app/network" (i.e., import { Route } from "@/routes/_app/network") to
satisfy the web source file import rule and keep the reference to the Route
symbol intact.
- Around line 61-66: Replace the inline object-shape type literal used for the
component props (the parameter typed in the block starting with "}: { children:
ReactNode; params?: { id?: string }; to: string; [key: string]: unknown; }) =>
{") with a named interface (e.g., NetworkLinkProps) and use that interface for
the parameter type; do the same for the other inline object-shape literals
referenced (the shapes around lines 89-94 and at 327) by declaring appropriately
named interfaces and swapping the inline types for those interface names so all
object-shape types in this file use interface declarations.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: a8dc484f-8eda-4c43-b7fd-e5abd170564d
📒 Files selected for processing (6)
internal/api/core/network.gointernal/api/core/network_test.gointernal/network/audit.gointernal/network/audit_test.goweb/src/routes/_app/-network.test.tsxweb/src/systems/bridges/components/bridge-create-dialog.test.tsx
✅ Files skipped from review due to trivial changes (1)
- internal/network/audit.go
🚧 Files skipped from review as they are similar to previous changes (1)
- internal/network/audit_test.go
| await waitFor(() => | ||
| expect(mockCreateNetworkChannelMutateAsync).toHaveBeenCalledWith({ | ||
| agent_names: ["polybot-main", "coder-agent-01"], | ||
| channel: "deployments", | ||
| workspace_id: "ws_main", | ||
| }) | ||
| ); | ||
| expect(mockCreateNetworkChannelMutateAsync).toHaveBeenCalledOnce(); | ||
| expect(toast.success).toHaveBeenCalledWith("Created channel deployments."); | ||
| }); |
There was a problem hiding this comment.
Make the toast success assertion asynchronous to avoid timing flakiness.
toast.success is asserted immediately after waitFor on mutation call. If toast dispatch happens on a later microtask, this can become flaky.
Suggested change
- expect(mockCreateNetworkChannelMutateAsync).toHaveBeenCalledOnce();
- expect(toast.success).toHaveBeenCalledWith("Created channel deployments.");
+ expect(mockCreateNetworkChannelMutateAsync).toHaveBeenCalledOnce();
+ await waitFor(() => {
+ expect(toast.success).toHaveBeenCalledWith("Created channel deployments.");
+ });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/routes/_app/-network.test.tsx` around lines 504 - 513, The
toast.success assertion is currently synchronous and can race with the mutation;
change it to be asserted asynchronously by awaiting a waitFor that checks
toast.success was called with "Created channel deployments." (i.e., replace the
immediate expect(toast.success).toHaveBeenCalledWith(...) with await waitFor(()
=> expect(toast.success).toHaveBeenCalledWith("Created channel deployments."))).
Keep the existing waitFor for mockCreateNetworkChannelMutateAsync and the
reference to mockCreateNetworkChannelMutateAsync and toast.success so the test
reliably waits for the toast dispatch.
There was a problem hiding this comment.
🧹 Nitpick comments (4)
web/src/routes/_app/network.tsx (3)
333-343: Consider extracting inline handlers for dialog props.The inline arrow functions for
onChannelNameChangeandonToggleAgentcreate new references on each render. For a top-level route component this is typically acceptable, but extracting them touseCallbackhooks would prevent unnecessary re-renders ofNetworkCreateChannelDialogif it's memoized.♻️ Optional extraction pattern
+ const handleChannelNameChange = useCallback((channelName: string) => { + setCreateDraft(currentDraft => ({ + ...currentDraft, + channelName, + })); + }, []); + + const handleToggleAgent = useCallback((agentName: string) => { + setCreateDraft(currentDraft => toggleDraftAgent(currentDraft, agentName)); + }, []); + // Then in JSX: - onChannelNameChange={channelName => - setCreateDraft(currentDraft => ({ - ...currentDraft, - channelName, - })) - } + onChannelNameChange={handleChannelNameChange} ... - onToggleAgent={agentName => - setCreateDraft(currentDraft => toggleDraftAgent(currentDraft, agentName)) - } + onToggleAgent={handleToggleAgent}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/routes/_app/network.tsx` around lines 333 - 343, The inline arrow props for onChannelNameChange and onToggleAgent are recreated each render and can trigger unnecessary re-renders of NetworkCreateChannelDialog; extract them into stable callbacks using useCallback (e.g., define handleChannelNameChange = useCallback(channelName => setCreateDraft(d => ({ ...d, channelName })), [setCreateDraft]) and handleToggleAgent = useCallback(agentName => setCreateDraft(d => toggleDraftAgent(d, agentName)), [setCreateDraft, toggleDraftAgent]) and then pass these handlers (and keep onOpenChange={setCreateDialogOpen} and onSubmit={handleCreateChannel}) to the dialog to maintain identical behavior while providing stable function references.
110-123: Redundant condition checks in loading state logic.
isNetworkStatusLoading(line 55) already includes the!networkStatusQuery.datacheck. The additional&& !networkStatusQuery.dataon lines 112 and 119 is redundant.♻️ Proposed simplification
const isChannelsListLoading = !isNetworkDisabled && - ((isNetworkStatusLoading && !networkStatusQuery.data) || + (isNetworkStatusLoading || (networkChannelsQuery.isLoading && !networkChannelsQuery.data)); const channelsListError = !isNetworkDisabled ? (networkStatusError ?? (!networkChannelsQuery.data ? networkChannelsQuery.error : null)) : null; const isPeersListLoading = !isNetworkDisabled && - ((isNetworkStatusLoading && !networkStatusQuery.data) || + (isNetworkStatusLoading || (networkPeersQuery.isLoading && !networkPeersQuery.data));🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/routes/_app/network.tsx` around lines 110 - 123, The loading checks for isChannelsListLoading and isPeersListLoading duplicate the "!networkStatusQuery.data" condition because isNetworkStatusLoading already encodes that; update the two expressions (the ones assigning isChannelsListLoading and isPeersListLoading) to remove the redundant "&& !networkStatusQuery.data" clause so each becomes: not disabled AND (isNetworkStatusLoading || networkChannelsQuery.isLoading && !networkChannelsQuery.data) (and similarly for networkPeersQuery) — locate the assignments to isChannelsListLoading and isPeersListLoading in network.tsx and simplify those boolean expressions accordingly while leaving channelsListError and peersListError logic unchanged.
82-96: Auto-selection may shift unexpectedly when sort order changes.The effective selection falls back to
visibleChannels[0]orvisiblePeers[0]when the prior selection is no longer in the filtered list. PersortNetworkChannels, channels are sorted bylast_message_atdescending—new incoming messages can reorder the list and silently move the user's focus to a different item.If preserving user selection is important, consider only auto-selecting on initial mount or when the list transitions from empty to populated, rather than on every filter/sort change.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/routes/_app/network.tsx` around lines 82 - 96, The current auto-selection logic in effectiveSelectedChannel and effectiveSelectedPeerId causes focus to jump when sortNetworkChannels reorders visibleChannels/visiblePeers; change the logic to only auto-select when the component first mounts or when the visible list transitions from empty to non-empty (instead of on every change). Implement this by tracking a ref or previous length (e.g., hasAutoSelectedChannel/hasAutoSelectedPeer or prevVisibleChannelsLength/prevVisiblePeersLength) and only fall back to visibleChannels[0]?.channel or visiblePeers[0]?.peer_id when the ref is false or previous length was 0; after performing the initial auto-select set the ref to true so subsequent sorts/filters won’t override an existing user-selected selectedChannel/selectedPeerId. Ensure both effectiveSelectedChannel and effectiveSelectedPeerId use the same pattern and keep sortNetworkChannels behavior unchanged.web/src/routes/_app/automation.tsx (1)
75-83: Consider extracting parameter type to an interface.The inline object type for
buildEmptyStateparameters could be extracted to a named interface for consistency with the coding guideline "Useinterfacefor defining object shapes."♻️ Suggested refactor
+interface BuildEmptyStateParams { + activeTab: AutomationTab; + hasQuery: boolean; + onCreate: () => void; +} + -function buildEmptyState({ - activeTab, - hasQuery, - onCreate, -}: { - activeTab: AutomationTab; - hasQuery: boolean; - onCreate: () => void; -}) { +function buildEmptyState({ activeTab, hasQuery, onCreate }: BuildEmptyStateParams) {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/routes/_app/automation.tsx` around lines 75 - 83, The inline parameter object for the buildEmptyState function should be extracted into a named interface (e.g., BuildEmptyStateProps) to follow the project guideline of using interface for object shapes; create the interface with properties activeTab: AutomationTab, hasQuery: boolean, and onCreate: () => void, then update the buildEmptyState signature to accept (props: BuildEmptyStateProps) and update any call sites accordingly to pass the same object shape.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@web/src/routes/_app/automation.tsx`:
- Around line 75-83: The inline parameter object for the buildEmptyState
function should be extracted into a named interface (e.g., BuildEmptyStateProps)
to follow the project guideline of using interface for object shapes; create the
interface with properties activeTab: AutomationTab, hasQuery: boolean, and
onCreate: () => void, then update the buildEmptyState signature to accept
(props: BuildEmptyStateProps) and update any call sites accordingly to pass the
same object shape.
In `@web/src/routes/_app/network.tsx`:
- Around line 333-343: The inline arrow props for onChannelNameChange and
onToggleAgent are recreated each render and can trigger unnecessary re-renders
of NetworkCreateChannelDialog; extract them into stable callbacks using
useCallback (e.g., define handleChannelNameChange = useCallback(channelName =>
setCreateDraft(d => ({ ...d, channelName })), [setCreateDraft]) and
handleToggleAgent = useCallback(agentName => setCreateDraft(d =>
toggleDraftAgent(d, agentName)), [setCreateDraft, toggleDraftAgent]) and then
pass these handlers (and keep onOpenChange={setCreateDialogOpen} and
onSubmit={handleCreateChannel}) to the dialog to maintain identical behavior
while providing stable function references.
- Around line 110-123: The loading checks for isChannelsListLoading and
isPeersListLoading duplicate the "!networkStatusQuery.data" condition because
isNetworkStatusLoading already encodes that; update the two expressions (the
ones assigning isChannelsListLoading and isPeersListLoading) to remove the
redundant "&& !networkStatusQuery.data" clause so each becomes: not disabled AND
(isNetworkStatusLoading || networkChannelsQuery.isLoading &&
!networkChannelsQuery.data) (and similarly for networkPeersQuery) — locate the
assignments to isChannelsListLoading and isPeersListLoading in network.tsx and
simplify those boolean expressions accordingly while leaving channelsListError
and peersListError logic unchanged.
- Around line 82-96: The current auto-selection logic in
effectiveSelectedChannel and effectiveSelectedPeerId causes focus to jump when
sortNetworkChannels reorders visibleChannels/visiblePeers; change the logic to
only auto-select when the component first mounts or when the visible list
transitions from empty to non-empty (instead of on every change). Implement this
by tracking a ref or previous length (e.g.,
hasAutoSelectedChannel/hasAutoSelectedPeer or
prevVisibleChannelsLength/prevVisiblePeersLength) and only fall back to
visibleChannels[0]?.channel or visiblePeers[0]?.peer_id when the ref is false or
previous length was 0; after performing the initial auto-select set the ref to
true so subsequent sorts/filters won’t override an existing user-selected
selectedChannel/selectedPeerId. Ensure both effectiveSelectedChannel and
effectiveSelectedPeerId use the same pattern and keep sortNetworkChannels
behavior unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 20b4f36c-8bc5-4495-965d-e1133ae76eb5
⛔ Files ignored due to path filters (8)
.agents/skills/systematic-qa/SKILL.mdis excluded by!**/*.md,!.agents/**.agents/skills/systematic-qa/assets/issue-template.mdis excluded by!**/*.md,!.agents/**.agents/skills/systematic-qa/assets/verification-report-template.mdis excluded by!**/*.md,!.agents/**.agents/skills/systematic-qa/references/checklist.mdis excluded by!**/*.md,!.agents/**.agents/skills/systematic-qa/references/project-signals.mdis excluded by!**/*.md,!.agents/**.agents/skills/systematic-qa/scripts/discover-project-contract.pyis excluded by!.agents/**docs/ideas/qa-e2e/README.mdis excluded by!**/*.mdskills-lock.jsonis excluded by!**/*.json
📒 Files selected for processing (13)
web/src/routes/_app/-automation.integration.test.tsxweb/src/routes/_app/-network.test.tsxweb/src/routes/_app/automation.tsxweb/src/routes/_app/network.tsxweb/src/systems/automation/components/automation-job-form.test.tsxweb/src/systems/automation/components/automation-job-form.tsxweb/src/systems/automation/components/automation-trigger-form.test.tsxweb/src/systems/automation/components/automation-trigger-form.tsxweb/src/systems/automation/index.tsweb/src/systems/automation/lib/automation-drafts.test.tsweb/src/systems/automation/lib/automation-drafts.tsweb/src/systems/network/hooks/use-network.tsweb/src/systems/network/lib/query-options.ts
✅ Files skipped from review due to trivial changes (1)
- web/src/routes/_app/-network.test.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- web/src/systems/automation/components/automation-job-form.test.tsx
## Release v0.0.1 This PR prepares the release of version v0.0.1. ### Changelog ## 0.0.1 - 2026-05-26 ### Other Changes - Lessons learned ### ♻️ Refactoring - Project structure (#7) - Kb improvements (#12) - Rename spaces to channels (#17) - Add extensions gaps (#21) - Improve tool calls ui (#22) - Remove web app header - Module improvements (#29) - Memory improvements (#35) - Storybook for web and ui (#38) - Enable AGH network by default for new installs (#57) - Hermes adjustments (#69) - Badges design (#84) - Storybook scenario and logos gallery - Migrate typescript tests (#114) - Internal go packages (#120) - Ui patterns (#127) - Improve e2e tests (#130) - Ui redesign - Workspace isolation across runtime surfaces (#145) - Prod ready applies (#162) - Tool card ui (#164) - Alpha on logo - Prod ready features (#167) - Thread sheet (#202) ### 🎉 Features - Implement config foundation packages - Implement sqlite store package - Add ACP client package - Add session lifecycle manager - Implement observe package - Add daemon composition root - Add uds api server - Implement cli package - Add http api server - Add system design - Add foundation types, schemas, and layout shell for web client - Add daemon health polling and agent sidebar systems for web client - Add session system CRUD, streaming core, and session store for web client - Add chat view, messages, and composer tests for web client - Add tool cards and renderers for web client - Add file-backed memory store core - Scaffold memory session seams - Add memory dream consolidation service - Wire memory assembler into daemon - Add memory api and cli - New skills system (#1) - Add workspace entity (#5) - Add new skill capabilities (#8) - Web ui v2 (#9) - Improve hooks system (#10) - Session resilience (#11) - Add extensability (#13) - Add automation (#16) - Add channels (#14) - Add network implementation (#15) - Add network, bridges and automations web pages (#18) - Ext registry (#20) - Add core tasks (#19) - Bridge adapters (#23) - Add site (#26) - Add ext refac and sandbox (#25) - Settings ui (#37) - Tasks ui (#36) - Harness improvements (#44) - Agent capabilities (#49) - Redesign ui (#48) - Unify capability (#53) - Redesign network workspace (#59) - Add task deletion and split session delete from stop (#58) - Session provider selection (#60) - Production grade adjustments (#66) - Autonomous system (#75) - Add agent session route (#80) - Tools registry (#85) - Agents soul (#88) - Add network threads (#105) - Orchestration improvements (#106) - Memory v2 (#108) - Agent categories (#113) - Providers model (#118) - Add canonical AGH bundled skill (#143) - Onboarding and improvements (#198) - Onboarding and improvements (#201) ### 🐛 Bug Fixes - Review round - Review rounds - Resolve memory extensibility review batch - Embed web into daemon - Defaults agents - Acp integration (#4) - Lint errors - Prd folder - Remove orphan web actions and dead surfaces (#55) - Qa testing and fixes (#73) - New review rounds (#82) - Security audit (#90) - Release qa round (#95) - Add missing tools (#141) - New qa round (#147) - Advanced qa round (#149) - Homebrew tap - Final review round (#151) - Daemon healthy - Reasoning models (#158) - Lint errors (#160) - Review round (#168) - Release adjustments (#171) - Stabilize release ci fixtures - Stabilize release integration gate - Stabilize release verify gates - Stabilize release integration flows - Stabilize release verify gates - Stabilize main verify shutdown - Ignore stale acpmock cancel - Marketplace search focus and filtering (#193) - Website video - Workspace command select ### 📚 Documentation - Update agents.md - Update prd - Update skills - Update compozy tasks - Update compozy - Update compozy - Add new skills - Archive prd - Update prds - Update rfc - Update prds - Update prds - Add automation prd - Channels prd - Update prd - Update prd - New prds - Archive prds - Bridges adapters prd - Sandbox prd - Update - Archive prd - Update - Add new prd - New design - Update prd - Archive prds - Update prds - Tasks-ui prd tasks - Update prd - Update design docs - Agent capabilities prd - Improve site docs - Remove old design references - Udpate - Autonomous prd - Update skills - Blog design - Agent sould prd - Final qa plan - Update - Remove codex ledgers from gitignore - Remove not needed files - Udpate ledger - Update cy-codex-loop skill - Orchestration improves prd - Update prds - Orch improvs prd - Memv2 prd - Providers model prd - Update refacs prd - New design proposal - Update rules - Update skills - New blog posts (#173) - Format docs - Remove old design files - Remove old - Skeeper update ### 📦 Build System - Initial structure - Commitlint - Frontend base structure - Update vscode settings - Add subagents - Coderabbit - Prd and tooling - Bun lock - Lint tooling - Copy.md and tooling adjusts - Add repoclone rc - Upgrade skeeper to v0.2.0 - Update go.mod - Adopt task artifacts into skeeper - Sync codex plans with skeeper - Skeeper lock - Skeeper lock - New skills - Skeeper lock - Skeeper lock - Skeeper lock - Update deps and go - Regenerate daytona sidecar assets for go 1.26.3 - Fix cliff - Ignore docs on fmt - Build web assets before goreleaser - Extend release dry-run timeout ### 🔧 CI/CD - Lint errors - Fint release pr - Fix goreleaser ### 🧪 Testing - Add e2e tests (#27) - Qa rounds (#78) - Improve test suite (#138) - Harden daemon-served restart reloads - Harden daemon-served readiness waits - Stabilize dashboard focus assertion - Stabilize release integration gates - Stabilize release e2e markers - Stabilize release e2e flows Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
## Release v0.0.1 This PR prepares the release of version v0.0.1. ### Changelog ## 0.0.1 - 2026-05-26 ### Other Changes - Lessons learned ### ♻️ Refactoring - Project structure (#7) - Kb improvements (#12) - Rename spaces to channels (#17) - Add extensions gaps (#21) - Improve tool calls ui (#22) - Remove web app header - Module improvements (#29) - Memory improvements (#35) - Storybook for web and ui (#38) - Enable AGH network by default for new installs (#57) - Hermes adjustments (#69) - Badges design (#84) - Storybook scenario and logos gallery - Migrate typescript tests (#114) - Internal go packages (#120) - Ui patterns (#127) - Improve e2e tests (#130) - Ui redesign - Workspace isolation across runtime surfaces (#145) - Prod ready applies (#162) - Tool card ui (#164) - Alpha on logo - Prod ready features (#167) - Thread sheet (#202) ### 🎉 Features - Implement config foundation packages - Implement sqlite store package - Add ACP client package - Add session lifecycle manager - Implement observe package - Add daemon composition root - Add uds api server - Implement cli package - Add http api server - Add system design - Add foundation types, schemas, and layout shell for web client - Add daemon health polling and agent sidebar systems for web client - Add session system CRUD, streaming core, and session store for web client - Add chat view, messages, and composer tests for web client - Add tool cards and renderers for web client - Add file-backed memory store core - Scaffold memory session seams - Add memory dream consolidation service - Wire memory assembler into daemon - Add memory api and cli - New skills system (#1) - Add workspace entity (#5) - Add new skill capabilities (#8) - Web ui v2 (#9) - Improve hooks system (#10) - Session resilience (#11) - Add extensability (#13) - Add automation (#16) - Add channels (#14) - Add network implementation (#15) - Add network, bridges and automations web pages (#18) - Ext registry (#20) - Add core tasks (#19) - Bridge adapters (#23) - Add site (#26) - Add ext refac and sandbox (#25) - Settings ui (#37) - Tasks ui (#36) - Harness improvements (#44) - Agent capabilities (#49) - Redesign ui (#48) - Unify capability (#53) - Redesign network workspace (#59) - Add task deletion and split session delete from stop (#58) - Session provider selection (#60) - Production grade adjustments (#66) - Autonomous system (#75) - Add agent session route (#80) - Tools registry (#85) - Agents soul (#88) - Add network threads (#105) - Orchestration improvements (#106) - Memory v2 (#108) - Agent categories (#113) - Providers model (#118) - Add canonical AGH bundled skill (#143) - Onboarding and improvements (#198) - Onboarding and improvements (#201) ### 🐛 Bug Fixes - Review round - Review rounds - Resolve memory extensibility review batch - Embed web into daemon - Defaults agents - Acp integration (#4) - Lint errors - Prd folder - Remove orphan web actions and dead surfaces (#55) - Qa testing and fixes (#73) - New review rounds (#82) - Security audit (#90) - Release qa round (#95) - Add missing tools (#141) - New qa round (#147) - Advanced qa round (#149) - Homebrew tap - Final review round (#151) - Daemon healthy - Reasoning models (#158) - Lint errors (#160) - Review round (#168) - Release adjustments (#171) - Stabilize release ci fixtures - Stabilize release integration gate - Stabilize release verify gates - Stabilize release integration flows - Stabilize release verify gates - Stabilize main verify shutdown - Ignore stale acpmock cancel - Marketplace search focus and filtering (#193) - Website video - Workspace command select ### 📚 Documentation - Update agents.md - Update prd - Update skills - Update compozy tasks - Update compozy - Update compozy - Add new skills - Archive prd - Update prds - Update rfc - Update prds - Update prds - Add automation prd - Channels prd - Update prd - Update prd - New prds - Archive prds - Bridges adapters prd - Sandbox prd - Update - Archive prd - Update - Add new prd - New design - Update prd - Archive prds - Update prds - Tasks-ui prd tasks - Update prd - Update design docs - Agent capabilities prd - Improve site docs - Remove old design references - Udpate - Autonomous prd - Update skills - Blog design - Agent sould prd - Final qa plan - Update - Remove codex ledgers from gitignore - Remove not needed files - Udpate ledger - Update cy-codex-loop skill - Orchestration improves prd - Update prds - Orch improvs prd - Memv2 prd - Providers model prd - Update refacs prd - New design proposal - Update rules - Update skills - New blog posts (#173) - Format docs - Remove old design files - Remove old - Skeeper update ### 📦 Build System - Initial structure - Commitlint - Frontend base structure - Update vscode settings - Add subagents - Coderabbit - Prd and tooling - Bun lock - Lint tooling - Copy.md and tooling adjusts - Add repoclone rc - Upgrade skeeper to v0.2.0 - Update go.mod - Adopt task artifacts into skeeper - Sync codex plans with skeeper - Skeeper lock - Skeeper lock - New skills - Skeeper lock - Skeeper lock - Skeeper lock - Update deps and go - Regenerate daytona sidecar assets for go 1.26.3 - Fix cliff - Ignore docs on fmt - Build web assets before goreleaser - Extend release dry-run timeout ### 🔧 CI/CD - Lint errors - Fint release pr - Fix goreleaser - Fix release ### 🧪 Testing - Add e2e tests (#27) - Qa rounds (#78) - Improve test suite (#138) - Harden daemon-served restart reloads - Harden daemon-served readiness waits - Stabilize dashboard focus assertion - Stabilize release integration gates - Stabilize release e2e markers - Stabilize release e2e flows Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
## Release v0.0.2 This PR prepares the release of version v0.0.2. ### Changelog ## 0.0.2 - 2026-05-26 ### Other Changes - Lessons learned ### ♻️ Refactoring - Project structure (#7) - Kb improvements (#12) - Rename spaces to channels (#17) - Add extensions gaps (#21) - Improve tool calls ui (#22) - Remove web app header - Module improvements (#29) - Memory improvements (#35) - Storybook for web and ui (#38) - Enable AGH network by default for new installs (#57) - Hermes adjustments (#69) - Badges design (#84) - Storybook scenario and logos gallery - Migrate typescript tests (#114) - Internal go packages (#120) - Ui patterns (#127) - Improve e2e tests (#130) - Ui redesign - Workspace isolation across runtime surfaces (#145) - Prod ready applies (#162) - Tool card ui (#164) - Alpha on logo - Prod ready features (#167) - Thread sheet (#202) ### 🎉 Features - Implement config foundation packages - Implement sqlite store package - Add ACP client package - Add session lifecycle manager - Implement observe package - Add daemon composition root - Add uds api server - Implement cli package - Add http api server - Add system design - Add foundation types, schemas, and layout shell for web client - Add daemon health polling and agent sidebar systems for web client - Add session system CRUD, streaming core, and session store for web client - Add chat view, messages, and composer tests for web client - Add tool cards and renderers for web client - Add file-backed memory store core - Scaffold memory session seams - Add memory dream consolidation service - Wire memory assembler into daemon - Add memory api and cli - New skills system (#1) - Add workspace entity (#5) - Add new skill capabilities (#8) - Web ui v2 (#9) - Improve hooks system (#10) - Session resilience (#11) - Add extensability (#13) - Add automation (#16) - Add channels (#14) - Add network implementation (#15) - Add network, bridges and automations web pages (#18) - Ext registry (#20) - Add core tasks (#19) - Bridge adapters (#23) - Add site (#26) - Add ext refac and sandbox (#25) - Settings ui (#37) - Tasks ui (#36) - Harness improvements (#44) - Agent capabilities (#49) - Redesign ui (#48) - Unify capability (#53) - Redesign network workspace (#59) - Add task deletion and split session delete from stop (#58) - Session provider selection (#60) - Production grade adjustments (#66) - Autonomous system (#75) - Add agent session route (#80) - Tools registry (#85) - Agents soul (#88) - Add network threads (#105) - Orchestration improvements (#106) - Memory v2 (#108) - Agent categories (#113) - Providers model (#118) - Add canonical AGH bundled skill (#143) - Onboarding and improvements (#198) - Onboarding and improvements (#201) ### 🐛 Bug Fixes - Review round - Review rounds - Resolve memory extensibility review batch - Embed web into daemon - Defaults agents - Acp integration (#4) - Lint errors - Prd folder - Remove orphan web actions and dead surfaces (#55) - Qa testing and fixes (#73) - New review rounds (#82) - Security audit (#90) - Release qa round (#95) - Add missing tools (#141) - New qa round (#147) - Advanced qa round (#149) - Homebrew tap - Final review round (#151) - Daemon healthy - Reasoning models (#158) - Lint errors (#160) - Review round (#168) - Release adjustments (#171) - Stabilize release ci fixtures - Stabilize release integration gate - Stabilize release verify gates - Stabilize release integration flows - Stabilize release verify gates - Stabilize main verify shutdown - Ignore stale acpmock cancel - Marketplace search focus and filtering (#193) - Website video - Workspace command select ### 📚 Documentation - Update agents.md - Update prd - Update skills - Update compozy tasks - Update compozy - Update compozy - Add new skills - Archive prd - Update prds - Update rfc - Update prds - Update prds - Add automation prd - Channels prd - Update prd - Update prd - New prds - Archive prds - Bridges adapters prd - Sandbox prd - Update - Archive prd - Update - Add new prd - New design - Update prd - Archive prds - Update prds - Tasks-ui prd tasks - Update prd - Update design docs - Agent capabilities prd - Improve site docs - Remove old design references - Udpate - Autonomous prd - Update skills - Blog design - Agent sould prd - Final qa plan - Update - Remove codex ledgers from gitignore - Remove not needed files - Udpate ledger - Update cy-codex-loop skill - Orchestration improves prd - Update prds - Orch improvs prd - Memv2 prd - Providers model prd - Update refacs prd - New design proposal - Update rules - Update skills - New blog posts (#173) - Format docs - Remove old design files - Remove old - Skeeper update ### 📦 Build System - Initial structure - Commitlint - Frontend base structure - Update vscode settings - Add subagents - Coderabbit - Prd and tooling - Bun lock - Lint tooling - Copy.md and tooling adjusts - Add repoclone rc - Upgrade skeeper to v0.2.0 - Update go.mod - Adopt task artifacts into skeeper - Sync codex plans with skeeper - Skeeper lock - Skeeper lock - New skills - Skeeper lock - Skeeper lock - Skeeper lock - Update deps and go - Regenerate daytona sidecar assets for go 1.26.3 - Fix cliff - Ignore docs on fmt - Build web assets before goreleaser - Extend release dry-run timeout ### 🔧 CI/CD - Lint errors - Fint release pr - Fix goreleaser - Fix release - Fix release process ### 🧪 Testing - Add e2e tests (#27) - Qa rounds (#78) - Improve test suite (#138) - Harden daemon-served restart reloads - Harden daemon-served readiness waits - Stabilize dashboard focus assertion - Stabilize release integration gates - Stabilize release e2e markers - Stabilize release e2e flows - Improve suite speed Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
## Release v0.0.2 This PR prepares the release of version v0.0.2. ### Changelog ## 0.0.2 - 2026-05-26 ### Other Changes - Lessons learned ### ♻️ Refactoring - Project structure (#7) - Kb improvements (#12) - Rename spaces to channels (#17) - Add extensions gaps (#21) - Improve tool calls ui (#22) - Remove web app header - Module improvements (#29) - Memory improvements (#35) - Storybook for web and ui (#38) - Enable AGH network by default for new installs (#57) - Hermes adjustments (#69) - Badges design (#84) - Storybook scenario and logos gallery - Migrate typescript tests (#114) - Internal go packages (#120) - Ui patterns (#127) - Improve e2e tests (#130) - Ui redesign - Workspace isolation across runtime surfaces (#145) - Prod ready applies (#162) - Tool card ui (#164) - Alpha on logo - Prod ready features (#167) - Thread sheet (#202) ### 🎉 Features - Implement config foundation packages - Implement sqlite store package - Add ACP client package - Add session lifecycle manager - Implement observe package - Add daemon composition root - Add uds api server - Implement cli package - Add http api server - Add system design - Add foundation types, schemas, and layout shell for web client - Add daemon health polling and agent sidebar systems for web client - Add session system CRUD, streaming core, and session store for web client - Add chat view, messages, and composer tests for web client - Add tool cards and renderers for web client - Add file-backed memory store core - Scaffold memory session seams - Add memory dream consolidation service - Wire memory assembler into daemon - Add memory api and cli - New skills system (#1) - Add workspace entity (#5) - Add new skill capabilities (#8) - Web ui v2 (#9) - Improve hooks system (#10) - Session resilience (#11) - Add extensability (#13) - Add automation (#16) - Add channels (#14) - Add network implementation (#15) - Add network, bridges and automations web pages (#18) - Ext registry (#20) - Add core tasks (#19) - Bridge adapters (#23) - Add site (#26) - Add ext refac and sandbox (#25) - Settings ui (#37) - Tasks ui (#36) - Harness improvements (#44) - Agent capabilities (#49) - Redesign ui (#48) - Unify capability (#53) - Redesign network workspace (#59) - Add task deletion and split session delete from stop (#58) - Session provider selection (#60) - Production grade adjustments (#66) - Autonomous system (#75) - Add agent session route (#80) - Tools registry (#85) - Agents soul (#88) - Add network threads (#105) - Orchestration improvements (#106) - Memory v2 (#108) - Agent categories (#113) - Providers model (#118) - Add canonical AGH bundled skill (#143) - Onboarding and improvements (#198) - Onboarding and improvements (#201) ### 🐛 Bug Fixes - Review round - Review rounds - Resolve memory extensibility review batch - Embed web into daemon - Defaults agents - Acp integration (#4) - Lint errors - Prd folder - Remove orphan web actions and dead surfaces (#55) - Qa testing and fixes (#73) - New review rounds (#82) - Security audit (#90) - Release qa round (#95) - Add missing tools (#141) - New qa round (#147) - Advanced qa round (#149) - Homebrew tap - Final review round (#151) - Daemon healthy - Reasoning models (#158) - Lint errors (#160) - Review round (#168) - Release adjustments (#171) - Stabilize release ci fixtures - Stabilize release integration gate - Stabilize release verify gates - Stabilize release integration flows - Stabilize release verify gates - Stabilize main verify shutdown - Ignore stale acpmock cancel - Marketplace search focus and filtering (#193) - Website video - Workspace command select ### 📚 Documentation - Update agents.md - Update prd - Update skills - Update compozy tasks - Update compozy - Update compozy - Add new skills - Archive prd - Update prds - Update rfc - Update prds - Update prds - Add automation prd - Channels prd - Update prd - Update prd - New prds - Archive prds - Bridges adapters prd - Sandbox prd - Update - Archive prd - Update - Add new prd - New design - Update prd - Archive prds - Update prds - Tasks-ui prd tasks - Update prd - Update design docs - Agent capabilities prd - Improve site docs - Remove old design references - Udpate - Autonomous prd - Update skills - Blog design - Agent sould prd - Final qa plan - Update - Remove codex ledgers from gitignore - Remove not needed files - Udpate ledger - Update cy-codex-loop skill - Orchestration improves prd - Update prds - Orch improvs prd - Memv2 prd - Providers model prd - Update refacs prd - New design proposal - Update rules - Update skills - New blog posts (#173) - Format docs - Remove old design files - Remove old - Skeeper update ### 📦 Build System - Initial structure - Commitlint - Frontend base structure - Update vscode settings - Add subagents - Coderabbit - Prd and tooling - Bun lock - Lint tooling - Copy.md and tooling adjusts - Add repoclone rc - Upgrade skeeper to v0.2.0 - Update go.mod - Adopt task artifacts into skeeper - Sync codex plans with skeeper - Skeeper lock - Skeeper lock - New skills - Skeeper lock - Skeeper lock - Skeeper lock - Update deps and go - Regenerate daytona sidecar assets for go 1.26.3 - Fix cliff - Ignore docs on fmt - Build web assets before goreleaser - Extend release dry-run timeout ### 🔧 CI/CD - Lint errors - Fint release pr - Fix goreleaser - Fix release - Fix release process - Fix release sync - Decouple release dry-run npm auth - Persist web assets git auth ### 🧪 Testing - Add e2e tests (#27) - Qa rounds (#78) - Improve test suite (#138) - Harden daemon-served restart reloads - Harden daemon-served readiness waits - Stabilize dashboard focus assertion - Stabilize release integration gates - Stabilize release e2e markers - Stabilize release e2e flows - Improve suite speed <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Updated web assets dependency to a newer version for improved stability and performance. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/compozy/agh/pull/211?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
## Release v0.0.2 This PR prepares the release of version v0.0.2. ### Changelog ## 0.0.2 - 2026-05-27 ### Other Changes - Lessons learned ### ♻️ Refactoring - Project structure (#7) - Kb improvements (#12) - Rename spaces to channels (#17) - Add extensions gaps (#21) - Improve tool calls ui (#22) - Remove web app header - Module improvements (#29) - Memory improvements (#35) - Storybook for web and ui (#38) - Enable AGH network by default for new installs (#57) - Hermes adjustments (#69) - Badges design (#84) - Storybook scenario and logos gallery - Migrate typescript tests (#114) - Internal go packages (#120) - Ui patterns (#127) - Improve e2e tests (#130) - Ui redesign - Workspace isolation across runtime surfaces (#145) - Prod ready applies (#162) - Tool card ui (#164) - Alpha on logo - Prod ready features (#167) - Thread sheet (#202) ### 🎉 Features - Implement config foundation packages - Implement sqlite store package - Add ACP client package - Add session lifecycle manager - Implement observe package - Add daemon composition root - Add uds api server - Implement cli package - Add http api server - Add system design - Add foundation types, schemas, and layout shell for web client - Add daemon health polling and agent sidebar systems for web client - Add session system CRUD, streaming core, and session store for web client - Add chat view, messages, and composer tests for web client - Add tool cards and renderers for web client - Add file-backed memory store core - Scaffold memory session seams - Add memory dream consolidation service - Wire memory assembler into daemon - Add memory api and cli - New skills system (#1) - Add workspace entity (#5) - Add new skill capabilities (#8) - Web ui v2 (#9) - Improve hooks system (#10) - Session resilience (#11) - Add extensability (#13) - Add automation (#16) - Add channels (#14) - Add network implementation (#15) - Add network, bridges and automations web pages (#18) - Ext registry (#20) - Add core tasks (#19) - Bridge adapters (#23) - Add site (#26) - Add ext refac and sandbox (#25) - Settings ui (#37) - Tasks ui (#36) - Harness improvements (#44) - Agent capabilities (#49) - Redesign ui (#48) - Unify capability (#53) - Redesign network workspace (#59) - Add task deletion and split session delete from stop (#58) - Session provider selection (#60) - Production grade adjustments (#66) - Autonomous system (#75) - Add agent session route (#80) - Tools registry (#85) - Agents soul (#88) - Add network threads (#105) - Orchestration improvements (#106) - Memory v2 (#108) - Agent categories (#113) - Providers model (#118) - Add canonical AGH bundled skill (#143) - Onboarding and improvements (#198) - Onboarding and improvements (#201) ### 🐛 Bug Fixes - Review round - Review rounds - Resolve memory extensibility review batch - Embed web into daemon - Defaults agents - Acp integration (#4) - Lint errors - Prd folder - Remove orphan web actions and dead surfaces (#55) - Qa testing and fixes (#73) - New review rounds (#82) - Security audit (#90) - Release qa round (#95) - Add missing tools (#141) - New qa round (#147) - Advanced qa round (#149) - Homebrew tap - Final review round (#151) - Daemon healthy - Reasoning models (#158) - Lint errors (#160) - Review round (#168) - Release adjustments (#171) - Stabilize release ci fixtures - Stabilize release integration gate - Stabilize release verify gates - Stabilize release integration flows - Stabilize release verify gates - Stabilize main verify shutdown - Ignore stale acpmock cancel - Marketplace search focus and filtering (#193) - Website video - Workspace command select ### 📚 Documentation - Update agents.md - Update prd - Update skills - Update compozy tasks - Update compozy - Update compozy - Add new skills - Archive prd - Update prds - Update rfc - Update prds - Update prds - Add automation prd - Channels prd - Update prd - Update prd - New prds - Archive prds - Bridges adapters prd - Sandbox prd - Update - Archive prd - Update - Add new prd - New design - Update prd - Archive prds - Update prds - Tasks-ui prd tasks - Update prd - Update design docs - Agent capabilities prd - Improve site docs - Remove old design references - Udpate - Autonomous prd - Update skills - Blog design - Agent sould prd - Final qa plan - Update - Remove codex ledgers from gitignore - Remove not needed files - Udpate ledger - Update cy-codex-loop skill - Orchestration improves prd - Update prds - Orch improvs prd - Memv2 prd - Providers model prd - Update refacs prd - New design proposal - Update rules - Update skills - New blog posts (#173) - Format docs - Remove old design files - Remove old - Skeeper update ### 📦 Build System - Initial structure - Commitlint - Frontend base structure - Update vscode settings - Add subagents - Coderabbit - Prd and tooling - Bun lock - Lint tooling - Copy.md and tooling adjusts - Add repoclone rc - Upgrade skeeper to v0.2.0 - Update go.mod - Adopt task artifacts into skeeper - Sync codex plans with skeeper - Skeeper lock - Skeeper lock - New skills - Skeeper lock - Skeeper lock - Skeeper lock - Update deps and go - Regenerate daytona sidecar assets for go 1.26.3 - Fix cliff - Ignore docs on fmt - Build web assets before goreleaser - Extend release dry-run timeout - Fix release dry-run token contract ### 🔧 CI/CD - Lint errors - Fint release pr - Fix goreleaser - Fix release - Fix release process - Fix release sync - Decouple release dry-run npm auth - Persist web assets git auth - Require npm auth before release merge ### 🧪 Testing - Add e2e tests (#27) - Qa rounds (#78) - Improve test suite (#138) - Harden daemon-served restart reloads - Harden daemon-served readiness waits - Stabilize dashboard focus assertion - Stabilize release integration gates - Stabilize release e2e markers - Stabilize release e2e flows - Improve suite speed <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Updated dependencies to latest versions. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/compozy/agh/pull/214?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Summary by CodeRabbit
New Features
Telemetry & Persistence
UI/UX Improvements