Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .claude/commands/add-sse-event.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,18 @@ If the event carries structured data beyond a simple string, add a serializable

## Step 4: Add frontend handler

**File**: `src/channels/web/static/app.js`
**File**: `crates/ironclaw_gateway/static/js/core/sse.js`

In the `connectSSE()` function, add a new `eventSource.addEventListener()` for the snake_case event name. Parse the JSON data and call a handler function.

Create the handler function that updates the DOM. Follow existing patterns:
Create the handler function that updates the DOM. Put it in the split file that matches its surface — e.g. `js/core/onboarding.js` for auth/onboarding handlers, `js/surfaces/chat.js` for chat message handlers, `js/surfaces/jobs.js` for sandbox job events. Follow existing patterns:
- `showApproval(data)` for complex card-style UI
- `addMessage(role, content)` for simple text
- `setStatus(text, spinning)` for status bar updates

## Step 5: Add CSS if needed

**File**: `src/channels/web/static/style.css`
**File**: pick the matching surface under `crates/ironclaw_gateway/static/styles/surfaces/` (e.g. `chat.css` for chat UI, `jobs.css` for sandbox job cards) or `styles/components/` for cross-surface reusable pieces.

If the event needs custom UI (cards, badges, etc.), add styles. Follow the existing naming conventions (`.approval-card`, `.log-entry`, etc.).

