Commit graph

1220 commits

Author SHA1 Message Date
Resham Joshi
c49fa23590
Merge pull request #849 from getagentseal/phase9/releasing-doc
docs(releasing): three-field version bump, exact core pin, core-before-cli publish order
2026-07-27 15:37:01 -07:00
iamtoruk
32165ddecd docs(releasing): three-field version bump, exact core pin, core-before-cli publish order
The #847 version gate fails the old single-workspace bump flow, and the
exact @codeburn/core pin makes publish order load-bearing: a CLI published
before its core version exists on the registry is uninstallable.
2026-07-27 15:35:59 -07:00
Resham Joshi
0a57aa5187
Merge pull request #847 from laulpogan/harden/core-release
Fix core release coupling, declaration build, and CI gates
2026-07-27 15:33:17 -07:00
Paul Logan
ed4f84da45 chore: stop emitting declaration maps
package.json#files ships dist and schemas but not src, so every emitted
.d.ts.map pointed at a source file the consumer never receives. That was 151
files and roughly 135 kB of maps that resolve to nothing.

Dropping declarationMap takes the tarball from 389 files to 238 and 376 kB to
354 kB. The declarations themselves are unchanged: 151 .d.ts, all 41 export
targets still verified present.
2026-07-27 15:22:15 -07:00
Paul Logan
0ec9ea93cb fix: guard publish against a half-built dist
The build is `tsup && tsc`. tsup runs with clean:true, so it wipes dist and
writes JavaScript; if tsc then fails, dist holds .js with no declarations. The
build exits non-zero, but packages/core declared no prepublishOnly, so nothing
rebuilt at publish time and a later npm publish would ship it.

Reproduced: remove the declarations from a copy of dist and npm pack --dry-run
still succeeds, with all 41 exports subpaths pointing at files absent from the
tarball. npm pack was never the guard.

Adds prepublishOnly (build then verify) and scripts/verify-dist.mjs, which
asserts every exports target exists. CI runs verify-dist as well, so the guard
is exercised on every push rather than only on the rare publish.
2026-07-27 15:12:13 -07:00
Paul Logan
6f1f8a4462 fix: check package-lock.json in the workspace version gate
The gate compared only the three package.json manifests, so it passed while
package-lock.json still recorded a stale workspace version. npm ci does not
reject that either (checked on npm 10.9.2, 11.12.1, 11.16.0, 11.17.0), so
nothing caught the exact drift the script exists to catch.

Reproduced with a fixture whose manifests all read 0.9.20 while the lockfile
recorded packages/core at 0.9.19 and a "*" CLI dependency: the gate exited 0.
It now exits 1.
2026-07-27 15:12:04 -07:00
Paul Logan
7e29455d4f ci: gate core builds and package integrity 2026-07-27 12:01:52 -07:00
Paul Logan
0054c9ceca fix: emit core declarations with TypeScript 2026-07-27 11:57:05 -07:00
Paul Logan
c52c567cdd fix: couple core and CLI releases 2026-07-27 11:55:29 -07:00
Resham Joshi
88f298cddf
Merge pull request #844 from getagentseal/phase9/core-readme
docs(core): replace Phase 1 skeleton README; bump core to 0.9.20 for republish
2026-07-27 10:53:41 -07:00
iamtoruk
f00904d0a6 docs(core): replace Phase 1 skeleton README; bump core to 0.9.20 for republish
The npm page was showing 'Status: skeleton. This package currently exports
nothing' — false since Phase 2, and badly so since Phase 8 completed. npm
auto-packs README.md regardless of the files list, and published versions
are immutable, so an accurate README needs a version bump to reach the
registry. ^0.9.19 ranges match 0.9.20.
2026-07-27 10:52:38 -07:00
Resham Joshi
20f17e8813
Merge pull request #843 from getagentseal/phase9/core-manifest
chore(core): publish-ready manifest — real description, public access
2026-07-27 10:20:48 -07:00
iamtoruk
ea4c99bc73 chore(core): publish-ready manifest — real description, public access
The description still carried the Phase 1 skeleton text and wrongly named
pricing as core content (pricing is host-side by design). publishConfig
access=public is required for the scoped package's first publish.
2026-07-27 10:19:15 -07:00
Resham Joshi
d8ea608f8d
Merge pull request #842 from getagentseal/phase8/vercel-gateway
refactor(core): vercel-gateway decode into core, report fetch host-side (phase 8, network special)
2026-07-27 09:43:28 -07:00
iamtoruk
6983b29bf3 refactor(core): vercel-gateway decode into core, report fetch host-side (phase 8, network special)
COMPLETES Phase 8 of the @codeburn/core extraction: 36/36 provider identities
(including qwen) now decode in core.

