Conversation
- Move strip_unc_prefix, build_global_scope, collect_context to sdk/src/services/common.rs - Restructure logger into sdk/src/infra/logger/ module (core, diagnostic, formatter, sink) - Rename command_diagnostics.rs -> command_diagnostics_service.rs, prompts.rs -> prompt_service.rs - Add OutputContext, CleanupSnapshot domain types - Extract git_fs module from git_discovery - Pass &Logger to collect_context and build_output_files - Fix PoisonError cascade in local tests: use unwrap_or_else for Mutex - Add cross-process file lock to prevent test binary interference - Add clean-before-install in 3 tests that lacked it - Fix dry_run encoding: use file.encoding.clone() instead of None - Remove unused mut, functions, fields (compiler warnings) - Add logging test files for observability coverage
…ression tests - Add entry.name to error messages in subagent, rule, command collectors/builders - Strengthen unit test assertions to verify file paths in error output - Copy missing .src.mdx to .mdx compiled prompts in aindex - Add trae smoke test file
1. Lock down embedded TS runtime: env allowlist, hide untrusted env by default 2. Path protection: install-time protected-path guard for file writes 3. Re-enable Clippy in xtask lint and CI 4. Replace unwrap/expect in GUI/MCP startup paths with proper error handling 5. Narrow tnmsd public exports with pub(crate) where possible 6. Add rustdoc to exported SDK types 7. Strengthen tests: malicious paths, env isolation, install protection 37 files changed, +515/-300
…link text Closes #195. Pre-fix the link-text simplification gate was \`t.value.contains('/') && t.value.contains('.')\`. That fired on strings like \`v1.0/release\` (has \`/\`, has \`.\`) and rewrote them to \`release\` — losing the version segment that was the actual point of the link text. Tighten the heuristic: require the *basename* (the segment after the final \`/\`) to itself contain a \`.\`. Now: - \`docs/guide/intro.md\` → basename \`intro.md\` (has \`.\`) → simplified to \`intro.md\`. (Unchanged.) - \`v1.0/release\` → basename \`release\` (no \`.\`) → left alone. - \`a/b/c\` → basename \`c\` (no \`.\`, no \`/\`-after-last-/) → left alone (was already left alone). Existing transformer tests still pass (12/12 in \`infra::md_compiler::transformer::tests\`). (cherry picked from commit 5323d46)
…ts arg Closes #208. \`collect_workspace_reserved_rules\` took a third parameter \`_include_reserved_workspace_content_roots: bool\` whose underscore prefix advertised the lie: the body never read it, both call sites just passed a literal \`true\`, and the only test for it (\`include_reserved_workspace_content_roots_is_inert\`) asserted that toggling the value didn't change the output. Dead surface area. Drop the parameter from the signature, the production call site (\`create_guard\`), and the test that probed it. The replacement test would have to assert "the function still returns rules", which is already covered by the 29 other \`policy::cleanup\` tests that exercise the guard end-to-end. \`cargo test --lib policy::cleanup\` is green at 30/30. (cherry picked from commit 71ec4c7)
…mpt_artifact Closes #198. \`assert_no_residual_module_syntax\` was identically duplicated in \`skill.rs\` and \`project_prompt.rs\`. Both bodies walked the same \`code_fence_pattern\` / \`residual_patterns\` regex setup and built the same error message — any bug fix had to be applied in two places. Hoist the function into \`prompt_artifact.rs\` (which both consumers already import from for \`read_prompt_artifact\`) and re-export it. Drop both copies; \`use ::{assert_no_residual_module_syntax, read_prompt_artifact}\` covers the call sites. Test coverage moves with the helper — five new tests in \`prompt_artifact::tests\` lock in the contract: - clean markdown passes - \`export default\` is rejected with file:line in the message - \`import\` is rejected with file:line - fenced code (\`\`\`js / \`\`\`) examples are skipped (legitimately quoted JS, not residual module syntax) - tilde fences (\`~~~ts\`) are also skipped `cargo test --lib repositories` is green at 50/50 (45 prior + 5 new prompt_artifact tests). (cherry picked from commit c66cdd7)
…_conflict Closes #199. \`detect_project_name_conflicts\` was near-identically implemented in both \`readme.rs\` (lines 33-81) and \`aindex_resolvers.rs\` (lines 29-77). The only meaningful difference between the two was the error-message prefix — \`"Readme project series name conflict:"\` vs \`"Aindex project series name conflict:"\`. Hoist the body to a new \`repositories::series_conflict\` module and replace both copies with thin shims that pass their respective prefix. The new function is generic over \`AsRef<str>\` so callers can hand it either \`Vec<&str>\` or \`Vec<String>\` without an extra clone. Module surface: - \`detect_project_name_conflicts(aindex_dir, series_names, error_prefix)\` walks every immediate subdirectory of each \`aindex_dir/<series>\`, groups the basenames by which series they appeared in, and returns \`Err(format!("{error_prefix}: {sorted_names_csv}"))\` if any name appeared in more than one series. Identical observable behaviour to the two former bodies. Both \`readme.rs\` and \`aindex_resolvers.rs\` lose the unused \`use std::collections::HashMap;\` import that came with the duplicated body. Tests in the new module pin the contract — five cases: - returns Ok when no overlap (zh:projA, en:projB) - detects a single shared name across two series - sorts multiple conflicts alphabetically before joining - ignores files at the series root (e.g. \`zh/notes.md\` is not a project) - missing series dirs are skipped, not treated as conflicts \`cargo test --lib repositories\` is green at 55/55 (50 prior + 5 new series_conflict tests). (cherry picked from commit f297bb9)
Bumps the cargo-workspace group with 4 updates: [clap](https://github.com/clap-rs/clap), [deno_core](https://github.com/denoland/deno), [tokio](https://github.com/tokio-rs/tokio) and [tar](https://github.com/alexcrichton/tar-rs). Updates `clap` from 4.6.0 to 4.6.1 - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](clap-rs/clap@clap_complete-v4.6.0...clap_complete-v4.6.1) Updates `deno_core` from 0.398.0 to 0.399.0 - [Release notes](https://github.com/denoland/deno/releases) - [Changelog](https://github.com/denoland/deno/blob/main/Releases.md) - [Commits](https://github.com/denoland/deno/commits) Updates `tokio` from 1.49.0 to 1.50.0 - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](tokio-rs/tokio@tokio-1.49.0...tokio-1.50.0) Updates `tar` from 0.4.44 to 0.4.45 - [Commits](alexcrichton/tar-rs@0.4.44...0.4.45) --- updated-dependencies: - dependency-name: clap dependency-version: 4.6.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-workspace - dependency-name: deno_core dependency-version: 0.399.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-workspace - dependency-name: tokio dependency-version: 1.50.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-workspace - dependency-name: tar dependency-version: 0.4.45 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-workspace ... Signed-off-by: dependabot[bot] <support@github.com> (cherry picked from commit 55426f0)
Closes #189. `send_output` cloned the formatted string for the channel send and kept the original around only for the rare sink-thread-dead fallback. On the hot path (sink alive), every `write_event` / `write_span_*` paid a `String::clone` for nothing. Move the `String` straight into the channel. `mpsc::SendError` already hands the unsent value back on the disconnect path, so we can pull it out via `if let Err(SendError(OutputCommand::Write { output, .. }))` and borrow it directly into `write_direct`. No allocation on the happy path; the cold path is unchanged. `cargo build --manifest-path sdk/Cargo.toml` clean. The 16 logger unit tests pass, including `test_thread_safety`. `cargo clippy --lib` shows no new warnings against `sink.rs` (the existing warnings on other modules are unchanged).
Closes #190. `read_flat_files` allocated a `HashSet<String>` and threaded it as `&mut seen` through `scan_directory` recursion just to call `seen.insert(full_name.clone())` once per new entry. The set was never read for dedup — `entries.iter_mut().find(|e| e.name == full_name)` is the actual existence check on the line above (#191 tracks the O(n²) → HashMap follow-up; this PR is just the dead write). Removing the parameter: - Deletes a per-call `String::clone` (set insertion took ownership of a clone of the name we already used to construct the entry). - Drops the `HashSet` allocation on every call to `read_flat_files`. - Removes the `use std::collections::HashSet` import. - Simplifies `scan_directory`'s signature (4 args → 3). `cargo build` + `cargo test --lib repositories` clean (45/45 repository tests pass). `cargo clippy --lib` shows no new warnings on `localized_reader.rs`.
Closes #192. `remove_blocking_file` checked `path.exists()` and then called `symlink_metadata(path)` separately. Between those two syscalls another process could create, replace, or delete the entry — the classic TOCTOU shape. Practically, an entry that disappears between the two stats produces a `symlink_metadata` `NotFound` error that gets bubbled to the caller as `Err(...)`, when the previous `exists()` already reported it absent (we'd want `Ok(false)`). Drop the redundant `exists()` and treat `symlink_metadata`'s `NotFound` directly as the "nothing to remove" case. One stat, race-free. Test: new `remove_blocking_file_returns_false_for_missing_path` covers the path that `exists()` previously short-circuited; the two existing tests (`remove_blocking_file_deletes_file` / `_skips_directory`) still pass. (The two `finds_blocking_file_in_directory_path` / `resolve_blocking_for_file_target` test failures on macOS are pre-existing `/var` symlink-resolution issues, unrelated to this patch.)
Closes #200. `BatchedGlobPlanner::execute()` walked the cleanup roots with `WalkDir` and used `let Ok(entry) = entry else { continue; }` to discard any iteration errors. Permission-denied entries, broken symlinks, and races where a tree got partially deleted mid-walk were skipped without a single trace, so a cleanup running under insufficient privileges (or against a half-removed shadow tree) would quietly miss files and the operator had no way to correlate the missed delete with the underlying syscall failure. Replace the silent continue with a `match`: on `Err` emit a `debug` log via the existing structured logger with the offending path (when `WalkDir` records it) and the `io::Error` message, then fall through to `continue` so behaviour is unchanged for the happy path. Operators tailing the cleanup logs now see exactly which entries were skipped and why; tests' `walked_entries` accounting is unaffected since the increment still only fires on `Ok(entry)`. `cargo test --lib policy::cleanup` is green (31/31).
Closes #209. `topological_sort(input_json)` previously rolled JSON parse failures into `DependencyResolverError::MissingDependency` with `node_name: "invalid input: …"` and an empty `missing_dependency`. Downstream consumers matching on the serialised `kind` field — the discriminator declared by `#[serde(tag = "kind", rename_all = "camelCase")]` — would treat parse failures as graph problems instead of input-shape problems. Add an `InvalidInput { message: String }` variant and route the serde error there. The `kind` payload now reads `invalidInput`, which the JS-side wrapper (and any future consumer) can branch on cleanly without string-sniffing the `node_name`. The two existing variants and their behaviour are unchanged. Tests in `dependency_resolver.rs` gain `topological_sort_maps_invalid_json_to_invalid_input` (asserts the new variant + `kind: "invalidInput"` payload) and `topological_sort_handles_well_formed_input` (sanity that the happy path still produces a sorted list). 13/13 module tests pass.
Closes #188. `write_config` did `let _ = fs::create_dir_all(parent)` and discarded the error. If `mkdir -p` failed (perms, EROFS, ENOSPC), the subsequent `fs::write(path, …)` would fail too — but with a secondary "No such file or directory" error that didn't point at the actual cause. Operators saw `CONFIG_WRITE_FAILED` and assumed the destination was unwritable, when really the parent never existed because `create_dir_all` had been silently swallowed. Bind the result and emit a `CONFIG_PARENT_DIR_CREATE_FAILED` diagnostic on `Err`, then `return` so we don't pile a confusing `CONFIG_WRITE_FAILED` on top. Operators now see the real failing step with the parent path + io::Error message, and the suggestion points at "parent path is writable / not on read-only or full filesystem" rather than the generic destination check. The serialization and write paths are unchanged. Behaviour on the happy path (parent exists, mkdir succeeds, write succeeds) is identical. `cargo build --manifest-path sdk/Cargo.toml` clean. `cargo test --lib domain::config` is green (24/24).
…ome / match Closes #196. Closes #197. Two adjacent unwrap-anti-patterns in `enhance_workspace_projects_with_aindex`: - L301-302: `if project.project_type.is_some() { vec![project.project_type.clone().unwrap()] }` → `match &project.project_type { Some(ptype) => vec![ptype.clone()], None => … }` Removes the redundant `is_some()` check, drops the `unwrap()`, and clones only the borrow we actually need (#196). - L307-319: `let matching_series = …find(…); if matching_series.is_none() { continue }; let series_name = matching_series.unwrap();` → `let Some(series_name) = …find(…) else { … continue }; …` Single binding, no redundant `is_none()` re-check, no `unwrap()` on the path that already proved `Some` (#197). Behaviour is identical; the change is purely an idiom cleanup. The existing `repositories::project_prompt` test coverage (rolled into the 45-test `repositories` suite) stays green.
… last Closes #211. `find_git_module_info_dirs::walk` tracked the nested \`modules\` dir in a single \`Option<PathBuf>\`, so a directory listing that yielded more than one entry whose \`file_name()\` matched \`modules\` would keep only the last one walked. The case is unusual on case-sensitive filesystems but reachable on case-insensitive ones (macOS / NTFS) where \`modules\` and \`Modules\` can collide as dir entries from different writers, and a future relax of the equality match (icase, alt names) would silently start dropping subtrees. Replace the \`Option<PathBuf>\` with a \`Vec<PathBuf>\` and walk each collected nested-modules dir in turn. The \`return\` on the inner \`fs::read_dir\` error becomes a \`continue\` so a single unreadable nested dir no longer aborts the walk for sibling subtrees in the same parent. `cargo test --lib policy::git_discovery` is green (3/3, including \`test_find_git_module_info_dirs_finds_nested_submodules\`).
…ck (#187) Signed-off-by: SAY-5 <say.apm35@gmail.com>
…-safe (#225) Signed-off-by: SAY-5 <say.apm35@gmail.com>
- Deleted cli/integrate-tests/ and mcp/integrate-tests/ - Removed workspace members from Cargo.toml - Updated CI workflow to remove integration test references and point packaging smoke to local-tests - Updated xtask to remove integration test excludes - Removed integrate-tests .gitignore entry - Updated AGENTS.md and CLAUDE.md in root, cli, and mcp to remove integration test docs - Regenerated Cargo.lock (removed testcontainers and related deps)
…gn page - Document removal of integration tests due to infrastructure complexity - Position local-tests as the economical and realistic testing choice - State CLI/SDK must be designed cross-platform, not OS-specific - Update technical-details index and _meta.ts navigation
- Introduced category_name field in SkillPrompt struct to allow categorization of skills. - Added functions to resolve skill directory names and build skill source identifiers based on category. - Updated output plan collection to include categorized skills and their supporting files. - Implemented logic to handle nested skill directories and ensure proper file structure. - Enhanced prompt service to parse and build identifiers for categorized skills. - Added tests to validate the new functionality, ensuring correct handling of categorized and legacy skills.
…o eliminate duplication
…agement and security boundaries
…dd tests for validation
…le UTF-8 workspace paths
… memory - Added support for emitting nested .cursorrules files for child memory prompts in cursor_output_plan. - Updated droid_output_plan to use global memory when AgentsOutputAdaptor is active and emit nested AGENTS.md files for child prompts. - Enhanced gemini_output_plan to emit global-only project files when AgentsOutputAdaptor is registered and maintain nested child memory files. - Modified opencode_output_plan to collapse project memory to global-only payload while AgentsOutputAdaptor is active and emit nested AGENTS.md files for child prompts. - Updated trae_output_plan to emit nested steering files for child memory prompts. - Enhanced windsurf_output_plan to emit nested .windsurfrules files for child memory prompts. - Introduced regression tests to ensure child memory prompts are emitted across all target plans and that global memory is used when AgentsOutputAdaptor is active. - Improved Deno runtime to restrict script execution to allowed script roots and prevent leaking absolute paths. - Refactored prompt_service to safely handle relative paths and prevent leaking absolute paths through the prompt catalog.
…ures - Introduced `IsolatedRulesFixture`, `IsolatedOpencodeFixture`, and `IsolatedTraeFixture` to encapsulate test setup and environment management for rules, opencode, and trae tests. - Updated tests to use the new fixture structures, improving isolation and reducing dependencies on the host workspace. - Enhanced the `write_rules_config`, `write_opencode_config`, and `write_trae_config` functions to streamline the creation of necessary configuration files for each test. - Improved assertions in the tests to ensure clarity and correctness, including checks for file existence and content validation. - Removed redundant code and comments, ensuring a cleaner and more maintainable test suite.
# Conflicts: # mcp/integrate-tests/tests/packaging_smoke.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
发布版本 2026.10502.118
变更概要