Skip to content

refactor(messaging): move build setup to manifest hooks#4949

Merged
cv merged 28 commits into
mainfrom
feat/issue-4395-manifest-hooks
Jun 11, 2026
Merged

refactor(messaging): move build setup to manifest hooks#4949
cv merged 28 commits into
mainfrom
feat/issue-4395-manifest-hooks

Conversation

@sandl99

@sandl99 sandl99 commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Migrate messaging build setup from legacy Docker build scripts and ad hoc build args into manifest-driven hooks. OpenClaw and Hermes now consume the staged messaging plan for package installs, static render outputs, and WeChat post-agent-install behavior.

Related Issue

Fixes #4395

Changes

  • Add common manifest hook support for static outputs and package-install build steps.
  • Replace the OpenClaw messaging build script with scripts/run-openclaw-build-hooks.mts and wire Docker builds through NEMOCLAW_MESSAGING_PLAN_B64.
  • Move Hermes messaging render/env handling to manifest hook application and remove agents/hermes/config/messaging-config.ts.
  • Remove old messaging build/env Docker args and deleted legacy script tests.
  • Update onboarding/rebuild/policy-channel tests and helpers for manifest plan based messaging setup.

Type of Change

  • Code change (feature, bug fix, or refactor)
  • Code change with doc updates
  • Doc only (prose changes, no code sample modifications)
  • Doc only (includes code sample changes)

Verification

Targeted checks run: npm run build:cli, npm run typecheck:cli, npx vitest run test/onboard-messaging.test.ts, npx vitest run src/lib/messaging/hooks/common/token-paste.test.ts, git diff --check.

  • npx prek run --all-files passes
  • npm test passes
  • Tests added or updated for new or changed behavior
  • No secrets, API keys, or credentials committed
  • Docs updated for user-facing behavior changes
  • npm run docs builds without warnings (doc changes only)
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Signed-off-by: San Dang sdang@nvidia.com

Summary by CodeRabbit

  • Refactor
    • Consolidated per-channel messaging inputs into a single encoded messaging plan and simplified image build/config generation.
  • New Features
    • Messaging manifest hooks run during image builds (pre/post agent-install) to render configs, install agent plugins, and seed account metadata so agents start preconfigured.
    • Hermes now derives per-platform entries and toolset wiring from the messaging plan.
  • Chores
    • Removed legacy messaging helper scripts and migrated provisioning into the manifest-driven pipeline.
  • Tests
    • Updated and added tests covering messaging-plan handling, build phases, rendering, and apply behavior.

@sandl99 sandl99 self-assigned this Jun 8, 2026
@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Switch messaging to a manifest-driven build plan (NEMOCLAW_MESSAGING_PLAN_B64). Compiler resolves render templates and runs hooks to emit OpenClaw JSON/env/files and package-install steps. A TypeScript applier executes agent-install and post-agent-install phases during Docker image build and sandbox rebuilds. Onboarding and tests updated to use plan transport.

Changes

Manifest-driven messaging migration

