Documentation
¶
Overview ¶
SPDX-License-Identifier: MIT Purpose: adw — Architectural Debt Watchdogs. Detects god modules, circular dependencies, high coupling, long functions, large files, and code smells. Pure Go implementation.
SPDX-License-Identifier: MIT Purpose: agent-show and agent-doctor CLI commands.
SPDX-License-Identifier: MIT Purpose: agent-edit, agent-set, agent-reset CLI commands.
SPDX-License-Identifier: MIT Purpose: shared helpers for the agent edit/set/reset/show/doctor CLI.
SPDX-License-Identifier: MIT Purpose: ast_go — exact Go outlines via go/parser + go/ast (stdlib, zero dependencies, always on). Replaces every Go regex heuristic: real start/end lines from the token.FileSet, methods named "Receiver.Name", struct fields and interface methods as children, full import list. Docs: cmd/sin-code/internal/ast.doc.md
SPDX-License-Identifier: MIT Purpose: ast_provider — language-aware structure extraction behind a single interface. Three tiers, best available wins: exact go/ast for Go (stdlib, always on), tree-sitter for Python/JS/TS/Rust/Java when built with -tags treesitter (CGO, opt-in — default build stays zero-dependency), and a pure-Go structural engine (brace/indent tracking with real end lines) as the universal fallback. Consumers: read --mode outline, edit --symbol, grasp, and (later) map/SCKG. Docs: cmd/sin-code/internal/ast.doc.md
SPDX-License-Identifier: MIT Purpose: ast_structural — pure-Go structural outlines for non-Go languages (always on; upgraded transparently by tree-sitter when built with -tags treesitter). Unlike the legacy single-line regex heuristics this engine computes REAL end lines: brace-depth tracking (string/comment aware) for C-family languages, indentation tracking for Python. That is what makes AST-anchored symbol edits safe without CGO. Docs: cmd/sin-code/internal/ast.doc.md
SPDX-License-Identifier: MIT Purpose: Build-tag stub: without -tags treesitter the structural engine (ast_structural.go) handles all non-Go languages and the bundle stays zero-dependency. This file only documents the seam. Docs: cmd/sin-code/internal/ast.doc.md
SPDX-License-Identifier: MIT Purpose: Shared utilities for the sin-code unified binary (error printing, shared flags, output formatting). All subcommands import this package.
SPDX-License-Identifier: MIT Purpose: config — view and manage sin-code configuration files. Supports reading, setting, and listing configuration values. Docs: config.doc.md
SPDX-License-Identifier: MIT Purpose: discover — file discovery with relevance scoring, pattern matching, and dependency analysis. Built-in Go implementation (no external binary dependency).
SPDX-License-Identifier: MIT Purpose: edit — hashline-anchored surgical file editing. Replaces fragile native string/line editors: anchors carry a content hash so stale edits fail loudly instead of corrupting files, drift up to ±25 lines is auto-resolved, occurrence counting prevents ambiguous string replaces, and every edit re-runs the atomic write path with syntax validation. Docs: cmd/sin-code/internal/edit.doc.md
SPDX-License-Identifier: MIT Purpose: efm — Ephemeral Full-Stack Mocking. Manages docker-compose stacks and ephemeral test environments. Pure Go implementation.
SPDX-License-Identifier: MIT Purpose: execute — safe shell command execution with safety checks, secret redaction, timeout handling, and error analysis. Built-in Go implementation.
SPDX-License-Identifier: MIT Purpose: grasp — deep code understanding for a single file. Built-in Go implementation providing structure, dependencies, and usage context.
SPDX-License-Identifier: MIT Purpose: harvest — URL fetching with caching, structure extraction, and change detection. Built-in Go implementation using net/http with local disk cache.
SPDX-License-Identifier: MIT Purpose: hashline — content-hash anchored line addressing shared by read and edit. An anchor "12:ab34cd56" means "line 12, whose content hashes to ab34cd56". Edits validate anchors against current content and tolerate small drift, eliminating the stale-line-number failure mode of classic line-based editors. Docs: cmd/sin-code/internal/hashline.doc.md
SPDX-License-Identifier: MIT Purpose: ibd — Intent-Based Diffing. Compare two versions of code and determine if the changes match the stated intent. Pure Go implementation.
SPDX-License-Identifier: MIT Purpose: sin-code lsp CLI — wrapper around Language Server Protocol (gopls, pyright, tsserver) for IDE-grade code intelligence.
SPDX-License-Identifier: MIT Purpose: map — architecture mapping with dependency graphs, entry points, hot paths, and module-level analysis. Built-in Go implementation.
SPDX-License-Identifier: MIT Purpose: sin-code memory CLI — long-term project knowledge.
SPDX-License-Identifier: MIT Purpose: oracle — Verification Oracle. Compares source files against test files to verify coverage. Pure Go implementation.
SPDX-License-Identifier: MIT Purpose: orchestrate — task management with dependencies, parallel execution plans, blocker detection, and rollback plans. Built-in Go implementation with JSON file storage in ~/.local/state/sin-code/.
SPDX-License-Identifier: MIT Purpose: sin-code orchestrate — multi-agent orchestrator CLI (v2). SOTA June 2026: Pre-LLM router + planner + parallel specialized agents with per-agent model + system prompt. Backed by the orchestrator package.
SPDX-License-Identifier: MIT Purpose: sin-code plugin CLI — install/list/info/enable/disable.
SPDX-License-Identifier: MIT Purpose: poc — Proof-of-Correctness. Verifies that code satisfies its specification by comparing code against spec documents (markdown, text, or structured requirements). Pure Go implementation.
SPDX-License-Identifier: MIT Purpose: read — token-efficient, anchor-aware file reading. Replaces naive native read/cat for agents: hashline mode emits stable edit anchors, outline mode emits structure instead of raw content (80–95% token savings on large files), and hard byte/line guards prevent context blowouts. Docs: cmd/sin-code/internal/read.doc.md
SPDX-License-Identifier: MIT Purpose: sbom — generate SPDX or CycloneDX JSON SBOMs for Go, Python, Node, and generic projects. Docs: cmd/sin-code/internal/sbom.go.doc.md
SPDX-License-Identifier: MIT Purpose: sckg — Semantic Codebase Knowledge Graphs. Builds a knowledge graph of a codebase: files, functions, imports, and their relationships. Pure Go implementation.
SPDX-License-Identifier: MIT Purpose: scout — parallel code search with regex, semantic, symbol, usage. Uses ripgrep (rg) as a fast bridge when available; falls back to a parallel Go worker pool with gitignore-aware walking. Binary files are auto-skipped. Docs: cmd/sin-code/internal/scout.doc.md
SPDX-License-Identifier: MIT Purpose: security — fast security analysis for Go, Python, Node, and generic projects. Auto-detects project type, finds available security tools, and runs a targeted scan. Docs: security.doc.md
SPDX-License-Identifier: MIT Purpose: self-update — check for and install new sin-code releases from GitHub. Auto-detects platform, downloads the correct binary, and replaces the current one. Docs: self-update.doc.md
SPDX-License-Identifier: MIT Purpose: serve — start an MCP (Model Context Protocol) server that exposes all 13 sin-code subcommands as MCP tools. This replaces the 7 separate MCP server registrations in opencode.json with a single one.
SPDX-License-Identifier: MIT Purpose: MCP tool handlers for the v2.0+ subcommands (todo, memory, notifications, orchestrator-*, agent-*, lsp). Each handler dispatches to the corresponding cobra subcommand and returns stdout.
SPDX-License-Identifier: MIT Purpose: MCP handlers for sin_read, sin_write, sin_edit. Call the internal readFile/writeFileAtomic/applyEdit functions directly (no subprocess), making the edit loop hot path as fast as possible. Docs: cmd/sin-code/internal/serve_rw_handlers.doc.md
SPDX-License-Identifier: MIT Purpose: write — atomic, validated file writing. Replaces naive native write: temp-file + fsync + rename (never a half-written file), syntax pre-validation before anything touches disk (Go via go/parser, JSON via encoding/json, bracket-balance heuristic elsewhere), and optional backup. Docs: cmd/sin-code/internal/write.doc.md
Index ¶
- Constants
- Variables
- func CheckUpdateAvailable() (string, bool, error)
- func FormatHashlines(lines []string, start int) string
- func JoinLines(lines []string, trailingNewline bool) string
- func LineHash(line string) string
- func PrintError(err error)
- func ResolveAnchor(lines []string, a Anchor, driftWindow int) (idx int, drift int, err error)
- func SetCurrentVersion(v string)
- func SplitLines(content string) (lines []string, trailingNewline bool)
- type Anchor
- type CycloneDXComponent
- type CycloneDXDocument
- type CycloneDXMetadata
- type CycloneDXTool
- type DoctorReport
- type FileOutline
- type GitHubRelease
- type SPDXCreationInfo
- type SPDXDocument
- type SPDXPackage
- type SecurityResult
- type SecuritySummary
- type SinCodeConfig
- type SymbolInfo
- type ToolResult
Constants ¶
const DefaultDriftWindow = 25
const HashLineLen = 8
Variables ¶
var AdwCmd = &cobra.Command{ Use: "adw", Short: "Architectural Debt Watchdogs — detect god modules, circular deps, etc.", Long: `Detect and report architectural debt in a codebase. Pure Go implementation. Detects: - God modules (files with >15 imports or >500 lines) - Circular dependencies (import cycles) - High coupling (files imported by >10 others) - Long functions (>100 lines) - Large files (>500 lines) - TODO/FIXME comments - Missing tests (source files without corresponding test files) Examples: sin-code adw . sin-code adw ./src --strict sin-code adw . --format json`, Args: cobra.ArbitraryArgs, RunE: func(cmd *cobra.Command, args []string) error { path := "." if len(args) > 0 { path = args[0] } absPath, err := filepath.Abs(path) if err != nil { return fmt.Errorf("invalid path: %w", err) } if info, err := os.Stat(absPath); err != nil || !info.IsDir() { if err != nil { return fmt.Errorf("path not found: %w", err) } return fmt.Errorf("path is not a directory: %s", absPath) } result := scanDebt(absPath, adwStrict) if adwFormat == "json" { enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") return enc.Encode(result) } return outputTextADW(result) }, }
var ConfigCmd = &cobra.Command{
Use: "config",
Short: "View and manage sin-code configuration",
Long: `Manage sin-code configuration files and settings.
Configuration files:
~/.config/sin/sin-code.toml Main configuration (theme, defaults)
~/.config/sin/tui.toml TUI preferences (theme, keybindings)
Subcommands:
config get <key> Get a configuration value
config set <key> <value> Set a configuration value
config list List all configuration values
config path Show configuration directory path
config init Create default configuration files`,
}
var DiscoverCmd = &cobra.Command{ Use: "discover [path]", Short: "Discover files with relevance scoring and pattern matching", Long: `Discover files in a directory with relevance scoring, pattern matching, and dependency analysis. Pure Go implementation — no external binary needed. Example: sin-code discover . --pattern "**/*.go" --sort_by relevance --format json`, Args: cobra.ArbitraryArgs, RunE: func(cmd *cobra.Command, args []string) error { path := "." if len(args) > 0 { path = args[0] } absPath, err := filepath.Abs(path) if err != nil { return fmt.Errorf("invalid path: %w", err) } if info, err := os.Stat(absPath); err != nil || !info.IsDir() { if err != nil { return fmt.Errorf("path not found: %w", err) } return fmt.Errorf("path is not a directory: %s", absPath) } results, err := discoverFiles(absPath, discoverPattern, discoverLimit) if err != nil { return err } sortResults(results, discoverSort) if len(results) > discoverLimit { results = results[:discoverLimit] } if discoverFormat == "json" { return outputJSON(results) } return outputText(results) }, }
var EditCmd = &cobra.Command{ Use: "edit [path]", Short: "Hashline-anchored surgical edits with validation", Long: `Surgical file editing with two addressing modes: Anchor mode (preferred — anchors come from 'sin-code read'): --anchor 12:ab34cd56 --new-text "replacement" replace one line --anchor 12:ab34cd56 --end-anchor 20:ef99aa01 ... replace a line range --anchor 12:ab34cd56 --insert after --new-text "..." insert after a line --anchor 12:ab34cd56 --delete delete line (or range) String mode (exact match, fails on ambiguity): --old-string "foo(a, b)" --new-string "foo(a, b, c)" --old-string "x" --new-string "y" --replace-all Every edit validates syntax (like 'sin-code write') and applies atomically. --dry-run prints a unified diff without touching the file.`, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { absPath, err := filepath.Abs(args[0]) if err != nil { return fmt.Errorf("invalid path: %w", err) } req := editRequest{ Anchor: editAnchor, EndAnchor: editEndAnchor, NewText: editNewText, OldString: editOldString, NewString: editNewString, ReplaceAll: editReplaceAll, Insert: editInsert, Delete: editDelete, DryRun: editDryRun, Validate: !editNoValidate, Drift: editDrift, Symbol: editSymbol, } result, err := applyEdit(absPath, req) if err != nil { return err } if editFormat == "json" { enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") return enc.Encode(result) } if result.DryRun { fmt.Print(result.Diff) return nil } fmt.Printf("edited %s: %s (%+d lines)\n", result.Path, result.Operation, result.LineDelta) if result.Diff != "" { fmt.Print(result.Diff) } return nil }, }
var EfmCmd = &cobra.Command{ Use: "efm", Short: "Ephemeral Full-Stack Mocking — spin up disposable test environments", Long: `Manage disposable full-stack environments (Docker Compose, ephemeral containers). Pure Go implementation. Container runtime: On macOS, OrbStack ('orb') is preferred and used automatically when available, with 'docker' as the fallback. On Linux, 'docker' is used directly. The runtime is fully Docker CLI-compatible, so the same compose commands work. Use --runtime to override the auto-detected value: --runtime auto auto-detect (default) --runtime orb force OrbStack --runtime docker force Docker (incl. legacy docker-compose fallback) Examples: sin-code efm --action list sin-code efm --action up --stack docker-compose.yml --ttl 3600 sin-code efm --action down --stack docker-compose.yml sin-code efm --action status sin-code efm --action list --runtime orb`, RunE: func(cmd *cobra.Command, args []string) error { return runEFM(efmAction, efmStack, efmTTL, efmFormat, efmRuntime) }, }
var ExecuteCmd = &cobra.Command{ Use: "execute", Short: "Execute shell commands safely with secret redaction and timeout", Long: `Execute shell commands with safety checks, secret redaction, timeout handling, and error analysis. Pure Go implementation — no external binary needed. Example: sin-code execute --command "ls -la" --timeout 10 --format json`, RunE: func(cmd *cobra.Command, args []string) error { if execCommand == "" { return fmt.Errorf("--command is required") } if err := checkSafety(execCommand); err != nil { return err } return runCommand(execCommand, execTimeout, execFormat, execStream) }, }
var GraspCmd = &cobra.Command{ Use: "grasp [path]", Short: "Deep code understanding for a single file", Long: `Deep code understanding for individual files — structure, dependencies, usage, and related context. Pure Go implementation. Example: sin-code grasp cmd/sin-code/main.go --format json`, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { absPath, err := filepath.Abs(args[0]) if err != nil { return fmt.Errorf("invalid path: %w", err) } info, err := os.Stat(absPath) if err != nil { return fmt.Errorf("file not found: %w", err) } if info.IsDir() { return fmt.Errorf("path is a directory, not a file: %s", absPath) } result, err := analyzeFile(absPath, info) if err != nil { return err } if graspFormat == "json" { enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") return enc.Encode(result) } return outputTextGrasp(result) }, }
var HarvestCmd = &cobra.Command{ Use: "harvest", Short: "Fetch URLs with caching, structure extraction, and change detection", Long: `Fetch URLs with caching, structure extraction, change detection, and auth management. Pure Go implementation with local disk cache. Example: sin-code harvest --url https://api.example.com/data --format json`, RunE: func(cmd *cobra.Command, args []string) error { if harvestURL == "" { return fmt.Errorf("--url is required") } return harvestURLFetch(harvestURL, harvestMethod, harvestTimeout, harvestFormat) }, }
var IbdCmd = &cobra.Command{ Use: "ibd", Short: "Intent-Based Diffing — compare code changes against stated intent", Long: `Compare two versions of code and determine if the changes match the stated intent. Pure Go implementation. Examples: sin-code ibd --before old.py --after new.py --intent "add retry logic" sin-code ibd --before v1.0 --after HEAD --intent "refactor authentication" sin-code ibd file.go --from main --to feature-branch --intent "add error handling"`, RunE: func(cmd *cobra.Command, args []string) error { var beforePath, afterPath string if ibdBefore != "" && ibdAfter != "" { beforePath = ibdBefore afterPath = ibdAfter } else if len(args) > 0 { beforePath = args[0] if ibdFrom != "" && ibdTo != "" { fmt.Fprintf(os.Stderr, "Note: Git diff (--from/--to) requires manual diff extraction. Reading file as-is.\n") } } else { return fmt.Errorf("either --before/--after or a target path is required") } result, err := diffWithIntent(beforePath, afterPath, ibdIntent) if err != nil { return err } if ibdFormat == "json" { enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") return enc.Encode(result) } return outputTextIBD(result) }, }
var IndexCmd = &cobra.Command{
Use: "index",
Short: "Manage persistent incremental code index",
Long: `Builds, refreshes, and inspects a persistent gob-persisted
index at <root>/.sin-code/index.bin. Trigram + symbol table
for instant lookups.`,
}
var LSPCmd = &cobra.Command{ Use: "lsp", Short: "LSP (Language Server Protocol) — IDE-grade code intelligence", Long: `Language Server Protocol wrapper for sin-code. Provides go-to-definition, find-references, hover, rename, document symbols, formatting, and diagnostics without launching an IDE. Spawns gopls/pyright/typescript-language-server on demand and caches them per-language. Examples: sin-code lsp servers # list detected LSPs sin-code lsp definition main.go 5 9 # go-to-def at line 5, col 9 sin-code lsp references main.go 5 9 # find all references sin-code lsp hover main.go 5 9 # type/doc on hover sin-code lsp rename main.go 5 9 MyFunc # rename symbol sin-code lsp symbols main.go # outline sin-code lsp format main.go # format file sin-code lsp diagnostics main.go # all errors/warnings`, SilenceUsage: true, }
var MapCmd = &cobra.Command{ Use: "map [path]", Short: "Map code architecture with dependency graphs and hot-path analysis", Long: `Map code architecture with dependency graphs, entry points, hot paths, and module-level analysis. Pure Go implementation. Example: sin-code map . --action map --format json`, Args: cobra.ArbitraryArgs, RunE: func(cmd *cobra.Command, args []string) error { path := "." if len(args) > 0 { path = args[0] } absPath, err := filepath.Abs(path) if err != nil { return fmt.Errorf("invalid path: %w", err) } info, err := os.Stat(absPath) if err != nil { return fmt.Errorf("path not found: %w", err) } if !info.IsDir() { return fmt.Errorf("path is not a directory: %s", absPath) } result, err := mapArchitecture(absPath, mapAction) if err != nil { return err } if mapFormat == "json" { enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") return enc.Encode(result) } return outputTextMap(result) }, }
var MemoryCmd = &cobra.Command{ Use: "memory", Short: "Long-term project memory with semantic search", Long: `Memory is a bd-style project knowledge store backed by bbolt. add <insight> Add a memory list List memories (filter by --project, --tag, --actor) search <query> Semantic search (uses NIM embeddings if SIN_NIM_API_KEY is set) link <from> <to> --rel Add a knowledge-graph link unlink <from> <to> Remove a link graph <id> Show knowledge-graph neighborhood prime <query> Print top-K relevant memories for an LLM prompt forget <id> Soft-delete (--hard for permanent) show <id> Show one memory stats Memory statistics Storage: ~/.config/sin-code/memory.db (override with --db). Embeddings: NIM nv-embed-v1 (set SIN_NIM_API_KEY).`, SilenceUsage: true, }
var OracleCmd = &cobra.Command{ Use: "oracle", Short: "Verify that a source file has corresponding test coverage", Long: `Compares functions/methods in a source file against test cases in a test file and reports which symbols are covered. Despite the legacy "claim/evidence" naming, --claim is the source file to verify and --evidence is the test file. Examples: sin-code oracle --claim src/main.py --evidence tests/test_main.py sin-code oracle --claim cmd/sin-code/main.go --evidence cmd/sin-code/main_test.go`, RunE: func(cmd *cobra.Command, args []string) error { if oracleClaim == "" { return fmt.Errorf("--claim (source file) is required") } if oracleEvidence == "" { return fmt.Errorf("--evidence (test file) is required") } result, err := verifyCoverage(oracleClaim, oracleEvidence) if err != nil { return err } if oracleFormat == "json" { enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") return enc.Encode(result) } return outputTextOracle(result) }, }
var OrchestrateCmd = &cobra.Command{ Use: "orchestrate", Short: "Legacy task manager (use 'sin-code todo' for the SOTA issue tracker)", Long: `Manage tasks with dependencies, parallel execution plans, blocker detection, and rollback plans. Pure Go implementation with JSON file storage. DEPRECATED: This command is maintained for backward compatibility. For new projects, use 'sin-code todo' which provides: - bbolt storage (faster, ACID) - Hash-based IDs (st-a1b2) - Dependency graph with cycle detection - Append-only audit log - Ready/Blocked queries - Project namespaces - Compaction for old closed tasks Example: sin-code orchestrate --action add --title "Implement feature X" --tags "urgent,backend" sin-code orchestrate --action list --format json sin-code orchestrate --action complete --id 1`, RunE: func(cmd *cobra.Command, args []string) error { return runOrchestrate(orchAction, orchTitle, orchTags, orchID, orchFormat) }, }
var OrchestratorAgentDoctorCmd = &cobra.Command{ Use: "agent-doctor [name]", Short: "Validate agents: model IDs exist, API keys present, base URLs reachable", Args: cobra.MaximumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { offline := agDoctorOffline || os.Getenv("SIN_LLM_OFFLINE") == "1" var filterName string if len(args) == 1 { filterName = strings.ToLower(args[0]) } agents, err := loadAllEffectiveAgents() if err != nil { return err } if filterName != "" { filtered := []orchestrator.AgentConfig{} for _, a := range agents { if a.Name == filterName { filtered = append(filtered, a) } } agents = filtered } report := runDoctor(agents, offline) if orch2Format == "json" { return json.NewEncoder(os.Stdout).Encode(report) } printDoctor(report) failed := 0 for _, r := range report { if !r.OK { failed++ } } if failed > 0 { return fmt.Errorf("%d/%d agents have issues", failed, len(report)) } return nil }, }
var OrchestratorAgentEditCmd = &cobra.Command{ Use: "agent-edit", Short: "Edit a per-agent TOML config (interactive $EDITOR or programmatic with --set)", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { agEditAgent = strings.ToLower(strings.TrimSpace(agEditAgent)) if agEditAgent == "" { return fmt.Errorf("--agent <name> required") } if len(agEditSet) > 0 { return applyAgentEdits(agEditAgent, agEditSet) } return openAgentInEditor(agEditAgent) }, }
var OrchestratorAgentResetCmd = &cobra.Command{ Use: "agent-reset <name>", Short: "Remove a user agent (falls back to defaults)", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { name := strings.ToLower(args[0]) dir, err := agentDir(name) if err != nil { return err } if _, err := os.Stat(dir); os.IsNotExist(err) { fmt.Printf("Agent %s has no user config — nothing to reset.\n", name) return nil } if err := os.RemoveAll(dir); err != nil { return err } fmt.Printf("Reset agent %s to defaults (removed %s)\n", name, dir) return nil }, }
var OrchestratorAgentSetCmd = &cobra.Command{ Use: "agent-set <name> key=value [key=value ...]", Short: "Programmatically set fields on a user agent (no editor required)", Args: cobra.MinimumNArgs(2), RunE: func(cmd *cobra.Command, args []string) error { name := strings.ToLower(args[0]) return applyAgentEdits(name, args[1:]) }, }
var OrchestratorAgentShowCmd = &cobra.Command{ Use: "agent-show <name>", Short: "Show effective config for an agent (merged defaults + user overrides)", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { name := strings.ToLower(args[0]) merged, source, err := loadEffectiveAgent(name) if err != nil { return err } if orch2Format == "json" { out := map[string]interface{}{ "agent": merged, "source": source, } return json.NewEncoder(os.Stdout).Encode(out) } fmt.Printf("Agent %s (source: %s):\n", name, source) fmt.Printf(" description: %s\n", merged.Description) fmt.Printf(" type: %s\n", merged.Type) fmt.Printf(" provider: %s\n", orDash(merged.Provider)) fmt.Printf(" base_url: %s\n", orDash(merged.BaseURL)) fmt.Printf(" model: %s\n", orDash(merged.Model)) fmt.Printf(" max_tokens: %d\n", merged.MaxTokens) fmt.Printf(" temperature: %g\n", merged.Temperature) fmt.Printf(" system_file: %s\n", orDash(merged.SystemFile)) fmt.Printf(" max_context: %d\n", merged.MaxContext) fmt.Printf(" memory_ns: %s\n", orDash(merged.MemoryNS)) fmt.Printf(" retention: %d days\n", merged.RetentionDays) if len(merged.ToolsAllow) > 0 { fmt.Printf(" tools_allow: %s\n", strings.Join(merged.ToolsAllow, ", ")) } if len(merged.ToolsDeny) > 0 { fmt.Printf(" tools_deny: %s\n", strings.Join(merged.ToolsDeny, ", ")) } return nil }, }
var OrchestratorAgentsCmd = &cobra.Command{ Use: "orchestrator-agents", Short: "List available agents (default + user-defined + plugin)", RunE: func(cmd *cobra.Command, args []string) error { extra, err := loadAllAgents() if err != nil { return err } o := orchestrator.NewWithAgents(extra) registry := o.Registry all := registry.List() pluginAgent := map[string]string{} if !orch2NoPlugins { pr := plugins.NewRegistry() _ = pr.LoadFromDir("") for _, p := range pr.List() { for _, a := range p.Agents { pluginAgent["plugin-"+p.Name+"-"+a.Name] = p.Name } } } if orch2Format == "json" { out := make([]map[string]any, 0, len(all)) for _, c := range all { entry := map[string]any{ "name": c.Name, "type": c.Type, "model": c.Model, "tools_allow": c.ToolsAllow, "description": c.Description, } if src, ok := pluginAgent[c.Name]; ok { entry["source"] = "plugin" entry["plugin"] = src } else { entry["source"] = "default-or-user" } out = append(out, entry) } return json.NewEncoder(os.Stdout).Encode(out) } fmt.Printf("Loaded %d agents:\n\n", len(all)) for _, c := range all { prefix := "" if src, ok := pluginAgent[c.Name]; ok { prefix = fmt.Sprintf("[plugin %s] ", src) } fmt.Printf(" %s%-12s type=%-10s model=%-32s tools=%d\n", prefix, c.Name, c.Type, c.Model, len(c.ToolsAllow)) if c.Description != "" { fmt.Printf(" %s\n", c.Description) } } return nil }, }
var OrchestratorPlanCmd = &cobra.Command{ Use: "orchestrator-plan <prompt>", Short: "Build a plan from a prompt (no execution)", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { extra, err := loadAllAgents() if err != nil { return err } o := orchestrator.NewWithAgents(extra) plan := o.Plan(args[0]) if orch2Format == "json" { return json.NewEncoder(os.Stdout).Encode(plan) } fmt.Printf("Plan %s (intent=%s, %d tasks):\n\n", plan.ID, plan.Intent, len(plan.Tasks)) for i, t := range plan.Tasks { deps := "" if len(t.DependsOn) > 0 { deps = fmt.Sprintf(" deps=[%s]", joinIDs(t.DependsOn)) } fmt.Printf(" %d. [%s] agent=%-10s%s\n %s\n", i+1, t.Type, t.AgentName, deps, t.Description) } return nil }, }
var OrchestratorRunCmd = &cobra.Command{ Use: "orchestrator-run <prompt>", Short: "Run a prompt through the multi-agent orchestrator (Pre-LLM router → planner → parallel agents)", Long: `orchestrate-run is the v2 SOTA orchestrator. It: 1. Routes the prompt via cheap keyword-based intent classification (Pre-LLM) 2. Decomposes it into ordered sub-tasks, each bound to a specialized agent 3. Dispatches the tasks in parallel (respecting dependencies) 4. Each agent runs with its own model, system prompt, and tool whitelist 5. Results merge into a shared scratchpad 6. Final aggregation produces the response Default agents: coder, tester, reviewer, docs, security, architect. User agents can be added to ~/.config/sin-code/agents/{name}/agent.toml Plugin agents are auto-loaded from ~/.local/share/sin-code/plugins/<name>/ Examples: sin-code orchestrate-run "Add user authentication with OAuth2" sin-code orchestrate-run "Refactor the billing module" --plan-only sin-code orchestrate-run "Write docs for the API" --format json --show-scratch`, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { orch2Prompt = args[0] return runOrchestrator() }, }
var PluginCmd = &cobra.Command{ Use: "plugin", Short: "Manage user-installed plugins (subcommands, agents, tools, hooks)", Long: `Plugins extend sin-code without forking. Install from a local path or git URL, and sin-code will: - Register their subcommands under sin-code (e.g. sin-code my-plugin-cmd) - Register their agents with the orchestrator (prefixed plugin-<name>-<agent>) - Register their tools with the MCP server (prefixed sin_plugin_<name>_<tool>) - Wire their hooks into todo events Discovery: ~/.local/share/sin-code/plugins/<name>/ with plugin.toml manifest.`, SilenceUsage: true, }
var PocCmd = &cobra.Command{ Use: "poc", Short: "Proof-of-Correctness — verify code satisfies its specification", Long: `Verify that code satisfies its specification. Compares code against spec documents (markdown, text, or structured requirements) and checks for compliance. Pure Go implementation. Checks: - Required functions/classes mentioned in spec exist in code - Function signatures match specification - Required imports are present - No forbidden patterns (e.g., os.Exit in library code) Examples: sin-code poc --spec spec.md --code src/main.py sin-code poc --spec requirements.json --code src/`, RunE: func(cmd *cobra.Command, args []string) error { target := pocCode if target == "" { target = pocSpec } if target == "" { return fmt.Errorf("--code (or --spec for back-compat) is required") } result, err := verifyCorrectness(pocSpec, target) if err != nil { return err } if pocFormat == "json" { enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") return enc.Encode(result) } return outputTextPOC(result) }, }
var ReadCmd = &cobra.Command{ Use: "read [path]", Short: "Read files with hashline anchors, outline, and size guards", Long: `Token-efficient file reading for agents and humans. Modes: hashline (default) lines prefixed with "LINE:HASH|" — anchors feed 'sin-code edit' raw plain content (still offset/limit guarded) outline structure only: imports, functions, classes, exports (huge files) Examples: sin-code read main.go sin-code read main.go --mode outline sin-code read big.log --offset 5000 --limit 200 --mode raw sin-code read pkg/x.go --format json`, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { absPath, err := filepath.Abs(args[0]) if err != nil { return fmt.Errorf("invalid path: %w", err) } result, err := readFile(absPath, readMode, readOffset, readLimit, readMaxBytes) if err != nil { return err } if readFormat == "json" { enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") return enc.Encode(result) } fmt.Print(result.Content) if result.Truncated { fmt.Fprintf(os.Stderr, "\n[truncated: showing lines %d-%d of %d — use --offset/--limit, or --mode outline]\n", result.Offset, result.Offset+result.ReturnedLines-1, result.TotalLines) } return nil }, }
var SbomCmd = &cobra.Command{ Use: "sbom [path]", Short: "Generate SPDX or CycloneDX JSON SBOM for a project", Long: `sbom generates a Software Bill of Materials (SBOM) for the project at <path>. Supported project types: Go → parses go.mod / go list -m -json all Python → parses requirements.txt or pyproject.toml Node.js → parses package.json (+ package-lock.json for versions) Generic → lists directory structure as a basic component tree Output formats: spdx-json (default) SPDX 2.3 JSON cyclonedx-json CycloneDX 1.5 JSON Examples: sin-code sbom . sin-code sbom ./my-project --format cyclonedx-json --output sbom.json`, Args: cobra.MaximumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { path := "." if len(args) > 0 { path = args[0] } path, _ = filepath.Abs(path) format, _ := cmd.Flags().GetString("format") output, _ := cmd.Flags().GetString("output") projType := detectProjectType(path) sbom, err := generateSBOM(path, projType, format) if err != nil { return fmt.Errorf("sbom generation failed: %w", err) } var out io.Writer = os.Stdout if output != "" && output != "-" { f, err := os.Create(output) if err != nil { return fmt.Errorf("cannot create output file: %w", err) } defer f.Close() out = f } enc := json.NewEncoder(out) enc.SetIndent("", " ") return enc.Encode(sbom) }, }
SbomCmd generates a Software Bill of Materials in SPDX or CycloneDX format.
var SckgCmd = &cobra.Command{ Use: "sckg", Short: "Semantic Codebase Knowledge Graphs — build & query code graph", Long: `Build and query a semantic graph of a codebase. Pure Go implementation. Actions: build — Build the knowledge graph from source code query — Query the graph for relationships (requires --query) stats — Show graph statistics export — Export graph as JSON Examples: sin-code sckg . --action build sin-code sckg . --action query --query "auth module dependencies" sin-code sckg . --action stats sin-code sckg . --action export --format json`, Args: cobra.ArbitraryArgs, RunE: func(cmd *cobra.Command, args []string) error { path := "." if len(args) > 0 { path = args[0] } absPath, err := filepath.Abs(path) if err != nil { return fmt.Errorf("invalid path: %w", err) } if info, err := os.Stat(absPath); err != nil || !info.IsDir() { if err != nil { return fmt.Errorf("path not found: %w", err) } return fmt.Errorf("path is not a directory: %s", absPath) } switch sckgAction { case "build": graph, err := buildGraph(absPath) if err != nil { return err } if sckgFormat == "json" { enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") return enc.Encode(graph) } return outputTextSCKGBuild(graph) case "query": if sckgQuery == "" { return fmt.Errorf("--query is required for action=query") } graph, err := buildGraph(absPath) if err != nil { return err } results := queryGraph(graph, sckgQuery) if sckgFormat == "json" { enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") return enc.Encode(results) } return outputTextSCKGQuery(results) case "stats": graph, err := buildGraph(absPath) if err != nil { return err } stats := graphStats(graph) if sckgFormat == "json" { enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") return enc.Encode(stats) } return outputTextSCKGStats(stats) case "export": graph, err := buildGraph(absPath) if err != nil { return err } enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") return enc.Encode(graph) default: return fmt.Errorf("unknown action: %s (use build|query|stats|export)", sckgAction) } }, }
var ScoutCmd = &cobra.Command{ Use: "scout", Short: "Search code with regex, semantic, symbol, and usage search", Long: `Parallel code search with optional ripgrep bridge (auto-detected on PATH). Search types: regex|semantic|symbol|usage regex literal regex pattern semantic word-order matching (case insensitive) symbol function/class/struct/variable definitions usage all references to a symbol name Examples: sin-code scout --query "func.*main" --path . --search_type regex --format json sin-code scout --query "handleError" --path . --search_type usage sin-code scout --query "class.*Factory" --search_type symbol --no-rg`, RunE: func(cmd *cobra.Command, args []string) error { if scoutQuery == "" { return fmt.Errorf("--query is required") } absPath, err := filepath.Abs(scoutPath) if err != nil { return fmt.Errorf("invalid path: %w", err) } if info, err := os.Stat(absPath); err != nil || !info.IsDir() { if err != nil { return fmt.Errorf("path not found: %w", err) } return fmt.Errorf("path is not a directory: %s", absPath) } if scoutFile != "" { return searchSingleFile(scoutFile, scoutQuery, scoutType, scoutMax, scoutFormat) } results, err := scoutSearchAuto(absPath, scoutQuery, scoutType, scoutMax, scoutNoRG) if err != nil { return err } if scoutFormat == "json" { enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") return enc.Encode(results) } return outputTextScout(results) }, }
var SecurityCmd = &cobra.Command{ Use: "security [path]", Short: "Fast security analysis — auto-detects project type and runs available tools", Long: `security runs a targeted security scan based on the project type detected at <path>. Supported project types and tools: Go → govulncheck, gosec, go vet (if available) Python → bandit, safety (if available) Node.js → npm audit (if available) Generic → secrets scan (grep for high-entropy strings), file-permission checks The scan is fast (defaults to 5-minute timeout) and produces a concise summary. Use --format json for machine-readable output.`, Args: cobra.MaximumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { path := "." if len(args) > 0 { path = args[0] } path, _ = filepath.Abs(path) projType, _ := cmd.Flags().GetString("type") if projType == "" || projType == "auto" { projType = detectProjectType(path) } toolFilter, _ := cmd.Flags().GetString("tools") format, _ := cmd.Flags().GetString("format") timeoutSec, _ := cmd.Flags().GetInt("timeout") strict, _ := cmd.Flags().GetBool("strict") result := runSecurityScan(path, projType, toolFilter, timeoutSec) result.Strict = strict if format == "json" { out, _ := json.MarshalIndent(result, "", " ") fmt.Println(string(out)) } else { printSecurityResult(result) } if strict && result.Summary.Issues > 0 { return fmt.Errorf("security scan found %d issues (strict mode)", result.Summary.Issues) } return nil }, }
SecurityCmd runs a fast security analysis tailored to the detected project type.
var SelfUpdateCmd = &cobra.Command{ Use: "self-update", Short: "Check for and install the latest sin-code release", Long: `self-update checks GitHub releases for a newer version of sin-code, downloads the correct binary for your platform, and installs it. The current binary is backed up before replacement. If the update fails, the backup is restored automatically. Usage: sin-code self-update # Check and install latest stable sin-code self-update --version # Show current version info sin-code self-update --dry-run # Check only, don't install Supported platforms: darwin/amd64, darwin/arm64, linux/amd64, linux/arm64, windows/amd64`, RunE: func(cmd *cobra.Command, args []string) error { dryRun, _ := cmd.Flags().GetBool("dry-run") showVersion, _ := cmd.Flags().GetBool("version") if showVersion { return printVersionInfo() } return runSelfUpdate(dryRun) }, }
var ServeCmd = &cobra.Command{ Use: "serve", Short: "Start an MCP server exposing all 13 sin-code tools", Long: `Start a Model Context Protocol (MCP) server that exposes all 13 sin-code subcommands as MCP tools. This allows opencode (and any MCP-compatible client) to use sin-code as a single registered MCP server instead of registering 13 separate binaries. Note: security, sbom, config, self-update, and tui are CLI-only subcommands and are NOT exposed as MCP tools. The MCP server only exposes the 13 core analysis tools listed below. Example opencode.json entry: "sin-code": { "command": ["/Users/jeremy/.local/bin/sin-code", "serve"], "description": "SIN-Code unified toolchain (13 MCP tools)", "enabled": true, "type": "local" } Then use sin_discover, sin_execute, sin_map, sin_grasp, sin_scout, sin_harvest, sin_orchestrate, sin_ibd, sin_poc, sin_sckg, sin_adw, sin_oracle, sin_efm as MCP tools.`, RunE: func(cmd *cobra.Command, args []string) error { ctx, cancel := context.WithCancel(context.Background()) defer cancel() server := mcp.NewServer(&mcp.Implementation{ Name: "sin-code", Version: ServerVersion, }, &mcp.ServerOptions{ Capabilities: &mcp.ServerCapabilities{ Tools: &mcp.ToolCapabilities{}, }, }) registerAllMCPTools(server) if serveTransport == "stdio" { return server.Run(ctx, &mcp.StdioTransport{}) } return fmt.Errorf("unsupported transport: %s (only stdio supported)", serveTransport) }, }
var ServerVersion = "dev"
ServerVersion is set at build time via -ldflags "-X github.com/OpenSIN-Code/SIN-Code-Bundle/cmd/sin-code/internal.ServerVersion=..."
var WriteCmd = &cobra.Command{ Use: "write [path]", Short: "Write files atomically with syntax pre-validation", Long: `Atomic file writing: content is validated, written to a temp file in the target directory, fsynced, then renamed over the destination. A crash or validation failure never leaves a corrupt file behind. Validation (skip with --no-validate): .go full parse via go/parser .json encoding/json other bracket/brace/paren balance heuristic (string/comment aware) Examples: sin-code write pkg/new.go --content "$(cat /tmp/draft.go)" cat draft.json | sin-code write config.json --stdin --backup sin-code write docs/new/file.md --stdin --mkdir < notes.md`, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { absPath, err := filepath.Abs(args[0]) if err != nil { return fmt.Errorf("invalid path: %w", err) } content := writeContent if writeStdin { data, err := io.ReadAll(os.Stdin) if err != nil { return fmt.Errorf("reading stdin: %w", err) } content = string(data) } result, err := writeFileAtomic(absPath, content, writeOpts{ validate: !writeNoValidate, backup: writeBackup, mkdir: writeMkdir, }) if err != nil { return err } if writeFormat == "json" { enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") return enc.Encode(result) } fmt.Printf("wrote %s (%d bytes, %d lines)%s\n", result.Path, result.Bytes, result.Lines, map[bool]string{true: " [backup: " + result.BackupPath + "]", false: ""}[result.BackupPath != ""]) return nil }, }
Functions ¶
func CheckUpdateAvailable ¶
CheckUpdateAvailable queries GitHub for the latest release and reports whether the current binary is outdated.
func FormatHashlines ¶
func PrintError ¶
func PrintError(err error)
PrintError prints an error to stderr in a consistent format and exits with code 1.
func ResolveAnchor ¶
func SetCurrentVersion ¶
func SetCurrentVersion(v string)
func SplitLines ¶
Types ¶
type Anchor ¶
func ParseAnchor ¶
type CycloneDXComponent ¶
type CycloneDXDocument ¶
type CycloneDXDocument struct {
BomFormat string `json:"bomFormat"`
SpecVersion string `json:"specVersion"`
SerialNumber string `json:"serialNumber"`
Version int `json:"version"`
Metadata CycloneDXMetadata `json:"metadata"`
Components []CycloneDXComponent `json:"components"`
}
CycloneDX 1.5 document
type CycloneDXMetadata ¶
type CycloneDXMetadata struct {
Timestamp string `json:"timestamp"`
Tools []CycloneDXTool `json:"tools"`
}
type CycloneDXTool ¶
type DoctorReport ¶
type FileOutline ¶
type FileOutline struct {
Language string `json:"language"`
Engine string `json:"engine"`
Symbols []SymbolInfo `json:"symbols"`
Imports []string `json:"imports"`
}
type GitHubRelease ¶
type SPDXCreationInfo ¶
type SPDXDocument ¶
type SPDXDocument struct {
SPDXVersion string `json:"spdxVersion"`
SPDXID string `json:"SPDXID"`
Name string `json:"name"`
DocumentNamespace string `json:"documentNamespace"`
CreationInfo SPDXCreationInfo `json:"creationInfo"`
Packages []SPDXPackage `json:"packages"`
}
SPDX 2.3 document
type SPDXPackage ¶
type SPDXPackage struct {
SPDXID string `json:"SPDXID"`
Name string `json:"name"`
VersionInfo string `json:"versionInfo"`
DownloadLocation string `json:"downloadLocation"`
FilesAnalyzed bool `json:"filesAnalyzed"`
VerificationCode *string `json:"verificationCode"`
LicenseConcluded string `json:"licenseConcluded"`
LicenseDeclared string `json:"licenseDeclared"`
CopyrightText string `json:"copyrightText"`
PrimaryPackagePurpose string `json:"primaryPackagePurpose"`
}
type SecurityResult ¶
type SecurityResult struct {
ProjectType string `json:"project_type"`
Path string `json:"path"`
Duration time.Duration `json:"duration"`
Strict bool `json:"strict"`
Tools []ToolResult `json:"tools"`
Summary SecuritySummary `json:"summary"`
}
type SecuritySummary ¶
type SinCodeConfig ¶
type SymbolInfo ¶
Source Files
¶
- adw.go
- agent_doctor_cmd.go
- agent_edit_cmd.go
- agent_helpers.go
- ast_go.go
- ast_provider.go
- ast_structural.go
- ast_treesitter_stub.go
- common.go
- config.go
- discover.go
- edit.go
- efm.go
- execute.go
- grasp.go
- harvest.go
- hashline.go
- ibd.go
- index_cmd.go
- index_store.go
- lsp_cmd.go
- map.go
- memory_cmd.go
- oracle.go
- orchestrate.go
- orchestrator_cmd.go
- plugin_cmd.go
- poc.go
- read.go
- sbom.go
- sckg.go
- scout.go
- scout_indexed.go
- security.go
- self-update.go
- serve.go
- serve_extra_handlers.go
- serve_index_handler.go
- serve_rw_handlers.go
- write.go
Directories
¶
| Path | Synopsis |
|---|---|
|
SPDX-License-Identifier: MIT Purpose: attachment store with SHA-256 dedup and magic-byte MIME detection.
|
SPDX-License-Identifier: MIT Purpose: attachment store with SHA-256 dedup and magic-byte MIME detection. |
|
SPDX-License-Identifier: MIT Purpose: NVIDIA NIM-specific helpers.
|
SPDX-License-Identifier: MIT Purpose: NVIDIA NIM-specific helpers. |
|
SPDX-License-Identifier: MIT Purpose: LSP (Language Server Protocol) client.
|
SPDX-License-Identifier: MIT Purpose: LSP (Language Server Protocol) client. |
|
SPDX-License-Identifier: MIT Purpose: text embedding via NVIDIA NIM.
|
SPDX-License-Identifier: MIT Purpose: text embedding via NVIDIA NIM. |
|
SPDX-License-Identifier: MIT Purpose: cobra CLI for sin-code notifications: list/read/dismiss/listen/clear/stats/prune.
|
SPDX-License-Identifier: MIT Purpose: cobra CLI for sin-code notifications: list/read/dismiss/listen/clear/stats/prune. |
|
SPDX-License-Identifier: MIT Purpose: Adversarial Reviewer — a second agent whose explicit mandate is to BREAK the change.
|
SPDX-License-Identifier: MIT Purpose: Adversarial Reviewer — a second agent whose explicit mandate is to BREAK the change. |
|
SPDX-License-Identifier: MIT Purpose: plugin manifest format + validator.
|
SPDX-License-Identifier: MIT Purpose: plugin manifest format + validator. |
|
SPDX-License-Identifier: MIT Purpose: OS-level isolation for shell command execution.
|
SPDX-License-Identifier: MIT Purpose: OS-level isolation for shell command execution. |
|
SPDX-License-Identifier: MIT Purpose: sin-code todo hook — manage pre/post event shell commands.
|
SPDX-License-Identifier: MIT Purpose: sin-code todo hook — manage pre/post event shell commands. |
|
SPDX-License-Identifier: MIT Purpose: sin-code web UI — stdlib HTTP server that exposes the orchestrator, todo store, notifications, and EFM stacks through a browser.
|
SPDX-License-Identifier: MIT Purpose: sin-code web UI — stdlib HTTP server that exposes the orchestrator, todo store, notifications, and EFM stacks through a browser. |