@pippit-dev/cli 1.0.17 → 1.0.20

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 (50) hide show
  1. package/README.md +41 -2
  2. package/checksums.txt +6 -6
  3. package/cmd/auth/auth.go +136 -142
  4. package/cmd/auth/auth_test.go +134 -0
  5. package/cmd/canvas/canvas.go +241 -0
  6. package/cmd/canvas/canvas_test.go +182 -0
  7. package/cmd/get_credit_balance.go +37 -0
  8. package/cmd/get_credit_balance_test.go +73 -0
  9. package/cmd/root.go +31 -5
  10. package/cmd/root_test.go +69 -0
  11. package/cmd/short_drama_test.go +5 -7
  12. package/cmd/update/update.go +34 -5
  13. package/cmd/update/update_test.go +84 -0
  14. package/dist/checksums.txt +6 -0
  15. package/dist/xyq-canvas-command-runtime.cjs +16 -0
  16. package/dist/xyq-canvas-command-runtime.cjs.LEGAL.txt +599 -0
  17. package/dist/xyq-canvas-command-runtime.cjs.sha256 +2 -0
  18. package/internal/auth/auth_test.go +813 -0
  19. package/internal/auth/browser_darwin.go +14 -0
  20. package/internal/auth/browser_env.go +35 -0
  21. package/internal/auth/browser_linux.go +14 -0
  22. package/internal/auth/browser_windows.go +14 -0
  23. package/internal/auth/identity.go +89 -0
  24. package/internal/auth/loopback.go +324 -0
  25. package/internal/auth/manager.go +338 -144
  26. package/internal/auth/store.go +303 -0
  27. package/internal/auth/store_file_unix.go +176 -0
  28. package/internal/auth/store_file_windows.go +11 -0
  29. package/internal/auth/types.go +72 -0
  30. package/internal/canvas/allocate.go +70 -0
  31. package/internal/canvas/apply.go +279 -0
  32. package/internal/canvas/canvas_test.go +559 -0
  33. package/internal/canvas/create.go +380 -0
  34. package/internal/canvas/get.go +156 -0
  35. package/internal/canvas/types.go +68 -0
  36. package/internal/canvas/upload.go +250 -0
  37. package/internal/common/access_key.go +42 -6
  38. package/internal/common/access_key_test.go +113 -0
  39. package/internal/common/client.go +119 -21
  40. package/internal/common/client_test.go +213 -0
  41. package/internal/common/get_credit_balance.go +61 -0
  42. package/internal/common/get_credit_balance_test.go +75 -0
  43. package/internal/common/runner.go +15 -0
  44. package/internal/config/config.go +11 -28
  45. package/internal/config/config_test.go +3 -18
  46. package/package.json +9 -2
  47. package/scripts/canvas-command.js +881 -0
  48. package/scripts/run.js +21 -4
  49. package/skills/short-drama/SKILL.md +4 -4
  50. package/skills/xyq-nest-skill/SKILL.md +11 -1