Layer / File(s) Summary
Manifest contracts & render templates
src/lib/messaging/manifest/types.ts, src/lib/messaging/compiler/engines/template.ts
Add when render guards, new hook phases/outputs (agent-install, package-install, agent-render), and a render-template engine (resolveRenderTemplatesInValue/Lines, isTruthyRenderTemplate).
Async hook-driven planning
src/lib/messaging/compiler/engines/agent-render-engine.ts, src/lib/messaging/compiler/engines/build-step-engine.ts, src/lib/messaging/compiler/manifest-compiler.ts
planAgentRender and planBuildSteps are async and invoke messaging hooks (including common.staticOutputs) to produce agent render plans and build-step plans with optional value, hookId, and handler metadata.
Common static outputs hook
src/lib/messaging/hooks/common/static-outputs.ts, src/lib/messaging/hooks/common/index.ts
New common.staticOutputs handler and registration factory that validates required outputs and returns structured hook outputs for static render/build declarations.
Channel manifests extended
src/lib/messaging/channels/*/manifest.ts (Discord, Slack, Telegram, WeChat, WhatsApp)
Channel manifests now render OpenClaw JSON fragments, Hermes env/config fragments, persist state (where needed), and declare agent-install package-install hooks for OpenClaw plugins.
Hermes config/env refactor
agents/hermes/config/build-env.ts, agents/hermes/config/hermes-config.ts, agents/hermes/config/hermes-env.ts, agents/hermes/generate-config.ts
Remove legacy per-channel messaging wiring; expose buildHermesEnvLines and finalizeHermesPlatformToolsets to derive enabled platforms/toolsets. Build settings no longer include messaging fields.
Messaging build applier (new)
src/lib/messaging/applier/build/messaging-build-applier.mts, test/messaging-build-applier.test.ts
New applier reads NEMOCLAW_MESSAGING_PLAN_B64, validates plan, applies agent renders (JSON fragments, env-lines, local files), performs agent-install (plugin installs + doctor env overrides) and post-agent-install file application, with CLI --dry-run. Covered by functional tests.
Agent config application & placeholder preservation
src/lib/messaging/applier/agent-config.ts, src/lib/messaging/applier/setup-applier.test.ts
applyJsonFragments preserves runtime credential placeholders and deep-merges objects at target JSON paths; tests updated for expectations and placeholder preservation.
Dockerfile and image build changes
Dockerfile, agents/hermes/Dockerfile, scripts/generate-openclaw-config.mts, scripts/lib/sandbox-init.sh
Consolidate messaging inputs to ARG NEMOCLAW_MESSAGING_PLAN_B64; copy TS messaging scripts into image; run messaging-build-applier.mts --phase agent-install and later --phase post-agent-install during build; remove legacy Python scripts.
Onboarding & Dockerfile patching
src/lib/onboard.ts, src/lib/onboard/dockerfile-patch.ts, src/lib/onboard/* tests
Onboarding drops legacy messaging-config collection, derives providers from current tokens, and patchStagedDockerfile injects encoded messaging plan ARG via MessagingSetupApplier; tests updated to construct/validate plan ARGs.
Rebuild-time reapplication
src/lib/actions/sandbox/rebuild.ts
After openclaw doctor --fix, reapply staged messaging render and post-agent-install hooks to restore seed files (e.g., WeChat) and config changes; adds OpenShell runner input plumbing.
OpenShell stdin support
src/lib/adapters/openshell/client.ts, src/lib/adapters/openshell/runtime.ts
Runner options gain input?: string, forwarded to spawned OpenShell commands to support hook inputs.
Tests & helpers
test/messaging-plan-test-helper.ts, various manifest/generator/onboard tests
New test helper builds messaging plans; many tests updated to use plan env, validate Hermes/OpenClaw outputs, and assert canonical WeChat paths; removed legacy seed/py-script tests.
Docs & CI
scripts/lib/sandbox-init.sh, agents/hermes/policy-additions.yaml, src/ext/wechat/qr.ts, test/e2e/*, ci/test-file-size-budget.json
Comments and e2e text updated to reference manifest hook ownership for WeChat seed behavior; CI budgets tweaked.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • NVIDIA/NemoClaw#4945: Related plan-backed messaging migration affecting sandbox lifecycle and rebuild application.

Suggested labels

enhancement: messaging

Poem

🐰 I baked a plan in base64 light,

Hooks hummed softly through the night.
Plugins pinned and fragments laid,
Hermes woke, configs obeyed.
A rabbit cheers — builds now neat!

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/issue-4395-manifest-hooks

Comment thread agents/hermes/config/manifest-hooks.ts Fixed
Comment thread scripts/generate-openclaw-config.mts Fixed
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: messaging-providers-e2e, channels-stop-start-e2e, channels-add-remove-e2e, token-rotation-e2e, hermes-discord-e2e, hermes-slack-e2e, hermes-secret-boundary-e2e, hermes-e2e, openclaw-onboard-security-posture-e2e, hermes-onboard-security-posture-e2e, rebuild-openclaw-e2e, rebuild-hermes-e2e, network-policy-e2e
Optional E2E: messaging-compatible-endpoint-e2e, inference-routing-e2e, sandbox-survival-e2e, credential-sanitization-e2e, openclaw-discord-pairing-e2e, openclaw-slack-pairing-e2e

Dispatch hint: messaging-providers-e2e,channels-stop-start-e2e,channels-add-remove-e2e,token-rotation-e2e,hermes-discord-e2e,hermes-slack-e2e,hermes-secret-boundary-e2e,hermes-e2e,openclaw-onboard-security-posture-e2e,hermes-onboard-security-posture-e2e,rebuild-openclaw-e2e,rebuild-hermes-e2e,network-policy-e2e

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • messaging-providers-e2e (high): Required because the PR rewrites the messaging credential/provider/placeholder path and channel manifests across Telegram, Discord, Slack, WeChat, and WhatsApp; this job validates the provider/placeholder/L7-proxy chain in a real sandbox.
  • channels-stop-start-e2e (very high): Required because stop/start lifecycle, cached credential reattachment, WeChat base URL handling, and all-channel OpenClaw/Hermes config rendering are directly affected by the new messaging build-plan/applier path.
  • channels-add-remove-e2e (high): Required because channel add/remove plus rebuild exercises the host-side channel mutation path changed in onboarding, registry state, sandbox rebuild, policy-channel, and messaging plan generation.
  • token-rotation-e2e (medium): Required because credential propagation through rebuild/re-onboard was changed by the new messaging plan and provider placeholder model; this job proves rotated Telegram/Discord/Slack credentials reach the sandbox and do not cross-talk.
  • hermes-discord-e2e (high): Required because Hermes Discord configuration moved from the deleted Hermes messaging-config.ts into manifest/applier rendering, while the Hermes Discord E2E script was also touched.
  • hermes-slack-e2e (high): Required because Hermes Slack enablement, env placeholders, provider rewrite, and policy/application are now produced by the shared messaging applier rather than the old Hermes config generator.
  • hermes-secret-boundary-e2e (medium): Required because Hermes Dockerfile/config/env generation and messaging hooks changed the path that writes credential placeholders into the image; this must prove raw secret-shaped values do not enter sandbox env/config.
  • hermes-e2e (high): Required as the baseline Hermes install/onboard/health/live-inference proof after Dockerfile, config generation, platform toolsets, and messaging applier build steps changed.
  • openclaw-onboard-security-posture-e2e (high): Required because OpenClaw Dockerfile/config generation and onboarding paths changed, including runtime initialization and build-time config rendering that affect the real user onboarding and sandbox security posture.
  • hermes-onboard-security-posture-e2e (high): Required because Hermes onboarding and image build changed in ways that can affect non-root host assumptions, trusted rc-file setup, runtime guards, and Hermes sandbox security posture.
  • rebuild-openclaw-e2e (high): Required because OpenClaw image build layers, generate-openclaw-config, sandbox build context, and rebuild action changed; this verifies a real OpenClaw sandbox rebuild remains functional.
  • rebuild-hermes-e2e (high): Required because Hermes Dockerfile now executes the shared messaging applier during agent-install and post-agent-install phases; this verifies real Hermes rebuild lifecycle.
  • network-policy-e2e (medium): Required because messaging channel policy application and Hermes messaging policy assets changed, and network policy is a security boundary for provider egress.

Optional E2E

  • messaging-compatible-endpoint-e2e (medium): Useful adjacent coverage for Telegram messaging plus OpenAI-compatible inference routing through inference.local after config generation and OpenShell adapter changes.
  • inference-routing-e2e (medium): Useful because Dockerfile/config generation and OpenShell runtime adapters changed, but the primary diff is messaging rather than model routing.
  • sandbox-survival-e2e (medium): Useful confidence for sandbox/gateway stop-start survival after sandbox state, OpenShell adapters, and sandbox-init changes, but less targeted than rebuild and channel lifecycle jobs.
  • credential-sanitization-e2e (medium): Useful adjacent security proof for secret redaction/filtering after messaging placeholder and credential-filter related changes; not as directly targeted as messaging-providers and Hermes secret-boundary.
  • openclaw-discord-pairing-e2e (medium): Useful extra OpenClaw Discord gateway placeholder/pairing proof because Discord manifest/template handling changed, but channels-stop-start and messaging-providers already cover core Discord provider paths.
  • openclaw-slack-pairing-e2e (medium): Useful extra OpenClaw Slack Socket Mode pairing proof because Slack manifest/template handling changed, but channels-stop-start and messaging-providers already cover core Slack provider paths.

New E2E recommendations

  • messaging-build-plan-applier (high): The new shared manifest/compiler/applier architecture is central to both OpenClaw and Hermes image builds. Existing lifecycle tests cover it indirectly, but a cheaper dedicated E2E could build both agents with a representative NEMOCLAW_MESSAGING_PLAN_B64 and assert rendered config/plugin files/providers without full stop/start churn.
    • Suggested test: Add a messaging-build-plan-applier-e2e that onboards OpenClaw and Hermes with fake Telegram/Discord/Slack/WeChat/WhatsApp inputs, inspects the built sandbox configs and provider registrations, and verifies no raw tokens are present.
  • wechat-ilink-runtime (medium): WeChat is experimental and the PR changes iLink base URL handling, seed hooks, and OpenClaw plugin installation. Current CI uses fake/noninteractive metadata and cannot prove a live QR/iLink handshake.
    • Suggested test: Add an opt-in manual wechat-ilink-live-e2e using dedicated test WeChat credentials or a controlled mock iLink service to validate QR login, token capture, seed-file rendering, and post-rebuild start.
  • hermes-multi-channel-runtime (medium): Hermes has dedicated Discord and Slack jobs plus all-channel lifecycle coverage, but there is no focused Hermes Telegram/WeChat/WhatsApp provider/env rendering E2E with per-channel assertions comparable to the OpenClaw-specific pairing checks.
    • Suggested test: Add a hermes-messaging-matrix-e2e that enables Telegram, WeChat, and WhatsApp on Hermes and asserts config.yaml/.env/platform startup behavior and OpenShell credential placeholders per channel.

Dispatch hint

  • Workflow: .github/workflows/nightly-e2e.yaml
  • jobs input: messaging-providers-e2e,channels-stop-start-e2e,channels-add-remove-e2e,token-rotation-e2e,hermes-discord-e2e,hermes-slack-e2e,hermes-secret-boundary-e2e,hermes-e2e,openclaw-onboard-security-posture-e2e,hermes-onboard-security-posture-e2e,rebuild-openclaw-e2e,rebuild-hermes-e2e,network-policy-e2e

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Vitest E2E Scenario Recommendation

Required Vitest E2E scenarios: ubuntu-repo-cloud-openclaw, ubuntu-repo-docker-post-reboot-recovery
Optional Vitest E2E scenarios: None

Dispatch required Vitest E2E scenarios:

  • gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw
  • gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-docker-post-reboot-recovery

Workflow run

Full Vitest E2E advisor summary

Vitest E2E Scenario Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required Vitest E2E scenarios

  • ubuntu-repo-cloud-openclaw: Core OpenClaw onboarding and sandbox-image behavior changed: Dockerfile/base image layers, OpenClaw config generation, sandbox init, OpenShell adapter/runtime, onboarding, build context, and the new messaging build-plan path all affect the repo-current Docker cloud OpenClaw live path. This is the smallest live-supported Vitest scenario that builds/onboards a current OpenClaw sandbox and validates steady-state smoke, inference, and credential behavior.
    • Dispatch: gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-openclaw
  • ubuntu-repo-docker-post-reboot-recovery: State and sandbox lifecycle surfaces changed (src/lib/state/registry.ts, src/lib/state/sandbox.ts, sandbox actions, OpenShell runtime/client). The live-supported post-reboot recovery scenario exercises host registry/container preservation and status behavior after a lifecycle mutation, covering the highest-risk state-management path available in the Vitest scenario registry.
    • Dispatch: gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-docker-post-reboot-recovery

Optional Vitest E2E scenarios

  • None.

Relevant changed files

  • Dockerfile
  • Dockerfile.base
  • agents/hermes/Dockerfile
  • agents/hermes/config/build-env.ts
  • agents/hermes/config/hermes-config.ts
  • agents/hermes/config/hermes-env.ts
  • agents/hermes/config/messaging-config.ts
  • agents/hermes/generate-config.ts
  • agents/hermes/policy-additions.yaml
  • scripts/generate-openclaw-config.mts
  • scripts/lib/sandbox-init.sh
  • scripts/openclaw-build-messaging-plugins.py
  • scripts/seed-wechat-accounts.py
  • src/ext/wechat/qr.ts
  • src/lib/actions/sandbox/policy-channel.ts
  • src/lib/actions/sandbox/rebuild.ts
  • src/lib/adapters/openshell/client.ts
  • src/lib/adapters/openshell/runtime.ts
  • src/lib/messaging-channel-config.ts
  • src/lib/messaging/applier/agent-config.ts
  • src/lib/messaging/applier/build/messaging-build-applier.mts
  • src/lib/messaging/channels/discord/manifest.ts
  • src/lib/messaging/channels/discord/template-resolver.ts
  • src/lib/messaging/channels/index.ts
  • src/lib/messaging/channels/slack/manifest.ts
  • src/lib/messaging/channels/slack/template-resolver.ts
  • src/lib/messaging/channels/telegram/manifest.ts
  • src/lib/messaging/channels/telegram/template-resolver.ts
  • src/lib/messaging/channels/template-resolver-utils.ts
  • src/lib/messaging/channels/template-resolver.ts
  • src/lib/messaging/channels/wechat/hooks/ilink-login.ts
  • src/lib/messaging/channels/wechat/hooks/seed-openclaw-account.ts
  • src/lib/messaging/channels/wechat/ilink-base-url.ts
  • src/lib/messaging/channels/wechat/manifest.ts
  • src/lib/messaging/channels/wechat/template-resolver.ts
  • src/lib/messaging/channels/whatsapp/manifest.ts
  • src/lib/messaging/channels/whatsapp/template-resolver.ts
  • src/lib/messaging/compiler/engines/agent-render-engine.ts
  • src/lib/messaging/compiler/engines/build-step-engine.ts
  • src/lib/messaging/compiler/engines/template.ts
  • src/lib/messaging/compiler/manifest-compiler.ts
  • src/lib/messaging/compiler/workflow-planner.ts
  • src/lib/messaging/hooks/common/index.ts
  • src/lib/messaging/hooks/common/static-outputs.ts
  • src/lib/messaging/manifest/types.ts
  • src/lib/onboard.ts
  • src/lib/onboard/dockerfile-patch.ts
  • src/lib/onboard/messaging-channel-setup.ts
  • src/lib/onboard/messaging-config.ts
  • src/lib/onboard/wechat-config.ts
  • src/lib/sandbox/build-context.ts
  • src/lib/state/registry.ts
  • src/lib/state/sandbox.ts

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor

Findings: 3 needs attention, 9 worth checking, 0 nice ideas
Since last review: 2 prior items resolved, 8 still apply, 0 new items found

Review findings

🛠️ Needs attention

  • Legacy rebuild plans still omit hooks and the render resolver (src/lib/actions/sandbox/rebuild.ts:202): The real rebuild staging path still constructs MessagingWorkflowPlanner with only createBuiltInChannelManifestRegistry(). For legacy registry entries with messagingChannels but no persisted messaging.plan, rebuild compiles without the built-in hook registry or createBuiltInRenderTemplateResolver(), so manifest render references can remain unresolved and hook-derived build-file outputs such as WeChat account seeding can be absent. This leaves issue Phase 5: migrate messaging agent rendering and build inputs to manifests #4395's rebuild hydration/rendering acceptance only partial.
    • Recommendation: Construct the rebuild planner with createBuiltInMessagingHookRegistry() and createBuiltInRenderTemplateResolver(), matching onboard/add-channel. Add a regression that stages rebuild from a legacy registry entry with Telegram, Discord, Slack, and WeChat config and asserts no unresolved {{...}} render templates plus expected WeChat post-agent-install build-file outputs.
    • Evidence: stageMessagingManifestPlanForRebuild() creates new MessagingWorkflowPlanner(createBuiltInChannelManifestRegistry()). Onboard/add-channel code paths construct the planner with createBuiltInMessagingHookRegistry() and createBuiltInRenderTemplateResolver().
  • Post-doctor messaging reapply failures are still treated as a skip (src/lib/actions/sandbox/rebuild.ts:253): After openclaw doctor --fix, manifest-owned channel config and WeChat seed files may need to be reapplied. The rebuild helper catches every reapply error, logs a dim skipped message, and does not feed that failure into rebuild success/degraded status, so rebuild can appear successful while messaging config is stale or broken.
    • Recommendation: Return reapply status to the rebuild flow and mark rebuild degraded or failed when enabled OpenClaw messaging channels require reapply. Add a regression where post-doctor reapply throws and the final rebuild output/result clearly reports that messaging config was not restored.
    • Evidence: reapplyMessagingManifestAfterOpenClawDoctor() catches err, logs Messaging manifest reapply failed, and prints Messaging manifest config reapply skipped; no status is returned to the later rebuild result.
  • Large security-sensitive hotspots grew during the build-hook refactor: This PR changes Docker image build setup, manifest compilation, credential placeholders, and rebuild behavior while increasing several already-large hotspot files. The growth makes future review harder in code that controls sandbox lifecycle, credential rendering, and image build behavior.
    • Recommendation: Extract the new planner/compiler/rebuild helper logic or offset the growth in the same hotspots before merge. Avoid normalizing additional growth in existing large files that control sandbox lifecycle, credential rendering, and image build behavior.
    • Evidence: Deterministic monolith context reports growth in src/lib/messaging/compiler/manifest-compiler.test.ts (+166), src/lib/messaging/applier/agent-config.ts (+94), src/lib/messaging/compiler/workflow-planner.test.ts (+93), src/lib/messaging/compiler/manifest-compiler.ts (+54), src/lib/actions/sandbox/rebuild.ts (+47), src/lib/messaging/compiler/workflow-planner.ts (+47), and src/lib/messaging/applier/setup-applier.test.ts (+41).

🔎 Worth checking

  • Source-of-truth review needed: OpenClaw image build post-agent-install apply, doctor, and reapply: The advisor marked localized patch analysis as needs_followup.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: applyMessagingBuildPhase() applies post-agent-install outputs, runs runOpenClawMessagingDoctor(), then reapplies outputs for OpenClaw.
  • Source-of-truth review needed: Rebuild post-doctor messaging manifest reapply: The advisor marked localized patch analysis as missing.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: reapplyMessagingManifestAfterOpenClawDoctor() catches all errors and logs Messaging manifest config reapply skipped.
  • Source-of-truth review needed: Credential-placeholder preservation on messaging reapply: The advisor marked localized patch analysis as needs_followup.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: preserveCredentialPlaceholders() keeps existing placeholders matching the same env key through isProviderPlaceholderForEnvKey() and placeholderSuffixMatchesEnvKey(), including vN_ suffixes.
  • Source-of-truth review needed: Compatibility fallback for older build steps without hook phase: The advisor marked localized patch analysis as needs_followup.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: buildStepMatchesPhase() falls back by output kind when findHookPhase() returns undefined.
  • Source-of-truth review needed: Line-break tolerant credential/config normalization: The advisor marked localized patch analysis as missing.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: normalizeCredentialValue(), config-prompt normalizeConfigValue(), and openshell-provider readCredentialEnv() use CR-stripping/trim patterns rather than rejecting LF.
  • Serialized messaging plans can carry stable credential fingerprints (src/lib/messaging/compiler/engines/credential-binding-engine.ts:26): The compiler adds an unsalted credentialHash when credentials are available, and dockerfile-patch.ts serializes the whole messaging plan into ARG NEMOCLAW_MESSAGING_PLAN_B64. Raw tokens are avoided, but stable cross-sandbox token fingerprints can still be baked into Docker build args or patched Dockerfiles outside the OpenShell credential store.
    • Recommendation: Keep credential hashes out of the Docker build transport, or split host-only conflict metadata from the image build plan. Add decoded-plan tests asserting raw tokens and credentialHash/fingerprint values are absent from NEMOCLAW_MESSAGING_PLAN_B64 while placeholders remain.
    • Evidence: planCredentialBindings() computes hashCredential(process.env[envKey]); dockerfile-patch.ts replaces ARG NEMOCLAW_MESSAGING_PLAN_B64 with MessagingSetupApplier.encodePlan(messagingPlan).
  • Token and config normalization should reject LF before persistence or provider upsert (src/lib/messaging/hooks/common/token-paste.ts:169): New render/build paths reject CR/LF before writing env files or build outputs, but token-paste, config-prompt, and OpenShell provider credential reads still strip carriage returns and trim without rejecting embedded line feeds before saving credentials, returning hook outputs, or upserting providers.
    • Recommendation: Reject any token-paste secret, config-prompt value, and provider credential containing CR or LF before saving, emitting, or passing it to OpenShell provider create/update. Add negative tests proving LF-containing values are not saved, emitted, or upserted.
    • Evidence: token-paste normalizeCredentialValue() uses value.replace(/\r/g, '').trim(); common config-prompt uses the same CR-stripping pattern; messaging/applier/openshell-provider.ts readCredentialEnv() also strips CR and trims.
  • Runtime image validation is still needed for build-time messaging hooks (Dockerfile:673): This PR changes Dockerfile ordering, trusted TypeScript copied into images, OpenClaw plugin installation, Hermes config generation, and WeChat account seed files. Unit and subprocess tests cover important logic, but they do not prove representative built image contents or startup-time consumption of generated files.
    • Recommendation: Add or identify targeted runtime/image validation that builds or inspects representative OpenClaw and Hermes sandbox images with messaging channels configured, then verifies generated OpenClaw config, Hermes .env/config, plugin entries, placeholders, and WeChat account files are present before startup.
    • Evidence: Changed runtime surfaces include Dockerfile, agents/hermes/Dockerfile, scripts/generate-openclaw-config.mts, agents/hermes/generate-config.ts, src/lib/messaging/applier/build/messaging-build-applier.mts, and src/lib/actions/sandbox/rebuild.ts. Deterministic test-depth context reports runtime_validation_recommended.
  • Localized doctor/reapply and compatibility workarounds need source-of-truth contracts (src/lib/messaging/applier/build/messaging-build-applier.mts:1083): The build applier intentionally applies post-agent-install outputs, runs OpenClaw doctor, then reapplies outputs, and it also contains compatibility fallback behavior for older build steps without hook phase. These are localized workaround/recovery paths in sandbox image build code; the code has some comments/tests but lacks a complete local contract for the invalid upstream state, why the source cannot be fixed here, and when the workaround can be removed.
    • Recommendation: Add concise source-of-truth comments and/or removal-tracking tests near applyMessagingBuildPhase(), buildStepMatchesPhase(), and credential-placeholder preservation describing the invalid state, source boundary, regression coverage, and removal condition. Prefer making invalid states impossible at source when feasible.
    • Evidence: applyMessagingBuildPhase() applies post-agent-install outputs, runs runOpenClawMessagingDoctor(), then reapplies outputs. buildStepMatchesPhase() falls back by output kind when findHookPhase() is undefined. preserveCredentialPlaceholders() keeps existing placeholders matching the same env key, including vN_ suffixes.

🌱 Nice ideas

  • None.
Consider writing more tests for
  • **Runtime validation** — rebuild legacy registry entry with Telegram Discord Slack WeChat compiles with hook registry and render resolver. Runtime/sandbox/infrastructure paths changed across Dockerfile, Dockerfile.base, agents/hermes/Dockerfile, Hermes config generation, OpenClaw config generation, and the new messaging build applier. Unit and subprocess tests cover important logic but do not prove final image contents or startup consumption.
  • **Runtime validation** — rebuild reports degraded or failed when post-doctor messaging manifest reapply throws. Runtime/sandbox/infrastructure paths changed across Dockerfile, Dockerfile.base, agents/hermes/Dockerfile, Hermes config generation, OpenClaw config generation, and the new messaging build applier. Unit and subprocess tests cover important logic but do not prove final image contents or startup consumption.
  • **Runtime validation** — decoded NEMOCLAW_MESSAGING_PLAN_B64 for Telegram Discord Slack WeChat contains placeholders but no raw tokens or credentialHash fields. Runtime/sandbox/infrastructure paths changed across Dockerfile, Dockerfile.base, agents/hermes/Dockerfile, Hermes config generation, OpenClaw config generation, and the new messaging build applier. Unit and subprocess tests cover important logic but do not prove final image contents or startup consumption.
  • **Runtime validation** — token-paste rejects LF-containing secret before save or hook output. Runtime/sandbox/infrastructure paths changed across Dockerfile, Dockerfile.base, agents/hermes/Dockerfile, Hermes config generation, OpenClaw config generation, and the new messaging build applier. Unit and subprocess tests cover important logic but do not prove final image contents or startup consumption.
  • **Runtime validation** — config-prompt rejects LF-containing channel config before persistence/render inputs. Runtime/sandbox/infrastructure paths changed across Dockerfile, Dockerfile.base, agents/hermes/Dockerfile, Hermes config generation, OpenClaw config generation, and the new messaging build applier. Unit and subprocess tests cover important logic but do not prove final image contents or startup consumption.
  • **Runtime image validation is still needed for build-time messaging hooks** — Add or identify targeted runtime/image validation that builds or inspects representative OpenClaw and Hermes sandbox images with messaging channels configured, then verifies generated OpenClaw config, Hermes .env/config, plugin entries, placeholders, and WeChat account files are present before startup.
  • **Acceptance clause:** OpenClaw `openclaw.json` snapshots match current Telegram, Discord, Slack, WeChat, and WhatsApp behavior. — add test evidence or identify existing coverage. OpenClaw channel manifests now carry agentRender JSON fragments and tests cover post-agent-install render and WeChat build files, but the production legacy rebuild path still omits the hook registry and render resolver, so legacy registry entries can rebuild with unresolved templates or missing hook outputs.
  • **Acceptance clause:** Hermes `.env`/config snapshots match current channel behavior, including WeChat `WEIXIN_*` env mapping and Slack bot/app placeholders. — add test evidence or identify existing coverage. Hermes config generation now delegates messaging env/config to manifest render; manifests emit WEIXIN_* and Slack bot/app placeholder lines, and subprocess tests apply Hermes render. Runtime/image validation is still recommended to prove final built image contents and startup consumption.
Since last review details

Current findings:

  • Source-of-truth review needed: OpenClaw image build post-agent-install apply, doctor, and reapply: The advisor marked localized patch analysis as needs_followup.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: applyMessagingBuildPhase() applies post-agent-install outputs, runs runOpenClawMessagingDoctor(), then reapplies outputs for OpenClaw.
  • Source-of-truth review needed: Rebuild post-doctor messaging manifest reapply: The advisor marked localized patch analysis as missing.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: reapplyMessagingManifestAfterOpenClawDoctor() catches all errors and logs Messaging manifest config reapply skipped.
  • Source-of-truth review needed: Credential-placeholder preservation on messaging reapply: The advisor marked localized patch analysis as needs_followup.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: preserveCredentialPlaceholders() keeps existing placeholders matching the same env key through isProviderPlaceholderForEnvKey() and placeholderSuffixMatchesEnvKey(), including vN_ suffixes.
  • Source-of-truth review needed: Compatibility fallback for older build steps without hook phase: The advisor marked localized patch analysis as needs_followup.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: buildStepMatchesPhase() falls back by output kind when findHookPhase() returns undefined.
  • Source-of-truth review needed: Line-break tolerant credential/config normalization: The advisor marked localized patch analysis as missing.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: normalizeCredentialValue(), config-prompt normalizeConfigValue(), and openshell-provider readCredentialEnv() use CR-stripping/trim patterns rather than rejecting LF.
  • Legacy rebuild plans still omit hooks and the render resolver (src/lib/actions/sandbox/rebuild.ts:202): The real rebuild staging path still constructs MessagingWorkflowPlanner with only createBuiltInChannelManifestRegistry(). For legacy registry entries with messagingChannels but no persisted messaging.plan, rebuild compiles without the built-in hook registry or createBuiltInRenderTemplateResolver(), so manifest render references can remain unresolved and hook-derived build-file outputs such as WeChat account seeding can be absent. This leaves issue Phase 5: migrate messaging agent rendering and build inputs to manifests #4395's rebuild hydration/rendering acceptance only partial.
    • Recommendation: Construct the rebuild planner with createBuiltInMessagingHookRegistry() and createBuiltInRenderTemplateResolver(), matching onboard/add-channel. Add a regression that stages rebuild from a legacy registry entry with Telegram, Discord, Slack, and WeChat config and asserts no unresolved {{...}} render templates plus expected WeChat post-agent-install build-file outputs.
    • Evidence: stageMessagingManifestPlanForRebuild() creates new MessagingWorkflowPlanner(createBuiltInChannelManifestRegistry()). Onboard/add-channel code paths construct the planner with createBuiltInMessagingHookRegistry() and createBuiltInRenderTemplateResolver().
  • Post-doctor messaging reapply failures are still treated as a skip (src/lib/actions/sandbox/rebuild.ts:253): After openclaw doctor --fix, manifest-owned channel config and WeChat seed files may need to be reapplied. The rebuild helper catches every reapply error, logs a dim skipped message, and does not feed that failure into rebuild success/degraded status, so rebuild can appear successful while messaging config is stale or broken.
    • Recommendation: Return reapply status to the rebuild flow and mark rebuild degraded or failed when enabled OpenClaw messaging channels require reapply. Add a regression where post-doctor reapply throws and the final rebuild output/result clearly reports that messaging config was not restored.
    • Evidence: reapplyMessagingManifestAfterOpenClawDoctor() catches err, logs Messaging manifest reapply failed, and prints Messaging manifest config reapply skipped; no status is returned to the later rebuild result.
  • Serialized messaging plans can carry stable credential fingerprints (src/lib/messaging/compiler/engines/credential-binding-engine.ts:26): The compiler adds an unsalted credentialHash when credentials are available, and dockerfile-patch.ts serializes the whole messaging plan into ARG NEMOCLAW_MESSAGING_PLAN_B64. Raw tokens are avoided, but stable cross-sandbox token fingerprints can still be baked into Docker build args or patched Dockerfiles outside the OpenShell credential store.
    • Recommendation: Keep credential hashes out of the Docker build transport, or split host-only conflict metadata from the image build plan. Add decoded-plan tests asserting raw tokens and credentialHash/fingerprint values are absent from NEMOCLAW_MESSAGING_PLAN_B64 while placeholders remain.
    • Evidence: planCredentialBindings() computes hashCredential(process.env[envKey]); dockerfile-patch.ts replaces ARG NEMOCLAW_MESSAGING_PLAN_B64 with MessagingSetupApplier.encodePlan(messagingPlan).
  • Token and config normalization should reject LF before persistence or provider upsert (src/lib/messaging/hooks/common/token-paste.ts:169): New render/build paths reject CR/LF before writing env files or build outputs, but token-paste, config-prompt, and OpenShell provider credential reads still strip carriage returns and trim without rejecting embedded line feeds before saving credentials, returning hook outputs, or upserting providers.
    • Recommendation: Reject any token-paste secret, config-prompt value, and provider credential containing CR or LF before saving, emitting, or passing it to OpenShell provider create/update. Add negative tests proving LF-containing values are not saved, emitted, or upserted.
    • Evidence: token-paste normalizeCredentialValue() uses value.replace(/\r/g, '').trim(); common config-prompt uses the same CR-stripping pattern; messaging/applier/openshell-provider.ts readCredentialEnv() also strips CR and trims.
  • Runtime image validation is still needed for build-time messaging hooks (Dockerfile:673): This PR changes Dockerfile ordering, trusted TypeScript copied into images, OpenClaw plugin installation, Hermes config generation, and WeChat account seed files. Unit and subprocess tests cover important logic, but they do not prove representative built image contents or startup-time consumption of generated files.
    • Recommendation: Add or identify targeted runtime/image validation that builds or inspects representative OpenClaw and Hermes sandbox images with messaging channels configured, then verifies generated OpenClaw config, Hermes .env/config, plugin entries, placeholders, and WeChat account files are present before startup.
    • Evidence: Changed runtime surfaces include Dockerfile, agents/hermes/Dockerfile, scripts/generate-openclaw-config.mts, agents/hermes/generate-config.ts, src/lib/messaging/applier/build/messaging-build-applier.mts, and src/lib/actions/sandbox/rebuild.ts. Deterministic test-depth context reports runtime_validation_recommended.
  • Localized doctor/reapply and compatibility workarounds need source-of-truth contracts (src/lib/messaging/applier/build/messaging-build-applier.mts:1083): The build applier intentionally applies post-agent-install outputs, runs OpenClaw doctor, then reapplies outputs, and it also contains compatibility fallback behavior for older build steps without hook phase. These are localized workaround/recovery paths in sandbox image build code; the code has some comments/tests but lacks a complete local contract for the invalid upstream state, why the source cannot be fixed here, and when the workaround can be removed.
    • Recommendation: Add concise source-of-truth comments and/or removal-tracking tests near applyMessagingBuildPhase(), buildStepMatchesPhase(), and credential-placeholder preservation describing the invalid state, source boundary, regression coverage, and removal condition. Prefer making invalid states impossible at source when feasible.
    • Evidence: applyMessagingBuildPhase() applies post-agent-install outputs, runs runOpenClawMessagingDoctor(), then reapplies outputs. buildStepMatchesPhase() falls back by output kind when findHookPhase() is undefined. preserveCredentialPlaceholders() keeps existing placeholders matching the same env key, including vN_ suffixes.
  • Large security-sensitive hotspots grew during the build-hook refactor: This PR changes Docker image build setup, manifest compilation, credential placeholders, and rebuild behavior while increasing several already-large hotspot files. The growth makes future review harder in code that controls sandbox lifecycle, credential rendering, and image build behavior.
    • Recommendation: Extract the new planner/compiler/rebuild helper logic or offset the growth in the same hotspots before merge. Avoid normalizing additional growth in existing large files that control sandbox lifecycle, credential rendering, and image build behavior.
    • Evidence: Deterministic monolith context reports growth in src/lib/messaging/compiler/manifest-compiler.test.ts (+166), src/lib/messaging/applier/agent-config.ts (+94), src/lib/messaging/compiler/workflow-planner.test.ts (+93), src/lib/messaging/compiler/manifest-compiler.ts (+54), src/lib/actions/sandbox/rebuild.ts (+47), src/lib/messaging/compiler/workflow-planner.ts (+47), and src/lib/messaging/applier/setup-applier.test.ts (+41).

Workflow run details

This is an automated advisory review. A human maintainer must make the final merge decision.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/lib/onboard.ts (1)

3383-3387: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve Telegram mention policy across channels stop/start.

Line 3383 now gates telegramConfig on activeMessagingChannels, which excludes temporarily disabled channels. A rebuild after channels stop telegram will therefore persist current.telegramConfig = null, so a later channels start telegram loses the prior TELEGRAM_REQUIRE_MENTION behavior unless the operator re-exports it. This should key off the configured channel set (enabledChannels / persisted messaging channels), not only the currently attached providers.

Suggested fix
-  if (activeMessagingChannels.includes("telegram")) {
+  const telegramConfigured =
+    enabledChannels?.includes("telegram") ?? activeMessagingChannels.includes("telegram");
+  if (telegramConfigured) {
     const telegramRequireMention = computeTelegramRequireMention();
     if (telegramRequireMention !== null) {
       telegramConfig.requireMention = telegramRequireMention;
     }
   }

Based on learnings, channel state is expected to persist durably across rebuilds, and the PR objective explicitly calls out rebuild-hydration parity for Telegram config.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/onboard.ts` around lines 3383 - 3387, The current guard uses
activeMessagingChannels to decide whether to set telegramConfig.requireMention,
which drops the persisted Telegram mention policy when providers are temporarily
stopped; change the check to use the persisted/configured channel set (e.g.,
enabledChannels or enabledMessagingChannels / persisted messaging channels)
instead of activeMessagingChannels so computeTelegramRequireMention() runs
whenever Telegram is configured, not only when a provider is attached; update
the block around telegramConfig and computeTelegramRequireMention to key off
that persisted/enable set (ensure you reference telegramConfig,
computeTelegramRequireMention, and the enabledChannels/enabledMessagingChannels
variable) so TELEGRAM_REQUIRE_MENTION survives channels stop/start cycles.

Source: Learnings

test/generate-openclaw-config.test.ts (1)

1-4: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Update the stale legacy test-size budget entry to unblock CI.

The pipeline is failing because this file is now 2105 lines while the recorded legacy budget remains 2106. Please lower the corresponding budget entry to match the current line count so codebase-growth-guardrails passes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/generate-openclaw-config.test.ts` around lines 1 - 4, The recorded
legacy "test-size" budget entry is off by one (recorded 2106 vs actual 2105
lines) causing CI failures; update the legacy test-size budget value to 2105 to
match test/generate-openclaw-config.test.ts current line count so
codebase-growth-guardrails passes—locate the budget entry named "legacy
test-size" (or the test-size entry used by the codebase-growth-guardrails
config) and lower its numeric value from 2106 to 2105.

Source: Pipeline failures

src/lib/messaging/compiler/manifest-compiler.ts (1)

333-343: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

validValues is bypassed for config env values.

At Line 337, config-resolved values return before the validValues gate at Line 342. That lets out-of-range config values pass manifest constraints.

Suggested fix
 function readInputEnvValue(input: ChannelInputSpec): MessagingSerializableValue | undefined {
+  const normalize = (raw: string | undefined): string | undefined => {
+    const normalized = raw?.replace(/\r/g, "").trim();
+    if (!normalized || normalized.length === 0) return undefined;
+    if (input.validValues && !input.validValues.includes(normalized)) return undefined;
+    return normalized;
+  };
+
   if (!input.envKey) return undefined;
   if (input.kind === "config") {
     const resolved = resolveMessagingChannelConfigEnvValue(input.envKey, process.env);
-    if (resolved.value) return resolved.value;
+    const normalizedResolved = normalize(resolved.value);
+    if (normalizedResolved !== undefined) return normalizedResolved;
   }
-  const value = process.env[input.envKey];
-  const normalized = value?.replace(/\r/g, "").trim();
-  if (!normalized || normalized.length === 0) return undefined;
-  if (input.validValues && !input.validValues.includes(normalized)) return undefined;
-  return normalized;
+  return normalize(process.env[input.envKey]);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/messaging/compiler/manifest-compiler.ts` around lines 333 - 343, In
readInputEnvValue, config-resolved values returned early bypass the validValues
check; after calling resolveMessagingChannelConfigEnvValue(input.envKey,
process.env) assign its value to a local, normalize it the same way as env
lookup (strip \r and trim), reject if empty, and then apply
input.validValues.includes(normalized) before returning—i.e., replace the early
return of resolved.value with the same normalization and validValues gating used
for process.env[input.envKey] so both code paths enforce constraints (refer to
readInputEnvValue, resolveMessagingChannelConfigEnvValue, and
input.validValues).
🧹 Nitpick comments (3)
src/lib/actions/sandbox/rebuild.ts (1)

273-273: Run the rebuild-specific E2E suite for this behavior shift.

Please run the channels-stop-start-e2e workflow for this rebuild-path change to validate disabled-channel persistence and post-rebuild messaging reapply behavior.

As per coding guidelines, "src/lib/actions/sandbox/rebuild.ts ... E2E test recommendation: channels-stop-start-e2e."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/actions/sandbox/rebuild.ts` at line 273, The rebuildSandbox change
needs its specific end-to-end validation: run the channels-stop-start-e2e
workflow to exercise rebuild-specific scenarios for disabled-channel persistence
and post-rebuild message reapply behavior; trigger that CI job and attach the
resulting logs to this PR, ensuring the rebuildSandbox function's behavior
around channel disable/persist and message reapply is confirmed by the E2E
results.

Source: Coding guidelines

Dockerfile (1)

413-550: Run the Dockerfile E2E subset before merge.

These changes move critical build behavior into manifest hook execution at image-build time, so unit tests alone won’t fully validate runtime delivery. Please run the recommended selective nightly E2E jobs for this path.

As per coding guidelines, Dockerfile changes are only fully testable with a real container build and should use the recommended selective E2E workflows.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Dockerfile` around lines 413 - 550, The Dockerfile change runs
generate-openclaw-config.mts and run-openclaw-build-hooks.mts at build time
which requires a real container build to validate; before merging, perform the
Dockerfile E2E subset by building the image and running the repository's
selective nightly E2E jobs that exercise build-hook and config-generation paths
(specifically exercise run-openclaw-build-hooks.mts and
generate-openclaw-config.mts execution), verify the produced openclaw.json and
gateway token behavior in both root and non-root modes, and surface any failures
back to the PR so we can fix build-hook or config generation issues before
merge.

Source: Coding guidelines

src/lib/messaging/compiler/engines/template.ts (1)

161-197: 🏗️ Heavy lift

Break up resolveTemplateReference to reduce branching complexity

This resolver now centralizes many channel-specific branches, which makes it brittle for future additions. Split into a keyed resolver map (or per-channel resolver modules) and keep this function as a thin dispatcher.

As per coding guidelines, **/*.{js,ts,tsx,jsx}: "Keep function complexity low in JavaScript and TypeScript code."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/messaging/compiler/engines/template.ts` around lines 161 - 197, The
resolveTemplateReference function has grown many channel-specific branches;
refactor it into a thin dispatcher that routes to per-channel resolver functions
or a keyed resolver map (e.g., a map keyed by the top-level token like
"discord", "telegramConfig", "wechatConfig", "slackConfig", "allowedIds",
"proxyUrl") and move the existing logic into those handlers (extract logic
currently in resolveTemplateReference for discord: discordGuilds,
discordAllowedUsers, discordRequireMention, for allowedIds:
resolveAllowedIdsTemplate usage, for telegramConfig: parseBoolean/stateValue,
for wechatConfig: stateValue, for slackConfig: slackAllowedChannels, and
proxyUrl) so resolveTemplateReference only picks the handler and returns
handler(reference, context) or the default template string; ensure semantics and
return types of RenderTemplateValue remain unchanged.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@agents/hermes/config/manifest-hooks.ts`:
- Around line 83-90: The code currently treats any non-"json-fragment" render as
env-lines; update the logic in manifest-hooks.ts where render.kind is checked
(around the applyJsonRender/applyEnvRender calls) to explicitly handle allowed
kinds (e.g., "json-fragment" and "env-lines") and fail-closed for anything else:
if render.kind === "json-fragment" call applyJsonRender and push
appliedHooks/appliedTargets, else if render.kind === "env-lines" call
applyEnvRender and push appliedTargets, otherwise throw a descriptive Error (or
call the project’s error/assert utility) including the invalid render.kind and
render.target so schema drift/typos surface immediately.