The row -> call mapping moves to packages/core/src/providers/vercel-gateway/
verbatim: day/model/cost defaults, the all-zero skip BEFORE the dedup key is
burned, the `vercel-gateway:<day>:<model>` key with add-after-skip semantics,
`${day}T12:00:00.000Z` timestamp synthesis ('' for a missing day), and the
`${day}:${model}` session id. The decoder is pure over supplied rows: no fs,
env, clock, or network.

Everything network stays host-side and byte-identical: the authenticated
/v1/report fetch, the AI_GATEWAY_API_KEY / VERCEL_OIDC_TOKEN reads, both stderr
warnings, discovery, `network: true`, and the gate that yields nothing when the
scan has no date range.

Adapter shape adjudication: the draft used createBridgedProvider and needed two
contortions to fit it — a Symbol-keyed dateRange stashed on the shared
SessionSource, and `project` packed into the records payload then unpacked by a
decode wrapper (the bridge passes neither the date range nor the source to the
mapping step). The Symbol injection also mutated the caller's discovered source
object, an observable behavior change. Rejected both; this provider now uses a
plain bespoke adapter like antigravity/kiro, which the bridge's own header
already documents as the escape hatch for providers it was not built to cover.
No change to bridge.ts, parser.ts, pricing-pass.ts, or session-cache.ts.

Emitted key shape is unchanged and gated by key-set assertions: `costUSD` is
present and there is NO `costBasis` key, so parser.ts keeps passing the
gateway's own dollar figure through instead of repricing it.

Validator fixes on top of the draft:
- Dropped the Symbol side-channel and the packed-payload decode wrapper.
- Corrected a false claim in the core observations header: it said the raw `day`
  was never emitted, but `day` is spliced verbatim into the timestamp, into
  startedAt/endedAt, and into the dedup key. The envelope's date-time constraint
  is what actually bounds it; a new smuggling arm pins that a hostile `day`
  fails envelope validation.
- Added golden arms for both stderr warnings, for the no-date-range arm making
  no fetch at all, and for the provider not mutating the discovered source.

Verification: the strengthened goldens were run against the pre-migration
provider restored in place and pass identically (13/13). Swapping the all-zero
skip and the dedup burn fails tests at both the core and CLI layers.
Core 509 tests, CLI 2470, root 2470 — all green.
2026-07-27 09:40:04 -07:00
Resham Joshi
024f5062e3
Merge pull request #841 from getagentseal/phase8/stateful-kiro
refactor(core): kiro decode into core, stores and companions host-side (phase 8, stateful tier)
2026-07-27 09:14:20 -07:00
iamtoruk
0540102a3f refactor(core): kiro decode into core, stores and companions host-side (phase 8, stateful tier)
Move all five kiro parse arms (legacy .chat, v1 modern execution,
workspace-session, CLI .jsonl, v2 IDE event log) into
@codeburn/core/providers/kiro as pure decode. The host keeps discovery,
every file read, the companion-file reads (CLI .json, v2 session.json),
the workspace-session mtime stat, project attribution, model display
names, and all pricing.

Behaviour is byte-identical to the pre-move provider; the four dedup-key
namespaces (kiro:, kiro:ws-session:, kiro-cli:, kiro-v2:) and the five
per-arm ParsedProviderCall key sets are unchanged.

Preserved verbatim, with tests that discriminate against plausible
refactors:
- A4's asymmetric turnIndex: a zero-output turn does NOT consume a
  user_turn_metadatas slot, while the dedup-hit and bad-timestamp skip
  arms DO. Every later turn's timestamp and metered credits depend on
  this. All three arms are mutation-tested.
- A1's toolSequence key stays present-with-undefined for single-entry
  sequences, gated by an Object.keys() assertion (toEqual cannot see it).
- A1's input tokens still derive from the already-truncated 500-char
  prompt, unlike every other arm.
- A5's dedup fallback stays `execId || String(calls.length)`, evaluated
  at flush time.
- The three-way workspace-session prepare/finish split keeps the mtime
  stat behind both content gates rather than hoisting it.

