Commit Graph
1764 Commits
Author SHA1 Message Date
Bellman 2d920ce915 Merge pull request #3318 from ultraworkers/pr-3292
fix: harden the agent loop against a self-hosted Anthropic-compatible backend
2026-10-13 08:07:04 +09:00
Bellman 80bfe94b77 Merge pull request #3299 from D4B34R987/main
fix: wire persisted provider configuration into runtime
2026-10-13 08:06:13 +09:00
dependabot[bot] 5303de65ad build(deps): bump quinn-proto
Bumps the cargo group with 1 update in the /rust directory: [quinn-proto](https://github.com/quinn-rs/quinn).


Updates `quinn-proto` from 0.11.14 to 0.11.19
- [Release notes](https://github.com/quinn-rs/quinn/releases)
- [Commits](https://github.com/quinn-rs/quinn/compare/quinn-proto-0.11.14...quinn-proto-0.11.19)

---
updated-dependencies:
- dependency-name: quinn-proto
  dependency-version: 0.11.19
  dependency-type: indirect
  dependency-group: cargo
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-10-12 23:03:59 +00:00
DaBear987 50ff600466 fix: wire persisted provider configuration into runtime 2026-10-12 23:03:56 +00:00
Bellman 4c3b10f087 Merge pull request #3317 from ultraworkers/lane/cc-issue-3283
docs: add OmniRoute documentation for OpenAI-compatible setup
2026-10-13 08:02:26 +09:00
reacechalmers 6a797de094 fix(runtime): keep a failed turn's tool results, and size guards from the real context window
Five defects found by auditing the agent stack, all of which let the harness act
confidently on a wrong picture of its own state.

1. A turn that errored discarded the record of tools that had already run. The CLI
   hands run_turn a CLONE of the session; the turn appends the user message, each
   assistant reply, and a tool_result per executed tool to that clone alone. The error
   path dropped it while the side effects of those tools remained on disk, and the
   recovery path then replayed the same user input against a session showing no sign
   they had ever run — inviting a second execution of tools that are not idempotent.
   The clone is now adopted before teardown, and recovery resumes the turn instead of
   replaying it (new ConversationRuntime::resume_turn).

2. Every sizing guard was computed against the model NAME's context window. With a
   local server behind a cloud model alias that is 200k against a much smaller
   backend, which does not make the preflights inaccurate — it makes them unreachable.
   CLAW_CONTEXT_WINDOW now declares the real window; model_token_limit honours it and
   returns a limit for unrecognised models instead of None, max_tokens is capped to a
   quarter of it, and the auto-compaction threshold derives from it (70%) rather than
   defaulting to a 200k-window constant.

3. Whether to recover by discarding conversation history was decided by substring
   matching on rendered error prose, including strings that ordinary transport and
   decode failures also produce — so a dropped connection cost the session its
   transcript. Classification now happens in the API layer, where the error still has
   its type and the request is still in hand: typed overflow errors, plus ambiguous
   transport failures only when the request actually filled the window. The two
   copy-pasted detection blocks are gone.

4. The top-level agent loop had no iteration ceiling (usize::MAX) while spawned
   subagents were bounded at 32. It now gets the same bound, overridable with
   CLAW_MAX_TURN_ITERATIONS.

5. Auto-continue nudges were injected as USER turns, so harness-authored text was
   persisted, re-sent on every later request, and folded into compaction summaries as
   something the user had said. They are recorded as system turns now; the wire
   payload is unchanged.

Also replaces the repository's own self-host section, which described a translator
and a serving stack no longer in the request path. That file is folded into the
system prompt verbatim, so it was briefing the model with an architecture that does
not exist.

(cherry picked from commit c8834cb4d1a3372eb70241429f641162a420297e)
2026-10-12 23:00:22 +00:00
Bellman e97ddc767f Merge pull request #3239 from AbbyJL/workspace-slash-command
fix(commands): wire workspace slash command
2026-10-13 07:59:47 +09:00
clawdbot 687c6b03a4 docs: add OmniRoute documentation for OpenAI-compatible setup (fixes #3283) 2026-10-12 22:59:18 +00:00
reacechalmers 7c38d78759 fix(runtime): auto-continue a turn the model stalled without a tool call
A reply carrying no tool_use ended the turn unconditionally. Small local
models routinely narrate the next tool call in prose — "Now running the
EEC-V probe:" — and then emit EOS, so the announced work never happened
and the user was dropped back at the prompt. The same failure wears a
second hat mid-task: stopping to ask for a go-ahead on work already
requested.

The loop now inspects the final line of a tool-less reply. If it
announces a pending action, or asks a question after tools have already
run this turn, a short nudge is pushed as a user message and the loop
continues instead of breaking. The budget is bounded (default 3 per
turn, CLAW_MAX_STALL_NUDGES, 0 disables) so a model that really is
finished still gets to stop.

Prevention pairs with recovery: the "Doing tasks" system-prompt section
now tells the model to act in the turn it plans in.

Tests cover the auto-continue, the bound, a plain completion that must
NOT be nudged, the disable switch, and last-line-only detection. The
behavioural pair was mutation-checked: reverting the continue to a break
fails both.

(cherry picked from commit 9035fe6f4bf4a8d4cb70d7a3baf1f3748c757498)
2026-10-12 22:58:32 +00:00
reacechalmers cb572811e1 fix(runtime): bound the git diff snapshot to a configurable budget
The git diff snapshot is rendered into the *system prompt*, so its cost is
paid again by every session whose working tree has changed -- and a diff
changes on essentially every edit. The 50_000-char budget was four times the
entire instruction-file budget (12_000) and unbounded in practical effect: a
single modified file added ~15_000 tokens to the prompt.

Measured against a self-hosted backend, one uncommitted change took the
prompt from 8_302 to 23_457 tokens and a one-word reply from ~3 s to 296 s.
With the new default the same session is 7_911 tokens and 36 s. That cost is
absorbable against a hosted frontier model and ruinous against a local one.

Default is now 4_000 chars, matching MAX_INSTRUCTION_FILE_CHARS, and is
overridable with CLAW_MAX_GIT_DIFF_CHARS following the same pattern as
CLAW_MAX_READ_CHARS. A budget of 0 omits the snapshot entirely rather than
emitting an empty section with a truncation marker; git status and the
recent-commit list are unaffected either way.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RNKqVB2JE9UnCkz8FC9HPy
(cherry picked from commit e01c6ea43d56a97e284ab80fa7a90a479997ed74)
2026-10-12 22:58:32 +00:00
reacechalmers fa0d53a969 fix(runtime): bound tool-result payloads to the actual context window
Two related gaps let a single agentic turn exceed a small context window,
with no recovery path once it happened.

1. read_file's character ceiling was a hardcoded 64 KB (~16k tokens), sized
   for a 200k window. Two reads in one turn reach ~48k tokens, which a 32k
   backend rejects outright. Make it configurable via CLAW_MAX_READ_CHARS,
   defaulting to the existing 64 KB so behavior is unchanged unless set.
   Reads remain paged, not refused: callers still get truncated/nextOffset.

2. Compaction could not help, because it works at message granularity and an
   agentic turn is five messages (user / assistant+tool_use / tool_result /
   assistant+tool_use / tool_result). With preserve_recent_messages: 4 the
   only droppable message is the short user prompt, so the two oversized
   tool results were preserved verbatim by design.

   Trim preserved tool-result payloads over 16 KB to a head/tail excerpt with
   an explicit "[... N characters elided ...]" marker, so the model knows its
   view is partial and can re-read. Small payloads pass through untouched.

   Also apply trimming on the early-return path: a session can exceed the
   window while holding fewer messages than preserve_recent_messages, where
   should_compact is false and message-granular compaction has no move to
   make. compact_now no longer gates on removed_message_count alone, which
   would have computed the smaller session and then discarded it.

Also fixes a pre-existing flaky test: repl_executes_python_code resolves the
python runtime through PATH, which the PowerShell tests blank while they run.
It now takes the same env_lock, so it no longer intermittently fails with
"python runtime not found" on a machine that has python.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013bVvRYn7CQKR6hT2j1L6Cs
(cherry picked from commit b0d4d41e8132f8dc75717b1f74554d649639de10)
2026-10-12 22:58:32 +00:00
reacechalmers 910ac4e326 fix(runtime): also check for compaction before a request is sent
The usage-based compaction gate is post-hoc: it can only see the context
after a call returns and reports its counters. Between that measurement and
the next request the session can grow enormously - a reasoning model emitting
a long thinking block, then a tool result carrying a large file.

Observed live: a call measured at 17,858 prompt tokens generated 10,842 more,
a read_file added ~19k on top, and the next request reached the provider at
47,755 tokens and was rejected outright. No tuning of the post-hoc threshold
prevents that, because nothing measures the session in between.

Add a pre-send check driven by estimate_session_tokens, a local heuristic over
the transcript, so it costs no API call and works before any usage has been
recorded at all.

Note the limit of this: compaction preserves the 4 most recent messages, and
in an agentic tool-use loop those messages ARE the tool results carrying the
bulk. This check bounds gradual growth; it cannot rescue a session whose last
four messages already exceed the window.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013bVvRYn7CQKR6hT2j1L6Cs
(cherry picked from commit 26ab52d70fb17e49b74d523aecfc1da7f69a6d60)
2026-10-12 22:58:19 +00:00
reacechalmers a25717aded fix(runtime): auto-compaction must measure the live context, not a running total
`maybe_auto_compact` gated on `usage_tracker.cumulative_usage().input_tokens`,
which is wrong in two independent ways:

1. It ignores cached input. With prompt caching a warm call reports
   `input_tokens: 2` and puts the real context in `cache_read_input_tokens`,
   so the counter barely moved and auto-compaction never fired at all,
   however large the conversation grew. Backends without prompt caching
   report the whole prompt as `input_tokens`, so the bug was invisible there.

2. A sum across calls is not a context measurement, and it never decreases.
   Once it did cross the threshold, every subsequent iteration compacted
   again, permanently, even after compaction had shrunk the context.

Gate on the latest call's total input instead — input + cache_creation +
cache_read — which is the live context window size. It rises with the real
context and falls back below the threshold once compaction has done its job,
so no counter reset is needed.

`CLAUDE_CODE_AUTO_COMPACT_INPUT_TOKENS` now means what it reads like:
compact when the live context reaches N tokens. The default of 100_000 is
unchanged and still lands at 50% of a 200k window.

Adds `TokenUsage::total_input_tokens()` (saturating) and four tests: the
cached-usage shape that never fired, non-latching across three turns, and
two unit tests for the new helper.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013bVvRYn7CQKR6hT2j1L6Cs
(cherry picked from commit aebba4e77eddf585fc5b21123967dbc4ebb6e6a1)
2026-10-12 22:58:19 +00:00
reacechalmers 7a1391fbc1 fix(test): isolate tests from the machine's real user config and kernel
The suite asserted against whatever the developer's box happened to be
configured as. Two independent leaks, both surfaced by a real `~/.claw`:

1. `parse_args` resolves defaults — notably `permissions.defaultMode` —
   through the user-scope config, which `default_config_home()` reads from
   `CLAW_CONFIG_HOME` falling back to `$HOME/.claw`. Nothing overrode it, so
   a `defaultMode` of `dontAsk` on the host turned 12 assertions from
   `WorkspaceWrite` into `DangerFullAccess`. `env_lock()` now returns an
   `EnvGuard` that points `CLAW_CONFIG_HOME` at a fresh empty directory and
   restores the previous value on drop, so "no user config" is the state
   under test. All 42 call sites already bind the guard, so this fixes them
   at once; tests that want a populated config home can still set the var
   themselves afterwards. `removed_login_and_logout_subcommands_error_helpfully`
   asserted a Default-sourced permission mode without taking the guard at
   all, and now does.

2. `direct_resume_safe_slash_commands_route_to_local_json_actions_831`
   hardcoded `/sandbox` => "warn", which is only true where namespace
   isolation is unsupported and just the filesystem sandbox is active
   (#731). On a host with working user namespaces the correct answer is
   "ok". That entry now accepts either; the test is about #831 routing —
   local JSON action instead of `interactive_only` — not about the kernel
   under the runner.

Verified with the real ~/.claw/settings.json in place (defaultMode=dontAsk):
cargo test --workspace 0 failures, clippy --workspace --all-targets
-D warnings 0 findings, scripts/fmt.sh clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9McEEH32ZtyM62GSXVSyJ
(cherry picked from commit 67aa4530c22f6fdf95a29d6a46992af137134c67)
2026-10-12 22:58:19 +00:00
reacechalmers 2944e02a09 fix(clippy): clear remaining -D warnings failures in rusty-claude-cli
`cargo clippy --workspace --all-targets -- -D warnings` is this repo's own
documented verification command, and it could not run to completion. Earlier
compile failures were masking a further 48 lints; with those cleared the
workspace now passes with zero findings.

Real fixes, not suppressions:
  - status_json_value took 8 positional parameters, four of them a tail of
    `Option<&_>` that most callers passed as None — trivially transposable.
    Grouped into `StatusJsonExtras` with a Default impl; all 7 call sites now
    name only the fields they actually set.
  - extract_help_metadata's 8-tuple return is now a documented `HelpMetadata`
    alias.
  - the auto-compact loop indexed preserve_schedule by its loop counter;
    it now iterates the array directly.
  - a sandbox status chain had two identical arms; merged the condition.
  - a filter_map whose every arm returned Some is now a map.
  - 33 unused stdout/stderr bindings in the output-format contract tests are
    prefixed with `_`, and 9 `map_or(false, ..)` are now `is_some_and(..)`.

NOTE: several `--bin claw` tests (parse_args defaults) read the *real*
`~/.claw/settings.json` rather than an isolated config home, so they fail on
any machine whose user config sets `permissions.defaultMode`. With that file
moved aside the binary's suite is 207/207. That isolation gap is pre-existing
and left for a separate change.

Verified: clippy workspace/all-targets/-D warnings reports 0; cargo test
--workspace passes with the user config neutralised; scripts/fmt.sh clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9McEEH32ZtyM62GSXVSyJ
(cherry picked from commit 03c8a8fd7ba6e405a8217d00d3766c1c6367e527)
2026-10-12 22:58:19 +00:00
reacechalmers cd01ffc5f3 fix(clippy): box ApiError::Api payload to clear result_large_err
`ApiError` is the `Err` half of nearly every `Result` in the api crate, and
its `Api` variant carried ~139 bytes inline (8 fields, four of them
`Option<String>`). That tripped clippy::result_large_err on 35 signatures
and, with -D warnings, made the whole crate unbuildable under the repo's
own documented verification command.

Move the payload into `ApiErrorDetails` behind a `Box`:
  - `ApiError::Api(Box<ApiErrorDetails>)`, with `ApiError::api(..)` to
    construct and `api_details()` to borrow
  - `ApiErrorDetails` re-exported from the crate root
  - adding a field here can no longer re-inflate every signature

This also simplifies `enrich_bearer_auth_error`, which previously
destructured and rebuilt all eight fields at five separate return points
just to append a hint; it now mutates the boxed payload in place.

Also clears the remaining pre-existing lints that blocked -D warnings:
unused test bindings, a redundant `use serde_json`, and an explicit
`.into_iter()` in claw-rag-service.

Verified: cargo test --workspace passes, 0 failures.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9McEEH32ZtyM62GSXVSyJ
(cherry picked from commit e9210bd75eb76e5d88b2ae797f537102bcabd41d)
2026-10-12 22:58:19 +00:00
reacechalmers 4361e98998 fix: page large read_file results instead of returning whole files
An unbounded read_file returned the entire file, which on a small-context
backend overflows the model's window. The backend then rejects the whole
request (llama-server: "request (N tokens) exceeds the available context
size"), which kills the turn — so reading everything at once is precisely
what makes the session stop. Observed live: one 100 KB source file is
~25k tokens against a 32k window with a ~6k-token prefix, and a session
read the same file three times and died on six 400s.

read_file now returns a page and says so:
  - absent `limit` yields DEFAULT_READ_LINES (2000) rather than EOF
  - MAX_READ_CHARS (64 KB) bounds the payload even when `limit` is
    explicit, so minified or generated files can't defeat the line cap
  - `truncated` and `nextOffset` tell the caller it has a partial view
    and exactly where to resume; the tool description explains both

MAX_READ_SIZE (10 MB) is untouched: it is a process guard against slurping
huge or binary blobs, not a context guard, and at ~2.5M tokens it never
fires on the files that actually overflow a window.

Also clears pre-existing clippy failures in trident.rs that blocked
-D warnings on every edit to this crate.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9McEEH32ZtyM62GSXVSyJ
(cherry picked from commit c796d7e5eedc66b0cb37bb6823ec772f8ceef9cf)
2026-10-12 22:58:19 +00:00
Bellman 95f797f5e2 Merge pull request #3316 from ultraworkers/fix/release-sha256-macos
fix(ci): use cross-platform sha256 for macOS and Linux release artifacts
v0.1.3
2026-10-13 07:32:17 +09:00
clawdbot ff515c9aeb fix(ci): use cross-platform sha256 for macOS and Linux release artifacts 2026-10-12 22:29:43 +00:00
Bellmanandclawdbot 0f1a69659c chore: remove accidentally committed .gjc session state and ignore .gjc/ (#3315)
Co-authored-by: clawdbot <clawdbot@ultraworkers.dev>
2026-10-13 07:22:41 +09:00
990cc33c19 test(runtime): expand json module unit tests [formatting fix] (#3308)
* test(runtime): expand json module unit tests

The hand-rolled JsonValue parser/renderer in runtime had only two
tests covering a self-contained JSON parser, renderer, accessor set,
and error type. Add focused unit tests covering primitive rendering,
sorted object keys, escape handling (quotes, backslashes, control
chars), signed-integer and whitespace-tolerant parsing, nested
structures, render->parse round-tripping, malformed-input rejection,
i64 overflow rejection, accessor variant mismatches, and JsonError
Display.

* style: format json.rs tests to match rustfmt standards

---------

Co-authored-by: 黄云龙 <76432572+nankingjing@users.noreply.github.com>
Co-authored-by: gaebal-gajae <clawdbot@users.noreply.github.com>
2026-10-13 07:22:31 +09:00
黄云龙 8d2c7b78b2 refactor(cli): let the emitter report the output tail it leaves behind (#3304)
refactor(cli): let the emitter report the output tail it leaves behind

Two places believed they owned terminal output: consume_stream streams
assistant deltas live while emit_output = true, and run_turn decided
whether to emit a separating newline before spinner.finish by guessing
from final_assistant_text(&summary).

That guess agrees with reality only because every *other* writer happens to
terminate its output with a newline — tool results go through
stream_markdown (which appends one), thinking summaries are written with a
trailing newline, and tool-call headers use writeln! — so the assistant
text path is the only one that can leave a partial line. That is a property
of the current renderers rather than of the streaming protocol, and it is
not enforced anywhere.

TerminalTail is state the emitter records into as it writes: both live
writers (AnthropicRuntimeClient::consume_stream and the tool-result blocks
in CliToolExecutor::execute) now push bytes through a TailTrackingWriter
that reports the last byte written, and the caller that ends a turn asks
where the emitter stopped instead of inferring it.

The heuristic also left the failure arm unguarded. A turn that streamed text
and then errored called spinner.fail on a partial line, which the line
clear then erased; that arm now carries the same guard.

Also gate the animated spinner.tick frame on is_terminal(). That frame is
pure cursor control (save, rewrite line, restore) and emits no newline, so
down a pipe it leaves an unterminated banner that the first streamed delta
then continues on the same physical line.

—
*[repo owner's gaebal-gajae (clawdbot) 🦞]*
2026-10-13 07:18:12 +09:00
Bellman 972ba85c3b Merge pull request #3268 from nankingjing/docs-model-aliases
docs(rust/README): document xAI and Kimi model aliases
2026-10-13 07:16:43 +09:00
Bellmanandclawdbot 6d6c83be01 docs(security): enable GitHub Security Advisories instructions (Fixes #3276) (#3311)
- Updated SECURITY.md with explicit instructions for reporting vulnerabilities via GitHub Security Advisories
- Replaced 'when available' qualifier since Private Vulnerability Reporting is now enabled
- Provided step-by-step guidance for security researchers to submit vulnerability reports

Co-authored-by: clawdbot <clawdbot@ultraworkers.dev>
2026-10-13 07:15:26 +09:00
Bellman 171a07b68c fix(cli): preserve trailing block separators in streamed markdown (#3312)
Merged via automated lane resolution
2026-10-13 07:15:19 +09:00
Bellman d1c678b6b0 Merge pull request #3310 from ultraworkers/release/v0.1.3-changelog
docs: add CHANGELOG for v0.1.3 release
2026-10-13 07:15:07 +09:00
黄云龙 8d81c61b7a test(runtime): cover JSON escapes end to end and pin the i64 boundary pair (#3305)
Reviewed and verified: 4 new tests added, all passing. 116 lines added to test JSON escape sequences and i64 boundaries. No production code changes.

—
*[repo owner's gaebal-gajae (clawdbot) 🦞]*
2026-10-13 07:14:47 +09:00
clawdbot faefa6e794 Merge pull request #3264 from JesseBrown1980/asolaria-wire
Add Asolaria json=0 wire-format + addressing example

Contributes a reproducible benchmark demonstrating:
- Binary wire format vs JSON text for agent event logs
- 4.64× size reduction (153.2 B → 33.0 B per record)
- ~11× faster encoding
- Tamper-detection via SHA-256 hash-chain
- Self-contained example with no changes to claw-code core

All measurements reproducible; architectural vision clearly distinguished.
2026-10-12 22:14:35 +00:00
devilking7x 39d2f73d67 docs: fix broken star history chart in README (#3307)
Closes #3293

The api.star-history.com SVG endpoint is broken due to GitHub
stargazer API restrictions. Switch to the working alternative at
star-history.dera.page for both dark/light SVGs and the chart link.
2026-10-13 07:14:27 +09:00
AbdullahFageehandOz 05a2d71cb5 fix: support groq compound defaults (#3281)
Route groq-prefixed models through the OpenAI-compatible client,
apply Groq token-limit metadata, and skip local tool injection for
compound models.

Add regression coverage for routing, token limits, and compound
local-tool behavior.

Co-authored-by: Oz <oz-agent@warp.dev>
2026-10-13 07:14:14 +09:00
Jesse Daniel Brown 5867ef8f9d Add Asolaria wire bench (reproducible binary+SHA vs JSON) 2026-10-12 22:14:13 +00:00
Jesse Daniel Brown 4ce9167e48 Add Asolaria wire bench (Cargo.toml) 2026-10-12 22:14:13 +00:00
Jesse Daniel Brown 49e6c2e72e Add Asolaria json=0 wire + addressing showcase (README) 2026-10-12 22:14:13 +00:00
YE 7633bc3638 docs: add Chinese translation (README.zh.md) (#3246)
docs: add Simplified Chinese translation (README.zh.md)

Adds a complete Chinese translation of the README with proper language selector.

Contribution by @JasonYeYuhe
2026-10-13 07:14:07 +09:00
Bellman 8aeef8d2e2 Merge pull request #3271 from Aneesh-382005/fix/local-model-validation-bypass
fix: generalize local-model validation bypass beyond Ollama tags
2026-10-13 07:13:39 +09:00
Ming LiuandClaude Opus 4.6 43d68dba75 feat: add persistent auto-memory system (#3241)
feat: add persistent auto-memory system

Implement a file-based persistent memory system that allows the AI to retain knowledge about users, feedback, projects, and references across sessions.

## Implementation Details
- MemoryStore data layer with FNV-1a workspace fingerprinting
- MemoryRead/MemoryWrite tools with security hardening (path traversal, symlink, absolute path, and size limit protections)
- System prompt injection of MEMORY.md index with prompt injection mitigation (fenced code block + trust-lowering notice)
- autoMemoryEnabled config option (defaults to true)
- Doctor health check for auto-memory state
- /memory command enhancement showing persistent memory info

## Verification
✓ 1023 lib tests pass
✓ Output format contract tests pass
✓ Release build succeeds
✓ Security hardening verified

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-10-13 07:13:36 +09:00
Bellman d6b7109d33 Merge pull request #3309 from ultraworkers/lane/cc-issue-3287
ci: pin all third-party GitHub Actions to immutable commit SHAs
2026-10-13 07:08:18 +09:00
clawdbot ad65ea5a47 docs(triage): document investigation and clarification needed for #3283 2026-10-12 22:07:06 +00:00
clawdbot e2e91e1ab0 docs: add CHANGELOG for v0.1.3 release 2026-10-12 22:06:23 +00:00
Gracy769 d02d5736ed trigger ci 2026-10-12 22:06:08 +00:00
Gracy769 0244976f8d test: add explicit coverage for unquoted UNC paths
Asserts that an unquoted UNC path like \\server\share\file.txt survives
extract_path_candidates unchanged, preventing the regression where
shlex.split(posix=True) stripped the backslashes.
2026-10-12 22:06:08 +00:00
Gracy769 358a5252f6 test: add end-to-end UNC containment test
Replaces the basic extraction test with an end-to-end test that verifies
UNC paths are correctly denied when outside the workspace (e.g. local root),
but correctly allowed when the workspace root is itself a UNC share.

Validates the fix from the PR review.
2026-10-12 22:06:08 +00:00
Gracy769 6ef743ad73 test: add regression coverage for drive-relative and escaped UNC paths
Adds explicit test coverage to ensure drive-relative paths (e.g. C:foo)
and escaped UNC paths (e.g. \\\\server\\share\\dir) from JSON payloads
are correctly validated by the workspace containment checks.

Closes final review suggestions.
2026-10-12 22:06:08 +00:00
Gracy769 ad8cd12fa2 test: ensure full candidate probing and clear cache in setUp
- Updates _check_bash_state to not short-circuit on the first unusable
  bash candidate on Windows, ensuring a working fallback is found if present.
- Clears bash detection cache in unittest setUp/tearDown rather than just
  relying on a pytest fixture, covering native unittest runners.
2026-10-12 22:06:08 +00:00
Gracy769 86cf10a43a test: enforce bash lru_cache clearance and expose specific skip reasons
Adds a conftest.py pytest fixture to explicitly clear the lru_cache for bash
detection, addressing the monkeypatching hazard in a way that doesn't rely
solely on comments. (Note: CI currently runs python -m unittest, but this
keeps local pytest runners safe.)

Also updates the bash check to run the execution probe directly inside the
cached _check_bash_state, exposing the difference between 'no bash found'
and 'bash present but execution failed' directly to the unittest skip reason.
2026-10-12 22:06:08 +00:00
Gracy769 c31c5e27dd test: extract bash detection to shared _bash helper
Moves get_bash_executable and require_bash into a shared module so their
lru_cache state is per-session rather than per-test-module. Also adds a
comment regarding monkeypatching since lru_cache will silently drop changes
to os.environ if it has already been populated.

Closes follow-up items from PR review.
2026-10-12 22:06:08 +00:00
Gracy769 a916bf9d66 perf(test): cache bash probe resolution per session with functools.lru_cache 2026-10-12 22:06:08 +00:00
Gracy769 0d8b50b378 fix(security): deny unresolvable paths and enable Git bash detection on Windows 2026-10-12 22:06:08 +00:00
Gracy769 3463331171 test: fix windows test compatibility 2026-10-12 22:06:08 +00:00
Gracy769 49a4f27d14 style: remove trailing whitespace in path_scope.py 2026-10-12 22:06:08 +00:00