tripo-cli 0.5.0 → 0.5.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
@@ -40,6 +40,7 @@ Works with both Tripo regions from the same install — international (`openapi.
40
40
  | `tripo files upload` | upload a file, print the `file_token` |
41
41
  | `tripo batch run <manifest.yaml>` | bulk pipelines with concurrency, retries, and resume |
42
42
  | `tripo config / doctor` | settings (global + per-directory `.tripo/context.json`) and self-diagnosis |
43
+ | `tripo update [--check]` | upgrade to the latest release (`npm install -g tripo-cli@latest`); every command also hints when a newer version exists |
43
44
  | `tripo docs [--topic t]` | print the bundled agent/skill docs (`--topic commands/generate` has the model versions / P series table) |
44
45
  | `tripo mcp` | run as an MCP server (Cursor / Claude Desktop) |
45
46
  | `tripo completion <shell>` | bash/zsh/fish completion |
@@ -103,6 +104,8 @@ tripo batch run assets.yaml --concurrency 2
103
104
  | `TRIPO_REGION` | `ov` or `cn` — normally unnecessary: `tripo login` probes both regions with your key and stores the right one automatically |
104
105
  | `TRIPO_API_BASE_URL` / `TRIPO_PLATFORM_BASE_URL` | endpoint overrides |
105
106
  | `TRIPO_HOME` | config/history directory (default `~/.tripo`) |
107
+ | `TRIPO_NO_UPDATE_CHECK` | disable the startup "new version available" hint (also off when `CI` is set, headless, or `--json`) |
108
+ | `TRIPO_NPM_REGISTRY` | npm registry used by `tripo update` and the version check (default `https://registry.npmjs.org`; e.g. a mirror) |
106
109
  | `HTTPS_PROXY` / `HTTP_PROXY` / `NO_PROXY` | standard proxy variables, honored for all CLI traffic (plain Node fetch ignores them) |
107
110
  | `TRIPO_LLM_BASE_URL` / `TRIPO_LLM_API_KEY` / `TRIPO_LLM_MODEL` | optional OpenAI-compatible LLM for `tripo ai` conversation mode |
108
111
 
@@ -5,7 +5,7 @@ const COMMANDS = [
5
5
  'login', 'logout', 'whoami', 'use', 'balance', 'usage', 'topup',
6
6
  'make', 'view', 'redo', 'ai',
7
7
  'generate', 'model', 'anim', 'mesh', 'task', 'files', 'batch', 'history',
8
- 'config', 'doctor', 'docs', 'completion', 'mcp',
8
+ 'config', 'doctor', 'update', 'docs', 'completion', 'mcp',
9
9
  ];
10
10
  const SUBS = {
11
11
  generate: ['text-to-model', 'image-to-model', 'multiview-to-model', 'text-to-image', 'image-to-image', 'image-to-multiview', 'edit-multiview', 'image-to-splat'],
@@ -0,0 +1,138 @@
1
+ /**
2
+ * `tripo update` — self-update via npm, plus the startup "new version
3
+ * available" hint (like Claude Code / Codex CLI).
4
+ *
5
+ * The startup check never blocks a command: it reads a 24h cache at
6
+ * ~/.tripo/update-check.json and only refreshes it in the background when
7
+ * stale. The hint is printed to stderr, TTY-only, and never in --json mode,
8
+ * so agents and pipes are unaffected.
9
+ */
10
+ import { spawn } from 'node:child_process';
11
+ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
12
+ import { join } from 'node:path';
13
+ import pc from 'picocolors';
14
+ import { tripoHome } from '../config/config.js';
15
+ import { CliError, NetworkError } from '../core/errors.js';
16
+ import { emitResult, isJsonMode, log, success } from '../core/output.js';
17
+ import { t } from '../i18n.js';
18
+ import { EXIT } from '../knowledge/error-catalog.js';
19
+ import { cliVersion } from '../version.js';
20
+ const PACKAGE_NAME = 'tripo-cli';
21
+ const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
22
+ const FETCH_TIMEOUT_MS = 3000;
23
+ function registryUrl() {
24
+ const base = process.env.TRIPO_NPM_REGISTRY || 'https://registry.npmjs.org';
25
+ return `${base.replace(/\/+$/, '')}/${PACKAGE_NAME}/latest`;
26
+ }
27
+ function cachePath() {
28
+ return join(tripoHome(), 'update-check.json');
29
+ }
30
+ function readCache() {
31
+ try {
32
+ const raw = JSON.parse(readFileSync(cachePath(), 'utf8'));
33
+ if (typeof raw.checked_at === 'number' && typeof raw.latest === 'string')
34
+ return raw;
35
+ }
36
+ catch { }
37
+ return undefined;
38
+ }
39
+ function writeCache(latest) {
40
+ try {
41
+ mkdirSync(tripoHome(), { recursive: true, mode: 0o700 });
42
+ writeFileSync(cachePath(), JSON.stringify({ checked_at: Date.now(), latest }) + '\n');
43
+ }
44
+ catch { }
45
+ }
46
+ /** Numeric major.minor.patch comparison; pre-release tags are ignored. */
47
+ export function isNewerVersion(candidate, current) {
48
+ const parse = (v) => v.replace(/^v/, '').split('-')[0].split('.').map((x) => Number(x) || 0);
49
+ const a = parse(candidate);
50
+ const b = parse(current);
51
+ for (let i = 0; i < 3; i++) {
52
+ if ((a[i] ?? 0) !== (b[i] ?? 0))
53
+ return (a[i] ?? 0) > (b[i] ?? 0);
54
+ }
55
+ return false;
56
+ }
57
+ /** Ask the npm registry for the latest published version. */
58
+ export async function fetchLatestVersion() {
59
+ const url = registryUrl();
60
+ let response;
61
+ try {
62
+ response = await fetch(url, { headers: { Accept: 'application/json' }, signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });
63
+ }
64
+ catch (err) {
65
+ throw new NetworkError(`cannot reach the npm registry (${url}): ${err instanceof Error ? err.message : String(err)}`);
66
+ }
67
+ if (!response.ok)
68
+ throw new NetworkError(`npm registry answered HTTP ${response.status} for ${url}`);
69
+ const body = (await response.json());
70
+ if (typeof body.version !== 'string')
71
+ throw new NetworkError(`unexpected npm registry response for ${url}`);
72
+ writeCache(body.version);
73
+ return body.version;
74
+ }
75
+ /**
76
+ * Startup hook: print a one-line hint when a newer version is known.
77
+ * Cheap on every run (one small file read); refreshes the cache in the
78
+ * background at most once a day. Skipped headless, in --json mode, and when
79
+ * TRIPO_NO_UPDATE_CHECK is set.
80
+ */
81
+ export function notifyIfOutdated() {
82
+ if (process.env.TRIPO_NO_UPDATE_CHECK || process.env.CI)
83
+ return;
84
+ if (isJsonMode() || !process.stderr.isTTY)
85
+ return;
86
+ const current = cliVersion();
87
+ const cache = readCache();
88
+ if (cache && isNewerVersion(cache.latest, current)) {
89
+ process.stderr.write(pc.yellow(t({
90
+ zh: `! 有新版本 tripo-cli ${cache.latest} 可用(当前 ${current}),运行 tripo update 升级`,
91
+ en: `! a new version of tripo-cli is available: ${cache.latest} (current ${current}) — run "tripo update" to upgrade`,
92
+ })) + '\n');
93
+ }
94
+ if (!cache || Date.now() - cache.checked_at > CHECK_INTERVAL_MS) {
95
+ // Fire-and-forget; the result shows up on the next run.
96
+ fetchLatestVersion().catch(() => { });
97
+ }
98
+ }
99
+ function runNpmInstall() {
100
+ return new Promise((resolve, reject) => {
101
+ const child = spawn('npm', ['install', '-g', `${PACKAGE_NAME}@latest`], {
102
+ stdio: 'inherit',
103
+ shell: process.platform === 'win32',
104
+ });
105
+ child.on('error', (err) => reject(new CliError(`failed to run npm: ${err.message}`, EXIT.FATAL)));
106
+ child.on('exit', (code) => {
107
+ if (code === 0)
108
+ resolve();
109
+ else
110
+ reject(new CliError(`npm install exited with code ${code}`, EXIT.FATAL, t({ zh: `手动执行: npm install -g ${PACKAGE_NAME}@latest`, en: `run manually: npm install -g ${PACKAGE_NAME}@latest` })));
111
+ });
112
+ });
113
+ }
114
+ export function registerUpdateCommand(program) {
115
+ program
116
+ .command('update')
117
+ .description('update tripo-cli to the latest version (npm install -g tripo-cli@latest)')
118
+ .option('--check', 'only check for a newer version; do not install')
119
+ .action(async (opts) => {
120
+ const current = cliVersion();
121
+ const latest = await fetchLatestVersion();
122
+ const available = isNewerVersion(latest, current);
123
+ if (!available) {
124
+ success(t({ zh: `已是最新版本 ${current}`, en: `already up to date (${current})` }));
125
+ emitResult({ current, latest, update_available: false, updated: false }, current);
126
+ return;
127
+ }
128
+ if (opts.check) {
129
+ log(t({ zh: `有新版本 ${latest} 可用(当前 ${current}),运行 tripo update 升级`, en: `new version ${latest} available (current ${current}); run "tripo update" to upgrade` }));
130
+ emitResult({ current, latest, update_available: true, updated: false }, `${current} → ${latest}`);
131
+ return;
132
+ }
133
+ log(t({ zh: `正在升级 ${current} → ${latest}…`, en: `updating ${current} → ${latest}…` }));
134
+ await runNpmInstall();
135
+ success(t({ zh: `已升级到 tripo-cli ${latest}`, en: `updated to tripo-cli ${latest}` }));
136
+ emitResult({ current, latest, update_available: true, updated: true }, `${current} → ${latest}`);
137
+ });
138
+ }
package/dist/program.js CHANGED
@@ -16,6 +16,7 @@ import { registerMcpCommand } from './commands/mcp.js';
16
16
  import { registerProcessCommands } from './commands/process-groups.js';
17
17
  import { registerTaskCommands } from './commands/task.js';
18
18
  import { registerTopupCommand } from './commands/topup.js';
19
+ import { notifyIfOutdated, registerUpdateCommand } from './commands/update.js';
19
20
  import { registerViewCommands } from './commands/view.js';
20
21
  import { loadConfig } from './config/config.js';
21
22
  import { RefError } from './config/history.js';
@@ -55,6 +56,10 @@ export function buildProgram() {
55
56
  const lang = loadConfig().language;
56
57
  if (lang)
57
58
  setLocale(lang);
59
+ // Startup version hint (cached, non-blocking). `update` reports on its
60
+ // own; `mcp` speaks JSON-RPC over stdio and must stay silent.
61
+ if (actionCommand.name() !== 'update' && actionCommand.name() !== 'mcp')
62
+ notifyIfOutdated();
58
63
  });
59
64
  registerMakeCommand(program);
60
65
  registerAiCommand(program);
@@ -68,6 +73,7 @@ export function buildProgram() {
68
73
  registerBatchCommand(program);
69
74
  registerConfigCommands(program);
70
75
  registerDoctorCommand(program);
76
+ registerUpdateCommand(program);
71
77
  registerDocsCommand(program);
72
78
  registerCompletionCommand(program);
73
79
  registerMcpCommand(program);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tripo-cli",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Tripo 3D intelligent CLI — turn a prompt or an image into engine-ready 3D assets from your terminal (Tripo V3 API)",
5
5
  "keywords": [
6
6
  "tripo",