magic-agent 1.0.3 → 1.0.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLIENT-CONTRACT.md +254 -8
- package/README.md +48 -5
- package/client-ui/index.html +32 -0
- package/client-ui/pc/app.css +89 -1
- package/client-ui/pc/index.html +18 -8
- package/client-ui/pc/js/00-base.js +8 -30
- package/client-ui/pc/js/05-task-list-render.js +4 -1
- package/client-ui/pc/js/07-chat-stream-render.js +2 -85
- package/client-ui/pc/js/10-markdown.js +3 -171
- package/client-ui/pc/js/18-askbox.js +2 -176
- package/client-ui/pc/js/90-glue.js +1 -1
- package/client-ui/pc/js/91-workbench-stubs.js +4 -10
- package/client-ui/pc/js/93-rail.js +10 -3
- package/client-ui/shared/conv/01-dom.js +52 -0
- package/client-ui/shared/conv/02-media-kinds.js +34 -0
- package/client-ui/shared/conv/03-chat-message.js +1561 -0
- package/client-ui/shared/conv/06-ask-answer.js +377 -0
- package/client-ui/shared/conv/07-stream-delegation.js +158 -0
- package/client-ui/{pc/js → shared/conv}/09-stream-apply.js +121 -6
- package/client-ui/shared/conv/10-markdown-render.js +252 -0
- package/client-ui/shared/conv/18-askbox-markup.js +185 -0
- package/client-ui/{pc/js → shared/conv}/19-attachments.js +365 -21
- package/client-ui/shared/conv/27-conv-ledger.js +381 -0
- package/client-ui/{pc/js → shared/conv}/29-msg-variants.js +112 -3
- package/client-ui/shared/conv/README.md +257 -0
- package/client-ui/shared/conv/conv.css +1638 -0
- package/client-ui/shared/conv/dom-map.md +170 -0
- package/client-ui/shared/conv/manifest.json +44 -0
- package/client-ui/shared/conversation.css +368 -190
- package/client-ui/shared/conversation.js +1722 -788
- package/client-ui/shared/host-glue.js +143 -0
- package/client-ui/shared/transport-http.js +130 -6
- package/client-ui-mobile/index.html +2417 -103
- package/cmd/magic-client/clientctl.go +273 -0
- package/cmd/magic-client/main.go +71 -5
- package/go.mod +6 -3
- package/go.sum +4 -1
- package/internal/agent/arkclaw.go +3 -2
- package/internal/agent/arkclaw_stream.go +126 -8
- package/internal/agent/arkclaw_stream_test.go +97 -15
- package/internal/agent/arkclaw_test.go +3 -3
- package/internal/agent/attachments.go +18 -5
- package/internal/agent/attachments_test.go +7 -1
- package/internal/agent/capability_test.go +11 -1
- package/internal/agent/claude.go +96 -158
- package/internal/agent/codebuddy.go +108 -133
- package/internal/agent/codebuddy_gateway.go +8 -4
- package/internal/agent/codebuddy_gateway_stream.go +82 -2
- package/internal/agent/codebuddy_gateway_test.go +236 -1
- package/internal/agent/codebuddy_stream_test.go +262 -0
- package/internal/agent/codex.go +50 -9
- package/internal/agent/codex_stream_test.go +30 -0
- package/internal/agent/codex_test.go +24 -0
- package/internal/agent/custom_models.go +109 -3
- package/internal/agent/custom_models_test.go +74 -0
- package/internal/agent/dsh.go +464 -130
- package/internal/agent/dsh_resume.go +258 -0
- package/internal/agent/dsh_sdk.go +68 -17
- package/internal/agent/dsh_sdk_test.go +102 -2
- package/internal/agent/dsh_test.go +409 -36
- package/internal/agent/engine.go +26 -6
- package/internal/agent/engine_base.go +46 -2
- package/internal/agent/engine_base_test.go +29 -0
- package/internal/agent/engine_test.go +101 -0
- package/internal/agent/env.go +69 -1
- package/internal/agent/itemtracker.go +271 -0
- package/internal/agent/launch.go +192 -0
- package/internal/agent/launch_test.go +206 -0
- package/internal/agent/launch_unix.go +15 -0
- package/internal/agent/launch_windows.go +24 -0
- package/internal/agent/limitnotice.go +103 -0
- package/internal/agent/limitnotice_test.go +211 -0
- package/internal/agent/llmengine.go +2 -2
- package/internal/agent/models.go +3 -2
- package/internal/agent/openclaw.go +4 -3
- package/internal/agent/openclaw_acp.go +7 -0
- package/internal/agent/openclaw_test.go +2 -2
- package/internal/agent/permission.go +100 -11
- package/internal/agent/permission_test.go +100 -36
- package/internal/agent/runcmd.go +13 -3
- package/internal/agent/runner.go +7 -1
- package/internal/agent/runner_test.go +1 -1
- package/internal/agent/stream.go +777 -43
- package/internal/agent/stream_test.go +3 -2
- package/internal/agent/stream_timeline_test.go +905 -0
- package/internal/agent/streamjson.go +36 -2
- package/internal/agent/toolkind.go +20 -1
- package/internal/agent/toolkind_test.go +7 -1
- package/internal/agent/tools_suffix_test.go +10 -3
- package/internal/agent/trae.go +5 -3
- package/internal/agent/workspace_test.go +52 -0
- package/internal/cli/ask.go +260 -33
- package/internal/cli/ask_test.go +15 -11
- package/internal/cli/attach_test.go +32 -20
- package/internal/cli/clientcmd.go +156 -0
- package/internal/cli/events.go +53 -8
- package/internal/cli/events_test.go +230 -0
- package/internal/cli/keepalive_test.go +101 -6
- package/internal/cli/permission_test.go +5 -1
- package/internal/cli/root.go +174 -32
- package/internal/cli/session.go +175 -28
- package/internal/cli/session_test.go +144 -5
- package/internal/cli/sessionlog.go +385 -38
- package/internal/cli/sessionlog_test.go +708 -0
- package/internal/cli/sessionlog_user_test.go +142 -1
- package/internal/cli/sessiontitle.go +141 -0
- package/internal/client/browse.go +456 -0
- package/internal/client/browse_test.go +199 -0
- package/internal/client/cors_test.go +35 -0
- package/internal/client/daemon.go +525 -0
- package/internal/client/daemon_test.go +212 -0
- package/internal/client/detach_unix.go +19 -0
- package/internal/client/detach_windows.go +27 -0
- package/internal/client/pair.go +3 -3
- package/internal/client/plugins.go +376 -0
- package/internal/client/plugins_test.go +223 -0
- package/internal/client/proxy.go +374 -0
- package/internal/client/proxy_test.go +212 -0
- package/internal/client/service.go +1464 -48
- package/internal/client/service_test.go +649 -206
- package/internal/client/session_events_test.go +130 -0
- package/internal/client/wsproxy.go +113 -0
- package/internal/client/wsproxy_test.go +102 -0
- package/internal/session/delete.go +151 -0
- package/internal/session/delete_test.go +103 -0
- package/internal/session/session.go +155 -20
- package/internal/session/session_append.go +79 -21
- package/internal/session/session_test.go +124 -10
- package/internal/session/sessionlog.go +572 -6
- package/internal/session/sessionlog_read_test.go +410 -0
- package/internal/session/title.go +486 -0
- package/internal/session/title_test.go +298 -0
- package/npm/bin/magic-agent.js +101 -10
- package/npm/bin/magic-client.js +118 -0
- package/npm/dist/darwin-arm64/magic-agent +0 -0
- package/npm/dist/darwin-arm64/magic-client +0 -0
- package/npm/dist/darwin-x64/magic-agent +0 -0
- package/npm/dist/darwin-x64/magic-client +0 -0
- package/npm/dist/linux-arm64/magic-agent +0 -0
- package/npm/dist/linux-arm64/magic-client +0 -0
- package/npm/dist/linux-x64/magic-agent +0 -0
- package/npm/dist/linux-x64/magic-client +0 -0
- package/npm/dist/win32-x64/magic-agent.exe +0 -0
- package/npm/dist/win32-x64/magic-client.exe +0 -0
- package/npm/install.js +36 -13
- package/npm/lib/platform.js +27 -5
- package/package.json +8 -3
- package/client-ui/pc/js/03-chat-message.js +0 -880
- package/client-ui/pc/js/06-ask-answer.js +0 -204
- /package/client-ui/{pc/js → shared/conv}/08-ask-event-map.js +0 -0
- /package/client-ui/{pc → shared}/vendor/highlight.min.js +0 -0
- /package/client-ui/{pc → shared}/vendor/marked.min.js +0 -0
- /package/client-ui/{pc → shared}/vendor/purify.min.js +0 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
package client
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"encoding/binary"
|
|
5
|
+
"fmt"
|
|
6
|
+
"io"
|
|
7
|
+
"log"
|
|
8
|
+
"net"
|
|
9
|
+
"net/http"
|
|
10
|
+
"net/http/httptest"
|
|
11
|
+
"net/url"
|
|
12
|
+
"strings"
|
|
13
|
+
"testing"
|
|
14
|
+
"time"
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
// socks5Request 手写一遍 SOCKS5 握手,验证服务端行为(不引第三方库)。
|
|
18
|
+
func socks5Request(t *testing.T, proxyAddr, user, pass, targetHost string, targetPort int) (net.Conn, error) {
|
|
19
|
+
t.Helper()
|
|
20
|
+
c, err := net.DialTimeout("tcp", proxyAddr, 3*time.Second)
|
|
21
|
+
if err != nil {
|
|
22
|
+
return nil, err
|
|
23
|
+
}
|
|
24
|
+
// 协商:只给「用户名口令」一种方法。
|
|
25
|
+
if _, err := c.Write([]byte{0x05, 0x01, 0x02}); err != nil {
|
|
26
|
+
return nil, err
|
|
27
|
+
}
|
|
28
|
+
sel := make([]byte, 2)
|
|
29
|
+
if _, err := io.ReadFull(c, sel); err != nil {
|
|
30
|
+
return nil, err
|
|
31
|
+
}
|
|
32
|
+
if sel[0] != 0x05 || sel[1] != 0x02 {
|
|
33
|
+
c.Close()
|
|
34
|
+
return nil, fmt.Errorf("协商失败:%v", sel)
|
|
35
|
+
}
|
|
36
|
+
// 认证
|
|
37
|
+
req := []byte{0x01, byte(len(user))}
|
|
38
|
+
req = append(req, user...)
|
|
39
|
+
req = append(req, byte(len(pass)))
|
|
40
|
+
req = append(req, pass...)
|
|
41
|
+
if _, err := c.Write(req); err != nil {
|
|
42
|
+
return nil, err
|
|
43
|
+
}
|
|
44
|
+
ar := make([]byte, 2)
|
|
45
|
+
if _, err := io.ReadFull(c, ar); err != nil {
|
|
46
|
+
return nil, err
|
|
47
|
+
}
|
|
48
|
+
if ar[1] != 0x00 {
|
|
49
|
+
c.Close()
|
|
50
|
+
return nil, fmt.Errorf("认证失败:%v", ar)
|
|
51
|
+
}
|
|
52
|
+
// CONNECT(域名形式)
|
|
53
|
+
r := []byte{0x05, 0x01, 0x00, 0x03, byte(len(targetHost))}
|
|
54
|
+
r = append(r, targetHost...)
|
|
55
|
+
p := make([]byte, 2)
|
|
56
|
+
binary.BigEndian.PutUint16(p, uint16(targetPort))
|
|
57
|
+
r = append(r, p...)
|
|
58
|
+
if _, err := c.Write(r); err != nil {
|
|
59
|
+
return nil, err
|
|
60
|
+
}
|
|
61
|
+
rep := make([]byte, 10)
|
|
62
|
+
if _, err := io.ReadFull(c, rep); err != nil {
|
|
63
|
+
return nil, err
|
|
64
|
+
}
|
|
65
|
+
if rep[1] != 0x00 {
|
|
66
|
+
c.Close()
|
|
67
|
+
return nil, fmt.Errorf("CONNECT 被拒:rep=%d", rep[1])
|
|
68
|
+
}
|
|
69
|
+
return c, nil
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
func TestSOCKS5ProxyConnect(t *testing.T) {
|
|
73
|
+
upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
74
|
+
_, _ = io.WriteString(w, "hello-from-upstream")
|
|
75
|
+
}))
|
|
76
|
+
defer upstream.Close()
|
|
77
|
+
uu, _ := url.Parse(upstream.URL)
|
|
78
|
+
|
|
79
|
+
s := &Service{log: testLogger(), opts: Options{Token: "sekret"}}
|
|
80
|
+
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
|
81
|
+
if err != nil {
|
|
82
|
+
t.Fatal(err)
|
|
83
|
+
}
|
|
84
|
+
defer ln.Close()
|
|
85
|
+
go func() { _ = s.ServeProxy(ln) }()
|
|
86
|
+
|
|
87
|
+
host, portStr, _ := net.SplitHostPort(uu.Host)
|
|
88
|
+
var port int
|
|
89
|
+
_, _ = fmt.Sscanf(portStr, "%d", &port)
|
|
90
|
+
|
|
91
|
+
conn, err := socks5Request(t, ln.Addr().String(), "magic", "sekret", host, port)
|
|
92
|
+
if err != nil {
|
|
93
|
+
t.Fatalf("SOCKS5 握手失败:%v", err)
|
|
94
|
+
}
|
|
95
|
+
defer conn.Close()
|
|
96
|
+
|
|
97
|
+
_, _ = io.WriteString(conn, "GET / HTTP/1.1\r\nHost: "+uu.Host+"\r\nConnection: close\r\n\r\n")
|
|
98
|
+
body, err := io.ReadAll(conn)
|
|
99
|
+
if err != nil {
|
|
100
|
+
t.Fatal(err)
|
|
101
|
+
}
|
|
102
|
+
if !strings.Contains(string(body), "hello-from-upstream") {
|
|
103
|
+
t.Errorf("未取到上游内容,实际:%s", body)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
func TestSOCKS5ProxyRejectsBadPassword(t *testing.T) {
|
|
108
|
+
s := &Service{log: testLogger(), opts: Options{Token: "sekret"}}
|
|
109
|
+
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
|
110
|
+
if err != nil {
|
|
111
|
+
t.Fatal(err)
|
|
112
|
+
}
|
|
113
|
+
defer ln.Close()
|
|
114
|
+
go func() { _ = s.ServeProxy(ln) }()
|
|
115
|
+
|
|
116
|
+
if _, err := socks5Request(t, ln.Addr().String(), "magic", "wrong", "example.com", 80); err == nil {
|
|
117
|
+
t.Error("错误口令应当被拒")
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
func testLogger() *log.Logger { return log.New(io.Discard, "", 0) }
|
|
122
|
+
|
|
123
|
+
// TestSOCKS5UDPAssociate 验证 UDP ASSOCIATE:VPN 里 DNS/QUIC 全靠它。
|
|
124
|
+
func TestSOCKS5UDPAssociate(t *testing.T) {
|
|
125
|
+
echo, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0})
|
|
126
|
+
if err != nil {
|
|
127
|
+
t.Fatal(err)
|
|
128
|
+
}
|
|
129
|
+
defer echo.Close()
|
|
130
|
+
go func() {
|
|
131
|
+
b := make([]byte, 2048)
|
|
132
|
+
for {
|
|
133
|
+
n, from, err := echo.ReadFromUDP(b)
|
|
134
|
+
if err != nil {
|
|
135
|
+
return
|
|
136
|
+
}
|
|
137
|
+
_, _ = echo.WriteToUDP(append([]byte("echo:"), b[:n]...), from)
|
|
138
|
+
}
|
|
139
|
+
}()
|
|
140
|
+
|
|
141
|
+
s := &Service{log: testLogger(), opts: Options{Token: "sekret"}}
|
|
142
|
+
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
|
143
|
+
if err != nil {
|
|
144
|
+
t.Fatal(err)
|
|
145
|
+
}
|
|
146
|
+
defer ln.Close()
|
|
147
|
+
go func() { _ = s.ServeProxy(ln) }()
|
|
148
|
+
|
|
149
|
+
c, err := net.DialTimeout("tcp", ln.Addr().String(), 3*time.Second)
|
|
150
|
+
if err != nil {
|
|
151
|
+
t.Fatal(err)
|
|
152
|
+
}
|
|
153
|
+
defer c.Close()
|
|
154
|
+
|
|
155
|
+
_, _ = c.Write([]byte{0x05, 0x01, 0x02})
|
|
156
|
+
sel := make([]byte, 2)
|
|
157
|
+
if _, err := io.ReadFull(c, sel); err != nil || sel[1] != 0x02 {
|
|
158
|
+
t.Fatalf("协商失败:%v %v", sel, err)
|
|
159
|
+
}
|
|
160
|
+
auth := []byte{0x01, 5}
|
|
161
|
+
auth = append(auth, "magic"...)
|
|
162
|
+
auth = append(auth, 6)
|
|
163
|
+
auth = append(auth, "sekret"...)
|
|
164
|
+
_, _ = c.Write(auth)
|
|
165
|
+
ar := make([]byte, 2)
|
|
166
|
+
if _, err := io.ReadFull(c, ar); err != nil || ar[1] != 0 {
|
|
167
|
+
t.Fatalf("认证失败:%v %v", ar, err)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// UDP ASSOCIATE(DST 用 0.0.0.0:0)
|
|
171
|
+
_, _ = c.Write([]byte{0x05, 0x03, 0x00, 0x01, 0, 0, 0, 0, 0, 0})
|
|
172
|
+
rep := make([]byte, 10)
|
|
173
|
+
if _, err := io.ReadFull(c, rep); err != nil {
|
|
174
|
+
t.Fatal(err)
|
|
175
|
+
}
|
|
176
|
+
if rep[1] != 0x00 {
|
|
177
|
+
t.Fatalf("UDP ASSOCIATE 被拒:rep=%d", rep[1])
|
|
178
|
+
}
|
|
179
|
+
relay := &net.UDPAddr{IP: net.IP(rep[4:8]), Port: int(binary.BigEndian.Uint16(rep[8:10]))}
|
|
180
|
+
if relay.IP.IsUnspecified() {
|
|
181
|
+
relay.IP = net.IPv4(127, 0, 0, 1)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
uc, err := net.DialUDP("udp", nil, relay)
|
|
185
|
+
if err != nil {
|
|
186
|
+
t.Fatal(err)
|
|
187
|
+
}
|
|
188
|
+
defer uc.Close()
|
|
189
|
+
|
|
190
|
+
target := echo.LocalAddr().(*net.UDPAddr)
|
|
191
|
+
pkt := []byte{0x00, 0x00, 0x00, 0x01}
|
|
192
|
+
pkt = append(pkt, target.IP.To4()...)
|
|
193
|
+
pkt = append(pkt, byte(target.Port>>8), byte(target.Port))
|
|
194
|
+
pkt = append(pkt, []byte("ping")...)
|
|
195
|
+
if _, err := uc.Write(pkt); err != nil {
|
|
196
|
+
t.Fatal(err)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
_ = uc.SetReadDeadline(time.Now().Add(5 * time.Second))
|
|
200
|
+
rb := make([]byte, 2048)
|
|
201
|
+
n, err := uc.Read(rb)
|
|
202
|
+
if err != nil {
|
|
203
|
+
t.Fatalf("读回包失败:%v", err)
|
|
204
|
+
}
|
|
205
|
+
_, payload, ok := parseSocksUDP(rb[:n])
|
|
206
|
+
if !ok {
|
|
207
|
+
t.Fatalf("回包格式不对:%x", rb[:n])
|
|
208
|
+
}
|
|
209
|
+
if string(payload) != "echo:ping" {
|
|
210
|
+
t.Errorf("回包内容不对:%q", payload)
|
|
211
|
+
}
|
|
212
|
+
}
|