In `@src/lib/messaging/compiler/engines/agent-render-engine.ts`:
- Around line 31-42: The default parameter creates an empty
MessagingHookRegistry which lacks required hooks (notably common.staticOutputs)
causing run-time failures when runMessagingHook is invoked; fix by ensuring the
passed-or-default registry contains the shared hooks before use — e.g., if hooks
is empty, register common.staticOutputs (and any other shared hooks) into the
MessagingHookRegistry instance used here (look for the hooks parameter,
MessagingHookRegistry, common.staticOutputs, renderHookForManifestEntry and
runMessagingHook) so render planning succeeds when callers omit hooks.

In `@test/e2e/docs/parity-inventory.generated.json`:
- Around line 8805-8807: The JSON entry's normalized_id is out of sync with its
text: update the "normalized_id" value for the object whose "text" is "M-W9:
Real WeChat token spliced into accounts/${WECHAT_ACCOUNT}.json — manifest seed
placeholder regression" so it reflects the manifest-seed regression semantics
(remove or replace the "seed.wechat.accounts.py" fragment and normalize to match
the text), ensuring the normalized_id string corresponds to the same source
semantics as the "text" field.

In `@test/onboard.test.ts`:
- Line 2718: Update the legacyMaxLines entry for the test file in the
test-file-size budget JSON: locate the JSON object key "test/onboard.test.ts" in
the test-file-size budget configuration and change its value from 4887 to 4879
so the legacyMaxLines matches the current file length (4879).

