Commit Graph
3943 Commits
Author SHA1 Message Date
Jeffrey Montoya 2ec52af6d0 perf(gateguard): profile a change only when used and check its window first 2026-09-30 12:13:18 -04:00
Jeffrey Montoya d39fcd8ac3 refactor(gateguard): read the transcript tail through a small shared module 2026-09-30 12:13:10 -04:00
drakeo338andClaude Sonnet 5.5 b802ec80a6 test(hooks): compare project sharing path against the canonical temp dir
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 16:06:15 +00:00
Jeffrey Montoya ef32c8e9ee docs(security): refresh GateGuard evidence for the latency changes 2026-09-30 11:36:10 -04:00
Jeffrey Montoya d95aa3425e feat(gateguard): measure hook latency in fresh processes 2026-09-30 11:35:49 -04:00
Jeffrey Montoya eab92ed21d perf(gateguard): skip plain character runs when lexing code 2026-09-30 11:35:49 -04:00
Jeffrey Montoya b7f80ff012 perf(gateguard): load modules and parse searches only when a call needs them 2026-09-30 11:35:49 -04:00
Toni AlataloandClaude Sonnet 5.5 708d621372 fix(ecc2): also sandbox the legacy ~/.claude/ecc2.toml path under cfg(test)
Addresses review feedback on #3277: the previous commit sandboxed the
primary config path, but Config::global_config_paths() also reads the
legacy $HOME/.claude/ecc2.toml. A test that called Config::load() would
pick up (or fail on a malformed) developer-local legacy config.

Under cfg(test), legacy_global_config_path() now resolves inside the same
per-test-thread scratch root as config_path().

Proof of red (new test, before the fix):

$ cargo test legacy_config_path_under_test
    running 1 test
    test config::tests::legacy_config_path_under_test_is_sandboxed_away_from_user_home ... FAILED
    failures:
    ---- config::tests::legacy_config_path_under_test_is_sandboxed_away_from_user_home stdout ----
    tests must never read the real legacy user config, got /Users/<me>/.claude/ecc2.toml
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    failures:
        config::tests::legacy_config_path_under_test_is_sandboxed_away_from_user_home
    test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 491 filtered out; finished in 0.00s
    error: test failed, to rerun pass `--bin ecc-tui`

After the fix:

$ cargo test legacy_config_path_under_test
    test config::tests::legacy_config_path_under_test_is_sandboxed_away_from_user_home ... ok
    test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 491 filtered out

$ cargo test   # full suite
    test result: ok. 491 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out

Refs #3276

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Y54kLgLGzLGqAxwLMFEc9
2026-09-30 23:08:55 +09:30
Toni AlataloandClaude Sonnet 5.5 6f141fe5a2 fix(ecc2): sandbox Config::config_path() under cfg(test)
Dashboard tests that spawn sessions reach Config::save() through
auto_split_layout_after_spawn, which wrote to the developer's real
~/Library/Application Support/ecc2/config.toml. The fixture's db_path
pointed at a deleted temp dir, so the next `cargo run` failed with
"unable to open database file".

Under cfg(test), config_root() now returns a per-test-thread scratch
directory that is removed when the thread exits, so no test can reach
the real user config.

Fixes #3276

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Y54kLgLGzLGqAxwLMFEc9
2026-09-30 22:50:52 +09:30
Yi-111-a b09a26aaad fix(package): publish scripts/github-coordination.js for the /epic-* commands
`package.json` `files[]` enumerates each top-level `scripts/*.js` by hand, and
`scripts/github-coordination.js` was never added. npm therefore drops it from
the tarball while `scripts/lib/` still ships wholesale, so only the CLI entry
disappears.

All seven `/epic-*` commands ship in `commands/` and each instructs the agent
to run:

    node scripts/github-coordination.js <command> <issue> --repo <owner/repo>

so anyone who installs from npm -- including the documented
`npm i -g ecc-universal` path -- gets seven commands that cannot run:

    Error: Cannot find module '.../ecc-universal/scripts/github-coordination.js'

It works from a git clone, which is what masked it locally.

Add the missing `files[]` entry, the matching publish-surface allowlist entry in
`tests/scripts/npm-publish-surface.test.js` (CONTRIBUTING asks for both), and a
guard test that fails when any published command invokes a `scripts/*.js` that
the publish surface does not cover. The guard reproduces this exact bug: with
`package.json` reverted it fails naming only `github-coordination.js`.

