@pippit-dev/cli 0.0.26 → 0.0.27

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/checksums.txt CHANGED
@@ -1,6 +1,6 @@
1
- 852db25f92e31d7791332a67d9fe321e09471ac59a4051a86cd10d120df5504b pippit-tool-cli-0.0.26-darwin-amd64.tar.gz
2
- d6b01e0b0784bc951785a9120adf5b81aeb8fd9e9591a9f5e361d59ad521043d pippit-tool-cli-0.0.26-darwin-arm64.tar.gz
3
- 8cab08ec5fa9fb5c2c933ef986313134b98bfd118c9d5997b6b328d63017143f pippit-tool-cli-0.0.26-linux-amd64.tar.gz
4
- 81f2783696ddfd374507d21d10a2854f8ac3fbb2df32bcb78559f0b9153b41f3 pippit-tool-cli-0.0.26-linux-arm64.tar.gz
5
- b089a0a1f27cc7e27e7905ad32863a90e8f401b914a9133e49476142e51e5824 pippit-tool-cli-0.0.26-windows-amd64.zip
6
- 41df908598017d53b857b475c080793f81956c9706c6d990d875d48432b27395 pippit-tool-cli-0.0.26-windows-arm64.zip
1
+ 3e95e8bbd667579fa1feddd4c58e583d70003f0f179d7249135b883a612165e5 pippit-tool-cli-0.0.27-darwin-amd64.tar.gz
2
+ 15671a5880feff8a67bd0c8042ab7e2a77d1ea7c81ed6625427bdd472d925c6a pippit-tool-cli-0.0.27-darwin-arm64.tar.gz
3
+ aef2fc4896d2c8966f681a82e5bd624b9ec9f0382e23dd05776f014cbb65473d pippit-tool-cli-0.0.27-linux-amd64.tar.gz
4
+ 5b01a760298c22a6fd42661f212f9f1d1e822e84d1feb87307c36590f795515a pippit-tool-cli-0.0.27-linux-arm64.tar.gz
5
+ 18315d247bb409f594d11e64cb2292ffbf48504d73290011f5c5a2ba319f93df pippit-tool-cli-0.0.27-windows-amd64.zip
6
+ 31284208bc244d9d48066c8e7086bf40e167209fff106ea6462c9638cbd6efef pippit-tool-cli-0.0.27-windows-arm64.zip
@@ -1,24 +1,42 @@
1
1
  package updatecmd
2
2
 
3
3
  import (
4
+ "bytes"
5
+ "encoding/json"
4
6
  "fmt"
5
7
  "io"
8
+ "net/http"
6
9
  "os"
7
10
  "os/exec"
8
11
  "path/filepath"
9
12
  "runtime"
10
13
  "strings"
14
+ "time"
11
15
 
16
+ "github.com/Pippit-dev/pippit-cli/internal/version"
12
17
  "github.com/spf13/cobra"
13
18
  )
14
19
 
15
20
  const defaultPackage = "@pippit-dev/cli"
16
21
 
22
+ const (
23
+ defaultTelemetryBaseURL = "https://xyq.jianying.com"
24
+ telemetryPath = "/api/biz/v1/skill/report_telemetry"
25
+ telemetryAuthHeader = "Bearer pippit-cli-skill-telemetry"
26
+ )
27
+
17
28
  var legacyGlobalSkills = []string{
18
29
  "pippit-short-drama-skill",
19
30
  "xyq-nest-skill",
20
31
  }
21
32
 
33
+ var telemetrySkillNames = []string{
34
+ "xyq-skill",
35
+ "xyq-short-drama-skill",
36
+ }
37
+
38
+ var telemetryHTTPClient = &http.Client{Timeout: 2 * time.Second}
39
+
22
40
  // NewCommand builds the update command.
