Skip to content

cherry-pick: upstream bugfix commits (2026-02-08-2013)#117

Merged
hughdidit merged 164 commits intodaisy/devfrom
cherry/bugfix-2026-02-08-2013
Mar 1, 2026
Merged

cherry-pick: upstream bugfix commits (2026-02-08-2013)#117
hughdidit merged 164 commits intodaisy/devfrom
cherry/bugfix-2026-02-08-2013

Conversation

@github-actions
Copy link
Copy Markdown

@github-actions github-actions bot commented Feb 8, 2026

Summary

Automated cherry-pick of upstream bugfix commits from upstream/main.

This branch was created from origin/main, so cherry-picks apply cleanly on
their own upstream lineage. Any merge conflicts in this PR are due to fork
divergence in daisy/dev and should be resolved during merge (not in the
cherry-picks themselves).

No upstream code was executed. These commits were classified by metadata
(commit subjects and file paths) and cherry-picked onto a throwaway branch
for human review only.

Commits

What to beware of

Bug fixes may subtly change behavior the fork relies on. Check for side effects in shared modules, altered return types, and changed error handling paths.

About conflicts

Some cherry-picks may have conflicted during application — these are committed
with conflict markers intact and are visible in the diff for manual resolution.
Additionally, this PR may show merge conflicts against daisy/dev due to
fork divergence. Resolve both in the merge UI or locally with git merge.

Risk

  • Category: bugfix
  • Commits: 165

Review checklist

  • No code was auto-executed — verify the diff manually before merging
  • CI passes on this branch
  • Smoke test affected functionality
  • Inspect each commit for unexpected side effects or behavioral changes
  • Check for new dependencies, post-install hooks, or permission changes
  • If merge conflicts exist, verify resolution preserves fork-specific changes

Generated by scripts/upstream-triage.sh --apply --open-pr on 2026-02-08-2013 — no upstream code was executed

Lukavyi and others added 30 commits February 8, 2026 20:13
875b018 removed onToolResult from dispatch-from-config.ts to prevent
tool summaries leaking into group channels. However, this also broke
verbose tool summaries in DM/private sessions where they are expected.

This restores onToolResult but gates it behind ChatType !== 'group',
so group channels remain unaffected while DM verbose works again.

mirror=false is passed to sendPayloadAsync to avoid duplicating tool
summaries in the session transcript (matching the block reply behavior).

Fixes openclaw#2665

(cherry picked from commit f27a503)
Native slash commands (e.g. /verbose, /status) should not emit tool
summaries. Gate onToolResult behind CommandSource !== 'native' in
addition to the existing ChatType !== 'group' check.

Add test for native command exclusion.

(cherry picked from commit c13c39f)
…ibility (openclaw#3750)

NTFS does not allow < or > in filenames, causing the XML filename
escaping test to fail on Windows CI with ENOENT.

Replace file<test>.txt with file&test.txt — & is valid on all platforms
and still requires XML escaping (&amp;), preserving the test's intent.

Fixes openclaw#3748

(cherry picked from commit c200350)
(cherry picked from commit 718bc3f)

# Conflicts:
#	CHANGELOG.md
#	src/telegram/bot-native-commands.ts
#	src/telegram/bot/delivery.ts
(cherry picked from commit d47b4e6)

# Conflicts:
#	src/commands/onboard-auth.config-core.ts
#	src/plugins/config-state.ts
(cherry picked from commit 0257661)

# Conflicts:
#	docs/providers/xiaomi.md
#	package.json
#	src/cli/banner.ts
#	src/commands/doctor-gateway-services.ts
#	src/commands/doctor.ts
#	src/commands/onboard-helpers.ts
#	src/daemon/inspect.ts
(cherry picked from commit a155e2f)

# Conflicts:
#	src/commands/doctor-config-flow.ts
(cherry picked from commit 9886fd1)

# Conflicts:
#	package.json
#	src/commands/onboard-helpers.ts
#	src/config/paths.ts
(cherry picked from commit b9afa3d)

# Conflicts:
#	package.json
#	src/infra/state-migrations.ts
(cherry picked from commit 151ddd6)

# Conflicts:
#	package.json
…obhparker)