Refs #3270
2026-09-30 21:09:38 +08:00
drakeo338andClaude Sonnet 5.5 334b7847bd fix(hooks): keep ~/.claude eligible as project sharing root with CLAUDE_CONFIG_DIR
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 12:43:02 +00:00
FenjuFu 74836ce65f fix(llm): forward tool definitions to Ollama
OllamaProvider built the /api/chat payload without the tools from
LLMInput, so Ollama models were never told any tools existed and a
ReActAgent backed by Ollama never ran one. The response side already
parsed message.tool_calls.

Send the tools in the OpenAI function format that /api/chat accepts,
matching the other providers.

Fixes #3274

Signed-off-by: FenjuFu <fufenjupku@gmail.com>
2026-09-30 20:38:19 +08:00
FenjuFu d6f20191de fix(llm): strip leaked reasoning from self-hosted model output
Self-hosted reasoning models served through vLLM or llama.cpp without a
reasoning parser, or through Ollama without a thinking template, return
their chain of thought inside message content. The OpenAI-compatible
providers and the Ollama provider passed it through verbatim, so
LLMOutput.content and ReActAgent final answers began with the reasoning.

Models whose chat template prefills <think> in the generation prompt
(Spark-X2.5, Qwen3 thinking variants) only emit the closing tag, so the
content arrives as "...</think>answer" with no opening tag.

Add strip_reasoning() and apply it in the OpenAI, Astraflow, Atlas and
Ollama providers. A <think> that does not open the output is kept as a
literal, and unterminated reasoning is left unchanged.

Signed-off-by: FenjuFu <fufenjupku@gmail.com>
2026-09-30 18:41:24 +08:00
Geronimo 25c5f504bf Merge branch 'main' of github.com:VarunGore36/ECC 2026-09-30 16:03:36 +05:30
Geronimo 5f7ba84b38 Merge branch 'affaan-m:main' into main 2026-09-30 16:02:28 +05:30
Seekers2001 b43a6770ab Merge upstream/main into codex/docs-governance-audit-foundation 2026-09-30 17:33:07 +08:00
rhmatzeka eb30409fc5 fix(skills): authorize laravel-security download on the model before signing a URL
The secure-storage example authorized `download` against a raw path string
taken from the request and generated the temporary URL before the check.
A string argument never resolves to a policy, and authorizing a
client-supplied path teaches an IDOR-prone pattern.

Bind a model (Document), authorize against it first, then sign the URL for
the stored path on the s3 disk configured just below. pi/core regenerated
via scripts/build-pi-core.js; skill-triggers registryDigest rebound.
2026-09-30 11:32:33 +07:00
Santhi Prakash ddef030123 Merge branch 'main' into fix/plan-orchestrate-retired-orchestrate
Second upstream sync this cycle: main c70874fa (#3264, curated pi/core
skills + 2.2.2 release sync) touches manifests/context-packs/skill-triggers@1.json,
the same field this branch bumps.

Resolution: main's manifest (293 canonical skills, triggers 32) with
registryDigest recomputed over the merged tree via the repo's own chain
(scripts/lib/context-pack-registry.js -> digestObject). Algorithm
validated first: the same computation reproduces main's committed digest
on main's tree and the prior head's committed digest on that tree exactly.

