fix(desktop): normalize source slug validation errors#5911
Conversation
|
@qwen-code /triage |
|
Thanks for the PR! Template looks good ✓ On direction: This is a natural follow-up to #5829 (path traversal fix). After the stricter slug guard landed, a few adjacent code paths still handled invalid/legacy slugs inconsistently — some threw generic errors, some used config slugs for filesystem lookups, some treated legacy dirs as hard errors. Normalizing these at the API boundary is the right call. Aligned with the security hardening direction. On approach: Scope is tight and focused — four specific code paths, each with a targeted fix and matching regression test. No drive-by refactors, no scope creep. The changes follow the existing skip-and-warn pattern from 中文说明感谢贡献! 模板完整 ✓ 方向:这是 #5829(路径穿越修复)的自然后续。更严格的 slug guard 落地后,相邻的几个代码路径对 invalid/legacy slug 的处理仍然不一致——有的抛泛化错误,有的用 config slug 做文件系统查找,有的把旧目录当硬错误。在 API 边界统一这些行为是正确的方向,与安全加固一致。 方案:范围紧凑、聚焦——四个具体代码路径,每个都有针对性修复和对应的回归测试。没有顺手重构,没有范围蔓延。改动完全复用了 — Qwen Code · qwen3.7-max |
Code ReviewNo critical blockers. The diff is clean and well-structured. config-validate.ts — Pre-validates source-test.ts — validators.ts — sources.ts (RPC delete) — Wraps types.ts — Adds Tests — 16 focused regression tests covering all four changed paths: validation fallback, source-test completeness with legacy slugs, all-source validation skip behavior, and RPC delete error classification. Tests are well-scoped and don't over-mock. Real-Scenario TestingThis PR modifies desktop package internals (source slug validation at API boundaries). There is no CLI-level observable behavior change — the affected paths are Bun is not available in this CI environment, so the desktop package tests ( Tmux real-scenario testing: N/A — no TUI output is affected by these changes. 中文说明代码审查无关键阻塞项。Diff 干净且结构良好。 config-validate.ts — 在调用 source-test.ts — validators.ts — sources.ts(RPC delete) — 用 try/catch 包裹 types.ts — 向 测试 — 16 个聚焦回归测试覆盖所有四个修改路径:validation fallback、legacy slug 下的 source-test completeness、全量 validation 跳过行为、RPC delete 错误分类。测试范围合理,没有过度 mock。 真实场景测试本 PR 修改桌面端内部包(API 边界的 source slug 验证)。没有 CLI 层面可观察的行为变化——受影响路径是 当前 CI 环境没有 Bun,无法独立重跑桌面端测试( Tmux 真实场景测试:N/A — 这些修改不影响 TUI 输出。 — Qwen Code · qwen3.7-max |
|
This PR does exactly what it says: takes the strict slug guard from #5829 and makes every adjacent code path behave consistently at its own API boundary. Validation tools return validation results, full-validation skips legacy dirs with warnings, and RPC delete surfaces bad input as The diff matches what I would have proposed independently. The test coverage is focused and adequate. The only minor caveat is that I couldn't re-run the bun tests in this environment, but the changes are straightforward enough that the test descriptions and code review give me confidence. LGTM, looks ready to ship. ✅ 中文说明本 PR 完全做到了它所描述的事情:把 #5829 的严格 slug guard 扩展到每个相邻代码路径,让它们在各自的 API 边界行为一致。验证工具返回验证结果,全量验证对旧目录 warning + skip,RPC delete 把坏输入标记为 Diff 与我独立提出的方案一致。测试覆盖聚焦且充分。唯一的小限制是当前环境无法重跑 bun 测试,但改动足够直观,测试描述和代码审查给了我信心。 LGTM,可以合并。✅ — Qwen Code · qwen3.7-max |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
|
@qwen-code /resolve |
|
Qwen Code resolved the merge conflicts and pushed the branch update. Merge Conflict Resolution SummaryPR
Conflicted File
Both the PR branch and
ResolutionCombined both test suites into a single file with a shared Key decisions:
No other files were modified — only the one conflicted file was touched. Commit
|
|
@wenshao quick update after the merge-conflict resolution on this PR. I re-checked the current head Results:
I also reran |
|
@qwen-code /triage |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
wenshao
left a comment
There was a problem hiding this comment.
[Suggestion] The fallback "validate all sources" path in config-validate.ts (the else branch at ~line 117, when ctx.validators is unavailable) iterates source directories and calls validateJsonFileHasFields without the assertValidSourceSlug pre-filter that was added to validateAllSources in validators.ts. Legacy directories like legacy-source- would produce spurious field-validation errors in this fallback path instead of the clean skip-with-warning behavior the primary path now provides. Consider adding a matching slug-validation guard to the loop.
— qwen3.7-max via Qwen Code /review
| try { | ||
| deleteSource(workspace.rootPath, sourceSlug) | ||
| } catch (error) { | ||
| if (error instanceof Error && error.message.startsWith('Invalid source slug')) { |
There was a problem hiding this comment.
[Suggestion] This inline check duplicates the existing isInvalidSourceSlugError() helper defined at line 9 of this file, and the two matching strings are inconsistent: the helper uses 'Invalid source slug:' (with colon) while this line uses 'Invalid source slug' (without colon). Use the helper for consistency:
| if (error instanceof Error && error.message.startsWith('Invalid source slug')) { | |
| } catch (error) { | |
| if (isInvalidSourceSlugError(error)) { | |
| ;(error as Error & { code?: string }).code = 'INVALID_ARGUMENT' | |
| } | |
| throw error | |
| } |
— qwen3.7-max via Qwen Code /review
| return successResponse(formatValidationResult(result)); | ||
| try { | ||
| const sourcePath = getSourceConfigPath(ctx.workspacePath, sourceSlug); | ||
| const result = validateJsonFileHasFields(sourcePath, ['slug', 'name', 'type']); |
There was a problem hiding this comment.
[Suggestion] This try/catch wraps both getSourceConfigPath (which throws on invalid slug via assertValidSourceSlug) and validateJsonFileHasFields (which returns a ValidationResult and doesn't throw today). If validateJsonFileHasFields ever throws in the future (e.g., due to a filesystem error), it would be misattributed as a slug validation failure. Consider narrowing the catch to only the slug validation call, or validating the slug explicitly before the path call.
— qwen3.7-max via Qwen Code /review
| return { handlers, warnings, errors } | ||
| } | ||
|
|
||
| describe('registerSourcesHandlers DELETE', () => { |
There was a problem hiding this comment.
[Suggestion] This describe block only tests the "Invalid source slug" error path. No test verifies that a different error from deleteSource (e.g., a filesystem error like ENOENT) is rethrown without the INVALID_ARGUMENT code being stamped. If someone accidentally removed the if (isInvalidSourceSlugError(error)) guard, no test would catch the regression. Consider adding a test that mocks deleteSource to throw a non-slug error and asserts the rethrown error has no code property.
— qwen3.7-max via Qwen Code /review
| expect(text).not.toContain('available on your next message'); | ||
| }); | ||
|
|
||
| it('uses the requested source slug for guide checks when config slug is legacy-formatted', async () => { |
There was a problem hiding this comment.
[Suggestion] writeSource creates guide.md in the source directory, so this test only exercises the success branch ('guide.md exists') of the completeness check. The warning branch ('⚠ No guide.md file') — which is the exact code path the PR changes (using sourceSlug instead of source.slug for the guide path lookup at source-test.ts:317) — is never tested. Consider adding a test that omits guide.md and asserts the warning references the requested slug, not the config's legacy slug.
— qwen3.7-max via Qwen Code /review
✅ Local real-handler verification — all four slug paths behave as describedI drove the actual desktop handlers (not the test files) against real on-disk fixtures with bun 1.3.14 — the same runtime CI/desktop uses — and confirmed each fix with a mutation A/B: run on the PR tree, then
Verdict: PASS — 4/4 behaviors verified, each with a decisive before/after.
Behaviors verified (real handler driven; revert-to-base flips each)
Why each is faithful (not a unit-test rerun)
Notes for the reviewer
🇨🇳 中文版本✅ 本地真实 handler 验证 —— 四条 slug 路径行为都与描述一致我用 bun 1.3.14(桌面端真实运行时)直接驱动真实的桌面 handler(不是测试文件),对接真实磁盘 fixture,并用变异 A/B 确认每个修复:先在 PR 树跑,再
结论:PASS —— 4/4 行为已验证,每条都有决定性的 before/after。
已验证行为(真实 handler 驱动;revert 到 base 即翻转)
每条为何是"真实驱动"而非"重跑单测"
给 reviewer 的说明
|
|
@wenshao thanks for the follow-up review. I updated this PR in
Validation completed:
I also had a separate agent review the updated diff against your comments; it found the requested behavior and test coverage aligned with the review expectations. GitHub's ubuntu CI leg is still running at the moment; the PR is otherwise blocked on review state, not on the local Windows/Linux validation above. |
🔄 Re-verification at head
|
| Change | Type | Verified behavior |
|---|---|---|
config_validate (no sourceSlug) now skips an invalid-slug source dir with a warning |
🆕 new behavior | A/B vs prior head: AFTER → ✓ Validation passed + sources/legacy-source-/config.json: Source 'legacy-source-' has invalid slug format, skipping source validation. BEFORE (42f794e7f) → ✗ Validation failed + legacy-source-/{slug,name,type}: Missing required field. |
config_validate (with sourceSlug) narrows the try/catch to just assertValidSourceSlug |
♻️ refactor | Behavior-preserving: the invalid-slug result is byte-identical to the prior head (✗ Validation failed … sourceSlug: Invalid source slug: "../sessions"). validateJsonFileHasFields returns an invalid result rather than throwing, so narrowing the catch changes no observable output for current inputs — it just stops a future real validation error from being mislabeled as a slug error. |
delete RPC: inline startsWith('Invalid source slug') → shared isInvalidSourceSlugError(error) helper |
♻️ refactor | Behavior-preserving: ../sessions still throws with code = 'INVALID_ARGUMENT'. The helper matches 'Invalid source slug:' (with colon) and assertValidSourceSlug always emits the colon form, so it's equivalent — and it removes the inconsistency where the helper was defined but the delete handler used an ad-hoc inline check. |
Re-confirmed (unchanged) on the new head
All four behaviors from the prior verification still hold — driven through the real handlers:
- ✅
config_validate({sourceSlug:'../sessions'})→ structuredValidation failedresult, no throw. - ✅
source_test({sourceSlug:'my-source'})with legacy config slugmy--source→guide.md exists,Validation passed(requested slug used for the guide path). - ✅
validateAllSources(shared) oversources/legacy-source-/→valid:true+ skip warning. (file untouched by this commit; re-ran to confirm.) - ✅ delete RPC
../sessions→INVALID_ARGUMENT; non-slug failure (workspace-not-found) → genericHANDLER_ERROR; valid-but-missing slug → idempotent no-op.
Notes
- The new validate-all-fallback skip now matches the shared
validateAllSourcesandvalidateAllPermissionsbehavior — the same bad slug is treated consistently across both the validator path and the session-tool fallback path. That consistency was the stated goal of the PR, and it now holds on both entry points. BLOCKED=REVIEW_REQUIRED(awaiting a maintainer approval), not a CI failure. macOS (Darwin, Node 22, bun 1.3.14). Supersedes my prior comment at42f794e7f.
🇨🇳 中文版本
🔄 在 head 848ebe22b(处理 review 反馈的提交)上重新验证 —— 仍然 ✅ PASS
PR 自我上次验证(head 42f794e7f)后又有新提交 848ebe22b「address source slug review feedback」。我在新 head 上重跑了同一套"真实 handler + 变异 A/B"工具,并专门隔离本次提交的 delta(A/B 对照前一个 head 42f794e7f,而非仅对 merge base)。
结论:PASS —— 原有四条行为保持不变,新增一条行为已验证,两处重构行为等价。
- 验证的 head:
848ebe22b…(与当前 PR head 一致) - 构建:
session-tools-core/shared/server-core三个包bun run tsc --noEmit全部 exit 0 - 测试: 4 个改动测试文件
bun test→ 20 pass, 0 fail(此前 17;本提交加了 3 个)。CI 仍不跑这些(desktop 在 root workspaces 之外)。
本提交改了什么,我观察到什么
| 改动 | 类型 | 验证到的行为 |
|---|---|---|
config_validate(不带 sourceSlug)现在对无效 slug 目录 warning + skip |
🆕 新行为 | 对照前一个 head 的 A/B: AFTER → ✓ Validation passed + sources/legacy-source-/config.json: Source 'legacy-source-' has invalid slug format, skipping source validation。BEFORE(42f794e7f)→ ✗ Validation failed + legacy-source-/{slug,name,type}: Missing required field。 |
config_validate(带 sourceSlug)把 try/catch 收窄到只包 assertValidSourceSlug |
♻️ 重构 | 行为等价: 无效 slug 的结果与前一个 head 逐字节相同(✗ Validation failed … sourceSlug: Invalid source slug: "../sessions")。validateJsonFileHasFields 是返回无效结果而非抛异常,所以收窄 catch 对当前输入不改变任何可观察输出 —— 只是避免将来真实验证错误被误标成 slug 错误。 |
删除 RPC:内联 startsWith('Invalid source slug') → 共享 isInvalidSourceSlugError(error) helper |
♻️ 重构 | 行为等价: ../sessions 仍抛出且 code = 'INVALID_ARGUMENT'。helper 匹配 'Invalid source slug:'(带冒号),而 assertValidSourceSlug 总是带冒号 —— 等价,并消除了"helper 已定义但删除 handler 用临时内联检查"的不一致。 |
在新 head 上重新确认(未变)
上次验证的四条行为依然成立 —— 都通过真实 handler 驱动:
- ✅
config_validate({sourceSlug:'../sessions'})→ 结构化Validation failed,不抛。 - ✅
source_test({sourceSlug:'my-source'})配 legacy slugmy--source→guide.md exists、Validation passed(guide 路径用请求 slug)。 - ✅
validateAllSources(shared)对sources/legacy-source-/→valid:true+ skip 警告。(本提交未动该文件;重跑确认。) - ✅ 删除 RPC
../sessions→INVALID_ARGUMENT;非 slug 失败(workspace 未找到)→ 泛化HANDLER_ERROR;合法但不存在的 slug → 幂等无操作。
说明
- 新的 validate-all fallback skip 现在与共享的
validateAllSources、validateAllPermissions行为一致 —— 同一个坏 slug 在 validator 路径和 session-tool fallback 路径上被一致处理。这正是本 PR 的目标,现在两个入口都成立。 BLOCKED=REVIEW_REQUIRED(等维护者 approve),非 CI 失败。环境 macOS(Darwin, Node 22, bun 1.3.14)。本评论取代我在42f794e7f的上一条。
doudouOUC
left a comment
There was a problem hiding this comment.
LGTM. The error normalization across the four entry points is clean and consistent. The assertValidSourceSlug catch in config-validate.ts is correctly scoped to only the slug validation call, and the validateAllSources fallback properly skips legacy directories with warnings. Tests cover the key scenarios (invalid slug rejection, non-slug error passthrough, legacy directory skip, and legacy-slug guide resolution).
— qwen3.7-max via Qwen Code /review
|
@qwen-code /triage |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
This PR keeps the stricter desktop source-slug path-traversal guard intact and normalizes the remaining invalid/legacy-slug paths so callers get predictable validation output instead of uncaught generic failures.
What this PR does
config_validatereturn a structured validation result for invalid source slug input such as{ target: "sources", sourceSlug: "../sessions" }, instead of lettinggetSourceConfigPath()throw through the fallback handler.source_testuse the requested source slug forguide.mdlookup, so a valid directory likesources/my-source/still checks the right guide path even ifconfig.jsoncontains a legacy-formatted slug such asmy--source.validateAllSourcesskip legacy invalid source directories such assources/legacy-source-/config.jsonwith a warning, matching the existingvalidateAllPermissionsbehavior.../sessionsto the RPCINVALID_ARGUMENTcode instead of the generic handler error code.Why it's needed
This is a follow-up to #5908 and #5829. #5829 fixed the core source deletion path traversal issue by rejecting path-like slugs before they can be resolved as filesystem paths. In practical terms, inputs such as
../sessionsor..\\sessionsshould never be allowed to turn a source path intosources/../sessionsor another neighboring workspace directory.After that stricter guard, a few unchanged desktop paths still handled invalid or legacy slugs inconsistently. The fallback
config_validatepath could throw instead of formatting a validation result.source_testcould load a source from a valid directory, then use theslugfield fromconfig.jsonfor a later guide-path lookup.validateAllSourcestreated legacy invalid-slug directories as hard validation errors, whilevalidateAllPermissionsalready skipped the same kind of directory with a warning. Source deletion correctly rejected invalid slugs, but the RPC boundary surfaced that caller mistake as a generic handler failure.That made the guard technically correct but operationally noisy: users and maintainers would see different behavior depending on which validation or RPC entry point touched the same bad slug. This PR keeps the strict validation in place and makes each affected path behave according to its API boundary: validation tools return validation results, full validation skips legacy invalid folders with warnings, and RPC delete reports bad caller input as
INVALID_ARGUMENT.Possible call chain / impact
The affected paths are desktop source validation, source testing, all-source validation, and source deletion RPC handling:
Before this PR, an invalid slug such as
../sessionscould throw through the fallback handler and be reported as a generic tool failure. This PR keeps the strict slug check but returns a formatted validation result for that validation entry point.Before this PR, the final guide-path lookup used
source.slugfromconfig.json. A valid folder such assources/my-source/with a legacy config slug likemy--sourcecould pass the earlier load path but fail later when the stricter path helper rejected the config slug. This PR uses the already requested source slug for filesystem lookup.Legacy invalid source directories are now skipped with a warning during all-source validation, matching the existing
validateAllPermissionsbehavior. Direct validation of an explicitly requested invalid slug still reports an error.Invalid delete slugs such as
../sessionsare still rejected before deletion. The difference is that the RPC response now classifies that caller-input failure asINVALID_ARGUMENTinstead of the generic handler error code.This PR only changes invalid/legacy source slug handling at these API boundaries. It does not relax the source slug regex, change valid source deletion behavior, change source creation, alter source config parsing, change guide content parsing, modify connection tests, or cover the broader hardening/diagnostics work tracked in #5909.
Reviewer Test Plan
How to verify
Confirm that:
config_validatewithsourceSlug: "../sessions"returnsValidation failedwith asourceSlugvalidation error.source_testforsourceSlug: "my-source"still checkssources/my-source/guide.mdwhen the source config contains a legacy slug likemy--source.validateAllSourcesskipssources/legacy-source-/config.jsonwith an invalid-slug warning.../sessionsasINVALID_ARGUMENT.Commands run:
cd packages/desktop && bun test packages/session-tools-core/src/handlers/config-validate.test.ts packages/session-tools-core/src/handlers/source-test.test.ts packages/shared/src/config/__tests__/source-slug-validation.test.ts packages/server-core/src/handlers/rpc/sources.test.ts-> 16 pass, 0 failcd packages/desktop/packages/session-tools-core && bun run tsc --noEmit-> passcd packages/desktop/packages/shared && bun run tsc --noEmit-> passcd packages/desktop/packages/server-core && bun run tsc --noEmit-> passUbuntu 24.04.2 LTS,Linux 6.8.0-53-generic,Node v22.23.1,Bun 1.3.14):cd packages/desktop && ELECTRON_SKIP_BINARY_DOWNLOAD=1 bun install-> passcd packages/desktop && bun test packages/session-tools-core/src/handlers/config-validate.test.ts packages/session-tools-core/src/handlers/source-test.test.ts packages/shared/src/config/__tests__/source-slug-validation.test.ts packages/server-core/src/handlers/rpc/sources.test.ts-> 16 pass, 0 failcd packages/desktop/packages/session-tools-core && bun run tsc --noEmit-> passcd packages/desktop/packages/shared && bun run tsc --noEmit-> passcd packages/desktop/packages/server-core && bun run tsc --noEmit-> passcd packages/desktop && bun run typecheck:all-> fails in pre-existing Electron/UI type errors unrelated to this PR (apps/electron/src/main/auto-update.ts,apps/electron/src/main/handlers/__tests__/settings-default-thinking.test.ts,apps/electron/src/renderer/lib/__tests__/*,apps/electron/src/renderer/pages/settings/MemorySettingsPage.tsx); full desktop preflight is therefore not claimed as passing in this checkoutEvidence (Before & After)
No UI evidence; this is non-UI behavior covered by focused regression tests.
Tested on
Environment (optional)
Windows PowerShell, Bun 1.3.12, Node v22.22.3. JD-Cloud Ubuntu 24.04.2 LTS (
Linux 6.8.0-53-generic), Bun 1.3.14, Node v22.23.1.Risk & Scope
INVALID_ARGUMENTprotocol error code for invalid slug input; other handler failures continue to use the existing generic error behavior.Linked Issues
Closes #5908
中文说明
本 PR 保留桌面端更严格的 source slug 路径穿越防护,同时统一剩余 invalid / legacy slug 路径的行为,让调用方拿到可预测的验证输出或输入错误,而不是未捕获的泛化 handler 失败。
What this PR does
config_validate在收到{ target: "sources", sourceSlug: "../sessions" }这类无效 source slug 输入时返回结构化验证结果,而不是让getSourceConfigPath()的异常穿透 fallback handler。source_test使用请求中的 source slug 查找guide.md,因此即使config.json中仍有my--source这类旧格式 slug,像sources/my-source/这样的有效目录仍会检查正确的 guide 路径。validateAllSources对sources/legacy-source-/config.json这类旧版无效 source 目录发出 warning 并跳过,与已有的validateAllPermissions行为保持一致。../sessions这类无效 slug 返回INVALID_ARGUMENT错误码,而不是泛化的 handler error code。Why it's needed
这是 #5908 和 #5829 的后续修复。#5829 已经通过在 source slug 被解析成文件系统路径前拒绝 path-like slug,修复了 source 删除路径的核心 traversal 风险。也就是说,
../sessions或..\\sessions这类输入不应被允许把 source 路径解析成sources/../sessions或其他相邻 workspace 目录。在这个更严格的 guard 之后,少数未改动的桌面端路径仍然对 invalid / legacy slug 表现不一致。fallback
config_validate路径可能直接抛异常,而不是格式化验证结果。source_test可能先从有效目录加载 source,然后在后续 guide 路径查找时使用config.json里的slug字段。validateAllSources会把旧版无效 slug 目录当作硬错误,但validateAllPermissions已经会对同类目录 warning + skip。source deletion 本身会正确拒绝无效 slug,但 RPC 边界会把这个调用方输入错误暴露成泛化 handler failure。这会让 guard 在安全上正确、但在操作上嘈杂:同一个坏 slug 会因为经过不同验证或 RPC 入口而表现不同。本 PR 保留严格验证,并让每个受影响路径按自己的 API 边界返回:验证工具返回验证结果,全量验证对旧版无效目录 warning + skip,RPC delete 把调用方坏输入报告为
INVALID_ARGUMENT。Possible call chain / impact
受影响路径是桌面端 source validation、source testing、all-source validation 以及 source deletion RPC handling:
在本 PR 之前,
../sessions这类无效 slug 可能从 fallback handler 直接抛出,并表现为泛化 tool failure。本 PR 保留严格 slug 检查,但在 validation 入口返回格式化验证结果。在本 PR 之前,最后的 guide-path lookup 使用的是
config.json中的source.slug。如果有效目录是sources/my-source/,但 config 里仍有my--source这类旧格式 slug,前面的加载路径可以通过,后续更严格的 path helper 却会拒绝 config slug。本 PR 改为使用请求中的 source slug 做文件系统路径查找。旧版无效 source 目录现在会在 all-source validation 中 warning + skip,与已有的
validateAllPermissions行为保持一致。直接验证一个显式传入的无效 slug 仍然会返回 error。../sessions这类无效 delete slug 仍然会在删除前被拒绝。区别是 RPC response 现在会把这个调用方输入错误标记为INVALID_ARGUMENT,而不是泛化 handler error code。本 PR 只改变这些 API 边界上的 invalid / legacy source slug 处理。它不会放宽 source slug regex,不会改变有效 source 的删除行为,不会改变 source 创建,不会改变 source config parsing,不会改变 guide 内容解析,不会修改 connection tests,也不覆盖 #5909 中跟踪的更广泛 hardening / diagnostics 工作。
Reviewer Test Plan
How to verify
确认:
config_validate携带sourceSlug: "../sessions"时返回包含sourceSlug错误的Validation failed。source_test携带sourceSlug: "my-source"时,即使 source config 里包含my--source这样的旧格式 slug,也仍然检查sources/my-source/guide.md。validateAllSources对sources/legacy-source-/config.json发出 invalid-slug warning 并跳过。../sessions这类无效 slug 返回INVALID_ARGUMENT。已运行命令:
cd packages/desktop && bun test packages/session-tools-core/src/handlers/config-validate.test.ts packages/session-tools-core/src/handlers/source-test.test.ts packages/shared/src/config/__tests__/source-slug-validation.test.ts packages/server-core/src/handlers/rpc/sources.test.ts-> 16 pass, 0 failcd packages/desktop/packages/session-tools-core && bun run tsc --noEmit-> passcd packages/desktop/packages/shared && bun run tsc --noEmit-> passcd packages/desktop/packages/server-core && bun run tsc --noEmit-> passUbuntu 24.04.2 LTS、Linux 6.8.0-53-generic、Node v22.23.1、Bun 1.3.14):cd packages/desktop && ELECTRON_SKIP_BINARY_DOWNLOAD=1 bun install-> passcd packages/desktop && bun test packages/session-tools-core/src/handlers/config-validate.test.ts packages/session-tools-core/src/handlers/source-test.test.ts packages/shared/src/config/__tests__/source-slug-validation.test.ts packages/server-core/src/handlers/rpc/sources.test.ts-> 16 pass, 0 failcd packages/desktop/packages/session-tools-core && bun run tsc --noEmit-> passcd packages/desktop/packages/shared && bun run tsc --noEmit-> passcd packages/desktop/packages/server-core && bun run tsc --noEmit-> passcd packages/desktop && bun run typecheck:all-> 因既有 Electron/UI 类型错误失败,错误位置与本 PR 无关:apps/electron/src/main/auto-update.ts、apps/electron/src/main/handlers/__tests__/settings-default-thinking.test.ts、apps/electron/src/renderer/lib/__tests__/*、apps/electron/src/renderer/pages/settings/MemorySettingsPage.tsx;因此本 checkout 不声称 full desktop preflight 已通过Evidence (Before & After)
无 UI 证据;这是非 UI 行为,已由聚焦回归测试覆盖。
Tested on
Environment (optional)
Windows PowerShell, Bun 1.3.12, Node v22.22.3. JD-Cloud Ubuntu 24.04.2 LTS(
Linux 6.8.0-53-generic)、Bun 1.3.14、Node v22.23.1。Risk & Scope
INVALID_ARGUMENTprotocol error code;其他 handler 失败仍保持原有泛化错误行为。Linked Issues
Closes #5908