---

Outside diff comments:
In `@src/lib/messaging/compiler/manifest-compiler.ts`:
- Around line 333-343: In readInputEnvValue, config-resolved values returned
early bypass the validValues check; after calling
resolveMessagingChannelConfigEnvValue(input.envKey, process.env) assign its
value to a local, normalize it the same way as env lookup (strip \r and trim),
reject if empty, and then apply input.validValues.includes(normalized) before
returning—i.e., replace the early return of resolved.value with the same
normalization and validValues gating used for process.env[input.envKey] so both
code paths enforce constraints (refer to readInputEnvValue,
resolveMessagingChannelConfigEnvValue, and input.validValues).

In `@src/lib/onboard.ts`:
- Around line 3383-3387: The current guard uses activeMessagingChannels to
decide whether to set telegramConfig.requireMention, which drops the persisted
Telegram mention policy when providers are temporarily stopped; change the check
to use the persisted/configured channel set (e.g., enabledChannels or
enabledMessagingChannels / persisted messaging channels) instead of
activeMessagingChannels so computeTelegramRequireMention() runs whenever
Telegram is configured, not only when a provider is attached; update the block
around telegramConfig and computeTelegramRequireMention to key off that
persisted/enable set (ensure you reference telegramConfig,
computeTelegramRequireMention, and the enabledChannels/enabledMessagingChannels
variable) so TELEGRAM_REQUIRE_MENTION survives channels stop/start cycles.