Credits seam: core emits `credits: number` and never prices. The host
multiplies by USD_PER_KIRO_CREDIT and builds costUSD/costBasis, matching
the codebuff precedent.

Validator fixes on top of the migration:
- A1's dedup key regained the raw `data.executionId` field; a fallback to
  basename(path) had been introduced, changing keys for chat files with a
  missing, empty, or non-string executionId.
- The content-smuggling non-vacuousness guard was vacuous per vector (an
  aggregate re-decode compared against itself); it now asserts per-vector
  call counts, verified by breaking two fixtures.
- Restored a mangled comment on the load-bearing v2-root derivation and
  several explanatory comments dropped during the move.
- Added goldens G1b (raw executionId), G4b (exact credit products) and
  G6b (turnIndex advances across a bad-timestamp turn), plus a core test
  for the same; all reproduce against the pre-move provider.

PROVIDER_PARSE_VERSIONS['kiro'] and CACHE_VERSION are unchanged. The
companion-file fingerprint blind spot (session-cache.ts) and the dead
project parameter on the old parseChatFile are left as-is.

This completes the Phase 8 tail.
2026-07-27 09:09:15 -07:00
Resham Joshi
74741a8b35
Merge pull request #840 from getagentseal/phase8/stateful-cursor
refactor(core): cursor decode into core, queries and caches host-side (phase 8, stateful tier)
2026-07-27 08:10:40 -07:00
iamtoruk
5960ae3535 refactor(core): cursor decode into core, queries and caches host-side (phase 8, stateful tier)
Cursor is the bucket-D stateful multi-store provider: it keeps its bespoke
adapter (no createBridgedProvider) and the host retains every store read.

Tagged-record composition over five query families. The host issues all five
queries in the load-bearing order [1] composerData meta, [2] bubble COUNT,
[3] bubbles (paged or since), [4] agentKv, [5] user messages, preserving the
per-query degradation semantics: [1]/[4]/[5] degrade to empty, [2] to total=0,
and a [3] failure early-returns zero calls while still writing the (empty)
cache and skipping [4]/[5]. decodeCursor() receives the four row sets plus the
host-supplied agentKv timestamp and performs the whole stitched pass — the
pre-pass scan, the agentKv fold, the user-message queue, and all three emit
arms (per-bubble, per-conversation input, stream-only).

The 19-key emitted call shape is a cache-compatibility contract. CURSOR_CACHE_VERSION
stays 6 and PROVIDER_PARSE_VERSIONS['cursor'] is unchanged, so existing
cursor-results.json files on disk are replayed through the new path; adding,
dropping, or undefined-ing any key would poison them. The goldens gate the key
set with Object.keys() on every arm, which is what catches a key present with an
undefined value — toEqual cannot see one, and JSON.stringify drops exactly those
on the way into the cache.

Pricing, bash base-name extraction, display names, project attribution, SQL,
paging, env reads and clock reads all stay host-side; toProviderCall is the
single mapper that re-adds costBasis 'estimated', costIsEstimated true and the
resolved pricing model. No costUSD is ever emitted.

Composer-id / dedup-key envelope finding: composer ids and request ids flow into
sessionId and into the envelope's dedupKeys by design, exactly like every other
provider's machine identifiers, so the content-smuggling block deliberately does
not plant a secret there. Hashing dedup keys uniformly is a schema-wide
follow-up, not a cursor-local change.

Validator fixes on top of the migration:
- relocated the content-smuggling block from cursor-decode.test.ts into
  content-smuggling.test.ts, matching all 25 other providers, and added a probe
  proving each planted secret actually reaches the field it guards
- G11 now gates the undefined-key cache contract it claimed to (toEqual passed
  under an injected extra undefined key; toStrictEqual plus key-set assertions
  catch it)
- restored the CODEBURN_CURSOR_MAX_BUBBLES override in the golden's afterEach so
  G12 cannot leak the scan budget into cursor-large-db-cap.test.ts
- restored the comment rationales that must travel with their code verbatim
  (pos-cursor queue performance note, parseComposerIdFromKey CR/LF signature,
  agentKv stream and pending-flush notes, dedup-key history, costIsEstimated)

