f99010fae1
Desktop Artifacts / Desktop Build (Linux) (push) Waiting to run
Desktop Artifacts / Desktop Build (Windows) (push) Waiting to run
Desktop Artifacts / Desktop Build (Linux (arm64)) (push) Waiting to run
Desktop Artifacts (macOS) / Desktop Build (macOS (aarch64)) (push) Waiting to run
Desktop Artifacts (macOS) / Desktop Build (macOS (x86_64)) (push) Waiting to run
CI / lint (push) Failing after 1s
CI / frontend (push) Failing after 1s
CI / scripts (push) Failing after 1s
CI / Go Test (ubuntu-latest) (push) Failing after 0s
CI / frontend-node-25 (push) Failing after 1s
CI / docs (push) Failing after 0s
CI / coverage (push) Failing after 0s
CI / e2e (push) Failing after 0s
Docker / build-and-push (push) Failing after 1s
CI / integration (push) Failing after 4m43s
CI / Go Test (windows-latest) (push) Has been cancelled
CI / Desktop Unit Tests (Windows) (push) Has been cancelled
158 lines
6.1 KiB
Go
158 lines
6.1 KiB
Go
package parser
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"database/sql"
|
|
"encoding/hex"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// Antigravity session databases carry no literal product version: PRAGMA
|
|
// user_version is a schema marker (1), not a dotted release, and neither the
|
|
// .db nor ~/.gemini state records the producing agy build. The only stable
|
|
// discriminator is the SQLite SCHEMA FINGERPRINT -- a sha256 over the database's
|
|
// CREATE statements (from sqlite_master) plus user_version. One schema spans
|
|
// several agy dot releases, so the fingerprint maps to a release range label.
|
|
//
|
|
// The fingerprint algorithm is kept byte-for-byte identical to agy-reader's
|
|
// agy-format-audit recorder (skills/agy-format-audit/scripts/audit_format.sh):
|
|
//
|
|
// { sqlite3 SELECT sql FROM sqlite_master WHERE sql IS NOT NULL ORDER BY type, name
|
|
// sqlite3 PRAGMA user_version } | sha256sum
|
|
//
|
|
// so labels seeded from agy-reader's COMPATIBILITY.md match real databases.
|
|
|
|
// antigravitySchemaPrefixLen is the number of leading hex characters of the
|
|
// full sha256 fingerprint kept for matching and for the unknown-schema marker.
|
|
// Short enough to keep labels well under 64 chars, long enough to stay unique.
|
|
const antigravitySchemaPrefixLen = 12
|
|
|
|
// antigravitySchemaVersions maps a short schema-fingerprint prefix to a known
|
|
// agy release-range label. Seeded from agy-reader COMPATIBILITY.md and verified
|
|
// against real ~/.gemini/antigravity[-cli] databases. Keys are the first
|
|
// antigravitySchemaPrefixLen hex chars of the full sha256.
|
|
//
|
|
// Full fingerprints (for traceability):
|
|
// - sha256:1ca98426f561fe73223c8620a238405030fdb3014444d970e1300a6009f72f43
|
|
// user_version=1, 7 tables (battle_mode_infos, executor_metadata,
|
|
// gen_metadata, parent_references, steps, trajectory_meta,
|
|
// trajectory_metadata_blob), indices idx_steps_status, idx_steps_step_type
|
|
// == agy 1.0.7-1.0.10.
|
|
var antigravitySchemaVersions = map[string]string{
|
|
"1ca98426f561": "1.0.7-1.0.10",
|
|
}
|
|
|
|
// antigravitySchemaUnknownPrefix tags an unrecognized schema fingerprint so new
|
|
// agy schemas stay visible in source_version (e.g. "agy-schema:abc123def456").
|
|
const antigravitySchemaUnknownPrefix = "agy-schema:"
|
|
|
|
// antigravitySchemaFingerprint computes the full hex sha256 schema fingerprint
|
|
// for an open Antigravity SQLite database. It mirrors the agy-reader audit
|
|
// recorder byte-for-byte: every non-null sqlite_master sql value ordered by
|
|
// (type, name), each followed by a newline, then the decimal user_version
|
|
// followed by a newline. Returns ("", err) when the schema cannot be read.
|
|
func antigravitySchemaFingerprint(db *sql.DB) (string, error) {
|
|
rows, err := db.Query(
|
|
`SELECT sql FROM sqlite_master ` +
|
|
`WHERE sql IS NOT NULL ORDER BY type, name`,
|
|
)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer rows.Close()
|
|
|
|
h := sha256.New()
|
|
for rows.Next() {
|
|
var stmt string
|
|
if err := rows.Scan(&stmt); err != nil {
|
|
return "", err
|
|
}
|
|
h.Write([]byte(stmt))
|
|
h.Write([]byte{'\n'})
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
var userVersion int64
|
|
if err := db.QueryRow(`PRAGMA user_version`).Scan(&userVersion); err != nil {
|
|
return "", err
|
|
}
|
|
h.Write([]byte(strconv.FormatInt(userVersion, 10)))
|
|
h.Write([]byte{'\n'})
|
|
|
|
return hex.EncodeToString(h.Sum(nil)), nil
|
|
}
|
|
|
|
// antigravitySchemaLabel maps a full hex fingerprint to a short source_version
|
|
// label: a known release range, or an "agy-schema:<prefix>" marker for an
|
|
// unrecognized (newer) schema. Returns "" for an empty fingerprint so callers
|
|
// can leave SourceVersion blank when no schema was available.
|
|
func antigravitySchemaLabel(fingerprint string) string {
|
|
if fingerprint == "" {
|
|
return ""
|
|
}
|
|
prefix := fingerprint
|
|
if len(prefix) > antigravitySchemaPrefixLen {
|
|
prefix = prefix[:antigravitySchemaPrefixLen]
|
|
}
|
|
if label, ok := antigravitySchemaVersions[prefix]; ok {
|
|
return label
|
|
}
|
|
return antigravitySchemaUnknownPrefix + prefix
|
|
}
|
|
|
|
// antigravitySourceVersion derives the source_version label for an open
|
|
// Antigravity database, shared by the IDE (.db) and CLI (.db) parse paths so
|
|
// both classify identically. Returns "" when the schema cannot be read, so a
|
|
// sidecar-only or undecodable session leaves SourceVersion empty rather than
|
|
// fabricating a label.
|
|
func antigravitySourceVersion(db *sql.DB) string {
|
|
fp, err := antigravitySchemaFingerprint(db)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return antigravitySchemaLabel(fp)
|
|
}
|
|
|
|
// DecodeConfidence values classify how much trust the schema-fingerprint
|
|
// decode of an Antigravity session warrants. They are consumed by the
|
|
// session-detail badge (as string literals) and the operator surfaces.
|
|
const (
|
|
DecodeConfidenceHigh = "high"
|
|
DecodeConfidenceLow = "low"
|
|
)
|
|
|
|
// DecodeConfidence reports how much to trust the heuristic decode of an
|
|
// Antigravity session, derived purely from its already-computed source_version
|
|
// label (see antigravitySchemaLabel). It is the single source of truth for the
|
|
// rule, shared by the service layer (session-detail badge), the doctor
|
|
// diagnostics, and the sync anomaly counter, so the "agy-schema:" prefix
|
|
// knowledge stays in one place next to the label logic.
|
|
//
|
|
// The agent gate is mandatory: SourceVersion is a generic field that other
|
|
// parsers also populate (piebald.go sets "piebald-appdb-v1", commandcode.go
|
|
// sets "2"), so a non-empty label alone must never imply confidence. Both the
|
|
// IDE agent ("antigravity") and the CLI agent ("antigravity-cli") classify
|
|
// identically because both .db parse paths compute the same fingerprint.
|
|
//
|
|
// - antigravity / antigravity-cli with an "agy-schema:" label (an
|
|
// unrecognized, newer schema) -> "low": the decode is heuristic and may be
|
|
// incomplete or wrong.
|
|
// - antigravity / antigravity-cli with any other non-empty label (a known
|
|
// release range) -> "high".
|
|
// - empty label, or any other agent -> "" (no value, no badge).
|
|
func DecodeConfidence(agent, sourceVersion string) string {
|
|
if agent != string(AgentAntigravity) && agent != string(AgentAntigravityCLI) {
|
|
return ""
|
|
}
|
|
if sourceVersion == "" {
|
|
return ""
|
|
}
|
|
if strings.HasPrefix(sourceVersion, antigravitySchemaUnknownPrefix) {
|
|
return DecodeConfidenceLow
|
|
}
|
|
return DecodeConfidenceHigh
|
|
}
|