In `@test/generate-openclaw-config.test.ts`:
- Around line 1-4: The recorded legacy "test-size" budget entry is off by one
(recorded 2106 vs actual 2105 lines) causing CI failures; update the legacy
test-size budget value to 2105 to match test/generate-openclaw-config.test.ts
current line count so codebase-growth-guardrails passes—locate the budget entry
named "legacy test-size" (or the test-size entry used by the
codebase-growth-guardrails config) and lower its numeric value from 2106 to
2105.

---

Nitpick comments:
In `@Dockerfile`:
- Around line 413-550: The Dockerfile change runs generate-openclaw-config.mts
and run-openclaw-build-hooks.mts at build time which requires a real container
build to validate; before merging, perform the Dockerfile E2E subset by building
the image and running the repository's selective nightly E2E jobs that exercise
build-hook and config-generation paths (specifically exercise
run-openclaw-build-hooks.mts and generate-openclaw-config.mts execution), verify
the produced openclaw.json and gateway token behavior in both root and non-root
modes, and surface any failures back to the PR so we can fix build-hook or
config generation issues before merge.

In `@src/lib/actions/sandbox/rebuild.ts`:
- Line 273: The rebuildSandbox change needs its specific end-to-end validation:
run the channels-stop-start-e2e workflow to exercise rebuild-specific scenarios
for disabled-channel persistence and post-rebuild message reapply behavior;
trigger that CI job and attach the resulting logs to this PR, ensuring the
rebuildSandbox function's behavior around channel disable/persist and message
reapply is confirmed by the E2E results.

