mirror of
https://github.com/nearai/ironclaw.git
synced 2026-09-03 08:06:01 +08:00
* feat(web-push): browser push notifications + PWA — the web app as a first-party notification channel The web app becomes a real, selectable notification route for automations, at parity with Slack/Telegram: a bundled first-party channel extension (web-push) delivers W3C Web Push (RFC 8030/8291/8292) to the user's enrolled browsers through the existing catalog → notification-channel set → notifier → delivery coordinator → channel adapter → policy-enforced egress chain, with zero new routing machinery and the two-lane delivery contract untouched. The WebUI ships as an installable PWA (root-scope service worker with push + notification-click deep links; manifest and icons already existed), and the automations page's notification-channels panel replaces the always-on "web app" placeholder with a real toggleable row plus a per-browser enroll/disable flow. New crates: ironclaw_web_push (domain: subscription records + CAS store, RFC 8291 aes128gcm encryption pinned to the RFC's Appendix A vector, VAPID key-material generation, transport-free request planning, channel identity grammar, late-bound runtime slot) and ironclaw_web_push_extension (channel package: manifest with vapid_authorization egress injection, adapter with 404/410 pruning and honest Sent-without-ref evidence, personal-DM codec, owner-scoped catalog provider). One generic host addition: the RuntimeCredentialTarget::VapidAuthorization egress injection kind — the host signs the RFC 8292 ES256 JWT at the existing credential chokepoint with the audience derived from the request's own push-service origin; adapters never see key bytes. VAPID material is auto-generated and seeded at composition boot. Enrollment is an authenticated product surface (three new /api/webchat/v2/web-push routes) with descriptors declared in ironclaw_product_contracts::web_push per the transport/product boundary, and endpoints validate against the manifest-declared push-service hosts. Also fixes a boot bug the new integration tests exposed: DeploymentChannelBinding rejected outbound-only channels, which would have failed the runtime build at serve. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(web-push): address review — redact VAPID secret, byte-budget payload, account-scoped enrollment, sanitized store errors Triage of the CodeRabbit + IronLoop review on #7398: - Secret exposure (Critical): hand-written redacting `Debug` on `VapidCredentialMaterialV1` and `GeneratedVapidKeyMaterial` so the ES256 private key can never reach a log, panic, or `{:?}`. - VAPID material (High): composition now ensures-then-reads-back the canonical stored keypair so multi-replica cold-start converges on one signing key and the advertised applicationServerKey matches it; material shape is validated at boot and again before egress signing. - Payload budget (Medium): notification body is trimmed by serialized-JSON bytes, not character count, so multi-byte content can't blow the single-record push budget (+ regression test). - Error hygiene (Medium): `WebPushError::Store` is a fixed sanitized category; the backend cause is logged server-side, never rendered into the boundary error. - Account-scoped enrollment (Medium): status projects an `endpoint_digest` (SHA-256 hex) so a shared browser profile distinguishes "enrolled here" from "enrolled for another account" without the endpoint URL leaving the backend; the frontend correlates on it and only offers destructive disable when verified. - Deep-link/tag grammar enforced in the owning crate; SW validates same-origin before navigating; subject parsed via `url`; concurrent-writer CAS test; registry key derived from the extension-id constant; parse-cause preserved; doc/count corrections. The manifest keeps the `web_push_vapid` field (a channel egress credential handle must be declared in [admin_configuration]); it stays host-seeded and not operator-supplied, with the rotation caveat documented. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(web-push): keep SW registration out of the initial /chat bundle; raise the chat budget for the feature's i18n copy The merge-lane bundle-budget gate (skipped on the PR lane) flagged the initial /chat JS at 218.2 KB against the 217.0 KB gzip budget. `main.tsx` boot-imported `registerServiceWorker` from `lib/web-push.ts`, which dragged the enrollment lib's api-client and WebCrypto imports into the initial chunk. Extracted the dependency-free `lib/register-sw.ts` for boot; the enrollment API stays in `web-push.ts`, imported only by the already-lazy automations route. That recovered the eager-code weight (218.2 -> 217.4 KB); the residual is the feature's new `en.ts` fallback-pack strings, so the /chat budget is raised 217.0 -> 218.0 KB with rationale, matching how prior features (hosted MCP, Router 8) handled eager localized copy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(web-push): register the browser channel in the journey coverage gate The merge-lane product-surface evidence gate (test_journey_coverage.py, skipped on the PR lane) requires every outbound channel manifest to name exact journey evidence. web-push declares `outbound = true`, so it entered the required delivery-target set with none. Added: - `JourneyDeliveryTarget.WEB_PUSH` and a `ProductJourneyCase` citing the existing `blocked_fire_pushes_web_push_notice_to_enrolled_browser` integration test, with unthreaded (`thread_anchor=None`) delivery-address evidence — browser push addresses a per-browser endpoint capability URL, not a conversation thread. - `assert_web_push_delivery_evidence` in delivery_user_journeys.rs, shaped as the gate's citability check requires (literal `expected_conversation_id` gating the count, `expected_thread_anchor = None`), called from that test. Verified: test_journey_coverage.py (68), test_product_surface_coverage.py + test_provider_capability_inventory.py (30), and the cited integration test all green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * style(web-push): rustfmt the journey-evidence helper `cargo fmt --all -- --check` (the first step of the Fast deterministic checks lane, PR-lane-skipped) flagged the iterator chain in `assert_web_push_delivery_evidence`. Formatting only, no behavior change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(web-push): present the channel as "Web UI" and hide it from the install catalog The web-app's browser-push channel is host infrastructure, not a browse-and-install integration, so: - Rename the extension/channel to "Web UI" (manifest name + channel display_name + first-party bundle label; description reworded). - Hide it from the install catalog (/extensions, /extensions/registry, and the Settings channels list) via an explicit built-in-host-surface classification in the product lifecycle projection — deliberately keyed by id, not inferred from channel direction, so it stays correct as the web-app channel later gains inbound/outbound. Its outbound notification target (/outbound/targets) is a separate registry and is unaffected, so it remains a selectable notification channel. Also finalizes the enrollment UI carried from this session: - Align the "This browser" device block with the channel cards (drop the stray left indent). - Lazy-mount the web-push device hook so its status query fires only when a web-push row is present, not on every automations view. - Rename the misleading webOnlyHelper i18n key to noSelectionHelper across all locale packs (the string already dropped the retired "stays in the web app" claim). - Manifest icons declare purpose "any maskable" so Chrome offers the PWA install prompt. Regression coverage extends the production web-push integration test to assert it is absent from the install endpoints yet present in /outbound/targets. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(web-push): fix stale helper name in install-catalog filter comment CodeRabbit flagged that the filter comment still named the removed `is_host_managed_channel` helper and described the old outbound-only heuristic. Point it at `is_builtin_host_surface` and the id-based classification the code actually uses. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(web-push): pin notification-helper i18n key as noSelectionHelper The P1 rename webOnlyHelper -> noSelectionHelper missed two test assertions that pin the i18n key, failing the affected-3 Reborn crate bucket (Tests (Reborn) rolls it up): - crates/app/ironclaw_composition/tests/webui_v2_serve.rs (served bundle) - crates/product/ironclaw_webui/src/webui_v2/static_assets/assets.rs (live source) Also renames the now-misleading test fn and corrects a stale bundle-budget comment. Test-only; no production behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(channels): notifications as a first-class channel capability Separates "notification target" from "final-reply / model-delivery target" so the web app is a notification channel (blocked-automation notices) without being a place the model or a run's final reply is delivered to. Folds the notifications-capability work into the web-push PR (#7398). Model / declarative: - ChannelDescriptor gains a `notifications` capability (serde default), so a manifest can independently declare inbound / outbound / notifications. The web-push manifest declares `notifications = true` (kept `outbound = true` for now: it is what registers the channel's delivery binding; outbound thread-creation is a later capability). Pinned by manifest_lockstep. Delivery authority (the load-bearing separation): - DeliveryTargetCapabilities gains a `notifications` bool, and a new `OutboundDeliveryTargetProvider::resolve_notification_target` resolves a target the caller may receive blocked-automation notices on, gated on `notifications` (not `final_replies`). Default impl + registry/mutable-registry overrides; the generic channel provider reuses its id-resolution. - web-push target caps flip to `final_replies: false, notifications: true`: browser push is where a run's reply already lands, never a destination the model/final-reply path delivers *to*. - The notification-channel picker (`/outbound/targets`) and the notifier + set-validation resolution now gate on the notifications capability; the model-facing delivery list (`builtin.outbound_delivery_targets_list`) narrows to `final_replies`, so a notification-only target (browser push) is invisible to the model until it gains outbound delivery. Why this shape: production blocked-automation notices run through TriggeredRunDeliveryDriver -> DeliveryCoordinator -> WebPushChannelAdapter and select targets by capability resolution; the `ThreadNotificationPolicy` / `progress` push-plan in ironclaw_outbound is dormant (no production writer or caller), so gating on `progress` would not have changed delivery. Slack and Telegram are both final-reply and notification targets and are unaffected. Regression coverage: web-push resolves as a notification target but NOT as a final-reply/model target (targets.rs); existing notifier + notification-channel integration journeys stay green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(channels): cargo fmt + drop vendor names from generic-code comments - cargo fmt reflow in notification_channel_resolution.rs. - Reword comments in ironclaw_composition/runtime.rs and ironclaw_extension_host/channel_outbound_targets.rs so generic code does not name Slack/Telegram (reborn_extension_specificity gate). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs+test(channels): fix notifications doc + serde-default coverage Addresses CodeRabbit on the notifications-capability commit: - channel.rs: reword ChannelDescriptor.notifications doc so it no longer claims the web app declines outbound (the manifest keeps outbound = true for the delivery binding). Net-zero line count (contracts size ceiling unchanged). - delivery_resolution.rs: assert notifications defaults false, and add a legacy-payload (omitted notifications) deserialize test for #[serde(default)]. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(outbound): decouple notification-picker list from model-delivery list Addresses the CodeRabbit "Major": final_replies and notifications were coupled through one shared base filter. Now RebornOutboundDeliveryTargetCapabilities carries a wire-level `notifications`; list_outbound_delivery_targets returns the union (final_replies || notifications); the notification picker (build_outbound_delivery_targets_view) filters notifications and the model list (list_outbound_delivery_targets_for_model) filters final_replies — independently. A final-reply-only target is now visible to the model but not the picker; a notification-only target (web-push) shows in the picker but never to the model. Verified: assistant, ironclaw_webui, frontend (1208), delivery_user_journeys (25), web-push round-trip, architecture suite (41). Chose "in #7398" per the overnight directive to fix review comments. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(outbound): cover divergent notifications/final_replies at the filter seam Addresses CodeRabbit's follow-up: the unit capability-filter seam couldn't construct divergent targets (the fixture set notifications = final_replies). Adds `target_entry_with_caps` (independent notifications) and a divergent-combo test asserting the base list is the union — a final-reply-only target and a notification-only target both survive, a neither-capable target is excluded. Existing coincident-case tests unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
552 lines
26 KiB
TOML
552 lines
26 KiB
TOML
[workspace]
|
|
members = [".", "crates/contracts/ironclaw_common", "crates/substrates/ironclaw_observability", "crates/contracts/ironclaw_host_api", "crates/product/ironclaw_host_ingress", "crates/substrates/ironclaw_libsql_runtime", "crates/substrates/ironclaw_filesystem", "crates/domains/ironclaw_attachments", "crates/domains/ironclaw_extractors", "crates/domains/ironclaw_memory", "crates/extensions/packages/memory-native", "crates/extensions/packages/mem0", "crates/events/ironclaw_event_log", "crates/events/ironclaw_event_projections", "crates/events/ironclaw_event_streams", "crates/events/ironclaw_event_store", "crates/extensions/ironclaw_extension_registry", "crates/extensions/ironclaw_extension_host", "crates/extensions/ironclaw_extension_manager", "crates/kernel/ironclaw_processes", "crates/lanes/ironclaw_sandbox", "crates/lanes/ironclaw_mcp", "crates/lanes/ironclaw_wasm", "crates/lanes/ironclaw_wasm_limiter", "crates/kernel/ironclaw_capabilities", "crates/substrates/ironclaw_secrets", "crates/substrates/ironclaw_network", "crates/kernel/ironclaw_host_runtime", "crates/kernel/ironclaw_runtime_policy", "crates/kernel/ironclaw_authorization", "crates/kernel/ironclaw_approvals", "crates/kernel/ironclaw_resources", "crates/domains/ironclaw_auth", "crates/kernel/ironclaw_trust", "crates/kernel/ironclaw_turns", "crates/contracts/ironclaw_loop_contracts", "crates/contracts/ironclaw_extension_contracts", "crates/contracts/ironclaw_product_contracts", "crates/loop/ironclaw_agent_loop", "crates/domains/ironclaw_threads", "crates/contracts/ironclaw_prompt_envelope", "crates/loop/ironclaw_hooks", "crates/loop/ironclaw_loop_host", "crates/loop/ironclaw_turn_runner", "crates/app/ironclaw_config", "crates/product/ironclaw_operator", "crates/app/ironclaw_composition", "crates/domains/ironclaw_identity", "crates/extensions/ironclaw_extension_support", "crates/app/ironclaw_cli", "crates/domains/ironclaw_trace_commons", "crates/product/ironclaw_webui", "crates/product/ironclaw_openai_compat", "crates/domains/ironclaw_conversations", "crates/product/ironclaw_assistant", "crates/extensions/packages/telegram", "crates/extensions/packages/slack", "crates/extensions/packages/web-push", "crates/domains/ironclaw_outbound", "crates/domains/ironclaw_triggers", "crates/domains/ironclaw_web_push", "crates/app/ironclaw_architecture_tests", "crates/substrates/ironclaw_safety", "crates/domains/ironclaw_skills", "crates/domains/ironclaw_llm", "tools/ironclaw_stress"]
|
|
default-members = ["crates/app/ironclaw_cli"]
|
|
exclude = [
|
|
# Standalone helper binary, `[workspace]`-rooted and never built here (it
|
|
# needs libclang + a C toolchain). Its §5 home is `tools/`, beside the
|
|
# stress harness — WS7 relocated it out of `crates/`, which after the
|
|
# family moves holds exactly the ten family directories (PROPOSAL §5,
|
|
# §12.13 D-O).
|
|
"tools/ironclaw_silk_decoder",
|
|
# The root `fuzz/` package was deleted in WS8: it declared
|
|
# `[dependencies.ironclaw] path = ".."` and fuzzed `ironclaw::safety` /
|
|
# `ironclaw::tools`, but the root package has had no lib target since the
|
|
# v1 monolith was removed, so it could not resolve. `ironclaw_safety/fuzz`
|
|
# is a separate, live fuzz package and stays.
|
|
"crates/substrates/ironclaw_safety/fuzz",
|
|
]
|
|
|
|
[workspace.package]
|
|
rust-version = "1.96"
|
|
|
|
[workspace.dependencies]
|
|
# WASM sandbox for untrusted tool execution.
|
|
# Floor 47.0.3: minimum current major patch containing the fixes for the
|
|
# Wasmtime advisories RUSTSEC-2026-0149, RUSTSEC-2026-0188,
|
|
# RUSTSEC-2026-0222, and RUSTSEC-2026-0223.
|
|
wasmtime = { version = "47.0.3", features = ["component-model"] }
|
|
# Only the WASI p2 host API is linked (`p2::add_to_linker_sync`). Keeping
|
|
# defaults off avoids compiling unused p0/p1 WITX proc macros under remote CI
|
|
# sccache workers, where registry sidecar WITX files are not present.
|
|
wasmtime-wasi = { version = "47.0.3", default-features = false, features = ["p2"] }
|
|
|
|
# Maintainability guardrails against dead/speculative public API
|
|
# (the "Theme 1" anti-pattern from the maintainability audit: accessors,
|
|
# `_dyn` variants, and getters with zero callers that needlessly expand the
|
|
# stable surface). These are `warn`, not `deny`, and are *opted into*
|
|
# per-crate via `[lints] workspace = true` so they do not flood the build
|
|
# with pre-existing noise across the whole workspace. Currently scoped to the
|
|
# hook/reborn crates.
|
|
#
|
|
# - `unreachable_pub`: flags `pub` items that are not reachable outside their
|
|
# crate — the classic "this should be `pub(crate)`" smell.
|
|
# - `dead_code`: warn on never-used items (this is the rustc default, declared
|
|
# here so it survives any future `#![allow(dead_code)]` creep at the crate root).
|
|
[workspace.lints.rust]
|
|
unreachable_pub = "warn"
|
|
dead_code = "warn"
|
|
# A `Result`/`#[must_use]` value that is silently discarded is a swallowed
|
|
# error. `unused_must_use` is warn-by-default; deny it so a dropped `Result`
|
|
# fails the build instead of hiding a failure. Verified zero current fires
|
|
# across the workspace, so this only guards against *future* silent drops.
|
|
#
|
|
# Companion clippy lints that catch the other swallow idioms are deferred to
|
|
# follow-up PRs because they need a real cleanup first (measured on this tree):
|
|
# * `clippy::let_underscore_must_use` — 67 sites (`let _ = <must_use>`), a mix
|
|
# of safe discards and genuine swallows (e.g. an ignored async delete).
|
|
# * `clippy::map_err_ignore` — ~861 sites; a blanket deny is wrong here since
|
|
# `.claude/rules/error-handling.md` permits `map_err` to a *specific* typed
|
|
# error and only forbids cause-dropping ones. Needs a scoped sweep.
|
|
unused_must_use = "deny"
|
|
|
|
[package]
|
|
# Tier B (see docs/internal/plans/2026-07-02-reborn-internal-module-refactor.md §8):
|
|
# the v1 legacy monolith (`src/`, package `ironclaw_legacy`, binary
|
|
# `ironclaw-legacy`) has been deleted. This package now exists solely to host
|
|
# the Reborn integration test suite (`tests/integration/*`, the `reborn_*`
|
|
# `[[test]]` targets below, and their shared `[dev-dependencies]`) — it has no
|
|
# library or binary target of its own.
|
|
name = "ironclaw_integration_tests"
|
|
publish = false
|
|
version = "0.1.0"
|
|
edition = "2024"
|
|
rust-version.workspace = true
|
|
license = "MIT OR Apache-2.0"
|
|
homepage = "https://github.com/nearai/ironclaw"
|
|
repository = "https://github.com/nearai/ironclaw"
|
|
|
|
[package.metadata.ironclaw]
|
|
layer = "app"
|
|
|
|
[package.metadata.dist]
|
|
dist = false
|
|
|
|
[dev-dependencies]
|
|
# Common utility crates the Reborn integration tests (`tests/integration/*`,
|
|
# `tests/reborn_*.rs`) reference directly — previously satisfied via the now-
|
|
# deleted v1 `[dependencies]` block, since regular deps were visible to test
|
|
# binaries too.
|
|
tokio = { version = "1", features = ["full"] }
|
|
serde = { version = "1", features = ["derive"] }
|
|
serde_json = "1"
|
|
async-trait = "0.1"
|
|
thiserror = "2"
|
|
chrono = { version = "0.4", features = ["serde"] }
|
|
uuid = { version = "1", features = ["v4", "v5", "serde"] }
|
|
secrecy = { version = "0.10", features = ["serde"] }
|
|
tracing = "0.1"
|
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
|
axum = { version = "0.8", features = ["ws"] }
|
|
tower = { version = "0.5", features = ["util"] }
|
|
reqwest = { version = "0.12", default-features = false, features = ["json", "multipart", "rustls-tls-native-roots", "stream"] }
|
|
base64 = "0.22"
|
|
rust_decimal = { version = "1", features = ["serde", "serde-with-str"] }
|
|
regex = "1"
|
|
sha2 = "0.11"
|
|
hex = "0.4"
|
|
url = "2"
|
|
toml = "1.1"
|
|
zip = { version = "8", default-features = false, features = ["deflate"] }
|
|
libsql = { version = "0.9", default-features = false, features = ["core", "replication", "remote", "tls"] }
|
|
# `test-support` exposes the witness-gated protocol-auth test seam and the
|
|
# messaging conformance helpers used by the integration fixtures. Declared
|
|
# explicitly because cfg(test) and sibling feature unification do not
|
|
# propagate reliably into an integration-test dependency graph.
|
|
ironclaw_host_api = { path = "crates/contracts/ironclaw_host_api", version = "0.1.0", features = ["test-support"] }
|
|
ironclaw_memory = { path = "crates/domains/ironclaw_memory", version = "0.1.0" }
|
|
# The production-backend memory integration scenario binds the native provider
|
|
# over the same libSQL composite used by memory tool dispatch.
|
|
ironclaw_memory_native = { path = "crates/extensions/packages/memory-native", version = "0.1.0" }
|
|
ironclaw_host_ingress = { path = "crates/product/ironclaw_host_ingress", version = "0.1.0" }
|
|
ironclaw_runtime_policy = { path = "crates/kernel/ironclaw_runtime_policy", version = "0.1.0" }
|
|
ironclaw_common = { path = "crates/contracts/ironclaw_common" }
|
|
ironclaw_safety = { path = "crates/substrates/ironclaw_safety" }
|
|
ironclaw_trace_commons = { path = "crates/domains/ironclaw_trace_commons", version = "0.1.0" }
|
|
# The Reborn integration harness provisions Postgres testcontainers in every
|
|
# feature lane (StorageMode::Postgres skips at runtime when unavailable), so
|
|
# the pool deps are unconditional dev-dependencies (the `postgres` feature is
|
|
# a marker with no dependency gating).
|
|
deadpool-postgres = "0.14"
|
|
tokio-postgres = { version = "0.7", features = ["with-uuid-1", "with-chrono-0_4", "with-serde_json-1"] }
|
|
# The generic-extension ingress/delivery integration suites verify webhook
|
|
# HMAC recipes and collect axum response bodies.
|
|
hmac = "0.13"
|
|
http-body-util = "0.1"
|
|
tokio-test = "0.4"
|
|
tracing-test = "0.2"
|
|
testcontainers-modules = { version = "0.12", features = ["postgres"] }
|
|
pretty_assertions = "1"
|
|
tempfile = "3"
|
|
insta = { version = "1.46.3", features = ["yaml"] }
|
|
# Pull the LLM crate's `testing` feature in only for tests so `StubLlm` and
|
|
# fault-injection helpers don't ship in release binaries.
|
|
ironclaw_llm = { path = "crates/domains/ironclaw_llm", version = "0.1.0", features = ["test-support"] }
|
|
ironclaw_agent_loop = { path = "crates/loop/ironclaw_agent_loop", version = "0.1.0", features = ["test-support"] }
|
|
ironclaw_approvals = { path = "crates/kernel/ironclaw_approvals", version = "0.1.0", features = ["test-support"] }
|
|
# Pull the auth crate's `test-support` feature in only for tests so the
|
|
# `test_support::conformance` OAuth-flow suite (used by the
|
|
# `reborn_integration_oauth_connect` test) doesn't ship in release binaries.
|
|
ironclaw_auth = { path = "crates/domains/ironclaw_auth", version = "0.1.0", features = ["test-support"] }
|
|
# C-ATTACH: `InboundAttachment` for `submit_turn_with_image_attachment`.
|
|
ironclaw_attachments = { path = "crates/domains/ironclaw_attachments", version = "0.1.0" }
|
|
# `test-support` enables the in-memory-backed capability-lease store constructor
|
|
# for the integration-test harness (cfg(test) does not propagate into deps).
|
|
ironclaw_authorization = { path = "crates/kernel/ironclaw_authorization", version = "0.1.0", features = ["test-support"] }
|
|
# Integration harness builds a fresh in-memory `ReplayPayloadStore`
|
|
# fallback for harnesses without shared approval parts (§5.3 Stage 2a-i).
|
|
ironclaw_capabilities = { path = "crates/kernel/ironclaw_capabilities", version = "0.1.0" }
|
|
ironclaw_extension_registry = { path = "crates/extensions/ironclaw_extension_registry", version = "0.1.0" }
|
|
# Extension-runtime P2: the invented-vendor fixture factory the integration
|
|
# harness registers (`NativeExtensionFactory`), plus scripted channel fakes.
|
|
ironclaw_extension_host = { path = "crates/extensions/ironclaw_extension_host", version = "0.1.0", features = ["test-support"] }
|
|
# WS2.4: the lifecycle service bundle the hosted-MCP registration integration
|
|
# test drives moved to the manager with the product face it builds.
|
|
ironclaw_extension_manager = { path = "crates/extensions/ironclaw_extension_manager", version = "0.1.0", features = ["test-support"] }
|
|
ironclaw_filesystem = { path = "crates/substrates/ironclaw_filesystem", version = "0.1.0" }
|
|
ironclaw_mcp = { path = "crates/lanes/ironclaw_mcp", version = "0.1.0" }
|
|
ironclaw_extension_support = { path = "crates/extensions/ironclaw_extension_support", version = "0.1.0" }
|
|
# W6-COLD-SPOTS: `CommunicationPreferenceRecord`/`CommunicationPreferenceKey`
|
|
# for the outbound-store-durability reopen test.
|
|
ironclaw_outbound = { path = "crates/domains/ironclaw_outbound", version = "0.1.0", features = ["test-support"] }
|
|
# Recording hook doubles + `HookDispatcherBuilderFactory` builders for the
|
|
# C-HOOKS / E-HOOK-INFRA int-tier coverage (tests/integration/support/hooks.rs).
|
|
ironclaw_hooks = { path = "crates/loop/ironclaw_hooks", version = "0.1.0" }
|
|
ironclaw_host_runtime = { path = "crates/kernel/ironclaw_host_runtime", version = "0.1.0" }
|
|
ironclaw_network = { path = "crates/substrates/ironclaw_network", version = "0.1.0" }
|
|
ironclaw_processes = { path = "crates/kernel/ironclaw_processes", version = "0.1.0", features = ["test-support"] }
|
|
ironclaw_resources = { path = "crates/kernel/ironclaw_resources", version = "0.1.0", features = ["test-support"] }
|
|
ironclaw_secrets = { path = "crates/substrates/ironclaw_secrets", version = "0.1.0" }
|
|
ironclaw_assistant = { path = "crates/product/ironclaw_assistant", version = "0.1.0", features = ["test-support"] }
|
|
ironclaw_turn_runner = { path = "crates/loop/ironclaw_turn_runner", version = "0.1.0", features = ["test-support"] }
|
|
# `ironclaw_webui` + `ironclaw_identity` sit on the int-tier coverage
|
|
# lane (identity_resolution_smoke / webui_v2_router_smoke); they compile into
|
|
# every int-tier build, behaviorally inert for suites that never call them.
|
|
# W5-SLACK-PAIR: the Slack host surface grows the lcov denominator by ~42k
|
|
# lines of slack_*.rs modules (previously invisible, not 0%) and unlocks
|
|
# composing them in int-tier tests. All 17 of those modules are recompiled
|
|
# into every int-tier test binary — a real, one-time build-time cost for the
|
|
# lane, behaviorally inert for suites that never reference Slack types.
|
|
ironclaw_composition = { path = "crates/app/ironclaw_composition", version = "0.1.0", features = ["test-support"] }
|
|
ironclaw_loop_host = { path = "crates/loop/ironclaw_loop_host", features = ["test-support"] }
|
|
# Direct dev-dep: composition deliberately does NOT re-export the bare
|
|
# `webui_v2_router`/`WebUiV2State` (facade-only rule), and the router smoke
|
|
# drives the bare router, not the `webui_v2_app` wrapper. The v2 route surface
|
|
# merged into `ironclaw_webui` (as its public `webui_v2` module).
|
|
ironclaw_webui = { path = "crates/product/ironclaw_webui", version = "0.1.0" }
|
|
# Direct dev-dep for the same reason as ironclaw_webui above: composition's
|
|
# facade-only rule means it re-exports no SLACK_V2_ADAPTER_ID/SLACK_USER_ACTOR_KIND-style
|
|
# constants; Slack pairing/actor-resolution int-tier tests need them directly.
|
|
ironclaw_slack_extension = { path = "crates/extensions/packages/slack", version = "0.1.0" }
|
|
ironclaw_telegram_extension = { path = "crates/extensions/packages/telegram", version = "0.1.0" }
|
|
ironclaw_web_push = { path = "crates/domains/ironclaw_web_push", version = "0.1.0" }
|
|
ironclaw_web_push_extension = { path = "crates/extensions/packages/web-push", version = "0.1.0" }
|
|
ironclaw_config = { path = "crates/app/ironclaw_config", version = "0.1.0" }
|
|
ironclaw_openai_compat = { path = "crates/product/ironclaw_openai_compat", version = "0.1.0"}
|
|
ironclaw_threads = { path = "crates/domains/ironclaw_threads", version = "0.1.0" }
|
|
# `test-support` unlocks the shared in-memory process-journal-backed turn
|
|
# runtime used by integration tests. cfg(test) does not propagate from an
|
|
# integration-test binary into its deps, so the feature is explicit here.
|
|
ironclaw_loop_contracts = { path = "crates/contracts/ironclaw_loop_contracts", version = "0.1.0" }
|
|
ironclaw_extension_contracts = { path = "crates/contracts/ironclaw_extension_contracts", version = "0.1.0" }
|
|
ironclaw_product_contracts = { path = "crates/contracts/ironclaw_product_contracts", version = "0.1.0" }
|
|
ironclaw_turns = { path = "crates/kernel/ironclaw_turns", version = "0.1.0", features = ["test-support"] }
|
|
# `InMemoryDurableEventLog` for the W5-WEBUI-API-1 SSE scenario's test-local
|
|
# `ProjectionStream` wiring (`build_webui_event_stream_for_test`).
|
|
ironclaw_event_log = { path = "crates/events/ironclaw_event_log", version = "0.1.0" }
|
|
# Binary Reborn E2E recovery scenarios replay the milestone-backed durable log
|
|
# through the production event projection service.
|
|
ironclaw_event_projections = { path = "crates/events/ironclaw_event_projections", version = "0.1.0" }
|
|
# `test-support` unlocks `TrustedTriggerSubmitRequest::new_for_test` (E-TRIGGERED-SUBMIT
|
|
# harness seam) — cfg(test) does not propagate from an integration-test binary into its deps.
|
|
ironclaw_triggers = { path = "crates/domains/ironclaw_triggers", version = "0.1.0", features = ["test-support"] }
|
|
# Trigger-conversation binding/session services for the E-TRIGGERED-SUBMIT harness seam —
|
|
# mirrors the conversation-services type production's own local-dev build wires for the
|
|
# trusted-trigger submit path (ironclaw_composition::runtime.rs).
|
|
ironclaw_conversations = { path = "crates/domains/ironclaw_conversations", version = "0.1.0" }
|
|
ironclaw_trust = { path = "crates/kernel/ironclaw_trust", version = "0.1.0" }
|
|
ironclaw_wasm = { path = "crates/lanes/ironclaw_wasm", version = "0.1.0" }
|
|
# `ironclaw_outbound/test-support` provides the in-memory-backed
|
|
# `OutboundStateStore` the triggered-delivery outcome-seam int-tier
|
|
# proof injects (asserting a real `TriggeredRunDeliveryDriver`'s recorded
|
|
# outcome via the same public store trait the composition factory accepts).
|
|
# Named `#[case]` parametrization for the storage-backend matrix tests (slice 3).
|
|
rstest = "0.23"
|
|
|
|
[features]
|
|
# Opt-in feature for especially heavy integration-test targets that run in a
|
|
# dedicated CI job instead of the default Rust test matrix.
|
|
integration = []
|
|
|
|
[[test]]
|
|
name = "reborn_group_approvals"
|
|
path = "tests/integration/group_approvals/main.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_group_memory"
|
|
path = "tests/integration/group_memory/main.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_group_extensions"
|
|
path = "tests/integration/group_extensions/main.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_group_triggers"
|
|
path = "tests/integration/group_triggers/main.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_group_multiuser"
|
|
path = "tests/integration/group_multiuser/main.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_group_skills"
|
|
path = "tests/integration/group_skills/main.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_generated_gate_sequences"
|
|
path = "tests/integration/generated_gate_sequences.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_generated_restart_sequences"
|
|
path = "tests/integration/generated_restart_sequences.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_group_journeys"
|
|
path = "tests/integration/group_journeys/main.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_oauth_refresh"
|
|
path = "tests/integration/auth/oauth_refresh.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_attach"
|
|
path = "tests/integration/attach.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_sandbox_shell_turn"
|
|
path = "tests/integration/reborn_sandbox_shell_turn.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_subagent_await_edge"
|
|
path = "tests/integration/subagent_await_edge.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_auth_failure"
|
|
path = "tests/integration/auth/auth_failure.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_auth_gate"
|
|
path = "tests/integration/auth/auth_gate.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_backend_matrix"
|
|
path = "tests/integration/backend_matrix.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_budget"
|
|
path = "tests/integration/budget.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_cancel"
|
|
path = "tests/integration/cancel.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_steering"
|
|
path = "tests/integration/steering.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_model_recovery"
|
|
path = "tests/integration/model_recovery.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_terminal_warning"
|
|
path = "tests/integration/terminal_warning.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_channel_connection_projection"
|
|
path = "tests/integration/channel_connection_projection.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_comm_context"
|
|
path = "tests/integration/comm_context.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_durable"
|
|
path = "tests/integration/durable.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_delivery_user_journeys"
|
|
path = "tests/integration/delivery_user_journeys.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_extension_runtime"
|
|
path = "tests/integration/extension_runtime.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_extension_ingress"
|
|
path = "tests/integration/extension_ingress.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_extension_delivery"
|
|
path = "tests/integration/extension_delivery.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_extension_visibility"
|
|
path = "tests/integration/extension_visibility.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_extension_user_lifecycle_isolation"
|
|
path = "tests/integration/extension_user_lifecycle_isolation.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_golden_payload"
|
|
path = "tests/integration/golden_payload.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_greeting"
|
|
path = "tests/integration/greeting.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_hooks"
|
|
path = "tests/integration/hooks.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_http_matcher"
|
|
path = "tests/integration/http_matcher.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_idempotent_replay"
|
|
path = "tests/integration/idempotent_replay.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_identity_resolution_smoke"
|
|
path = "tests/integration/identity_resolution_smoke.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_lease_wedge"
|
|
path = "tests/integration/lease_wedge.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_mcp"
|
|
path = "tests/integration/mcp.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_hosted_mcp_registration"
|
|
path = "tests/integration/hosted_mcp_registration.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_oauth_connect"
|
|
path = "tests/integration/auth/oauth_connect.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_oauth_popup_journeys"
|
|
path = "tests/integration/auth/oauth_popup_journeys.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_outbound_store_durability"
|
|
path = "tests/integration/outbound_store_durability.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_outbound_target"
|
|
path = "tests/integration/outbound_target.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_process_port"
|
|
path = "tests/integration/process_port.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_profile"
|
|
path = "tests/integration/profile.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_project_create"
|
|
path = "tests/integration/project_create.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_real_egress_pipeline"
|
|
path = "tests/integration/real_egress_pipeline.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_reopen_resume_through_gate"
|
|
path = "tests/integration/auth/reopen_resume_through_gate.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_safety"
|
|
path = "tests/integration/safety.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_secret_injection"
|
|
path = "tests/integration/secret_injection.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_secrets"
|
|
path = "tests/integration/secrets.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_skill_activate"
|
|
path = "tests/integration/skill_activate.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_surface_disclosure"
|
|
path = "tests/integration/surface_disclosure.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_tool_call"
|
|
path = "tests/integration/tool_call.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_tool_disclosure"
|
|
path = "tests/integration/tool_disclosure.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_trace_capture"
|
|
path = "tests/integration/trace_capture.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_tracecap"
|
|
path = "tests/integration/tracecap.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_triggered_submit"
|
|
path = "tests/integration/triggered_submit.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_web_access"
|
|
path = "tests/integration/web_access.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_webui_v2_product_api"
|
|
path = "tests/integration/webui_v2_product_api.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_webui_v2_router_smoke"
|
|
path = "tests/integration/webui_v2_router_smoke.rs"
|
|
|
|
[[test]]
|
|
name = "reborn_integration_wiring_parity"
|
|
path = "tests/integration/wiring_parity.rs"
|
|
|
|
[profile.release]
|
|
strip = true # Remove debug symbols from release binaries
|
|
|
|
# The profile that 'cargo dist' will build with
|
|
[profile.dist]
|
|
inherits = "release"
|
|
lto = "thin"
|
|
|
|
# Config for 'dist'
|
|
[workspace.metadata.dist]
|
|
# The preferred dist version to use in CI (Cargo.toml SemVer syntax)
|
|
cargo-dist-version = "0.31.0"
|
|
# cargo-dist 0.31 grants `contents: write` to every generated job. Keep the
|
|
# checked-in CI customized so only the host job can publish a GitHub Release.
|
|
allow-dirty = ["ci"]
|
|
# Release only the canonical Reborn CLI.
|
|
packages = ["ironclaw"]
|
|
# CI backends to support
|
|
ci = "github"
|
|
# Match the canonical `ironclaw-v*` release tags.
|
|
tag-namespace = "ironclaw"
|
|
# Install build-only prerequisites before cargo-dist compiles each target.
|
|
github-build-setup = "../dist-build-setup.yml"
|
|
# The installers to generate for each app
|
|
installers = ["shell", "powershell", "msi"]
|
|
# Publish jobs to run in CI
|
|
publish-jobs = []
|
|
# Target platforms to build apps for (Rust target-triple syntax)
|
|
targets = [
|
|
"aarch64-apple-darwin",
|
|
"aarch64-unknown-linux-gnu",
|
|
"aarch64-unknown-linux-musl",
|
|
"x86_64-apple-darwin",
|
|
"x86_64-unknown-linux-gnu",
|
|
"x86_64-unknown-linux-musl",
|
|
"x86_64-pc-windows-msvc",
|
|
]
|
|
# The archive format to use for windows builds (defaults .zip)
|
|
windows-archive = ".tar.gz"
|
|
# The archive format to use for non-windows builds (defaults .tar.xz)
|
|
unix-archive = ".tar.gz"
|
|
# Which actions to run on pull requests
|
|
pr-run-mode = "skip"
|
|
# Path that installers should place binaries in
|
|
install-path = "CARGO_HOME"
|
|
# Whether to install an updater program
|
|
install-updater = true
|
|
# Cache intermediate build artifacts to speed up the release pipelines
|
|
cache-builds = true
|
|
|
|
[workspace.metadata.dist.github-custom-runners]
|
|
aarch64-unknown-linux-gnu = "ubuntu-24.04-arm"
|
|
aarch64-unknown-linux-musl = "ubuntu-24.04-arm"
|
|
x86_64-unknown-linux-gnu = "ubuntu-22.04"
|
|
x86_64-unknown-linux-musl = "ubuntu-22.04"
|
|
x86_64-pc-windows-msvc = "windows-2022"
|
|
x86_64-apple-darwin = "macos-15-intel"
|
|
aarch64-apple-darwin = "macos-14"
|
|
|
|
[workspace.metadata.dist.github-action-commits]
|
|
"actions/checkout" = "df4cb1c069e1874edd31b4311f1884172cec0e10"
|
|
"actions/download-artifact" = "37930b1c2abaa49bbe596cd826c3c89aef350131"
|
|
"actions/upload-artifact" = "b7c566a772e6b6bfb58ed0dc250532a479d7789f"
|
|
"swatinem/rust-cache" = "e18b497796c12c097a38f9edb9d0641fb99eee32"
|