0e4e446fe43b59c176d420414cb9bcb338f22613
33
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
256ff2528e |
test(config): two e2e routing tests stop racing KIGI_CODE_BASE_URL
`e2e_default_model_with_session_routes_to_proxy` and `e2e_duplicate_model_field_both_entries_survive` assert the default model's base URL. They were not serial and read `KIGI_CODE_BASE_URL` through `EndpointsConfig`, while two serial tests (auth_method.rs, models_fetch.rs) point that variable at wiremock. When the runs overlapped, the base URL came back as the wiremock URI: the Linux suite failed in 2 of 13 full runs. Presetting the variable fails both tests every time, on v0.1.15 as well. Both tests are now `#[serial]` and unset the variable for their scope, the same cure `e2e_enterprise_endpoints_only_no_model_override` got for the moonshot variable. With the variable preset they pass. |
||
|
|
00a5e318bb |
fix(config): an explicit [model.X] api_backend survives same-slug propagation
The slug-match step treated an entry whose api_backend equals the default as unset and overwrote it with a same-slug sibling's backend, so `api_backend = "chat_completions"` silently became messages/responses. Config keys whose override sets api_backend are recorded and skipped by the donor step; an unset backend still inherits. Ported from upstream 1.0.22 (grok-build agent/config.rs explicit_api_backend_keys). Claude-Session: https://claude.ai/code/session_01RUqV8HVGXcAETyYbZ2tPQ4 |
||
|
|
1ae803519e |
fix(compaction): configurable summarizer tool_choice; wider overflow detection
Port of upstream grok-build 0.2.105 + 0.2.118. - CompactionToolChoice (auto default | none), resolved env KIGI_COMPACTION_TOOL_CHOICE > [features].compaction_tool_choice > remote settings. Some OpenAI-compatible servers reject tool_choice:"none" with tools attached, failing every long-session compaction; auto keeps them working (the summarization prompt already forbids tool use). Threaded from agent + subagent spawn through CompactionConfig into generate_session_compact; the Responses gate counts hosted tools too, so a hosted-only request still carries the configured choice. - is_context_length_error recognizes the "current message ... exceeds budget" phrasing, so that overflow is Fatal instead of burning the retry budget on a deterministic failure. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KSy9S31pZNWXtRZNVJ1sDf |
||
|
|
a02b555e66 |
docs(comments): rewrite comments across all crates to the guidelines
Sweep every first-party crate source (1956 .rs files) to the project comment guidelines: delete redundant restatements, decorative banners, change narration, and end-of-line comments; keep and tighten the crucial ones (invariants, bug rationale, SAFETY blocks, ported-source attribution). No functional code changed. Every edit is proven comment-only against the prior tree by a comment-stripping lexer (string/char/raw-string aware) plus a separate doctest-fence check. Where removing a comment made rustfmt or clippy want to re-lay-out adjacent code, the minimal triggering comment is restored so code tokens stay byte-identical. Gates green: cargo fmt --all --check (0 diffs), cargo check and cargo clippy --workspace --all-targets (0 warnings). Adds scripts/check_codegen_comment_guidelines.py — the enforcement gate for these guidelines (flags banners, end-of-line comments, change narration, and commented-out code). |
||
|
|
301eb61de4 |
fix(chat): BYOK dialect defaults to Passthrough; dedicated Mistral dialect
C1 (decision): custom/BYOK ChatCompletions entries defaulted to the Kimi
dialect, leaking Kimi-specific body mutations (thinking:{…} control,
replayed reasoning_content, schema rewrites) to arbitrary third-party
OpenAI-compatible servers. The default is now Passthrough (vanilla
OpenAI semantics), with ONE exception mirroring Pi's base-url quirk
sniffing: entries pointed at the house/Kimi coding endpoint keep the
Kimi dialect. Registry platforms are unaffected (all declare
explicitly).
C2 (Pi mistral-conversations normalizer): Mistral requires tool-call ids
of EXACTLY nine [a-zA-Z0-9] chars; even same-session synthesized UUIDs
violate it. New ChatCompat::Mistral = StrictOpenAi behavior + the
normalizer — strip non-alphanumerics, keep exact-9 ids, else FNV-1a →
base36 (build-stable, deterministic across requests for prefix-cache
stability) with collision retry; ONE map covers tool_calls[].id and
tool_call_id so pairing survives. The mistral registry row and the
persisted 'mistral' serde value both resolve to it (pre-rename Mistral
sessions gain the contract automatically); Cerebras/NVIDIA stay on
StrictOpenAi untouched.
Verified: models+sampling-types+sampler+chat-state+shell all green,
clippy clean.
|
||
|
|
10149f50dd |
install: stop persisting KIGI_GRAPH — the binary default is the product default
The README always shipped graph engineering enabled; the enablement was
delegated to installer env plumbing that diverged per platform:
install.sh exported KIGI_GRAPH=1 into shell rc (worked), install.ps1
wrote the User registry variable — which running Windows terminals (and
new tabs of an open Windows Terminal) never pick up, so /graph was
'missing on Windows' despite a successful install.
With resolve_graph() defaulting true in the binary (
|
||
|
|
e53a66d113 |
feat(graph): /graph ships on by default — end the KIGI_GRAPH gray release
Release / build (x86_64-unknown-linux-gnu) (push) Failing after 6s
Release / build (aarch64-apple-darwin) (push) Canceled after 0s
Release / build (aarch64-unknown-linux-gnu) (push) Canceled after 0s
Release / build (x86_64-apple-darwin) (push) Canceled after 0s
Release / build (x86_64-pc-windows-msvc) (push) Canceled after 0s
Release / publish GitHub Release (push) Canceled after 0s
resolve_graph() read only the KIGI_GRAPH env var with default(false) (plan.md G0 gate), so /graph existed solely on machines whose environment exported the dev flag — which presented as '/graph is missing on Windows'. There was never any platform-conditional code: the Mac worked because the dev env var was set there. Default is now true (matching /goal's shipped state); KIGI_GRAPH=0 remains the off-switch, and availability still requires the goal harness (BuiltinGate::Graph). AGENTS.md updated; new test pins fresh-install-on plus env-zero-off. Verified: kigi-shell 5262 + kigi-tui 6874 tests green, clippy clean. |
||
|
|
63ff114f71 |
feat(model-picker): each row names its connected provider
The shell stamps meta.provider (platform display name via
parse_managed_model_key) on every managed {platform}/{model} catalog
entry in to_acp_model_info; user-defined [model.*] entries stay
provider-less. The /model dropdown surfaces it in the description column
(a model's own description still wins), so the picker reads as 'choose a
model from your connected providers'.
Verified: kigi-shell 5261 + kigi-tui 6873 tests green, clippy clean.
|
||
|
|
48d89c7830 |
refactor(auth): centralize inference-credential routing in CredentialAuthority
One authority answers 'which credential may ride this request': credential_class / manager_for / credential_for / bearer_resolver_for, keyed by (platform, base_url). SessionCredential is an opaque type with no production constructor, so a new call site cannot re-introduce the session-bearer leak. Platform-scoped tests extended across all bearer channels (session, aux, summary, subagent override). Verified: cargo check --workspace --all-targets clean; kigi-shell and kigi-tui suites green (6611+ tests). |
||
|
|
2d00a4e6e6 | update | ||
|
|
422e241e13 |
feat(providers): add ChatGPT/Codex subscription OAuth (PKCE + account-id, hardcoded catalog)
29th platform `openai-codex` (uses_oauth, Responses wire). PKCE-localhost login at auth.openai.com (client app_EMoamEEZ73f0CkXaXp7hrann, redirect localhost:1455/auth/ callback, form token exchange, fresh-random state) reusing the claude-pro-max flow; OAuthFlow::PkceLocalhost gained a redirect_path and OAuthConfig an authorize_extra (empty elsewhere, so claude/xai/copilot authorize URLs stay byte-identical). Codex-specific: the access token is a JWT carrying chatgpt_account_id, which becomes the `chatgpt-account-id` inference header. It is derived STATELESSLY from whichever bearer rides each request (so a rotated token needs no persisted field), and BOTH login and refresh fail fast when the claim is absent — gated on the explicit OAuthConfig.requires_chatgpt_account_id fact, never inferred from the token-body encoding (a plain form endpoint is the OAuth norm and must not inherit this). Inference rides the existing Responses wire at chatgpt.com/backend-api/codex → /responses, with codex headers (chatgpt-account-id, originator, OpenAI-Beta responses=experimental, codex UA) gated on SamplerConfig.openai_codex so API-key `openai` stays byte-identical; store:false was already the global Responses default. Catalog is HARDCODED (no live endpoint exists for this backend; read from the official Codex CLI's model cache): gpt-5.6-sol/terra/luna + gpt-5.5, ctx 272000, each with its real reasoning levels (low..ultra — ReasoningEffort gained Ultra). Excluded: gpt-5.3-codex-spark (supported_in_api=false), gpt-5.4/-mini and codex-auto-review (hidden) — they would list but fail at inference. The fetch short-circuits before any HTTP; Kigi never shells out to the codex CLI or reads ~/.codex. Security review fixes: redact any `account-id` header from request logs (it was reaching debug logs), strict 3-segment JWT check (fail closed), refresh no longer fails open on a missing claim. Inherits leak-safe pooled routing (scope oauth/openai-codex) — never the Kimi token. Full gate green (234 suites, 0 warnings). |
||
|
|
8179438278 |
feat(providers): add GitHub Copilot subscription OAuth (device flow + copilot-token re-mint)
28th platform `github-copilot` (uses_oauth, ChatCompletions wire). Two-stage auth: RFC-8628 GitHub device flow (client Iv1.b507a08c87ecfe98, scope read:user, errors in a 200 body) mints the DURABLE github token; a GET api.github.com/copilot_internal/ v2/token exchange re-mints the SHORT-LIVED copilot token. Persisted as key=copilot token, refresh_token=github token, expires_at=copilot expiry; the "refresh" is a copilot-token re-mint (not a refresh_token grant), dispatched via OAuthTokenBody::GithubCopilotExchange in the generic refresher. VS Code editor-identity headers on /models + /chat/completions, gated on SamplerConfig.github_copilot / PlatformId::sends_copilot_editor_headers() so every other ChatCompletions provider stays byte-identical. Live /models filtered (parse_github_copilot_listing) to the openai-completions-served models: keep iff model_picker_enabled && policy.state!="disabled" && tool_calls!=false AND not a claude-4.x/5.x (messages) or gpt-5/oswe/mai- (responses-only) id — those need per-model wire routing (documented debt), excluded rather than mis-routed. Inherits the leak-safe pooled routing (scope oauth/github-copilot); its bearer/ refresh/api_key never touch the Kimi token (regression test added). Fail-fast on an out-of-range copilot expires_at (would otherwise silently 401 mid-session). Adversarial security review: GO, no CRITICAL/HIGH. Known limitation: Pi's per-model policy-enablement POST is not ported (documented in AGENTS.md). |
||
|
|
5a9183b08b |
feat(providers): add Claude Pro/Max subscription OAuth (PKCE-localhost)
27th registry variant, 2nd subscription-OAuth provider. Log in with a Claude
Pro/Max subscription via PKCE authorization-code + S256 (loopback callback on
127.0.0.1:53692, with a manual code-paste fallback), then use it against
api.anthropic.com — reusing the existing Anthropic Messages wire + Anthropic
listing + the multi-provider OAuth foundation (
|
||
|
|
dbce6bf305 |
feat(providers): add xAI Grok subscription OAuth (device-code) + per-provider session auth
First subscription-OAuth provider beyond Kimi Code (26th registry variant). Log in with a Grok/SuperGrok/X subscription via RFC-8628 device-code OAuth (auth.x.ai), then use it against api.x.ai/v1 — reusing the existing xai wire (ChatCompletions + OpenAI listing + Passthrough + restrict + models_dev_id xai). Sourced from Pi (earendil-works/pi auth/oauth/xai.ts): client b1a00492..., scope 'openid profile email offline_access grok-cli:access api:access', standard Bearer (no x-xai-token-auth). Foundation (generalizes Kigi's Kimi-singleton OAuth to per-provider, root cause, not a patch): - Registry: OAuthConfig on PlatformSpec (client_id/host/device+token paths/scope/scope_key); XAI_OAUTH_CONFIG + XAI_GROK_SPEC (uses_oauth, method id 'xai-grok', an interactive login after kimi-code). - Generic device-code wire (auth/oauth_device.rs) + GenericDeviceRefresher, sharing the RFC-8628 core with Kimi; Kimi's bespoke flow is byte-identical (X-Msh headers, KIMI_CODE_OAUTH_SCOPE, keyring gating unchanged). - Per-provider AuthManager via a process-global pool (auth/oauth_registry.rs): build-on-demand with start_proactive_refresh, keyed by scope. The session resolves the AuthManager for the ACTIVE model's platform for bearer/refresh/ 401-recovery/api_key — an oauth-platform model always uses its OWN token, never the primary. - Live /models under OAuth; base routes oauth().is_some() -> platform.base_url() (kimi-code stays on proxy_url). Security: adversarial review + a systematic token-leak audit found and closed FIVE channels where the primary Kimi token could reach api.x.ai (bearer resolver, api_key stamping, aux summary/classifier/image-describe models, and subagent model-override). Each fix routes through the platform-aware resolver (the oauth model's pooled token or None, NEVER the primary) and is revert-to-red verified. No access/refresh token is ever logged. Registry at 26; picker updated (xai-grok interactive login row); TUI context-window already auto-updates per model. Full gate green (234 suites, fmt, clippy -D warnings, deny). GPT/Claude/Grok officially permit third-party subscription use. |
||
|
|
ebf11057f8 |
feat(providers): add xAI (Grok) + migrate house BYOK env to KIGI_API_KEY
13th provider (16th registry variant). Also reconciles a naming collision the matrix flagged: this fork is house-branded "xai" (cf. xai.dev metadata, KIGI_CODE_XAI_API_KEY legacy env), so XAI_API_KEY + method xai.api_key were the GENERIC house BYOK, not x.ai/Grok. The provider table wants xai/XAI_API_KEY for Grok. Resolution (user-approved): XAI_API_KEY now keys the x.ai/Grok provider; the house BYOK primary env moves to KIGI_API_KEY, keeping XAI_API_KEY and KIGI_CODE_XAI_API_KEY as back-compat fallbacks (read_xai_api_key_env checks KIGI_API_KEY first). The xai.api_key method id is unchanged (persisted-session compat); the platform method id is the bare "xai", distinct from it. xAI spec: api.x.ai/v1, Bearer, OpenAI listing + ChatCompletions, Passthrough (docs confirm stream_options.include_usage accepted). /v1/models is minimal (ids only) and requires auth, so it doubles as the key validator (401 on bad key, no override) and metadata comes from models.dev enrichment. Live ids match the models.dev "xai" keys byte-for-byte, so restrict_to_enriched keeps the 5 tool-calling chat models (grok-4.5/4.3/4.20-0309-*/build-0.1) and drops the grok-imagine-* generators + the non-tool multi-agent model. Snapshot regenerated to include the xai provider (was stale; gen script already listed it in TARGETS). Env migration is comprehensive to avoid keying the xai platform (which would trigger a live api.x.ai fetch) or leaving house-key reads stranded: routed the trace CLI resolver + acp_agent/auth.json bridge + paste-key ext handler through the new primary; moved all leader/pager/e2e harness setters to KIGI_API_KEY; made every house-key isolation test unset KIGI_API_KEY too; updated user-facing hints to name KIGI_API_KEY. Tests: e2e proves enrichment-supplied context (wire carries none), non-vacuous tool_call restriction, bare-id round-trip under xai/, Passthrough; validation tests hit /models (401 reject, 200 accept); house_env_var_takes_precedence_over_xai pins the new precedence. Registry at 16; picker 17 rows; 4 auth arrays + xai. Review (16 findings, all fixed): caught a missed else-branch env clear in the paste-key handler (would leak the house key past a clear) and a non-hermetic credential-priority test; both fixed. |
||
|
|
f825132983 |
Add Cerebras platform + generalize StrictOpenAi dialect (provider 10)
The 13th registry row: id "cerebras", CEREBRAS_API_KEY > auth.json "cerebras" scope, https://api.cerebras.ai/v1 with KIGI_CEREBRAS_BASE_URL override, Bearer, ChatCompletions, enrichment-backed metadata (models_dev_id cerebras). Cerebras' catalog is all chat LLMs (no embedding/tts pollution) and its /models is minimal (ids only), so restrict_to_enriched=FALSE: keep every live model, enrich the known ones (context + effort menus low/medium/high), unknown ones keep the default context. The e2e pins this enrich-without- restrict path (new — prior enrichment providers all used restrict=true). Review caught a likely-DOA defect: Cerebras uses strict additionalProperties:false validation (confirmed 400-rejecting store, maxTokens, thinking, nested reasoning_content), and stream_options is not in its schema — so Passthrough (which keeps the stream_options.include_usage kigi injects on every streaming request) would very likely 400 all streaming. Generalized ChatCompat::Mistral -> ChatCompat::StrictOpenAi (serde alias "mistral" keeps pre-rename persisted sessions loading), which strips stream_options + private fields for any strict OpenAI-compat validator; both Mistral and Cerebras now map to it. Future strict-validator candidates (NVIDIA/Azure/Xiaomi/OpenCode) noted for the same check. reasoning_effort (incl. "none") passes through; /v1/models requires auth so key validation works; console cloud.cerebras.ai. |
||
|
|
9953a26b8d |
Add Mistral platform + Mistral dialect + array-content handling (provider 5)
The 8th registry row: id "mistral", MISTRAL_API_KEY > auth.json "mistral" scope, https://api.mistral.ai/v1 with KIGI_MISTRAL_BASE_URL override, enrichment-backed metadata with the tool-calling listing restriction (embed/moderation/OCR noise). Mistral is NOT a pure-pattern provider — an adversarial review found two doc-confirmed blockers that no test exercises (no e2e covers a chat POST), so the gate-green registry row alone would have shipped it DOA. A research workflow pinned the exact wire shapes against the mistralai/client-python SDK source (adversarially verified), then both were fixed: 1. stream_options 422: Mistral's strict Pydantic validator rejects the stream_options.include_usage field kigi injects on every streaming request (the SDK's request model has no such field). New ChatCompat::Mistral dialect strips it (plus the kigi-private message fields, like Passthrough). Streaming usage falls back to token estimation. 2. Reasoning content arrays: Mistral reasoning models return content as Union[str, List[ContentChunk]] on both streaming and non-streaming, which the flat Option<String> path could not decode -> aborted turn. A UNIVERSAL lenient deserializer (#[serde(from = "Raw..")] on ChatResponseMessage + ChatChunkDelta) accepts string-or-array, routing {type:text} chunks to the answer and the nested text of {type:thinking} chunks to reasoning_content, tolerant of the OPEN chunk union (unknown types ignored, never fatal). String content stays byte-identical for every other provider (kimi/deepseek/groq/BYOK). Review refuted all seven attack lines (no regression, no crash, exhaustive) and flagged one coverage gap, now closed: a stream-consumer integration test drives a full thinking -> transition -> answer chunk sequence and proves it yields the same reasoning-sibling + assistant-answer result as the reasoning_content string path. Also folds a verified quirk matrix for all 23 remaining API providers into providers-plan.md, tiered by real difficulty (self-enriching OpenRouter/ Vercel; bare-array Together listing; Messages-dialect MiniMax reusing the Anthropic machinery; non-Bearer Azure/Bedrock; router wildcards; the OAuth block). |
||
|
|
49e6414c29 |
Add Groq platform (provider 4)
The 7th registry row and the first pure-pattern cycle: id "groq", GROQ_API_KEY > auth.json "groq" scope, https://api.groq.com/openai/v1 with KIGI_GROQ_BASE_URL override, OpenAI listing + ChatCompletions + Passthrough dialect (Groq accepts the OpenAI-style reasoning_effort scalar verbatim), enrichment-backed metadata with the tool-calling restriction (the listing carries whisper/tts/guard noise — 8 of 15 enrichment entries are non-chat). Review verdict: faithful pattern repeat, zero blocking findings — row facts verified against live Groq docs, registry integrity at 7, e2e proven strong on both axes (restriction + dialect mapping). Added the recommended pin: managed keys split on the FIRST slash, so Groq's provider-native slashed ids (openai/gpt-oss-120b and 10 more) round-trip as groq/openai/gpt-oss-120b → (Groq, openai/gpt-oss-120b). Also fixes a pre-existing test race this cycle surfaced: the enterprise- endpoints test asserted moonshot's fixed base while non-serial, racing serial tests that legitimately point KIGI_MOONSHOT_CN_BASE_URL at wiremock; now serial + env-unset like its documented siblings. Two display-only advisories logged as tracked debt (Groq's delta.reasoning field invisible in the TUI; platform-generic rate-limit copy). |
||
|
|
7efb4b07cc |
Add DeepSeek platform + ChatCompletions dialect system (provider 3)
The 6th registry row: id "deepseek", DEEPSEEK_API_KEY > auth.json "deepseek" scope, base https://api.deepseek.com (chat rides {base}/chat/completions per official docs) with KIGI_DEEPSEEK_BASE_URL override, enrichment-backed metadata (1M context, 384k output cap, high/max effort menu). Structural fix the cycle exposed: kigi's Kimi-specific body adaptation ran UNCONDITIONALLY on every ChatCompletions request. New ChatCompat dialect, declared per platform row and threaded through SamplerConfig, ClientDefaults, and the session-persisted SamplingConfig (serde-default Kimi keeps restored pre-field sessions and BYOK endpoints byte-identical; production persist seams copy it; subagents inherit it): - Kimi: full legacy pipeline (dispatch ≡ legacy pinned) - DeepSeek: thinking:{type, reasoning_effort} per api-docs.deepseek.com (server maps low/medium→high, xhigh→max itself; none disables; absent leaves the server default) - Passthrough: OpenAI-style reasoning_effort scalar untouched (unblocks Groq and the rest of the OpenAI-compatible list) Review-confirmed release blocker fixed: kigi replays Kimi's reasoning_content (and its private model_id) on input assistant messages — Kimi consumes these, but DeepSeek documents input reasoning_content as prefix-mode-only (historically a 400) and other providers don't know either field. The DeepSeek and Passthrough arms now strip both; Kimi's own pipeline is untouched. Pinned on both message shapes. |
||
|
|
c5ddaec71e |
Add per-provider auth.json keys; make auth methods registry-generic (P0b)
Platform API keys now live in auth.json under the platform-id scope (the per-provider auth.json key contract), resolved env > auth.json > legacy [platforms.*] config.toml (read-only fallback). The TUI login picker, paste box, auth-method advertising, and authenticate handler are all registry-generic: a new PlatformSpec row appears in the login UI and authenticates with zero UI changes. Spec rows gained vendor/console_host/ login_label display fields (moonshot strings byte-identical, pinned by tests). Adversarial review caught that auth.json keys were validated at login but never stamped onto catalog entries (completions would 401; restart lost eager auth). Fixed red-green: resolve_model_list/resolve_model_catalog now take a resolved PlatformApiKeys snapshot consumed by the credential- stamping layer (auth.json beats stale config.toml, matching the login validator), with production callers resolving fresh per catalog build. Also from review: the new auth.json writer takes the manager's cross- process flock (bounded retry — an unlocked RMW racing a token refresh could revert a rotated refresh token); the oauth-401 wiremock test is hermetic (KIGI_SHARE_DIR tempdir; it could read a dev's real auth.json and hit live moonshot); cli_models resolves real keys; auth.json is read once per registry sweep; caller-less lock_config_writes deleted; catalog resolvers tightened to pub(crate); stale config.toml doc comments and the no-credentials error copy updated. |
||
|
|
02cf5deebd |
Add /graph G6: plan-boundary topology optimizer
A restricted optimizer pass now reviews the graph at plan boundaries —
right after initial planning and piggybacked on each replan version
boundary, never mid-execution. An optimizer subagent may emit four ops
over Waiting/Ready nodes only: remove_dep (delete a false dependency,
restoring parallelism — the highest-value edit), reorder (pending
priority for the serial scheduler), merge (fold two tiny nodes; specs
concatenate, deps union, dependents re-point, absorbed self-deps drop),
and split (2-3 focused replacements inheriting the original's deps and
dependents). The optimizer changes graph DATA only; the executor stays
pure deterministic Rust. KIGI_GRAPH_OPTIMIZER=0 disables it entirely.
apply_optimization enforces the contract twice: per-op checks
(pending-only targets, known ids, terminal node untouchable, dead-node
deps rejected as DeadDep, merge/split targets with non-pending
dependents rejected with the true reason instead of tripping the
immutable invariant later), then FINAL invariants — every non-pending
node byte-identical in the result, the gn-final gate rebuilt over all
survivors, node cap, whole-graph acyclicity, and a BIDIRECTIONAL status
re-derivation for pending nodes (adversarial review caught the critical
hole: a merge grafting unsatisfied deps onto a Ready node would
otherwise dispatch it ahead of its new prerequisites, since
recompute_ready is promote-only). Applied passes bump plan_version,
freeze an immutable baseline, and consume a slot of the SHARED replan
cap; an explicit {"ops": []} is a respected free no-op; any failure
degrades to keeping the current plan. Plumbing reuses a new shared
artifact-pass runner (stale-artifact delete, size cap, missing-file
fail-closed) extracted from the replanner.
Tests: remove_dep parallelism restore + loud no-such-dep, immutable and
terminal-node rejections across all four ops, merge/split dependent
rewiring incl. final-gate rebuild and intra-split dep resolution,
result-cycle rejection, dead-dep splits, Ready-demote-on-merge, and
three e2e flows — false-dep removal proven ACTUALLY parallel by the
held-reply fan-out gate, OPTIMIZER=0 spawning zero passes, and the
shared-cap guard. kigi-shell 4959 lib tests green; clippy clean.
|
||
|
|
bb5cbff62d |
Add /graph G3: dynamic replan from DISCOVERED work items
Workers, verifiers, and serial node goals can now surface out-of-scope work
as line-anchored 'DISCOVERED: <text>' markers (fence-stripped and
placeholder-filtered — the templates' own examples are fenced so verbatim
echoes never parse; worker summaries embedded in verifier prompts get the
marker neutralized alongside NODE_RESULT/NODE_VERDICT). Discoveries queue on
the orchestration as persisted state and fold into the graph at dispatch
boundaries: a replanner subagent produces a strictly APPEND-ONLY appendix,
validated against the live graph (existing-id deps allowed; edges onto
gn-final rejected — they would cycle the moment the final-gating extension
lands; Blocks deps on Failed/Blocked nodes rejected as DeadDep so the
attempt-2 feedback loop repairs the artifact). Installing an appendix bumps
plan_version, freezes an immutable graph.baseline.v{N}.json next to the
prior versions, extends gn-final's gate (demoting a Ready final back to
Waiting), and recomputes readiness.
DiscoveredFrom edges are audit metadata, never scheduling gates: an origin
is always terminal at replan time, so gating on it is either a no-op or a
permanent wedge — and a failed node's discoveries are still real work.
Replanning is bounded by KIGI_GRAPH_REPLAN_CAP (default 3; 0 disables it
quietly): past the cap, after the final node has achieved, or on replan
failure, discoveries drain to history only — a working graph is never
paused for a failed enhancement pass, and it always converges. The budget
gate now precedes the replan boundary (a budget-dead graph keeps its
discoveries queued for a later --budget top-up instead of spending two
replanner runs first), and both planner runners delete stale artifacts
before spawning so a child that responds without writing can never get a
previous pass's file validated as its own output.
Tests: validate_replan unit coverage (existing-id resolution,
DiscoveredFrom dedup, collisions, dead deps vs dead origins, terminal-node
edges, combined-graph cycles), tracker appendix/regate/audit-edge tests,
and two e2e flows — discovery → replan → appended node runs to Achieved
with both baselines frozen, and cap-0 draining to history while the graph
still converges. kigi-shell 4935 lib tests green; workspace clippy clean.
|
||
|
|
4d1e4fdc52 |
Add /graph G1: parallel fan-out with worktree isolation and merge-back
With KIGI_GRAPH_CONCURRENCY > 1 (default 3, clamp [1,8]) and >=2 Ready nodes, drive_graph — the single dispatch loop shared by setup/advance/resume — runs parallel batches: each node executes as a bounded worker<->verifier subagent loop (KIGI_GRAPH_NODE_ROUNDS, default 3; general-purpose children with the full implementer toolset; worktree isolation on round 1, resume keeps context and worktree on later rounds; NODE_RESULT/NODE_VERDICT terminal contracts parsed fail-closed with fence-stripping and line anchoring). Achieved nodes merge back SEQUENTIALLY via kigi_workspace apply_worktree in Merge mode; a conflict fails the node, block_dependents fires, and surviving chains keep going. gn-final always runs serially on the full goal engine. Concurrency=1 is byte-identical to the serial G0 path; non-git projects degrade to serial. Merge primitive hardened for real use (kigi-workspace): the 3-way apply is now byte-safe (binary files no longer read as UTF-8 and silently deleted) and gains the identical-content rule (ours==theirs => already present, not a conflict) — without it, any dirty file inherited via PreserveWorkingTree false-conflicted every node merge and multi-wave graphs self-poisoned. Adversarial review pass (16 confirmed findings, all fixed): in-session resume demotes orphaned Running nodes instead of wedge-pausing forever after a mid-batch Esc; cancel re-sweeps subagents AFTER the turn abort so workers spawned in the cancel window die too; empty child ids are never adopted as resume targets (no unisolated escape to the shared tree); a successful isolated round returning no worktree fails the node (soft-fallback can no longer put N writers in one tree); main-HEAD movement during a batch aborts merges instead of reverse-applying external commits; failed nodes still charge the token budget; budget trips terminally fail the in-flight node; runaway (>600s) rounds are cancelled by spawn id and retried via resume; worker summaries are marker-sanitized before verifier embedding. Merged worktrees are removed immediately (storage discipline); failed nodes keep theirs for postmortem. Tests: 4922 kigi-shell lib tests green (58 graph-specific), including fan-out proven by a held-reply gate, real-git batch merge with cleanup assertions, budget charging across verdicts, cap trimming, resume-after- cancelled-batch, and backgrounded-round cancel semantics. |
||
|
|
4361b03259 |
Add /graph G0: serial graph engineering mode over the goal engine
A deterministic DAG scheduler layered on the existing goal engine: /graph <objective> decomposes the objective via a graph-planner subagent, gates the result through Agentproof-style static validation (cycles, unknown deps, duplicate slugs, caps), appends a structural final-verification node, then executes each node as one ordinary goal — planner, worker loop, adversarial verifier, budget and pause machinery all reused verbatim. The in-turn loop advances nodes within the same turn (multi-loop closed loop); goal-side auto-pauses cascade to the graph at a single chokepoint; node goals are armed with the remaining graph budget so mid-node overruns trip graph-wide. Gated by KIGI_GRAPH=1 (default off) + the goal harness. State persists to <session_dir>/graph/state.json with a clear-tombstone; per-version immutable baselines and per-node artifact archives live under graph/<graph_id>/. Restore demotes Active->UserPaused and Running->Ready (verifier-gated re-run). Review hardening (adversarial multi-agent pass, 24 confirmed findings fixed): the goal-inactive loop break now consults the graph seam (mid-turn classifier-disabled completions can no longer strand an Active graph), the pause cascade fires even when no node goal is in flight (cancel during planning), node bookkeeping precedes the long setup await, /graph clear only resets the engine it owns, budget trips terminally fail the in-flight node, and the pause transitions in /goal pause + /graph pause no longer hide inside debug_assert! (a release-build no-op inherited from upstream). Tests: 4908 kigi-shell lib tests green, including a serial 4-node closed-loop e2e, restore/resume, cascade, mutual-exclusion, planning-retry, persistence round-trip + tombstone, and status rendering. |
||
|
|
3952c28f16 |
Login picker: offer all three platforms like the official CLI
The unauthenticated welcome screen previously offered only 'Login with
Kimi Code'. It now lists every interactive platform the shell
advertises, matching the official kimi-cli picker:
Kimi Code (OAuth)
Moonshot Open Platform (API key · moonshot.cn)
Moonshot Open Platform (API key · moonshot.ai)
Quit
- Shell: new ACP auth methods moonshot-cn / moonshot-ai (advertised
after kimi-code; the BYOK first-position invariant holds).
authenticate(moonshot-*) reloads keys from env>config, fails with an
actionable message when none is configured, validates the key against
GET {base}/models (401 → 'invalid API key' naming the console), then
swaps the fresh config in, triggers the model sync, and reports
auth_mode api_key so the pager treats it like other API-key logins.
Never session-based; keys never logged.
- Config: save_platform_api_key persists [platforms.<id>].api_key via an
atomic mode-preserving write under the config lock; refuses OAuth
platforms, blank keys, and unparseable files.
- TUI: the Pending welcome renders the picker rows from the advertised
methods (arrows/Enter/mouse; 'l' keeps selecting the OAuth row).
Choosing a Moonshot row opens a masked paste box ('Paste your Moonshot
API key (from platform.moonshot.cn)'); Esc returns to the picker,
Enter persists the key and authenticates in one sequential effect;
failures return to the picker with the error line, success lands on
the normal welcome. Startup eager-auth is unchanged: a key already in
the environment authenticates exactly as before, and single-method
shells keep the historical auto-device-flow.
Gates: workspace check/clippy 0/0; shell 4870 + tui 6620 lib tests
green; headless probe advertises [kimi-code, moonshot-cn, moonshot-ai]
for a fresh user and xai.api_key-first with a key configured.
|
||
|
|
6f31415ed6 |
§9 acceptance: grep-zero sweep — every internal x.ai/grok identifier renamed
The PRD's first acceptance gate now holds: grep -RinE '\bx\.ai\b|grok' crates/ --include='*.rs' → 0 matches (exempt: NOTICE and third-party license archives, README provenance, and the required 'Based on Grok Build Open Source' attribution, now sourced from version_attribution.txt). Wire-visible renames (both sides in this repo, changed in lockstep): - Auth method id 'grok.com' → 'kimi-code' (AuthMethodKind::KimiCode). - Every x.ai/* and _x.ai/* ACP ext method and meta key → kigi/* / _kigi/* (~200 names; grokShell → kigiShell). Session-file replay keeps a read-side alias for the legacy '_x.ai/session/update' method so existing updates.jsonl histories load; writes emit only the new name (both directions test-pinned). - Agent types grok-build* → kigi* with a documented legacy-prefix alias at resolution time so persisted sessions keep resolving. - ToolNamespace/BuiltinAgentName GrokBuild* → Kigi* (wire snake_case kigi/kigi_concise/kigi_hashline; schema regenerated); grok_build implementation dirs renamed to kigi*. - x-grok-* headers → x-kigi-*, __GROK_* sentinels → __KIGI_*, themes grokday/groknight → kigiday/kiginight (old persisted values fall back to the default theme), web_fetch allowlist xAI hosts → kimi.com + moonshot platforms, changelog CDN → this repo, grok-build changelog archives deleted. - BYOK default endpoint removed: [endpoints] api_base_url is now truly optional with NO default — consumers fail fast with the flag name when unset (no silent x.ai egress). Mock harnesses inject it explicitly. - System-prompt identity fixed: 'released by xAI' → 'an unofficial community CLI for Kimi' (template + regenerated encrypted form). Also repaired pre-existing grok-era test debt found by the sweep: the stale trace_classify default-model pin, the grok-pager UA label test, pty-harness stale-binary reuse and non-hermetic moonshot routing (a PTY test could previously reach the real api.moonshot.cn), and the outdated oauth fixture scope key. Gates: §9 grep 0; fmt clean; workspace check/clippy 0/0 (-D warnings); FULL cargo test --workspace: 234 suites, 21,961 passed, 0 failed; deny advisories ok. |
||
|
|
5e4e24db99 |
M2 audit: excise managed connectors and xAI media-gen tools
Managed connectors (grok.com MCP admin) removed root-and-branch: - The managed-MCP fetch/injection pipeline is gone, including the whole kigi-shell-session-support crate (managed-config fetch client, gateway tool catalog + dispatch, header injection, refresh task), reactive managed re-auth, mcp_doctor's grok.com-source discovery, and the [managed_mcps] config surface. - TUI: the 'Managed by grok.com' section, connectors URL/deep-link, Action::OpenManagedConnectors, and session_team_id are gone. Local MCP management (list/toggle/add/remove/auth/tools) is fully intact. - Kept as LOCAL policy: managed-settings.json MCP allow/deny enforcement, the multi-source local MCP merge, folder-trust gating. PluginOrigin Project/User labels kept (they tag locally discovered plugin dirs). imagine/media-gen tools (xAI image/video generation) removed: - image_gen, image_edit, video_gen, image_to_video, reference_to_video implementations, registrations, ToolKind/ToolInput/Output variants (serde-safe), config plumbing end to end, ZDR video machinery, /imagine + /imagine-video commands and guidance text, the bundled imagine skill (added to legacy cleanup so user installs delete it), and the media-gen render path. - Kept: image INPUT (paste/attach, [Image #N] meta, pdf/image fetch, clipboard wrap), generic media-ref rendering, and the generic tool 401-retry machinery (tests renamed, assertions unweakened). - deploy_app stays: it is a permanently-disabled local stub deploying nowhere. 121 files changed, 8 deleted. Gates: workspace check/clippy 0/0, fmt, deny ok; suites green (tools 2554, shell 4862, tui 6608, workspace 1042). Remaining grok.com strings live only in the auth-method ids and changelog archives (§9/M3 sweep). |
||
|
|
fa75eb139a |
M2 audit: excise the Computer Hub stack — Kigi's last remote-cloud surface
Removed root-and-branch for the zero-egress guarantee (the hub was xAI's remote-workspace/cloud-sandbox service): - Crates deleted: kigi-computer-hub-core, kigi-computer-hub-sdk, kigi-computer-hub-mcp-adapter, kigi-workspace-client (hub-proxied workspace RPC client), and kigi-tracing (its sole network path was the OTLP gRPC exporter; zero consumers remained). kigi-tracing-macros (purely local) stays. - kigi-workspace: every hub surface deleted — hub server/channel/auth, HITL-over-hub permissions, donation/metrics pumps, file upload RPCs, hub tool-snapshot merge (resolve pipeline is MCP-only now), WorkspaceOps::Proxy. Local worktrees, sessions, leader IPC, MCP, and the ACP permission prompt path are untouched; LocalRegistry re-homed into kigi-tool-runtime on the existing ToolDyn types so in-process tool dispatch is unchanged. - kigi-shell: leader workspace-exposure control surface (incl. the wss://computer-hub... URL), [hub] config, ObservabilityBridge, hub WebSocket proxy, dead OTLP config knobs. ClientMode::Headless (never constructed) removed. - kigi-tui/bin: hidden `kigi workspace` command removed (`kigi worktree` stays). - Renames: --xai-api-base-url → --api-base-url / KIGI_API_BASE_URL / [endpoints] api_base_url (serde alias keeps old configs working; the flag feeds BYOK/custom-endpoint routing, not main inference); grok_version → kigi_version in inspect/models-cache/trace metadata (old caches self-heal via version-mismatch refetch). - Dependency tree: dropped fastrace*, opentelemetry-otlp/http/proto, tokio-tungstenite from the workspace; fixed the 4 real useless_format violations the fastrace lint allowance was masking and removed the allowance. - marketplaceAllowlist kept: it gates the LOCAL plugin-marketplace feature, not an xAI service. Known §9 leftover (deliberate, for the M3 sweep): the BYOK default base URL string. Gates: workspace check/clippy 0/0, fmt, deny ok; suites green (workspace 1042, shell 4918, tui 6634, tools 2608, tool-runtime 47, mcp 154). |
||
|
|
74b210535e |
F5: web search/fetch on the Kimi services (kimi-cli parity)
web_search now speaks the Kimi search service (kimi-cli tools/web/search.py,
wire-verified against api.kimi.com):
- POST {coding_base}/search with {text_query, limit 1-20 (default 5),
enable_page_crawling, timeout_seconds: 30}, OAuth bearer +
X-Msh-Tool-Call-Id; results render in kimi-cli's Title/Date/URL/Summary
schema with result URLs as citations.
- The old implementation called the xAI Responses API with a search model;
that client is fully replaced and the entire model-based config surface
is excised root-and-branch: web_search_model config keys/env/CLI plumbing,
resolve_web_search_sampling_config, toolset web_search SamplerConfig,
RemoteSettings.web_search_model, default_web_search_model.
- Enablement is now purely structural: the service exists only on the Kimi
Code subscription channel, so OAuth sessions get Enabled and API-key-only
sessions get Disabled (tool absent) — per PRD F5.
web_fetch gains the Kimi fetch service as its primary path (kimi-cli
tools/web/fetch.py): POST {coding_base}/fetch with {url}, Accept:
text/markdown, OAuth bearer + X-Msh-Tool-Call-Id; the 200 body is the
extracted markdown (still overflow-budgeted). Any service failure falls
back to the existing local pipeline (SSRF guards, cache, extraction).
The tool gate defaults ON now (kimi-cli always offers FetchURL) and the
egress User-Agent no longer claims grok-agent/x.ai.
Verified end-to-end against the scripted mock service: a headless session
drove web_search (limit/crawling/call-id observed on the wire) then
web_fetch (Accept + call-id observed) to completion.
|
||
|
|
ea0ce9d15f |
F3: Kimi inference pipeline + full grok cloud-surface excision
Sampler / inference (PRD F3):
- kimi_compat.rs: single adaptation point for the Kimi chat/completions
dialect (thinking-field mapping, model_id stripping, empty-content
tool-call message fix, stream_options.include_usage), with kimi-cli
source citations
- Rate-limit handling reworked for Kimi/Moonshot semantics; UA kigi/{version}
- /models replaces the xAI models-v2 endpoint everywhere; idle model
refresh carries X-Msh-* device headers only (X-XAI-Token-Auth and
x-grok-client-mode/CLIENT_MODE_HEADER machinery deleted)
Cloud-surface excision (PRD §5, zero-egress):
- remote/ conversations lane, cli-chat-proxy-types crate, prod/ dir,
share command, credit bar: deleted (single local session lane;
paginate() replaces merge_and_paginate)
- Subscription/tier gate stack deleted end-to-end: AppView
gate/tier/team/ZDR fields, app/subscription.rs watch loop,
dispatch/billing.rs paywall + SuperGrok upsell, free-usage-exhausted
chain, tier-restricted commands, GateInfo, RemoteSettings gate fields,
SettingsUpdateNotification gate fields
- /privacy + coding-data-sharing setting deleted (backed by a dead xAI
RPC; Kigi is zero-egress — nothing to share or retain remotely)
Auth UX correctness (user-reported):
- Device-flow fixtures now mirror the live Kimi payload shape
(https://www.kimi.com/code/authorize_device?user_code=..., verified
against auth.kimi.com); the fabricated auth.kimi.com/device?code=...
URLs are gone
- open_browser_detached is a no-op under cfg(test): unit tests drove
wiremock fixture URLs into the real browser (root cause of the
"garbage mock link" ABCD-1234 tabs)
- Welcome/pager-minimal rebrand: Grok Build -> Kigi, grok.com ->
kimi.com, "Sign in to Grok" -> "Sign in to Kimi"
|
||
|
|
fe1f885bb3 |
M1/F2+F4: platform registry, Moonshot API-key channel, dynamic model sync
F2 — fixed three-platform registry in kigi-models: kimi-code (subscription, OAuth bearer, base kigi_env::coding_api_base_url()), moonshot-cn (https://api.moonshot.cn/v1), moonshot-ai (https://api.moonshot.ai/v1) with kimi-k model-prefix filtering. Moonshot API keys via KIGI_MOONSHOT_CN_API_KEY / KIGI_MOONSHOT_AI_API_KEY (+ KIGI_MOONSHOT_API_KEY shared fallback) or ~/.kigi/config.toml; values redacted from logs/display. F4 — model catalog now syncs from GET {base}/models (Bearer auth, wire shape per official kimi-cli: id/context_length/supports_reasoning/ supports_image_in/supports_video_in/display_name) with the official capability-derivation rules (thinking / always_thinking-in-name / kimi-k2 implicit set). Managed keys {platform_id}/{model_id}; default model = first list entry; default thinking iff capabilities contain thinking/always_thinking. Sync failure → last cache; no cache → built-in fallback table seeded from ids sourced in official kimi-cli (kimi-for-coding, kimi-k2-turbo-preview, kimi-k2-thinking-turbo). 401 during sync forces one token refresh and retries. Model resolution priority preserved: CLI > env > config > server > fallback. Grok model artifacts (grok-4*/grok-build catalog, tier gating remnants) removed from non-test code. All first-party endpoints re-verified live: device_authorization mints real codes; /models on all three platforms answers with real API auth errors when unauthenticated. Gates: check/clippy --all-targets 0/0, fmt clean, deny ok, kigi-shell lib 5136 green, kigi-tui lib 6819 green, kigi-models 8. |
||
|
|
021b82443d |
M1/F1: Kimi Code OAuth device-code flow
Replace the xAI OAuth stack with the Kimi device authorization grant:
- kimi_oauth.rs wire layer (device_authorization + token poll + refresh
against kigi_env::oauth_host(); client_id per PRD; retryable statuses
429/5xx with backoff; expired_token restarts authorization)
- X-Msh-Device-{Name,Model,Id} headers; device_id minted uuid4-hex at
~/.kigi/device_id (0600)
- Storage: system keyring service `kigi`, entry `oauth/kimi-code`
(macOS/Windows native backends), atomic-file fallback under ~/.kigi;
official client's keyring/~/.kimi never touched
- Refresh manager: 60s tick, threshold max(300, expires_in*0.5),
401-tombstone keyed by rejected refresh token with 300s cooldown and
rotation auto-clear, cross-process lock with sibling-adoption
triple-check, sleep/wake forced refresh
- Deleted xAI machinery: enterprise OIDC (PKCE/JWKS/teams), devbox login,
external auth provider, JWT tier gating + subscription paywall stack,
X-XAI-Token-Auth marker headers, ZDR gates, /user enrichment
- kigi login / TUI /login both drive the device flow; login-host display
now derives from kigi_env::oauth_host()
- 264 auth unit/wiremock tests; live contract probe of
auth.kimi.com/api/oauth/device_authorization matches the wire shapes
Gates: check/clippy --all-targets clean, fmt, deny ok, kigi-shell lib
5131 tests green.
|
||
|
|
d6c20fc13f |
M0: compilable skeleton — Kigi 0.1.0 fork surgery
Hard fork of xai-org/grok-build (Apache-2.0) re-targeted as Kigi, an
unofficial Kimi Code CLI community build.
Rename & identity
- 72 xai-*/xai-grok-* crates -> kigi-* (explicit: xai-grok-pager-bin ->
kigi-bin [binary `kigi`], xai-grok-pager -> kigi-tui; rest mechanical);
ptyctl, ptyctl-cli, third_party/ unchanged; proto package
xai.grok.tools.v1 -> kigi.tools.v1
- Config home ~/.kigi (KIGI_SHARE_DIR override), env prefix GROK_* ->
KIGI_*, `kigi --version` carries the unofficial-community-build notice
- clap identity, help text, startup banner, prompt templates rebranded
(templates re-encrypted)
Deletions (PRD removal list #5/#6/#7/#9/#10)
- voice input (xai-grok-voice) and all TUI wiring
- telemetry: Mixpanel client, external OTel stream, Sentry, OTLP layers,
trace/GCS/S3 upload queues (kigi-file-utils halved), workspace upload
module & dc_log, heap-profile uploader, auth-diagnostics uploader,
session-analytics halves of feedback; local zero-egress observability
preserved in new kigi-log crate (unified log, --debug firehose,
subsystem file logs, opt-in instrumentation)
- announcements (crate, remote-settings fields, TUI surfaces)
- plugin marketplace (crate, sources/browse/CTA/extensions-modal tab);
direct plugin install/uninstall/update via kigi-agent git_install kept
- relay/gateway/assets endpoints and features (agent relay, headless
relay transport, gateway bridge, LeaderEnvUrls); leader IPC socket now
~/.kigi/leader.sock + KIGI_LEADER_SOCKET, no ws-url derivation
- functional types rehomed instead of deleted: PermissionMode ->
kigi-config-types, McpInitStrategy -> kigi-mcp, PrCreationSource ->
session signals, TerminalDiagnostics -> kigi-pager-render, agent_id ->
shell util
Endpoints
- kigi-env rewritten: single production KigiEndpoints {coding_api_base_url
https://api.kimi.com/coding/v1 (KIGI_CODE_BASE_URL), oauth_host
https://auth.kimi.com (KIGI_OAUTH_HOST), update_base_url (GitHub
Releases API), upgrade_page_url}; GrokBuildEnvironment enum deleted
Toolchain & workspace hygiene
- Rust 1.97.0 pinned; edition 2024; full cargo update; git2 hoisted to
workspace at 0.21 (Option->Result API migration), quick-xml 0.41
- Root Cargo.toml hand-maintained (PRD §8.1): version 0.1.0 inherited by
all members, members sorted, unused deps pruned
- cargo-deny advisories gate (deny.toml with documented transitive
exceptions); CI workflow (check/clippy/fmt/deny/test, macOS+Linux)
- cross-crate test seams re-gated behind `test-support` cargo feature;
insta snapshot baselines renamed to the kigi_tui prefix
- clippy --workspace --all-targets: zero warnings; fmt clean
Fixes surfaced by the port
- updater probe/installer divergence (bin/kigi vs bin/grok symlink set)
- idle model-metadata refresh dead under KIGI_CODE_BASE_URL override
(new is_effective_coding_endpoint_url, loopback+override aware)
- macOS symlinked-TMPDIR fixture canonicalization (foreign_sessions,
fast-worktree); RSS measurement tests serialized via serial_test
Docs & legal (Apache §4)
- NOTICE added (upstream attribution + change statement); THIRD-PARTY
notices sustained; kigi-tools ported-code notices extended; README,
CONTRIBUTING, SECURITY, AGENTS.md rewritten
Out of scope for M0 (tracked): Kimi auth/inference (M1), search/fetch,
command parity, config import (M2), Computer Hub excision & final
brand-token sweep (M2), distribution & self-update rewrite (M3).
|