23
41
  func NewCommand(stdout, stderr io.Writer) *cobra.Command {
24
42
  cmd := &cobra.Command{
@@ -57,6 +75,7 @@ func runUpdate(stdout, stderr io.Writer) error {
57
75
  return fmt.Errorf("update pippit-tool-cli skills: %w", err)
58
76
  }
59
77
 
78
+ reportBundledSkillTelemetry("update", "cli_update", stderr)
60
79
  fmt.Fprintln(stdout, "pippit-tool-cli and skills updated")
61
80
  return nil
62
81
  }
@@ -105,6 +124,83 @@ func cleanupLegacyGlobalSkills(globalSkillsDir string) error {
105
124
  return nil
106
125
  }
107
126
 
127
+ type telemetryPayload struct {
128
+ Event string `json:"event"`
129
+ SkillName string `json:"skill_name"`
130
+ Source string `json:"source"`
131
+ CliVersion string `json:"cli_version"`
132
+ Platform string `json:"platform"`
133
+ Arch string `json:"arch"`
134
+ }
135
+
136
+ func reportBundledSkillTelemetry(event string, source string, stderr io.Writer) {
137
+ if os.Getenv("PIPPIT_CLI_DISABLE_TELEMETRY") == "1" {
138
+ return
139
+ }
140
+ for _, skillName := range telemetrySkillNames {
141
+ payload := telemetryPayload{
142
+ Event: event,
143
+ SkillName: skillName,
144
+ Source: source,
145
+ CliVersion: telemetryCliVersion(),
146
+ Platform: runtime.GOOS,
147
+ Arch: runtime.GOARCH,
148
+ }
149
+ go func(payload telemetryPayload) {
150
+ if err := reportSkillTelemetry(payload); err != nil && os.Getenv("PIPPIT_CLI_DEBUG_TELEMETRY") == "1" {
151
+ fmt.Fprintf(stderr, "[pippit-tool-cli] telemetry failed: %v\n", err)
152
+ }
153
+ }(payload)
154
+ }
155
+ }
156
+
157
+ func reportSkillTelemetry(payload telemetryPayload) error {
158
+ body, err := json.Marshal(payload)
159
+ if err != nil {
160
+ return err
161
+ }
162
+
163
+ req, err := http.NewRequest(http.MethodPost, telemetryBaseURL()+telemetryPath, bytes.NewReader(body))
164
+ if err != nil {
165
+ return err
166
+ }
167
+ req.Header.Set("Content-Type", "application/json")
168
+ req.Header.Set("Authorization", telemetryAuthHeader)
169
+ req.Header.Set("x-use-ppe", "1")
170
+ req.Header.Set("x-tt-env", "ppe_harness_novel_v2")
171
+
172
+ resp, err := telemetryHTTPClient.Do(req)
173
+ if err != nil {
174
+ return err
175
+ }
176
+ defer resp.Body.Close()
177
+ _, _ = io.Copy(io.Discard, resp.Body)
178
+ if resp.StatusCode >= 400 {
179
+ return fmt.Errorf("telemetry returned HTTP %d", resp.StatusCode)
180
+ }
181
+ return nil
182
+ }
183
+
184
+ func telemetryBaseURL() string {
185
+ for _, key := range []string{"PIPPIT_CLI_TELEMETRY_BASE_URL", "XYQ_OPENAPI_BASE", "XYQ_BASE_URL"} {
186
+ if value := strings.TrimRight(strings.TrimSpace(os.Getenv(key)), "/"); value != "" {
187
+ return value
188
+ }
189
+ }
190
+ return defaultTelemetryBaseURL
191
+ }
192
+
193
+ func telemetryCliVersion() string {
194
+ return stripPrereleaseVersion(version.Current())
195
+ }
196
+
197
+ func stripPrereleaseVersion(value string) string {
198
+ if idx := strings.Index(value, "-"); idx >= 0 {
199
+ return value[:idx]
200
+ }
201
+ return value
202
+ }
203
+
108
204
  func runInherit(stderr io.Writer, name string, args ...string) error {
109
205
  return runInheritEnv(stderr, nil, name, args...)
110
206
  }
@@ -2,6 +2,9 @@ package updatecmd
2
2
 
3
3
  import (
4
4
  "bytes"
5
+ "encoding/json"
6
+ "net/http"
7
+ "net/http/httptest"
5
8
  "os"
6
9
  "path/filepath"
7
10
  "runtime"
@@ -70,3 +73,67 @@ func TestCleanupLegacyGlobalSkills(t *testing.T) {
70
73
  }
71
74
  }
72
75
  }
