Files
mcode-sl/docs/DECISIONS.md
T
aygea fd8e8cbbd7 docs: AGENTS.md + evidence-backed scaffold (state, trials, decisions, handoff)
- AGENTS.md operating rules incl. Gitea SSH port-2222 note + known_hosts incident
- CURRENT_STATE / TODO / CHANGELOG / TRIALS
- trials: endpoint-key pairing; config-merge safety matrix 14/14 (verify.sh + output)
- docs: DECISIONS (mcode 0.6.12 bundle facts, digest-pinned), FEATURE-MATRIX, PROJECT-HANDOFF
- handoffs: TEMPLATE + 2026-10-19 initial-install record
2026-10-19 23:25:21 -07:00

85 lines
5.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DECISIONS
Stable IDs; newest at the bottom. Each records context, choice, alternatives, consequences.
## D1 — Vault-first credentials, `api.zai` direct; credential.json fallback
- **Context:** the Aygea Claude statusline used `~/.secretvault/credential.json`
(`url` + `clientKey` → `vault.itsaygea.com` proxy). The user wants this repo public
and machines to need nothing but their existing SecretVault (`zai_api_key`).
- **Choice:** read `zai_api_key` via `secretvault run` (name from env, default
`zai_api_key`), hit `https://api.z.ai/api/monitor/usage/quota/limit`; fall back to
credential.json → `${url}/proxy/zai/...`. Key reaches curl via a 0600 header file
(`--header @file`), never argv.
- **Alternatives:** bake the proxy URL + require credential.json everywhere (rejected:
repo would document private infra as a requirement); store JSON {url,key} in the
vault (rejected: existing secret is a plain key).
- **Consequences:** one secret per machine is the only setup; trial
`mcode-endpoint-key-pairing-2026-10-19` pins the pairing. Proxy users still work.
## D2 — mcode statusline mechanics (verified facts, release-pinned)
Confirmed by reading the 0.6.12 bundle — re-verify after every mcode update.
Files (SHA-256): `chunks/launcher-AVQRYDKB.js` `2c4337e3…edfbe3`,
`chunks/chunk-X3PES5WL.js` `600c23d…09ee5` under
`~/.minimax-code/releases/0.6.12/lib/node_modules/@minimax-ai/code/`.
- Config source: `<dataDir>/config.yaml` → `tui.statusLine` (array) +
`tui.customStatusLine` (`Pv()` in launcher chunk).
- Valid statusLine items: `current-dir, session-title, git-branch, review-link,
plan-mode, approval-mode, model-with-reasoning, model, context-window, subagent,
token-quota, cache-read-ratio, context-remaining, context-meter, custom-command`.
- Custom command runner: only active when `custom-command` is in `statusLine` **and**
`build-mode` is not; command required (non-empty). Schema:
`display: inline|block`, `position: above|below`, `colorMode: plain|ansi`,
`intervalSeconds` (default 0 = off, clamp ≥10), `timeoutMs` (default 5000,
clamp 500–30000), block `maxLines` default 3 (clamp 1–5).
- Invocation: `{command}` parsed + spawned with `cwd = workspace_dir`, JSON on stdin
(`{protocol, event: startup|interval|session-change|workspace-change, session_id,
workspace_dir, model, session_title, tui_version}`), stdout capped ~8 KiB
(exact cap expression `Q1` not disambiguated: `8*1024` vs `8e3` — inferred).
stdout becomes the `custom-command` item **only on exit 0 without timeout**;
inline mode renders the first line; `colorMode: ansi` keeps escape codes when the
terminal color level > 0, strips otherwise.
- **Consequence:** our script must be silent-fail (`exit 0`, empty output when unknown)
and must not rely on stdin content.
## D3 — mcode is the scheduler; refresh decoupled in-process
- **Context:** the Claude statusline needed a systemd timer because Claude Code has no
interval hook. mcode's `customStatusLine.intervalSeconds` re-runs the command itself.
- **Choice:** no cron/systemd. On each call: fresh cache (≤150s) → print; stale → spawn
detached (`setsid`, fallback `& disown`) flock-guarded refresh (`--refresh-bg`) and
show the still-valid value (≤360s) or nothing.
- **Consequences:** zero extra services; segment self-heals; offline machines just hide
the segment after 6 min. Timer coexistence is harmless (same cache file).
## D4 — Shared cache with the Claude Aygea statusline
- **Choice:** keep schema `{pct, reset_iso, ts}` at `~/.cache/aygea-sl/quota.json`
exactly as the Claude refresher writes it (reset written as local ISO; epoch
conversions have GNU/BSD branches).
- **Consequence:** both ecosystems interop; any writer refreshes both. Constrained the
parser to ISO strings instead of the internally simpler `reset_ms`.
## D5 — Config merge safety rails
- **Context:** user requirement: atomic, previous-entry aware, must never break a config
holding API keys. Two early bugs (in-place write; backup taken after merge) proved the point.
- **Choice:** python3 stdlib line surgery limited to the `tui:` block; refuses multiple
`tui:` blocks or duplicate keys; validates result (structural + PyYAML when available);
writes temp + fsync + `os.replace`; preserves mode (0600 for new); timestamped backup
copied **before** first modification; byte-exact elsewhere (incl. trailing newline).
- **Alternatives:** PyYAML full round-trip (rejected: reformats/comments lost); yq
(rejected: extra dependency on every machine).
- **Consequences:** merge is monotonic and reviewable; `docs/FEATURE-MATRIX.md` gates
remaining platform risk.
## D6 — Public repo + Gitea over SSH port 2222
- **Choice:** repo `git.itsaygea.com/admin/mcode-sl` (`main`); remote via SSH; the
curl one-liner points at `…/raw/branch/main/install.sh`. No secrets in the repo by
design (D1).
- **Consequences:** see `AGENTS.md` → "SSH to Gitea" for the port-22 incident record,
accepted host-key fingerprint, and the repeat guard.