In `@src/lib/messaging/compiler/engines/template.ts`:
- Around line 161-197: The resolveTemplateReference function has grown many
channel-specific branches; refactor it into a thin dispatcher that routes to
per-channel resolver functions or a keyed resolver map (e.g., a map keyed by the
top-level token like "discord", "telegramConfig", "wechatConfig", "slackConfig",
"allowedIds", "proxyUrl") and move the existing logic into those handlers
(extract logic currently in resolveTemplateReference for discord: discordGuilds,
discordAllowedUsers, discordRequireMention, for allowedIds:
resolveAllowedIdsTemplate usage, for telegramConfig: parseBoolean/stateValue,
for wechatConfig: stateValue, for slackConfig: slackAllowedChannels, and
proxyUrl) so resolveTemplateReference only picks the handler and returns
handler(reference, context) or the default template string; ensure semantics and
return types of RenderTemplateValue remain unchanged.
🪄 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: Enterprise

Run ID: 4beb4b5f-e93c-4052-9c9a-7af56ccfdd8d

📥 Commits

Reviewing files that changed from the base of the PR and between ec408c8 and 59c6309.

📒 Files selected for processing (56)
  • Dockerfile
  • agents/hermes/Dockerfile
  • agents/hermes/config/build-env.ts
  • agents/hermes/config/hermes-config.ts
  • agents/hermes/config/hermes-env.ts
  • agents/hermes/config/manifest-hooks.ts
  • agents/hermes/config/messaging-config.ts
  • agents/hermes/generate-config.ts
  • agents/hermes/policy-additions.yaml
  • scripts/generate-openclaw-config.mts
  • scripts/lib/sandbox-init.sh
  • scripts/openclaw-build-messaging-plugins.py
  • scripts/run-openclaw-build-hooks.mts
  • scripts/seed-wechat-accounts.py
  • src/ext/wechat/qr.ts
  • src/lib/actions/sandbox/policy-channel.ts
  • src/lib/actions/sandbox/rebuild.ts
  • src/lib/adapters/openshell/client.ts
  • src/lib/adapters/openshell/runtime.ts
  • src/lib/messaging/applier/agent-config.ts
  • src/lib/messaging/applier/setup-applier.test.ts
  • src/lib/messaging/channels/discord/manifest.ts
  • src/lib/messaging/channels/manifests.test.ts
  • src/lib/messaging/channels/slack/manifest.ts
  • src/lib/messaging/channels/telegram/manifest.ts
  • src/lib/messaging/channels/wechat/manifest.ts
  • src/lib/messaging/channels/whatsapp/manifest.ts
  • src/lib/messaging/compiler/engines/agent-render-engine.ts
  • src/lib/messaging/compiler/engines/build-step-engine.ts
  • src/lib/messaging/compiler/engines/template.ts
  • src/lib/messaging/compiler/manifest-compiler.test.ts
  • src/lib/messaging/compiler/manifest-compiler.ts
  • src/lib/messaging/compiler/workflow-planner.test.ts
  • src/lib/messaging/hooks/common/index.ts
  • src/lib/messaging/hooks/common/static-outputs.ts
  • src/lib/messaging/hooks/common/token-paste.test.ts
  • src/lib/messaging/hooks/hook-runner.test.ts
  • src/lib/messaging/manifest/types.ts
  • src/lib/onboard.ts
  • src/lib/onboard/dockerfile-patch.test.ts
  • src/lib/onboard/dockerfile-patch.ts
  • src/lib/onboard/messaging-config.test.ts
  • src/lib/onboard/messaging-config.ts
  • src/lib/onboard/wechat-config.ts
  • src/lib/sandbox/build-context.ts
  • test/e2e/docs/parity-inventory.generated.json
  • test/e2e/test-messaging-providers.sh
  • test/generate-hermes-config.test.ts
  • test/generate-openclaw-config.test.ts
  • test/messaging-plan-test-helper.ts
  • test/onboard-messaging.test.ts
  • test/onboard.test.ts
  • test/run-openclaw-build-hooks.test.ts
  • test/sandbox-build-context.test.ts
  • test/sandbox-provisioning.test.ts
  • test/seed-wechat-accounts.test.ts
💤 Files with no reviewable changes (6)
  • src/lib/onboard/messaging-config.test.ts
  • scripts/openclaw-build-messaging-plugins.py
  • test/seed-wechat-accounts.test.ts
  • scripts/seed-wechat-accounts.py
  • agents/hermes/config/messaging-config.ts
  • agents/hermes/config/build-env.ts

Comment thread agents/hermes/config/manifest-hooks.ts Outdated
Comment thread src/lib/messaging/compiler/engines/agent-render-engine.ts Outdated
Comment thread test/e2e/docs/parity-inventory.generated.json Outdated
Comment thread test/onboard.test.ts
@sandl99 sandl99 marked this pull request as draft June 8, 2026 13:43
@copy-pr-bot

copy-pr-bot Bot commented Jun 8, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

Comment thread test/openclaw-config-render.test.ts Fixed
Comment thread src/lib/messaging/applier/build/messaging-build-applier.mts Fixed
Comment thread test/security-c2-dockerfile-injection.test.ts Fixed
Comment thread test/openclaw-config-render.test.ts Fixed
Comment thread src/lib/messaging/compiler/engines/agent-render-engine.ts Fixed
@NVIDIA NVIDIA deleted a comment from github-actions Bot Jun 8, 2026
@wscurran wscurran added area: messaging Messaging channels, bridges, manifests, or channel lifecycle refactor PR restructures code without intended behavior change labels Jun 8, 2026
@wscurran

wscurran commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

…ort, function or class'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
Dockerfile (1)

559-597: Run the Dockerfile E2E subset before merge.

This path changes build-time messaging hook orchestration and post-install file generation, so it should be validated with the recommended nightly E2E job subset for Dockerfile-impacting changes.