The 12 goldens were cross-checked against the pre-migration provider by
restoring it in place: they pass identically on both sides. H2 (queue pop before
skip) and H4 (arm B dedup-key burn before the timestamp check) were mutation
tested and are killed by G8 and C6 respectively.
2026-07-27 08:05:46 -07:00
Resham Joshi
be00eed4e9
Merge pull request #839 from getagentseal/phase8/stateful-antigravity
refactor(core): antigravity decode into core, stitching and caches host-side (phase 8, stateful tier)
2026-07-27 01:09:08 -07:00
iamtoruk
2f3f65533b refactor(core): antigravity decode into core, stitching and caches host-side (phase 8, stateful tier)
Moves every record-parsing arm into @codeburn/core/providers/antigravity:
the protobuf wire reader, the gen_metadata row decode, the RPC
generatorMetadata decode, the statusline JSONL run-collapse/delta decode,
and model canonicalization. All five emit arms (statusline, cache-hit,
sqlite, RPC, RPC-failure fallback) plus the snapshot write-path keep their
host-side control flow byte-for-byte.

Cache integrity: CACHE_VERSION stays 5 and antigravity-results.json keeps
its shape. The cache is not re-derivable — the RPC-failure fallback arm
replays cached.calls for cascades whose language server is gone — so no
bump, and the cache-write-before-seenKeys-filter ordering is preserved in
both the sqlite and RPC arms.

Pricing stays host-side: normalizePricingModel / PRICING_ALIASES remain in
the CLI, and every arm now emits through one shared toProviderCall carrying
costBasis 'estimated' plus pricingModel, and no costUSD.

parseStatusLinePayload's wall clock becomes an injected `at` parameter; the
host passes new Date().toISOString() at each call site, once per payload.

Validator fixes on top of the migration:
- content-smuggling: the hostile statusline record used the hook-payload
  shape, so the decoder dropped it and the cwd/session_id assertions proved
  nothing; corrected to the recorded-event shape, with a call-count guard.
- goldens: G14 maps through the exported host toProviderCall instead of a
  private copy, and a new G15 pins the emit loop's turnIndex-before-seenKeys
  and previousSnapshotUsage-before-skip ordering, which no golden could
  previously detect.
- core: removed an unused type import and a dead CANONICAL_TOOL_NAME const;
  restored the statusline reasoningTokens rationale comment.
2026-07-27 01:04:25 -07:00
Resham Joshi
87b72d7260
Merge pull request #838 from getagentseal/phase8/judgment-mistral-vibe
refactor(core): mistral-vibe decode into core with host-side cost resolution (phase 8, judgment tier)
2026-07-26 23:47:39 -07:00
iamtoruk
e11c29937c refactor(core): mistral-vibe decode into core with host-side cost resolution (phase 8, judgment tier)
Moves the Mistral Vibe rich decode into @codeburn/core behind the bridge:
discovery, file I/O and pricing stay CLI-side, the pure record decode
(including the even allocation of the session dollar figure and the session
token totals across assistant messages) moves byte-exact into core.

Seam adjudication: the draft brief said the `session_cost > 0` gate should
move into core. It cannot — that gate is the first arm of a three-arm cost
resolution whose last arm consults the generic price table, which is
forbidden in core. The whole resolution therefore stays host-side in
`calculateSessionCost` and core receives a pre-resolved `sessionCost`;
core keeps only the pure allocation arithmetic (allocateInteger /
allocateCost, allocationIndex / assistantOrdinal), unchanged in rounding,
remainder distribution and float operation order. The move is
observationally equivalent: the original resolved the cost once per session
during parse, with no per-call state.

Validator fixes on the draft:
- core dropped the `metadata.session_id || basename(sessionDir)` fallback,
  emitting sessionId '' (and colliding dedup keys `mistral-vibe::<msg>`)
  for sessions whose meta.json omits session_id. The host now passes
  `sessionIdFallback`.
- `toProviderCall` set `turnId: undefined` unconditionally, adding a key
  the original omits entirely on the no-assistant session-level arm.
- the moved comment block described a seam that no longer exists; adjusted
  minimally to describe where the resolution actually lives.

