@gizai/cli 1.2.1 → 2.0.0
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 +98 -80
- package/cli/computer-identity.mjs +7 -7
- package/cli/giz.mjs +114 -41
- package/cli/mcp-stdio-client.mjs +81 -0
- package/cli/media-capture.mjs +321 -0
- package/cli/update.mjs +150 -0
- package/mcp.json +6 -0
- package/package.json +28 -13
- package/plugin.json +10 -0
- package/skills/giz/SKILL.md +20 -13
- package/skills/giz/references/operations.md +1 -1
package/README.md
CHANGED
|
@@ -1,15 +1,33 @@
|
|
|
1
1
|
# Giz CLI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The official command-line interface for [giz.ai](https://www.giz.ai). Run Giz text, image, video and audio models, manage Drive files, tables, Apps and Computers, and connect Claude Code, Codex and other AI agents to your Giz account, all from a terminal.
|
|
4
|
+
|
|
5
|
+
[Documentation](https://www.giz.ai/mcp/) · [giz.ai](https://www.giz.ai) · [Sign up](https://www.giz.ai)
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
Requires Node.js 20.12 or later and a [giz.ai](https://www.giz.ai) account.
|
|
4
10
|
|
|
5
11
|
```bash
|
|
6
12
|
npm install -g @gizai/cli
|
|
7
|
-
giz
|
|
8
|
-
|
|
13
|
+
giz --version
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Update later with `giz update` (or `npm install -g @gizai/cli`).
|
|
17
|
+
|
|
18
|
+
## Quick start
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
giz auth login # opens your browser, one-time sign-in
|
|
22
|
+
giz chat gpt-6-luna "Say hello in Korean" # chat with a text model
|
|
9
23
|
giz generate image "A paper observatory at blue hour"
|
|
24
|
+
giz credits # check your balance
|
|
25
|
+
giz --help # every command
|
|
10
26
|
```
|
|
11
27
|
|
|
12
|
-
|
|
28
|
+
## Run any model
|
|
29
|
+
|
|
30
|
+
Discover a model's live inputs, upload local files, and run it:
|
|
13
31
|
|
|
14
32
|
```bash
|
|
15
33
|
giz model list --type video-generation
|
|
@@ -19,104 +37,89 @@ giz model run ltx2-distilled \
|
|
|
19
37
|
--upload image=./first-frame.png
|
|
20
38
|
```
|
|
21
39
|
|
|
22
|
-
|
|
40
|
+
Media jobs run independently. Track them with `giz job get JOB` or block with `giz job wait JOB` (exit status 1 if the job failed or was cancelled). Add `--json` to any command for machine-readable output on stdout; progress goes to stderr.
|
|
41
|
+
|
|
42
|
+
## Use Giz from Claude Code, Codex and other agents
|
|
43
|
+
|
|
44
|
+
Register the Giz MCP server with your agent (install the client first):
|
|
23
45
|
|
|
24
46
|
```bash
|
|
25
47
|
giz auth login
|
|
26
|
-
giz mcp add codex
|
|
27
48
|
giz mcp add claude
|
|
28
|
-
giz mcp
|
|
49
|
+
giz mcp add codex
|
|
50
|
+
giz mcp check --json # verifies the MCP handshake and lists tool names
|
|
29
51
|
```
|
|
30
52
|
|
|
31
|
-
|
|
32
|
-
MCP protocol and shares the CLI's rotating OAuth credentials. Tokens are not
|
|
33
|
-
copied into Claude or Codex configuration. A custom `GIZ_CONFIG` path is preserved.
|
|
53
|
+
This registers `giz mcp serve` over stdio. It forwards Giz's live MCP protocol and shares the CLI's credentials, so no token is copied into the client's configuration. For clients that run their own OAuth session, use `giz mcp add claude --transport http` (then sign in with `/mcp`) or `giz mcp add codex --transport http`. The remote endpoint is `https://www.giz.ai/api/mcp`; it supports OAuth discovery and scoped API keys.
|
|
34
54
|
|
|
35
|
-
|
|
36
|
-
and sign in through `/mcp`, or `giz mcp add codex --transport http`. The remote
|
|
37
|
-
endpoint also supports OAuth discovery and scoped API keys. A manually copied
|
|
38
|
-
OAuth access token expires after one hour; updating CLI credentials does not
|
|
39
|
-
update a static client header.
|
|
55
|
+
Install the Giz agent skill with `giz skill install`. The package root is also an [Agent Plugins](https://agent-plugins.org) 1.0 plugin (`plugin.json`, the `giz` skill and `mcp.json`), so a client that installs plugins gets the skill and the MCP server together.
|
|
40
56
|
|
|
41
|
-
|
|
57
|
+
## Drive, Computers and Apps
|
|
42
58
|
|
|
43
59
|
```bash
|
|
44
|
-
|
|
60
|
+
giz drive ls
|
|
61
|
+
giz drive read /notes/todo.md
|
|
62
|
+
giz computer list
|
|
63
|
+
giz computer exec --deadline-ms 120000 -- ls -la # up to 15 minutes; the remote exit code is preserved
|
|
64
|
+
giz app list
|
|
45
65
|
```
|
|
46
66
|
|
|
47
|
-
`giz
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
67
|
+
App changes are explicit: pass the `revision` shown by `giz app list` as `--expected-revision REVISION` to `run`, `publish` and `delete`, and as `expectedRevision` in the `--input` of `create` and `save` (use 0 for a new App). A concurrent change is rejected by the server instead of being overwritten.
|
|
68
|
+
|
|
69
|
+
Free Computers have a runtime limit; check your plan before starting long workflows. Signing in does not extend that runtime.
|
|
70
|
+
|
|
71
|
+
### Inside a Giz Computer
|
|
72
|
+
|
|
73
|
+
`giz` is already installed in every Giz Computer, and no login is needed: the Computer signs in as itself and can reach only its own Drive, model discovery and inference, and jobs it started. API keys, billing, organization administration, destructive operations and external writes need a separate user sign-in with `giz auth login`. `giz auth status` shows who you are.
|
|
52
74
|
|
|
53
|
-
|
|
75
|
+
## Plugins
|
|
54
76
|
|
|
55
77
|
```bash
|
|
56
|
-
giz skill
|
|
78
|
+
giz plugin search QUERY [--origin skill|mcp]
|
|
79
|
+
giz plugin install ID --query QUERY
|
|
80
|
+
giz plugin list
|
|
81
|
+
giz connection list # connected apps
|
|
57
82
|
```
|
|
58
83
|
|
|
59
|
-
|
|
60
|
-
`~/.config/giz/credentials.json` with mode `0600` (owner access only), using atomic
|
|
61
|
-
writes and serialized sign-in, refresh, and sign-out. Failed token revocation is
|
|
62
|
-
reported before local credentials are removed. It never stores a Giz password.
|
|
63
|
-
The sign-in callback binds a fresh loopback port; use the URL printed by the
|
|
64
|
-
current login. Progress goes to stderr, leaving `--json` stdout machine-readable.
|
|
84
|
+
Also available: `plugin inspect`, `update`, `remove`, `enable`, `disable`, `publish` and `unpublish`.
|
|
65
85
|
|
|
66
|
-
|
|
67
|
-
Refreshing an old grant cannot add this scope. `giz auth status --json` shows
|
|
68
|
-
granted scopes; a missing scope error names the required permission.
|
|
86
|
+
## Authentication and security
|
|
69
87
|
|
|
70
|
-
`giz
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
that runtime. Media jobs run independently and are tracked with `giz job get`.
|
|
88
|
+
- `giz auth login` uses browser OAuth with a loopback callback; the CLI never sees or stores your password.
|
|
89
|
+
- Credentials are stored as JSON in `~/.config/giz/credentials.json` with mode `0600` (owner only), written atomically. `GIZ_CONFIG` overrides the path. `giz auth logout` revokes the token and removes the file.
|
|
90
|
+
- `giz auth status --json` shows the granted scopes; a missing scope error names the permission it needs. After updating from 1.0.1, sign in again to grant `giz.inference`.
|
|
91
|
+
- Create a scoped API key with `giz api-key create "My app"` (the secret is shown once). Set `GIZ_TOKEN` only for short-lived automation.
|
|
92
|
+
- An OAuth access token copied by hand expires after one hour. Prefer `giz mcp add`, which refreshes it for you.
|
|
76
93
|
|
|
77
|
-
|
|
94
|
+
## Configuration
|
|
78
95
|
|
|
79
|
-
|
|
96
|
+
| Variable | Purpose |
|
|
97
|
+
| --- | --- |
|
|
98
|
+
| `GIZ_TOKEN` | Use this API key or token instead of the stored login |
|
|
99
|
+
| `GIZ_CONFIG` | Path of the credentials file |
|
|
100
|
+
| `GIZ_NO_UPDATE_CHECK=1` | Turn off the update notice (or set `updates.mode` to `off` in `credentials.json`) |
|
|
80
101
|
|
|
81
|
-
|
|
102
|
+
The update check is cached for up to 24 hours and prints only in interactive terminals.
|
|
82
103
|
|
|
83
|
-
|
|
84
|
-
`/opt/giz/managed/apps/giz-cli`, with `/opt/giz/managed/bin/giz` first on PATH.
|
|
85
|
-
No npm installation or browser login is needed inside a managed Computer:
|
|
104
|
+
## Upgrading from 1.x
|
|
86
105
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
106
|
+
Version 2.0 removes `giz capability` with no alias. Skills, MCP servers and Agents now install as one plugin.
|
|
107
|
+
|
|
108
|
+
| 1.x | 2.0 |
|
|
109
|
+
| --- | --- |
|
|
110
|
+
| `giz capability list` | `giz connection list` (connected apps), `giz plugin list` (installed plugins) |
|
|
111
|
+
| `giz capability search skill\|mcp QUERY` | `giz plugin search QUERY [--origin skill\|mcp]` |
|
|
112
|
+
| `giz capability install skill\|mcp ID --query QUERY` | `giz plugin install ID --query QUERY` |
|
|
113
|
+
| `giz capability update\|remove ID` | `giz plugin update\|remove NAME` |
|
|
92
114
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
token or API key for this identity. `giz auth status` displays
|
|
99
|
-
`컴퓨터 신원으로 로그인됨 (소유자 <email>)`. A saved `giz auth login` takes priority;
|
|
100
|
-
`giz auth logout` removes that user login and returns to the Computer identity.
|
|
101
|
-
Shared Computers can access only their own Drive, model discovery/inference, and
|
|
102
|
-
jobs started by that Computer. API key, billing, organization administration,
|
|
103
|
-
destructive operations and external writes require a separate user authorization.
|
|
104
|
-
The managed `giz --version` includes the Region source revision; npm installations
|
|
105
|
-
continue to report the package version. Existing Computers receive overlay updates
|
|
106
|
-
without recreation. The Region's normal release activation attaches identity sockets
|
|
107
|
-
for existing instances, and socket replacement remains visible through the directory mount.
|
|
108
|
-
|
|
109
|
-
App 변경은 `giz app list`에서 확인한 `revision`을 명시적으로 전달합니다.
|
|
110
|
-
`run`, `publish`, `delete`에는 `--expected-revision REVISION`이 필요합니다.
|
|
111
|
-
`create`/`save`의 `--input`에는 `id`와 `expectedRevision`을 넣습니다(새 앱은 0).
|
|
112
|
-
목록을 다시 읽어 개정 번호를 자동 대체하지 않으므로, 검토 뒤 다른 변경이 생기면 서버가 충돌을 거부합니다.
|
|
113
|
-
|
|
114
|
-
아래 표는 CLI 디스패처와 도구 item에서 생성합니다. 갱신 명령:
|
|
115
|
-
`GIZ_UPDATE_CLI_SURFACE=1 pnpm --filter giz-app-giz test --runInBand --runTestsByPath server/external/cli-surface.spec.ts`.
|
|
116
|
-
일반 CI 실행은 문서를 쓰지 않고 표의 차이를 실패로 보고합니다.
|
|
115
|
+
New in 2.0: `plugin inspect`, `install --path`, `enable`, `disable`, `publish` and `unpublish`. A Giz server that supports plugins reports 2.0.0 as its minimum CLI, so 1.x prints an update warning there.
|
|
116
|
+
|
|
117
|
+
## Command reference
|
|
118
|
+
|
|
119
|
+
Generated from the CLI dispatcher and the Giz tool descriptors.
|
|
117
120
|
|
|
118
121
|
<!-- cli-surface:start -->
|
|
119
|
-
|
|
|
122
|
+
| Command | Tool ID | MCP tool | Required input | Scope | Agent discovery |
|
|
120
123
|
| --- | --- | --- | --- | --- | --- |
|
|
121
124
|
| model list | model.list | model_list | - | giz.read | model.list |
|
|
122
125
|
| model get | model.get | model_get | model | giz.read | model.get |
|
|
@@ -130,6 +133,7 @@ App 변경은 `giz app list`에서 확인한 `revision`을 명시적으로 전
|
|
|
130
133
|
| job get | job.get | job_get | job | giz.read | server job |
|
|
131
134
|
| job wait | job.get | job_get | job | giz.read | server job |
|
|
132
135
|
| job cancel | job.cancel | job_cancel | job | giz.destructive | server job |
|
|
136
|
+
| credits | account.credits | account_credits | - | giz.read | account.credits |
|
|
133
137
|
| drive ls | drive.list | drive_list | - | giz.read | drive.list |
|
|
134
138
|
| drive list | drive.list | drive_list | - | giz.read | drive.list |
|
|
135
139
|
| drive search | drive.search | drive_search | query | giz.read | drive.search |
|
|
@@ -155,12 +159,26 @@ App 변경은 `giz app list`에서 확인한 `revision`을 명시적으로 전
|
|
|
155
159
|
| app publish | app.publish | app_publish | id, expectedRevision, visibility | giz.write | app.publish |
|
|
156
160
|
| app open | app.open | app_open | id | giz.read | app.open |
|
|
157
161
|
| app delete | app.delete | app_delete | id, expectedRevision | giz.destructive | app.delete |
|
|
158
|
-
|
|
|
159
|
-
|
|
|
160
|
-
|
|
|
161
|
-
|
|
|
162
|
-
|
|
|
162
|
+
| plugin list | plugin.catalog | plugin_catalog | - | giz.read | plugin.catalog |
|
|
163
|
+
| plugin search | plugin.catalog | plugin_catalog | - | giz.read | plugin.catalog |
|
|
164
|
+
| plugin inspect | plugin.catalog | plugin_catalog | - | giz.read | plugin.catalog |
|
|
165
|
+
| plugin install | plugin.install | plugin_install | - | giz.execute | plugin.install |
|
|
166
|
+
| plugin update | plugin.manage | plugin_manage | operation | giz.destructive | plugin.manage |
|
|
167
|
+
| plugin enable | plugin.manage | plugin_manage | operation | giz.destructive | plugin.manage |
|
|
168
|
+
| plugin disable | plugin.manage | plugin_manage | operation | giz.destructive | plugin.manage |
|
|
169
|
+
| plugin remove | plugin.manage | plugin_manage | operation | giz.destructive | plugin.manage |
|
|
170
|
+
| plugin publish | plugin.manage | plugin_manage | operation | giz.destructive | plugin.manage |
|
|
171
|
+
| plugin unpublish | plugin.manage | plugin_manage | operation | giz.destructive | plugin.manage |
|
|
172
|
+
| connection list | capability.status | capability_status | - | giz.read | capability.status |
|
|
163
173
|
| agent start | agent.start | agent_start | agentId, prompt | giz.execute | external only |
|
|
164
174
|
| agent status | agent.status | agent_status | turnId | giz.read | agent.status |
|
|
165
175
|
| agent cancel | agent.cancel | agent_cancel | turnId | giz.execute | agent.cancel |
|
|
166
176
|
<!-- cli-surface:end -->
|
|
177
|
+
|
|
178
|
+
## Support
|
|
179
|
+
|
|
180
|
+
Questions and bug reports: [support@giz.ai](mailto:support@giz.ai) or the Support Forum at [giz.ai](https://www.giz.ai).
|
|
181
|
+
|
|
182
|
+
## License
|
|
183
|
+
|
|
184
|
+
Proprietary. Copyright Giz Inc. All rights reserved. Use of the service is governed by the [Terms of Use](https://www.giz.ai/terms-of-use).
|
|
@@ -33,18 +33,18 @@ export async function computerIdentity(rejectedToken) {
|
|
|
33
33
|
res.setEncoding('utf8')
|
|
34
34
|
res.on('data', chunk => {
|
|
35
35
|
body += chunk
|
|
36
|
-
if (body.length > 16_384) req.destroy(new Error('
|
|
36
|
+
if (body.length > 16_384) req.destroy(new Error('The Computer identity response is too large.'))
|
|
37
37
|
})
|
|
38
38
|
res.on('error', reject)
|
|
39
39
|
res.on('end', () => {
|
|
40
40
|
try {
|
|
41
41
|
const value = JSON.parse(body)
|
|
42
|
-
if (res.statusCode !== 200) throw new Error(value.error_description || value.message || '
|
|
42
|
+
if (res.statusCode !== 200) throw new Error(value.error_description || value.message || 'The Computer identity is unavailable.')
|
|
43
43
|
const url = new URL(value.baseUrl)
|
|
44
44
|
if (!['http:', 'https:'].includes(url.protocol) || url.username || url.password ||
|
|
45
45
|
url.pathname !== '/' || url.search || url.hash || !value.access_token ||
|
|
46
46
|
value.token_type !== 'Bearer' || Number(value.expires_in) <= 0 || Number(value.expires_in) > 900) {
|
|
47
|
-
throw new Error('
|
|
47
|
+
throw new Error('The Computer identity response is invalid.')
|
|
48
48
|
}
|
|
49
49
|
cached = { access_token: value.access_token, baseUrl: url.origin,
|
|
50
50
|
expires_at: Date.now() + Number(value.expires_in) * 1000 }
|
|
@@ -56,20 +56,20 @@ export async function computerIdentity(rejectedToken) {
|
|
|
56
56
|
if (error.code !== 'ENOENT') return reject(error)
|
|
57
57
|
try {
|
|
58
58
|
await lstat(socketPath)
|
|
59
|
-
reject(new Error('
|
|
59
|
+
reject(new Error('Cannot reach the Computer identity service. Try again shortly.'))
|
|
60
60
|
} catch (lookupError) {
|
|
61
61
|
if (lookupError.code !== 'ENOENT') return reject(lookupError)
|
|
62
62
|
try {
|
|
63
63
|
if (await managedRevision() !== undefined) {
|
|
64
|
-
reject(new Error('
|
|
64
|
+
reject(new Error('Cannot verify the Computer identity. Try again shortly or contact the owner.'))
|
|
65
65
|
} else resolve(undefined)
|
|
66
66
|
} catch (error) { reject(error) }
|
|
67
67
|
}
|
|
68
68
|
})
|
|
69
|
-
req.setTimeout(10_000, () => req.destroy(new Error('
|
|
69
|
+
req.setTimeout(10_000, () => req.destroy(new Error('The Computer identity response timed out.')))
|
|
70
70
|
req.end()
|
|
71
71
|
})).catch(error => {
|
|
72
|
-
error.hint = '
|
|
72
|
+
error.hint = 'Check that the Computer is running and try again; if it is blocked, contact the owner or an organization admin.'
|
|
73
73
|
throw error
|
|
74
74
|
}).finally(() => { pending = undefined })
|
|
75
75
|
return pending
|
package/cli/giz.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { computerIdentity, managedRevision } from './computer-identity.mjs'
|
|
3
|
+
import { checkForUpdate, explicitUpdate, installSource, maybeNotify } from './update.mjs'
|
|
3
4
|
import { createHash, randomBytes } from 'node:crypto'
|
|
4
5
|
import { openAsBlob } from 'node:fs'
|
|
5
6
|
import { mkdir, readFile, rename, unlink, writeFile } from 'node:fs/promises'
|
|
@@ -133,7 +134,7 @@ async function credentials(baseUrl, rejectedToken) {
|
|
|
133
134
|
if (!config?.access_token) {
|
|
134
135
|
const computer = await computerIdentity(rejectedToken)
|
|
135
136
|
if (!computer) throw new CliError('Not authenticated.', 'Run: giz auth login')
|
|
136
|
-
if (computer.baseUrl !== baseUrl) throw new CliError('
|
|
137
|
+
if (computer.baseUrl !== baseUrl) throw new CliError('A Computer identity cannot be used with another server.', 'Run giz auth login with your user account.')
|
|
137
138
|
return computer
|
|
138
139
|
}
|
|
139
140
|
if (String(config.baseUrl).replace(/\/+$/, '') !== baseUrl) {
|
|
@@ -190,10 +191,10 @@ async function jsonResponse(response, baseUrl) {
|
|
|
190
191
|
if (response.status === 404 && (payload?.code === 'EXTERNAL_TOOL_UNAVAILABLE' ||
|
|
191
192
|
(new URL(response.url).pathname.startsWith('/api/tools/') && /^Unknown Giz tool: /.test(message)))) {
|
|
192
193
|
const compatibility = payload?.code === 'EXTERNAL_TOOL_UNAVAILABLE'
|
|
193
|
-
? message : '
|
|
194
|
+
? message : 'The server version is unknown (older server).'
|
|
194
195
|
throw new CliError(
|
|
195
|
-
|
|
196
|
-
|
|
196
|
+
`This server does not support the requested command. CLI ${CLI_VERSION}. ${compatibility}`,
|
|
197
|
+
`Check the server address (${baseUrl}) and its supported version; choose a supporting server with --base-url.`,
|
|
197
198
|
response.status
|
|
198
199
|
)
|
|
199
200
|
}
|
|
@@ -342,8 +343,9 @@ async function waitForCallback(expectedState) {
|
|
|
342
343
|
}
|
|
343
344
|
|
|
344
345
|
function openBrowser(url) {
|
|
345
|
-
|
|
346
|
-
const
|
|
346
|
+
// Not `cmd /c start`: cmd splits the URL at its first `&`, so Windows sign-in lost client_id and every later parameter.
|
|
347
|
+
const command = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'rundll32' : 'xdg-open'
|
|
348
|
+
const args = process.platform === 'win32' ? ['url.dll,FileProtocolHandler', url] : [url]
|
|
347
349
|
const child = spawn(command, args, { detached: true, stdio: 'ignore' })
|
|
348
350
|
child.on('error', () => {})
|
|
349
351
|
child.unref()
|
|
@@ -404,11 +406,11 @@ async function applyUploads(baseUrl, input, values = []) {
|
|
|
404
406
|
function appRevision(options) {
|
|
405
407
|
const raw = options['expected-revision']
|
|
406
408
|
if (raw === undefined || raw === '') {
|
|
407
|
-
throw new CliError('
|
|
409
|
+
throw new CliError('A revision is required.', 'Pass the revision from giz app list as --expected-revision.')
|
|
408
410
|
}
|
|
409
411
|
const revision = Number(raw)
|
|
410
412
|
if (typeof raw !== 'string' || !/^\d+$/.test(raw) || !Number.isSafeInteger(revision) || revision < 1 || revision > 9_007_199_254_740_990) {
|
|
411
|
-
throw new CliError('
|
|
413
|
+
throw new CliError('The revision must be a safe integer of 1 or more.', 'Check the current revision with giz app list.')
|
|
412
414
|
}
|
|
413
415
|
return revision
|
|
414
416
|
}
|
|
@@ -446,11 +448,26 @@ async function serveMcp(baseUrl) {
|
|
|
446
448
|
|
|
447
449
|
async function runCommand(baseUrl, positionals, options) {
|
|
448
450
|
const [command, subcommand, ...rest] = positionals
|
|
451
|
+
if (command === '__update-check') {
|
|
452
|
+
await checkForUpdate({ file: options.cache, url: options.registry })
|
|
453
|
+
return undefined
|
|
454
|
+
}
|
|
455
|
+
if (command === 'update' && options.help === true) return { kind: 'help', value: help('update') }
|
|
456
|
+
if (command === 'update' && !subcommand) {
|
|
457
|
+
const result = await explicitUpdate({ version: CLI_VERSION, source: installSource() })
|
|
458
|
+
return { kind: 'message', value: result.message }
|
|
459
|
+
}
|
|
449
460
|
if (options.version === true) {
|
|
450
461
|
const revision = await managedRevision()
|
|
451
462
|
return { kind: 'message', value: CLI_VERSION + (revision ? ` (region ${revision.trim()})` : '') }
|
|
452
463
|
}
|
|
453
|
-
if (!command || command === 'help' || options.help === true)
|
|
464
|
+
if (!command || command === 'help' || options.help === true) {
|
|
465
|
+
// A script that asks for help on a command that does not exist must fail, not read the overview as success.
|
|
466
|
+
if (command && command !== 'help' && !help().split('\n').some((line) => line.trim().split(' ')[1] === command && line.startsWith(' giz '))) {
|
|
467
|
+
throw new CliError(`Unknown command "${command}".`, 'Run: giz --help')
|
|
468
|
+
}
|
|
469
|
+
return { kind: 'help', value: help(command) }
|
|
470
|
+
}
|
|
454
471
|
if (command === 'engine' && subcommand === 'run') {
|
|
455
472
|
if (rest[0] !== 'claude') throw new CliError('Only Claude Code is an engine connection.')
|
|
456
473
|
await api(baseUrl, '/api/external/engine/claude/authorization')
|
|
@@ -505,6 +522,11 @@ async function runCommand(baseUrl, positionals, options) {
|
|
|
505
522
|
}
|
|
506
523
|
}
|
|
507
524
|
|
|
525
|
+
if (command === 'credits') {
|
|
526
|
+
// Batch scripts read the balance before paid work instead of learning it from a refusal (MCP-TOOL-SCHEMA-LIMITS).
|
|
527
|
+
if (subcommand) throw new CliError(`Unknown command "credits ${subcommand}".`, 'Run: giz credits')
|
|
528
|
+
return { kind: 'result', value: await invoke(baseUrl, 'account.credits', {}) }
|
|
529
|
+
}
|
|
508
530
|
if (command === 'model' && subcommand === 'list') {
|
|
509
531
|
return {
|
|
510
532
|
kind: 'models',
|
|
@@ -638,6 +660,11 @@ async function runCommand(baseUrl, positionals, options) {
|
|
|
638
660
|
if (command === 'table' && subcommand === 'action') {
|
|
639
661
|
const view = required(rest[0], 'TABLE', 'Run: giz table action TABLE ACTION [--id ID] --input JSON')
|
|
640
662
|
const action = required(rest[1], 'ACTION', 'Run: giz table get TABLE to see its actions')
|
|
663
|
+
// Namespaced table tools use their canonical external contract and table ownership checks.
|
|
664
|
+
if (action.startsWith('table.')) {
|
|
665
|
+
if (options.id !== undefined) throw new CliError('Table tools do not take --id.', 'Put row IDs in --input.')
|
|
666
|
+
return { kind: 'result', value: await invoke(baseUrl, action, { ...jsonInput(options.input), table: view }) }
|
|
667
|
+
}
|
|
641
668
|
const id = options.id === undefined ? undefined : String(options.id).includes(',') ? String(options.id).split(',') : String(options.id)
|
|
642
669
|
return {
|
|
643
670
|
kind: 'result',
|
|
@@ -716,7 +743,7 @@ async function runCommand(baseUrl, positionals, options) {
|
|
|
716
743
|
throw new CliError(`Unknown app command "${subcommand || ''}".`, 'Run: giz app --help')
|
|
717
744
|
}
|
|
718
745
|
|
|
719
|
-
if (command === '
|
|
746
|
+
if (command === 'connection') {
|
|
720
747
|
if (subcommand === 'list') {
|
|
721
748
|
return {
|
|
722
749
|
kind: 'result',
|
|
@@ -725,44 +752,65 @@ async function runCommand(baseUrl, positionals, options) {
|
|
|
725
752
|
})
|
|
726
753
|
}
|
|
727
754
|
}
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
755
|
+
throw new CliError(`Unknown connection command "${subcommand || ''}".`, 'Run: giz connection --help')
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
if (command === 'plugin') {
|
|
759
|
+
const computer = options.computer ? { computer: options.computer } : {}
|
|
760
|
+
if (subcommand === 'list' || subcommand === 'search') {
|
|
761
|
+
const query = subcommand === 'search'
|
|
762
|
+
? required(rest.join(' '), 'QUERY', 'Run: giz plugin search QUERY [--origin catalog|skill|mcp]')
|
|
763
|
+
: undefined
|
|
731
764
|
return {
|
|
732
765
|
kind: 'result',
|
|
733
|
-
value: await invoke(baseUrl, '
|
|
734
|
-
|
|
735
|
-
query,
|
|
736
|
-
...(options.limit ? { limit: Number(options.limit) } : {})
|
|
766
|
+
value: await invoke(baseUrl, 'plugin.catalog', {
|
|
767
|
+
...(query ? { query } : { origin: 'installed' }),
|
|
768
|
+
...(query && options.origin ? { origin: options.origin } : {}),
|
|
769
|
+
...(options.limit ? { limit: Number(options.limit) } : {}),
|
|
770
|
+
...computer
|
|
737
771
|
})
|
|
738
772
|
}
|
|
739
773
|
}
|
|
774
|
+
if (subcommand === 'inspect') {
|
|
775
|
+
const drivePath = required(rest[0], 'PATH', 'Run: giz plugin inspect DRIVE_PATH')
|
|
776
|
+
return { kind: 'result', value: await invoke(baseUrl, 'plugin.catalog', { path: drivePath, ...computer }) }
|
|
777
|
+
}
|
|
740
778
|
if (subcommand === 'install') {
|
|
741
|
-
const
|
|
742
|
-
|
|
743
|
-
|
|
779
|
+
const source = options.path
|
|
780
|
+
? { path: options.path }
|
|
781
|
+
: { id: required(rest[0], 'ID', 'Run: giz plugin install ID --query QUERY, or giz plugin install --path DRIVE_PATH') }
|
|
744
782
|
return {
|
|
745
783
|
kind: 'result',
|
|
746
|
-
value: await invoke(baseUrl, '
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
...(options.computer ? { computer: options.computer } : {})
|
|
784
|
+
value: await invoke(baseUrl, 'plugin.install', {
|
|
785
|
+
...source,
|
|
786
|
+
...(options.query ? { query: options.query } : {}),
|
|
787
|
+
...computer
|
|
751
788
|
})
|
|
752
789
|
}
|
|
753
790
|
}
|
|
754
|
-
if (
|
|
755
|
-
const
|
|
791
|
+
if (['update', 'enable', 'disable', 'remove'].includes(subcommand)) {
|
|
792
|
+
const name = required(rest[0], 'NAME', `Run: giz plugin ${subcommand} NAME`)
|
|
793
|
+
return { kind: 'result', value: await invoke(baseUrl, 'plugin.manage', { operation: subcommand, name, ...computer }) }
|
|
794
|
+
}
|
|
795
|
+
if (subcommand === 'publish') {
|
|
796
|
+
const drivePath = required(rest[0], 'PATH', 'Run: giz plugin publish DRIVE_PATH --visibility organization|public')
|
|
797
|
+
const visibility = required(options.visibility, 'VISIBILITY', 'Add --visibility organization|public.')
|
|
756
798
|
return {
|
|
757
799
|
kind: 'result',
|
|
758
|
-
value: await invoke(baseUrl, '
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
800
|
+
value: await invoke(baseUrl, 'plugin.manage', {
|
|
801
|
+
operation: 'publish',
|
|
802
|
+
path: drivePath,
|
|
803
|
+
visibility,
|
|
804
|
+
...(options.organization ? { organizationId: options.organization } : {}),
|
|
805
|
+
...computer
|
|
762
806
|
})
|
|
763
807
|
}
|
|
764
808
|
}
|
|
765
|
-
|
|
809
|
+
if (subcommand === 'unpublish') {
|
|
810
|
+
const releaseId = required(rest[0], 'RELEASE', 'Run: giz plugin unpublish RELEASE')
|
|
811
|
+
return { kind: 'result', value: await invoke(baseUrl, 'plugin.manage', { operation: 'unpublish', releaseId }) }
|
|
812
|
+
}
|
|
813
|
+
throw new CliError(`Unknown plugin command "${subcommand || ''}".`, 'Run: giz plugin --help')
|
|
766
814
|
}
|
|
767
815
|
|
|
768
816
|
if (command === 'agent') {
|
|
@@ -853,7 +901,7 @@ function print(kind, value, json, output = process.stdout) {
|
|
|
853
901
|
return
|
|
854
902
|
}
|
|
855
903
|
if (kind === 'auth' && value.identity?.type === 'computer') {
|
|
856
|
-
output.write(
|
|
904
|
+
output.write(`Signed in as a Computer identity (owner ${value.email || value.name})\n`)
|
|
857
905
|
return
|
|
858
906
|
}
|
|
859
907
|
if (kind === 'models') {
|
|
@@ -897,6 +945,11 @@ Progress and the final diff, files and summary are returned. Interrupting stops
|
|
|
897
945
|
giz api-key revoke KEY_ID
|
|
898
946
|
|
|
899
947
|
The secret is shown only when the key is created.`
|
|
948
|
+
if (command === 'credits') return `Usage
|
|
949
|
+
giz credits
|
|
950
|
+
|
|
951
|
+
Prints your remaining credit (purchased and plan), when plan credit resets, and this month's spend and charges.
|
|
952
|
+
In a workspace it prints the workspace's monthly budget. Read it before paid batch work.`
|
|
900
953
|
if (command === 'chat') return `Usage
|
|
901
954
|
giz chat MODEL "your prompt"
|
|
902
955
|
giz chat MODEL --input '{"messages":[{"role":"user","content":"Hello"}]}'`
|
|
@@ -939,7 +992,7 @@ Generation returns a job immediately; use giz job wait JOB_ID for its result.`
|
|
|
939
992
|
|
|
940
993
|
TABLE is a table's Drive path (for example Sales/Customers.view.ts) or a business object name from giz table list
|
|
941
994
|
(for example task, issue, requirement). giz table get shows its fields, the row changes it accepts (writes) and its
|
|
942
|
-
actions; an object without a write changes only through its actions. Use --org to work in an organization.
|
|
995
|
+
actions. Namespaced table actions (such as table.updateSchema) use the table tool contract; an object without a write changes only through its actions. Use --org to work in an organization.
|
|
943
996
|
read input: {"select":["name"],"filters":[{"field":"status","operator":"eq","value":"open"}],"limit":50}
|
|
944
997
|
write input: {"create":[{"name":"Acme"}],"update":[{"id":"ROW_ID","status":"done"}],"remove":["ROW_ID"]}
|
|
945
998
|
One write is one change people can undo in the table. At most 200 rows per write.`
|
|
@@ -954,11 +1007,19 @@ One write is one change people can undo in the table. At most 200 rows per write
|
|
|
954
1007
|
giz app publish APP_ID private|workspace|public --expected-revision REVISION [--computer COMPUTER]
|
|
955
1008
|
giz app open APP_ID [--computer COMPUTER]
|
|
956
1009
|
giz app delete APP_ID --expected-revision REVISION [--computer COMPUTER]`
|
|
957
|
-
if (command === '
|
|
958
|
-
giz
|
|
959
|
-
giz
|
|
960
|
-
giz
|
|
961
|
-
giz
|
|
1010
|
+
if (command === 'plugin') return `Usage
|
|
1011
|
+
giz plugin list [--computer COMPUTER]
|
|
1012
|
+
giz plugin search QUERY [--origin catalog|skill|mcp] [--limit N]
|
|
1013
|
+
giz plugin inspect DRIVE_PATH
|
|
1014
|
+
giz plugin install ID --query QUERY [--computer COMPUTER]
|
|
1015
|
+
giz plugin install --path DRIVE_PATH [--computer COMPUTER]
|
|
1016
|
+
giz plugin update|enable|disable|remove NAME [--computer COMPUTER]
|
|
1017
|
+
giz plugin publish DRIVE_PATH --visibility organization|public [--organization ORG]
|
|
1018
|
+
giz plugin unpublish RELEASE
|
|
1019
|
+
|
|
1020
|
+
A plugin (Agent Plugins 1.0) bundles skills, MCP servers and Agents; it is what you install, turn off and share.`
|
|
1021
|
+
if (command === 'connection') return `Usage
|
|
1022
|
+
giz connection list [--computer COMPUTER]`
|
|
962
1023
|
if (command === 'agent') return `Usage
|
|
963
1024
|
giz agent start [--computer COMPUTER] --input JSON
|
|
964
1025
|
giz agent status TURN [--wait]
|
|
@@ -971,6 +1032,7 @@ One write is one change people can undo in the table. At most 200 rows per write
|
|
|
971
1032
|
|
|
972
1033
|
stdio (default) shares giz auth login and refreshes tokens automatically.
|
|
973
1034
|
http uses the client's own OAuth login. Install the chosen client first.`
|
|
1035
|
+
if (command === 'update') return `Usage\n giz update\n\nUpdates @gizai/cli with its owning package manager.`
|
|
974
1036
|
if (command === 'auth') return `Usage
|
|
975
1037
|
giz auth login [--device]
|
|
976
1038
|
giz auth status
|
|
@@ -979,6 +1041,7 @@ http uses the client's own OAuth login. Install the chosen client first.`
|
|
|
979
1041
|
|
|
980
1042
|
Usage
|
|
981
1043
|
giz auth login [--device]
|
|
1044
|
+
giz update
|
|
982
1045
|
giz api-key list|create|revoke
|
|
983
1046
|
giz chat MODEL "your prompt"
|
|
984
1047
|
giz model list [--type TYPE] [--search TEXT]
|
|
@@ -987,12 +1050,14 @@ Usage
|
|
|
987
1050
|
giz generate image|video|music|talking-head "PROMPT" [--model MODEL]
|
|
988
1051
|
giz generate audio --input JSON [--model MODEL]
|
|
989
1052
|
giz job list|get|wait|cancel [JOB]
|
|
1053
|
+
giz credits
|
|
990
1054
|
giz drive ls|list|search|read|write|mkdir|move|delete
|
|
991
1055
|
giz table list|get|read|write|action
|
|
992
1056
|
giz upload LOCAL_PATH
|
|
993
1057
|
giz computer list|get|start|stop|exec
|
|
994
1058
|
giz app list|create|save|run|publish|open|delete
|
|
995
|
-
giz
|
|
1059
|
+
giz plugin list|search|inspect|install|update|enable|disable|remove|publish|unpublish
|
|
1060
|
+
giz connection list
|
|
996
1061
|
giz agent start|status|cancel
|
|
997
1062
|
giz engine run claude "instruction" [--dir path]
|
|
998
1063
|
giz mcp url|serve|check|add
|
|
@@ -1012,9 +1077,17 @@ Docs: https://www.giz.ai/mcp/`
|
|
|
1012
1077
|
|
|
1013
1078
|
async function main() {
|
|
1014
1079
|
const { positionals, options } = parse(process.argv.slice(2))
|
|
1080
|
+
if (positionals[0] === '__update-check') {
|
|
1081
|
+
await runCommand('', positionals, options)
|
|
1082
|
+
return
|
|
1083
|
+
}
|
|
1084
|
+
const source = installSource()
|
|
1015
1085
|
const saved = await readConfig()
|
|
1086
|
+
const updateMode = ['notify', 'off'].includes(saved?.updates?.mode) ? saved.updates.mode : 'notify'
|
|
1087
|
+
void maybeNotify({ version: CLI_VERSION, source, mode: updateMode, env: { ...process.env, GIZ_JSON: options.json === true ? '1' : process.env.GIZ_JSON } }).catch(() => {})
|
|
1016
1088
|
const requiresAuth = positionals.length && !options.help && !options.version &&
|
|
1017
|
-
!(positionals[0] === 'auth' && ['login', 'logout'].includes(positionals[1]))
|
|
1089
|
+
!(positionals[0] === 'auth' && ['login', 'logout'].includes(positionals[1])) &&
|
|
1090
|
+
!['update', '__update-check'].includes(positionals[0])
|
|
1018
1091
|
const computer = requiresAuth && !process.env.GIZ_TOKEN && !saved?.access_token ? await computerIdentity() : undefined
|
|
1019
1092
|
const baseUrl = String(options['base-url'] || process.env.GIZ_URL || saved?.baseUrl || computer?.baseUrl || DEFAULT_URL).replace(/\/+$/, '')
|
|
1020
1093
|
if (typeof options.org === 'string') process.env.GIZ_ORGANIZATION = options.org
|