tools

package
v0.65.0 Latest Latest
Warning

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

Go to latest
Published: May 10, 2026 License: AGPL-3.0 Imports: 58 Imported by: 0

Documentation

Overview

Package tools — argument-extraction helpers.

Copied from internal/agent/agent.go (str/intOr/floatOr/boolOr). From Wave 1 onwards all registry handlers use these copies so the helpers are co-located with the Spec definitions rather than across package lines.

faultier.go — Faultier USB voltage-glitcher Specs.

Six primitives wired here:

  • glitch_arm — arm the configured trigger; device waits for edge.
  • glitch_fire — fire a single glitch immediately (no trigger wait).
  • glitch_set_pulse — configure delay_us + pulse_us before arm/fire.
  • glitch_sweep — sweep delay from start_us to end_us, firing on each step.
  • glitch_disarm — cancel an armed trigger.
  • glitch_status — read armed state and last glitch outcome (read-only).

All destructive specs carry risk.Critical because a voltage glitch can permanently damage the target chip or Faultier hardware if parameters are mis-set. glitch_status is risk.Low (read-only query).

Package tools — iclass_loclass_recover Spec (v0.5 task #8).

Registers the iclass_loclass_recover Spec which invokes the loclass offline key-recovery attack against an HID iCLASS Elite / High Security reader. The attack is purely CPU-side (no Flipper hardware involved). The algorithm is derived from García, de Koning Gans, Verdult, Meriac — "Dismantling iClass and iClass Elite", ESORICS 2012. License posture: clean-reimpl.

See docs/refactor/iclass-loclass-algorithm.md for full design context.

Package tools — security Specs (v0.5 Tier-1 MCP harvest).

hash_identify

Heuristic hash-format detector: inspects length, character class, and structural prefixes to produce a ranked candidate list. Pure offline; no network or external dependencies. Source: reimplemented from public algorithm descriptions (name-that-hash, hashcat --example-hashes docs). License posture: clean-reimpl.

hash_crack_dictionary

Offline dictionary attack. Reads a wordlist line-by-line (bufio.Scanner; streaming — never fully in memory) and hashes each candidate with the requested algorithm. Algorithms: MD5, SHA-1, SHA-256, SHA-512 (stdlib), NTLM (MD4 of UTF-16LE via golang.org/x/crypto/md4), bcrypt (golang.org/x/crypto/bcrypt). Concurrent goroutine pool bounded by the workers parameter. License posture: clean-reimpl.

port_scan_tcp

Host-side pure-Go TCP connect scan. No raw sockets; no root required. Distinct from wifi_port_scan (which runs on the ESP32/Marauder sidecar). Concurrency-capped worker pool; per-connection and wall-clock timeouts. License posture: clean-reimpl.

http_enum_common

Wordlist-driven HTTP path enumeration. Concurrent GET requests; configurable status-code filter; soft-404 canary detection; ships with a built-in ~500-entry CC0 wordlist (internal/wordlists/common.txt). License posture: clean-reimpl; embedded wordlist is CC0-1.0.

Package tools is the single source of truth for every tool PromptZero exposes to an LLM (via internal/agent) and to MCP clients (via internal/mcp). Adding a tool means writing one Spec and calling Register from a package init — the agent dispatch switch and the MCP s.add() side are then generated automatically from the registry.

Before this package existed, every tool lived in three places:

  • internal/mcp/server.go: s.add(name, desc, opts, required, handler)
  • internal/agent/tools.go: tool(name, desc, props, required...)
  • internal/agent/agent.go: case "name": return <handler logic>

Drift between those layers caused real user-facing bugs (device_info vs system_info naming drift; storage_write registered in MCP but undispatched in the agent; nfc_dump_protocol sending the wrong protocol token to Momentum). See docs/refactor/registry-migration.md for the cross-wave runbook.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Names

func Names() []string

Names returns every registered name AND alias, sorted. Intended for tests, /tools listings, and audit/report generation — production dispatch should iterate All so registration order is preserved.

func Register

func Register(s Spec)

Register adds a Spec to the registry. Panics on duplicate Name or Alias — a collision is a programming error that would silently corrupt dispatch, so we fail loudly at init.

func UnregisterForTest added in v0.48.0

func UnregisterForTest(name string)

UnregisterForTest removes a single tool (and its aliases) from the registry. Exported so sibling-package tests (e.g. internal/agent) can register a one-shot fake tool with t.Cleanup(...) and avoid leaking it across re-runs (`go test -count=N`). Production code has no reason to reach for this — the registry is intended to be init-time-immutable after all package init()s have completed.

No-op if name is unregistered, so cleanup paths can call it unconditionally.

Types

type Deps

type Deps struct {

	// Flipper is the serial transport + capability bag for the
	// connected Flipper Zero. Nil only in degenerate test setups that
	// do not touch hardware; production handlers may assume non-nil.
	Flipper *flipper.Flipper

	// Marauder is the optional ESP32 Marauder devboard. Nil when the
	// operator did not start PromptZero with --wifi (or the MCP
	// NewServer was called with m==nil). WiFi handlers MUST
	// short-circuit on a nil Marauder — the agent's requireMarauder()
	// helper does this in the current code; handlers can call a
	// similar helper on Deps.
	Marauder *marauder.Marauder

	// Bruce is the optional Bruce ESP32 devboard (https://github.com/pr3y/Bruce).
	// Nil when the operator has not configured a Bruce device (bruce.port
	// absent in config, or --bruce flag not supplied). Bruce handlers MUST
	// short-circuit on a nil Bruce — call [Deps.RequireBruce] at the top
	// of every handler, mirroring the [Deps.RequireMarauder] pattern.
	Bruce *bruce.Client

	// Faultier is the optional hextreeio Faultier USB voltage-glitcher.
	// Nil when no faultier.port is configured. Glitch handlers MUST
	// short-circuit on a nil Faultier — call [Deps.RequireFaultier]
	// at the top of each handler.
	Faultier *faultier.Client

	// BusPirate is the optional Bus Pirate 5 universal-bus probe.
	// Nil when no buspirate.port is configured. BusPirate handlers
	// MUST short-circuit on nil — call [Deps.RequireBusPirate] at
	// the top of each handler.
	BusPirate *buspirate.Client

	// Audit is the session audit log. Nil means "audit disabled" —
	// handlers that write to the log should no-op in that case. The
	// audit_* tools surface this with a friendly string.
	Audit *audit.Log

	// Config is the running process's resolved configuration — used
	// by badusb_run to consult Validator.BadUSB.AllowCritical, by
	// anything that resolves paths, etc. Nil is a bug.
	Config *config.Config

	// Generator drives the generate_* tools (evil_portal, badusb,
	// subghz, ir, nfc). Nil means no generation LLM is configured;
	// the handlers return a friendly "generator not configured" error.
	Generator *generate.Generator

	// GenLLM is the underlying provider the generator uses. Some
	// workflow handlers call it directly for ad-hoc synthesis that
	// doesn't fit the generator's typed payload shape.
	GenLLM provider.Provider

	// Vision drives analyze_image. Nil means vision is not configured.
	Vision *vision.Analyzer

	// Snapshot stores pre-write copies of Flipper SD files so /rewind
	// can roll back. Nil disables snapshots (Store is skipped). Tools
	// that clobber SD content (storage_copy, storage_rename,
	// storage_write, fileformat_edit, *_build, generate_*) must call
	// [Deps.SnapshotBeforeWrite] before writing.
	Snapshot *snapshot.Manager

	// SessionID is the active session's identifier. Paired with
	// Snapshot — [Deps.SnapshotBeforeWrite] is a no-op when this is
	// empty (off-session tests, MCP mode) even if Snapshot is non-nil.
	SessionID string

	// RAG is the lexical index for docs_search. Nil falls back to the
	// embedded index on first call (the existing behaviour in
	// internal/agent/agent.go:docsSearch).
	RAG *rag.Index

	// TargetMem is the persistent target-facts store (internal/targetmem).
	// Nil means target_* tools return the "targets feature not
	// enabled" friendly message.
	TargetMem *targetmem.Store

	// WorkflowConfirm is the operator-confirmation hook for workflow
	// sub-tools. Nil means "auto-approve every sub-step" (the MCP and
	// test defaults). The returned bool indicates approval.
	WorkflowConfirm func(ctx context.Context, tool string, input any, riskLevel string) bool

	// BuildVerify runs the chain-of-verification LLM pass on freshly-built
	// file bytes and returns (summary, blockMsg). A non-empty blockMsg means
	// the caller MUST NOT persist the file — surface it as the tool result.
	// An empty blockMsg and non-empty summary means the write can proceed;
	// append the summary to the success message.
	//
	// Nil means skip verification (MCP mode, test setups without a live LLM
	// client). Handlers for *_build and generate_* tools call
	// [Deps.RunBuildVerification] which handles the nil guard, so direct
	// nil checks are not needed in individual handlers.
	BuildVerify func(ctx context.Context, payloadType string, content []byte, bypass bool) (summary, blockMsg string)
}

Deps is the dependency bag both host modes inject when invoking a Handler. Fields are pointers so a nil zero value is a valid "feature disabled" signal; handlers MUST tolerate nil for any feature their mode does not wire up.

MCP mode (internal/mcp) wires only the first four — Flipper, Marauder, Audit, Config. The LLM-specific fields (Generator, GenLLM, Vision, Snapshot, RAG, TargetMem, SessionID, WorkflowConfirm) stay nil, and AgentOnly handlers are the only ones allowed to dereference them.

Agent mode (internal/agent) wires every field from the running *Agent instance.

func (*Deps) RequireBruce added in v0.9.0

func (d *Deps) RequireBruce() error

RequireBruce returns a friendly error when the optional Bruce devboard is not connected. Bruce handlers call this before invoking any d.Bruce method, mirroring RequireMarauder (internal/tools/spec.go).

func (*Deps) RequireBusPirate added in v0.9.0

func (d *Deps) RequireBusPirate() error

RequireBusPirate returns a friendly error when the optional Bus Pirate 5 universal-bus probe is not connected. BusPirate handlers call this before invoking any d.BusPirate method, mirroring Deps.RequireMarauder.

func (*Deps) RequireFaultier added in v0.9.0

func (d *Deps) RequireFaultier() error

RequireFaultier returns a friendly error when the optional Faultier client is not connected. Faultier handlers call this before invoking any d.Faultier method.

func (*Deps) RequireMarauder

func (d *Deps) RequireMarauder() error

RequireMarauder returns a friendly error when the optional Marauder devboard is not connected. WiFi and Marauder handlers call this before invoking any d.Marauder method, mirroring the agent's requireMarauder() shape (internal/agent/agent.go:870).

func (*Deps) RunBuildVerification

func (d *Deps) RunBuildVerification(ctx context.Context, payloadType string, content []byte, bypass bool) (summary, blockMsg string)

RunBuildVerification calls BuildVerify if wired, or returns empty strings when the verifier is not available (MCP mode, tests). A convenience wrapper so individual *_build handlers do not need to nil-check BuildVerify themselves.

func (*Deps) SnapshotBeforeWrite

func (d *Deps) SnapshotBeforeWrite(ctx context.Context, path string)

SnapshotBeforeWrite captures a pre-write copy of path's existing content (if any) into the per-session snapshot tree, so /rewind can roll the write back. A no-op when the snapshot feature is disabled (nil manager, empty session ID, or empty path). Errors are swallowed — snapshots are advisory and must never block the write path.

Wave engineers migrating storage_copy / storage_rename / fileformat_edit / *_build / generate_* handlers MUST call this before the underlying write, mirroring the existing agent.snapshotBeforeWrite behaviour. An identical helper kept the diff smaller in the agent-side migration.

type Group

type Group string

Group classifies a tool for the per-turn router (internal/agent/router.go). The string values MUST stay in sync with the Group* constants in that file so narrowTools can resolve a tool to its group purely from its Spec.

const (
	GroupMetaAudit      Group = "meta.audit"
	GroupMetaUtil       Group = "meta.util"
	GroupFlipperSystem  Group = "flipper.system"
	GroupFlipperSubGHz  Group = "flipper.rf.subghz"
	GroupFlipperIR      Group = "flipper.rf.ir"
	GroupFlipperNFC     Group = "flipper.nfc"
	GroupFlipperRFID    Group = "flipper.rfid"
	GroupFlipperIButton Group = "flipper.ibutton"
	GroupFlipperBadUSB  Group = "flipper.badusb"
	GroupFlipperHW      Group = "flipper.hw"
	GroupMarauderWiFi   Group = "marauder.wifi"
	GroupGen            Group = "gen"
	GroupWorkflows      Group = "workflows"
	GroupVision         Group = "vision"

	// GroupSecurity covers host-side security tools (hash analysis,
	// network scanning, HTTP enumeration). Single group for v0.5; may
	// be split into per-family subgroups (GroupSecurityHash,
	// GroupSecurityRecon, etc.) in v0.6 if the tool count grows past ~10.
	GroupSecurity Group = "security"

	// GroupHostTools covers tools that run on the operator's host machine
	// rather than on Flipper-attached hardware — firmware extraction,
	// container-bridge tools, binary analysis utilities.
	GroupHostTools Group = "host.tools"
)

Group* constants mirror the values in internal/agent/router.go. They are duplicated here (rather than imported) so this package stays leaf-like — internal/agent depends on internal/tools, not the other way round.

const GroupBruce Group = "bruce"

GroupBruce is the router bucket for all Bruce-backend tools.

const GroupFaultier Group = "faultier"

GroupFaultier is the router bucket for Faultier voltage-glitcher tools.

type Handler

type Handler func(ctx context.Context, d *Deps, args map[string]any) (string, error)

Handler is the single unified tool handler signature. Ctx is the turn context (already carrying trace IDs, OTel span, etc. in agent mode). The Deps bag is injected by whichever mode hosts the registry; the handler MUST guard against nil fields that its mode may not wire up (e.g. an MCP-only host will not set Snapshot or Generator).

type Spec

type Spec struct {
	// Name is the canonical tool identifier. Must be unique across the
	// entire registry — [Register] panics on a duplicate (an init-time
	// loud failure is the right shape for a programming error that
	// would silently corrupt dispatch otherwise).
	Name string

	// Aliases are additional names that resolve to the same Handler.
	// Used for legacy synonyms — e.g. system_info was the agent-side
	// name and device_info is the MCP / firmware name. Both resolve
	// via [Get]. Aliases MUST NOT collide with another Spec's Name.
	Aliases []string

	// Description is the user-visible tool documentation. Must be
	// self-contained — the MCP client, the agent's Anthropic schema,
	// and /tools all read this same string. Keep it under ~1 KB so
	// the prompt-cache breakpoint stays reasonable.
	Description string

	// Schema is the canonical JSON Schema for the tool's parameters
	// (an object with "properties" and optionally "required"). Both
	// mode adapters decode arguments into map[string]any, so the
	// schema's job is catalog advertisement, not runtime validation.
	Schema json.RawMessage

	// Required lists parameters the caller MUST supply. The MCP mode
	// adapter validates this explicitly (missingRequired in the old
	// s.add()); the agent mode advertises it via InputSchema.Required.
	Required []string

	// Risk is the confirmation-gate classification. Drives
	// internal/risk.Classify, the MCP annotation hints
	// (readOnlyHint/destructiveHint/openWorldHint), and the interactive
	// ConfirmFunc prompt in REPL mode.
	Risk risk.Level

	// Group is the router bucket. Defaults to GroupMetaUtil when the
	// zero value is registered. See internal/agent/router.go for the
	// narrowing logic.
	Group Group

	// AgentOnly excludes this tool from the MCP adapter. Reserved for
	// LLM-composition tools that require facilities MCP does not have
	// (generator LLM, vision analyzer, snapshot manager, workflow
	// confirmation hook). An AgentOnly handler may safely dereference
	// any field on Deps; a non-AgentOnly handler must degrade when
	// those fields are nil.
	AgentOnly bool

	// Handler is the dispatch body. Wave engineers paste the
	// corresponding `case "<name>":` body from internal/agent/agent.go's
	// dispatch switch into this function, substituting `a.flipper` →
	// `d.Flipper`, `a.marauder` → `d.Marauder`, etc.
	Handler Handler

	// Streams declares whether the tool can emit partial output via
	// a streaming.Sink during dispatch (roadmap P3-28 first half).
	// Operator-facing UIs (CLI status line, web UI, SSE forwarder)
	// subscribe to the per-call sink to surface live progress;
	// the LLM-facing tool_result is unchanged — it remains the
	// final return string. Default false; non-streaming dispatch is
	// the historical behaviour.
	Streams bool

	// StreamHandler is the streaming-handler variant. Optional —
	// when nil, the dispatcher uses Handler. When set AND the host
	// has installed a stream callback, the dispatcher invokes
	// StreamHandler with a fresh sink and forwards frames to the
	// callback in real time. The callback ALSO receives a final
	// frame on close so consumers can flush any per-tool buffer.
	//
	// StreamHandler still returns the final tool_result string so
	// the LLM contract is unchanged: the agent serialises the
	// return value into the tool_result block exactly as for the
	// non-streaming Handler. Streaming is an addition to the side
	// channel, never a replacement for the model-facing answer.
	StreamHandler streamHandler

	// WriteIntent, when non-nil, is invoked by the confirmation flow
	// to extract the (path, content) the tool would write. The flow
	// uses these to fetch the existing file and show a unified diff
	// in the confirmation prompt before the operator approves a
	// medium-risk overwrite. nil means "this tool isn't a file write"
	// — the vast majority of Specs.
	//
	// The function MUST be cheap and side-effect-free: it runs at
	// confirmation time, on the args the model proposed, before any
	// risk gate has cleared. Returning ok=false signals "args don't
	// describe a write right now" and the framework skips the diff
	// preview without erroring (e.g. a deploy=false flag).
	WriteIntent func(args map[string]any) (path string, content string, ok bool)
}

Spec is the canonical description of one tool.

A Spec is self-contained: Name + Description + Schema + Required are the contract that the MCP server advertises and the Anthropic schema declares; Risk + Group drive confirmation gates and the per-turn router; Handler is the code that runs when the tool is invoked; and AgentOnly / Aliases adapt the same Spec to the two host modes.

func All

func All() []Spec

All returns every registered Spec in registration order. The slice is a fresh copy — callers may sort or filter in place without affecting the registry.

func Get

func Get(name string) (Spec, bool)

Get returns the Spec registered under name or any of its aliases, and whether the lookup succeeded.

type StreamHandler added in v0.55.0

type StreamHandler = streamHandler

StreamHandler is the exported alias of streamHandler. Tool authors declare the streaming variant via the public name; the internal type stays unexported so the Spec field's signature in the catalog reads cleanly.

type WiegandResult added in v0.44.0

type WiegandResult struct {
	Format          string `json:"format"`
	BitCount        int    `json:"bit_count"`
	FacilityCode    uint64 `json:"facility_code"`
	FacilityCodeHex string `json:"facility_code_hex"`
	CardNumber      uint64 `json:"card_number"`
	CardNumberHex   string `json:"card_number_hex"`
	ParityValid     bool   `json:"parity_valid"`
	LeadingParity   bool   `json:"leading_parity"`
	TrailingParity  bool   `json:"trailing_parity"`
	RawBits         string `json:"raw_bits"`
}

WiegandResult is the decoded view of a Wiegand bitstream.

FacilityCode and CardNumber are exposed in both decimal (the numeric fields) and hex strings (the *Hex fields) because access cards are often printed in either form depending on the manufacturer; serving both saves the operator a conversion step when they're cross-referencing a printed card against a sniffed frame.

func DecodeWiegand added in v0.44.0

func DecodeWiegand(bits []bool) (WiegandResult, error)

DecodeWiegand dispatches to the per-format decoder by bit count. Exposed so other internal tooling (workflows, future MCP federation adapters) can reuse the parser without going through the Spec registry.

Jump to

Keyboard shortcuts

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