Parity was verified arm-by-arm against the pre-migration decode checked out
in place over a 28-session adversarial fixture matrix (strict equality plus
per-call key-presence), and the adversarial allocation arms (7 over 3,
1 over 3, terminal zero-cost, idx-N keys, basename fallback, float-op order)
are promoted into the bridge and core decode tests with values captured
from the original.
2026-07-26 23:43:45 -07:00
Resham Joshi
f4f4dccaec
Merge pull request #837 from getagentseal/phase8/shared-modules
refactor(core): opencode-session shared decode into core — opencode, kilo-code (phase 8, shared batch S2)
2026-07-26 22:59:47 -07:00
iamtoruk
4808b115cc refactor(core): opencode-session shared decode into core — opencode, kilo-code (phase 8, shared batch S2)
Unifies the three-file OpenCode decode family — session-message.ts,
sqlite-session-parser.ts, and opencode-file-parser.ts — into a single core
module, packages/core/src/providers/opencode-session, exposing a two-arm
tagged envelope (kind: 'sqlite' | 'file') over one shared assistant-turn
builder. The SQLite driver, both WITH RECURSIVE session_tree queries,
blobToText, discovery, and extractBashCommands all stay CLI-side.

session-message.ts shrinks to the discovery-side sanitize helper;
sqlite-session-parser.ts and opencode-file-parser.ts keep their SQL and
directory walks and expose readRecords adapters. No decode logic remains
CLI-side in any of the three.

kilo-code is now fully converted: both arms — cline task dirs via the batch-S1
core vscode-cline module and SQLite via the new module — run through core
decodes from one bridged provider, and the thin createClineParser adapter S1
retained is deleted.

The CODEBURN_VERBOSE zero-yield notice is reconstructed host-side by
zed-style decode wrappers, byte-identical for both the OpenCode and KiloCode
labels, with parseFailCount/roleSkipCount derived from the decode's
malformed-json / unknown-shape diagnostics. The session-level SQLite fallback
is pre-fetched onto the envelope instead of queried lazily — output-neutral,
changing only I/O volume — and keeps its distinct key shape, emitting no
skills/subagentTypes keys.

Validator fixes on top of the migration:

- opencode's file arm emitted a spurious SQLite verbose stderr line, reporting
  a previous SQLite source's session id and message count, because the
  readRecords -> decode count handoff was never cleared when switching arms.
  The handoff is now reset on the file path. Pinned by a new regression test.
- The S8 and F9 dedup goldens did not actually pin add-after-build: the SQLite
  fixture used two different message ids, and both file fixtures were degenerate
  (the CLI one wrote the same filename twice and silently overwrote; the core
  one shared a text part across both messages, so the "skipped" message built
  successfully). All four now fail if seenKeys.add is hoisted above the build.
- Added key-presence gates to the goldens, since toEqual accepts a
  present-but-undefined key: the session-level fallback must omit
  skills/subagentTypes, a message-arm call per arm must carry them, and
  fallbackCostUSD must be present for cost 0 and absent for an absent cost.

Goldens were captured pre-migration and re-verified against the original tree
by restoring 38172892's sources in place; all 36 pass on both sides.

Pre-existing issues moved verbatim and left alone: the bare-Record tool map
with a truthy hit check in normalizeToolName (prototype leak on names like
'constructor'), opencode.ts's duplicated display-only tool map, and the dead
inner role guard in the SQLite arm. Every new lookup introduced by the
unification is a Map.
2026-07-26 22:55:34 -07:00
Resham Joshi
3817289238
Merge pull request #836 from getagentseal/phase8/shared-modules
refactor(core): vscode-cline shared decode into core — cline, ibm-bob, roo-code (phase 8, shared batch S1)
2026-07-26 22:07:39 -07:00
iamtoruk
3c0849f2d6 refactor(core): vscode-cline shared decode into core — cline, ibm-bob, roo-code (phase 8, shared batch S1)
Cuts the decode shared by the vscode-cline family out of the CLI and into
@codeburn/core/providers/vscode-cline. This is the first shared-module batch:
one core decoder now backs four provider identities, with the provider name
sourced from context.providerId and the per-consumer fallback model passed as
a decode knob.

- cline, ibm-bob and roo-code become createBridgedProvider specs. Discovery,
  file I/O and pricing stay CLI-side; vscode-cline-parser.ts keeps the
  discovery helpers and gains readClineRecords (I/O adapter) plus
  toClineProviderCall (rich -> ParsedProviderCall, where cost re-enters).
- kilo-code.ts is a zero-line diff. Its SQLite arm does not move until batch
  S2, so createClineParser is retained but reimplemented as a thin adapter
  over the core decode — I/O and mapping only, no decode logic CLI-side.
- Behavior is preserved verbatim, including the dedup burn-through: the key
  is added to seenKeys before the zero-token skip, so a skipped entry burns
  its key. Also preserved: the unguarded new Date(entry.ts), the cost != null
  (not !== undefined) measured-cost test, and project/projectPath written
  unconditionally so key presence is unchanged.

