@model-go/cli 0.1.3 → 0.1.5-rc.1

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/README.md CHANGED
@@ -44,7 +44,7 @@ The CLI talks to a named environment. Two are built in:
44
44
  | Env | Base URL |
45
45
  | ------ | ---------------------------- |
46
46
  | `cn` | `https://api.modelgo.com` |
47
- | `intl` | `https://api.modelgo.global` |
47
+ | `intl` | `https://api.modelgo.ai` |
48
48
 
49
49
  The active environment defaults to `cn`. Switch it, or register your own:
50
50
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@model-go/cli",
3
- "version": "0.1.3",
3
+ "version": "0.1.5-rc.1",
4
4
  "description": "The official CLI for modelgo. Pairs with AI agent skills so AI agents can operate modelgo on your behalf.",
5
5
  "bin": {
6
6
  "modelgo": "scripts/run.js"
@@ -17,7 +17,6 @@
17
17
  "scripts/install.js",
18
18
  "scripts/install-wizard.js",
19
19
  "scripts/run.js",
20
- "checksums.txt",
21
20
  "LICENSE",
22
21
  "README.md"
23
22
  ],
@@ -34,6 +34,15 @@ const messages = {
34
34
  done: "安装完成!\n试试跟你的 AI 工具(Claude Code、Codex 等)说:\"用 modelgo 跟我打个招呼\"",
35
35
  cancelled: "安装已取消",
36
36
  nonTtyHint: "非交互模式,已完成 npm 全局安装 + skills 安装。",
37
+ envPrompt: "请选择环境 / Select environment",
38
+ envCN: "国内(api.modelgo.com)",
39
+ envIntl: "国际(api.modelgo.ai)",
40
+ envDone: "已切换到 %s 环境",
41
+ envFail: "环境切换失败,可稍后运行: modelgo env use %s",
42
+ authPrompt: "现在登录 modelgo 吗?(将通过浏览器授权,也可稍后再登录)",
43
+ authDone: "登录成功",
44
+ authSkip: "已跳过登录。稍后运行: modelgo auth login",
45
+ authFail: "登录失败,可稍后运行: modelgo auth login",
37
46
  },
38
47
  en: {
39
48
  setup: "Setting up modelgo CLI...",
@@ -49,6 +58,15 @@ const messages = {
49
58
  done: "You are all set!\nTry asking your AI tool (Claude Code, Codex, etc.): \"Have modelgo say hello to me\"",
50
59
  cancelled: "Installation cancelled",
51
60
  nonTtyHint: "Non-interactive mode. Completed global install + skills install.",
61
+ envPrompt: "Select environment",
62
+ envCN: "China (api.modelgo.com)",
63
+ envIntl: "International (api.modelgo.ai)",
64
+ envDone: "Switched to %s environment",
65
+ envFail: "Failed to switch env. Run later: modelgo env use %s",
66
+ authPrompt: "Log in to modelgo now? (browser authorization; you can also log in later)",
67
+ authDone: "Logged in",
68
+ authSkip: "Skipped login. Run later: modelgo auth login",
69
+ authFail: "Login failed. Run later: modelgo auth login",
52
70
  },
53
71
  };
54
72
 
@@ -200,6 +218,42 @@ async function stepInstallSkills(msg, isInteractive) {
200
218
  }
201
219
  }
202
220
 
221
+ async function stepSelectEnv(msg) {
222
+ const env = handleCancel(
223
+ await p.select({
224
+ message: msg.envPrompt,
225
+ options: [
226
+ { value: "cn", label: msg.envCN },
227
+ { value: "intl", label: msg.envIntl },
228
+ ],
229
+ }),
230
+ msg
231
+ );
232
+ try {
233
+ // `modelgo` is on PATH after the global install in stepInstallGlobally.
234
+ runSilent("modelgo", ["env", "use", env], { timeout: 15000 });
235
+ p.log.success(fmt(msg.envDone, env));
236
+ } catch (_) {
237
+ p.log.warn(fmt(msg.envFail, env));
238
+ }
239
+ }
240
+
241
+ async function stepAuthLogin(msg) {
242
+ const wantLogin = handleCancel(await p.confirm({ message: msg.authPrompt }), msg);
243
+ if (!wantLogin) {
244
+ p.log.info(msg.authSkip);
245
+ return;
246
+ }
247
+ try {
248
+ // `auth login` prints a verification URL and blocks polling until the user
249
+ // approves in the browser — inherit stdio so the URL and progress show.
250
+ execCmd("modelgo", ["auth", "login"], { stdio: "inherit" });
251
+ p.log.success(msg.authDone);
252
+ } catch (_) {
253
+ p.log.warn(msg.authFail);
254
+ }
255
+ }
256
+
203
257
  // ---------------------------------------------------------------------------
204
258
  // Main
205
259
  // ---------------------------------------------------------------------------
