@weftlabs/cli 0.25.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 +186 -0
- package/bin/weft.mjs +5 -0
- package/dist/cli.d.ts +26 -0
- package/dist/cli.js +1104 -0
- package/dist/cli.js.map +1 -0
- package/dist/weft-skill/SKILL.md +220 -0
- package/dist/weft-skill/rules/cli.md +96 -0
- package/examples/agent-bootstrap.sh +69 -0
- package/examples/cli-quickstart.sh +7 -0
- package/package.json +55 -0
- package/scripts/install-skill.mjs +273 -0
- package/scripts/skill-paths.mjs +42 -0
package/README.md
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# Weft CLI
|
|
2
|
+
|
|
3
|
+
Use Weft from a shell or an autonomous agent. Application code should use the
|
|
4
|
+
separate [`@weftlabs/sdk`](../typescript/README.md) package.
|
|
5
|
+
|
|
6
|
+
The CLI prints one versioned JSON object per command. It accepts credentials
|
|
7
|
+
through `--api-key-stdin`, `WEFT_API_KEY`, or its protected local credential
|
|
8
|
+
store; it rejects API keys in command arguments so they do not leak into shell
|
|
9
|
+
history or process listings.
|
|
10
|
+
`weft --help` and `weft <command> --help` return machine-readable JSON without
|
|
11
|
+
requiring authentication.
|
|
12
|
+
|
|
13
|
+
## With a buyer API key
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
export WEFT_API_KEY="your-buyer-api-key"
|
|
17
|
+
npx --package @weftlabs/cli weft me
|
|
18
|
+
npx --package @weftlabs/cli weft search "weather data API"
|
|
19
|
+
npx --package @weftlabs/cli weft fetch "https://merchant.example/data" \
|
|
20
|
+
--max-cost-usd 0.05
|
|
21
|
+
npx --package @weftlabs/cli weft --help
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Fetch results
|
|
25
|
+
|
|
26
|
+
One `weft fetch` call saves the exact response bytes before it prints its JSON
|
|
27
|
+
result. The default fetch output uses `schema_version: "2"`. The `meta` object
|
|
28
|
+
comes before the body and contains `saved_path` (an absolute path), `byte_count`,
|
|
29
|
+
`receipt_path`, and `idempotency_key`. The `data` object retains the SDK receipt
|
|
30
|
+
fields, including `status`, `headers`, `paidUsd`, `heldUsd`, `paymentStatus`, and
|
|
31
|
+
`artifactId`.
|
|
32
|
+
|
|
33
|
+
For text and JSON with valid UTF-8, `data.body` contains the complete original
|
|
34
|
+
text and `data.body_encoding` is `"utf-8"`. JSON is kept as text, so number
|
|
35
|
+
precision, duplicate keys, whitespace, and a UTF-8 BOM are preserved. The body
|
|
36
|
+
is escaped as a string in the outer JSON object. `data.media_type` identifies
|
|
37
|
+
its media type. Binary, compressed, invalid UTF-8, and other non-text responses
|
|
38
|
+
use `data.body_encoding: "file"` and omit `body`. Read `meta.saved_path` to use
|
|
39
|
+
those bytes. Reading the local file does not make a request or spend money.
|
|
40
|
+
|
|
41
|
+
Results are saved under `$HOME/.weft-results/result-<random>/` by default
|
|
42
|
+
(`USERPROFILE` or the operating system home is used when `HOME` is absent).
|
|
43
|
+
Set `WEFT_RESULTS_DIR` to use another storage directory. On Unix, that directory
|
|
44
|
+
must belong to your user and must not be writable by another user. The storage
|
|
45
|
+
path itself must not be a symlink. Each result directory has mode `0700`; its
|
|
46
|
+
`body` and `receipt.json` files have mode `0600`. The receipt file contains
|
|
47
|
+
metadata and the retry key, with no copy of the response body. Upstream filenames
|
|
48
|
+
do not determine the local path. Payloads are never made executable.
|
|
49
|
+
|
|
50
|
+
The CLI never deletes saved results. Remove individual result directories when
|
|
51
|
+
you no longer need them. A failed call can leave an empty directory or a partial
|
|
52
|
+
file. Do not use a file from a failed delivery as a complete result.
|
|
53
|
+
|
|
54
|
+
If the CLI cannot reserve a directory, it returns
|
|
55
|
+
`RESULT_STORAGE_UNAVAILABLE` before it sends the fetch. If storage fails after
|
|
56
|
+
fetch, it returns `RESULT_STORAGE_FAILED` on stderr with exit code `5`, the
|
|
57
|
+
receipt, and the same retry key. This is a local delivery failure; the receipt
|
|
58
|
+
still describes the payment state. Fix storage and retry the same URL, method,
|
|
59
|
+
and cost limit with `--idempotency-key` set to that key. The CLI does not retry
|
|
60
|
+
or purchase again automatically. Keep the same key after any uncertain result;
|
|
61
|
+
the server's existing retry rules and expiry still apply.
|
|
62
|
+
|
|
63
|
+
Invalid Base64 from the API returns `RESULT_DECODE_FAILED` with the receipt and
|
|
64
|
+
retry key; the CLI does not claim that damaged bytes were delivered. If stdout
|
|
65
|
+
fails, for example because a pipe closes, `RESULT_OUTPUT_FAILED` on stderr keeps
|
|
66
|
+
the receipt and saved paths. Read the saved file to recover without another
|
|
67
|
+
fetch. These delivery errors use exit code `5`.
|
|
68
|
+
|
|
69
|
+
Existing scripts can select `weft fetch ... --raw`. This retains the version 1
|
|
70
|
+
SDK envelope with `data.bodyBase64` and does not save local files. Other commands
|
|
71
|
+
retain their version 1 output. There is one fetch operation for every body size.
|
|
72
|
+
Hosts can still limit the text shown to a model; use the saved path when stdout
|
|
73
|
+
is clipped.
|
|
74
|
+
|
|
75
|
+
## With no credential: agent bootstrap and human claim
|
|
76
|
+
|
|
77
|
+
An agent that has no Weft credential can start by itself. The flow needs the
|
|
78
|
+
human's email address and nothing else. There is no promotional balance, free
|
|
79
|
+
credit, or subsidy: paid fetch spends the human's own funded wallet, and the
|
|
80
|
+
wallet is funded by the human after the claim.
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
npm install -g @weftlabs/cli
|
|
84
|
+
|
|
85
|
+
# 1. Ask the human for an email address. Never ask for a password.
|
|
86
|
+
# 2. Create the temporary bootstrap and send the claim email.
|
|
87
|
+
weft bootstrap --email "human@example.com" \
|
|
88
|
+
--agent-name "Research agent" \
|
|
89
|
+
--reason "Find weather data"
|
|
90
|
+
|
|
91
|
+
# 3. Search immediately, before the human does anything.
|
|
92
|
+
weft search "weather data API"
|
|
93
|
+
|
|
94
|
+
# 4. Tell the human to open the claim email and approve the agent.
|
|
95
|
+
# 5. Poll at the interval the bootstrap response returned.
|
|
96
|
+
weft auth status
|
|
97
|
+
|
|
98
|
+
# 6. After approval the CLI exchanges OAuth device tokens for the temporary
|
|
99
|
+
# credential, and normal authenticated commands work again.
|
|
100
|
+
weft me
|
|
101
|
+
|
|
102
|
+
# 7. Ask the human to fund the wallet before any paid fetch.
|
|
103
|
+
weft balance
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### The `weft` Skill
|
|
107
|
+
|
|
108
|
+
Installing the package does not write to the machine. Install the `weft` Skill
|
|
109
|
+
(`SKILL.md` plus `rules/cli.md`, vendored from
|
|
110
|
+
[weftlabs/skills](https://github.com/weftlabs/skills)) with:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
weft skill install
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Any ordinary command installs it too, so an agent that runs `weft search`
|
|
117
|
+
before anyone reads this section still gets the Skill. Both paths are the same
|
|
118
|
+
idempotent operation, and running either again is safe.
|
|
119
|
+
|
|
120
|
+
Install one optional Weft workflow Skill for a specific agent host with:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
weft skill install weft-flights-search --agent codex
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Add `--global` to install it for all projects for that host. Named workflow
|
|
127
|
+
installs do not need Weft authentication. They delegate to the public Skills
|
|
128
|
+
CLI and keep its installation layout and host support.
|
|
129
|
+
|
|
130
|
+
Earlier versions installed the Skill from an `npm` package hook. That hook was
|
|
131
|
+
removed: `pnpm` and `bun` block dependency scripts by default, and `pnpm`
|
|
132
|
+
replays a cached package without re-running them, so the hook could be skipped
|
|
133
|
+
with no error and no Skill. Running it from the CLI removes that whole class of
|
|
134
|
+
silent failure, and it also picks up an agent host installed after the CLI —
|
|
135
|
+
the hook only ever ran once, at package install time.
|
|
136
|
+
|
|
137
|
+
The installer writes only for supported agent hosts already present on the
|
|
138
|
+
machine. It does not create configuration for absent hosts or replace a
|
|
139
|
+
different existing Skill. If an earlier version of this package installed the
|
|
140
|
+
retired `weft-cli` Skill, the installer removes that copy after the `weft`
|
|
141
|
+
Skill is in place; a hand-edited or user-owned `weft-cli` copy stays
|
|
142
|
+
untouched. Restart the agent host after the first install. Set
|
|
143
|
+
`WEFT_SKIP_SKILL_INSTALL=1` to opt out of both paths. Removing the package
|
|
144
|
+
leaves the Skill in place; remove the host's `skills/weft` directory if you
|
|
145
|
+
also want to remove the Skill.
|
|
146
|
+
|
|
147
|
+
`weft bootstrap` registers its OAuth client, creates the bootstrap, and writes
|
|
148
|
+
the temporary and device credentials to a local credential file created with
|
|
149
|
+
mode `0600`. After approval, the stored OAuth credential replaces the temporary
|
|
150
|
+
credential and refreshes before expiry. Normal output never prints a secret.
|
|
151
|
+
|
|
152
|
+
### The temporary `wbt_` credential
|
|
153
|
+
|
|
154
|
+
- **Secret.** Never print, log, paste, commit, or email it. The CLI stores it
|
|
155
|
+
for you.
|
|
156
|
+
- **Temporary.** It expires 30 minutes after creation and has no refresh.
|
|
157
|
+
- **Search-only.** Its capabilities are `search`, `status`, and `cancel`.
|
|
158
|
+
Balance, paid fetch, wallet, transfer, withdrawal, seller, and organization
|
|
159
|
+
mutation surfaces all refuse it. A refusal there is the contract, not a bug.
|
|
160
|
+
|
|
161
|
+
The human's password is never part of this flow. The agent does not choose,
|
|
162
|
+
receive, or store it. An existing user completes fresh authentication on the
|
|
163
|
+
claim page; possession of the email link alone cannot attach an agent to an
|
|
164
|
+
existing account.
|
|
165
|
+
|
|
166
|
+
### Bootstrap states
|
|
167
|
+
|
|
168
|
+
| Status | Meaning | Agent action |
|
|
169
|
+
| --- | --- | --- |
|
|
170
|
+
| `pending` | Waiting for the human. Search works. | Keep polling at the returned interval. |
|
|
171
|
+
| `claimed` | The human approved. Search continues until OAuth delivery succeeds. | Complete the OAuth device exchange. |
|
|
172
|
+
| `rejected` | The human declined. Terminal. | Stop; do not re-create the same bootstrap. |
|
|
173
|
+
| `expired` | The 30-minute window closed unclaimed. Terminal. | Offer to start a new bootstrap. |
|
|
174
|
+
| `consumed` | OAuth tokens were delivered. Terminal. | Use the OAuth credential. |
|
|
175
|
+
|
|
176
|
+
These are server lifecycle states. `weft auth status` handles `claimed` by
|
|
177
|
+
performing the OAuth exchange and emits `consumed` after successful delivery;
|
|
178
|
+
it does not emit an intermediate `claimed` result.
|
|
179
|
+
|
|
180
|
+
`rejected`, `expired`, and `consumed` are terminal. A `pending` or `claimed`
|
|
181
|
+
bootstrap can search; `claimed` also keeps status and OAuth token exchange.
|
|
182
|
+
|
|
183
|
+
See [`examples/agent-bootstrap.sh`](examples/agent-bootstrap.sh) for the same
|
|
184
|
+
sequence as a script, and
|
|
185
|
+
[`docs/operation-inventory.md`](../docs/operation-inventory.md) for commands,
|
|
186
|
+
output envelopes, and stable exit codes.
|
package/bin/weft.mjs
ADDED
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
declare const EXIT_SUCCESS = 0;
|
|
2
|
+
declare const EXIT_USAGE = 2;
|
|
3
|
+
declare const EXIT_AUTH = 3;
|
|
4
|
+
declare const EXIT_API = 4;
|
|
5
|
+
declare const EXIT_INTERNAL = 5;
|
|
6
|
+
interface CliDependencies {
|
|
7
|
+
env?: Record<string, string | undefined>;
|
|
8
|
+
fetchApi?: typeof fetch;
|
|
9
|
+
readStdin?: () => Promise<string>;
|
|
10
|
+
writeOut?: (value: string) => void | Promise<void>;
|
|
11
|
+
writeErr?: (value: string) => void;
|
|
12
|
+
generateIdempotencyKey?: () => string;
|
|
13
|
+
runProcess?: ProcessRunner;
|
|
14
|
+
platform?: NodeJS.Platform;
|
|
15
|
+
nodeExecutable?: string;
|
|
16
|
+
npxCliPath?: string;
|
|
17
|
+
}
|
|
18
|
+
interface ProcessResult {
|
|
19
|
+
exitCode: number;
|
|
20
|
+
stdout: string;
|
|
21
|
+
stderr: string;
|
|
22
|
+
}
|
|
23
|
+
type ProcessRunner = (command: string, args: string[]) => Promise<ProcessResult>;
|
|
24
|
+
declare function runCli(args: string[], dependencies?: CliDependencies): Promise<number>;
|
|
25
|
+
|
|
26
|
+
export { type CliDependencies, EXIT_API, EXIT_AUTH, EXIT_INTERNAL, EXIT_SUCCESS, EXIT_USAGE, runCli };
|