Validator pass over the migration:
- Added a permanent key-presence gate to the shared-bridge goldens. toEqual
  cannot distinguish an absent key from a present-but-undefined one, which
  hid exactly this class of regression in earlier batches; the goldens now
  assert costUSD is absent when estimated and that project/projectPath are
  always present.
- Turned the kilo-code .db: dispatch case from a negative-only assertion into
  a positive one: it now captures and asserts the SQLite arm's open-failure
  line, proving dispatch reached that arm rather than merely yielding nothing
  (and keeping the line out of test output).

Parity was checked against the pre-migration decoder as oracle over 25 task
fixtures per provider, comparing values, key presence, key order, JSON
serialization and the resulting seenKeys sets across two dedup passes — exact
match for all four consumers and for the retained adapter.
2026-07-26 22:03:40 -07:00
Resham Joshi
f984728f90
Merge pull request #835 from getagentseal/phase8/sqlite-copilot
refactor(core): copilot decode into core (phase 8, sqlite batch 3)
2026-07-26 21:21:59 -07:00
iamtoruk
93b4f7707f refactor(core): copilot decode into core (phase 8, sqlite batch 3)
Bridged via a tagged envelope record across the four parse paths
(jsonl / chatsession / jetbrains / otel): readRecords shapes one envelope
per source kind and a single decodeCopilot dispatches on envelope.kind.

The sqlite driver, the three OTel queries, blob reads, git-root probing,
extractBashCommands / extractOtelBashCommands, and the sanctioned
shutdown-site calculateCost residual all stay host-side. The residual
keeps its exact argument order (model, input, 0, cacheWrite, cacheRead, 0),
emits costUSD + costIsEstimated: false with no costBasis key, and carries
its explanatory comment unchanged.

Validator fixes over the draft:
- collectJetBrainsRepoDirCandidates used a [\|"] character class instead
  of the original's (?:\\|") alternation, so a file:// path containing a
  pipe was truncated, its dir never resolved, and the JetBrains project
  fell back to the generic bucket. Restored the alternation.
- the otel arm dropped the subagentTypes key when undefined; the original
  always emits it. Restored so key presence matches byte for byte.
- otel chat-span attributes were looked up with a linear Array.find per
  chat span; replaced with a per-span-id map built in the same pass.

Verified by a differential harness running the pre-migration provider
against the migrated one over 27 scenarios (all eight goldens plus
edge cases), comparing calls, seenKeys, and key presence. The harness is
not committed; the scenarios it proved are now goldens G9-G17.
2026-07-26 21:17:48 -07:00
Resham Joshi
5b7ea74e0a
Merge pull request #834 from getagentseal/phase8/sqlite-batch2
refactor(core): tail migrations — hermes, warp, cursor-agent, quickdesk, devin (phase 8, sqlite batch 2)
2026-07-26 20:30:37 -07:00
iamtoruk
4ef24e9fcd refactor(core): tail migrations — hermes, warp, cursor-agent, quickdesk, devin (phase 8, sqlite batch 2)
Move the pure record decode for five sqlite-backed providers into
@codeburn/core, keeping discovery, sqlite I/O, pricing, and bash
base-name extraction CLI-side behind the dual-registry bridge.

sqlite variant: the host opens the database, runs the SQL, textualizes
BLOBs (warp stylized_command, quickdesk content/tool_names), probes
sqlite_master table variants (quickdesk), and re-throws SQLITE_BUSY so a
transient lock on a live database retries instead of being cached as an
empty result (hermes). The core decoders receive already-normalized rows.

Validator fixes over the drafted migration (original behavior is the
authority in every case):

- warp: restored the `run_command` tool-name check as an identity
  comparison. The draft had rewritten it as a bare Record lookup, so
  'constructor'/'toString'/'__proto__' resolved to inherited Object
  members instead of passing through. Added a regression test.
- warp: restored `safeNumber` to the host's semantics (positive finite
  numbers only). The draft's rewrite accepted numeric strings and
  negative values, changing token budgets and dominant-model selection
  for untrusted conversation_data.
- warp: `estimateTokensFromChars` now mirrors the host helper exactly.
- devin: model DISPLAY names move back CLI-side. The draft shipped a
  7-line regex standing in for the host's `getShortModelName`, which
  mis-rendered every non-Claude model id. The decoder now emits the raw
  generation_model / model_name ids and the CLI formats them.
