@yargote/artifacts-cli 0.1.0-beta.3 → 0.1.0-beta.5
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 +28 -6
- package/package.json +3 -3
- package/skills/artifacts-cli/SKILL.md +6 -0
- package/skills/artifacts-cli/references/commands.md +17 -1
- package/skills/artifacts-design/SKILL.md +13 -7
- package/skills/artifacts-design/THIRD-PARTY-NOTICES.md +31 -0
- package/skills/artifacts-design/references/interface-checks.md +11 -1
- package/skills/artifacts-design/templates/starter.html +3 -3
- package/src/index.js +25 -8
- package/src/operations.d.ts +19 -37
- package/src/operations.js +3 -1
package/README.md
CHANGED
|
@@ -11,9 +11,9 @@ Use Node 24 or later. The beta targets macOS and Linux. Windows has not been ver
|
|
|
11
11
|
Choose one persistent installation:
|
|
12
12
|
|
|
13
13
|
```sh
|
|
14
|
-
npm install --global @yargote/artifacts-cli@0.1.0-beta.
|
|
14
|
+
npm install --global @yargote/artifacts-cli@0.1.0-beta.5
|
|
15
15
|
# Or, with pnpm and an existing global bin directory on PATH:
|
|
16
|
-
pnpm add --global @yargote/artifacts-cli@0.1.0-beta.
|
|
16
|
+
pnpm add --global @yargote/artifacts-cli@0.1.0-beta.5
|
|
17
17
|
artifacts --version
|
|
18
18
|
```
|
|
19
19
|
|
|
@@ -22,8 +22,8 @@ If pnpm reports that no global bin directory exists, run `pnpm setup` and reopen
|
|
|
22
22
|
For one-off execution, pin the same version:
|
|
23
23
|
|
|
24
24
|
```sh
|
|
25
|
-
npx --yes @yargote/artifacts-cli@0.1.0-beta.
|
|
26
|
-
pnpm dlx @yargote/artifacts-cli@0.1.0-beta.
|
|
25
|
+
npx --yes @yargote/artifacts-cli@0.1.0-beta.5 --help
|
|
26
|
+
pnpm dlx @yargote/artifacts-cli@0.1.0-beta.5 --help
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
`@beta` follows future prereleases. Exact versions remain reproducible. No stable `latest` release is part of this beta. An organization's pnpm minimum release age or trust policy can delay a new release. Follow that policy rather than disabling it globally.
|
|
@@ -108,9 +108,11 @@ The private `credentials.sqlite` file stores credentials. The separate `credenti
|
|
|
108
108
|
artifacts login [--no-browser]
|
|
109
109
|
artifacts logout
|
|
110
110
|
artifacts whoami
|
|
111
|
-
artifacts create --snapshot FILE [--
|
|
111
|
+
artifacts create --snapshot FILE [--project NAME] [--request-id ID]
|
|
112
|
+
[--response full|compact]
|
|
112
113
|
artifacts create --command FILE
|
|
113
|
-
artifacts list [--limit N] [--cursor CURSOR]
|
|
114
|
+
artifacts list [--limit N] [--cursor CURSOR] [--project NAME]
|
|
115
|
+
artifacts projects
|
|
114
116
|
artifacts read ID [--revision REV] [--response full|compact] [--out FILE [--quiet]]
|
|
115
117
|
artifacts update ID --snapshot FILE --expected-revision REV [--request-id ID]
|
|
116
118
|
[--response full|compact]
|
|
@@ -120,6 +122,8 @@ artifacts history ID [--limit N] [--before-sequence N] [--summary]
|
|
|
120
122
|
artifacts publish ID --revision REV --expected-version N [--request-id ID]
|
|
121
123
|
artifacts publish [ID] --command FILE
|
|
122
124
|
artifacts export ID --revision REV --out FILE
|
|
125
|
+
artifacts move ID --project NAME [--request-id ID]
|
|
126
|
+
artifacts move ID --no-project [--request-id ID]
|
|
123
127
|
artifacts retry REQUEST_ID
|
|
124
128
|
artifacts skills [list]
|
|
125
129
|
artifacts skills get NAME [--full]
|
|
@@ -175,6 +179,24 @@ A default full read contains the complete snapshot under `revision.snapshot`. `e
|
|
|
175
179
|
|
|
176
180
|
History defaults to complete revisions. `--summary` returns revision metadata and attachment summaries. `--before-sequence` continues a page. `list --cursor` continues an artifact list.
|
|
177
181
|
|
|
182
|
+
## Projects
|
|
183
|
+
|
|
184
|
+
A project groups artifacts by name. `create --snapshot FILE --project NAME` files the new artifact under that project. A name that matches an existing project regardless of letter case reuses its stored spelling, so `--project alpha` joins `Alpha`. Names are trimmed and NFC-normalized, contain 1 to 80 characters, and cannot contain control characters. A complete create command file can include the same optional `project` field.
|
|
185
|
+
|
|
186
|
+
```sh
|
|
187
|
+
artifacts create --snapshot snapshot.json --project Alpha
|
|
188
|
+
artifacts list --project alpha
|
|
189
|
+
artifacts projects
|
|
190
|
+
artifacts move ARTIFACT_ID --project Beta
|
|
191
|
+
artifacts move ARTIFACT_ID --no-project
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Every artifact read and list item includes `project`, a name or null. `projects` prints `{ "items": [{ "name": "Alpha", "artifactCount": 1 }] }`, ordered by name without regard to letter case. A project exists only while it contains an artifact.
|
|
195
|
+
|
|
196
|
+
`move ID` requires exactly one of `--project NAME` or `--no-project`. It prints `{ "artifactId": "...", "project": "Beta" }` with the stored spelling, or `null` after `--no-project`. Move never creates a revision or changes the publication. Moving to the current project succeeds without change. Move is a retained mutation like the others, so `retry` recovers a lost response.
|
|
197
|
+
|
|
198
|
+
Version `0.1.0-beta.4` and earlier parse artifact responses strictly and fail with `invalid_response` against a server that returns `project`. Upgrade the CLI together with the server.
|
|
199
|
+
|
|
178
200
|
## Complete commands and edits
|
|
179
201
|
|
|
180
202
|
`--command FILE` accepts a complete create, update, or publish command. It cannot be combined with other mutation options. For update and publish, an optional positional artifact ID must equal the command's `artifactId`. Every field, including the omission of `response`, is retained.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yargote/artifacts-cli",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Command-line client for the Artifacts REST API.",
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"skills"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@yargote/artifacts-contracts": "0.1.0-beta.
|
|
31
|
-
"@yargote/artifacts-client": "0.1.0-beta.
|
|
30
|
+
"@yargote/artifacts-contracts": "0.1.0-beta.5",
|
|
31
|
+
"@yargote/artifacts-client": "0.1.0-beta.5",
|
|
32
32
|
"openid-client": "6.8.8",
|
|
33
33
|
"zod": "4.6.5"
|
|
34
34
|
},
|
|
@@ -31,6 +31,12 @@ Resolve an existing artifact by its supplied ID, an observed publication URL, or
|
|
|
31
31
|
|
|
32
32
|
Use `edit` for partial changes that preserve omitted fields. Use `update` for a complete next snapshot with the observed `headRevisionId` as its expected revision. Changing the attachment list replaces that inventory; an empty list removes all attachments. An update creates a retained revision and does not change the published revision.
|
|
33
33
|
|
|
34
|
+
## Organize projects
|
|
35
|
+
|
|
36
|
+
When the user names a project for new content, add `--project NAME` to `create`. Run `artifacts projects` first when an existing project may already fit. A name matching an existing project regardless of letter case joins it and keeps the stored spelling. Do not invent a project the user did not ask for. Use `list --project NAME` to find artifacts in a project.
|
|
37
|
+
|
|
38
|
+
Use `move ID --project NAME` to file an existing artifact under a project and `move ID --no-project` to remove it from one. A move changes only the project. It creates no revision and leaves the publication unchanged. It is a retained mutation, so recover an uncertain move with `retry`. Verify it with `read` or `list --project NAME`. A project disappears when its last artifact leaves it.
|
|
39
|
+
|
|
34
40
|
## Publish deliberately
|
|
35
41
|
|
|
36
42
|
Publish when the user requests publication, a shareable artifact URL, or a change to the live artifact. Use the exact saved revision selected by the user or returned by the edit. Read the current publication version before preparing publication. Use zero only when the artifact is unpublished.
|
|
@@ -75,6 +75,22 @@ For `read`, `--out FILE --quiet` saves the returned response without printing su
|
|
|
75
75
|
|
|
76
76
|
Check installed help for `--quiet` support before running these examples. Older versions, including `0.1.0-beta.1`, can suppress stdout with `artifacts read ARTIFACT_ID --out saved.json > /dev/null`. This redirection preserves stderr and the command's exit status. Use the same fallback for the revision reads below.
|
|
77
77
|
|
|
78
|
+
## Organize projects
|
|
79
|
+
|
|
80
|
+
Check that installed help lists `projects` and `move` before using them.
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
artifacts create --snapshot snapshot.json --project "Client onboarding"
|
|
84
|
+
artifacts projects
|
|
85
|
+
artifacts list --project "client onboarding"
|
|
86
|
+
artifacts move ARTIFACT_ID --project Archive
|
|
87
|
+
artifacts move ARTIFACT_ID --no-project
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
A project name contains 1 to 80 characters after trimming and NFC normalization, without control characters. A name that matches an existing project regardless of letter case joins it and keeps its stored spelling. Every read and list item includes `project`, a name or null. `projects` prints `{ "items": [{ "name": "Client onboarding", "artifactCount": 1 }] }`, ordered by name without regard to letter case. A project exists only while it contains an artifact.
|
|
91
|
+
|
|
92
|
+
`move` takes exactly one of `--project NAME` or `--no-project` and prints `{ "artifactId": "...", "project": "Archive" }`, or `null` for the project after `--no-project`. It creates no revision and leaves the publication unchanged. Moving to the current project succeeds without change. A lost move response is recovered with `retry REQUEST_ID` like any other retained mutation.
|
|
93
|
+
|
|
78
94
|
## Edit without losing retained data
|
|
79
95
|
|
|
80
96
|
For a title change, save `changes.json` with only the requested field.
|
|
@@ -104,7 +120,7 @@ Command files contain the command itself, without the CLI's retained-operation w
|
|
|
104
120
|
| `update` | `requestId`, `artifactId`, `expectedRevisionId`, `snapshot` |
|
|
105
121
|
| `publish` | `requestId`, `artifactId`, `revisionId`, `expectedPublicationVersion` |
|
|
106
122
|
|
|
107
|
-
`requestId` is a caller-chosen string of 8 to 128 characters. Create and update also accept optional `response` with value `full` or `compact`. This complete update example replaces a snapshot. Substitute the observed IDs and preserve all required content and attachments in its `snapshot`.
|
|
123
|
+
`requestId` is a caller-chosen string of 8 to 128 characters. Create and update also accept optional `response` with value `full` or `compact`. Create also accepts an optional `project` name. This complete update example replaces a snapshot. Substitute the observed IDs and preserve all required content and attachments in its `snapshot`.
|
|
108
124
|
|
|
109
125
|
```json
|
|
110
126
|
{
|
|
@@ -9,9 +9,15 @@ The calling skill owns the snapshot, size limit, and save workflow. This skill o
|
|
|
9
9
|
|
|
10
10
|
The document renders in a sandbox that blocks every network request. Fonts, images, and icons load only as `data:` URIs. External stylesheets, Google Fonts links, and CDN scripts silently fail. Inline all CSS and JavaScript.
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## Choose the composition
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Before writing HTML, identify the reader's task, the facts and assets available, and what the reader should understand or do first. Use supplied facts. Label illustrative inputs and assumptions, and leave unavailable evidence absent.
|
|
15
|
+
|
|
16
|
+
Choose the element that carries the answer: a comparison, a diagram, a sequence, a chart, or a result beside its inputs. Give it the most space and put its supporting text nearby. If the same composition would fit an unrelated topic unchanged, use the subject's actual relationships or quantities to make the structure more specific. A report can be dense, an explanation can use large scenes, and a calculator can fit on one screen. Do not impose a hero, a section count, or a word budget.
|
|
17
|
+
|
|
18
|
+
## Use the starter's tokens
|
|
19
|
+
|
|
20
|
+
Copy the `<style>` block of [the starter](templates/starter.html) into the new document. It defines the color, font, and spacing tokens and shared components: contextual text and labels, lede, summary strip, pills, expandable rows, panel, note, table, filter bar, and footer. Delete components the page does not use. Derive every new color and type decision from its tokens.
|
|
15
21
|
|
|
16
22
|
The starter supplies a vocabulary, not a layout. Compose the body for the reader's task:
|
|
17
23
|
|
|
@@ -31,11 +37,11 @@ Open in a complete state with the user's real data. Never ship an empty shell or
|
|
|
31
37
|
Use the bundled faces through the starter's tokens:
|
|
32
38
|
|
|
33
39
|
- `--f-display` is Bricolage Grotesque. Use it for `h1` to `h3` and large figures only.
|
|
34
|
-
- `--f-body` is Public Sans for running text and
|
|
35
|
-
- `--f-mono` is JetBrains Mono for code
|
|
40
|
+
- `--f-body` is Public Sans for running text, controls, labels, and table headers.
|
|
41
|
+
- `--f-mono` is JetBrains Mono for code and identifiers. Use it for measurements when it helps the reader read or align them.
|
|
36
42
|
- Newsreader is an optional reading face. For a long essay or editorial guide, set `--f-body` to `"Newsreader",Charter,Georgia,serif` and keep Public Sans for controls.
|
|
37
43
|
|
|
38
|
-
|
|
44
|
+
Start with `h1` at `clamp(28px,4vw,40px)` and body at 15 to 16 px with a 1.55 line height. Set labels in the body face at 12 to 13 px, in sentence case without added tracking. Adjust the scale for the document's main visual and reading density. Keep `text-wrap: balance` on headings and `font-variant-numeric: tabular-nums` wherever digits align.
|
|
39
45
|
|
|
40
46
|
After the HTML file is complete, embed the fonts it names:
|
|
41
47
|
|
|
@@ -59,7 +65,7 @@ The starter follows the viewer's system theme. Light uses Catppuccin Latte and d
|
|
|
59
65
|
|
|
60
66
|
- Center one `.wrap` column at `--width` with `max(16px, env(safe-area-inset-*))` side gutters. Space siblings with grid or flex `gap`.
|
|
61
67
|
- Use borders and fills by role. A summary strip, a table, and one panel can each earn a surface. Running text and headings sit on the page.
|
|
62
|
-
-
|
|
68
|
+
- Use an eyebrow only for source or scope information the heading does not already give. A label names a field, and numbering appears only for real sequences.
|
|
63
69
|
- Encode attention in form. A row that needs action gets a pill or a muted closed state, not only a different word.
|
|
64
70
|
- Put wide code and diagrams in their own `overflow-x: auto` container. Use a `<table>` only for short records that stay readable when scrolled; use expandable rows for records with long text. The page itself never scrolls sideways at 375 px.
|
|
65
71
|
- Draw diagrams in inline SVG with token colors and labels inside the view box. For icons, use inline Tabler outline SVGs with `currentColor`.
|
|
@@ -71,6 +77,6 @@ Give the `<title>` a specific name of two to four words, or the name the user al
|
|
|
71
77
|
|
|
72
78
|
## Check the rendered page
|
|
73
79
|
|
|
74
|
-
Run the [interface checks](references/interface-checks.md)
|
|
80
|
+
Run the [interface checks](references/interface-checks.md) before saving. They distinguish required checks from visual judgment. Render the finished page at 375 px and 1280 px in both light and dark when browser tools are available. Fix observed failures and repeat the affected checks. Report checks you could not run.
|
|
75
81
|
|
|
76
82
|
The license notices for bundled fonts and adapted guidance are in [third-party notices](THIRD-PARTY-NOTICES.md).
|
|
@@ -119,6 +119,37 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
119
119
|
SOFTWARE.
|
|
120
120
|
```
|
|
121
121
|
|
|
122
|
+
## Hallmark
|
|
123
|
+
|
|
124
|
+
The composition guidance in [SKILL.md](SKILL.md) and the review categories in
|
|
125
|
+
[references/interface-checks.md](references/interface-checks.md) adapt ideas from
|
|
126
|
+
[Hallmark](https://github.com/Nutlope/hallmark), reviewed on 2026-10-24.
|
|
127
|
+
[Upstream license](https://github.com/Nutlope/hallmark/blob/main/LICENSE).
|
|
128
|
+
|
|
129
|
+
```text
|
|
130
|
+
MIT License
|
|
131
|
+
|
|
132
|
+
Copyright (c) 2026 Hallmark contributors
|
|
133
|
+
|
|
134
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
135
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
136
|
+
in the Software without restriction, including without limitation the rights
|
|
137
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
138
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
139
|
+
furnished to do so, subject to the following conditions:
|
|
140
|
+
|
|
141
|
+
The above copyright notice and this permission notice shall be included in all
|
|
142
|
+
copies or substantial portions of the Software.
|
|
143
|
+
|
|
144
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
145
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
146
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
147
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
148
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
149
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
150
|
+
SOFTWARE.
|
|
151
|
+
```
|
|
152
|
+
|
|
122
153
|
## Bundled fonts
|
|
123
154
|
|
|
124
155
|
The files in [fonts](fonts) are the Latin subsets of Bricolage Grotesque, Public Sans, JetBrains Mono, and Newsreader, as served by Google Fonts on 2026-10-17. Each is licensed under the SIL Open Font License, Version 1.1. The copyright lines and the complete license text are in [fonts/OFL.txt](fonts/OFL.txt).
|
|
@@ -31,7 +31,9 @@ Keep input-driven calculations in document memory. Use labeled controls without
|
|
|
31
31
|
|
|
32
32
|
Keep filters and tabs local to the document. Do not depend on host URL synchronization, router packages, persistent storage, network requests, or remote fonts. Embed fonts and other required assets as `data:` URIs within the snapshot budget.
|
|
33
33
|
|
|
34
|
-
##
|
|
34
|
+
## Required checks
|
|
35
|
+
|
|
36
|
+
Check content fidelity, sandbox compatibility, and usable behavior regardless of the composition. Preserve supplied facts, units, qualifications, and requested controls. For a visual revision, record the existing content and actions before editing and confirm that they still work afterward.
|
|
35
37
|
|
|
36
38
|
When browser tools are available, inspect the generated document at a narrow viewport around 375 px and a wide viewport around 1280 px, or the user's requested sizes. Verify that body content fits, labels remain legible, and only intentionally wide tables or code regions scroll locally. Check the artifact itself rather than relying on the surrounding application's appearance.
|
|
37
39
|
|
|
@@ -41,10 +43,18 @@ Finish when each relevant check passes or an unavailable check is identified. Fi
|
|
|
41
43
|
|
|
42
44
|
For a requested audit, identify each issue by element or source location and state its correction. Distinguish source inspection from browser verification. Do not turn ordinary artifact delivery into an unsolicited audit report.
|
|
43
45
|
|
|
46
|
+
## Visual judgment
|
|
47
|
+
|
|
48
|
+
Check whether the main visual or result answers the reader's task, whether its labels stay close to what they describe, and whether the reading order is clear at both widths. Read the headings alone and check that they describe this document's content. Remove containers and repeated labels that add no grouping or information.
|
|
49
|
+
|
|
50
|
+
Choose density, alignment, cards, and section rhythm for the content. A long report, a diagram sequence, and a calculator need different compositions. These choices are defaults to reconsider with a concrete reason, not automatic failures. Keep the user's requested style and content. Do not remove evidence or simplify away a qualification to meet an aesthetic preference.
|
|
51
|
+
|
|
44
52
|
## Sources
|
|
45
53
|
|
|
46
54
|
Adapted on 2026-10-14 from [Emil Kowalski's design engineering skill](https://raw.githubusercontent.com/emilkowalski/skills/refs/heads/main/skills/emil-design-eng/SKILL.md) and [Vercel's web design guidelines skill](https://raw.githubusercontent.com/vercel-labs/agent-skills/refs/heads/main/skills/web-design-guidelines/SKILL.md).
|
|
47
55
|
|
|
48
56
|
The accessibility and interface checks incorporate Vercel's Web Interface Guidelines `command.md` as local guidance. Its remote command workflow and output format are not required. The sandbox adaptations are specific to Artifacts.
|
|
49
57
|
|
|
58
|
+
The composition workflow and the distinction between required checks and visual judgment draw on [Hallmark](https://github.com/Nutlope/hallmark), reviewed on 2026-10-24. This adaptation retains Artifacts' document types, palette, embedded fonts, and sandbox constraints.
|
|
59
|
+
|
|
50
60
|
License notices are retained in [Third-party notices](../THIRD-PARTY-NOTICES.md).
|
|
@@ -47,7 +47,7 @@ code,kbd,pre{font-family:var(--f-mono);font-size:.86em}
|
|
|
47
47
|
pre{margin:0;padding:14px 16px;background:var(--sunken);border-radius:8px;overflow-x:auto;line-height:1.5}
|
|
48
48
|
:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
|
|
49
49
|
|
|
50
|
-
.eyebrow,.label{font:600
|
|
50
|
+
.eyebrow,.label{font:600 12px/1.35 var(--f-body);color:var(--muted)}
|
|
51
51
|
header{display:grid;gap:8px}
|
|
52
52
|
.lede{color:var(--muted);max-width:68ch;font-size:16px}
|
|
53
53
|
.prose{display:grid;gap:12px;max-width:68ch}
|
|
@@ -71,14 +71,14 @@ section{display:grid;gap:14px}
|
|
|
71
71
|
|
|
72
72
|
.table{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);overflow-x:auto}
|
|
73
73
|
table{width:100%;border-collapse:collapse;font-size:14px}
|
|
74
|
-
th{font:600
|
|
74
|
+
th{font:600 12px/1.35 var(--f-body);color:var(--muted);text-align:left;padding:10px 14px;background:var(--sunken);border-bottom:1px solid var(--line);white-space:nowrap}
|
|
75
75
|
td{padding:11px 14px;border-bottom:1px solid var(--line);vertical-align:top;font-variant-numeric:tabular-nums}
|
|
76
76
|
tr:last-child td{border-bottom:0}
|
|
77
77
|
td.num,th.num{text-align:right;white-space:nowrap}
|
|
78
78
|
|
|
79
79
|
.rows{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden}
|
|
80
80
|
.rows-head,.row>summary{display:grid;grid-template-columns:var(--cols,88px minmax(0,2fr) minmax(0,1fr) minmax(0,1.4fr));gap:16px;padding:12px 16px;align-items:start}
|
|
81
|
-
.rows-head{font:600
|
|
81
|
+
.rows-head{font:600 12px/1.35 var(--f-body);color:var(--muted);background:var(--sunken);border-bottom:1px solid var(--line)}
|
|
82
82
|
.row{border-bottom:1px solid var(--line)}
|
|
83
83
|
.row:last-child{border-bottom:0}
|
|
84
84
|
.row>summary{cursor:pointer;list-style:none}
|
package/src/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { homedir } from 'node:os';
|
|
|
6
6
|
import { join, resolve } from 'node:path';
|
|
7
7
|
import { parseArgs } from 'node:util';
|
|
8
8
|
import { z } from 'zod';
|
|
9
|
-
import { createSchema, publishSchema, updateSchema } from '@yargote/artifacts-contracts';
|
|
9
|
+
import { createSchema, moveSchema, publishSchema, updateSchema } from '@yargote/artifacts-contracts';
|
|
10
10
|
import { canonicalResource } from '@yargote/artifacts-contracts/http';
|
|
11
11
|
import { createArtifactHttpClient, HttpError, prepareArtifactEdit } from '@yargote/artifacts-client';
|
|
12
12
|
import { accessToken, login, logout } from "./auth.js";
|
|
@@ -30,9 +30,11 @@ Commands:
|
|
|
30
30
|
login [--no-browser]
|
|
31
31
|
logout
|
|
32
32
|
whoami
|
|
33
|
-
create --snapshot FILE [--
|
|
33
|
+
create --snapshot FILE [--project NAME] [--request-id ID]
|
|
34
|
+
[--response full|compact]
|
|
34
35
|
create --command FILE
|
|
35
|
-
list [--limit N] [--cursor CURSOR]
|
|
36
|
+
list [--limit N] [--cursor CURSOR] [--project NAME]
|
|
37
|
+
projects
|
|
36
38
|
read ID [--revision REV] [--response full|compact] [--out FILE [--quiet]]
|
|
37
39
|
update ID --snapshot FILE --expected-revision REV [--request-id ID]
|
|
38
40
|
[--response full|compact]
|
|
@@ -42,11 +44,16 @@ Commands:
|
|
|
42
44
|
publish ID --revision REV --expected-version N [--request-id ID]
|
|
43
45
|
publish [ID] --command FILE
|
|
44
46
|
export ID --revision REV --out FILE
|
|
47
|
+
move ID --project NAME [--request-id ID]
|
|
48
|
+
move ID --no-project [--request-id ID]
|
|
45
49
|
retry REQUEST_ID
|
|
46
50
|
|
|
47
51
|
Mutation command files contain the complete create, update, or publish JSON.
|
|
48
52
|
Mutation request IDs default to a random UUID. Commands are retained before
|
|
49
53
|
submission. Retry sends the exact retained command for the same server and owner.
|
|
54
|
+
Projects group artifacts by name without regard to letter case. A project
|
|
55
|
+
exists while it contains an artifact. Move changes the project of an artifact
|
|
56
|
+
without creating a revision; --no-project removes it from its project.
|
|
50
57
|
Read --out saves the returned artifact JSON. Export --out saves the ZIP.
|
|
51
58
|
Read --quiet requires --out and suppresses successful JSON stdout.
|
|
52
59
|
Output files are created exclusively and never overwrite an existing path.
|
|
@@ -63,12 +70,12 @@ class UsageError extends Error {
|
|
|
63
70
|
}
|
|
64
71
|
const commandOptions = {
|
|
65
72
|
login: ['no-browser'], logout: [], whoami: [],
|
|
66
|
-
create: ['snapshot', 'request-id', 'response', 'command'],
|
|
67
|
-
list: ['limit', 'cursor'], read: ['revision', 'response', 'out', 'quiet'],
|
|
73
|
+
create: ['snapshot', 'project', 'request-id', 'response', 'command'],
|
|
74
|
+
list: ['limit', 'cursor', 'project'], projects: [], read: ['revision', 'response', 'out', 'quiet'],
|
|
68
75
|
update: ['snapshot', 'expected-revision', 'request-id', 'response', 'command'],
|
|
69
76
|
edit: ['changes', 'request-id'], history: ['limit', 'before-sequence', 'summary'],
|
|
70
77
|
publish: ['revision', 'expected-version', 'request-id', 'command'],
|
|
71
|
-
export: ['revision', 'out'], retry: [],
|
|
78
|
+
export: ['revision', 'out'], move: ['project', 'no-project', 'request-id'], retry: [],
|
|
72
79
|
skills: ['full', 'all', 'agent', 'global', 'force'],
|
|
73
80
|
};
|
|
74
81
|
async function jsonFile(path) {
|
|
@@ -105,6 +112,7 @@ async function main() {
|
|
|
105
112
|
summary: { type: 'boolean' }, out: { type: 'string' }, quiet: { type: 'boolean' },
|
|
106
113
|
full: { type: 'boolean' }, all: { type: 'boolean' }, agent: { type: 'string' },
|
|
107
114
|
global: { type: 'boolean' }, force: { type: 'boolean' },
|
|
115
|
+
project: { type: 'string' }, 'no-project': { type: 'boolean' },
|
|
108
116
|
},
|
|
109
117
|
});
|
|
110
118
|
const seen = new Set();
|
|
@@ -203,11 +211,14 @@ async function main() {
|
|
|
203
211
|
if (values.command)
|
|
204
212
|
return mutate(await commandFile('create'));
|
|
205
213
|
none();
|
|
206
|
-
return mutate({ kind: 'create', command: createSchema.parse({ requestId: values['request-id'] ?? randomUUID(), snapshot: await jsonFile(required('snapshot')), ...(response === undefined ? {} : { response }) }) });
|
|
214
|
+
return mutate({ kind: 'create', command: createSchema.parse({ requestId: values['request-id'] ?? randomUUID(), snapshot: await jsonFile(required('snapshot')), ...(values.project === undefined ? {} : { project: values.project }), ...(response === undefined ? {} : { response }) }) });
|
|
207
215
|
}
|
|
208
216
|
case 'list':
|
|
209
217
|
none();
|
|
210
|
-
return client.list({ ...(values.limit === undefined ? {} : { limit: integer('limit') }), ...(values.cursor === undefined ? {} : { cursor: values.cursor }) });
|
|
218
|
+
return client.list({ ...(values.limit === undefined ? {} : { limit: integer('limit') }), ...(values.cursor === undefined ? {} : { cursor: values.cursor }), ...(values.project === undefined ? {} : { project: values.project }) });
|
|
219
|
+
case 'projects':
|
|
220
|
+
none();
|
|
221
|
+
return client.projects();
|
|
211
222
|
case 'read': {
|
|
212
223
|
const result = await client.read({ artifactId: argument(), ...(values.revision === undefined ? {} : { revisionId: values.revision }), ...(response === undefined ? {} : { response }) });
|
|
213
224
|
if (values.out)
|
|
@@ -238,6 +249,12 @@ async function main() {
|
|
|
238
249
|
await writeOutput(output, archive.bytes);
|
|
239
250
|
return { filename: archive.filename, path: resolve(output), mediaType: archive.mediaType, sha256: archive.sha256, bytes: archive.bytes.byteLength };
|
|
240
251
|
}
|
|
252
|
+
case 'move': {
|
|
253
|
+
const artifactId = argument();
|
|
254
|
+
if ((values.project !== undefined) === (values['no-project'] ?? false))
|
|
255
|
+
throw new UsageError('Specify exactly one of --project NAME or --no-project');
|
|
256
|
+
return mutate({ kind: 'move', command: moveSchema.parse({ artifactId, requestId: values['request-id'] ?? randomUUID(), project: values.project ?? null }) });
|
|
257
|
+
}
|
|
241
258
|
case 'retry': {
|
|
242
259
|
const requestId = argument();
|
|
243
260
|
const owner = await client.identity();
|
package/src/operations.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { createSchema, publishSchema, updateSchema } from '@yargote/artifacts-contracts';
|
|
2
|
+
import { createSchema, moveSchema, publishSchema, updateSchema } from '@yargote/artifacts-contracts';
|
|
3
3
|
import type { ArtifactHttpClient } from '@yargote/artifacts-client';
|
|
4
4
|
export declare const operationSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
5
5
|
kind: z.ZodLiteral<"create">;
|
|
@@ -29,6 +29,7 @@ export declare const operationSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
29
29
|
data: z.ZodString;
|
|
30
30
|
}, z.core.$strict>>;
|
|
31
31
|
}, z.core.$strict>;
|
|
32
|
+
project: z.ZodOptional<z.ZodString>;
|
|
32
33
|
response: z.ZodOptional<z.ZodEnum<{
|
|
33
34
|
full: "full";
|
|
34
35
|
compact: "compact";
|
|
@@ -86,6 +87,16 @@ export declare const operationSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
86
87
|
version: z.ZodLiteral<1>;
|
|
87
88
|
resource: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
|
|
88
89
|
ownerId: z.ZodString;
|
|
90
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
91
|
+
kind: z.ZodLiteral<"move">;
|
|
92
|
+
command: z.ZodObject<{
|
|
93
|
+
requestId: z.ZodString;
|
|
94
|
+
artifactId: z.ZodString;
|
|
95
|
+
project: z.ZodNullable<z.ZodString>;
|
|
96
|
+
}, z.core.$strict>;
|
|
97
|
+
version: z.ZodLiteral<1>;
|
|
98
|
+
resource: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
|
|
99
|
+
ownerId: z.ZodString;
|
|
89
100
|
}, z.core.$strict>], "kind">;
|
|
90
101
|
export type PreparedOperation = z.infer<typeof operationSchema>;
|
|
91
102
|
export type Mutation = {
|
|
@@ -97,48 +108,19 @@ export type Mutation = {
|
|
|
97
108
|
} | {
|
|
98
109
|
kind: 'publish';
|
|
99
110
|
command: z.input<typeof publishSchema>;
|
|
111
|
+
} | {
|
|
112
|
+
kind: 'move';
|
|
113
|
+
command: z.input<typeof moveSchema>;
|
|
100
114
|
};
|
|
101
115
|
export declare function operationPath(stateDir: string, resource: string, requestId: string): string;
|
|
102
116
|
export declare function retainOperation(stateDir: string, resource: string, ownerId: string, mutation: Mutation): Promise<PreparedOperation>;
|
|
103
117
|
export declare function loadOperation(stateDir: string, requestId: string, resource: string, ownerId: string): Promise<PreparedOperation>;
|
|
104
118
|
export declare function submitOperation(client: ArtifactHttpClient, operation: PreparedOperation): Promise<{
|
|
119
|
+
artifactId: string;
|
|
120
|
+
project: string | null;
|
|
121
|
+
}> | Promise<{
|
|
105
122
|
revisionId: string;
|
|
106
123
|
version: number;
|
|
107
124
|
url: string;
|
|
108
125
|
artifactId: string;
|
|
109
|
-
}
|
|
110
|
-
artifactId: string;
|
|
111
|
-
ownerId: string;
|
|
112
|
-
headRevisionId: string;
|
|
113
|
-
publication: {
|
|
114
|
-
revisionId: string;
|
|
115
|
-
version: number;
|
|
116
|
-
url: string;
|
|
117
|
-
} | null;
|
|
118
|
-
revision: {
|
|
119
|
-
id: string;
|
|
120
|
-
parentRevisionId: string | null;
|
|
121
|
-
sequence: number;
|
|
122
|
-
authorUserId: string;
|
|
123
|
-
authorClientId: string;
|
|
124
|
-
createdAt: string;
|
|
125
|
-
sha256: string;
|
|
126
|
-
snapshot: {
|
|
127
|
-
metadata: {
|
|
128
|
-
title: string;
|
|
129
|
-
description: string;
|
|
130
|
-
custom?: z.core.util.JSONType | undefined;
|
|
131
|
-
};
|
|
132
|
-
content: {
|
|
133
|
-
kind: "text" | "html" | "markdown";
|
|
134
|
-
text: string;
|
|
135
|
-
};
|
|
136
|
-
files: {
|
|
137
|
-
path: string;
|
|
138
|
-
mediaType: string;
|
|
139
|
-
encoding: "utf8" | "base64";
|
|
140
|
-
data: string;
|
|
141
|
-
}[];
|
|
142
|
-
};
|
|
143
|
-
};
|
|
144
|
-
} | import("@yargote/artifacts-client").CompactArtifactRead>;
|
|
126
|
+
}>;
|
package/src/operations.js
CHANGED
|
@@ -3,7 +3,7 @@ import { lstat, mkdir, open } from 'node:fs/promises';
|
|
|
3
3
|
import { createHash } from 'node:crypto';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
5
|
import { z } from 'zod';
|
|
6
|
-
import { createSchema, publishSchema, updateSchema } from '@yargote/artifacts-contracts';
|
|
6
|
+
import { createSchema, moveSchema, publishSchema, updateSchema } from '@yargote/artifacts-contracts';
|
|
7
7
|
import { canonicalResource } from '@yargote/artifacts-contracts/http';
|
|
8
8
|
const binding = {
|
|
9
9
|
version: z.literal(1),
|
|
@@ -14,6 +14,7 @@ export const operationSchema = z.discriminatedUnion('kind', [
|
|
|
14
14
|
z.strictObject({ ...binding, kind: z.literal('create'), command: createSchema }),
|
|
15
15
|
z.strictObject({ ...binding, kind: z.literal('update'), command: updateSchema }),
|
|
16
16
|
z.strictObject({ ...binding, kind: z.literal('publish'), command: publishSchema }),
|
|
17
|
+
z.strictObject({ ...binding, kind: z.literal('move'), command: moveSchema }),
|
|
17
18
|
]);
|
|
18
19
|
export function operationPath(stateDir, resource, requestId) {
|
|
19
20
|
createSchema.shape.requestId.parse(requestId);
|
|
@@ -86,5 +87,6 @@ export function submitOperation(client, operation) {
|
|
|
86
87
|
case 'create': return client.create(operation.command);
|
|
87
88
|
case 'update': return client.update(operation.command);
|
|
88
89
|
case 'publish': return client.publish(operation.command);
|
|
90
|
+
case 'move': return client.move(operation.command);
|
|
89
91
|
}
|
|
90
92
|
}
|