Expand Down
8 changes: 4 additions & 4 deletions .claude/commands/trace.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ StatusUpdate variant (channel.rs)
→ WebChannel::send_status() (web/mod.rs) maps to SseEvent
→ broadcast via tokio::broadcast channel
→ SSE endpoint streams events (web/server.rs)
→ Browser EventSource listener (app.js)
→ DOM update function
→ CSS styling (style.css)
→ Browser EventSource listener (js/core/sse.js)
→ DOM update function (js/surfaces/<surface>.js or js/core/<module>.js)
→ CSS styling (styles/surfaces/<surface>.css or styles/components/*.css)
```

### Tool Flow (tool definition to execution)
Expand Down Expand Up @@ -72,7 +72,7 @@ Tool trait impl (tools/builtin/*.rs or tools/mcp/client.rs or tools/wasm/wrapper
| Channel trait | `src/channels/channel.rs` | `Channel`, `StatusUpdate`, `IncomingMessage` |
| Web gateway | `src/channels/web/mod.rs` | `send_status`, `send_response` |
| Web server | `src/channels/web/server.rs` | Route handlers, SSE endpoints |
| Web frontend | `src/channels/web/static/app.js` | SSE listeners, DOM builders |
| Web frontend | `crates/ironclaw_gateway/static/js/` (core/ + surfaces/) | SSE listeners in `core/sse.js`; DOM builders per surface |
| Tool registry | `src/tools/registry.rs` | `tool_definitions`, `get`, `register` |
| MCP tools | `src/tools/mcp/client.rs` | `McpToolWrapper`, `list_tools`, `call_tool` |
| MCP protocol | `src/tools/mcp/protocol.rs` | `McpTool`, `inputSchema` |
Expand Down
10 changes: 8 additions & 2 deletions .github/workflows/code_style.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,14 @@ jobs:
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4
with:
node-version: "22"
- name: Check gateway app.js syntax
run: node --check crates/ironclaw_gateway/static/app.js
- name: Check gateway JS syntax
run: |
# app.js was split into per-surface/per-concern modules under
# static/js/ that are concatenated at compile time into APP_JS.
# Cuts land on top-level symbol boundaries, so each file is
# self-parseable — a per-file node --check is sufficient.
find crates/ironclaw_gateway/static/js -type f -name '*.js' \
-exec node --check {} +

deny-check:
name: cargo-deny
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Current ownership:
- `src/bridge/auth_manager.rs`: canonical auth-flow extension-name resolver
- `src/bridge/router.rs`: auth gate display + submit routing
- `src/channels/web/server.rs`: pending-gate/history rehydration
- `crates/ironclaw_gateway/static/app.js`: unified onboarding controller and configure-modal routing
- `crates/ironclaw_gateway/static/js/core/onboarding.js`: unified onboarding controller and configure-modal routing (previously in the monolithic `app.js`, now split — see `crates/ironclaw_gateway/src/assets.rs` for the concat order)

Temporary compatibility boundary:

Expand Down
119 changes: 112 additions & 7 deletions crates/ironclaw_gateway/src/assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,116 @@
/// Main HTML page (SPA shell).
pub const INDEX_HTML: &str = include_str!("../static/index.html");

/// Main application JavaScript.
pub const APP_JS: &str = include_str!("../static/app.js");

/// Base stylesheet.
pub const STYLE_CSS: &str = include_str!("../static/style.css");
/// Main application JavaScript — compile-time concatenation of the split
/// modules under `static/js/`. Each file owns one surface, one slice of
/// lifecycle, or one shared helper; merge-conflict churn used to
/// dominate `app.js` when it was a single 11 k-line file.
///
/// Execution order MUST match the original top-to-bottom order of the
/// pre-split monolith — code has forward references (closures, event
/// bindings) that are order-dependent. A newline between each module
/// prevents the last token of one file running into the first token of
/// the next when a file ends without a trailing newline.
pub const APP_JS: &str = concat!(
include_str!("../static/js/core/bootstrap.js"),
"\n",
include_str!("../static/js/core/activity-store.js"),
"\n",
include_str!("../static/js/core/routing.js"),
"\n",
include_str!("../static/js/core/init-auth.js"),
"\n",
include_str!("../static/js/core/sse.js"),
"\n",
include_str!("../static/js/surfaces/chat.js"),
"\n",
include_str!("../static/js/core/render.js"),
"\n",
include_str!("../static/js/core/tool-activity.js"),
"\n",
include_str!("../static/js/core/onboarding.js"),
"\n",
include_str!("../static/js/core/history.js"),
"\n",
include_str!("../static/js/surfaces/memory.js"),
"\n",
include_str!("../static/js/surfaces/logs.js"),
"\n",
include_str!("../static/js/surfaces/extensions.js"),
"\n",
include_str!("../static/js/surfaces/jobs.js"),
"\n",
include_str!("../static/js/surfaces/routines.js"),
"\n",
include_str!("../static/js/surfaces/projects.js"),
"\n",
include_str!("../static/js/surfaces/users.js"),
"\n",
include_str!("../static/js/core/gateway-tee.js"),
"\n",
include_str!("../static/js/surfaces/skills.js"),
"\n",
include_str!("../static/js/surfaces/tool-permissions.js"),
"\n",
include_str!("../static/js/surfaces/settings.js"),
"\n",
include_str!("../static/js/core/ui-helpers.js"),
"\n",
include_str!("../static/js/surfaces/config.js"),
"\n",
include_str!("../static/js/core/widgets.js"),
);

/// Base stylesheet — compile-time concatenation of the split modules
/// under `static/styles/`. Authoring happens in one module per surface,
/// component, or primitive (see `static/styles/`); the served blob is
/// the same text a monolithic `style.css` would be. Load order is
/// base → layout → components → primitives → surfaces.
///
/// A newline between each module guards against the last rule of one
/// file running into the first selector of the next when a file ends
/// without a trailing newline.
pub const STYLE_CSS: &str = concat!(
include_str!("../static/styles/base.css"),
"\n",
include_str!("../static/styles/layout.css"),
"\n",
include_str!("../static/styles/components/topbar.css"),
"\n",
include_str!("../static/styles/components/markdown.css"),
"\n",
include_str!("../static/styles/primitives/toast.css"),
"\n",
include_str!("../static/styles/surfaces/auth.css"),
"\n",
include_str!("../static/styles/surfaces/chat.css"),
"\n",
include_str!("../static/styles/surfaces/memory.css"),
"\n",
include_str!("../static/styles/surfaces/jobs.css"),
"\n",
include_str!("../static/styles/surfaces/missions.css"),
"\n",
include_str!("../static/styles/surfaces/routines.css"),
"\n",
include_str!("../static/styles/surfaces/logs.css"),
"\n",
include_str!("../static/styles/surfaces/extensions.css"),
"\n",
include_str!("../static/styles/surfaces/activity.css"),
"\n",
include_str!("../static/styles/surfaces/skills.css"),
"\n",
include_str!("../static/styles/surfaces/settings.css"),
"\n",
include_str!("../static/styles/surfaces/config.css"),
"\n",
include_str!("../static/styles/surfaces/users.css"),
"\n",
include_str!("../static/styles/surfaces/tool-permissions.css"),
"\n",
include_str!("../static/styles/surfaces/projects.css"),
);

/// Theme initialization script (runs synchronously in `<head>` to prevent FOUC).
pub const THEME_INIT_JS: &str = include_str!("../static/theme-init.js");
Expand Down Expand Up @@ -48,7 +153,7 @@ pub const THEME_CSS: &str = include_str!("../static/theme.css");
pub const ADMIN_HTML: &str = include_str!("../static/admin.html");

/// Admin panel stylesheet.
pub const ADMIN_CSS: &str = include_str!("../static/admin.css");
pub const ADMIN_CSS: &str = include_str!("../static/admin/admin.css");

/// Admin panel JavaScript.
pub const ADMIN_JS: &str = include_str!("../static/admin.js");
pub const ADMIN_JS: &str = include_str!("../static/admin/admin.js");
Loading
Loading