@@ -0,0 +1,213 @@
1
+ package common
2
+
3
+ import (
4
+ "context"
5
+ "net/http"
6
+ "net/http/httptest"
7
+ "net/url"
8
+ "os"
9
+ "path/filepath"
10
+ "strings"
11
+ "sync/atomic"
12
+ "testing"
13
+ "time"
14
+ )
15
+
16
+ type observedHeaders struct {
17
+ authorization string
18
+ }
19
+
20
+ func TestHTTPClientScopesCredentialsToBaseOrigin(t *testing.T) {
21
+ apiHeaders := make(chan observedHeaders, 1)
22
+ api := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
23
+ apiHeaders <- captureRoutingHeaders(r)
24
+ _, _ = w.Write([]byte(`{}`))
25
+ }))
26
+ defer api.Close()
27
+
28
+ thirdPartyHeaders := make(chan observedHeaders, 1)
29
+ thirdParty := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
30
+ thirdPartyHeaders <- captureRoutingHeaders(r)
31
+ _, _ = w.Write([]byte(`{}`))
32
+ }))
33
+ defer thirdParty.Close()
34
+
35
+ client := NewHTTPClient(
36
+ api.URL,
37
+ time.Second,
38
+ NewAccessKeyAuthorizer("secret-ak"),
39
+ )
40
+ if err := client.SendRequest(context.Background(), "/api/test", nil, nil); err != nil {
41
+ t.Fatalf("same-origin SendRequest() error = %v", err)
42
+ }
43
+ gotAPI := <-apiHeaders
44
+ if gotAPI.authorization != "Bearer secret-ak" {
45
+ t.Fatalf("same-origin Authorization = %q", gotAPI.authorization)
46
+ }
47
+
48
+ thirdPartyURL := thirdParty.URL + "/asset.mp4"
49
+ err := client.SendRequestWithHeaders(context.Background(), thirdPartyURL, nil, map[string]string{
50
+ "Authorization": "Bearer caller-supplied",
51
+ }, nil)
52
+ if err != nil {
53
+ t.Fatalf("third-party SendRequest() error = %v", err)
54
+ }
55
+ gotThirdParty := <-thirdPartyHeaders
56
+ if gotThirdParty != (observedHeaders{}) {
57
+ t.Fatalf("third-party sensitive headers leaked: %#v", gotThirdParty)
58
+ }
59
+ }
60
+
61
+ func TestHTTPClientTreatsSameOriginAbsoluteURLAsAPI(t *testing.T) {
62
+ headers := make(chan observedHeaders, 1)
63
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
64
+ headers <- captureRoutingHeaders(r)
65
+ _, _ = w.Write([]byte(`{}`))
66
+ }))
67
+ defer server.Close()
68
+
69
+ client := NewHTTPClient(
70
+ server.URL+"/base-path",
71
+ time.Second,
72
+ NewAccessKeyAuthorizer("same-origin-ak"),
73
+ )
74
+ if err := client.SendRequest(context.Background(), server.URL+"/api/absolute", nil, nil); err != nil {
75
+ t.Fatalf("SendRequest() error = %v", err)
76
+ }
77
+ got := <-headers
78
+ if got.authorization != "Bearer same-origin-ak" {
79
+ t.Fatalf("same-origin absolute headers = %#v", got)
80
+ }
81
+ }
82
+
83
+ func TestHTTPClientRejectsAPICrossOriginRedirectBeforeSendingBody(t *testing.T) {
84
+ var thirdPartyRequests atomic.Int32
85
+ thirdParty := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
86
+ thirdPartyRequests.Add(1)
87
+ _, _ = w.Write([]byte(`{}`))
88
+ }))
89
+ defer thirdParty.Close()
90
+
91
+ api := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
92
+ http.Redirect(w, r, thirdParty.URL+"/redirected-asset", http.StatusTemporaryRedirect)
93
+ }))
94
+ defer api.Close()
95
+
96
+ client := NewHTTPClient(
97
+ api.URL,
98
+ time.Second,
99
+ NewAccessKeyAuthorizer("redirect-ak"),
100
+ )
101
+ err := client.SendRequest(context.Background(), "/api/redirect", map[string]string{"canvas": "private"}, nil)
102
+ if err == nil || !strings.Contains(err.Error(), "拒绝 Pippit API 跨域重定向") {
103
+ t.Fatalf("SendRequest() error = %v, want cross-origin redirect rejection", err)
104
+ }
105
+ if got := thirdPartyRequests.Load(); got != 0 {
106
+ t.Fatalf("third party received %d API redirect requests, want 0", got)
107
+ }
108
+ }
109
+
110
+ func TestHTTPClientDoesNotRestoreAuthorizationAfterCrossOriginRedirect(t *testing.T) {
111
+ finalHeaders := make(chan observedHeaders, 1)
112
+ var apiURL string
113
+ thirdParty := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
114
+ if got := captureRoutingHeaders(r); got != (observedHeaders{}) {
115
+ t.Errorf("cross-origin hop leaked protected headers: %#v", got)
116
+ }
117
+ http.Redirect(w, r, apiURL+"/final", http.StatusFound)
118
+ }))
119
+ defer thirdParty.Close()
120
+
121
+ api := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
122
+ finalHeaders <- captureRoutingHeaders(r)
123
+ _, _ = w.Write([]byte(`{}`))
124
+ }))
125
+ defer api.Close()
126
+ apiURL = api.URL
127
+
128
+ client := NewHTTPClient(
129
+ api.URL,
130
+ time.Second,
131
+ NewAccessKeyAuthorizer("redirect-bounce-ak"),
132
+ )
133
+ if err := client.SendRequest(context.Background(), thirdParty.URL+"/bounce", nil, nil); err != nil {
134
+ t.Fatalf("SendRequest() error = %v", err)
135
+ }
136
+ if got := <-finalHeaders; got != (observedHeaders{}) {
137
+ t.Fatalf("trusted return hop restored protected headers: %#v", got)
138
+ }
139
+ }
140
+
141
+ func TestHTTPClientPreventsCallerAuthorizationOverride(t *testing.T) {
142
+ headers := make(chan observedHeaders, 1)
143
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
144
+ headers <- captureRoutingHeaders(r)
145
+ _, _ = w.Write([]byte(`{}`))
146
+ }))
147
+ defer server.Close()
148
+
149
+ client := NewHTTPClient(
150
+ server.URL,
151
+ time.Second,
152
+ NewAccessKeyAuthorizer("production-ak"),
153
+ )
154
+ err := client.SendRequestWithHeaders(context.Background(), "/api/test", nil, map[string]string{
155
+ "Authorization": "Bearer caller-override",
156
+ }, nil)
157
+ if err != nil {
158
+ t.Fatalf("SendRequest() error = %v", err)
159
+ }
160
+ got := <-headers
161
+ if got.authorization != "Bearer production-ak" {
162
+ t.Fatalf("protected headers = %#v", got)
163
+ }
164
+ }
165
+
166
+ func TestHTTPClientMultipartRequestInjectsOnlyAuthorization(t *testing.T) {
167
+ headers := make(chan observedHeaders, 1)
168
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
169
+ headers <- captureRoutingHeaders(r)
170
+ _, _ = w.Write([]byte(`{}`))
171
+ }))
172
+ defer server.Close()
173
+
174
+ filePath := filepath.Join(t.TempDir(), "sample.txt")
175
+ if err := os.WriteFile(filePath, []byte("sample"), 0o600); err != nil {
176
+ t.Fatal(err)
177
+ }
178
+ client := NewHTTPClient(
179
+ server.URL,
180
+ time.Second,
181
+ NewAccessKeyAuthorizer("upload-ak"),
182
+ )
183
+ err := client.SendMultipartRequest(context.Background(), "/api/upload", nil, MultipartFile{
184
+ FieldName: "file",
185
+ Path: filePath,
186
+ }, nil)
187
+ if err != nil {
188
+ t.Fatalf("SendMultipartRequest() error = %v", err)
189
+ }
190
+ got := <-headers
191
+ if got.authorization != "Bearer upload-ak" {
192
+ t.Fatalf("multipart headers = %#v", got)
193
+ }
194
+ }
195
+
196
+ func TestSameOriginUsesEffectiveDefaultPorts(t *testing.T) {
197
+ httpsDefault, _ := url.Parse("https://xyq.jianying.com/api")
198
+ httpsExplicit, _ := url.Parse("https://XYQ.JIANYING.COM:443/asset")
199
+ if !sameOrigin(httpsDefault, httpsExplicit) {
200
+ t.Fatal("sameOrigin() = false for equivalent HTTPS origins")
201
+ }
202
+
203
+ differentPort, _ := url.Parse("https://xyq.jianying.com:8443/api")
204
+ if sameOrigin(httpsDefault, differentPort) {
205
+ t.Fatal("sameOrigin() = true for different ports")
206
+ }
207
+ }
208
+
209
+ func captureRoutingHeaders(r *http.Request) observedHeaders {
210
+ return observedHeaders{
211
+ authorization: r.Header.Get("Authorization"),
212
+ }
213
+ }
@@ -0,0 +1,61 @@
1
+ package common
2
+
3
+ import (
4
+ "context"
5
+ "fmt"
6
+
7
+ "github.com/Pippit-dev/pippit-cli/internal/config"
8
+ )
9
+
10
+ // GetCreditBalanceResult is the JSON output printed by `pippit-tool-cli get-credit-balance`.
11
+ type GetCreditBalanceResult struct {
12
+ TotalRemainAmount int64 `json:"total_remain_amount,string"`
13
+ LogID string `json:"-"`
14
+ }
15
+
16
+ type getCreditBalanceResponse struct {
17
+ Ret string `json:"ret"`
18
+ Errmsg string `json:"errmsg"`
19
+ LogID string `json:"log_id"`
20
+ Data *getCreditBalanceResponseData `json:"data"`
21
+ }
22
+
23
+ type getCreditBalanceResponseData struct {
24
+ TotalRemainAmount *int64 `json:"total_remain_amount,string"`
25
+ }
26
+
27
+ // GetCreditBalance queries the effective credit balance of the access-key owner.
28
+ func GetCreditBalance(ctx context.Context, runner *Runner) (*GetCreditBalanceResult, error) {
29
+ if runner == nil || runner.Client == nil {
30
+ return nil, fmt.Errorf("get_credit_balance 运行器客户端缺失")
31
+ }
32
+
33
+ var resp getCreditBalanceResponse
34
+ if err := runner.Client.SendRequest(ctx, getCreditBalancePath(runner), struct{}{}, &resp); err != nil {
35
+ return nil, fmt.Errorf("获取积分余额请求失败: %w", err)
36
+ }
37
+ if resp.Ret != "0" {
38
+ if resp.Errmsg == "" {
39
+ resp.Errmsg = "未知错误"
40
+ }
41
+ return nil, NewLogIDError(fmt.Sprintf("获取积分余额请求返回失败: ret=%s errmsg=%s", resp.Ret, resp.Errmsg), resp.LogID)
42
+ }
43
+ if resp.Data == nil {
44
+ return nil, NewLogIDError("get_credit_balance 响应缺少 data", resp.LogID)
45
+ }
46
+ if resp.Data.TotalRemainAmount == nil {
47
+ return nil, NewLogIDError("get_credit_balance 响应缺少 data.total_remain_amount", resp.LogID)
48
+ }
49
+
50
+ return &GetCreditBalanceResult{
51
+ TotalRemainAmount: *resp.Data.TotalRemainAmount,
52
+ LogID: resp.LogID,
53
+ }, nil
54
+ }
55
+
56
+ func getCreditBalancePath(runner *Runner) string {
57
+ if runner != nil && runner.Config != nil && runner.Config.Paths != nil && runner.Config.Paths.GetCreditBalance != "" {
58
+ return runner.Config.Paths.GetCreditBalance
59
+ }
60
+ return config.GetCreditBalancePath
61
+ }
@@ -0,0 +1,75 @@
1
+ package common
2
+
3
+ import (
4
+ "context"
5
+ "fmt"
6
+ "strings"
7
+ "testing"
8
+
9
+ "github.com/bytedance/sonic"
10
+ )
11
+
12
+ type creditBalanceFakeClient struct {
13
+ response string
14
+ path string
15
+ body any
16
+ }
17
+
18
+ func (c *creditBalanceFakeClient) SendRequest(_ context.Context, path string, body any, out any) error {
19
+ c.path = path
20
+ c.body = body
21
+ return sonic.Unmarshal([]byte(c.response), out)
22
+ }
23
+
24
+ func (c *creditBalanceFakeClient) SendRequestWithHeaders(ctx context.Context, path string, body any, _ map[string]string, out any) error {
25
+ return c.SendRequest(ctx, path, body, out)
26
+ }
27
+
28
+ func (c *creditBalanceFakeClient) SendMultipartRequest(context.Context, string, map[string]string, MultipartFile, any) error {
29
+ return fmt.Errorf("unexpected multipart request")
30
+ }
31
+
32
+ func TestGetCreditBalanceReturnsAmount(t *testing.T) {
33
+ client := &creditBalanceFakeClient{
34
+ response: `{"ret":"0","log_id":"log_balance","data":{"total_remain_amount":"4321"}}`,
35
+ }
36
+
37
+ result, err := GetCreditBalance(context.Background(), &Runner{Client: client})
38
+ if err != nil {
39
+ t.Fatalf("GetCreditBalance() error = %v", err)
40
+ }
41
+ if result.TotalRemainAmount != 4321 {
42
+ t.Fatalf("TotalRemainAmount = %d, want 4321", result.TotalRemainAmount)
43
+ }
44
+ if result.LogID != "log_balance" {
45
+ t.Fatalf("LogID = %q, want log_balance", result.LogID)
46
+ }
47
+ if client.path != "/api/biz/v1/skill/get_credit_balance" {
48
+ t.Fatalf("path = %q, want get_credit_balance path", client.path)
49
+ }
50
+ if _, ok := client.body.(struct{}); !ok {
51
+ t.Fatalf("body = %#v, want an empty POST body", client.body)
52
+ }
53
+ }
54
+
55
+ func TestGetCreditBalanceRequiresOptionalAmount(t *testing.T) {
56
+ client := &creditBalanceFakeClient{
57
+ response: `{"ret":"0","log_id":"log_missing","data":{}}`,
58
+ }
59
+
60
+ _, err := GetCreditBalance(context.Background(), &Runner{Client: client})
61
+ if err == nil || !strings.Contains(err.Error(), "data.total_remain_amount") || !strings.Contains(err.Error(), "log_id=log_missing") {
62
+ t.Fatalf("GetCreditBalance() error = %v, want missing amount and log_id", err)
63
+ }
64
+ }
65
+
66
+ func TestGetCreditBalanceBusinessErrorIncludesLogID(t *testing.T) {
67
+ client := &creditBalanceFakeClient{
68
+ response: `{"ret":"16008","errmsg":"查询失败","log_id":"log_123"}`,
69
+ }
70
+
71
+ _, err := GetCreditBalance(context.Background(), &Runner{Client: client})
72
+ if err == nil || !strings.Contains(err.Error(), "ret=16008 errmsg=查询失败") || !strings.Contains(err.Error(), "log_id=log_123") {
73
+ t.Fatalf("GetCreditBalance() error = %v, want business error and log_id", err)
74
+ }
75
+ }
@@ -1,13 +1,28 @@
1
1
  package common
