返回 DeepSeek-Reasonix
provides.go
根目录 / internal / extension / sidecar / provides.go
1 package sidecar
2
3 import (
4 "fmt"
5 "strings"
6
7 "reasonix/internal/extension/protocol"
8 "reasonix/internal/pluginpkg"
9 )
10
11 func (c *Client) initializeParams() protocol.InitializeParams {
12 return protocol.InitializeParams{
13 ProtocolVersion: protocol.ProtocolVersion,
14 ProtocolID: protocol.ProtocolID,
15 Manifest: c.manifestExpectation(),
16 Session: c.session,
17 DependencySchemaVersion: protocol.DependencySchemaVersion,
18 Capabilities: protocol.HostCapabilities{
19 ContentRefs: true,
20 UIHost: c.uiHost,
21 ProtocolVersion: protocol.ProtocolVersion,
22 DependencySchemaVersion: protocol.DependencySchemaVersion,
23 },
24 }
25 }
26
27 func (c *Client) manifestExpectation() protocol.ManifestExpectation {
28 rt := c.rt
29 expectation := protocol.ManifestExpectation{
30 Intercepts: append([]string(nil), rt.Intercepts...),
31 Replaces: append([]string(nil), rt.Replaces...),
32 Capabilities: append([]string(nil), rt.Capabilities...),
33 Requires: requirementWires(c.requires),
34 Provides: capabilityWires(c.provides),
35 }
36 for _, provided := range c.provides {
37 switch strings.ToLower(strings.TrimSpace(provided.Kind)) {
38 case "provider":
39 expectation.Providers = append(expectation.Providers, capabilityAddress(provided))
40 case "uiaction":
41 expectation.UIActions = append(expectation.UIActions, strings.TrimSpace(provided.ID))
42 }
43 }
44 return expectation
45 }
46
47 func capabilityAddress(ref pluginpkg.CapabilityRef) string {
48 return strings.TrimSuffix(strings.TrimSpace(ref.Namespace), "/") + "/" + strings.TrimPrefix(strings.TrimSpace(ref.ID), "/")
49 }
50
51 func capabilityWires(refs []pluginpkg.CapabilityRef) []protocol.CapabilityWire {
52 out := make([]protocol.CapabilityWire, 0, len(refs))
53 for _, ref := range refs {
54 out = append(out, protocol.CapabilityWire{
55 Namespace: strings.TrimSpace(ref.Namespace),
56 Kind: strings.TrimSpace(ref.Kind),
57 ID: strings.TrimSpace(ref.ID),
58 Version: strings.TrimSpace(ref.Version),
59 SchemaHash: strings.TrimSpace(ref.SchemaHash),
60 })
61 }
62 return out
63 }
64
65 func requirementWires(refs []pluginpkg.CapabilityRef) []protocol.RequirementWire {
66 out := make([]protocol.RequirementWire, 0, len(refs))
67 for _, ref := range refs {
68 out = append(out, protocol.RequirementWire{
69 Namespace: strings.TrimSpace(ref.Namespace),
70 Kind: strings.TrimSpace(ref.Kind),
71 ID: strings.TrimSpace(ref.ID),
72 Version: strings.TrimSpace(ref.Version),
73 SchemaHash: strings.TrimSpace(ref.SchemaHash),
74 VersionRange: strings.TrimSpace(ref.VersionRange),
75 Optional: ref.Optional,
76 })
77 }
78 return out
79 }
80
81 // validateProvidesCeiling rejects handshake Provides entries that are not a
82 // subset of the manifest capability ceiling (by namespace/kind/id).
83 func validateProvidesCeiling(manifest []pluginpkg.CapabilityRef, wire []protocol.CapabilityWire) error {
84 if len(wire) == 0 {
85 return nil
86 }
87 if len(manifest) == 0 {
88 // No v2 provides list: fall back to runtime.capabilities string checks above.
89 return nil
90 }
91 allowed := map[string]bool{}
92 for _, p := range manifest {
93 key := strings.TrimSpace(p.Namespace) + "/" + strings.TrimSpace(p.Kind) + "/" + strings.TrimSpace(p.ID)
94 allowed[key] = true
95 }
96 for _, w := range wire {
97 key := strings.TrimSpace(w.Namespace) + "/" + strings.TrimSpace(w.Kind) + "/" + strings.TrimSpace(w.ID)
98 if !allowed[key] {
99 return fmt.Errorf("handshake provides %q is outside the manifest provides ceiling", key)
100 }
101 }
102 return nil
103 }
104
104 lines GO