Verification: node scripts/ci/validate-context-profiles.js (293 skills,
triggers 32/293) OK; plan-orchestrate registry fixtures pass; full
node tests/run-all.js = 704 passed / 0 failed.
2026-09-30 04:26:24 +00:00
Jeffrey Montoya 4b02f66951 docs(gateguard): refresh evaluation and security evidence 2026-09-30 00:24:50 -04:00
Jeffrey Montoya f19425dbf1 docs(gateguard): move change-profile notes into their own file 2026-09-30 00:23:08 -04:00
Jeffrey Montoya b15c0538f6 refactor(gateguard): split change profile and search filters into focused modules 2026-09-30 00:23:08 -04:00
Jeffrey Montoya 3055eb3746 fix(gateguard): link SARIF findings to the evaluated corpus 2026-09-30 00:04:11 -04:00
Jeffrey Montoya 1221a8727f fix(gateguard): honour directory-qualified include globs 2026-09-30 00:04:11 -04:00
Jeffrey Montoya 8438f040ac docs(security): add AgentShield evidence for GateGuard fact-force 2026-09-29 23:30:41 -04:00
drakeo338 01c9a670de fix(hooks): honor CLAUDE_CONFIG_DIR for the default agent data home
getDefaultClaudeAgentDataHome ignored CLAUDE_CONFIG_DIR and always returned ~/.claude, so sessions with a relocated Claude config dir wrote ECC data to the wrong place when ECC_AGENT_DATA_HOME was unset. Fixes #3266.
2026-09-30 03:06:16 +00:00
Jeffrey Montoya a202f31b78 docs(security): add GateGuard fact-force security evidence 2026-09-29 22:20:41 -04:00
Jeffrey Montoya 216fe89c36 feat(gateguard): write scenario gate results as SARIF 2026-09-29 22:20:41 -04:00
Gunwoo 840eb53efd chore: sync MyBatis skill triggers with current catalog 2026-09-30 10:54:59 +09:00
Jeffrey Montoya 8a1f763184 test(gateguard): create file symlinks for the hard-link case on Windows 2026-09-29 21:50:27 -04:00
Jeffrey Montoya d4045c7370 docs(gateguard): document NotebookEdit, hard links and exempt precedence 2026-09-29 21:50:27 -04:00
Jeffrey Montoya 10639a0c9e fix(gateguard): gate NotebookEdit and hard-linked targets
NotebookEdit is gated as a first-touch edit of notebook_path.
A file with more than one hard link gets no credit, trivial, sibling or cap allowance.
2026-09-29 21:50:26 -04:00
Jeffrey Montoya 4e33e29005 test(gateguard): use descriptive helper and fixture names 2026-09-29 21:50:26 -04:00
Jeffrey Montoya 7a8d8437ef test(gateguard): add comment-context and exported-member scenarios 2026-09-29 21:50:26 -04:00
Jeffrey Montoya 20eb2395e9 fix(gateguard): gate MultiEdit by its file_path and widen surface checks
Also refuses rg -z as read-only and never writes metrics through a symlink.
2026-09-29 21:50:26 -04:00
Jeffrey Montoya 6e677b008c fix(gateguard): judge comment-only edits against the file they change 2026-09-29 21:50:25 -04:00
Jeffrey Montoya 82420f061a fix(gateguard): treat directive comments and continuations as code 2026-09-29 21:50:24 -04:00
Jeffrey Montoya 42e9072136 feat(gateguard): credit test files by their module stem
Drop the hardcoded baseline alias from the evaluation script and refresh the results.
2026-09-29 21:50:23 -04:00
Jeffrey Montoya 21ea5f96a8 feat(gateguard): profile shell scripts and Python module constants 2026-09-29 21:50:22 -04:00
Jeffrey Montoya 0301055327 feat(gateguard): build condensed code hints from the question ids 2026-09-29 21:50:21 -04:00
Jeffrey Montoya bd4584b5ed docs(gateguard): add evaluation results 2026-09-29 21:50:20 -04:00
Jeffrey Montoya 142ecf8fdb test(gateguard): replay the scenario corpus as a regression test 2026-09-29 21:50:20 -04:00
Jeffrey Montoya f7e4735cca feat(gateguard): add scenario corpus and evaluation script
Replays 16 labelled sessions against the working tree and git-ref baselines.
2026-09-29 21:50:20 -04:00
Jeffrey Montoya 4c035dd834 feat(gateguard): record opt-in decision metrics 2026-09-29 21:50:20 -04:00
Jeffrey Montoya d591999ec0 feat(gateguard): add metrics event schema and report script 2026-09-29 21:50:19 -04:00
Jeffrey Montoya 15d4f169d3 feat(gateguard): gate sensitive targets in subagents
A subagent's pass does not unlock the path for the parent.
2026-09-29 21:50:19 -04:00
Jeffrey Montoya 6f0fbb6bc9 feat(gateguard): keep session-keyed state for 8 idle hours
The project-directory fallback keeps the 30-minute window.
2026-09-29 21:50:18 -04:00
Jeffrey Montoya 77ddf9a792 feat(gateguard): pass read-only shell commands before the routine gate
The first command that can change something is still gated.
2026-09-29 21:50:17 -04:00
Jeffrey Montoya c3b2a7e627 feat(gateguard): name the closest search that did not count
One sanitized line in the denial with a reason code, from the cached turn scan.
2026-09-29 21:50:15 -04:00
Jeffrey Montoya ad0d9183ff feat(gateguard): pass comment and whitespace-only edits
The file stays unchecked, so the next code change is still gated; counted in trivial_allows.
2026-09-29 21:50:14 -04:00
Jeffrey Montoya 10f67715b1 feat(gateguard): ask code questions that fit the change
Stable question ids; local call sites instead of importers when no public
declaration is touched; data question only when the change handles data.
2026-09-29 21:50:13 -04:00