cmd

package
v0.17.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 15, 2026 License: Apache-2.0 Imports: 53 Imported by: 0

Documentation

Index

Constants

View Source
const CacheVersion = "0.1.0"

CacheVersion is the schema_version mache writes into the lockfile meta. Bumps require an LLO ADR-0021 schema change first.

View Source
const ConfigFileName = ".mache.json"

ConfigFileName is the convention file looked up by `mache serve`.

View Source
const MacheProducerName = "mache"

MacheProducerName is the producer field per ADR-0020. Short-name convention for v1; reverse-DNS reserved for v2 if collisions.

View Source
const SmellRulesEnvVar = "MACHE_SMELL_RULES_DIR"

SmellRulesEnvVar names the environment variable that points to a directory of JSON files containing additional SmellRule entries. External rules are merged with the built-in registry per find_smells request (see activeSmellRules) and are otherwise indistinguishable from built-ins — same MCP shape, same query contract, same pre-flight table check. Loading per-request (rather than once at package init) is what makes rule files live-reloadable: drop a new JSON in the dir and the next call sees it, no restart.

Each file in the directory must be a single SmellRule object (not an array — one rule per file keeps diffs clean and avoids "the third rule errored, what was the first?" debugging). The loader is fail-fast: a single read / parse / validation / collision error aborts loading, returning the error to the caller. serve logs and falls back to built-ins in that case so a typo can't take down the server; the CLI surfaces the error directly.

Variables

View Source
var (
	// Version is the binary's build version, shown by `mache version` and
	// stamped into build artifacts (_mache_meta, the build-cache lockfile
	// producer field, the MCP server version). `task build` and release.yml
	// inject it from `git describe --tags` via -ldflags, so it tells the truth
	// about the built code: a clean tag (0.10.0) on a tagged release, a
	// git-distance string (0.9.0-9-gabc1234) between releases. A bare
	// `go build` / `go test` (no ldflags) falls back to the clean release base
	// in internal/buildinfo (version.txt).
	//
	// NOTE: server.json and melange.yaml derive from buildinfo.Version (the
	// clean, committed, drift-checked release base) — never from this string —
	// so a dev-distance build version can't break the server-json drift gate or
	// produce an invalid apk package version.
	Version = resolveBuildVersion()
	Commit  = "none"
	Date    = "unknown"
)
View Source
var MacheProducerVersion = Version

