@bty/customer-service-cli 0.1.9 → 0.1.10

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 (2) hide show
  1. package/dist/bin.js +113 -13
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -66,10 +66,8 @@ function outputInfo(message) {
66
66
  process.stderr.write(message + "\n");
67
67
  }
68
68
 
69
- // src/client/auth-api.ts
70
- import CryptoJS from "crypto-js";
71
-
72
- // src/utils/credentials.ts
69
+ // src/utils/update-checker.ts
70
+ import https from "https";
73
71
  import fs2 from "fs";
74
72
  import path2 from "path";
75
73
 
@@ -150,13 +148,109 @@ function initLocalConfig() {
150
148
  return filePath;
151
149
  }
152
150
 
151
+ // src/utils/update-checker.ts
152
+ var CACHE_FILENAME = "update-check.json";
153
+ var CHECK_INTERVAL_MS = 4 * 60 * 60 * 1e3;
154
+ var REQUEST_TIMEOUT_MS = 3e3;
155
+ var PACKAGE_NAME = "@bty/customer-service-cli";
156
+ var REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
157
+ function getCachePath() {
158
+ return path2.join(getConfigDir(), CACHE_FILENAME);
159
+ }
160
+ function readCache() {
161
+ try {
162
+ const content = fs2.readFileSync(getCachePath(), "utf-8");
163
+ return JSON.parse(content);
164
+ } catch {
165
+ return null;
166
+ }
167
+ }
168
+ function writeCache(cache) {
169
+ const dir = getConfigDir();
170
+ fs2.mkdirSync(dir, { recursive: true });
171
+ fs2.writeFileSync(getCachePath(), JSON.stringify(cache, null, 2));
172
+ }
173
+ function compareSemver(current, latest) {
174
+ const parse = (v) => v.replace(/^v/, "").split(".").map(Number);
175
+ const a = parse(current);
176
+ const b = parse(latest);
177
+ for (let i = 0; i < 3; i++) {
178
+ const av = a[i] ?? 0;
179
+ const bv = b[i] ?? 0;
180
+ if (av < bv) return -1;
181
+ if (av > bv) return 1;
182
+ }
183
+ return 0;
184
+ }
185
+ function fetchLatestVersion() {
186
+ return new Promise((resolve, reject) => {
187
+ const req = https.get(REGISTRY_URL, { timeout: REQUEST_TIMEOUT_MS }, (res) => {
188
+ if (res.statusCode !== 200) {
189
+ reject(new Error(`HTTP ${res.statusCode}`));
190
+ res.resume();
191
+ return;
192
+ }
193
+ let body = "";
194
+ res.setEncoding("utf-8");
195
+ res.on("data", (chunk) => {
196
+ body += chunk;
197
+ });
198
+ res.on("end", () => {
199
+ try {
200
+ const data = JSON.parse(body);
201
+ if (data.version) {
202
+ resolve(data.version);
203
+ } else {
204
+ reject(new Error("No version field in response"));
205
+ }
206
+ } catch {
207
+ reject(new Error("Invalid JSON response"));
208
+ }
209
+ });
210
+ });
211
+ req.on("error", reject);
212
+ req.on("timeout", () => {
213
+ req.destroy();
214
+ reject(new Error("Request timeout"));
215
+ });
216
+ });
217
+ }
218
+ async function checkForUpdate(currentVersion) {
219
+ if (process.env.CS_CLI_NO_UPDATE_CHECK === "1") {
220
+ return null;
221
+ }
222
+ try {
223
+ const cache = readCache();
224
+ const now = Date.now();
225
+ if (cache && now - cache.lastCheckedAt < CHECK_INTERVAL_MS) {
226
+ return compareSemver(currentVersion, cache.latestVersion) < 0 ? formatUpdateMessage(currentVersion, cache.latestVersion) : null;
227
+ }
228
+ const latestVersion = await fetchLatestVersion();
229
+ writeCache({ latestVersion, lastCheckedAt: now });
230
+ return compareSemver(currentVersion, latestVersion) < 0 ? formatUpdateMessage(currentVersion, latestVersion) : null;
231
+ } catch {
232
+ return null;
233
+ }
234
+ }
235
+ function formatUpdateMessage(current, latest) {
236
+ return `
237
+ \u26A0 \u53D1\u73B0\u65B0\u7248\u672C ${PACKAGE_NAME}@${latest}\uFF08\u5F53\u524D ${current}\uFF09
238
+ \u8FD0\u884C pnpm add -g ${PACKAGE_NAME} \u5347\u7EA7
239
+ `;
240
+ }
241
+
242
+ // src/client/auth-api.ts
243
+ import CryptoJS from "crypto-js";
244
+
153
245
  // src/utils/credentials.ts
