magic-agent 1.0.2 → 1.0.46

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.
Files changed (159) hide show
  1. package/CLIENT-CONTRACT.md +254 -8
  2. package/README.md +48 -5
  3. package/client-ui/index.html +32 -0
  4. package/client-ui/pc/app.css +89 -1
  5. package/client-ui/pc/index.html +18 -8
  6. package/client-ui/pc/js/00-base.js +8 -30
  7. package/client-ui/pc/js/05-task-list-render.js +4 -1
  8. package/client-ui/pc/js/07-chat-stream-render.js +2 -85
  9. package/client-ui/pc/js/10-markdown.js +3 -171
  10. package/client-ui/pc/js/18-askbox.js +2 -176
  11. package/client-ui/pc/js/90-glue.js +1 -1
  12. package/client-ui/pc/js/91-workbench-stubs.js +4 -10
  13. package/client-ui/pc/js/93-rail.js +10 -3
  14. package/client-ui/shared/conv/01-dom.js +52 -0
  15. package/client-ui/shared/conv/02-media-kinds.js +34 -0
  16. package/client-ui/shared/conv/03-chat-message.js +1561 -0
  17. package/client-ui/shared/conv/06-ask-answer.js +377 -0
  18. package/client-ui/shared/conv/07-stream-delegation.js +158 -0
  19. package/client-ui/{pc/js → shared/conv}/09-stream-apply.js +121 -6
  20. package/client-ui/shared/conv/10-markdown-render.js +252 -0
  21. package/client-ui/shared/conv/18-askbox-markup.js +185 -0
  22. package/client-ui/{pc/js → shared/conv}/19-attachments.js +365 -21
  23. package/client-ui/shared/conv/27-conv-ledger.js +381 -0
  24. package/client-ui/{pc/js → shared/conv}/29-msg-variants.js +112 -3
  25. package/client-ui/shared/conv/README.md +257 -0
  26. package/client-ui/shared/conv/conv.css +1638 -0
  27. package/client-ui/shared/conv/dom-map.md +170 -0
  28. package/client-ui/shared/conv/manifest.json +44 -0
  29. package/client-ui/shared/conversation.css +368 -190
  30. package/client-ui/shared/conversation.js +1722 -788
  31. package/client-ui/shared/host-glue.js +143 -0
  32. package/client-ui/shared/transport-http.js +130 -6
  33. package/client-ui-mobile/index.html +2417 -103
  34. package/cmd/magic-client/clientctl.go +273 -0
  35. package/cmd/magic-client/main.go +71 -5
  36. package/go.mod +6 -3
  37. package/go.sum +4 -1
  38. package/internal/agent/arkclaw.go +3 -2
  39. package/internal/agent/arkclaw_stream.go +126 -8
  40. package/internal/agent/arkclaw_stream_test.go +97 -15
  41. package/internal/agent/arkclaw_test.go +3 -3
  42. package/internal/agent/attachments.go +18 -5
  43. package/internal/agent/attachments_test.go +7 -1
  44. package/internal/agent/capability_test.go +11 -1
  45. package/internal/agent/claude.go +96 -158
  46. package/internal/agent/codebuddy.go +108 -133
  47. package/internal/agent/codebuddy_gateway.go +8 -4
  48. package/internal/agent/codebuddy_gateway_stream.go +82 -2
  49. package/internal/agent/codebuddy_gateway_test.go +236 -1
  50. package/internal/agent/codebuddy_stream_test.go +262 -0
  51. package/internal/agent/codex.go +50 -9
  52. package/internal/agent/codex_stream_test.go +30 -0
  53. package/internal/agent/codex_test.go +24 -0
  54. package/internal/agent/custom_models.go +260 -8
  55. package/internal/agent/custom_models_test.go +204 -7
  56. package/internal/agent/dsh.go +464 -130
  57. package/internal/agent/dsh_resume.go +258 -0
  58. package/internal/agent/dsh_sdk.go +68 -17
  59. package/internal/agent/dsh_sdk_test.go +102 -2
  60. package/internal/agent/dsh_test.go +409 -36
  61. package/internal/agent/engine.go +26 -6
  62. package/internal/agent/engine_base.go +46 -2
  63. package/internal/agent/engine_base_test.go +29 -0
  64. package/internal/agent/engine_test.go +101 -0
  65. package/internal/agent/env.go +78 -2
  66. package/internal/agent/env_test.go +37 -0
  67. package/internal/agent/itemtracker.go +271 -0
  68. package/internal/agent/launch.go +192 -0
  69. package/internal/agent/launch_test.go +206 -0
  70. package/internal/agent/launch_unix.go +15 -0
  71. package/internal/agent/launch_windows.go +24 -0
  72. package/internal/agent/limitnotice.go +103 -0
  73. package/internal/agent/limitnotice_test.go +211 -0
  74. package/internal/agent/llmengine.go +2 -2
  75. package/internal/agent/models.go +3 -2
  76. package/internal/agent/openclaw.go +4 -3
  77. package/internal/agent/openclaw_acp.go +7 -0
  78. package/internal/agent/openclaw_test.go +2 -2
  79. package/internal/agent/permission.go +100 -11
  80. package/internal/agent/permission_test.go +100 -36
  81. package/internal/agent/repair_models_test.go +194 -0
  82. package/internal/agent/runcmd.go +13 -3
  83. package/internal/agent/runner.go +7 -1
  84. package/internal/agent/runner_test.go +1 -1
  85. package/internal/agent/stream.go +777 -43
  86. package/internal/agent/stream_test.go +3 -2
  87. package/internal/agent/stream_timeline_test.go +905 -0
  88. package/internal/agent/streamjson.go +36 -2
  89. package/internal/agent/toolkind.go +20 -1
  90. package/internal/agent/toolkind_test.go +7 -1
  91. package/internal/agent/tools_suffix_test.go +10 -3
  92. package/internal/agent/trae.go +5 -3
  93. package/internal/agent/workspace_test.go +52 -0
  94. package/internal/cli/ask.go +282 -51
  95. package/internal/cli/ask_test.go +15 -11
  96. package/internal/cli/attach_test.go +32 -20
  97. package/internal/cli/clientcmd.go +156 -0
  98. package/internal/cli/events.go +53 -8
  99. package/internal/cli/events_test.go +230 -0
  100. package/internal/cli/keepalive_test.go +101 -6
  101. package/internal/cli/login.go +61 -4
  102. package/internal/cli/login_test.go +99 -0
  103. package/internal/cli/permission_test.go +5 -1
  104. package/internal/cli/repair.go +60 -0
  105. package/internal/cli/repair_test.go +51 -0
  106. package/internal/cli/root.go +195 -32
  107. package/internal/cli/session.go +183 -29
  108. package/internal/cli/session_test.go +144 -5
  109. package/internal/cli/sessionlog.go +385 -38
  110. package/internal/cli/sessionlog_test.go +708 -0
  111. package/internal/cli/sessionlog_user_test.go +142 -1
  112. package/internal/cli/sessiontitle.go +141 -0
  113. package/internal/client/browse.go +456 -0
  114. package/internal/client/browse_test.go +199 -0
  115. package/internal/client/cors_test.go +35 -0
  116. package/internal/client/daemon.go +525 -0
  117. package/internal/client/daemon_test.go +212 -0
  118. package/internal/client/detach_unix.go +19 -0
  119. package/internal/client/detach_windows.go +27 -0
  120. package/internal/client/pair.go +3 -3
  121. package/internal/client/plugins.go +376 -0
  122. package/internal/client/plugins_test.go +223 -0
  123. package/internal/client/proxy.go +374 -0
  124. package/internal/client/proxy_test.go +212 -0
  125. package/internal/client/service.go +1464 -48
  126. package/internal/client/service_test.go +649 -206
  127. package/internal/client/session_events_test.go +130 -0
  128. package/internal/client/wsproxy.go +113 -0
  129. package/internal/client/wsproxy_test.go +102 -0
  130. package/internal/session/delete.go +151 -0
  131. package/internal/session/delete_test.go +103 -0
  132. package/internal/session/session.go +155 -20
  133. package/internal/session/session_append.go +79 -21
  134. package/internal/session/session_test.go +124 -10
  135. package/internal/session/sessionlog.go +572 -6
  136. package/internal/session/sessionlog_read_test.go +410 -0
  137. package/internal/session/title.go +486 -0
  138. package/internal/session/title_test.go +298 -0
  139. package/npm/bin/magic-agent.js +78 -10
  140. package/npm/bin/magic-client.js +100 -0
  141. package/npm/dist/darwin-arm64/magic-agent +0 -0
  142. package/npm/dist/darwin-arm64/magic-client +0 -0
  143. package/npm/dist/darwin-x64/magic-agent +0 -0
  144. package/npm/dist/darwin-x64/magic-client +0 -0
  145. package/npm/dist/linux-arm64/magic-agent +0 -0
  146. package/npm/dist/linux-arm64/magic-client +0 -0
  147. package/npm/dist/linux-x64/magic-agent +0 -0
  148. package/npm/dist/linux-x64/magic-client +0 -0
  149. package/npm/dist/win32-x64/magic-agent.exe +0 -0
  150. package/npm/dist/win32-x64/magic-client.exe +0 -0
  151. package/npm/install.js +36 -13
  152. package/npm/lib/platform.js +27 -5
  153. package/package.json +8 -3
  154. package/client-ui/pc/js/03-chat-message.js +0 -880
  155. package/client-ui/pc/js/06-ask-answer.js +0 -204
  156. /package/client-ui/{pc/js → shared/conv}/08-ask-event-map.js +0 -0
  157. /package/client-ui/{pc → shared}/vendor/highlight.min.js +0 -0
  158. /package/client-ui/{pc → shared}/vendor/marked.min.js +0 -0
  159. /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
+ }