MacheProducerVersion is the mache version recorded in the lockfile. Sourced from the embedded internal/buildinfo via the package-level Version (same value as the binary's `mache version`), so the lockfile producer field, server.json, and the binary never disagree.

Functions

func Execute

func Execute()

Execute runs the root command.

func LoadCapnpBindings added in v0.8.0

func LoadCapnpBindings(qg refsQuerier, dbPath string) error

LoadCapnpBindings populates the per-connection _capnp_binding_refs TEMP table from the sibling .bindings.capnp event log of dbPath. Must be called AFTER ensureCanonicalViews on the same connection (the TEMP table is created there).

No-op when the sibling log is missing (returns nil) — the canonical view's UNION arm just stays empty. Returns an error when the log exists but is corrupt.

Producers that write to BOTH _lsp_refs AND .bindings.capnp will produce duplicate-shaped rows in v_refs (one per producer); set- membership consumers (alive-check in dead_code) deduplicate naturally, so this isn't a correctness issue. Once the capnp event log is the canonical producer (post-T8.5), the _lsp_refs UNION arm in ensureCanonicalViews can be removed.

func PresetNames added in v0.6.0

func PresetNames() []string

PresetNames returns the sorted list of available preset schema names.

Types

type MountMetadata added in v0.2.0

type MountMetadata struct {
	PID        int       `json:"pid"`
	Source     string    `json:"source"`
	MountPoint string    `json:"mount_point"`
	Type       string    `json:"type,omitempty"`       // "nfs", "fuse", "mcp-http", "mcp-stdio"
	GitRepo    string    `json:"git_repo,omitempty"`   // org/repo
	GitBranch  string    `json:"git_branch,omitempty"` // branch name
	GitRemote  string    `json:"git_remote,omitempty"` // full remote URL
	Timestamp  time.Time `json:"timestamp"`
	Writable   bool      `json:"writable"`
	Addr       string    `json:"addr,omitempty"` // listen address for MCP HTTP servers
}

MountMetadata stores information about an agent-mode mount.

type OCIBlobMissingError added in v0.9.0

type OCIBlobMissingError struct {
	Digest string
}

OCIBlobMissingError is returned by GetBlob on 404. Callers can errors.As() it to distinguish "blob not present" from other errors.

func (*OCIBlobMissingError) Error added in v0.9.0

func (e *OCIBlobMissingError) Error() string

type OCIClient added in v0.9.0

type OCIClient struct {
	// contains filtered or unexported fields
}

OCIClient speaks the build-cache/v1 transport against a provider.

Construct via NewOCIClient(baseURL). Methods are safe to call concurrently on the same client; the underlying http.Client handles connection pooling.

func NewOCIClient added in v0.9.0

func NewOCIClient(baseURL, producer, scope string) (*OCIClient, error)

NewOCIClient builds a client targeting <baseURL>/v2/<producer>/<scope>/. Empty baseURL is rejected up front; producer + scope can be empty only if the caller is using methods that don't need them (we don't have any such methods today, but the constructor doesn't enforce non-empty to keep test ergonomics simple).

func (*OCIClient) GetBlob added in v0.9.0

func (c *OCIClient) GetBlob(ctx context.Context, digest string) ([]byte, error)

GetBlob fetches the bytes under `digest` and verifies BLAKE3(body) matches the digest. Mismatch is a hard error — the consumer MUST refuse to vouch for tampered/corrupted blobs (per LLO BlobStore substrate contract).

func (*OCIClient) GetManifest added in v0.9.0

func (c *OCIClient) GetManifest(ctx context.Context, ref string) (*OCIManifest, string, error)

GetManifest fetches and parses the manifest under <ref>. Verifies the body is well-formed OCI manifest with the expected mediaType + config.mediaType, and re-hashes the body to assert content-address integrity (if <ref> looks like a digest).

Returns the parsed manifest + the manifest's actual BLAKE3 digest (useful for tag-resolved pulls: pin the digest from the response).

func (*OCIClient) HeadBlob added in v0.9.0

func (c *OCIClient) HeadBlob(ctx context.Context, digest string) (bool, error)

HeadBlob reports whether the registry has a blob at the given digest. Mapping: 200 → true, 404 → false, anything else → error.

Per push-protocol.md step 1: producers HEAD before uploading to honor the idempotency contract (no re-upload of existing chunks).

func (*OCIClient) PullBundle added in v0.9.0

func (c *OCIClient) PullBundle(ctx context.Context, ref string, parallelism int) (*OCIManifest, []byte, map[string][]byte, string, error)

PullBundle is the inverse of PushBundle: GET manifest, GET config, GET every layer, verify-on-read at every step.

Returns (manifest, configBytes, chunks). chunks is a map digest → bytes.

Caller is responsible for asserting the lockfile's internal invariants (chunk-hash chain, root). This client just delivers the bytes faithfully.

func (*OCIClient) PushBundle added in v0.9.0

func (c *OCIClient) PushBundle(ctx context.Context, manifest *OCIManifest, configBytes []byte, chunks map[string][]byte, tag string, parallelism int) (string, error)

PushBundle uploads a (config, chunks) bundle:

  • PutBlob the config (idempotent)
  • PutBlob every chunk in parallel (idempotent, bounded concurrency)
  • PutManifest under both the manifest's content digest AND the human-readable tag (if non-empty)

Returns the manifest's content digest. Producers SHOULD pin to that digest for future pulls even when they also pushed a tag.

chunks is a map digest → bytes. The manifest references those digests in its layers; if a layer digest isn't in the map, that's a producer bug and PushBundle fails.

parallelism controls how many concurrent chunk uploads run. 0 → 4.

func (*OCIClient) PutBlob added in v0.9.0

func (c *OCIClient) PutBlob(ctx context.Context, digest string, data []byte) error

PutBlob uploads `data` under `digest`. Two-step per OCI:

POST /v2/<scope>/blobs/uploads/      → 202 Location: <upload-url>
PUT  <upload-url>?digest=<digest>    → 201 Created

HEAD-check first: skip the upload if the registry already has it. Returns nil on success (idempotent — re-uploading an existing blob is a no-op from the producer's perspective).

func (*OCIClient) PutManifest added in v0.9.0

func (c *OCIClient) PutManifest(ctx context.Context, ref string, manifest *OCIManifest) (string, error)

PutManifest uploads the manifest under <ref> (a digest like "sha256:abc..." or a tag like "latest").

Returns the manifest's own digest (BLAKE3 of the JSON body) so producers that pushed by tag can also pin the immutable form.

func (*OCIClient) SetHTTPClient added in v0.9.0

func (c *OCIClient) SetHTTPClient(client *http.Client)

SetHTTPClient swaps the underlying *http.Client — useful for tests (httptest) and for callers that need custom timeouts / TLS.

func (*OCIClient) SetToken added in v0.9.0

func (c *OCIClient) SetToken(token string)

SetToken configures bearer-token auth for subsequent requests. Empty token clears it.

type OCIDescriptor added in v0.9.0

type OCIDescriptor struct {
	MediaType   string            `json:"mediaType"`
	Digest      string            `json:"digest"`
	Size        int64             `json:"size"`
	Annotations map[string]string `json:"annotations,omitempty"`
}

OCIDescriptor matches OCI Image Spec descriptor shape.

type OCIManifest added in v0.9.0

type OCIManifest struct {
	SchemaVersion int               `json:"schemaVersion"`
	MediaType     string            `json:"mediaType"`
	Config        OCIDescriptor     `json:"config"`
	Layers        []OCIDescriptor   `json:"layers"`
	Annotations   map[string]string `json:"annotations,omitempty"`
}

OCIManifest is the JSON shape per cloister-spec/build-cache/v1/wire/manifest-shape.md. Used for both push (we build + serialize) and pull (we parse + verify).

type OCIManifestMissingError added in v0.9.0

type OCIManifestMissingError struct {
	Ref string
}

OCIManifestMissingError is returned by GetManifest on 404.

func (*OCIManifestMissingError) Error added in v0.9.0

func (e *OCIManifestMissingError) Error() string

type ProjectConfig added in v0.6.0

type ProjectConfig struct {
	Sources []SourceConfig `json:"sources"`
	// SmellRulesDir points at a directory of external SmellRule JSON
	// files (see LoadExternalSmellRules). A relative value is resolved
	// against the .mache.json's own directory for portability; see
	// resolveSmellRulesDir. Optional — omit to use built-in rules only.
	SmellRulesDir string `json:"smellRulesDir,omitempty"`
}

ProjectConfig represents the .mache.json project configuration.

type Severity added in v0.9.0

type Severity string

Severity is one of off / warn / error. ESLint precedent (string names, no numeric aliases). See mache-ec1a06 for the prior-art rationale across ruff/pylint/eslint/clippy/semgrep.

const (
	SeverityOff   Severity = "off"
	SeverityWarn  Severity = "warn"
	SeverityError Severity = "error"
)

type SmellRule added in v0.8.0

type SmellRule struct {
	ID          string   // stable identifier, used as the MCP tool argument
	Languages   []string // matches `_source.language` values; empty = any
	Description string   // shown in the help payload
	Query       string   // SQL with one `%s` placeholder for the optional scope clause
	ScopeColumn string   // SQL expression to compare to source_id; empty disables source_id scoping
	// Requires lists the SQL tables this rule reads. Surfaced in the
	// rules listing so an agent can decide upfront whether the rule is
	// usable on the active backend. Standalone mache emits `nodes`,
	// `node_refs`, `node_defs`; LLO-built .db additionally has `_ast`,
	// `_source`, `_imports`, `_lsp*`. See docs/ARCHITECTURE.md
	// "Interplay with ley-line-open" for the full table.
	Requires []string
	// DefaultMinMetric is the rule's recommended metric threshold
	// when the request omits min_metric. Zero means "no default
	// threshold; return all rows." Used for metric-bearing rules
	// where the query's natural output includes a long tail of
	// uninteresting low-metric rows (e.g. long_function returns
	// every function regardless of size; without a default
	// threshold the response is dominated by 1-line setters).
	// Callers can pass min_metric=0 explicitly to override the
	// default and see everything; any non-zero min_metric also
	// overrides.
	DefaultMinMetric int64
	// Severity controls whether a finding from this rule is fatal to
	// the gate. Three tiers per ESLint precedent (off/warn/error) —
	// see ADR-0018 and bead mache-ec1a06 for the prior-art rationale.
	//
	//   - "off"   — rule defined but never produces findings; useful
	//     for shipping a rule in a pack that's disabled for now
	//   - "warn"  — emits findings, exit 0 (observability default)
	//   - "error" — emits findings, exit 1 (rule author asserts this
	//     drift must not ship)
	//
	// Default ("") is treated as "warn" — preserves the existing
	// observability contract for all rules that haven't opted in.
	// Gate decision is made at CLI invocation via --fail-on (pylint
	// precedent): rule says what's true, gate decides whether truth
	// is fatal.
	Severity Severity
	// Tags is a free-form classification used for CLI selection via
	// --tags=foo,bar. Per ADR-0018 + research, NOT a closed enum:
	// stages (pre-commit, ci) emerge as CLI profiles from
	// (--tags × --fail-on) combinations, not from a fixed schema.
	// Cap at 3-5 tags per rule to avoid the clippy-group explosion;
	// expand the vocabulary deliberately, not reactively.
	Tags []string
}

SmellRule describes one structural code-smell pattern. Rules are language-aware: each carries the language(s) it applies to plus a SQL query template that runs against the `_ast` / `nodes` / `node_defs` / `node_refs` tables produced by `leyline parse`.

The query MUST select exactly seven columns:

source_id, node_id, start_byte, end_byte, start_row, start_col, metric

in that order. `metric` is an integer score (cyclomatic complexity, fan-out count, line length, etc.); binary rules that don't carry a metric emit `0 AS metric`. The handler shapes the row into a uniform response with 1-based line/column and an optional snippet.

`ScopeColumn` is the SQL expression the handler will compare to source_id when the caller passes `source_id` to find_smells (e.g. "lit.source_id" for AST-walking rules; "n.source_file" for rules that join via nodes). The query template MUST contain a single `%s` placeholder where the scope clause should be spliced in; rules unconcerned with scoping can leave ScopeColumn blank.

Threshold filtering on the metric column is server-side via the `min_metric` request arg — handler drops findings whose metric is below the cutoff before returning. Default 0 keeps every row.

Bead mache-6z2e tracks the broader "machelint" idea — declarative rules consumed via this tool. Today the registry is hard-coded; in the future it becomes user-extensible (declarative JSON, per-repo overrides, etc.).

func LoadExternalSmellRules added in v0.8.0

func LoadExternalSmellRules(dir string) ([]SmellRule, error)

LoadExternalSmellRules reads `*.json` files from dir, parses each as a SmellRule, validates the result, and returns the parsed rules. Fail-fast: any read, parse, validation, or collision error aborts and returns immediately — caller decides whether to log+skip or treat as fatal. init() logs and skips; tests fail loudly.

Validation:

  • ID must be non-empty and not collide with a built-in rule (or another external loaded from this same dir)
  • Query must be non-empty, contain exactly one '%s' placeholder for the scope clause, AND be a valid fmt.Sprintf format string (no stray `%` chars that fmt would treat as verbs — common trap with SQL `LIKE '%foo%'` patterns; escape as `%%`)
  • Requires may be empty (rule reads no tables) or list table names

func (*SmellRule) Effective added in v0.9.0

func (r *SmellRule) Effective() Severity

Effective returns the resolved severity, treating the zero value ("") as warn — the default for any rule that hasn't opted in. Callers asking "is this rule fatal" should always go through Effective() rather than reading Severity directly.

type SourceConfig added in v0.6.0

type SourceConfig struct {
	Path   string `json:"path"`
	Schema string `json:"schema,omitempty"`
}

SourceConfig describes a single data source within a project.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL