sap-ai-dev-toolkit 0.9.9921 → 0.9.9922
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/NOTICE +2 -1
- package/dist/checksums.txt +5 -5
- package/dist/vsp-darwin-arm64 +0 -0
- package/dist/vsp-darwin-x64 +0 -0
- package/dist/vsp-linux-arm64 +0 -0
- package/dist/vsp-linux-x64 +0 -0
- package/dist/vsp-win32-x64.exe +0 -0
- package/package.json +1 -1
- package/patches/vsp-namespaced-class-include-edit.patch +134 -0
- package/scripts/build-vsp.mjs +3 -1
package/NOTICE
CHANGED
|
@@ -2,7 +2,8 @@ Third-party notices for sap-ai-dev-toolkit
|
|
|
2
2
|
|
|
3
3
|
This package includes patched VSP (vibing-steampunk) binaries built from upstream commit
|
|
4
4
|
9886d2727f47506368b0a3c2f1c1766f1200f747. The BAS proxy-auth change is documented in
|
|
5
|
-
patches/vsp-bas-proxy-auth.patch
|
|
5
|
+
patches/vsp-bas-proxy-auth.patch; the namespaced class-include EditSource fix is documented in
|
|
6
|
+
patches/vsp-namespaced-class-include-edit.patch. The following upstream notice is reproduced from VSP:
|
|
6
7
|
|
|
7
8
|
vibing-steampunk (vsp)
|
|
8
9
|
Copyright (c) 2025-2026 Alice Vinogradova and contributors
|
package/dist/checksums.txt
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
31902921b0d2b5349be8e392aae3632ca8c3dee26950ea30c412ec83271722f3 vsp-linux-x64
|
|
2
|
+
df39b324fe419348f5157954d56c5f8d60e5bac28edc04a56e90c380b67de10d vsp-linux-arm64
|
|
3
|
+
754338fbbbe66260cac722677753b16a0a2f23127b947bf1f3a189044fa66c32 vsp-darwin-x64
|
|
4
|
+
ac153052b5d02b2f19a536623c957369af3412f5bbe2eed0f6a43e8597ed0f1b vsp-darwin-arm64
|
|
5
|
+
722c6de352719dd9374932b56546189a75c29800e74da3bdcb0308b2034248ac vsp-win32-x64.exe
|
package/dist/vsp-darwin-arm64
CHANGED
|
Binary file
|
package/dist/vsp-darwin-x64
CHANGED
|
Binary file
|
package/dist/vsp-linux-arm64
CHANGED
|
Binary file
|
package/dist/vsp-linux-x64
CHANGED
|
Binary file
|
package/dist/vsp-win32-x64.exe
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
diff --git a/pkg/adt/edit_namespaced_include_test.go b/pkg/adt/edit_namespaced_include_test.go
|
|
2
|
+
new file mode 100644
|
|
3
|
+
index 0000000..514ab35
|
|
4
|
+
--- /dev/null
|
|
5
|
+
+++ b/pkg/adt/edit_namespaced_include_test.go
|
|
6
|
+
@@ -0,0 +1,80 @@
|
|
7
|
+
+package adt
|
|
8
|
+
+
|
|
9
|
+
+import (
|
|
10
|
+
+ "context"
|
|
11
|
+
+ "io"
|
|
12
|
+
+ "net/http"
|
|
13
|
+
+ "net/http/httptest"
|
|
14
|
+
+ "strings"
|
|
15
|
+
+ "sync"
|
|
16
|
+
+ "testing"
|
|
17
|
+
+)
|
|
18
|
+
+
|
|
19
|
+
+// TestEditSource_NamespacedClassInclude guards against double-encoding the
|
|
20
|
+
+// class name of a namespaced class include: the object URL arrives with
|
|
21
|
+
+// "%2FABC%2F", and every request (read, lock, hash check, PUT, unlock,
|
|
22
|
+
+// activate) must keep exactly one encoding — never "%252F".
|
|
23
|
+
+func TestEditSource_NamespacedClassInclude(t *testing.T) {
|
|
24
|
+
+ const source = "CLASS lcl_x DEFINITION.\n \" old\nENDCLASS.\n"
|
|
25
|
+
+ const classPath = "/sap/bc/adt/oo/classes/%2FABC%2FCL_TEST"
|
|
26
|
+
+
|
|
27
|
+
+ for _, include := range []string{"definitions", "implementations", "testclasses"} {
|
|
28
|
+
+ for _, withHash := range []bool{false, true} {
|
|
29
|
+
+ name := include
|
|
30
|
+
+ if withHash {
|
|
31
|
+
+ name += "/hash"
|
|
32
|
+
+ }
|
|
33
|
+
+ t.Run(name, func(t *testing.T) {
|
|
34
|
+
+ includePath := classPath + "/includes/" + include
|
|
35
|
+
+ var mu sync.Mutex
|
|
36
|
+
+ var puts []string
|
|
37
|
+
+ current := source
|
|
38
|
+
+ srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
39
|
+
+ w.Header().Set("x-csrf-token", "TOKEN")
|
|
40
|
+
+ raw := r.URL.EscapedPath()
|
|
41
|
+
+ if strings.Contains(raw, "%25") {
|
|
42
|
+
+ t.Errorf("double-encoded request: %s %s", r.Method, r.RequestURI)
|
|
43
|
+
+ w.WriteHeader(http.StatusNotFound)
|
|
44
|
+
+ return
|
|
45
|
+
+ }
|
|
46
|
+
+ switch {
|
|
47
|
+
+ case r.URL.Query().Get("_action") == "LOCK":
|
|
48
|
+
+ w.Header().Set("Content-Type", "application/xml")
|
|
49
|
+
+ _, _ = w.Write([]byte(`<?xml version="1.0"?><asx:abap xmlns:asx="http://www.sap.com/abapxml">
|
|
50
|
+
+ <asx:values><DATA><LOCK_HANDLE>HANDLE-1</LOCK_HANDLE>
|
|
51
|
+
+ <MODIFICATION_SUPPORT>Modification</MODIFICATION_SUPPORT></DATA></asx:values></asx:abap>`))
|
|
52
|
+
+ case r.Method == http.MethodGet && raw == includePath:
|
|
53
|
+
+ mu.Lock()
|
|
54
|
+
+ _, _ = w.Write([]byte(current))
|
|
55
|
+
+ mu.Unlock()
|
|
56
|
+
+ case r.Method == http.MethodPut:
|
|
57
|
+
+ mu.Lock()
|
|
58
|
+
+ puts = append(puts, raw)
|
|
59
|
+
+ body, _ := io.ReadAll(r.Body)
|
|
60
|
+
+ current = string(body)
|
|
61
|
+
+ mu.Unlock()
|
|
62
|
+
+ default:
|
|
63
|
+
+ w.WriteHeader(http.StatusOK)
|
|
64
|
+
+ }
|
|
65
|
+
+ }))
|
|
66
|
+
+ defer srv.Close()
|
|
67
|
+
+
|
|
68
|
+
+ opts := &EditSourceOptions{}
|
|
69
|
+
+ if withHash {
|
|
70
|
+
+ opts.ExpectedSourceHash = SourceHash(source)
|
|
71
|
+
+ }
|
|
72
|
+
+ c := NewClient(srv.URL, "TESTUSER", "pw")
|
|
73
|
+
+ res, err := c.EditSourceWithOptions(context.Background(), includePath, "\" old", "\" new", opts)
|
|
74
|
+
+ if err != nil {
|
|
75
|
+
+ t.Fatalf("EditSourceWithOptions: %v", err)
|
|
76
|
+
+ }
|
|
77
|
+
+ if !res.Success {
|
|
78
|
+
+ t.Fatalf("edit failed: %s", res.Message)
|
|
79
|
+
+ }
|
|
80
|
+
+ if len(puts) != 1 || puts[0] != includePath {
|
|
81
|
+
+ t.Fatalf("PUT paths = %v, want [%s]", puts, includePath)
|
|
82
|
+
+ }
|
|
83
|
+
+ })
|
|
84
|
+
+ }
|
|
85
|
+
+ }
|
|
86
|
+
+}
|
|
87
|
+
diff --git a/pkg/adt/workflows_edit.go b/pkg/adt/workflows_edit.go
|
|
88
|
+
index 6da5df7..01c02e0 100644
|
|
89
|
+
--- a/pkg/adt/workflows_edit.go
|
|
90
|
+
+++ b/pkg/adt/workflows_edit.go
|
|
91
|
+
@@ -3,6 +3,7 @@ package adt
|
|
92
|
+
import (
|
|
93
|
+
"context"
|
|
94
|
+
"fmt"
|
|
95
|
+
+ "net/url"
|
|
96
|
+
"strings"
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
@@ -204,9 +205,9 @@ func (c *Client) EditSourceWithOptions(ctx context.Context, objectURL, oldString
|
|
100
|
+
if idx := strings.Index(objectURL, classesPrefix); idx >= 0 {
|
|
101
|
+
rest := objectURL[idx+len(classesPrefix):]
|
|
102
|
+
if slashIdx := strings.Index(rest, "/"); slashIdx > 0 {
|
|
103
|
+
- classNameForMethod = rest[:slashIdx]
|
|
104
|
+
+ classNameForMethod = decodeClassNameSegment(rest[:slashIdx])
|
|
105
|
+
} else {
|
|
106
|
+
- classNameForMethod = rest
|
|
107
|
+
+ classNameForMethod = decodeClassNameSegment(rest)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
result.Method = opts.Method
|
|
111
|
+
@@ -227,7 +228,7 @@ func (c *Client) EditSourceWithOptions(ctx context.Context, objectURL, oldString
|
|
112
|
+
classesPrefix := "/sap/bc/adt/oo/classes/"
|
|
113
|
+
if strings.Contains(objectURL, classesPrefix) {
|
|
114
|
+
classStart := strings.Index(objectURL, classesPrefix) + len(classesPrefix)
|
|
115
|
+
- className = objectURL[classStart:includesIdx]
|
|
116
|
+
+ className = decodeClassNameSegment(objectURL[classStart:includesIdx])
|
|
117
|
+
includeType = ClassIncludeType(objectURL[includesIdx+len("/includes/"):])
|
|
118
|
+
parentClassURL = objectURL[:includesIdx]
|
|
119
|
+
}
|
|
120
|
+
@@ -488,3 +489,14 @@ func (c *Client) EditSourceWithOptions(ctx context.Context, objectURL, oldString
|
|
121
|
+
}
|
|
122
|
+
return result, nil
|
|
123
|
+
}
|
|
124
|
+
+
|
|
125
|
+
+// decodeClassNameSegment turns the class-name path segment of an object URL
|
|
126
|
+
+// ("%2FABC%2FCL_TEST") into the raw name ("/ABC/CL_TEST"). Downstream helpers
|
|
127
|
+
+// (GetClassIncludeSourceURL, GetClassMethods, activation) escape the name
|
|
128
|
+
+// themselves, so passing the still-encoded segment would yield "%252F".
|
|
129
|
+
+func decodeClassNameSegment(segment string) string {
|
|
130
|
+
+ if decoded, err := url.PathUnescape(segment); err == nil {
|
|
131
|
+
+ return decoded
|
|
132
|
+
+ }
|
|
133
|
+
+ return segment
|
|
134
|
+
+}
|
package/scripts/build-vsp.mjs
CHANGED
|
@@ -33,7 +33,9 @@ async function main() {
|
|
|
33
33
|
await mkdir(dirname(source), { recursive: true });
|
|
34
34
|
await run('git', ['clone', '--filter=blob:none', upstream, source]);
|
|
35
35
|
await run('git', ['-C', source, 'checkout', '--detach', commit]);
|
|
36
|
-
|
|
36
|
+
for (const patchFile of ['vsp-bas-proxy-auth.patch', 'vsp-namespaced-class-include-edit.patch']) {
|
|
37
|
+
await run('patch', ['-p1', '-i', join(root, 'patches', patchFile)], { cwd: source });
|
|
38
|
+
}
|
|
37
39
|
await mkdir(dist, { recursive: true });
|
|
38
40
|
const checksums = [];
|
|
39
41
|
for (const [goos, goarch, os, arch, extension] of targets) {
|