(cherry picked from commit 9025da2)

# Conflicts:
#	src/telegram/bot-native-commands.ts
…gway)

(cherry picked from commit 3a85cb1)

# Conflicts:
#	CHANGELOG.md
(cherry picked from commit bc432d8)

# Conflicts:
#	README.md
…bviyus)

(cherry picked from commit fa9ec6e)

# Conflicts:
#	CHANGELOG.md
(cherry picked from commit da71eae)

# Conflicts:
#	CHANGELOG.md
#	src/markdown/render.ts
#	src/telegram/format.test.ts
…penclaw#4593)

OAuth credentials with a refresh token auto-renew on first API call,
so the doctor should not warn about access token expiration when a
refresh token is present. This avoids unnecessary "expired" warnings
that prompt users to re-auth when no action is needed.

Fixes openclaw#3032

Co-authored-by: Ayush Ojha <[email protected]>
(cherry picked from commit 37e295f)
Co-authored-by: jlowin <[email protected]>
(cherry picked from commit f24e3cd)

# Conflicts:
#	src/cli/models-cli.ts
#	src/commands/models/list.status-command.ts
#	src/commands/models/list.status.test.ts
(cherry picked from commit daf27dd)

# Conflicts:
#	CHANGELOG.md
Co-authored-by: Hisleren <[email protected]>
(cherry picked from commit e5a95b5)

# Conflicts:
#	src/commands/configure.gateway.ts
#	src/wizard/onboarding.gateway-config.ts
…Hisleren)

Co-authored-by: Hisleren <[email protected]>
(cherry picked from commit 39eb0b7)

# Conflicts:
#	CHANGELOG.md
…hanks @YuriNachos)

Co-authored-by: YuriNachos <[email protected]>
(cherry picked from commit 34bdbdb)

# Conflicts:
#	CHANGELOG.md
#	src/infra/control-ui-assets.ts
…unce routing (openclaw#4957)

* fix: prefer requesterOrigin over stale session entry in subagent announce routing

When a subagent finishes and announces results back, resolveAnnounceOrigin
merged the session entry (primary) with requesterOrigin (fallback). If the
session store had a stale lastChannel (e.g. whatsapp) from a previous
interaction but the user was now on a different channel (e.g. bluebubbles),
the announce would route to the wrong channel.

Swap the merge order so requesterOrigin (captured at spawn time, reflecting
the actual current channel) takes priority, with the session entry as
fallback for any missing fields.

Error before fix:
  Delivery failed (whatsapp to bluebubbles:chat_guid:...): Unknown channel: whatsapp

Adds regression test for the stale-channel scenario.

* fix: match test to exact failure scenario and improve reliability (openclaw#4957) (thanks @tyler6204)

- Remove lastTo from stale session store to match the exact mismatch scenario described in the PR
- Replace 5ms setTimeout sleeps with expect.poll for better test reliability
- Prevents flakiness on slower CI machines

(cherry picked from commit 57248a7)
…jasonsschin)

(cherry picked from commit e849df6)

# Conflicts:
#	CHANGELOG.md
#	src/telegram/token.ts
(cherry picked from commit 310eed8)

# Conflicts:
#	src/config/sessions/store.ts
#	src/utils/delivery-context.test.ts
#	src/utils/delivery-context.ts
(cherry picked from commit 3c8fa0f)

# Conflicts:
#	src/cli/completion-cli.ts
(cherry picked from commit e9f0be0)

# Conflicts:
#	src/agents/pi-embedded-runner/compact.ts
#	src/agents/pi-model-discovery.ts
dxd5001 and others added 21 commits February 8, 2026 20:13
* Fix: Enable scrolling in dashboard

* Fix: Enable scrolling in dashboard

* Fix: Enable scrolling in dashboard

(cherry picked from commit cefd87f)
(cherry picked from commit de7b2ba)

# Conflicts:
#	docs/tools/thinking.md
Adds cleanup handlers to release held file locks when the process
terminates via SIGTERM, SIGINT, or normal exit. This prevents orphaned
lock files that would block future sessions.

Fixes openclaw#1951

(cherry picked from commit ec0728b)
The dist/control-ui/ files were committed before the dist/ gitignore
rule was effective. These build artifacts get regenerated during
builds, causing dirty repo errors that block the auto-update mechanism.

Removes the files from git tracking while keeping them locally and
respecting the existing dist/ gitignore entry.

Fixes openclaw#1838

Co-authored-by: Claude <[email protected]>
(cherry picked from commit 3ad7958)
…2022)