- devin: dropped the added `costBasis: 'measured'`; the pre-migration
  call carried `costUSD` with no basis marker. Golden corrected.
- quickdesk: fixed an inverted source-variant predicate that routed
  `sourceId: 'metrics'` on a sessions.db path (and `sourceId:
  'sessions-db'` on a metrics path) to the wrong parser.
- cursor-agent: the "unrecognized transcript format" warning is now
  re-emitted from the real decode result via a decode wrapper. The draft
  re-derived `recognized` host-side as `hasUser && hasAssistant`, which
  silently dropped the warning whenever a jsonl transcript had both roles
  but produced no turns.
- cursor-agent: restored the per-conversation summary cache, so the
  attribution database is opened once per conversation id, not per source.
- cursor-agent/devin: the session id is derived once, host-side, and
  passed through, removing a second derivation that could disagree with
  the host's on Windows-style paths.
- hermes: `browser_vision` maps to Vision, matching the original table.

Goldens re-verified by running each bridge fixture through the
pre-migration provider implementation: all five reproduce field-for-field.
2026-07-26 20:26:18 -07:00
Resham Joshi
6c64a1bbde
Merge pull request #832 from getagentseal/phase8/sqlite-batch1
refactor(core): tail migrations — crush, zcode, zed, forge, goose (phase 8, sqlite batch 1)
2026-07-26 18:31:30 -07:00
iamtoruk
afaf9ffc8a refactor(core): tail migrations — crush, zcode, zed, forge, goose (phase 8, sqlite batch 1)
Category B (sqlite) variant of the bridge migration: the sqlite driver and every
SQL query stay CLI-side. Each provider's `readRecords` opens the database, runs
the same queries as before, and hands the resulting rows (blob and all) to a
pure core decoder; `toProviderCall` maps the rich, cost-free decode back onto
ParsedProviderCall, where cost re-enters via the parser.ts pricing pass.

Per provider:
- crush: session row + dominant-model query -> one combined record. Crush stores
  cost in dollars, so a row with cost > 0 carries `measuredCostUSD` (costBasis
  'measured'); a zero-cost row falls back to token estimation, arm order intact.
- zcode: model_usage + tool_usage row sets -> one composite record. Each turn's
  tools still attach to the first non-skipped usage row of that turn only.
- zed: threads rows handed over compressed; zstd decompression, JSON parsing and
  per-request/cumulative-remainder accounting are pure. The Node >= 22.15 zstd
  capability check stays host-side.
- forge: conversation row handed over with `context` still serialized; JSON
  parsing and per-message decode are pure. Bash base-name extraction (and its
  strip-ansi dependency) stays CLI-side over the decoder's raw command strings.
- goose: session + assistant tool-message + first-user-message rows, BLOB
  columns pre-converted to text host-side, bundled into one composite record.

Validator fixes (original behavior is the authority):
- forge: the draft replaced the pre-migration `mapToolName` switch with an
  object-literal lookup. Tool names come straight from conversation JSON, so
  names colliding with Object.prototype members ("constructor", "toString",
  "__proto__", "hasOwnProperty") resolved to inherited Functions / the prototype
  object and were pushed into `tools` as non-strings instead of falling through
  to the identity default. Restored the switch and pinned the arm in the fixture.
- zed: the draft routed the "skipped N unreadable Zed threads" notice into
  record diagnostics, which the bridge discards, silently dropping a warning the
  pre-migration decode printed. Re-emitted host-side from the diagnostics count
  and pinned with a stderr assertion.
- Fixture coverage extended for the arms that were regression-blind: forge's
  prototype-named tool calls, zed's aggregate stderr line, and goose's
  single-turn `toolSequence` omission plus the unparseable-timestamp fallback.