@@ -213,6 +267,8 @@ async function main() {
213
267
  p.intro(msg.setup);
214
268
  await stepInstallGlobally(msg, isInteractive);
215
269
  await stepInstallSkills(msg, isInteractive);
270
+ await stepSelectEnv(msg);
271
+ await stepAuthLogin(msg);
216
272
  p.outro(msg.done);
217
273
  } else {
218
274
  console.log(msg.setup);
@@ -31,6 +31,13 @@ const ext = isWindows ? ".zip" : ".tar.gz";
31
31
  const archiveName = `${NAME}-${VERSION}-${platform}-${arch}${ext}`;
32
32
  const GITHUB_URL = `https://github.com/${REPO}/releases/download/v${VERSION}/${archiveName}`;
33
33
 
34
+ // checksums.txt is published by goreleaser alongside the release artifacts.
35
+ // We fetch it from the release at install time rather than bundling it in the
36
+ // npm package: a bundled copy generated locally (goreleaser --snapshot) can
37
+ // never match the CI-built release artifacts' names or SHAs.
38
+ const CHECKSUMS_NAME = "checksums.txt";
39
+ const GITHUB_CHECKSUMS_URL = `https://github.com/${REPO}/releases/download/v${VERSION}/${CHECKSUMS_NAME}`;
40
+
34
41
  const binDir = path.join(__dirname, "..", "bin");
35
42
  const dest = path.join(binDir, NAME + (isWindows ? ".exe" : ""));
36
43
 
@@ -184,6 +191,21 @@ function download(url, destPath) {
184
191
  execFileSync("curl", args, { stdio: ["ignore", "ignore", "pipe"] });
185
192
  }
186
193
 
194
+ // Try each URL in order, returning once one succeeds. Throws the last error if
195
+ // all fail.
196
+ function downloadFirst(urls, destPath) {
197
+ let lastErr;
198
+ for (const url of urls) {
199
+ try {
200
+ download(url, destPath);
201
+ return;
202
+ } catch (e) {
203
+ lastErr = e;
204
+ }
205
+ }
206
+ throw lastErr;
207
+ }
208
+
187
209
  function extractZipWindows(archivePath, destDir) {
188
210
  const psOpts = ["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command"];
189
211
  const psStdio = ["ignore", "inherit", "inherit"];
@@ -228,20 +250,33 @@ function install() {
228
250
  const archivePath = path.join(tmpDir, archiveName);
229
251
 
230
252
  try {
231
- let lastErr;
232
- let downloaded = false;
233
- for (const url of downloadUrls) {
234
- try {
235
- download(url, archivePath);
236
- downloaded = true;
237
- break;
238
- } catch (e) {
239
- lastErr = e;
240
- }
253
+ downloadFirst(downloadUrls, archivePath);
254
+
255
+ // Fetch the authoritative checksums.txt from the same release (GitHub
256
+ // first, then mirrors). If it can't be fetched (restricted network),
257
+ // skip verification rather than block the install — the binary itself
258
+ // came from an allowlisted host over HTTPS.
259
+ const checksumsUrls = [
260
+ GITHUB_CHECKSUMS_URL,
261
+ ...resolveMirrorUrls(process.env, CHECKSUMS_NAME, VERSION),
262
+ ];
263
+ for (const u of checksumsUrls) ALLOWED_HOSTS.add(new URL(u).hostname);
264
+ const checksumsPath = path.join(tmpDir, CHECKSUMS_NAME);
265
+ let checksumsFetched = true;
266
+ try {
267
+ downloadFirst(checksumsUrls, checksumsPath);
268
+ } catch (e) {
269
+ checksumsFetched = false;
270
+ console.error(
271
+ `[WARN] could not fetch ${CHECKSUMS_NAME} from release ` +
272
+ `(${e.message}); skipping checksum verification`
273
+ );
241
274
  }
242
- if (!downloaded) throw lastErr;
243
-
244
- const expectedHash = getExpectedChecksum(archiveName);
275
+ // A fetched-but-incomplete checksums.txt is a real integrity problem and
276
+ // must fail loudly, so parse outside the network try/catch above.
277
+ const expectedHash = checksumsFetched
278
+ ? getExpectedChecksum(archiveName, tmpDir)
279
+ : null;
245
280
  verifyChecksum(archivePath, expectedHash);
246
281
 
247
282
  if (isWindows) {
package/checksums.txt DELETED
@@ -1,6 +0,0 @@
1
- d2301f86bdccb4225e959062382d20108eaac2ce023456f306485b8addcacacc modelgo-0.1.2-rc.1-SNAPSHOT-7701312-darwin-amd64.tar.gz
2
- 88480f50f971139c72866d73a69a67368a08a260c96b71e04add4eb7d6676ecf modelgo-0.1.2-rc.1-SNAPSHOT-7701312-darwin-arm64.tar.gz
3
- 9bc1719a182e3b996a793491775fd501da419a6c526d2b8a7cb2e72479cd9e1c modelgo-0.1.2-rc.1-SNAPSHOT-7701312-linux-amd64.tar.gz
4
- 534554cb7b7fff278260b4e030fcbe30a0029c146d46980493a1d902e65c7669 modelgo-0.1.2-rc.1-SNAPSHOT-7701312-linux-arm64.tar.gz
5
- 13cfa7761480b595fab0e1c3400c299013d29eaca3643282f2817b872b7d89d1 modelgo-0.1.2-rc.1-SNAPSHOT-7701312-windows-amd64.zip
6
- 3d57522bf6cfaeaded3ea3b6db4cf4afd8ddd4f0fbf0bcea71241531898a939c modelgo-0.1.2-rc.1-SNAPSHOT-7701312-windows-arm64.zip