Without KILO_ORG_ID the kilo provider sends no X-KiloCode-OrganizationId
header, so the gateway bills the key owner's personal balance instead of
the org. The dry run (run 30107542234) 402'd every triage chunk with
"Add credits to continue, or switch to a free model" and silently
classified 0/187 PRs.
Hoist KILO_API_KEY + KILO_ORG_ID to job-level env, matching smoke-test.yml.
* feat: daily docs-sync bot workflow (Kilo CLI)
Adds a scheduled workflow that keeps packages/kilo-docs in sync with PRs
merged to Kilo-Org/cloud and Kilo-Org/kilocode:
- watermark.mjs derives the processing window from the bot's own PR body
marker (self-healing, no external state; 72h fallback, 14d cap)
- collect.mjs queries merged PRs via the GitHub API and applies a
deterministic pre-filter (bots, chores, docs-only PRs)
- triage.mjs classifies PRs in chunks of 25 with kilo run; failed chunks
degrade to unclassified instead of failing the run
- edit.mjs updates docs in batches of 5 PRs with kilo run, bounded per
batch; failures surface as skipped entries in the PR body
- verify runs the kilo-docs build + test suite; one LLM fix pass on
failure; still-red becomes a draft PR
- upsert-pr.mjs maintains one rolling auto-docs PR (appends while open,
fresh branch after merge), with a 15-file draft cap and a
machine-readable processed-through watermark
Also adds docs-sync.yml to the workflow allowlist in
script/check-workflows.ts.
* fix: correct kilo run invocation and auth
- message positional must come before flags: --file is multi-value and
consumes a trailing message as a file path (File not found)
- authenticate via the existing KILO_API_KEY repo secret (the kilo
provider reads it natively); drop the DOCS_SYNC_KILO_CONFIG config
secret requirement
- fix default model IDs: gateway provider id is kilo/, not kilocode/
- include stderr tail in triage/edit failure logs
* fix: handle kilo run double-printed assistant output
kilo run prints the assistant message twice (streaming render + final
summary), so stdout can contain the same JSON array back-to-back. Parse
the largest valid trailing array instead of slicing first-to-last
bracket. Verified against real chunked triage output.
* fix: reviewer-pass robustness fixes
- edit.mjs: unambiguous summary file path in the batch prompt and a
fallback read when the agent drops the docs-sync-out/ prefix, so real
edits never report as skipped
- prepare-branch.mjs: use the open auto-docs PR's actual head.ref
instead of assuming docs/auto-sync
- upsert-pr.mjs: compute the 15-file draft cap on the cumulative PR
diff (origin/main...HEAD), not just the latest commit
* fix: address Kilobot review findings
Security:
- sanitize HTML-comment sequences out of agent-generated PR body values
so a crafted value cannot forge section markers or the watermark
- draft any PR whose diff touches non-content files in packages/kilo-docs
(outside pages/ and lib/nav/) — build-executable changes force human
review before merge
- on merge conflict, keep the conflicted rolling branch untouched
(preserving human commits) and continue on a fresh dated branch that
links the old PR
Resilience:
- retry GitHub API calls on network errors and 5xx, not just 403
rate limits
- isolate per-PR collect failures instead of aborting the run
- trust watermark markers only on bot-authored PRs and clamp future
dates loudly
- validate chunk triage entries belong to their chunk before the shared
dedupe
- use changed_files for files_total and skip docs-only classification
on truncated (300+) file lists
- pipe stderr in the edit pass so failure warnings carry the real CLI
error
* fix: address second Kilobot review round
- escape pipe characters in changeRow actions (same as skippedRow)
- sanitize agent-chosen file paths before they land in draftReasons
and the PR body (residual marker-forgery path via filenames)
- log expected fetch misses in prepare-branch instead of silent catches
* feat: keep bot-authored PRs in the docs-sync digest
Release and dependency bots ship user-facing changes (e.g. JetBrains
release PRs from kilo-maintainer[bot]). The auto-docs label check and
docs-only path filter remain as the loop guards.