Skip to content

fix(cli): wire ACP model-invocable commands - #5504

Merged
wenshao merged 1 commit into
QwenLM:mainfrom
tt-a1i:fix/acp-model-invocable-commands
Jun 20, 2026
Merged

fix(cli): wire ACP model-invocable commands#5504
wenshao merged 1 commit into
QwenLM:mainfrom
tt-a1i:fix/acp-model-invocable-commands

Conversation

@tt-a1i

@tt-a1i tt-a1i commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

What this PR does

  • Registers the model-invocable command provider/executor when ACP builds command snapshots from session settings.
  • Avoids partial registration when session settings are unavailable.
  • Avoids retaining the snapshot timeout signal for later hook execution.
  • Keeps disabled slash commands out of SkillTool's model-invocable command path.

Why it's needed

ACP available_commands_update builds slash commands through getAvailableCommands(), but that path only returned the command list. It did not wire the model-invocable command provider/executor onto Config, so SkillTool could miss MCP prompts or file commands that the ACP command snapshot already knew about.

There was also a cancellation edge where a snapshot timeout signal could be captured by a long-lived executor. Later UserPromptExpansion hooks could then see an already-aborted signal.

Reviewer Test Plan

How to verify

  • Review the ACP command snapshot path: it should register model-invocable commands when settings are available.
  • Review disabled slash command handling: disabled commands should not become model-invocable commands.
  • Review timeout handling: the snapshot timeout signal should not be retained for later hook execution.
  • Run npm test --workspace=packages/cli -- --coverage.enabled=false src/nonInteractiveCliCommands.test.ts.
  • Run npm test --workspace=packages/cli -- --coverage.enabled=false src/acp-integration/session/Session.test.ts.
  • Run npx eslint packages/cli/src/nonInteractiveCliCommands.ts packages/cli/src/nonInteractiveCliCommands.test.ts packages/cli/src/acp-integration/session/Session.ts packages/cli/src/acp-integration/session/Session.test.ts.
  • Run npx prettier --check packages/cli/src/nonInteractiveCliCommands.ts packages/cli/src/nonInteractiveCliCommands.test.ts packages/cli/src/acp-integration/session/Session.ts packages/cli/src/acp-integration/session/Session.test.ts.
  • Run git diff --check.

Evidence (Before & After)

Before: ACP snapshots could list commands without wiring the matching model-invocable provider/executor on Config, so later model-invocable command execution could miss commands the snapshot had advertised. After: the snapshot path registers the same model-invocable command surface when settings are available, and disabled commands remain excluded.

Tested on

OS Status
🍏 macOS ✅ tested
🪟 Windows ⚠️ not tested locally; covered by CI
🐧 Linux ⚠️ not tested locally; covered by CI

Environment (optional)

Local npm workspace. npm run typecheck --workspace=packages/cli still fails on existing BaseTextInput.tsx ink/dom and ink/components/CursorContext type resolution.

Risk & Scope

  • Main risk or tradeoff: ACP command snapshot setup now also mutates the model-invocable command registration on Config when settings are available.
  • Not validated / out of scope: changing command discovery semantics outside the ACP snapshot/model-invocable command path.
  • Breaking changes / migration notes: none.

Linked Issues

Fixes #5503

中文说明

What this PR does

  • ACP 从 session settings 构建 command snapshot 时,同时注册 model-invocable command provider/executor。
  • session settings 不可用时避免半注册状态。
  • 避免把 snapshot timeout signal 保存给后续 hook 执行使用。
  • 禁用的 slash command 不会进入 SkillTool 的 model-invocable command 路径。

Why it's needed

ACP available_commands_update 通过 getAvailableCommands() 构建 slash commands,但旧路径只返回 command list,没有把 model-invocable command provider/executor 挂到 Config 上。因此 SkillTool 可能拿不到 ACP command snapshot 已经知道的 MCP prompts 或 file commands。

此外还有一个取消信号边界:snapshot timeout signal 如果被长期 executor 捕获,后续 UserPromptExpansion hooks 可能会看到一个已经 aborted 的 signal。

Reviewer Test Plan