76
+
77
+ func TestReportSkillTelemetry(t *testing.T) {
78
+ var gotAuth string
79
+ var gotHeaders http.Header
80
+ var gotPayload telemetryPayload
81
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
82
+ if r.URL.Path != telemetryPath {
83
+ t.Fatalf("path = %q, want %q", r.URL.Path, telemetryPath)
84
+ }
85
+ gotAuth = r.Header.Get("Authorization")
86
+ gotHeaders = r.Header.Clone()
87
+ if err := json.NewDecoder(r.Body).Decode(&gotPayload); err != nil {
88
+ t.Fatalf("decode request body: %v", err)
89
+ }
90
+ _, _ = w.Write([]byte(`{"ret":"0","errmsg":""}`))
91
+ }))
92
+ defer server.Close()
93
+
94
+ t.Setenv("PIPPIT_CLI_TELEMETRY_BASE_URL", server.URL+"/")
95
+ err := reportSkillTelemetry(telemetryPayload{
96
+ Event: "update",
97
+ SkillName: "xyq-skill",
98
+ Source: "cli_update",
99
+ CliVersion: "0.0.26",
100
+ Platform: "darwin",
101
+ Arch: "arm64",
102
+ })
103
+ if err != nil {
104
+ t.Fatalf("reportSkillTelemetry() error = %v", err)
105
+ }
106
+ if gotAuth != telemetryAuthHeader {
107
+ t.Fatalf("Authorization = %q, want %q", gotAuth, telemetryAuthHeader)
108
+ }
109
+ if got := gotHeaders.Get("x-use-ppe"); got != "1" {
110
+ t.Fatalf("x-use-ppe = %q, want 1", got)
111
+ }
112
+ if got := gotHeaders.Get("x-tt-env"); got != "ppe_harness_novel_v2" {
113
+ t.Fatalf("x-tt-env = %q, want ppe_harness_novel_v2", got)
114
+ }
115
+ if gotPayload.Event != "update" || gotPayload.SkillName != "xyq-skill" || gotPayload.Source != "cli_update" {
116
+ t.Fatalf("payload = %#v", gotPayload)
117
+ }
118
+ }
119
+
120
+ func TestTelemetryBaseURL(t *testing.T) {
121
+ t.Setenv("PIPPIT_CLI_TELEMETRY_BASE_URL", " ")
122
+ t.Setenv("XYQ_OPENAPI_BASE", "https://example.com///")
123
+ if got := telemetryBaseURL(); got != "https://example.com" {
124
+ t.Fatalf("telemetryBaseURL() = %q, want https://example.com", got)
125
+ }
126
+ }
127
+
128
+ func TestStripPrereleaseVersion(t *testing.T) {
129
+ cases := map[string]string{
130
+ "0.0.27": "0.0.27",
131
+ "0.0.27-rc.1": "0.0.27",
132
+ "1.2.3-beta.4": "1.2.3",
133
+ }
134
+ for input, want := range cases {
135
+ if got := stripPrereleaseVersion(input); got != want {
136
+ t.Fatalf("stripPrereleaseVersion(%q) = %q, want %q", input, got, want)
137
+ }
138
+ }
139
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pippit-dev/cli",
3
- "version": "0.0.26",
3
+ "version": "0.0.27",
4
4
  "description": "Pippit CLI",
5
5
  "bin": {
6
6
  "pippit-tool-cli": "scripts/run.js"
@@ -35,6 +35,7 @@
35
35
  "scripts/platform.js",
36
36
  "scripts/run.js",
37
37
  "scripts/skills.js",
38
+ "scripts/telemetry.js",
38
39
  "scripts/version-check.js",
39
40
  "checksums.txt",
40
41
  "README.md",
@@ -4,6 +4,7 @@ const fs = require("fs");
4
4
  const path = require("path");
5
5
  const { isWindows, run, runSilent } = require("./platform");
6
6
  const { DEFAULT_PKG, installGlobalPackageSkills } = require("./skills");
7
+ const { reportBundledSkillTelemetry } = require("./telemetry");
7
8
 
8
9
  const PKG = process.env.PIPPIT_CLI_INSTALL_PACKAGE || DEFAULT_PKG;
9
10
 
@@ -68,6 +69,7 @@ function main() {
68
69
  }
69
70
 
70
71
  console.log(`pippit-tool-cli is ready: ${bin}`);
72
+ reportBundledSkillTelemetry("install", "npx_install");
71
73
  console.log("Try: pippit-tool-cli short-drama +submit-run --message \"写一个短剧开头\"");
72
74
  }
73
75
 
@@ -6,6 +6,7 @@ const os = require("os");
6
6
  const path = require("path");
7
7
  const { isWindows, run } = require("./platform");
8
8
  const { cleanupLegacyGlobalSkills, installSkillsFromRoot } = require("./skills");
9
+ const { reportBundledSkillTelemetry } = require("./telemetry");
9
10
 
10
11
  const VERSION = require("../package.json").version.replace(/-.*$/, "");
11
12
  const REPO = "Pippit-dev/cli";
@@ -134,6 +135,7 @@ function install() {
134
135
 
135
136
  if (process.env.PIPPIT_CLI_SKIP_SKILLS !== "1") {
136
137
  installSkillsFromRoot(ROOT);
138
+ reportBundledSkillTelemetry("install", "npm_install");
137
139
  } else {
138
140
  cleanupLegacyGlobalSkills();
139
141
  }
@@ -0,0 +1,83 @@
1
+ const os = require("os");
2
+ const http = require("http");
3
+ const https = require("https");
4
+
5
+ const VERSION = require("../package.json").version.replace(/-.*$/, "");
6
+ const DEFAULT_BASE_URL = "https://xyq.jianying.com";
7
+ const REPORT_PATH = "/api/biz/v1/skill/report_telemetry";
8
+ const AUTH_HEADER = "Bearer pippit-cli-skill-telemetry";
9
+ const SKILL_NAMES = [
10
+ "xyq-skill",
11
+ "xyq-short-drama-skill",
12
+ ];
13
+
14
+ function telemetryBaseURL() {
15
+ for (const key of ["PIPPIT_CLI_TELEMETRY_BASE_URL", "XYQ_OPENAPI_BASE", "XYQ_BASE_URL"]) {
16
+ const value = (process.env[key] || "").trim().replace(/\/+$/, "");
17
+ if (value) return value;
18
+ }
19
+ return DEFAULT_BASE_URL;
20
+ }
21
+
22
+ function reportBundledSkillTelemetry(event, source) {
23
+ if (process.env.PIPPIT_CLI_DISABLE_TELEMETRY === "1") {
24
+ return;
25
+ }
26
+ for (const skillName of SKILL_NAMES) {
27
+ reportSkillTelemetry({
28
+ event,
29
+ skill_name: skillName,
30
+ source,
31
+ cli_version: VERSION,
32
+ platform: os.platform(),
33
+ arch: os.arch(),
34
+ });
35
+ }
36
+ }
37
+
38
+ function reportSkillTelemetry(payload) {
39
+ const body = JSON.stringify(payload);
40
+ const url = new URL(`${telemetryBaseURL()}${REPORT_PATH}`);
41
+ const client = url.protocol === "http:" ? http : https;
42
+
43
+ try {
44
+ const req = client.request(url, {
45
+ method: "POST",
46
+ timeout: 2000,
47
+ headers: {
48
+ "Content-Type": "application/json",
49
+ "Content-Length": Buffer.byteLength(body),
50
+ "Authorization": AUTH_HEADER,
51
+ "x-use-ppe": "1",
52
+ "x-tt-env": "ppe_harness_novel_v2",
53
+ },
54
+ }, (res) => {
55
+ res.resume();
56
+ if (process.env.PIPPIT_CLI_DEBUG_TELEMETRY === "1" && res.statusCode >= 400) {
57
+ console.warn(`[pippit-tool-cli] telemetry failed: HTTP ${res.statusCode}`);
58
+ }
59
+ });
60
+
61
+ req.on("timeout", () => {
62
+ req.destroy(new Error("telemetry request timeout"));
63
+ });
64
+ req.on("error", (err) => {
65
+ if (process.env.PIPPIT_CLI_DEBUG_TELEMETRY === "1") {
66
+ const msg = err && err.message ? err.message : String(err);
67
+ console.warn(`[pippit-tool-cli] telemetry failed: ${msg}`);
68
+ }
69
+ });
70
+ req.end(body);
71
+ } catch (err) {
72
+ if (process.env.PIPPIT_CLI_DEBUG_TELEMETRY === "1") {
73
+ const msg = err && err.message ? err.message : String(err);
74
+ console.warn(`[pippit-tool-cli] telemetry failed: ${msg}`);
75
+ }
76
+ }
77
+ }
78
+
79
+ module.exports = {
80
+ reportBundledSkillTelemetry,
81
+ reportSkillTelemetry,
82
+ telemetryBaseURL,
83
+ };