As per coding guidelines: Dockerfile ... E2E test recommendation: cloud-e2e, sandbox-survival-e2e, hermes-e2e, rebuild-openclaw-e2e, openclaw-tui-chat-correlation-e2e.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Dockerfile` around lines 559 - 597, This change updates build-time messaging
hook orchestration (the RUN node --experimental-strip-types
/src/lib/messaging/applier/build/messaging-build-applier.mts calls for --phase
agent-install and --phase post-agent-install and the openclaw plugins
install/enable/inspect steps), so before merging run the Dockerfile-impact E2E
subset: cloud-e2e, sandbox-survival-e2e, hermes-e2e, rebuild-openclaw-e2e, and
openclaw-tui-chat-correlation-e2e; verify the messaging post-agent-install
outputs are generated into the sandbox as expected, that openclaw plugins
install/enable/inspect succeeds and registers the /nemoclaw runtime command, and
that no network resolution occurred during the plugin install (confirm
NPM_CONFIG_OFFLINE behavior and pruned plugin-runtime-deps artifacts).

Source: Coding guidelines

agents/hermes/Dockerfile (1)

135-147: Run the Hermes E2E subset before merge.

These changes affect Hermes onboarding/build hooks and post-install render/build-file application, so they should be validated with the Hermes-focused nightly jobs.

As per coding guidelines: agents/hermes/** ... E2E test recommendation: hermes-e2e, hermes-inference-switch-e2e, hermes-discord-e2e, hermes-slack-e2e, hermes-onboard-security-posture-e2e, rebuild-hermes-e2e, rebuild-hermes-stale-base-e2e.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agents/hermes/Dockerfile` around lines 135 - 147, These Dockerfile changes
touch Hermes onboarding and post-install hooks (see the RUN commands invoking
/src/lib/messaging/applier/build/messaging-build-applier.mts with --agent hermes
--phase agent-install and --phase post-agent-install and the nemoclaw plugin
copy into /sandbox/.hermes/plugins/nemoclaw/), so ensure the Hermes-focused E2E
subset is executed before merging by updating CI to include the recommended jobs
(hermes-e2e, hermes-inference-switch-e2e, hermes-discord-e2e, hermes-slack-e2e,
hermes-onboard-security-posture-e2e, rebuild-hermes-e2e,
rebuild-hermes-stale-base-e2e) in the PR/check pipeline or by scheduling a
blocking nightly run that validates these changes; modify the workflow matrix or
job list accordingly so these tests run against this Dockerfile change.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/messaging/applier/build/messaging-build-applier.mts`:
- Around line 385-396: The current resolveAgentRenderTarget allows path
traversal via inputs like "~/.openclaw/../..." because it only checks prefixes;
fix by normalizing/ resolving the sliced subpath and validating it stays inside
the intended agent root before returning. In resolveAgentRenderTarget (variables
target, agent, home and throws MessagingBuildApplierError), compute the
agentRoot (join(home, ".openclaw") or join(home, ".hermes")), resolve the
candidate path against agentRoot and ensure the resolved path starts with
agentRoot (or that no path segment is ".."/contains upward traversal) and throw
MessagingBuildApplierError if validation fails; only return the resolved safe
path when the check passes.

---

Nitpick comments:
In `@agents/hermes/Dockerfile`:
- Around line 135-147: These Dockerfile changes touch Hermes onboarding and
post-install hooks (see the RUN commands invoking
/src/lib/messaging/applier/build/messaging-build-applier.mts with --agent hermes
--phase agent-install and --phase post-agent-install and the nemoclaw plugin
copy into /sandbox/.hermes/plugins/nemoclaw/), so ensure the Hermes-focused E2E
subset is executed before merging by updating CI to include the recommended jobs
(hermes-e2e, hermes-inference-switch-e2e, hermes-discord-e2e, hermes-slack-e2e,
hermes-onboard-security-posture-e2e, rebuild-hermes-e2e,
rebuild-hermes-stale-base-e2e) in the PR/check pipeline or by scheduling a
blocking nightly run that validates these changes; modify the workflow matrix or
job list accordingly so these tests run against this Dockerfile change.

In `@Dockerfile`:
- Around line 559-597: This change updates build-time messaging hook
orchestration (the RUN node --experimental-strip-types
/src/lib/messaging/applier/build/messaging-build-applier.mts calls for --phase
agent-install and --phase post-agent-install and the openclaw plugins
install/enable/inspect steps), so before merging run the Dockerfile-impact E2E
subset: cloud-e2e, sandbox-survival-e2e, hermes-e2e, rebuild-openclaw-e2e, and
openclaw-tui-chat-correlation-e2e; verify the messaging post-agent-install
outputs are generated into the sandbox as expected, that openclaw plugins
install/enable/inspect succeeds and registers the /nemoclaw runtime command, and
that no network resolution occurred during the plugin install (confirm
NPM_CONFIG_OFFLINE behavior and pruned plugin-runtime-deps artifacts).
🪄 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: Enterprise

Run ID: 4959dcd2-ec8c-461d-8cd7-1045da67a1c3

📥 Commits

Reviewing files that changed from the base of the PR and between 59c6309 and 19ab1d1.

📒 Files selected for processing (20)
  • Dockerfile
  • agents/hermes/Dockerfile
  • agents/hermes/generate-config.ts
  • ci/test-file-size-budget.json
  • scripts/generate-openclaw-config.mts
  • src/lib/messaging/applier/build/messaging-build-applier.mts
  • src/lib/messaging/compiler/engines/agent-render-engine.ts
  • src/lib/messaging/compiler/manifest-compiler.ts
  • src/lib/onboard.ts
  • src/lib/sandbox/build-context.ts
  • test/e2e/docs/parity-inventory.generated.json
  • test/fetch-guard-patch-regression.test.ts
  • test/generate-hermes-config.test.ts
  • test/generate-openclaw-config.test.ts
  • test/helpers/messaging-plan-fixtures.ts
  • test/messaging-build-applier.test.ts
  • test/onboard-messaging.test.ts
  • test/sandbox-build-context.test.ts
  • test/sandbox-provisioning.test.ts
  • test/security-c2-dockerfile-injection.test.ts
✅ Files skipped from review due to trivial changes (1)
  • test/e2e/docs/parity-inventory.generated.json
🚧 Files skipped from review as they are similar to previous changes (5)
  • agents/hermes/generate-config.ts
  • test/generate-hermes-config.test.ts
  • src/lib/messaging/compiler/manifest-compiler.ts
  • test/onboard-messaging.test.ts
  • scripts/generate-openclaw-config.mts

Comment thread src/lib/messaging/applier/build/messaging-build-applier.mts
@sandl99 sandl99 marked this pull request as ready for review June 10, 2026 05:24

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/lib/messaging/applier/agent-config.ts (1)

232-310: 💤 Low value

Consider extracting shared placeholder logic to reduce duplication.

The credential placeholder preservation logic here (lines 232-310) is nearly identical to the implementation in messaging-build-applier.mts (lines 634-712). While duplication may be intentional due to different execution contexts (standalone .mts module vs. library code), consider extracting this to a shared utility if both contexts can import from a common source.

Minor difference: isProviderPlaceholderForEnvKey uses indexOf here vs. regex in the .mts file. Both work correctly for valid placeholders.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/messaging/applier/agent-config.ts` around lines 232 - 310, This code
duplicates placeholder-preservation logic found in messaging-build-applier.mts;
extract the shared logic into a new utility module (e.g.,
messaging-placeholder-utils) and import it from both places: move
credentialPlaceholderRules, preserveCredentialPlaceholders,
isProviderPlaceholderForEnvKey, placeholderSuffixMatchesEnvKey (and getJsonPath
if used by both) into the new module and export them; update both
src/lib/messaging/applier/agent-config.ts and messaging-build-applier.mts to
import and use those exported functions, and unify the slight behavioral
difference by adopting the regex-based check for alias matching (make
isProviderPlaceholderForEnvKey use the same regex approach as the .mts version)
so both callers behave identically.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/lib/messaging/applier/agent-config.ts`:
- Around line 232-310: This code duplicates placeholder-preservation logic found
in messaging-build-applier.mts; extract the shared logic into a new utility
module (e.g., messaging-placeholder-utils) and import it from both places: move
credentialPlaceholderRules, preserveCredentialPlaceholders,
isProviderPlaceholderForEnvKey, placeholderSuffixMatchesEnvKey (and getJsonPath
if used by both) into the new module and export them; update both
src/lib/messaging/applier/agent-config.ts and messaging-build-applier.mts to
import and use those exported functions, and unify the slight behavioral
difference by adopting the regex-based check for alias matching (make
isProviderPlaceholderForEnvKey use the same regex approach as the .mts version)
so both callers behave identically.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: c637cb18-ba0c-45d0-993c-cceff0740ee3

📥 Commits

Reviewing files that changed from the base of the PR and between 1f2f263 and acd6bec.

📒 Files selected for processing (4)
  • src/lib/messaging/applier/agent-config.ts
  • src/lib/messaging/applier/build/messaging-build-applier.mts
  • src/lib/messaging/applier/setup-applier.test.ts
  • test/messaging-build-applier.test.ts

@NVIDIA NVIDIA deleted a comment from github-actions Bot Jun 10, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 27261238223
Target ref: feat/issue-4395-manifest-hooks
Requested jobs: cloud-e2e,messaging-providers-e2e,channels-add-remove-e2e,channels-stop-start-e2e,hermes-e2e,hermes-discord-e2e,hermes-slack-e2e,rebuild-openclaw-e2e,rebuild-hermes-e2e,network-policy-e2e,credential-sanitization-e2e,hermes-secret-boundary-e2e,inference-routing-e2e
Summary: 13 passed, 0 failed, 0 skipped

Job Result
channels-add-remove-e2e ✅ success
channels-stop-start-e2e ✅ success
cloud-e2e ✅ success
credential-sanitization-e2e ✅ success
hermes-discord-e2e ✅ success
hermes-e2e ✅ success
hermes-secret-boundary-e2e ✅ success
hermes-slack-e2e ✅ success
inference-routing-e2e ✅ success
messaging-providers-e2e ✅ success
network-policy-e2e ✅ success
rebuild-hermes-e2e ✅ success
rebuild-openclaw-e2e ✅ success

@github-actions

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/messaging/channels/wechat/hooks/ilink-login.ts`:
- Around line 160-165: The function normalizeCredentialValue currently trims the
input before checking for line breaks so leading/trailing CR/LF are allowed;
change it to test the raw input string for /[\r\n]/ and throw if found, then
perform value.trim() and return the trimmed result; update the implementation in
normalizeCredentialValue to check the original parameter (not the trimmed
variable) for line breaks before trimming.
🪄 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: Enterprise

Run ID: c0b63581-bfb2-45f4-bdba-676cf7119a63

📥 Commits

Reviewing files that changed from the base of the PR and between e5ef86c and 7484aeb.

📒 Files selected for processing (28)
  • Dockerfile.base
  • ci/test-file-size-budget.json
  • docs/manage-sandboxes/messaging-channels.mdx
  • scripts/generate-openclaw-config.mts
  • src/ext/wechat/qr.ts
  • src/lib/messaging-channel-config.ts
  • src/lib/messaging/applier/build/messaging-build-applier.mts
  • src/lib/messaging/applier/setup-applier.test.ts
  • src/lib/messaging/channels/manifests.test.ts
  • src/lib/messaging/channels/template-resolver-utils.ts
  • src/lib/messaging/channels/wechat/hooks/ilink-login.ts
  • src/lib/messaging/channels/wechat/hooks/implementations.test.ts
  • src/lib/messaging/channels/wechat/hooks/seed-openclaw-account.ts
  • src/lib/messaging/channels/wechat/ilink-base-url.ts
  • src/lib/messaging/channels/wechat/manifest.ts
  • src/lib/messaging/channels/wechat/template-resolver.ts
  • src/lib/messaging/compiler/engines/agent-render-engine.ts
  • src/lib/messaging/compiler/manifest-compiler.test.ts
  • src/lib/messaging/compiler/manifest-compiler.ts
  • src/lib/messaging/compiler/workflow-planner.test.ts
  • src/lib/onboard.ts
  • src/lib/onboard/messaging-channel-setup.test.ts
  • src/lib/state/sandbox.ts
  • test/e2e/test-channels-stop-start.sh
  • test/e2e/test-messaging-providers.sh
  • test/generate-openclaw-config.test.ts
  • test/messaging-build-applier.test.ts
  • test/onboard.test.ts
💤 Files with no reviewable changes (7)
  • test/e2e/test-channels-stop-start.sh
  • Dockerfile.base
  • test/e2e/test-messaging-providers.sh
  • test/onboard.test.ts
  • test/messaging-build-applier.test.ts
  • scripts/generate-openclaw-config.mts
  • test/generate-openclaw-config.test.ts
✅ Files skipped from review due to trivial changes (3)
  • src/lib/onboard/messaging-channel-setup.test.ts
  • src/ext/wechat/qr.ts
  • src/lib/state/sandbox.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • ci/test-file-size-budget.json
  • src/lib/messaging/compiler/workflow-planner.test.ts
  • src/lib/messaging/applier/setup-applier.test.ts
  • src/lib/messaging/channels/manifests.test.ts

Comment thread src/lib/messaging/channels/wechat/hooks/ilink-login.ts
@NVIDIA NVIDIA deleted a comment from github-actions Bot Jun 10, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ❌ Some jobs failed

Run: 27268567856
Target ref: feat/issue-4395-manifest-hooks
Requested jobs: all (no filter)
Summary: 60 passed, 4 failed, 3 skipped