How to verify

  • 检查 ACP command snapshot 路径:settings 可用时应该注册 model-invocable commands。
  • 检查禁用 slash command 的处理:disabled commands 不应该成为 model-invocable commands。
  • 检查 timeout 处理:snapshot timeout signal 不应该被保存给后续 hook 执行。
  • 运行英文部分列出的测试、eslint、prettier 和 git diff --check 命令。

Evidence (Before & After)

修复前:ACP snapshot 可能列出 commands,但没有把对应 model-invocable provider/executor 注册到 Config,导致后续 model-invocable command execution 漏掉 snapshot 已经 advertised 的 commands。修复后:settings 可用时,snapshot 路径会注册同一套 model-invocable command surface,并继续排除 disabled commands。

Tested on

OS Status
🍏 macOS ✅ tested
🪟 Windows ⚠️ not tested locally; covered by CI
🐧 Linux ⚠️ not tested locally; covered by CI

Environment (optional)

本地 npm workspace。npm run typecheck --workspace=packages/cli 仍在既有 BaseTextInput.tsxink/domink/components/CursorContext 类型解析处失败。

Risk & Scope

  • 主要风险或取舍:ACP command snapshot setup 现在会在 settings 可用时同步更新 Config 上的 model-invocable command registration。
  • 未验证 / 不在范围内:修改 ACP snapshot/model-invocable command 路径之外的 command discovery 语义。
  • Breaking changes / migration notes:无。

Linked Issues

Fixes #5503

AI Assistance Disclosure

I used Codex to review the changes, sanity-check the implementation against existing patterns, and help spot potential edge cases.

@tt-a1i
tt-a1i marked this pull request as ready for review June 20, 2026 16:58
@wenshao

