Commit Graph

8350 Commits

Author SHA1 Message Date
kilo-maintainer[bot] 2464bfe475 release: v7.4.3 2026-07-09 11:55:41 +00:00
marius-kilocode e55ded1941 fix(cli): clarify SWE-Pruner usage guidance 2026-07-09 13:02:33 +02:00
marius-kilocode 2aba150983 refactor(cli): generalize SWE-Pruner focus guidance 2026-07-09 12:59:04 +02:00
marius-kilocode ed36326b1f feat(cli): prune large bash outputs with SWE-Pruner 2026-07-09 12:26:37 +02:00
Marius 833d78b99c Merge pull request #12054 from Kilo-Org/fix/prompt-active-run-test-timeout
test(cli): stabilize active-run prompt test
2026-07-09 11:41:20 +02:00
Evgeny Shurakov 047364eb3c feat: add dev:local script to run CLI against local cloud dev server (#12055)
* feat: add dev:local script to run CLI against local cloud dev server

* fix(cli): validate --cloud flag has a value in dev-local.ts

---------

Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
2026-07-09 11:00:01 +02:00
Marius 61d90f166a fix(cli): exclude scoped instructions from SWE-Pruner (#12052)
* fix(cli): preserve scoped instructions during pruning

* test(cli): cover CRLF scoped instructions
2026-07-09 10:50:05 +02:00
Marius 78ac5ffc91 Merge pull request #12045 from Kilo-Org/investigate-darwin-test-failures
test(cli): stabilize process-heavy integration tests
2026-07-09 10:49:23 +02:00
kilo-maintainer[bot] 6509c66b4b release: v7.4.2 2026-07-08 20:39:16 +00:00
marius-kilocode b33e28ceb2 test(cli): stabilize active-run prompt test 2026-07-08 21:25:28 +02:00
Marius d5c75b7da9 Merge pull request #12043 from Kilo-Org/fix/10361-dismissed-question-visibility-vr2
fix: show dismissed question content in chat history
2026-07-08 18:25:45 +02:00
marius-kilocode 57e2734071 test(cli): stabilize process-heavy integration tests 2026-07-08 18:22:48 +02:00
Marius 885a994106 fix(agent-manager): defer automatic branch naming until intent is clear (#12002)
* fix(agent-manager): defer automatic branch naming until intent is clear

Agent Manager auto branch naming (PR #11741) renamed the placeholder
branch on the first user message, so a read-only question like "check if
issue #11903 was fixed?" locked the branch to investigate-issue-11903
immediately. Renaming is one-shot, so a later pivot to actually fixing the
issue could not recover the branch name.

Defer naming until there is evidence of a durable workstream:
- The first user message never triggers a rename via the send path;
  prompts 2-4 may, and after four prompts without a rename the worktree
  disarms permanently (fixing an unbounded-retry bug where null responses
  re-fired an LLM call on every message forever).
- A new idle trigger renames once when the armed session goes idle and the
  worktree already has work (dirty files or commits ahead of base), so a
  single detailed first prompt that produces edits still gets named without
  naming on message 1.
- The rename itself only runs while the session is idle: names generated
  while the agent is busy are held and applied on the next idle transition
  with all guards re-checked, removing mid-turn name-capture races.

Also tighten the CLI branch-name prompt to return null for read-only
status/verification questions as a second layer behind the structural
gates.

* fix(agent-manager): address review on branch naming

- generateOnIdle now checks the auto-naming setting before dispatching,
  matching prompt(), so a setting toggled off after arming disarms without
  a wasted LLM roundtrip.
- prompt() also suppresses dispatch while a rename is pending, closing the
  redundant-generation window the busy path left open; the generate comment
  now accurately describes both the immediate and pending rename paths.
- Expose forget(worktreeId) and call it from both worktree-removal handlers
  so the controller's pending/model/idleAttempted entries are reclaimed when
  a worktree is deleted mid-flight.
- hasWork logs the rev-list error instead of silently swallowing it, while
  still failing safe to false (placeholder name kept).
- Reword the CLI prompt's null condition to a clear "only ask a question and
  do not describe work to perform", dropping the vague temporal clause.

* fix(agent-manager): clean busySessions in forget and call before worktree removal
2026-07-08 18:08:58 +02:00
Marius 81c7bd18ee Merge branch 'main' into fix/10361-dismissed-question-visibility-vr2 2026-07-08 18:05:56 +02:00
V Keerthi Vikram dfa712d989 feat: add AI image generation tool (#11826)
* feat: add AI image generation tool

Port the legacy generate_image tool to the opencode-based CLI as a
Kilo-owned tool gated by experimental.image_generation config flag.

- New generate_image tool with prompt/path/image/model params
- Routes through Kilo Gateway (zero-config) or BYO OpenRouter key
- Supports text-to-image generation and image editing
- Dynamic model discovery via GET /kilo/models/images endpoint
- VS Code settings toggle + live model dropdown in Experimental tab
- Writes image to disk and returns inline FilePart attachment
- Fallback model catalog for offline resilience

* refactor: change default image model to openrouter/auto

* fix: address bot review feedback

- Remove unused fetchKiloImageModels import in tool
- Normalize jpg→jpeg MIME in parser, input image, and attachment
- Replace mismatched extensions in ensureExtension (not just append)
- Add assertExternalDirectoryEffect for output path traversal guard
- Map unauthorized errors to 401 (not 400) in image models handler
- Keep last known model list on fetch failure (don't overwrite with empty)
- Fix tool description (remove false web search claim, fix grammar)
- Remove duplicated provider resolver tests

* fix: add retry for image models request to handle backend startup race

* fix(image-generation): address kilo bot review comments

- ensureExtension replaces mismatched image extensions instead of
  appending (photo.jpg + PNG -> photo.png, not photo.jpg.png)
- Gateway /models/images normalizes errors to 400/401 matching every
  other gateway route (was leaking undeclared upstream statuses)
- Add 401 response to openapi.json + SDK types for /kilo/models/images
  to match the gateway's errors(400, 401) declaration

* fix(gateway): align /models/images error handling with other gateway routes

* refactor: switch image generation to effect HttpClient

* test: cover kilo models images endpoint in httpapi exercise scenarios

* Exclude POST-only and parameterized API endpoints from link checker

* Add ImageModelsProvider to agent manager context tree

* chore(deps): bump @openrouter/ai-sdk-provider to 2.10.0

Switches imageModel() to OpenRouter's POST /api/v1/images endpoint for
proper image usage/billing and image-specific params.

* fix: address image generation PR review feedback

- revert @openrouter/ai-sdk-provider 2.9.0->2.10.0 bump (image tool uses raw HTTP, not the SDK)
- translate image generation settings strings across all locales
- use central KILO_OPENROUTER_BASE instead of hardcoded URL fallback
- remove completed plan file

* chore: refresh source-links.md after URL refactor
2026-07-08 18:01:01 +02:00
Thomas Brugman 8ff2a163af fix: show dismissed question content in chat history (#10361) 2026-07-08 16:46:46 +02:00
Drilmo adcbe0f373 feat(opencode): experimental SWE-Pruner for task-aware tool output pruning (#11980)
* feat(opencode): experimental SWE-Pruner for task-aware tool output pruning

Adds an experimental.swe_pruner config flag (default off). When enabled,
the read and grep tools advertise an optional context_focus_question
parameter; when the agent provides it, large outputs are skimmed by the
small model down to the lines relevant to the question, with omitted
sections marked inline. Failures fall back to the full output.

Based on SWE-Pruner (arXiv:2601.16746).

* chore: regenerate source-links for swe-pruner arxiv reference

* fix(opencode): address swe-pruner review suggestions

Harden the skimmer instruction against prompt injection from untrusted
tool output, and document that pruning runs before the tool.execute.after
hook so plugins observe the model-facing output.

* feat(ui): surface SWE-Pruner activity on read/grep tool rows

The read renderer hides tool output entirely, so pruning was invisible in
the webview even though the model received the pruned output. Show a
'SWE-Pruner · kept/total' row driven by the swePruner tool metadata.

* chore: retrigger CI (flaky windows/jetbrains tests, review service delivery error)

* feat(opencode): configurable SWE-Pruner skimming model

Adds experimental.swe_pruner_model (provider/model format) with a model
selector in the VS Code Experimental tab, shown when SWE-Pruner is
enabled. Falls back to the configured small model when unset or when the
configured model is unavailable.

* fix(ui): localize the SWE-Pruner pruning indicator

Replace the hardcoded label with a ui.tool.swePruned i18n key
(interpolated kept/total) added to all 20 shared UI locales.

* chore: retrigger CI (windows bun install network timeout on tree-sitter-powershell)

---------

Co-authored-by: marius-kilocode <marius@kilocode.ai>
2026-07-08 13:44:57 +00:00
Mark IJbema 5c96360202 Merge pull request #12034 from Kilo-Org/mark/warn-leftover-opencode-config
feat(opencode): warn users about leftover opencode configuration
2026-07-08 13:51:50 +02:00
markijbema 98bf848027 docs(cli): link opencode config notice to client-neutral settings page
Point the notification at getting-started/settings instead of the CLI
platform page, and add the opencode migration callout there so the
neutral page is self-contained for VS Code and JetBrains users too.

Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
2026-07-08 11:33:36 +00:00
markijbema d3b8ae6ec5 refactor(cli): surface opencode config notice via dismissible notifications
Move the leftover-.opencode-directory detection off the always-on config
warning and into the cloud notifications list (client.kilo.notifications),
so it flows through each client's per-id dismissal: dismiss it once and it
won't return unless the directory is still present.

Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
2026-07-08 11:12:03 +00:00
Marius 9fc1a1d94c fix(cli): return a typed 422 for commit-message with no changes (#12033)
A plain Error thrown when no changes are found became an untyped
defect through EffectBridge.fromPromise, which the error middleware
masked as a generic 500 "Unexpected server error". Declare a
CommitMessageNoChangesError (Schema.ErrorClass, httpApiStatus 422)
on the endpoint and translate the domain NoChangesError defect into
that typed failure, so the real message surfaces. The extension now
shows it directly instead of prepending a redundant prefix.
2026-07-08 12:08:37 +02:00
markijbema 64c9b7e42f feat(opencode): warn users about leftover opencode configuration
Kilo no longer falls back to opencode configuration stored in `.opencode`
directories. This change adds detection for both global and project-level
opencode configuration directories and issues a warning to guide users
on how to migrate their settings to the new Kilo configuration paths.

- Implement `KilocodeConfig.detectOpencodeConfig` to identify legacy
  config locations.
- Add warning messages to the CLI configuration loading process.
- Update documentation to include migration instructions.
- Add tests to verify detection of global and project-level opencode
  configs.

Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
2026-07-08 09:36:45 +00:00
IOLOII eefd891c62 feat(commit-message): Generate commit messages in the user's selected UI language instead of always using English. (#11994)
* feat(commit-message): add language parameter to commit message generation

Add support for generating commit messages in the user's selected UI language.
The language parameter flows through the entire stack: VSCode extension passes
the selected locale, the HTTP API accepts the new field, and the generation
service appends language instructions to the system prompt for non-English
locales.

- Update CommitMessageRequest types to include optional language field
- Modify VSCode service to pass selected locale to the API
- Append language requirements to system prompt when language is not English
- Update OpenAPI specification and regenerate SDK types
- Add test coverage for language instruction generation

* feat(commit-message): add configurable language setting for AI-generated commit messages

Add a new `kilo-code.new.languageCommitMessage` VS Code setting that allows
users to choose a specific language for AI-generated commit messages,
independent of the UI language. When set to "sync" (default), the commit
message language follows the Kilo Code UI language.

- Add language selector dropdown to CommitMessageTab settings UI
- Add getCommitMessageLanguage() helper in i18n service
- Pass languageCommitMessage setting through KiloProvider to webview
- Add translation strings for all 20 supported locales

* refactor(locale): standardize commit message terminology across locale files

Replace literal translations of "commit" with the loanword form in Brazilian
Portuguese and Spanish locale dictionaries, correct a Korean typo (커AI → 커밋),
translate an untranslated English label in Norwegian, and align terminology with
conventional usage across all four affected language packs.

* style(i18n): fix prettier formatting on commit-message language strings

---------

Co-authored-by: marius-kilocode <marius@kilocode.ai>
2026-07-08 08:30:07 +00:00
Mark IJbema facc157242 Merge remote-tracking branch 'origin/main' into mark/selected-organization-default
# Conflicts:
#	packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/rpc/KiloAppRpcApiImpl.kt
2026-07-07 17:01:13 +02:00
Mark IJbema 7ea26b0ed5 refactor: apply cloud org as login-time default 2026-07-07 16:46:34 +02:00
Marius aa454ebe27 Merge pull request #12008 from Kilo-Org/feat/sandbox-writable-paths-ui-test
feat(sandbox): widen writable-paths settings input and add coverage
2026-07-07 15:55:16 +02:00
Marius a87a4e027d Merge pull request #12004 from Kilo-Org/design-reload-feature
feat: add /reload action to reboot the instance from disk
2026-07-07 14:56:58 +02:00
Christiaan Arnoldus 98583247cb Merge pull request #11969 from Kilo-Org/fix/fable-routed-model
Show actually used models when using fable
2026-07-07 14:50:24 +02:00
Mark IJbema d70977fd92 test: cover Kilo account selection defaults 2026-07-07 14:38:02 +02:00
marius-kilocode e29196c949 feat(sandbox): widen writable-paths settings input and add coverage
Widen the Additional Writable Paths input in the Sandboxing settings tab
so long filesystem paths are readable while typing, reusing the existing
wide-input variant without affecting the network toggle row.

Add tests for the sandbox_writable_paths behavior: real sandbox
enforcement that configured extra paths become writable while unlisted
paths and .git stay denied, and a config-scope test confirming the
setting is honored from global config only and dropped from project
config.
2026-07-07 14:35:34 +02:00
marius-kilocode 4ab34f1f4c test: add /instance/reload scenario to httpapi exercise
The coverage mode requires every documented endpoint to have a
scenario. Without this, test:httpapi fails with a missing scenario
for the new /instance/reload route.
2026-07-07 14:33:06 +02:00
Marius 6cdc26c1f2 Merge pull request #11995 from trim21/feat/sandbox-writable-paths
feat(sandbox): add configurable writable paths option
2026-07-07 14:24:15 +02:00
Mark IJbema 552167fc33 fix: preserve manual Kilo account selection 2026-07-07 14:08:03 +02:00
Mark IJbema b1d004d568 fix: avoid profile sync side effects 2026-07-07 13:54:38 +02:00
Mark IJbema 08f0bf6457 Merge pull request #11886 from Kilo-Org/mark/config-file-substitution-trust
fix(cli): block file/env references in untrusted project config
2026-07-07 13:37:17 +02:00
Christiaan Arnoldus 208ebfc6a7 Merge branch 'main' into fix/fable-routed-model 2026-07-07 13:36:56 +02:00
marius-kilocode 1c31d7ea49 fix: address review feedback on reload handler
- Block reload for retry and offline session states, not just busy
  (hasActiveSession rejects any non-idle state)
- Close TOCTOU race by calling store.reload inline instead of deferring
  to a pre-response handler, so the busy check and reload run in the
  same effect
- Avoid double-firing reloadAfterAuthChange: only call it eagerly for
  worktree sessions where the SSE directory check won't match; for the
  workspace root the existing SSE handler already fires it
- Replace err: any with unknown + narrowing
- Add in-flight guard to the CLI /reload plugin to prevent overlapping
  reloads from rapid double-invocation
- Remove the TaskHeader reload button (redundant with /reload slash
  command, avoids chat visual regression baseline churn)
2026-07-07 13:22:30 +02:00
marius-kilocode cef3dc7ae8 feat: add /reload action to reboot the instance from disk
Reboots the per-directory instance, reloading config, skills, agents,
commands, and MCP prompts changed on disk without restarting the
server. Sessions and history are preserved; only the per-directory
instance caches are torn down and rebuilt.

Server: POST /instance/reload wraps the existing atomic
InstanceStore.reload path (the same one project.git.init uses). The
rebuild completes before the 200 response, so clients can refetch with
no race. Returns 409 ConflictError while a session is actively
running. Emits the existing server.instance.disposed SSE event, which
the TUI and extension already use to auto-refetch.

CLI: /reload palette command calls the endpoint; the TUI already
bootstraps on server.instance.disposed.

Extension: /reload slash command, a reload button in the task header
and settings panel, and a Kilo Code: Reload Config and Skills command
palette entry. The handler clears the command cache and reuses
reloadAfterAuthChange to re-fetch config, providers, agents, skills,
and commands. Reload targets the current session's directory so Agent
Manager worktree sessions reload their own worktree instance rather
than the workspace root.

SDK: regenerate so client.instance.reload is available to external
integrations.
2026-07-07 12:38:12 +02:00
Trim21 af6bbd8c9f Update packages/opencode/src/config/config.ts
Co-authored-by: kilo-code-bot[bot] <240665456+kilo-code-bot[bot]@users.noreply.github.com>
2026-07-07 18:35:01 +08:00
trim21 e463069674 fix(sandbox): expand ~ in writable paths and restrict to global config only
- Expand leading ~ to os.homedir() in execute() before passing paths
  to the sandbox profile, so ~/tmp resolves correctly.
- Strip sandbox_writable_paths from project-scoped config overlays.
  A repo kilo.json must not be able to widen the sandbox beyond the
  user's global config intent.
2026-07-07 18:05:53 +08:00
Mark IJbema 81213b9f25 fix: respect unavailable personal Kilo accounts 2026-07-07 11:46:34 +02:00
Mark IJbema 61b9e0935c fix(cli): honor cloud-selected Kilo organization 2026-07-07 11:30:13 +02:00
Evgeny Shurakov 40790d8139 fix(cli): show remote badge in prompt status (#11976) 2026-07-07 09:32:11 +02:00
trim21 0d27eb17fd feat(sandbox): add configurable writable paths option
Add experimental.sandbox_writable_paths config option that allows users
to specify additional filesystem paths the sandbox permits writes to.
These paths are merged with the default writable paths when the sandbox
is active.

CLI: new config field + policy integration
VS Code: list input UI in the Sandboxing settings tab
2026-07-07 12:42:42 +08:00
Catriel Müller 9ce665d3ee Merge remote-tracking branch 'origin/main' into feat/cli-vim-mode-prompt 2026-07-06 16:03:20 -03:00
Catriel Müller ea0f5a044f Merge pull request #11223 from maphew/fix/cli-cloud-fork-session-import
fix(cli): import cloud sessions before validation
2026-07-06 14:44:53 -03:00
Johnny Eric Amancio b976b5a013 feat(cli): opt-in project memory (#11921)
* feat(memory): opt-in project memory — capture, recall, CLI + TUI integration

Add project memory: the standalone @kilocode/kilo-memory effect layer plus the
opencode CLI/server/TUI integration. Memory is disabled by default, so it is a
no-op until enabled (no behavior change when off).

Capture (turn-close consolidation): per-op parse salvage, secret redaction that
skips the offending op instead of aborting the batch, supersede-only auto-updates
(never model-driven deletes), correction-aware echo handling, non-LLM fallback
digests on interrupted/error turns, a shared interval throttle with idle-flush.

Recall + injection: keyword tokenizer with camelCase/compound splitting, light
stemming, and an English-first stopword filter (Unicode-aware; non-English falls
back to plain token-overlap), a live relevance floor, a budget-reserved startup
index, a session-digest catalog, and per-session prompt-cache pinning of the
injected memory block.

Surfaces: kilo_memory_save / kilo_memory_recall tools, the memory HTTP API
(contract schemas live in the package), and a status-focused TUI sidebar showing
auto-save, loaded context, and active recall, plus the /memory dialog.

* fix(memory): address PR review feedback

- C1: bump @kilocode/kilo-memory in the changeset
- C2: redact secrets before they hit the audit log (skip + salvage paths);
  redact before truncating in salvageTyped so a secret straddling the
  500-char cap can't leak an unmatched fragment; opText -> salvageText
- C3: de-abbreviate savedOperations, "changes" wording, ops.ts -> operations.ts
- C4: log.warn on the remaining silent-catch fallbacks (turn diff, memory
  context injection, tool-visibility check)
- C5: relocate memory storage from ~/.kilo to Global.Path.data, delete the
  now-dead needsDependencyInstall guard, add /memory status (root path) and
  /memory edit ($VISUAL/$EDITOR + auto-rebuild)
- C6: replace the hardcoded English stopword list with corpus-derived
  ubiquitous-term filtering (df across the user's own entries) and the
  English suffix stemmer with suffix-tolerant term matching, so recall
  noise-filtering works in any language
- C8: delete the CORRECTION_INTENT English regex; echo turns now run typed
  capture (digest stays echo-gated), bounded by the interval throttle, with
  the typed prompt as the language-agnostic content filter
- C9: exclude generated paths (dist/build/coverage/*.gen.*/*.map/snapshots)
  from the durable-diff churn fallback so generated churn can't burn a
  consolidation call
- C11: fix duplicated assert in httpapi-memory test; assert the error body
- kilo-code-bot batch: clause-boundary regex fix, byte-safe catalog
  truncation, max-length guards on remember/correct/forget payloads (text,
  query, key, sessionID), trim consistency in reconcile, param-shadowing
  rename, missing doc entry for kilo_memory_recall, dead-code removal,
  dialog UI fixes, memoryEnabledCache eviction bound, dedicated Configure
  schema, recall permission renderer, covered-session pointer cap, redact
  chat transcript before the consolidation model call, split configProtected
  metadata from disableAlways so memory-save prompts don't show config-file
  copy, drop unused MemoryService.layer provide from tool registry
- redact colon-separated low-entropy secrets too (password: hunterx),
  accepting the prose false-positive tradeoff (secret: enabled) in favor of
  not missing a real secret
- rename lastConsolidatedAt -> lastTypedConsolidationAt to make its narrow
  scope (typed-consolidation throttle clock) explicit; regen openapi/SDK
- drop now-dead home/config fields from MemoryPaths.Host after the data-dir
  relocation; add Process.splitCommand for quoted $EDITOR/$VISUAL paths with
  spaces, used by /memory edit and the pre-existing Editor.open utility

* refactor(memory): shared client helpers, capture hardening, /memory UX rework

- extract client-side derivations into kilo-memory so both frontends share
  one implementation: MemoryDecisions.summarize (decision-log summary),
  MemoryAutosaveStatus.summarize (autosave-status semantics), and
  MemoryMarkerMeta (marker wire contract encode/decode)
- match exact-key upserts via the canonical stored id (slugged key,
  normalized section) so a re-emitted spaced/uppercase key updates the
  entry instead of falling to fuzzy dedupe
- salvageTyped throws on valid JSON without an operations array so the
  caller's fallback path records a parse error instead of a silent
  zero-op success
- rename memory tool metadata files -> sources (stripPartMetadata rewrites
  tool-part metadata.files assuming apply_patch records, mangling string[])
- read state instead of status for tool enabled checks; dedupe TUI helpers
  (errorMessage, shared route(), Locale.number, relativeTime)
- /memory UX: bare /memory opens a help modal driven by a structured
  command catalog in kilo-memory; /memory on|off become the canonical
  toggle verbs (enable/disable kept as quiet aliases); /memory status opens
  a clean overview dialog (root path, autosave, startup context, source
  counts, index size) instead of a toast; /memory show is the single full
  audit view (inspect removed)
2026-07-06 17:45:49 +02:00
Christiaan Arnoldus dc99ae8f79 fix(cli): route fable model aliases 2026-07-06 15:55:31 +02:00
Evgeny Shurakov cd49ae633c CLI - Remote model catalog and WebSocket reconnection fixes (#11835)
* feat(cli): remote model catalog and WebSocket reconnection fixes

* fix(cli): preserve provider default semantics under truncation and deflake reconnect test

* fix(cli): omit provider default when per-provider truncation removes preferred model

* refactor(cli): simplify remote model catalog by removing size limits

* refactor(cli): strip remote model catalog to sanitize-and-shape only

* fix(cli): cap remote model catalog at MAX_MODELS

* fix(cli): preserve model metadata and enforce remote catalog limits

* fix(cli): omit currentModel and defaultModel when truncation drops them

* fix(cli): keep stable connection identity across reconnects

* feat(cli): include protocol version in remote session heartbeat
2026-07-06 14:48:30 +02:00
Mark IJbema 8dad071203 fix(cli): surface scope-blocked {file:} even under missing:empty; cover guard
Agent prompts substitute with missing:"empty", which swallowed every file read error — including a deliberate out-of-scope scope block — so an escaping {file:} was silently emptied and never warned, contradicting the agent.ts catch narrative. Tag security blocks as ConfigVariableGuard.BlockedError (out-of-scope, fd swap, /proc) and, in substitute(), always reject those regardless of missing:"empty"; genuine missing/IO errors are still emptied. Now an out-of-scope {file:} in an agent prompt rejects, hits the agent catch, and records a warning. Adds guard/substitute tests for the block-under-missing:empty, missing-is-emptied, and BlockedError classification cases.
2026-07-06 13:37:39 +02:00