Parity was verified independently of the bridge tests with a git-show harness
that runs the same fixtures through the pre-migration provider files and asserts
field-for-field equality, including the extra arms above.
2026-07-26 18:27:44 -07:00
Resham Joshi
104365414f
Merge pull request #831 from getagentseal/phase8/tail-batch2
refactor(core): tail migrations — gemini, kimicode, pi/omp (phase 8, batch 2)
2026-07-26 17:36:44 -07:00
iamtoruk
ec449afa3f test: make durable-totals live-session fixture time-of-day independent
The seeded 'today' session used a fixed noon timestamp; under the suite's
TZ=UTC pin any run between 00:00 and ~12:30 UTC placed it in the future,
so the provider-filtered durable path (today-range ends at now) dropped it
and the parity assertion failed. Seed timestamps proportionally between
start-of-today and now so they are always today and always in the past.
2026-07-26 17:33:42 -07:00
iamtoruk
b3e483ad3b Merge remote-tracking branch 'origin/feat/core-extraction' into phase8/tail-batch2 2026-07-26 17:23:21 -07:00
Resham Joshi
57a9892b04
Merge pull request #830 from getagentseal/phase8/kimi-batch-b
refactor(core): tail migrations — codebuff, openclaw (phase 8)
2026-07-26 17:22:54 -07:00
iamtoruk
1c010918ec refactor(core): tail migrations — gemini, kimicode, pi/omp (phase 8) 2026-07-26 16:49:17 -07:00
iamtoruk
541ac2b4ce refactor(core): tail migrations — codebuff, openclaw (phase 8) 2026-07-26 16:41:33 -07:00
Resham Joshi
5a82402d4e
Merge pull request #829 from getagentseal/phase8/tail-batch1
refactor(core): tail migrations — zerostack, droid, mux, open-design, lingtai-tui (phase 8)
2026-07-26 16:16:03 -07:00
iamtoruk
d4664a6dfe test: make grok bridge golden path-portable 2026-07-26 15:25:56 -07:00
iamtoruk
bf40ccaff1 Merge remote-tracking branch 'origin/feat/core-extraction' into phase8/tail-batch1 2026-07-26 15:23:09 -07:00
iamtoruk
a562d1c040 refactor(core): tail migrations — zerostack, droid, mux, open-design, lingtai-tui (phase 8)
All five providers wired through createBridgedProvider with decode in
packages/core only. Deep validation corrected the initial drafts: zerostack
dedup-key/sessionId/project regressions, droid and mux crude bash-extraction
reimplementations (host now runs the real extractBashCommands on raw
strings), lingtai-tui dedup-key source, open-design dropped project. Goldens
are byte-identical toEqual pins anchored to the pre-migration decode.
2026-07-26 15:23:09 -07:00
Resham Joshi
43058baadd
Merge pull request #828 from getagentseal/phase8/kimi-batch-a
refactor(core): tail migrations — grok, kimi, codewhale (phase 8)
2026-07-26 15:15:18 -07:00
iamtoruk
05b3380635 refactor(core): tail migrations — grok, kimi, codewhale (phase 8)
Move the pure record decode for grok, kimi, and codewhale into
@codeburn/core and rewire the CLI providers through createBridgedProvider,
keeping discovery, file I/O, config resolution, and pricing host-side.

Validation fixes (legacy-parity, caught arm-by-arm against the pre-lift
decode):
- grok/codewhale: the host toProviderCall wrongly wrapped bashCommands in a
  Set. The legacy decode deduped nothing (flat push of extracted base
  commands), so per-command breakdown counts drifted. Drop the Set.
- kimi: the core decode dropped the legacy per-turn tool Set, so repeated
  tools in a turn no longer collapsed. Restore [...new Set(tools)].
- codewhale: remove an unused codeWhaleToolNameMap import.

Parity fixtures now exercise the dedup arms (repeated tools/commands) and the
goldens are pinned to the ORIGINAL in-CLI decode output, captured by running
the pre-migration providers over the same fixtures.
2026-07-26 15:11:38 -07:00
Resham Joshi
ae2d3e97aa
Merge pull request #827 from getagentseal/phase8/bridge
feat(core): dual-registry bridge + qwen exemplar migration (phase 8.1)
2026-07-26 14:31:54 -07:00
iamtoruk
0381fc9e86 feat(core): dual-registry bridge + qwen exemplar migration (phase 8.1) 2026-07-26 14:26:00 -07:00
Resham Joshi
615e7231c2
Merge pull request #826 from getagentseal/phase7/act-apply
test(core+cli): act/apply stays host-derived — advisory findings gated (phase 7)
2026-07-26 14:06:18 -07:00
iamtoruk
dffd49a2c3 test(core+cli): act/apply stays host-derived — advisory findings gated (phase 7) 2026-07-26 14:02:43 -07:00
Resham Joshi
07f9998d72
Merge pull request #825 from getagentseal/phase6/classifier-gate
test(core): architecture gate — classification and free text can never enter core (phase 6)
2026-07-26 13:52:14 -07:00