@miruzero/zgpt 0.1.5 → 0.1.6
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 +4 -2
- package/package.json +3 -2
- package/src/auth/index.js +10 -3
- package/src/cli/sdk-dispatch.js +2 -1
- package/src/cli.js +7 -0
package/README.md
CHANGED
|
@@ -50,7 +50,9 @@ const chatgpt = require('@miruzero/zgpt');
|
|
|
50
50
|
|
|
51
51
|
The npm package name and the CLI binary name are independent; installing **only** `@miruzero/zgpt` does not create a local `node_modules/zgpt` alias.
|
|
52
52
|
|
|
53
|
-
The package exposes the `zgpt` executable through npm's `bin` field. A local `npm install` does not add `node_modules/.bin` to the parent shell's PATH, so use `npx zgpt` for local installs or install globally for the bare `zgpt` command.
|
|
53
|
+
The package exposes the `zgpt` executable through npm's `bin` field. Running **`zgpt` with no arguments displays root Help** (as do `zgpt help` and `zgpt --help`) without making an HTTP request. A local `npm install` does not add `node_modules/.bin` to the parent shell's PATH, so use `npx zgpt` for local installs or install globally for the bare `zgpt` command.
|
|
54
|
+
|
|
55
|
+
**Windows troubleshooting (HTTP 401 while `auth-status` is valid):** `zgpt auth-status` reads local token metadata and does **not** probe the upstream server. Versions before `0.1.6` can report a stale token as valid when stored session expiry exceeds its JWT `exp`. Check `Get-Command zgpt` and `node -p "require('@miruzero/zgpt/package.json').version"` in the consuming project to identify the exact installation. Each npm installation maintains independent state unless `ZERO_CHATGPT_STATE_DIR` points to the same persistent writable directory. For example, set `$env:ZERO_CHATGPT_STATE_DIR = "$HOME\\.zgpt\\state"` in PowerShell before running the CLI and run `zgpt login` to acquire authentication for that directory. Do not copy or display access tokens or cookies when troubleshooting. `zgpt get --help` displays local usage without requesting the Backend in `0.1.6`.
|
|
54
56
|
|
|
55
57
|
### Hierarchical SDK → CLI automatic command discovery
|
|
56
58
|
|
|
@@ -150,7 +152,7 @@ zgpt api apps getAppsDirectoryBrowse --query category=productivity
|
|
|
150
152
|
zgpt api composer getComposerItems --query 'entrypoint=chat&limit=10'
|
|
151
153
|
```
|
|
152
154
|
|
|
153
|
-
The `--query` flag accepts shell-friendly `name=value` or `name=value&name2=value2`, as well as a JSON object. For GET routes requiring query parameters, see `zgpt api show "GET /backend-api/..."` and `src/api/contracts.json`. The auditor and capture scanners are developer scripts in this source checkout and are not bundled in the npm package. Version `0.1.5`
|
|
155
|
+
The `--query` flag accepts shell-friendly `name=value` or `name=value&name2=value2`, as well as a JSON object. For GET routes requiring query parameters, see `zgpt api show "GET /backend-api/..."` and `src/api/contracts.json`. The auditor and capture scanners are developer scripts in this source checkout and are not bundled in the npm package. Version `0.1.5` was published; changes to JWT-expiry validation and `get --help` are prepared in local source `0.1.6` and require a new npm publish before external installations receive them.
|
|
154
156
|
|
|
155
157
|
### Custom MCP server CRUD and action refresh
|
|
156
158
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miruzero/zgpt",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"type": "commonjs",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
"node": ">=20"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"classic-level": "^3.0.0"
|
|
22
|
+
"classic-level": "^3.0.0",
|
|
23
|
+
"zgpt": "npm:@miruzero/zgpt@^0.1.5"
|
|
23
24
|
},
|
|
24
25
|
"allowScripts": {
|
|
25
26
|
"classic-level@3.0.0": true
|
package/src/auth/index.js
CHANGED
|
@@ -12,6 +12,13 @@ const tokenExpiry = (token) => {
|
|
|
12
12
|
return Number.isFinite(payload.exp) ? new Date(payload.exp * 1000).toISOString() : null;
|
|
13
13
|
} catch { return null; }
|
|
14
14
|
};
|
|
15
|
+
// Cached session expiry can exceed the actual JWT expiry. Never mark a JWT as
|
|
16
|
+
// usable past its own exp claim merely because persisted metadata says so.
|
|
17
|
+
const earliestExpiry = (token, reported) => {
|
|
18
|
+
const claim = tokenExpiry(token);
|
|
19
|
+
const parsed = [claim, reported].map(value => Date.parse(value || '')).filter(Number.isFinite);
|
|
20
|
+
return parsed.length ? new Date(Math.min(...parsed)).toISOString() : (reported || claim || null);
|
|
21
|
+
};
|
|
15
22
|
const isExpired = (expires) => { const at = Date.parse(expires || ''); return Number.isFinite(at) && at <= Date.now(); };
|
|
16
23
|
const rawFromEnv = (env) => {
|
|
17
24
|
const token = typeof env.ZERO_CHATGPT_ACCESS_TOKEN === 'string' ? env.ZERO_CHATGPT_ACCESS_TOKEN.trim() : '';
|
|
@@ -24,7 +31,7 @@ const rawFromFile = (env) => {
|
|
|
24
31
|
const file = paths.authFile(env);
|
|
25
32
|
const data = readJson(file);
|
|
26
33
|
if (!data || typeof data.accessToken !== 'string' || !data.accessToken) return null;
|
|
27
|
-
return { tokenName: data.tokenName || 'ACCESS', accessToken: data.accessToken, expires: data.
|
|
34
|
+
return { tokenName: data.tokenName || 'ACCESS', accessToken: data.accessToken, expires: earliestExpiry(data.accessToken, data.expires), updatedAt: data.updatedAt || null, source: 'file', file };
|
|
28
35
|
};
|
|
29
36
|
|
|
30
37
|
exports.status = ({ env = process.env } = {}) => {
|
|
@@ -39,7 +46,7 @@ exports.importSession = ({ body, env = process.env, source = 'session' } = {}) =
|
|
|
39
46
|
if (!accessToken || typeof accessToken !== 'string') {
|
|
40
47
|
throw Object.assign(new Error('ChatGPT session did not provide an access token'), { code: 'AUTH_REQUIRED' });
|
|
41
48
|
}
|
|
42
|
-
const expires = body?.expires || body?.expires_at
|
|
49
|
+
const expires = earliestExpiry(accessToken, body?.expires || body?.expires_at);
|
|
43
50
|
const value = {
|
|
44
51
|
tokenName: 'ACCESS',
|
|
45
52
|
accessToken,
|
|
@@ -69,7 +76,7 @@ exports.refresh = async ({ env = process.env, acquireSession, fresh = false } =
|
|
|
69
76
|
const value = {
|
|
70
77
|
tokenName: 'ACCESS',
|
|
71
78
|
accessToken,
|
|
72
|
-
expires: body?.expires || body?.expires_at
|
|
79
|
+
expires: earliestExpiry(accessToken, body?.expires || body?.expires_at),
|
|
73
80
|
updatedAt: new Date().toISOString()
|
|
74
81
|
};
|
|
75
82
|
writeJson(paths.authFile(env), value);
|
package/src/cli/sdk-dispatch.js
CHANGED
|
@@ -306,7 +306,8 @@ exports.run = async (argv, options = {}) => {
|
|
|
306
306
|
const stdout = options.stdout || console.log;
|
|
307
307
|
const stderr = options.stderr || console.error;
|
|
308
308
|
try {
|
|
309
|
-
|
|
309
|
+
// A bare `zgpt` is a help request, not an unknown SDK namespace.
|
|
310
|
+
if (!argv.length || argv[0] === 'help' || argv[0] === '--help' || argv[0] === '-h') {
|
|
310
311
|
const name = argv[1];
|
|
311
312
|
if (argv.length > 3 || argv.length === 3 && name !== 'api') throw error('Usage: zgpt help [namespace]');
|
|
312
313
|
if (!name) stdout(exports.help(runtime));
|
package/src/cli.js
CHANGED
|
@@ -39,6 +39,13 @@ exports.run = async (argv = [], options = {}) => {
|
|
|
39
39
|
if (command === 'help' || command === '--help' || command === '-h') {
|
|
40
40
|
return require('./cli/sdk-dispatch').run(argv, { ...options, stdout, stderr });
|
|
41
41
|
}
|
|
42
|
+
// A help flag directly after a legacy command must never become a room ID.
|
|
43
|
+
if (['get', 'export'].includes(command) && ['--help', '-h', 'help'].includes(argv[1])) {
|
|
44
|
+
stdout(command === 'get'
|
|
45
|
+
? 'Usage: zgpt get <conversation-id> [--json | --debug | --limit N]'
|
|
46
|
+
: 'Usage: zgpt export <conversation-id> [--json | --debug | --limit N] [--out PATH]');
|
|
47
|
+
return 0;
|
|
48
|
+
}
|
|
42
49
|
// SDK namespaces are routed dynamically; legacy aliases below remain compatible.
|
|
43
50
|
const runtime = options.runtime || require('./index');
|
|
44
51
|
if (command === 'functions' || command === 'call' || command === 'api' ||
|