246
+ import fs3 from "fs";
247
+ import path3 from "path";
154
248
  function getCredentialsPath() {
155
- return path2.join(getConfigDir(), "credentials.json");
249
+ return path3.join(getConfigDir(), "credentials.json");
156
250
  }
157
251
  function readCredentials() {
158
252
  try {
159
- const content = fs2.readFileSync(getCredentialsPath(), "utf-8");
253
+ const content = fs3.readFileSync(getCredentialsPath(), "utf-8");
160
254
  return JSON.parse(content);
161
255
  } catch {
162
256
  return null;
@@ -164,12 +258,12 @@ function readCredentials() {
164
258
  }
165
259
  function writeCredentials(creds) {
166
260
  const dir = getConfigDir();
167
- fs2.mkdirSync(dir, { recursive: true });
168
- fs2.writeFileSync(getCredentialsPath(), JSON.stringify(creds, null, 2));
261
+ fs3.mkdirSync(dir, { recursive: true });
262
+ fs3.writeFileSync(getCredentialsPath(), JSON.stringify(creds, null, 2));
169
263
  }
170
264
  function clearCredentials() {
171
265
  try {
172
- fs2.unlinkSync(getCredentialsPath());
266
+ fs3.unlinkSync(getCredentialsPath());
173
267
  } catch {
174
268
  }
175
269
  }
@@ -194,7 +288,7 @@ function toExitCode(err) {
194
288
  return 1;
195
289
  }
196
290
  function createRequest(globalTimeout) {
197
- return async function request(baseUrl, path3, options) {
291
+ return async function request(baseUrl, path4, options) {
198
292
  const headers = {
199
293
  "Content-Type": "application/json",
200
294
  ...options.headers
@@ -215,7 +309,7 @@ function createRequest(globalTimeout) {
215
309
  if (workspaceId) {
216
310
  headers["workspace-id"] = workspaceId;
217
311
  }
218
- let url = `${baseUrl}${path3}`;
312
+ let url = `${baseUrl}${path4}`;
219
313
  if (options.query) {
220
314
  const params = new URLSearchParams();
221
315
  for (const [key, value] of Object.entries(options.query)) {
@@ -495,7 +589,7 @@ async function updateAgent(configId, data) {
495
589
  }
496
590
 
497
591
  // src/utils/data-parser.ts
498
- import fs3 from "fs";
592
+ import fs4 from "fs";
499
593
  function parseDataOption(value) {
500
594
  if (!value) {
501
595
  throw new Error("Data option cannot be empty");
@@ -507,7 +601,7 @@ function parseDataOption(value) {
507
601
  }
508
602
  let content;
509
603
  try {
510
- content = fs3.readFileSync(filePath, "utf-8");
604
+ content = fs4.readFileSync(filePath, "utf-8");
511
605
  } catch {
512
606
  throw new Error(`Cannot read file: ${filePath}`);
513
607
  }
@@ -1919,6 +2013,12 @@ program.hook("preAction", (thisCommand) => {
1919
2013
  setRuntimeWorkspaceId(opts.workspace);
1920
2014
  }
1921
2015
  });
2016
+ program.hook("postAction", async () => {
2017
+ const message = await checkForUpdate(version);
2018
+ if (message) {
2019
+ outputInfo(message);
2020
+ }
2021
+ });
1922
2022
  registerAuthCommand(program);
1923
2023
  registerConfigCommand(program);
1924
2024
  registerWorkspaceCommand(program);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bty/customer-service-cli",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "AI Customer Service CLI - Agent friendly",
5
5
  "type": "module",
6
6
  "main": "./dist/bin.js",