Commit Graph
7028 Commits
Author SHA1 Message Date
Marius 4c0fcb0b43 Merge pull request #12687 from Kilo-Org/yielding-newsboy
fix(cli): remove unset config keys from every layered config file
2026-07-30 13:07:19 +02:00
Marius 6f9ee943da Merge pull request #12599 from Kilo-Org/remove-unused-cli-code
refactor(cli): remove provably unused kilocode code
2026-07-30 12:54:00 +02:00
marius-kilocode 624b5890f1 fix(cli): remove unset config keys from every layered config file 2026-07-30 12:18:42 +02:00
Igor Šćekićandkiloconnect[bot] d579774960 fix(ci): docs-sync bot passes --auto, drains its backlog, and reports readable causes; fix(cli): honest exit codes for headless runs (#12605)
* fix(ci): pass --auto to the docs-sync kilo runs and keep full stderr logs

Headless kilo run auto-rejects every permission ask it receives, and the
GitHub runner has no user config granting bash — so without --auto the
docs-sync bot's triage, edit and verify-fix calls were silently crippled
whenever the agent reached for a non-allowlisted shell command (CI run
30306629290: 9 rejections, all 11 edit batches failed, exit 0).

- Pass --auto immediately after "run" at all three call sites
  (triage.mjs, edit.mjs, docs-sync.yml Fix verify failures step)
- runKilo now always writes the child's full stderr to
  docs-sync-out/kilo-stderr-<label>.log, on success as well as failure —
  the blindness that hid the defect
- selftest asserts --auto non-vacuously (region-scoped source match +
  a stub invocation that records argv) and proves the stderr log is
  written on both the failure and the summary-writing success path

* fix(cli): exit nonzero when a headless run auto-rejects or its session errors

Non-interactive kilo run reported success for runs that accomplished
nothing — a caller cannot distinguish success from a dead run, which is
why the docs-sync bot had to stop trusting exit codes entirely.

- Plain headless run (neither --auto nor --dangerously-skip-permissions)
  in which the CLI auto-rejected at least one permission ask now exits
  non-zero, even when the session still reaches idle afterwards, with
  the diagnostic: run ended with an auto-rejected permission; pass
  --auto for autonomous use. Deliberate contract change: any
  auto-rejected ask means the run was crippled, not successful.
- A mid-stream session error now writes its diagnostic to stderr before
  emitting the json error event, so the cause is visible under
  --format json as well (the emit-first shape skipped the stderr write).
- The old exit-0 contract lock-in test is replaced: its llm.fail fixture
  never published a consumable session.error, so it locked in a false
  premise. New tests cover both scenarios in both output formats;
  happy-path and --format json runs still exit 0 unchanged.

* fix(ci): redact secret env values from persisted kilo stderr logs

The full-stderr capture added for observability lands in uploaded CI
artifacts, which are raw files (GitHub masks secrets in log streams
only) on a public repo, and the runner env holds a long-lived
KILO_API_KEY. Redact exact values of KEY|TOKEN|SECRET-named env vars
(len >= 8) once at capture, so both the console tail and the artifact
file are safe. Adds the changeset for the headless exit-code contract
change.

* fix(ci): redact secrets from persisted kilo stdout and harden redaction

The docs-sync workflow uploads docs-sync-out/ as a public 14-day artifact,
and kilo stdout was persisted raw there in two more places: triage-raw-*.txt
and the edit-log.txt tee. Redact at capture in runKilo for stdout as already
done for stderr, and pipe the verify-fix step's kilo stdout through a new
line-wise redact-stream.mjs filter before tee.

Also harden redactEnvSecrets: widen the name pattern to
KEY|TOKEN|SECRET|CREDENTIAL|PASSWORD|ORG_ID|_PAT (KILO_ORG_ID is a repo
secret), replace longer values first so a short secret that prefixes a
longer one cannot leak the remainder, and document the exact-substring
limitation. Selftest gains cases 2e (prefix ordering), 2f (stdout capture),
2g (stream filter) and a non-vacuous exact-line assertion in 2d.

* fix(cli): correct the headless-exit changeset's json-format claim

The auto-reject path adds a new error event to the --format json stream;
only the existing event shapes are unchanged. Also state that the exit-1
rule covers a plain non-interactive --attach run that auto-rejects an ask.

* fix(ci): document --auto security trade-off and deferred hardening

Update comments in triage.mjs and edit.mjs to accurately describe the
security implications of --auto (unrestricted bash for an agent steered
by external PR content) and note that a scoped permission.bash map via
KILO_CONFIG_CONTENT is the intended hardening, deferred until required
shell patterns are stable.

* fix(ci): raise docs-sync budgets so the backlog can actually drain

--auto fixes the batches the bot attempted; it does not fix the ones it
never started. In run 30306629290 (254 PRs collected, 51 docs-worthy),
the wall-clock budgets deferred 54 PRs untriaged and 31 unedited without
an attempt — 45 of the 60 pending rows on the rolling PR. Triage got 8 of
11 chunks in 35 min; edit got 4 of 11 batches in 50 min.

Both are ceilings, not costs. A caught-up run needs ~2 chunks and ~1
batch and finishes in ~25 min, so raising them spends nothing on a normal
day and drains the backlog on a bad one. 90/120 covers 20 chunks and 14
batches — 500 triaged and 70 edited PRs against a ~5 docs-worthy/day
inflow — inside a 240-minute job timeout.

Also strip ANSI CSI sequences in tailText, the shared path both triage
and edit route their pending causes through. kilo renders its TUI to
stderr, so every "Why" cell on the rolling PR currently reads
"^[[0m→ ^[[0mRead packages/..." instead of the diagnostic. The persisted
docs-sync-out/kilo-stderr-*.log stays raw as the debugging record.

selftest case 2h asserts the pending reason is escape-free and still
carries the diagnostic text; case 2i asserts each budget fits at least
two units and the job timeout outlasts both, so a future edit cannot
silently restore a budget too small to run anything. Both shown failing
on the unmodified code first.

* fix(ci): keep the docs-sync rebuild authoritative in the fix step

The "Fix verify failures" step runs under `set -o pipefail` and the
default `bash -e`. Once the CLI half of this PR ships, `kilo run` exits 1
on a mid-stream session error, which aborts the block before the rebuild
runs: verify2.log is never written and `Re-verify status` reports
VERIFIED=false even when the docs build fine. A transient provider error
would flip every rolling docs PR to "Verification: failing".

The agent's exit code was never the signal for this step — the rebuild
is. Guard the pipeline with `|| echo ::warning::` so a nonzero kilo run
is surfaced but the rebuild still decides the outcome.

Extends selftest case 2b (which already parses this step) rather than
adding a case: the guard must appear between the pipeline's tee and the
rebuild, so a comment elsewhere in the block cannot satisfy it. Shown
failing with the guard removed.

---------

Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
2026-07-29 15:34:41 +00:00
Marius 5b5f96a52b Merge branch 'main' into remove-unused-cli-code 2026-07-29 14:03:07 +02:00
Marius e4fcb061bf Merge pull request #12639 from Kilo-Org/fix-premature-stop-warning-flicker
fix(vscode): stop flashing interruption warning on queued follow-up handoff
2026-07-29 13:07:42 +02:00
marius-kilocode 8a47d8b788 fix(vscode): stop flashing interruption warning on queued follow-up handoff
A prompt sent while a session is running queues behind the active turn,
which breaks out of its loop after the current LLM step drains. That
handoff was recorded with close reason "interrupted", so the webview
rendered the yellow "Turn interrupted." card during the brief idle
window before the queued turn started.

The handoff now closes with a dedicated "superseded" reason instead.
Clients extend their close-reason unions and the webview suppresses the
terminal warning card for superseded turns; memory digests still treat
the cut-short turn as interrupted, and real user interruptions are
unchanged.
2026-07-29 12:31:47 +02:00
Aarav 92076e7071 feat(tui): register /auto-approve slash command for toggling auto-approve mode (#12444)
* feat(tui): register `/auto-approve` slash command for toggling auto-approve mode

The TUI already exposed auto-approve mode toggling through the command
palette (Ctrl+P -> "Enable/Disable auto-approve mode" backed by
`Permission.allowEverything`), but there was no slash command for it.

Promote the existing `permission.allow_everything` palette entry to a
slash command by adding `slashName: "auto-approve"` plus a few common
aliases (`autoapprove`, `approve-all`, `approveall`) and a `desc` for
autocomplete. The slash command dispatches the same palette entry, so
behavior, gating, and toasts stay identical to the Ctrl+P path.

- packages/opencode/src/kilocode/cli/cmd/tui/app.tsx

* fix(tui): clarify /auto-approve desc reads from global config
2026-07-29 12:08:40 +02:00
Marius e80b3b2b04 Merge branch 'main' into remove-unused-cli-code 2026-07-29 10:51:30 +02:00
Christiaan Arnoldus 782b85d219 Merge branch 'main' into fix/exclude-gpt-5-6-chatgpt 2026-07-29 10:40:38 +02:00
Aarav c0ebf98778 feat(opencode): route websearch Exa through Kilo proxy (#12470)
Add a new Kilo-REST Exa transport alongside the existing MCP-Exa
and MCP-Parallel transports. When the websearch tool picks the Exa
provider and the user is signed into Kilo, requests go to
https://app.kilo.ai/api/exa/search with the user's Kilo bearer.
The cloud proxy injects its own Exa API key; the client sends the
user's Kilo API key as a Bearer token. The MCP-BYOK path (EXA_API_KEY)
and MCP-unauthed fallback are preserved unchanged.

Changes:
* New `packages/opencode/src/kilocode/tool/websearch-kilo-exa.ts`
  implements `callKiloExa` against the Exa REST API
  (`POST /search`) with `{ highlights: true }` contents and clamps
  numResults at 10 (Exa's first-10-results flat $0.007 tier).
* `packages/opencode/src/tool/websearch.ts` adds a `"kilo-exa"`
  provider variant (selected only via `KILO_WEBSEARCH_PROVIDER`
  override), an Auth.Service yield to source the Kilo bearer, a
  transport-dispatch block that prefers Kilo-REST over MCP when
  auth is available and EXA_API_KEY is unset, and `transport`
  metadata on the tool part. MCP-Exa numResults is now clamped
  at 10 (default stays 8).
* 13 unit tests in
  `packages/opencode/test/kilocode/tool/websearch-kilo-exa.test.ts`
  cover request shape, response formatting, error handling, and
  the costDollars ignore case.
* Parameters snapshot updated for the new numResults description
  string.
* Patch-level changeset added.
2026-07-29 10:07:24 +02:00
Christiaan Arnoldus 9203f47f21 Merge branch 'main' into fix/exclude-gpt-5-6-chatgpt 2026-07-28 15:50:06 +02:00
Aarav 290a5af56e fix(cli): include credentials in console URLs printed for headless users (#12333)
The headless path printed `${urls.local}/console` and `${urls.network}/console` without basic-auth credentials, leaving remote or display-less users unable to reach the console.

Rename `browserUrl` to `withCredentials(base, state)` so credentials are embedded into any base URL, and use it for both the printed Local/Network URLs and the in-process browser launch (which previously used `state.url` directly and now matches what the user would see if they copy/pasted the Local URL from the terminal).
2026-07-28 14:45:10 +02:00
Christiaan Arnoldus dab2e79d6e fix(cli): exclude gpt-5.6 from ChatGPT subscriptions 2026-07-28 14:44:40 +02:00
Whitebeard 1310c1200a fix: make snapshot diffs resilient on Windows (#12583) 2026-07-28 14:23:47 +02:00
marius-kilocode 526572c6c0 Merge branch 'main' into remove-unused-cli-code 2026-07-28 13:42:24 +02:00
marius-kilocode b0a546049e refactor(cli): remove provably unused kilocode code
Delete code with zero references anywhere in the monorepo (including
tests, docs, scripts, and dynamic import or string-based usage):

- background-process/windows-job.ts: entire Windows Job Object FFI
  module left unreferenced after the background process runner refactor
- session/prompt.ts: createShellDecoders helper, CODE_SWITCH_TEXT alias,
  and the now-unused StringDecoder import
- text-stream.ts: openUtf8 wrapper
- cli/cmd/tui/component/prompt/vim.ts: enterInsert helper
- config/config.ts: KILO_CONFIG_FILES, AGENT_PATTERNS, COMMAND_PATTERNS
- remote-attachments.ts: TEXT_PLAIN constant
- plan-followup.ts: PLAN_PREFIX constant
- server/httpapi/groups/background-process.ts: SessionParams schema
- server/httpapi/groups/session-import.ts: SessionImportPayloads map
- cloud/contracts.ts: RepositoryInput type alias
2026-07-28 13:42:15 +02:00
Marius fb5f5ae31b Merge pull request #12593 from Kilo-Org/profile-active-kilo-sessions-cpu-usage
fix(vscode): avoid eager worktree watchers
2026-07-28 13:05:29 +02:00
marius-kilocode 8f4b146103 fix(vscode): use normalized client flag 2026-07-28 12:55:41 +02:00
marius-kilocode 160b06661a fix(vscode): avoid eager worktree watchers 2026-07-28 12:48:30 +02:00
Marius fc04f4f6ff Merge branch 'main' into reproduce-and-fix-revert-file-rollback-bug 2026-07-28 11:27:54 +02:00
marius-kilocode 2c61d29fb7 fix(cli): compensate checkpoint restore failures 2026-07-28 11:09:55 +02:00
Marius c21b01f25a Merge pull request #12460 from Kilo-Org/marius-kilocode/kilo-opencode-v1.17.9
chore(opencode): merge v1.17.6 through v1.17.9
2026-07-28 11:03:04 +02:00
Marius f336cfee0a Merge pull request #12588 from Kilo-Org/fix/provider-first-byte-timeout
fix(cli): prevent agent-loop freeze when a provider stalls after headers
2026-07-28 11:00:52 +02:00
marius-kilocode 60217b482d Merge remote-tracking branch 'origin/main' into marius-kilocode/kilo-opencode-v1.17.9 2026-07-28 10:43:36 +02:00
marius-kilocode deddf0012f fix(cli): bound provider first response byte by the request timeout
A provider can accept a request, return response headers, and then never
send a byte of body data. The connection-phase request timeout was cleared
as soon as headers arrived, so nothing bounded that wait and the agent turn
hung indefinitely after a tool call completed: step-finish:tool-calls was
recorded and the next step-start never arrived, with the HTTP server still
responsive.

Extend the same configured timeout deadline to the wait for the response
body's first byte. The connection-phase timer covers the fetch up to
headers; once headers arrive, the remaining deadline is handed to a
first-byte guard that aborts the request if no data arrives. After the
first byte the guard becomes a passthrough, so idle gaps inside an already
streaming response (reasoning, buffering, slow token generation) are never
touched and remain opt-in via chunkTimeout.

This is a transport-level signal (bytes on the wire, before any content)
rather than the absence of normalized AI SDK events, so it cannot fire on
long prompt processing or reasoning the way the reverted stream watchdog
did. timeout: false still disables the bound entirely.

Adds a hermetic regression test that injects a simulated stalled socket
through the provider's own fetch option via the plugin config hook, so the
SDK, Kilo's fetch wrapper, SSE parsing, the processor and the agent loop
all stay production code. The stalled request is transient, so the test
asserts the turn recovers by retrying and completing instead of freezing.
The test goes red without the fix (no retry, frozen at step-finish) and
green with it.

Refs #8656
2026-07-28 10:35:56 +02:00
marius-kilocode 16f8e7ef7f fix(cli): keep session reverts atomic 2026-07-28 10:34:40 +02:00
Marius a0a760e00e fix(cli): enforce permissions on shell commands the parser fails to scan (#12585)
* fix(cli): enforce permissions on shell commands the parser fails to scan

* fix(cli): fail closed on error chunks without command names, move pwsh execution test to kilo file
2026-07-28 09:50:32 +02:00
Igor Šćekić b2735bfbc9 fix(cli): flush the session ingest tail on shutdown (#12545)
* fix(cli): drain session ingest queue on shutdown and flush terminal batches promptly

* fix(cli): drain the session ingest queue on process shutdown

* fix(cli): pin drain bound expiry, add changeset, conform to naming rule

* fix(cli): keep kilo-sessions out of the CLI startup import graph

* fix(cli): never let the ingest drain task reject the shutdown sequence

* test(cli): pin drain-before-dispose ordering on the KiloCli shutdown path

* fix(cli): make the guarded ingest drain non-rejecting and correct the lazy-import rationale

* test(cli): cover the retryable-status drain path under shutdown

* test(cli): decouple cli-shutdown drain assertions from declaration order
2026-07-27 11:12:42 +02:00
marius-kilocode 28f2abe5e9 Merge remote-tracking branch 'origin/main' into marius-kilocode/kilo-opencode-v1.17.9 2026-07-27 08:11:14 +02:00
chrarnoldusandkiloconnect[bot] 8aeff4856f fix(cli): cover future sonnet adaptive versions
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
2026-07-26 20:50:52 +00:00
chrarnoldusandkiloconnect[bot] a69a7cc5c4 fix(cli): cover future opus adaptive versions
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
2026-07-26 20:03:01 +00:00
chrarnoldusandkiloconnect[bot] b8d83fb537 fix(cli): support adaptive thinking for opus 5
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
2026-07-26 19:36:51 +00:00
Igor Šćekić a19d44c3ef Advertise the instance from enableRemote and report attention status on the heartbeat (#12532)
* fix(cli): advertise the instance from enableRemote so /remote registers as a spawn target

Enabling the remote relay from the TUI `/remote` slash command connected the
socket and mirrored sessions, but never advertised the instance, so the CLI
never appeared as a spawn target in the mobile "Run on" picker. Only the
explicit `kilo remote` command called setInstanceAdvertisement.

The advertisement now runs on every successful enableRemote() entry, before the
already-connected and coalescing early returns. That ordering matters: bootstrap
auto-enable frequently connects first, so `/remote` usually hits
`if (remote) return` and an advertisement placed in the connection-setup body
would leave the defect unfixed in the common case. `ingestDisabled` returns
before the advertisement and stays unadvertised.

The ensure helper is a no-op when an advertisement is already set, so it fires no
extra heartbeat, while explicit setInstanceAdvertisement keeps its existing
replace semantics. buildInstanceAdvertisement moves to a shared module so the
command path and the enable path derive it identically.

* fix(cli): report pending question and permission on the session heartbeat

The heartbeat built each session's status from SessionStatus.Service, whose
union is idle/retry/busy/offline and which never consults Question.Service or
Permission.Service. deriveStatus() already did consult both, but only fed the
ingest session_status sync. So a session genuinely blocked on a question was
advertised as busy on the heartbeat, and the mobile app — which takes live row
status from the heartbeat — showed no needs-input badge.

Extract the precedence (permission, then question, then SessionStatus) into a
shared helper used by both deriveStatus and the heartbeat, so the two channels
cannot drift.

The heartbeat runs on a ~10s timer across every session, and deriveStatus makes
service calls per session, so the permission and question lists are fetched once
per tick and indexed by session id rather than queried per session. A test pins
the call count.

Behaviour note beyond the strict fix: sharing the derivation also means a
SessionStatus of offline now reports as retry on the wire, matching what
deriveStatus has always sent to ingest. Nothing consumes offline from the
heartbeat — the transport forwards only idle and busy, and the mobile row treats
both as non-attention — so the effect is that the two channels now agree. The
detach fence test is parameterised accordingly; its assertion that the status
clears on detach is unchanged.

* chore(cli): widen the promise-facade allowlist for the heartbeat attention tests

The DEF-3 heartbeat tests raise and reply to real Question and Permission
requests through the global AppRuntime, which took kilo-sessions.test.ts from 4
classified references to 29 and failed the allowlist check.

Bumping the count rather than restructuring the tests is deliberate: the
heartbeat resolves attention status from the global Question.Service and
Permission.Service, so asserting it requires driving those same services.
Scoped layers cannot express that — the global-runtime coupling is the thing
under test — and it is the same integration pattern this entry already
sanctioned for the detach fence. The reason string records that.
2026-07-25 15:45:43 +02:00
Joshua Lambert eab61d853a Merge pull request #12505 from Kilo-Org/fix/run-duplicate-events
fix(cli): emit run events once
2026-07-24 19:48:51 -04:00
LCZcn96 c72817e67f fix(cli): bound skill discovery in non-git projects (#12475) 2026-07-24 16:31:31 +02:00
Bruno Agatao 9c16457083 Merge remote-tracking branch 'origin/main' into feat/explain-tool-auto-approval 2026-07-24 14:27:39 +02:00
Marius 470d78bfac Merge branch 'main' into fix/preserve-other-finish-reason 2026-07-24 14:02:52 +02:00
marius-kilocode 64343089d8 chore: merge latest main 2026-07-24 13:12:52 +02:00
marius-kilocode 3d2036a379 fix: preserve Kilo repository links 2026-07-24 12:57:47 +02:00
marius-kilocode 1b60773cae fix: resolve OpenCode merge regressions 2026-07-24 12:56:42 +02:00
Johnny Eric Amancio 0fe46ecb8d fix: recover from read-only database files at startup (#12508) 2026-07-24 12:51:05 +02:00
marius-kilocode 40fd27d22a fix(cli): validate persisted Vercel request IDs 2026-07-24 12:42:15 +02:00
Bruno Agatao 0eb9face86 Merge remote-tracking branch 'origin/main' into feat/explain-tool-auto-approval 2026-07-24 12:35:42 +02:00
Bruno Agatao b36b24e827 fix(cli): track auto-approval provenance per permission pattern, not per key 2026-07-24 12:32:33 +02:00
marius-kilocode d29f1bdd43 fix(vscode): show both response identifiers 2026-07-24 12:21:21 +02:00
marius-kilocode 2fcb137ebc fix: preserve unexpected provider finish reasons 2026-07-24 12:20:43 +02:00
Marius e6f4216088 Merge pull request #12497 from Kilo-Org/revert/stream-stall-watchdog
revert(cli): restore opt-in stream idle timeouts
2026-07-24 12:13:37 +02:00
Bruno Agatao 7f37d015ed fix(cli): tag permission rules by origin so auto-approval provenance is accurate 2026-07-24 12:12:58 +02:00
Christiaan Arnoldus a4177125b8 Merge pull request #12485 from rakshith1928/fix/12477-compaction-maxoutputtokens-leak
fix(core): strict OpenAI-compatible compaction failure caused by maxOutputTokens leak into provider options
2026-07-24 11:13:50 +02:00