返回 DeepSeek-Reasonix
errors.go
根目录 / internal / installsource / errors.go
1 package installsource
2
3 import (
4 "errors"
5 "fmt"
6 )
7
8 // RiskLevel classifies how dangerous an action is. The install-capability skill
9 // prompt tells the model to call apply=true only when every action is low or
10 // medium, or to ask the user first when any action is high.
11 type RiskLevel string
12
13 const (
14 // RiskLow is read-mostly safe: copy/link of a single skill file, or
15 // connecting an MCP endpoint whose URL the user already trusts.
16 RiskLow RiskLevel = "low"
17 // RiskMedium is a write that mutates the active config (new MCP server,
18 // new skill registered into a project root the user already shares).
19 RiskMedium RiskLevel = "medium"
20 // RiskHigh is a write the user almost certainly wants to see first: a
21 // symlink target outside any expected scope, a remote URL with auth
22 // headers, a package name that triggers an out-of-process fetch, or a
23 // replace of an existing MCP server.
24 RiskHigh RiskLevel = "high"
25 )
26
27 // Sentinel errors. Callers use errors.Is to map a failure to a remediation
28 // hint without scraping error messages.
29 var (
30 // ErrAuthRequired: the upstream demanded credentials that the request
31 // did not carry. Surface a hint to set the relevant env var or header.
32 ErrAuthRequired = errors.New("install_source: authentication required")
33 // ErrBinaryMissing: a stdio MCP server references a command that is not
34 // on PATH or not present at the given path.
35 ErrBinaryMissing = errors.New("install_source: command or runtime not found")
36 // ErrAlreadyExists: a target file / config entry already exists and the
37 // call did not opt into replace=true.
38 ErrAlreadyExists = errors.New("install_source: target already exists")
39 // ErrUnsafeLinkTarget: a link-mode skill install would create a symlink
40 // that escapes the expected skill roots — typically an attempt to
41 // read arbitrary host files.
42 ErrUnsafeLinkTarget = errors.New("install_source: link target escapes skill roots")
43 // ErrSourceUnreadable: a URL did not respond, returned non-2xx, or a
44 // local path was not readable.
45 ErrSourceUnreadable = errors.New("install_source: source is not readable")
46 // ErrManifestMissing: a path was reachable but contained no installable
47 // artifact (no SKILL.md, no .mcp.json, no executable, etc.).
48 ErrManifestMissing = errors.New("install_source: no installable manifest")
49 // ErrInvalidManifest: a manifest existed but did not validate (missing
50 // required fields, unknown transport, etc.).
51 ErrInvalidManifest = errors.New("install_source: manifest did not validate")
52 // ErrNoCompatibleCapabilities: a plugin manifest was valid but none of its
53 // capabilities can run in Reasonix. Preview returns a structured block.
54 ErrNoCompatibleCapabilities = errors.New("install_source: plugin has no compatible capabilities")
55 // ErrUnsupportedKind: kind was set explicitly to something the resolver
56 // cannot satisfy (e.g. kind=skill for a remote MCP endpoint).
57 ErrUnsupportedKind = errors.New("install_source: kind does not match source")
58 // ErrApprovalDenied: the host's ApprovalFunc returned a non-nil error,
59 // or the call set apply=true while the host requires explicit consent.
60 ErrApprovalDenied = errors.New("install_source: host denied the install")
61 )
62
63 // errKind wraps a sentinel with a human-readable detail so logs and the
64 // `next` field stay useful.
65 type errKind struct {
66 sentinel error
67 detail string
68 }
69
70 func (e *errKind) Error() string { return fmt.Sprintf("%s: %s", e.sentinel, e.detail) }
71 func (e *errKind) Unwrap() error { return e.sentinel }
72
73 func newErr(sentinel error, format string, args ...any) error {
74 return &errKind{sentinel: sentinel, detail: fmt.Sprintf(format, args...)}
75 }
76
76 lines GO