2
2
 
3
3
  import (
4
+ "context"
5
+
6
+ "github.com/Pippit-dev/pippit-cli/internal/auth"
4
7
  "github.com/Pippit-dev/pippit-cli/internal/config"
5
8
  )
6
9
 
10
+ // AuthManager is the credential boundary shared by native CLI commands. It
11
+ // resolves explicit CI credentials first and browser-managed credentials
12
+ // second, without exposing either value to command output.
13
+ type AuthManager interface {
14
+ ResolveAccessKey(context.Context) (string, error)
15
+ Login(context.Context, auth.LoginOptions) (*auth.Credential, error)
16
+ Status(context.Context) (*auth.Status, error)
17
+ Logout(context.Context, bool) error
18
+ CredentialScope(context.Context) (string, error)
19
+ }
20
+
7
21
  // Runner carries runtime dependencies for command execution.
8
22
  type Runner struct {
9
23
  Config *config.Config
10
24
  Client Client
25
+ Auth AuthManager
11
26
  }
12
27
 
13
28
  func NewRunner(cfg *config.Config, client Client) *Runner {
@@ -10,10 +10,9 @@ const (
10
10
  DefaultBaseURL = "https://xyq.jianying.com"
11
11
  DefaultHTTPTimeout = 30 * time.Minute
12
12
  DefaultAuthTTL = 30 * time.Second
13
- DefaultOAuthClientKey = "mock-cli"
14
- DefaultOAuthBaseURL = "https://passport.bytedance.com"
15
13
  DefaultAuthStoreServiceName = "pippit-cli"
16
14
  SubmitRunPath = "/api/biz/v1/skill/submit_run"
15
+ GetCreditBalancePath = "/api/biz/v1/skill/get_credit_balance"
17
16
  GetThreadPath = "/api/biz/v1/skill/get_thread"
18
17
  UploadFilePath = "/api/biz/v1/skill/upload_file"
19
18
  ListThreadFilePath = "/api/biz/v1/skill/list_thread_file"
@@ -27,22 +26,15 @@ type Config struct {
27
26
  HTTPTimeout time.Duration
28
27
  AuthTTL time.Duration
29
28
  AccessKey string
30
- OAuth *OAuth
31
29
  Paths *Paths
32
30
  }
33
31
 
34
- type OAuth struct {
35
- ClientKey string
36
- BaseURL string
37
- StoreServiceName string
38
- Scopes []string
39
- }
40
-
41
32
  type Paths struct {
42
- SubmitRun string
43
- GetThread string
44
- UploadFile string
45
- ListThreadFile string
33
+ SubmitRun string
34
+ GetCreditBalance string
35
+ GetThread string
36
+ UploadFile string
37
+ ListThreadFile string
46
38
  }
47
39
 
48
40
  // Load resolves the built-in runtime config.
@@ -52,21 +44,12 @@ func Load() *Config {
52
44
  HTTPTimeout: DefaultHTTPTimeout,
53
45
  AuthTTL: DefaultAuthTTL,
54
46
  AccessKey: strings.TrimSpace(os.Getenv(EnvXYQAccessKey)),
55
- OAuth: resolveOAuth(),
56
47
  Paths: &Paths{
57
- SubmitRun: SubmitRunPath,
58
- GetThread: GetThreadPath,
59
- UploadFile: UploadFilePath,
60
- ListThreadFile: ListThreadFilePath,
48
+ SubmitRun: SubmitRunPath,
49
+ GetCreditBalance: GetCreditBalancePath,
50
+ GetThread: GetThreadPath,
51
+ UploadFile: UploadFilePath,
52
+ ListThreadFile: ListThreadFilePath,
61
53
  },
62
54
  }
63
55
  }
64
-
65
- func resolveOAuth() *OAuth {
66
- return &OAuth{
67
- ClientKey: DefaultOAuthClientKey,
68
- BaseURL: DefaultOAuthBaseURL,
69
- StoreServiceName: DefaultAuthStoreServiceName,
70
- Scopes: []string{"user_info", "aigc_generate"},
71
- }
72
- }
@@ -17,27 +17,12 @@ func TestLoadUsesDefaultConfig(t *testing.T) {
17
17
  if cfg.AccessKey != "" {
18
18
  t.Fatalf("AccessKey = %q, want empty", cfg.AccessKey)
19
19
  }
20
- if cfg.OAuth.ClientKey != DefaultOAuthClientKey {
21
- t.Fatalf("OAuth.ClientKey = %q, want %q", cfg.OAuth.ClientKey, DefaultOAuthClientKey)
22
- }
23
- if cfg.OAuth.StoreServiceName != DefaultAuthStoreServiceName {
24
- t.Fatalf("OAuth.StoreServiceName = %q, want %q", cfg.OAuth.StoreServiceName, DefaultAuthStoreServiceName)
25
- }
26
- if cfg.OAuth.BaseURL != DefaultOAuthBaseURL {
27
- t.Fatalf("OAuth.BaseURL = %q, want %q", cfg.OAuth.BaseURL, DefaultOAuthBaseURL)
28
- }
29
- wantScopes := []string{"user_info", "aigc_generate"}
30
- if len(cfg.OAuth.Scopes) != len(wantScopes) {
31
- t.Fatalf("OAuth.Scopes = %#v, want %#v", cfg.OAuth.Scopes, wantScopes)
32
- }
33
- for i := range wantScopes {
34
- if cfg.OAuth.Scopes[i] != wantScopes[i] {
35
- t.Fatalf("OAuth.Scopes = %#v, want %#v", cfg.OAuth.Scopes, wantScopes)
36
- }
37
- }
38
20
  if cfg.Paths.SubmitRun != SubmitRunPath {
39
21
  t.Fatalf("SubmitRun path = %q, want %q", cfg.Paths.SubmitRun, SubmitRunPath)
40
22
  }
23
+ if cfg.Paths.GetCreditBalance != GetCreditBalancePath {
24
+ t.Fatalf("GetCreditBalance path = %q, want %q", cfg.Paths.GetCreditBalance, GetCreditBalancePath)
25
+ }
41
26
  }
42
27
 
43
28
  func TestLoadReadsAccessKey(t *testing.T) {
package/package.json CHANGED
@@ -1,13 +1,16 @@
1
1
  {
2
2
  "name": "@pippit-dev/cli",
3
- "version": "1.0.17",
3
+ "version": "1.0.20",
4
4
  "description": "Pippit CLI",
5
5
  "bin": {
6
6
  "pippit-tool-cli": "scripts/run.js"
7
7
  },
8
8
  "scripts": {
9
9
  "postinstall": "node scripts/install.js",
10
- "test": "node scripts/version-check.test.js && node scripts/skills.test.js && node scripts/install-wizard.test.js && go test ./... && go vet ./..."
10
+ "prepack": "node scripts/prepare-canvas-runtime.js",
11
+ "prepare:canvas-runtime": "node scripts/prepare-canvas-runtime.js",
12
+ "test": "node scripts/version-check.test.js && node scripts/skills.test.js && node scripts/install-wizard.test.js && node scripts/canvas-command.test.js && node scripts/prepare-canvas-runtime.test.js && go test ./... && go vet ./...",
13
+ "verify:canvas-runtime": "node scripts/prepare-canvas-runtime.js --check-only"
11
14
  },
12
15
  "os": [
13
16
  "darwin",
@@ -32,11 +35,15 @@
32
35
  "skills",
33
36
  "scripts/install.js",
34
37
  "scripts/install-wizard.js",
38
+ "scripts/canvas-command.js",
35
39
  "scripts/platform.js",
36
40
  "scripts/run.js",
37
41
  "scripts/skills.js",
38
42
  "scripts/telemetry.js",
39
43
  "scripts/version-check.js",
44
+ "dist/xyq-canvas-command-runtime.cjs",
45
+ "dist/xyq-canvas-command-runtime.cjs.LEGAL.txt",
46
+ "dist/xyq-canvas-command-runtime.cjs.sha256",
40
47
  "checksums.txt",
41
48
  "README.md",
42
49
  "LICENSE"