wenshao commented Jun 20, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hi @tt-a1i, thanks for the fix — the bug itself (ACP snapshots missing model-invocable command wiring, issue #5503) is real and worth addressing.

However, the PR body doesn't follow our pull request template. The current headings are ## Summary, ## Testing, and ## AI Assistance Disclosure, but the template requires:

  • ## What this PR does — describe the change in prose
  • ## Why it's needed — motivation and user-facing impact
  • ## Reviewer Test Plan — with How to verify, Evidence (Before & After), and Tested on (OS table)
  • ## Risk & Scope — main risk, what's out of scope, breaking changes
  • ## Linked IssuesFixes #5503

Could you update the PR description to match the template? It helps reviewers (and future-us) understand the context without reading every diff line. Happy to re-run triage once that's done.

中文说明

你好 @tt-a1i,感谢提交修复——#5503 描述的 bug(ACP 快照缺少 model-invocable command 注册)确实存在且值得修复。

不过 PR 正文没有使用我们的PR 模板。当前的标题是 ## Summary## Testing## AI Assistance Disclosure,但模板要求的是:

  • ## What this PR does — 用文字描述改动
  • ## Why it's needed — 动机和用户影响
  • ## Reviewer Test Plan — 包含 How to verify(验证步骤)、Evidence(前后对比)、Tested on(操作系统表格)
  • ## Risk & Scope — 主要风险、不在范围内的内容、破坏性变更
  • ## Linked IssuesFixes #5503

能否按照模板更新 PR 描述?这样 reviewer(和未来的我们)不需要逐行看 diff 就能理解上下文。更新后可以重新触发 triage。

Qwen Code · qwen3.7-max

@qwen-code-ci-bot qwen-code-ci-bot added category/cli Command line interface and interaction scope/commands Command implementation scope/mcp Model Context Protocol type/bug Something isn't working as expected labels Jun 20, 2026
@tt-a1i

tt-a1i commented Jun 20, 2026

Copy link
Copy Markdown
Contributor Author

updated the PR description to match the template.\n\n@qwen-code /triage

@tt-a1i

tt-a1i commented Jun 20, 2026

Copy link
Copy Markdown
Contributor Author

updated the PR description to match the template.

@qwen-code /triage

@wenshao

wenshao commented Jun 20, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@wenshao

wenshao commented Jun 20, 2026

Copy link
Copy Markdown
Collaborator

✅ Local end-to-end verification (real command pipeline, tmux)

Verified by driving the real exported getAvailableCommands (the ACP snapshot registration site) and handleSlashCommand with a real custom TOML command on disk (modelInvocable via command-factory), loaded through the real CommandService + FileCommandLoader. The Config is a faithful stand-in that actually stores/returns the model-invocable provider/executor — exactly what core's real Config does and what SkillTool reads via getModelInvocableCommandsProvider/Executor (skill.ts/skill-utils.ts). Both sides ran via the worktree's real dist; only the 4 changed files differ:

  • BASE = merge-base 56e76e7e
  • PR = head 8cc05d0f

A/B result — each probe maps to a PR bullet

Probe BASE 56e76e7e PR 8cc05d0f
A — ACP getAvailableCommands('acp', settings) registers provider/executor provider=null, executor=null (the bug — model can't invoke commands in ACP) provider=[expand], executor('expand','hello')"EXPANDED[hello]"
B — disabled command kept out of the model-invocable path provider=[expand], executor('expand')"EXPANDED[]" (disabled cmd is exposed and executes) provider=[], executor('expand')null
C — executor's hook uses a fresh signal (snapshot signal already expired) hookSignal.aborted=true (retains the expired snapshot signal) hookSignal.aborted=false (fresh AbortController)
D — no settings → no partial registration registered=false registered=false (early-return guard)
========== BASE (56e76e7e) ==========
  A  loadedExpand=true  provider=null      executor('expand','hello')=null
  B  result=unsupported provider=[expand]  executor('expand')="EXPANDED[]"
  C  hookSignal.aborted=true
========== PR (8cc05d0f) ==========
  A  loadedExpand=true  provider=[expand]  executor('expand','hello')="EXPANDED[hello]"
  B  result=unsupported provider=[]        executor('expand')=null
  C  hookSignal.aborted=false

In ACP mode the command is loaded on both builds, but BASE never registers the provider/executor, so SkillTool sees no model-invocable commands — the model cannot invoke them (#5503). PR wires them through the snapshot path and the executor expands the real command. The three robustness facets also hold: a disabled command is no longer exposed to (or executed by) the model, the executor's prompt-expansion hook runs with a fresh non-aborted signal instead of the expired snapshot timeout, and nothing is registered when settings is absent (no half-wired state).

Unit test + revert-proof + static

  • vitest run on the PR source → nonInteractiveCliCommands.test.ts model-invocable tests 4/4 pass; Session.test.ts (the two mockSettings pass-through assertions) 2/2 pass.
  • Revert-proof: running the PR's new tests against the base source fails the two regression tests — registers model-invocable commands for ACP command snapshots ❌ and does not expose disabled model-invocable commands through SkillTool ❌ — while does not partially register … without settings passes on both (a guard test, not a regression test).
  • ESLint clean (exit 0); Prettier clean; git diff --check clean.
  • tsc not run end-to-end: per the PR description the CLI typecheck has a pre-existing, unrelated failure (BaseTextInput.tsx ink/dom + ink/components/CursorContext); the changed files are type-clean under ESLint and load/run under the real pipeline above.

Note

buildAvailableCommandsSnapshot (called by Session.sendAvailableCommandsUpdate and the ACP agent) now forwards settings into getAvailableCommands, which is what enables registration along the ACP path. acpAgent.ts:4245's one-arg buildAvailableCommandsSnapshot(session.getConfig()) is left settings-less by design (initial snapshot), so registration is driven by sendAvailableCommandsUpdate carrying this.settings.

Verdict: LGTM — ACP now wires model-invocable commands so the model can actually invoke them via SkillTool, with disabled-command exclusion, a fresh hook signal, and no partial registration.

🇨🇳 中文版本(点击展开)

✅ 本地端到端验证(真实命令管线,tmux)

通过驱动真实导出的 getAvailableCommands(ACP 快照的注册点)和 handleSlashCommand,配合磁盘上真实的自定义 TOML 命令(经 command-factory 标记为 modelInvocable),经由真实的 CommandService + FileCommandLoader 加载来验证。Config 用一个忠实的替身,它真正存取 model-invocable 的 provider/executor——这正是 core 真实 Config 的行为,也是 SkillTool 通过 getModelInvocableCommandsProvider/Executorskill.ts/skill-utils.ts)读取的内容。两边都跑 worktree 的真实 dist,仅 4 个改动文件不同:

  • BASE = merge-base 56e76e7e
  • PR = head 8cc05d0f

A/B 结果 —— 每个探针对应一个 PR 改动点

探针 BASE 56e76e7e PR 8cc05d0f
A —— ACP getAvailableCommands('acp', settings) 注册 provider/executor provider=nullexecutor=null即 bug——ACP 下模型无法调用命令 provider=[expand]executor('expand','hello')"EXPANDED[hello]"
B —— 被禁用命令排除在 model-invocable 路径之外 provider=[expand]executor('expand')"EXPANDED[]"被禁用命令既暴露又被执行 provider=[]executor('expand')null
C —— executor 的 hook 使用全新信号(快照信号已过期) hookSignal.aborted=true(沿用了过期的快照信号) hookSignal.aborted=false(全新 AbortController
D —— 无 settings 时不做部分注册 registered=false registered=false(提前返回守卫)

在 ACP 模式下命令在两个版本都能被加载,但 BASE 从不注册 provider/executor,因此 SkillTool 看不到任何 model-invocable 命令——模型无法调用它们(#5503)。PR 通过快照路径完成注册,executor 能展开真实命令。三个健壮性改动也都成立:被禁用的命令不再暴露给模型(也不再被执行)、executor 的 prompt 展开 hook 使用全新且未中止的信号而非过期的快照超时信号、且在缺少 settings 时不注册(不留半注册状态)。

单元测试 + 反向验证 + 静态检查

  • 在 PR 源码上 vitest runnonInteractiveCliCommands.test.ts 的 model-invocable 测试 4/4 通过Session.test.ts(两处 mockSettings 透传断言)2/2 通过
  • 反向验证:把 PR 新增测试放到 base 源码上跑,两个回归测试失败——registers model-invocable commands for ACP command snapshots ❌ 与 does not expose disabled model-invocable commands through SkillTool ❌;而 does not partially register … without settings 在两边都通过(守卫型,非回归型)。
  • ESLint 通过(exit 0);Prettier 通过;git diff --check 通过。
  • tsc 未端到端运行:按 PR 说明,CLI typecheck 存在与本 PR 无关的既有报错(BaseTextInput.tsx 的 ink/dom 与 ink/components/CursorContext);改动文件在 ESLint 下类型干净,并在上面的真实管线中正常加载/运行。

补充说明

buildAvailableCommandsSnapshot(由 Session.sendAvailableCommandsUpdate 与 ACP agent 调用)现在会把 settings 透传给 getAvailableCommands,这正是让 ACP 路径能够注册的关键。acpAgent.ts:4245 处单参数的 buildAvailableCommandsSnapshot(session.getConfig()) 按设计不带 settings(初始快照),因此注册由携带 this.settingssendAvailableCommandsUpdate 驱动。

结论:LGTM —— ACP 现在正确接线了 model-invocable 命令,使模型能真正通过 SkillTool 调用它们,并具备禁用命令排除、全新 hook 信号、且不做部分注册。

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓ — all required headings present, bilingual summary included, test plan is specific with commands.

On direction: this is a straightforward bug fix — ACP's available_commands_update path builds slash commands but never wires the model-invocable provider/executor onto Config, so SkillTool can't actually invoke commands that the snapshot already advertised. Clearly within scope, fixes a real functional gap (#5503). No direction concerns.

On approach: the scope is tight and well-targeted. Two focused changes:

  • Thread settings through getAvailableCommandsbuildAvailableCommandsSnapshotSession.sendAvailableCommandsUpdate so the ACP path can register the model-invocable surface.
  • Extract registerModelInvocableCommands to eliminate duplication between handleSlashCommand and getAvailableCommands, while also fixing the disabled-command leak (provider now uses the filtered service) and the expired-signal bug (fresh AbortController per execution).

The two-CommandService approach in handleSlashCommand (one for existence check, one for filtered execution+registration) is the right trade-off — reusing allCommandService for the existence fallback while keeping disabled commands out of the registered provider. No scope creep, no unrelated changes.

Moving on to code review. 🔍

中文说明

感谢贡献!

模板完整 ✓ — 所有必需标题齐全,双语说明包含,测试计划具体且包含可执行命令。

方向:这是一个直接的 bug 修复 — ACP 的 available_commands_update 路径构建了 slash commands 但从未将 model-invocable provider/executor 挂到 Config 上,导致 SkillTool 实际上无法调用 snapshot 已经 advertised 的命令。明确在项目范围内,修复了真实的功能缺口(#5503)。方向无顾虑。

方案:范围紧凑且目标明确。两个聚焦改动:

  • settings 透传到 getAvailableCommandsbuildAvailableCommandsSnapshotSession.sendAvailableCommandsUpdate,使 ACP 路径能注册 model-invocable 命令。
  • 提取 registerModelInvocableCommands 消除 handleSlashCommandgetAvailableCommands 之间的重复,同时修复禁用命令泄漏(provider 现在使用过滤后的 service)和过期信号 bug(每次执行使用全新 AbortController)。

handleSlashCommand 中的双 CommandService 方案(一个用于存在性检查,一个用于过滤后的执行+注册)是正确的取舍 — 用 allCommandService 做存在性回退,同时把禁用命令排除在注册的 provider 之外。无范围蔓延,无关改动。

进入代码审查 🔍

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Code Review

Independent proposal (before reading the diff):
To fix the ACP model-invocable command gap, I'd thread settings through getAvailableCommands so the ACP snapshot path can register the provider/executor on Config. The disabled-command leak (provider using the unfiltered service) and the expired-signal bug (reusing the snapshot's abort signal for the hook) are both real issues worth fixing in the same pass.

Comparison with the diff:
The PR matches and exceeds this proposal. The extracted registerModelInvocableCommands function eliminates duplication between handleSlashCommand and getAvailableCommands, fixes all three sub-issues in one pass, and the two-CommandService pattern in handleSlashCommand correctly separates existence-check from filtered registration. The fresh AbortController().signal per execution cleanly solves the expired-signal bug without adding complexity.

No critical blockers or AGENTS.md violations found. The code is focused, idiomatic, and follows project conventions.

Test Results

Unit Tests (worktree)

nonInteractiveCliCommands.test.ts: 29/29 passed ✅
Session.test.ts: 165/165 passed ✅

New tests cover all four facets of the fix:

  • registers model-invocable commands for ACP command snapshots — provider returns correct commands, executor expands prompts, hook fires with fresh signal
  • does not expose disabled model-invocable commands through SkillTool — disabled commands excluded from provider and executor returns null
  • does not partially register model-invocable commands without settings — early return when settings absent
  • Session.test.ts assertions updated to verify mockSettings is passed through to buildAvailableCommandsSnapshot

Static Checks

ESLint: 0 errors, 0 warnings on changed files ✅
Prettier: All matched files use Prettier code style! ✅

Real-Scenario Test (tmux, dev build)

runner@runnervm7b5n9:~/work/qwen-code/qwen-code/.qwen/worktrees/triage$ npm run dev -- -p 'hello world'
> @qwen-code/qwen-code@0.18.3 dev
> node scripts/dev.js -p hello world

DEV is set to true, but the React DevTools server is not running.
$ npx react-devtools

Hello! How can I help you today?

CLI starts cleanly and responds to prompts with the PR changes applied. Note: the ACP-specific bug (model-invocable commands not registered in ACP snapshot path) requires an ACP server for full E2E reproduction — not available in this environment. However, the unit tests comprehensively cover the registration, exclusion, signal, and no-settings paths, and the prior maintainer A/B verification (@wenshao's comment) confirms the fix against the real pipeline.

中文说明

代码审查

独立方案(读 diff 前):
要修复 ACP model-invocable 命令缺口,我会将 settings 透传到 getAvailableCommands,使 ACP 快照路径能在 Config 上注册 provider/executor。禁用命令泄漏(provider 使用了未过滤的 service)和过期信号 bug(复用快照的 abort signal 给 hook)都值得在同一轮一起修复。

与 diff 对比:
PR 达到并超出了这个方案。提取的 registerModelInvocableCommands 函数消除了 handleSlashCommandgetAvailableCommands 之间的重复,一次性修复了所有三个子问题,handleSlashCommand 中的双 CommandService 模式正确地将存在性检查与过滤后注册分离。每次执行使用全新的 AbortController().signal 干净地解决了过期信号 bug,没有增加复杂度。

无关键阻碍或 AGENTS.md 违规。 代码聚焦、符合惯例、遵循项目约定。

测试结果

单元测试(worktree)

nonInteractiveCliCommands.test.ts: 29/29 通过 ✅
Session.test.ts: 165/165 通过 ✅

新测试覆盖了修复的所有四个方面:

  • registers model-invocable commands for ACP command snapshots — provider 返回正确命令,executor 展开 prompt,hook 使用全新信号触发
  • does not expose disabled model-invocable commands through SkillTool — 禁用命令被排除,executor 返回 null
  • does not partially register model-invocable commands without settings — 无 settings 时提前返回
  • Session.test.ts 断言更新以验证 mockSettings 透传到 buildAvailableCommandsSnapshot

静态检查

ESLint: 改动文件 0 错误,0 警告 ✅
Prettier: 所有匹配文件符合 Prettier 格式! ✅

真实场景测试(tmux,dev 构建)

CLI 启动正常,带 PR 改动能正确响应 prompt。注意:ACP 特定 bug(ACP 快照路径未注册 model-invocable 命令)需要 ACP 服务器做完整 E2E 复现——当前环境不可用。但单元测试全面覆盖了注册、排除、信号和无 settings 路径,且之前维护者的 A/B 验证(@wenshao 的评论)已在真实管线上确认了修复效果。

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

This PR is clean and ready to merge.

Stepping back: it fixes a real gap (#5503) where ACP mode advertises commands to the model via the snapshot but never wires the provider/executor on Config, so SkillTool can't actually invoke them. The fix is minimal — thread settings through the existing call chain, extract the registration into a shared function, and fix two latent bugs (disabled-command leak, expired signal reuse) along the way.

The implementation matches what I'd propose independently. The two-CommandService pattern in handleSlashCommand is the right trade-off: slightly more work at startup for correct separation between existence-check and filtered registration. The fresh AbortController per execution is a clean one-line fix for the signal bug. No abstractions beyond what's needed, no scope creep.

194 unit tests pass, lint and format are clean, the dev CLI starts and responds normally. The new regression tests are well-constructed — running them against the base source confirms they'd catch the bug. Combined with @wenshao's prior A/B verification against the real pipeline, the evidence is solid.

Approving. ✅

中文说明

这个 PR 干净且可以合并。

退一步看:它修复了真实的缺口(#5503)——ACP 模式通过快照向模型 advertised 命令,但从未在 Config 上接线 provider/executor,导致 SkillTool 无法实际调用它们。修复最小化——将 settings 透传到现有调用链中,提取注册逻辑到共享函数,并顺带修复了两个潜在 bug(禁用命令泄漏、过期信号复用)。

实现与我独立提出的方案一致。handleSlashCommand 中的双 CommandService 模式是正确的取舍:启动时多一点点开销,换来存在性检查与过滤后注册的正确分离。每次执行全新的 AbortController 是信号 bug 的干净一行修复。没有不必要的抽象,没有范围蔓延。

194 个单元测试通过,lint 和格式检查干净,dev CLI 正常启动和响应。新增的回归测试构造良好——在 base 源码上运行确认它们能捕获 bug。加上 @wenshao 之前在真实管线上的 A/B 验证,证据充分。

批准合并 ✅

Qwen Code · qwen3.7-max

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, looks ready to ship. ✅

@wenshao
wenshao merged commit 7e66b17 into QwenLM:main Jun 20, 2026
43 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

category/cli Command line interface and interaction scope/commands Command implementation scope/mcp Model Context Protocol type/bug Something isn't working as expected

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(cli): ACP snapshots miss model-invocable command wiring

3 participants