@amdahl/cli 0.1.4 → 0.2.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 +157 -7
- package/bin/amdahl.js +22 -0
- package/dist/amdahl.js +8298 -61
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
The `amdahl` command line. It signs you in with your console account, checks
|
|
4
4
|
that a workspace can optimize, rewrites messages, manages API keys (each one
|
|
5
|
-
approved in the console),
|
|
5
|
+
approved in the console), points MCP clients at Amdahl, and installs skills
|
|
6
|
+
from the library at https://amdahl.ai/skills.
|
|
6
7
|
|
|
7
8
|
## Using the Claude or ChatGPT app? You do not need this CLI
|
|
8
9
|
|
|
@@ -39,7 +40,8 @@ Full steps: https://amdahl.ai/connect
|
|
|
39
40
|
|
|
40
41
|
## Install
|
|
41
42
|
|
|
42
|
-
Needs Node.js 20 or later.
|
|
43
|
+
Needs Node.js 20 or later. On an older Node, `amdahl` stops before it does
|
|
44
|
+
anything, names the version it found, and links the Node.js download page.
|
|
43
45
|
|
|
44
46
|
```sh
|
|
45
47
|
# Run once, with no install
|
|
@@ -50,6 +52,10 @@ npm i -g @amdahl/cli
|
|
|
50
52
|
amdahl login
|
|
51
53
|
```
|
|
52
54
|
|
|
55
|
+
`amdahl` is also on npm by its short name, so `npx amdahl ...` is the same as
|
|
56
|
+
`npx @amdahl/cli ...`. That package ([packages/amdahl](packages/amdahl)) has no
|
|
57
|
+
code of its own: it depends on `@amdahl/cli` at the same version and runs it.
|
|
58
|
+
|
|
53
59
|
To connect an AI client, run `amdahl install claude-code` (or `codex`,
|
|
54
60
|
`cursor`). It adds the Amdahl MCP server and also installs the Amdahl skill,
|
|
55
61
|
a map of everything Amdahl can do, so your agent knows which tool fits each
|
|
@@ -76,6 +82,7 @@ amdahl whoami # the account, workspace and role you are signed in
|
|
|
76
82
|
amdahl status # can this workspace optimize, and what blocks it
|
|
77
83
|
amdahl optimize draft.md # rewrite one message (or pipe it in with -)
|
|
78
84
|
amdahl install claude-code # connect an AI client and add the Amdahl skill (also codex, cursor)
|
|
85
|
+
amdahl skills add <publisher>/<skill> # add a skill from amdahl.ai/skills to this project
|
|
79
86
|
```
|
|
80
87
|
|
|
81
88
|
No workspace yet? `amdahl login` prints the console link where you can
|
|
@@ -98,11 +105,129 @@ amdahl keys list
|
|
|
98
105
|
amdahl keys revoke <id|prefix> [--yes] [--no-browser]
|
|
99
106
|
amdahl workspace list | amdahl workspace use <profile>
|
|
100
107
|
amdahl install claude-code|codex|cursor [--print] [--force]
|
|
108
|
+
amdahl skills add <publisher>/<skill> [-g] [--agents] [--force] [--site <origin>]
|
|
101
109
|
```
|
|
102
110
|
|
|
103
111
|
Global flags: `--profile`, `--api-url`, `--api-key`, `--json`, `--no-color`,
|
|
104
112
|
`-h`, `-v`. With `--json`, data goes to stdout and messages to stderr.
|
|
105
113
|
|
|
114
|
+
## Skills
|
|
115
|
+
|
|
116
|
+
`skills add` installs one skill from the library at https://amdahl.ai/skills.
|
|
117
|
+
It needs no sign-in.
|
|
118
|
+
|
|
119
|
+
```sh
|
|
120
|
+
npx amdahl skills add <publisher>/<skill>
|
|
121
|
+
# the skill's link works too, with or without .md:
|
|
122
|
+
npx amdahl skills add https://amdahl.ai/skills/<publisher>/<skill>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
In a terminal, it asks one question. It prints `Checking <publisher>/<skill>
|
|
126
|
+
on amdahl.ai... OK` while it downloads and checks the skill. Then it names
|
|
127
|
+
the skill and the agents it sees in use, and asks where to install it, in a
|
|
128
|
+
menu:
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
System diagram, by Amdahl (17 files), for Claude Code and Cursor.
|
|
132
|
+
Install it in:
|
|
133
|
+
> This project (~/proj)
|
|
134
|
+
Every project on this computer
|
|
135
|
+
(Use the arrow keys, then Enter)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Up and Down (or `k` and `j`) move the marker; typing `1` or `2` jumps to
|
|
139
|
+
that row. Enter picks, and the menu shrinks to one line, such as
|
|
140
|
+
`Install it in: This project (~/proj)`. The marked row is in the brand
|
|
141
|
+
colour, or bold when colour is off (`--no-color`, `NO_COLOR`, `TERM=dumb`).
|
|
142
|
+
The pick is the go-ahead: it installs, prints the folders it wrote, and
|
|
143
|
+
says to open a new chat. In your home folder it does not ask, and installs
|
|
144
|
+
for every project. Ctrl+C stops it with nothing written (exit 130).
|
|
145
|
+
|
|
146
|
+
It never asks about agents. A `.claude` folder here or in your home folder,
|
|
147
|
+
or `CLAUDECODE` set, means Claude Code (`.claude/skills`). A `.codex` folder
|
|
148
|
+
means Codex, a `.cursor` folder or `CURSOR_AGENT` means Cursor, and an
|
|
149
|
+
`.agents` folder means other agents (all `.agents/skills`). When it sees
|
|
150
|
+
both kinds, or neither, it writes both folders. To choose yourself, use the
|
|
151
|
+
flags below.
|
|
152
|
+
|
|
153
|
+
If a different copy of the skill is already there, it asks once more, in
|
|
154
|
+
the same kind of menu: "Keep your copy" (where the marker starts) or
|
|
155
|
+
"Replace it". With `--force` it replaces it without asking.
|
|
156
|
+
|
|
157
|
+
It never asks when stdin or stdout is not a terminal (an agent, CI, a pipe),
|
|
158
|
+
or with `--json`, `-y`, `-g` or `--agents`, or with `AMDAHL_NO_PROMPT=1`.
|
|
159
|
+
Then the flags say where. Without `--agents`, it uses the folder of the agent
|
|
160
|
+
that ran it, when that agent says so: Claude Code sets `CLAUDECODE`
|
|
161
|
+
(`.claude/skills`), Cursor sets `CURSOR_AGENT` (`.agents/skills`). Codex
|
|
162
|
+
documents no such variable, so a run from Codex gets the default, Claude
|
|
163
|
+
Code. Without flags it says on stderr where the skill went. `-y` (`--yes`)
|
|
164
|
+
adds it to this project without asking. Neither replaces a different copy
|
|
165
|
+
without `--force`.
|
|
166
|
+
|
|
167
|
+
It reads the skill's index,
|
|
168
|
+
`https://amdahl.ai/skills/<publisher>/<skill>/.well-known/agent-skills/index.json`
|
|
169
|
+
([Agent Skills Discovery](https://schemas.agentskills.io/discovery/0.2.0/schema.json)
|
|
170
|
+
v0.2.0). The index lists one of two kinds of skill:
|
|
171
|
+
|
|
172
|
+
- `type: "skill-md"`: one SKILL.md. `skills add` downloads it.
|
|
173
|
+
- `type: "archive"`: a folder (the SKILL.md plus scripts, references and
|
|
174
|
+
other files), as one `.tar.gz`. `skills add` downloads it and unpacks it
|
|
175
|
+
with its own reader. It never runs `tar`.
|
|
176
|
+
|
|
177
|
+
It refuses the download, and writes nothing, unless all of these are true:
|
|
178
|
+
|
|
179
|
+
- The index points at a file on the same site.
|
|
180
|
+
- The sha256 of the downloaded bytes equals the index's `digest`. This is
|
|
181
|
+
checked before anything in an archive is read. The index and the file come
|
|
182
|
+
from the same site, so this only catches a corrupted or cut-off download.
|
|
183
|
+
It is not a signature and does not show the file is unchanged: that rests
|
|
184
|
+
on HTTPS and on who can publish to amdahl.ai/skills.
|
|
185
|
+
- The SKILL.md front matter parses as YAML, `name` is a string, and
|
|
186
|
+
`description` is a string that is not empty.
|
|
187
|
+
- `name` equals the skill's name in the index.
|
|
188
|
+
|
|
189
|
+
An archive must also be a plain folder. `skills add` refuses it if:
|
|
190
|
+
|
|
191
|
+
- the gzip CRC-32 or length does not match, or bytes follow the gzip data;
|
|
192
|
+
- a tar header has a wrong checksum, is not ustar, or the tar has no end;
|
|
193
|
+
- a path is absolute, holds `..`, `.` or an empty segment, a backslash or a
|
|
194
|
+
control character, or two entries share a path (also when only the
|
|
195
|
+
case differs);
|
|
196
|
+
- an entry is not a file or a folder (a link, a device, a pax header);
|
|
197
|
+
- a file mode is not 0644 or 0755;
|
|
198
|
+
- it has more than 200 files, or more than 4 MB of file contents;
|
|
199
|
+
- SKILL.md is not at its root.
|
|
200
|
+
|
|
201
|
+
Without the questions, the flags say where it writes, and it prints each
|
|
202
|
+
path it wrote:
|
|
203
|
+
|
|
204
|
+
| flag | where |
|
|
205
|
+
|---|---|
|
|
206
|
+
| (none) or `-y` | `./.claude/skills/<name>/`, for Claude Code in this project |
|
|
207
|
+
| `-g`, `--global` | `~/.claude/skills/<name>/`, for every project |
|
|
208
|
+
| `--agents` | also `.agents/skills/<name>/` (in this project, or in `~` with `-g`), which Codex, Cursor and most other agents read |
|
|
209
|
+
|
|
210
|
+
A `skill-md` skill writes `SKILL.md` in that folder, exactly as downloaded,
|
|
211
|
+
through a temp file renamed into place. It refuses, even with `--force`, when
|
|
212
|
+
the skill folder, the `skills` or `.claude`/`.agents` folder above it, or
|
|
213
|
+
`SKILL.md` itself is a symbolic link, so it never writes outside that folder.
|
|
214
|
+
An `archive` skill unpacks into a hidden temp folder beside each target,
|
|
215
|
+
then renames it into place only when every target is complete. If any step
|
|
216
|
+
fails, it removes what it unpacked and puts back any folder it replaced.
|
|
217
|
+
|
|
218
|
+
If a different file or folder with that name is already there, `skills add`
|
|
219
|
+
stops before it writes anything. Add `--force` to replace it. For a folder
|
|
220
|
+
skill, `--force` replaces the whole folder, with any files you added to it.
|
|
221
|
+
A skill that is already identical is left as it is.
|
|
222
|
+
|
|
223
|
+
It sends two requests, both to amdahl.ai: the index, then the file. It
|
|
224
|
+
follows no redirect and sends no telemetry. It waits at most 15 seconds for
|
|
225
|
+
each request. It refuses an index over 256 KB, a SKILL.md over 64 KB (the
|
|
226
|
+
most amdahl.ai accepts) and an archive over 4 MB. Each refusal writes
|
|
227
|
+
nothing. `--site <origin>` sends both requests to another origin, for
|
|
228
|
+
example a local copy of the site (`--site http://localhost:6782`). The
|
|
229
|
+
origin must be `https`; `http` is allowed only for localhost.
|
|
230
|
+
|
|
106
231
|
## Targeting staging
|
|
107
232
|
|
|
108
233
|
```sh
|
|
@@ -141,7 +266,7 @@ code shown in the terminal; then the key is printed once and stored nowhere.
|
|
|
141
266
|
| code | meaning |
|
|
142
267
|
|---|---|
|
|
143
268
|
| 0 | ok |
|
|
144
|
-
| 1 | general (`login_timeout`, `state_mismatch`, optimize `ok: false`) |
|
|
269
|
+
| 1 | general (`login_timeout`, `state_mismatch`, optimize `ok: false`, a `skills add` refusal) |
|
|
145
270
|
| 2 | usage |
|
|
146
271
|
| 3 | not signed in (401, `invalid_grant`, no credential) |
|
|
147
272
|
| 4 | forbidden (403, `oauth_required`, `cli_client_required`, `not_admin`) |
|
|
@@ -149,6 +274,7 @@ code shown in the terminal; then the key is printed once and stored nowhere.
|
|
|
149
274
|
| 6 | rate limited or quota (429) |
|
|
150
275
|
| 7 | approval denied, expired or locked out |
|
|
151
276
|
| 8 | network or 5xx |
|
|
277
|
+
| 130 | stopped with Ctrl+C at a question (nothing was written) |
|
|
152
278
|
|
|
153
279
|
## Development
|
|
154
280
|
|
|
@@ -160,7 +286,7 @@ pnpm install
|
|
|
160
286
|
pnpm build # dist/amdahl.js, one file, no runtime deps
|
|
161
287
|
pnpm test # vitest, against a local mock server
|
|
162
288
|
pnpm type-check
|
|
163
|
-
pnpm smoke:pack # pack, install offline, run --version
|
|
289
|
+
pnpm smoke:pack # pack both packages, install offline, run --help and --version
|
|
164
290
|
pnpm sync:skill # refresh skill/SKILL.md from docs.amdahl.ai (and skill/shipped.json), then commit both
|
|
165
291
|
```
|
|
166
292
|
|
|
@@ -171,9 +297,10 @@ See [CONTRIBUTING.md](CONTRIBUTING.md). Report security issues as described in
|
|
|
171
297
|
|
|
172
298
|
`.github/workflows/publish.yml` publishes to npm. To release:
|
|
173
299
|
|
|
174
|
-
1. In a PR, bump the version in `package.json` and `src/version.ts` together
|
|
175
|
-
|
|
176
|
-
|
|
300
|
+
1. In a PR, bump the version in `package.json` and `src/version.ts` together,
|
|
301
|
+
and in `packages/amdahl/package.json` both its `version` and its
|
|
302
|
+
`@amdahl/cli` dependency. The workflow refuses a version that does not
|
|
303
|
+
match the first two, or one that is already on npm; a test checks the third.
|
|
177
304
|
2. After it merges, push a tag `cli-v<version>` (for example `cli-v0.2.0`). A
|
|
178
305
|
version with a `-` (for example `0.2.0-rc.1`) goes to the `next` dist-tag;
|
|
179
306
|
anything else goes to `latest`.
|
|
@@ -189,3 +316,26 @@ the `npm` environment, so no long-lived npm token is needed. Every release
|
|
|
189
316
|
carries a signed [provenance attestation](https://docs.npmjs.com/generating-provenance-statements)
|
|
190
317
|
that links the package on npm to the commit and workflow run that built it.
|
|
191
318
|
Check it with `npm audit signatures` or on the package page on npmjs.com.
|
|
319
|
+
|
|
320
|
+
The workflow publishes `amdahl` (the short name) right after `@amdahl/cli`,
|
|
321
|
+
from the same run, only when the repository variable `NPM_PUBLISH_AMDAHL` is
|
|
322
|
+
`true`. Amdahl already holds the `amdahl` name on npm (a 0.0.1 placeholder
|
|
323
|
+
with no bin), so trusted publishing can be set up for it now. Before you push
|
|
324
|
+
the tag:
|
|
325
|
+
|
|
326
|
+
1. On npmjs.com, `amdahl`, Settings, add a trusted publisher: GitHub Actions,
|
|
327
|
+
`amdahlco/amdahl-cli`, workflow `publish.yml`, environment `npm`.
|
|
328
|
+
2. Set the repository variable `NPM_PUBLISH_AMDAHL` to `true`.
|
|
329
|
+
|
|
330
|
+
Then each `cli-v<version>` tag publishes both packages from CI, both with
|
|
331
|
+
provenance. Each publish step skips a version already on npm, so if the
|
|
332
|
+
`amdahl` step fails, use **Re-run failed jobs** on that run. (Re-running every
|
|
333
|
+
job stops at the check that the version is not on npm yet.)
|
|
334
|
+
|
|
335
|
+
Only if CI cannot publish `amdahl`, publish it by hand as a fallback: download
|
|
336
|
+
the `tarball` artifact from the run (it holds `amdahl-<version>.tgz`, already
|
|
337
|
+
checked), then, as an owner of the `amdahl` npm org with 2FA, run
|
|
338
|
+
`npm publish amdahl-<version>.tgz --access public --provenance=false`.
|
|
339
|
+
`publishConfig` asks for provenance, which a laptop cannot give, so without
|
|
340
|
+
`--provenance=false` the publish is expected to fail. That version has no
|
|
341
|
+
provenance.
|
package/bin/amdahl.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// bin/amdahl.js
|
|
3
|
+
//
|
|
4
|
+
// The `amdahl` command. It checks the Node.js version before it loads the
|
|
5
|
+
// CLI: dist/amdahl.js is built for Node 20, and an older Node fails to parse
|
|
6
|
+
// it or crashes in it, while npx only warns about `engines`. So this file
|
|
7
|
+
// uses no syntax newer than Node 14 (no `??=`, no top-level await, no class
|
|
8
|
+
// fields), and an old Node can run it far enough to say what to do.
|
|
9
|
+
|
|
10
|
+
var version = process.versions.node
|
|
11
|
+
var major = parseInt(version.split('.')[0], 10)
|
|
12
|
+
|
|
13
|
+
if (!(major >= 20)) {
|
|
14
|
+
process.stderr.write(
|
|
15
|
+
'amdahl needs Node.js 20 or later. This computer has Node.js ' +
|
|
16
|
+
version +
|
|
17
|
+
'.\nInstall a newer one from https://nodejs.org/en/download, then run the same command again.\n'
|
|
18
|
+
)
|
|
19
|
+
process.exitCode = 1
|
|
20
|
+
} else {
|
|
21
|
+
import('../dist/amdahl.js')
|
|
22
|
+
}
|