HOTFIX: Tool summaries were not being sent to chat channels when verbose mode
was enabled. The onToolResult callback was defined in the types but never
wired up in dispatch-from-config.ts.

This adds the missing callback alongside onBlockReply, using the same
dispatcher.sendBlockReply() path to deliver tool summaries to WhatsApp,
Telegram, and other chat channels.

Fixes verbose tool summaries not appearing in WhatsApp despite /verbose on.

(cherry picked from commit 05b28c1)
(cherry picked from commit 47538bc)

# Conflicts:
#	src/gateway/server-http.ts
* fix: Gateway authentication token exposed in URL query parameters

* fix: silence unused hook token url param

* fix: remove gateway auth tokens from URLs (openclaw#9436) (thanks @coygeek)

* test: fix Windows path separators in audit test (openclaw#9436)

---------

Co-authored-by: George Pickett <[email protected]>
(cherry picked from commit 717129f)

# Conflicts:
#	docs/gateway/configuration.md
#	docs/help/faq.md
#	docs/platforms/exe-dev.md
#	docs/start/clawd.md
#	docs/web/dashboard.md
#	src/commands/dashboard.ts
#	src/gateway/hooks.ts
#	src/gateway/server-http.ts
#	src/wizard/onboarding.finalize.ts
#	ui/src/ui/app-settings.ts
#	ui/src/ui/views/overview.ts
(cherry picked from commit 7224585)

# Conflicts:
#	CHANGELOG.md
#	src/infra/control-ui-assets.ts
…resolution

(cherry picked from commit 4a59b77)

# Conflicts:
#	src/cli/update-cli.ts
#	src/version.ts
* fix: guard resolveUserPath against undefined input

When subagent spawner omits workspaceDir, resolveUserPath receives
undefined and crashes on .trim().  Add a falsy guard that falls back
to process.cwd(), matching the behavior callers already expect.

Closes openclaw#10089

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: harden runner workspace fallback (openclaw#10176) (thanks @Yida-Dev)

* fix: harden workspace fallback scoping (openclaw#10176) (thanks @Yida-Dev)

* refactor: centralize workspace fallback classification and redaction (openclaw#10176) (thanks @Yida-Dev)

* test: remove explicit any from utils mock (openclaw#10176) (thanks @Yida-Dev)

* security: reject malformed agent session keys for workspace resolution (openclaw#10176) (thanks @Yida-Dev)

---------

Co-authored-by: Yida-Dev <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: Gustavo Madeira Santana <[email protected]>
(cherry picked from commit 4216449)

# Conflicts:
#	CHANGELOG.md
#	src/agents/cli-runner.test.ts
#	src/agents/cli-runner.ts
#	src/agents/pi-embedded-runner/run.ts
#	src/agents/pi-embedded-runner/run/attempt.ts
#	src/auto-reply/reply/agent-runner-execution.ts
#	src/commands/status-all/channels.ts
#	src/utils.test.ts
…n session-memory (openclaw#10730)

* fix: replace debug console.log with proper subsystem logging in session-memory

* fix(hooks): normalize session-memory subsystem logging

---------

Co-authored-by: Tak Hoffman <[email protected]>
(cherry picked from commit 2c8af78)
…openclaw#10776)

* refactor: update cron job wake mode and run mode handling

- Changed default wake mode from 'next-heartbeat' to 'now' in CronJobEditor and related CLI commands.
- Updated cron-tool tests to reflect changes in run mode, introducing 'due' and 'force' options.
- Enhanced cron-tool logic to handle new run modes and ensure compatibility with existing job structures.
- Added new tests for delivery plan consistency and job execution behavior under various conditions.
- Improved normalization functions to handle wake mode and session target casing.

This refactor aims to streamline cron job configurations and enhance the overall user experience with clearer defaults and improved functionality.

* test: enhance cron job functionality and UI

- Added tests to ensure the isolated agent correctly announces the final payload text when delivering messages via Telegram.
- Implemented a new function to pick the last deliverable payload from a list of delivery payloads.
- Enhanced the cron service to maintain legacy "every" jobs while minute cron jobs recompute schedules.
- Updated the cron store migration tests to verify the addition of anchorMs to legacy every schedules.
- Improved the UI for displaying cron job details, including job state and delivery information, with new styles and layout adjustments.

These changes aim to improve the reliability and user experience of the cron job system.

* test: enhance sessions thinking level handling

- Added tests to verify that the correct thinking levels are applied during session spawning.
- Updated the sessions-spawn-tool to include a new parameter for overriding thinking levels.
- Enhanced the UI to support additional thinking levels, including "xhigh" and "full", and improved the handling of current options in dropdowns.

These changes aim to improve the flexibility and accuracy of thinking level configurations in session management.

* feat: enhance session management and cron job functionality

- Introduced passthrough arguments in the test-parallel script to allow for flexible command-line options.
- Updated session handling to hide cron run alias session keys from the sessions list, improving clarity.
- Enhanced the cron service to accurately record job start times and durations, ensuring better tracking of job execution.
- Added tests to verify the correct behavior of the cron service under various conditions, including zero-delay timers.

These changes aim to improve the usability and reliability of session and cron job management.

* feat: implement job running state checks in cron service

- Added functionality to prevent manual job runs if a job is already in progress, enhancing job management.
- Updated the `isJobDue` function to include checks for running jobs, ensuring accurate scheduling.
- Enhanced the `run` function to return a specific reason when a job is already running.
- Introduced a new test case to verify the behavior of forced manual runs during active job execution.

These changes aim to improve the reliability and clarity of cron job execution and management.

* feat: add session ID and key to CronRunLogEntry model

- Introduced `sessionid` and `sessionkey` properties to the `CronRunLogEntry` struct for enhanced tracking of session-related information.
- Updated the initializer and Codable conformance to accommodate the new properties, ensuring proper serialization and deserialization.

These changes aim to improve the granularity of logging and session management within the cron job system.

* fix: improve session display name resolution

- Updated the `resolveSessionDisplayName` function to ensure that both label and displayName are trimmed and default to an empty string if not present.
- Enhanced the logic to prevent returning the key if it matches the label or displayName, improving clarity in session naming.

These changes aim to enhance the accuracy and usability of session display names in the UI.

* perf: skip cron store persist when idle timer tick produces no changes

recomputeNextRuns now returns a boolean indicating whether any job
state was mutated. The idle path in onTimer only persists when the
return value is true, eliminating unnecessary file writes every 60s
for far-future or idle schedules.

* fix: prep for merge - explicit delivery mode migration, docs + changelog (openclaw#10776) (thanks @tyler6204)

(cherry picked from commit d90cac9)

# Conflicts:
#	CHANGELOG.md
#	docs/automation/cron-jobs.md
#	scripts/test-parallel.mjs
#	src/agents/openclaw-tools.subagents.sessions-spawn-applies-thinking-default.test.ts
#	src/cli/cron-cli/register.cron-add.ts
#	src/cron/delivery.ts
#	src/cron/isolated-agent.skips-delivery-without-whatsapp-recipient-besteffortdeliver-true.test.ts
#	src/cron/isolated-agent/run.ts
#	src/cron/normalize.ts
#	src/cron/run-log.ts
#	src/cron/service.every-jobs-fire.test.ts
#	src/cron/service.skips-main-jobs-empty-systemevent-text.test.ts
#	src/cron/service.store.migration.test.ts
#	src/cron/service/jobs.ts
#	src/cron/service/store.ts
#	src/cron/service/timer.ts
#	src/cron/store.ts
#	src/gateway/protocol/schema/cron.ts
#	src/gateway/session-utils.ts
#	ui/src/ui/app-defaults.ts
#	ui/src/ui/app-render.helpers.ts
#	ui/src/ui/app-render.ts
#	ui/src/ui/format.test.ts
#	ui/src/ui/format.ts
#	ui/src/ui/views/cron.ts
#	ui/src/ui/views/sessions.ts
* feat(bluebubbles): auto-strip markdown from outbound messages (openclaw#7402)

* fix(security): add timeout to webhook body reading (openclaw#6762)

Adds 30-second timeout to readBody() in voice-call, bluebubbles, and nostr
webhook handlers. Prevents Slow-Loris DoS (CWE-400, CVSS 7.5).
Merged with existing maxBytes protection in voice-call.

* fix(security): unify Error objects and lint fixes in webhook timeouts (openclaw#6762)

* fix: prevent plugins from auto-enabling without user consent (openclaw#3961)

Changes default plugin enabled state from true to false in enablePluginEntry().
Preserves existing enabled:true values. Fixes openclaw#3932.

* fix: apply hierarchical mediaMaxMb config to all channels (openclaw#8749)

Generalizes resolveAttachmentMaxBytes() to use account → channel → global
config resolution for all channels, not just BlueBubbles. Fixes openclaw#7847.

* fix(bluebubbles): sanitize attachment filenames against header injection (openclaw#10333)

Strip ", \r, \n, and \\ from filenames after path.basename() to prevent
multipart Content-Disposition header injection (CWE-93, CVSS 5.4).
Also adds sanitization to setGroupIconBlueBubbles which had zero filename
sanitization.

* fix(lint): exclude extensions/ from Oxlint preflight check (openclaw#9313)

Extensions use PluginRuntime|null patterns that trigger
no-redundant-type-constituents because PluginRuntime resolves to any.
Excluding extensions/ from Oxlint unblocks user upgrades.
Re-applies the approach from closed PR openclaw#10087.

* fix(bluebubbles): add tempGuid to createNewChatWithMessage payload (openclaw#7745)

Non-Private-API mode (AppleScript) requires tempGuid in send payloads.
The main sendMessageBlueBubbles already had it, but createNewChatWithMessage
was missing it, causing 400 errors for new chat creation without Private API.

* fix: send stop-typing signal when run ends with NO_REPLY (openclaw#8785)

Adds onCleanup callback to the typing controller that fires when the
controller is cleaned up while typing was active (e.g., after NO_REPLY).
Channels using createTypingCallbacks automatically get stop-typing on
cleanup. This prevents the typing indicator from lingering in group chats
when the agent decides not to reply.

* fix(telegram): deduplicate skill commands in multi-agent setup (openclaw#5717)

Two fixes:
1. Skip duplicate workspace dirs when listing skill commands across agents.
   Multiple agents sharing the same workspace would produce duplicate commands
   with _2, _3 suffixes.
2. Clear stale commands via deleteMyCommands before registering new ones.
   Commands from deleted skills now get cleaned up on restart.

* fix: add size limits to unbounded in-memory caches (openclaw#4948)

Adds max-size caps with oldest-entry eviction to prevent OOM in
long-running deployments:
- BlueBubbles serverInfoCache: 64 entries (already has TTL)
- Google Chat authCache: 32 entries
- Matrix directRoomCache: 1024 entries
- Discord presenceCache: 5000 entries per account

* fix: address review concerns (openclaw#11093)

- Chain deleteMyCommands → setMyCommands to prevent race condition (openclaw#5717)
- Rename enablePluginEntry to registerPluginEntry (now sets enabled: false)
- Add Slow-Loris timeout test for readJsonBody (openclaw#6023)

(cherry picked from commit 1007d71)

# Conflicts:
#	extensions/bluebubbles/src/chat.ts
#	extensions/bluebubbles/src/send.ts
#	extensions/voice-call/src/webhook.ts
#	src/auto-reply/skill-commands.ts
#	src/config/plugin-auto-enable.ts
* fix: add .caf to AUDIO_FILE_EXTENSIONS for iMessage voice messages

* fix: add caf audio extension regression coverage (openclaw#10982) (thanks @succ985)

---------

Co-authored-by: succ985 <[email protected]>
Co-authored-by: Gustavo Madeira Santana <[email protected]>
(cherry picked from commit b8f740f)

# Conflicts:
#	CHANGELOG.md
#	src/media/mime.test.ts
…penclaw#11579)

* fix: gracefully handle oversized tool results causing context overflow

When a subagent reads a very large file or gets a huge tool result (e.g.,
gh pr diff on a massive PR), it can exceed the model's context window in
a single prompt. Auto-compaction can't help because there's no older
history to compact — just one giant tool result.

This adds two layers of defense:

1. Pre-emptive: Hard cap on tool result size (400K chars ≈ 100K tokens)
   applied in the session tool result guard before persistence. This
   prevents extremely large tool results from being stored in full,
   regardless of model context window size.

2. Recovery: When context overflow is detected and compaction fails,
   scan session messages for oversized tool results relative to the
   model's actual context window (30% max share). If found, truncate
   them in the session via branching (creating a new branch with
   truncated content) and retry the prompt.

The truncation preserves the beginning of the content (most useful for
understanding what was read) and appends a notice explaining the
truncation and suggesting offset/limit parameters for targeted reads.

Includes comprehensive tests for:
- Text truncation with newline-boundary awareness
- Context-window-proportional size calculation
- In-memory message truncation
- Oversized detection heuristics
- Guard-level size capping during persistence

* fix: prep fixes for tool result truncation PR (openclaw#11579) (thanks @tyler6204)

(cherry picked from commit 0deb8b0)

# Conflicts:
#	src/agents/pi-embedded-runner/run.ts
#	src/agents/session-tool-result-guard.test.ts
#	src/agents/session-tool-result-guard.ts
(cherry picked from commit 95263f4)

# Conflicts:
#	src/memory/search-manager.test.ts
…canvas (openclaw#4824)

* fix: use STATE_DIR instead of hardcoded ~/.openclaw for identity and canvas

device-identity.ts and canvas-host/server.ts used hardcoded
path.join(os.homedir(), '.openclaw', ...) ignoring OPENCLAW_STATE_DIR
env var and the resolveStateDir() logic from config/paths.ts.

This caused ~/.openclaw/identity and ~/.openclaw/canvas directories
to be created even when state dir was overridden or resided elsewhere.

* fix: format and remove duplicate imports

* fix: scope state-dir patch + add regression tests (openclaw#4824) (thanks @kossoy)

* fix: align state-dir fallbacks in hooks and agent paths (openclaw#4824) (thanks @kossoy)

---------

Co-authored-by: Gustavo Madeira Santana <[email protected]>
(cherry picked from commit ebe5730)

# Conflicts:
#	CHANGELOG.md
#	src/agents/agent-scope.ts
#	src/agents/sandbox/constants.ts
#	src/canvas-host/server.ts
#	src/cli/update-cli.ts
#	src/commands/agents.test.ts
#	src/hooks/bundled/command-logger/handler.ts
#	src/hooks/bundled/session-memory/handler.ts
#	src/infra/device-identity.ts
…penclaw#11664) (thanks @tyler6204)

* initial commit

* feat: implement deriveSessionTotalTokens function and update usage tests

* Added deriveSessionTotalTokens function to calculate total tokens based on usage and context tokens.
* Updated usage tests to include cases for derived session total tokens.
* Refactored session usage calculations in multiple files to utilize the new function for improved accuracy.

* fix: restore overflow truncation fallback + changelog/test hardening (openclaw#11551) (thanks @tyler6204)

(cherry picked from commit 191da1f)

# Conflicts:
#	CHANGELOG.md
#	scripts/test-parallel.mjs
#	src/agents/clawdbot-tools.subagents.sessions-spawn-normalizes-allowlisted-agent-ids.test.ts
#	src/agents/pi-embedded-runner/run.overflow-compaction.test.ts
#	src/agents/pi-embedded-runner/run.ts
#	src/agents/pi-embedded-runner/run/types.ts
#	src/agents/pi-embedded-subscribe.handlers.messages.ts
#	src/agents/subagent-announce.format.test.ts
#	src/agents/subagent-announce.ts
#	src/agents/subagent-registry.ts
#	src/agents/timeout.ts
#	src/agents/usage.test.ts
#	src/commands/agent/session-store.ts
#	ui/src/styles/components.css
#	ui/src/ui/views/chat.ts
Comment thread src/cli/completion-cli.ts
Comment on lines +153 to +157
const desc = c
.description()
.replace(/'/g, "'\\''")
.replace(/\[/g, "\\[")
.replace(/\]/g, "\\]");

Check failure

Code scanning / CodeQL

Incomplete string escaping or encoding High

This does not escape backslash characters in the input.

Copilot Autofix

AI 2 months ago

In general, to fix incomplete escaping when using String.replace, you must ensure that all relevant metacharacters for the target context are handled, including backslashes, and that replacements are global (using regexes with the g flag). In many cases, using a dedicated escaping/sanitization helper is better than duplicating similar logic in multiple places.

In this file, the specific issue is in generateZshSubcmdList, where the description is escaped like this:

const desc = c
  .description()
  .replace(/'/g, "'\\''")
  .replace(/\[/g, "\\[")
  .replace(/\]/g, "\\]");

Backslashes in the original description are not escaped, so an input containing \ can interact badly with the subsequent escaping for ', [, and ] or with the zsh _arguments syntax. The minimal, behavior-preserving fix is to first escape backslashes themselves, then apply the existing replacements. That way, any literal backslash in the description becomes \\ in the completion script, preventing it from unintentionally escaping characters that follow.

We only need to modify the generateZshSubcmdList function in src/cli/completion-cli.ts. Specifically, in the .map((c) => { ... }) block, we should insert a .replace(/\\/g, "\\\\") before the other replacements on c.description(). No new imports or helper functions are required; the built-in String.replace with a regex literal is sufficient.

Suggested changeset 1
src/cli/completion-cli.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/cli/completion-cli.ts b/src/cli/completion-cli.ts
--- a/src/cli/completion-cli.ts
+++ b/src/cli/completion-cli.ts
@@ -152,6 +152,7 @@
     .map((c) => {
       const desc = c
         .description()
+        .replace(/\\/g, "\\\\")
         .replace(/'/g, "'\\''")
         .replace(/\[/g, "\\[")
         .replace(/\]/g, "\\]");
EOF
@@ -152,6 +152,7 @@
.map((c) => {
const desc = c
.description()
.replace(/\\/g, "\\\\")
.replace(/'/g, "'\\''")
.replace(/\[/g, "\\[")
.replace(/\]/g, "\\]");
Copilot is powered by AI and may make mistakes. Always verify output.
Comment thread src/cli/completion-cli.ts
Comment on lines +153 to +156
const desc = c
.description()
.replace(/'/g, "'\\''")
.replace(/\[/g, "\\[")

Check failure

Code scanning / CodeQL

Incomplete string escaping or encoding High

This does not escape backslash characters in the input.

Copilot Autofix

AI 2 months ago

In general, the fix is to ensure that all characters with special meaning in the target context (here, zsh completion descriptions inside single quotes and bracket expressions) are escaped consistently. Since we are already doing string .replace operations to escape some characters, we should extend that sequence to also escape backslashes (\), and do so before any replacements that introduce new backslashes. Alternatively, a dedicated shell-escaping utility could be used, but here a targeted additional replacement is sufficient.

Concretely, in src/cli/completion-cli.ts, in generateZshSubcmdList, we build desc from c.description() and then chain .replace(/'/g, "'\\''"), .replace(/\[/g, "\\["), .replace(/\]/g, "\\]"). We should add an initial .replace(/\\/g, "\\\\") so that every backslash in the original description becomes \\ in the output. This must be the first replacement in the chain, because the later replacements insert backslashes; escaping those again would change their meaning. No other parts of the file need changes, and no new imports are required.

Suggested changeset 1
src/cli/completion-cli.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/cli/completion-cli.ts b/src/cli/completion-cli.ts
--- a/src/cli/completion-cli.ts
+++ b/src/cli/completion-cli.ts
@@ -152,6 +152,7 @@
     .map((c) => {
       const desc = c
         .description()
+        .replace(/\\/g, "\\\\")
         .replace(/'/g, "'\\''")
         .replace(/\[/g, "\\[")
         .replace(/\]/g, "\\]");
EOF
@@ -152,6 +152,7 @@
.map((c) => {
const desc = c
.description()
.replace(/\\/g, "\\\\")
.replace(/'/g, "'\\''")
.replace(/\[/g, "\\[")
.replace(/\]/g, "\\]");
Copilot is powered by AI and may make mistakes. Always verify output.
@github-actions github-actions bot added the patchbot:triaged PR passed Patchbot triage rules label Mar 1, 2026
@github-actions
Copy link
Copy Markdown
Author

github-actions bot commented Mar 1, 2026

Patchbot

Stage Status
Triage ✅ Passed
CI ⏳ No CI checks found yet
Approval ⏳ Awaiting review
Release ⏳ pending
Deploy ⏳ pending
Verify ⏳ pending
CI Checks (0/0 passed)
Check Result

Updated 2026-03-01T02:37:09.568Z · Run #22534269444

@hughdidit hughdidit merged commit b5bcbd8 into daisy/dev Mar 1, 2026
9 checks passed
@hughdidit hughdidit deleted the cherry/bugfix-2026-02-08-2013 branch March 1, 2026 02:37
hughdidit added a commit that referenced this pull request Mar 1, 2026
hughdidit added a commit that referenced this pull request Mar 1, 2026
* Revert "cherry-pick: upstream refactor/feature commits (2026-02-08-2013) (#119)"

This reverts commit ca1d391.

* Revert "cherry-pick: upstream bugfix commits (2026-02-08-2013) (#117)"

This reverts commit b5bcbd8.

* Revert "cherry-pick: upstream deps/security commits (2026-02-08-2013) (#115)"

This reverts commit 89c4883.

* Revert "cherry-pick: upstream ci commits (2026-02-08-2013) (#116)"

This reverts commit 595f964.

* Revert "cherry-pick: upstream docs commits (2026-02-08-2013) (#118)"

This reverts commit da859ed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

patchbot:triaged PR passed Patchbot triage rules

Projects

None yet

Development

Successfully merging this pull request may close these issues.