Job Result
agent-turn-latency-e2e ✅ success
bedrock-runtime-compatible-anthropic-e2e ✅ success
brave-search-e2e ✅ success
channels-add-remove-e2e ✅ success
channels-stop-start-e2e ❌ failure
cloud-e2e ✅ success
cloud-inference-e2e ✅ success
cloud-onboard-e2e ✅ success
common-egress-agent-e2e ✅ success
concurrent-gateway-ports-e2e ✅ success
credential-migration-e2e ✅ success
credential-sanitization-e2e ✅ success
device-auth-health-e2e ✅ success
diagnostics-e2e ✅ success
docs-validation-e2e ✅ success
double-onboard-e2e ✅ success
gpu-double-onboard-e2e ⏭️ skipped
gpu-e2e ⏭️ skipped
gpu-jetson-nvmap-e2e ⏭️ skipped
hermes-anthropic-inference-switch-e2e ✅ success
hermes-dashboard-e2e ✅ success
hermes-discord-e2e ✅ success
hermes-e2e ✅ success
hermes-inference-switch-e2e ✅ success
hermes-onboard-security-posture-e2e ✅ success
hermes-root-entrypoint-smoke-e2e ✅ success
hermes-secret-boundary-e2e ❌ failure
hermes-slack-e2e ✅ success
inference-routing-e2e ✅ success
issue-2478-crash-loop-recovery-e2e ✅ success
issue-3600-gpu-proof-optional-e2e ✅ success
issue-4434-tui-unreachable-inference-e2e ✅ success
issue-4462-gateway-pinned-approval-characterization-e2e ✅ success
issue-4462-scope-upgrade-approval-e2e ✅ success
kimi-inference-compat-e2e ✅ success
launchable-smoke-e2e ✅ success
messaging-compatible-endpoint-e2e ✅ success
messaging-providers-e2e ✅ success
network-policy-e2e ✅ success
onboard-negative-paths-e2e ✅ success
onboard-repair-e2e ✅ success
onboard-resume-e2e ✅ success
openclaw-anthropic-inference-switch-e2e ✅ success
openclaw-discord-pairing-e2e ✅ success
openclaw-inference-switch-e2e ✅ success
openclaw-onboard-security-posture-e2e ✅ success
openclaw-skill-cli-e2e ✅ success
openclaw-slack-pairing-e2e ✅ success
openclaw-tui-chat-correlation-e2e ❌ failure
openshell-gateway-upgrade-e2e ✅ success
overlayfs-autofix-e2e ✅ success
rebuild-hermes-e2e ✅ success
rebuild-hermes-stale-base-e2e ✅ success
rebuild-openclaw-e2e ✅ success
runtime-overrides-e2e ✅ success
sandbox-operations-e2e ✅ success
sandbox-survival-e2e ✅ success
sessions-agents-cli-e2e ✅ success
shields-config-e2e ✅ success
skill-agent-e2e ✅ success
snapshot-commands-e2e ✅ success
state-backup-restore-e2e ❌ failure
telegram-injection-e2e ✅ success
token-rotation-e2e ✅ success
tunnel-lifecycle-e2e ✅ success
upgrade-stale-sandbox-e2e ✅ success
vm-driver-privileged-exec-routing-e2e ✅ success

Failed jobs: channels-stop-start-e2e, hermes-secret-boundary-e2e, openclaw-tui-chat-correlation-e2e, state-backup-restore-e2e. Check run artifacts for logs.

@sandl99 sandl99 added the v0.0.63 Release target label Jun 10, 2026
@sandl99 sandl99 requested a review from cv June 10, 2026 10:32
@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ❌ Some jobs failed

Run: 27268567856
Target ref: feat/issue-4395-manifest-hooks
Requested jobs: all (no filter)
Summary: 63 passed, 1 failed, 3 skipped

Job Result
agent-turn-latency-e2e ✅ success
bedrock-runtime-compatible-anthropic-e2e ✅ success
brave-search-e2e ✅ success
channels-add-remove-e2e ✅ success
channels-stop-start-e2e ❌ failure
cloud-e2e ✅ success
cloud-inference-e2e ✅ success
cloud-onboard-e2e ✅ success
common-egress-agent-e2e ✅ success
concurrent-gateway-ports-e2e ✅ success
credential-migration-e2e ✅ success
credential-sanitization-e2e ✅ success
device-auth-health-e2e ✅ success
diagnostics-e2e ✅ success
docs-validation-e2e ✅ success
double-onboard-e2e ✅ success
gpu-double-onboard-e2e ⏭️ skipped
gpu-e2e ⏭️ skipped
gpu-jetson-nvmap-e2e ⏭️ skipped
hermes-anthropic-inference-switch-e2e ✅ success
hermes-dashboard-e2e ✅ success
hermes-discord-e2e ✅ success
hermes-e2e ✅ success
hermes-inference-switch-e2e ✅ success
hermes-onboard-security-posture-e2e ✅ success
hermes-root-entrypoint-smoke-e2e ✅ success
hermes-secret-boundary-e2e ✅ success
hermes-slack-e2e ✅ success
inference-routing-e2e ✅ success
issue-2478-crash-loop-recovery-e2e ✅ success
issue-3600-gpu-proof-optional-e2e ✅ success
issue-4434-tui-unreachable-inference-e2e ✅ success
issue-4462-gateway-pinned-approval-characterization-e2e ✅ success
issue-4462-scope-upgrade-approval-e2e ✅ success
kimi-inference-compat-e2e ✅ success
launchable-smoke-e2e ✅ success
messaging-compatible-endpoint-e2e ✅ success
messaging-providers-e2e ✅ success
network-policy-e2e ✅ success
onboard-negative-paths-e2e ✅ success
onboard-repair-e2e ✅ success
onboard-resume-e2e ✅ success
openclaw-anthropic-inference-switch-e2e ✅ success
openclaw-discord-pairing-e2e ✅ success
openclaw-inference-switch-e2e ✅ success
openclaw-onboard-security-posture-e2e ✅ success
openclaw-skill-cli-e2e ✅ success
openclaw-slack-pairing-e2e ✅ success
openclaw-tui-chat-correlation-e2e ✅ success
openshell-gateway-upgrade-e2e ✅ success
overlayfs-autofix-e2e ✅ success
rebuild-hermes-e2e ✅ success
rebuild-hermes-stale-base-e2e ✅ success
rebuild-openclaw-e2e ✅ success
runtime-overrides-e2e ✅ success
sandbox-operations-e2e ✅ success
sandbox-survival-e2e ✅ success
sessions-agents-cli-e2e ✅ success
shields-config-e2e ✅ success
skill-agent-e2e ✅ success
snapshot-commands-e2e ✅ success
state-backup-restore-e2e ✅ success
telegram-injection-e2e ✅ success
token-rotation-e2e ✅ success
tunnel-lifecycle-e2e ✅ success
upgrade-stale-sandbox-e2e ✅ success
vm-driver-privileged-exec-routing-e2e ✅ success

Failed jobs: channels-stop-start-e2e. Check run artifacts for logs.

@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 27270967967
Target ref: feat/issue-4395-manifest-hooks
Requested jobs: channels-stop-start-e2e
Summary: 1 passed, 0 failed, 0 skipped

Job Result
channels-stop-start-e2e ✅ success

@jyaunches jyaunches added v0.0.64 Release target and removed v0.0.63 Release target labels Jun 11, 2026
@cv cv merged commit e9d0416 into main Jun 11, 2026
41 checks passed
@cv cv deleted the feat/issue-4395-manifest-hooks branch June 11, 2026 02:29
@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ❌ Some jobs failed

Run: 27326674298
Target ref: 3108a19b1a8596bd4f8bdccd2a4a0fb830d6dbed
Workflow ref: main
Requested jobs: issue-4462-scope-upgrade-approval-e2e
Summary: 0 passed, 1 failed, 0 skipped

Job Result
issue-4462-scope-upgrade-approval-e2e ❌ failure

Failed jobs: issue-4462-scope-upgrade-approval-e2e. Check run artifacts for logs.

cv pushed a commit that referenced this pull request Jun 11, 2026
## Summary
This PR narrows the `openclaw devices approve` compatibility recovery so
a failed scope-upgrade approval can recover when OpenClaw replaces the
original pending request with a same-device request that includes
`operator.admin`. PR #4949 is not treated as the root cause: it changed
the build/startup path enough to expose this latent approval replacement
behavior, while the actual bug is the approval wrapper returning failure
after OpenClaw leaves only the replacement request pending.

## Changes
- Pass the failed approve command output into the existing post-failure
recovery path.
- Detect only same-device replacement requests reported by the CLI as
`scope upgrade pending approval` or `pairing required`.
- Match replacement request IDs with token boundaries instead of
substring matching.
- Persist `pending.json` and `paired.json` through same-directory atomic
replaces.
- Merge existing `approvedScopes` and `scopes`, approve only the
expected operator scope closure, strip `operator.admin`, and keep token
scopes aligned.
- Keep the focused guard regression in `test/nemoclaw-start.test.ts` and
ratchet its legacy size budget down after removing comment-only
scaffolding.

## Type of Change
- [x] Code change (feature, bug fix, or refactor)
- [ ] Code change with doc updates
- [ ] Doc only (prose changes, no code sample modifications)
- [ ] Doc only (includes code sample changes)

## Verification
- [ ] `npx prek run --all-files` passes
- [ ] `npm test` passes
- [x] Tests added or updated for new or changed behavior
- [x] No secrets, API keys, or credentials committed
- [ ] Docs updated for user-facing behavior changes
- [ ] `npm run docs` builds without warnings (doc changes only)
- [ ] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)

Additional verification run locally:
- `bash -n scripts/nemoclaw-start.sh`
- `npx @biomejs/biome check test/nemoclaw-start.test.ts
ci/test-file-size-budget.json`
- `npm run test-size:check`
- `npx vitest --run test/nemoclaw-start.test.ts`

Note: `npx prek run --files ci/test-file-size-budget.json
scripts/nemoclaw-start.sh test/nemoclaw-start.test.ts` passed
formatting, shellcheck, repository checks, and test-size budget, but its
CLI hook also launched broader live E2E tests and failed on unrelated
live sandbox/onboard cleanup/timeouts. It is not marked as passing
above.

---
Signed-off-by: San Dang <sdang@nvidia.com>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* More reliable device approval handling with deterministic recovery of
pairing/pending state, stricter scope allowlist enforcement, and safer
replacement-selection logic.
* **Tests**
* Updated tests to simulate approval failure and verify guarded recovery
behavior; strengthened startup/entrypoint assertions (tokens, file
locks, stderr).
* **Chores**
  * Reduced test file-size budget for a specific test.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: messaging Messaging channels, bridges, manifests, or channel lifecycle refactor PR restructures code without intended behavior change v0.0.64 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Phase 5: migrate messaging agent rendering and build inputs to manifests

5 participants