@yargote/artifacts-cli 0.1.0-beta.4 → 0.1.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -6
- package/package.json +3 -3
- package/skills/artifacts-cli/SKILL.md +11 -1
- package/skills/artifacts-cli/references/commands.md +21 -0
- 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 +14 -3
- package/src/operations.d.ts +46 -2
- package/src/operations.js +7 -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.6
|
|
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.6
|
|
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.6 --help
|
|
26
|
+
pnpm dlx @yargote/artifacts-cli@0.1.0-beta.6 --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.
|
|
@@ -64,7 +64,7 @@ artifacts export ARTIFACT_ID --revision REVISION_ID --out artifact.zip
|
|
|
64
64
|
artifacts logout
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
A publication URL requires sign-in. It opens for the owner and for a user whose verified email equals an email share of the artifact. That user sees only the published revision and its attachments. A retained request ID appears on stderr before each mutation. If the response is lost, run `artifacts retry REQUEST_ID` with the same server and state directory. Keep that state directory when upgrading, reinstalling, or switching between global and one-off execution.
|
|
68
68
|
|
|
69
69
|
## Upgrade or uninstall
|
|
70
70
|
|
|
@@ -124,6 +124,9 @@ artifacts publish [ID] --command FILE
|
|
|
124
124
|
artifacts export ID --revision REV --out FILE
|
|
125
125
|
artifacts move ID --project NAME [--request-id ID]
|
|
126
126
|
artifacts move ID --no-project [--request-id ID]
|
|
127
|
+
artifacts share ID --email EMAIL [--notify] [--request-id ID]
|
|
128
|
+
artifacts shares ID
|
|
129
|
+
artifacts unshare ID SHARE_ID [--request-id ID]
|
|
127
130
|
artifacts retry REQUEST_ID
|
|
128
131
|
artifacts skills [list]
|
|
129
132
|
artifacts skills get NAME [--full]
|
|
@@ -197,6 +200,27 @@ Every artifact read and list item includes `project`, a name or null. `projects`
|
|
|
197
200
|
|
|
198
201
|
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
202
|
|
|
203
|
+
## Share publication access
|
|
204
|
+
|
|
205
|
+
These commands are available from `0.1.0-beta.6`. Check installed help for support.
|
|
206
|
+
|
|
207
|
+
```sh
|
|
208
|
+
artifacts share ARTIFACT_ID --email ana@example.com --request-id share-ana-001
|
|
209
|
+
artifacts shares ARTIFACT_ID
|
|
210
|
+
artifacts unshare ARTIFACT_ID SHARE_ID --request-id unshare-ana-001
|
|
211
|
+
artifacts retry share-ana-001
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
`share` trims and lowercases the email and prints one share as JSON with `shareId`, `artifactId`, `kind: "email"`, `value`, and `createdAt`. `shares` prints `{ "items": [...] }` with current grants and retains no operation. Take `SHARE_ID` from that output. `unshare` and a successful retry of an unshare exit zero with empty stdout. All three commands require the owner's `artifacts:publish` scope.
|
|
215
|
+
|
|
216
|
+
A signed-in user whose verified email matches a share can view the published revision and its attachments. History, export, edits, and project moves remain owner-only. Shares created before first publication remain stored, but the URL opens only after publication. Add `--notify` to request one invitation email. Invited people can sign in with an email code when the server enables email.
|
|
217
|
+
|
|
218
|
+
Share and unshare retain the complete normalized command before submission. Recover an uncertain result with `retry REQUEST_ID`. A replay confirms the original operation, so a historical share replay does not restore a revoked grant. An old unshare replay leaves a deliberate new share intact. Run `shares ARTIFACT_ID` to verify current grants.
|
|
219
|
+
|
|
220
|
+
Share with `--notify` to request one email attempt. Access succeeds when mail is disabled or the owner has used the daily allowance. The JSON result adds `notification.status` as `requested` or `skipped`, with `disabled` or `rate_limited` as the skip reason. `requested` does not confirm delivery. A crash after commit can lose the message. An exact retry preserves the captured flag and never sends a second email. Use a new deliberate command to request another attempt for existing access.
|
|
221
|
+
|
|
222
|
+
Owners can reserve 100 invitations per UTC day. Revoke, deletion, and failed delivery do not refund reservations. New access is limited to 100 people per artifact and 1000 grants per owner. Existing access remains listable and revocable.
|
|
223
|
+
|
|
200
224
|
## Complete commands and edits
|
|
201
225
|
|
|
202
226
|
`--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.
|
|
@@ -228,7 +252,7 @@ Publish always selects an immutable revision. `--expected-version 0` expects no
|
|
|
228
252
|
|
|
229
253
|
Each invocation resolves one access token for its reads, owner check, and submission. A concurrent login cannot change the command owner between these requests. Every mutation verifies the owner and retains an exclusive private operation file before submission. Missing request IDs default to random UUIDs. The operation stores its exact command, owner, and resource. It contains no credentials. Existing operation files require explicit `retry` and are never replaced by another preparation.
|
|
230
254
|
|
|
231
|
-
`retry REQUEST_ID` verifies the current resource and owner, then sends the unchanged command once. Retry does not read a new head, change expected versions, add a response projection, or rebase a conflict. Its diagnostic identifies the
|
|
255
|
+
`retry REQUEST_ID` verifies the current resource and owner, then sends the unchanged command once. Retry does not read a new head, change expected versions, add a response projection, or rebase a conflict. Its diagnostic identifies replay of the original operation and warns that replay does not establish current state. A fresh `read` or `shares` returns current state.
|
|
232
256
|
|
|
233
257
|
If a response is lost after commit, retry recovers the original receipt. If a conflict occurs, the retained operation remains available for inspection. A new read and a deliberate new command with a new request ID are required to incorporate another writer's changes.
|
|
234
258
|
|
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.6",
|
|
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.6",
|
|
31
|
+
"@yargote/artifacts-client": "0.1.0-beta.6",
|
|
32
32
|
"openid-client": "6.8.8",
|
|
33
33
|
"zod": "4.6.5"
|
|
34
34
|
},
|
|
@@ -41,7 +41,17 @@ Use `move ID --project NAME` to file an existing artifact under a project and `m
|
|
|
41
41
|
|
|
42
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.
|
|
43
43
|
|
|
44
|
-
A published URL
|
|
44
|
+
A published URL requires sign-in by the owner or a user whose verified email matches a current share. Publishing a historical revision leaves the draft head unchanged. Report the returned protected URL only after the publication succeeds and its current state is verified.
|
|
45
|
+
|
|
46
|
+
## Share publication access
|
|
47
|
+
|
|
48
|
+
Check installed help for `share`, `shares`, and `unshare` support. These commands are available from `0.1.0-beta.6`. Share only when the user requests access for an exact email. Use `share ARTIFACT_ID --email EMAIL`, then verify the normalized email with `shares ARTIFACT_ID`. Use the observed `shareId` with `unshare ARTIFACT_ID SHARE_ID` to revoke it. Unshare and its successful retry exit zero with empty stdout.
|
|
49
|
+
|
|
50
|
+
A matching signed-in user must have a verified email. Access covers the published revision and its attachments. History, export, editing, and project moves stay owner-only. A share before first publication remains stored and waits for publication. Add `--notify` when the user asks for an invitation email. Invited people can sign in with an email code when the server enables email.
|
|
51
|
+
|
|
52
|
+
Recover uncertain share or unshare results with `retry REQUEST_ID`. Replay confirms the original operation and does not establish current grants. An old share replay does not restore revoked access. An old unshare replay does not remove a deliberate new share. Verify current grants with `shares ARTIFACT_ID`.
|
|
53
|
+
|
|
54
|
+
When the user asks to notify an invited person, add `--notify` to `artifacts share`. Preserve that flag in the retained command and use `artifacts retry` after an uncertain response. Report `requested` as an invitation request, never as confirmed delivery. A skipped notification still grants access. A new deliberate share command can request another attempt for existing access, subject to the owner's daily allowance.
|
|
45
55
|
|
|
46
56
|
## Recover an uncertain write
|
|
47
57
|
|
|
@@ -158,6 +158,27 @@ The publication example applies only to an unpublished artifact. For an existing
|
|
|
158
158
|
|
|
159
159
|
History returns `nextBeforeSequence`; pass it as `--before-sequence N` to continue. List returns `nextCursor`; pass it as `--cursor CURSOR`. Do not substitute an offset or assume that one page contains everything.
|
|
160
160
|
|
|
161
|
+
## Share publication access
|
|
162
|
+
|
|
163
|
+
Check installed help for these commands. They are available from `0.1.0-beta.6`.
|
|
164
|
+
|
|
165
|
+
```sh
|
|
166
|
+
artifacts share ARTIFACT_ID --email ana@example.com --request-id share-ana-001
|
|
167
|
+
artifacts shares ARTIFACT_ID
|
|
168
|
+
artifacts unshare ARTIFACT_ID SHARE_ID --request-id unshare-ana-001
|
|
169
|
+
artifacts retry share-ana-001
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Share requires the owner's `artifacts:publish` scope, trims and lowercases the email, and prints a share with `shareId`, `artifactId`, `kind: "email"`, `value`, and `createdAt`. `shares` requires the same scope and prints `{ "items": [...] }` with current grants without retaining a mutation. Use an observed `shareId` to unshare. Unshare requires the same scope. Unshare and its successful retry exit zero with empty stdout.
|
|
173
|
+
|
|
174
|
+
The publication admits the owner and signed-in users whose verified email matches a current share. Guests see the published revision and attachments. History, export, editing, and project moves remain owner-only. Shares before first publication wait for publication. Add `--notify` to request one invitation email. Invited people can sign in with an email code when the server enables email.
|
|
175
|
+
|
|
176
|
+
Share and unshare retain complete normalized commands. `retry REQUEST_ID` replays the original operation. A historical share replay does not regrant revoked access, and an old unshare replay leaves a deliberate new share intact. Verify current grants with `shares ARTIFACT_ID` after a replay.
|
|
177
|
+
|
|
178
|
+
Share with `--notify` to request one email attempt. Access succeeds when mail is disabled or the owner has used the daily allowance. The JSON result adds `notification.status` as `requested` or `skipped`, with `disabled` or `rate_limited` as the skip reason. `requested` does not confirm delivery. A crash after commit can lose the message. An exact retry preserves the captured flag and never sends a second email. Use a new deliberate command to request another attempt for existing access.
|
|
179
|
+
|
|
180
|
+
Owners can reserve 100 invitations per UTC day. Revoke, deletion, and failed delivery do not refund reservations. New access is limited to 100 people per artifact and 1000 grants per owner. Existing access remains listable and revocable.
|
|
181
|
+
|
|
161
182
|
## Retry and export
|
|
162
183
|
|
|
163
184
|
```sh
|
|
@@ -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, moveSchema, publishSchema, updateSchema } from '@yargote/artifacts-contracts';
|
|
9
|
+
import { createSchema, listSharesSchema, moveSchema, publishSchema, shareSchema, unshareSchema, 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";
|
|
@@ -46,6 +46,9 @@ Commands:
|
|
|
46
46
|
export ID --revision REV --out FILE
|
|
47
47
|
move ID --project NAME [--request-id ID]
|
|
48
48
|
move ID --no-project [--request-id ID]
|
|
49
|
+
share ID --email EMAIL [--notify] [--request-id ID]
|
|
50
|
+
shares ID
|
|
51
|
+
unshare ID SHARE_ID [--request-id ID]
|
|
49
52
|
retry REQUEST_ID
|
|
50
53
|
|
|
51
54
|
Mutation command files contain the complete create, update, or publish JSON.
|
|
@@ -75,6 +78,7 @@ const commandOptions = {
|
|
|
75
78
|
update: ['snapshot', 'expected-revision', 'request-id', 'response', 'command'],
|
|
76
79
|
edit: ['changes', 'request-id'], history: ['limit', 'before-sequence', 'summary'],
|
|
77
80
|
publish: ['revision', 'expected-version', 'request-id', 'command'],
|
|
81
|
+
share: ['email', 'notify', 'request-id'], shares: [], unshare: ['request-id'],
|
|
78
82
|
export: ['revision', 'out'], move: ['project', 'no-project', 'request-id'], retry: [],
|
|
79
83
|
skills: ['full', 'all', 'agent', 'global', 'force'],
|
|
80
84
|
};
|
|
@@ -112,7 +116,7 @@ async function main() {
|
|
|
112
116
|
summary: { type: 'boolean' }, out: { type: 'string' }, quiet: { type: 'boolean' },
|
|
113
117
|
full: { type: 'boolean' }, all: { type: 'boolean' }, agent: { type: 'string' },
|
|
114
118
|
global: { type: 'boolean' }, force: { type: 'boolean' },
|
|
115
|
-
project: { type: 'string' }, 'no-project': { type: 'boolean' },
|
|
119
|
+
project: { type: 'string' }, 'no-project': { type: 'boolean' }, email: { type: 'string' }, notify: { type: 'boolean' },
|
|
116
120
|
},
|
|
117
121
|
});
|
|
118
122
|
const seen = new Set();
|
|
@@ -255,11 +259,18 @@ async function main() {
|
|
|
255
259
|
throw new UsageError('Specify exactly one of --project NAME or --no-project');
|
|
256
260
|
return mutate({ kind: 'move', command: moveSchema.parse({ artifactId, requestId: values['request-id'] ?? randomUUID(), project: values.project ?? null }) });
|
|
257
261
|
}
|
|
262
|
+
case 'share': return mutate({ kind: 'share', command: shareSchema.parse({ artifactId: argument(), requestId: values['request-id'] ?? randomUUID(), email: required('email'), ...(values.notify === undefined ? {} : { notify: values.notify }) }) });
|
|
263
|
+
case 'shares': return client.listShares(listSharesSchema.parse({ artifactId: argument() }));
|
|
264
|
+
case 'unshare': {
|
|
265
|
+
if (arguments_.length !== 2)
|
|
266
|
+
throw new UsageError('unshare requires two positional arguments');
|
|
267
|
+
return mutate({ kind: 'unshare', command: unshareSchema.parse({ artifactId: arguments_[0], shareId: arguments_[1], requestId: values['request-id'] ?? randomUUID() }) });
|
|
268
|
+
}
|
|
258
269
|
case 'retry': {
|
|
259
270
|
const requestId = argument();
|
|
260
271
|
const owner = await client.identity();
|
|
261
272
|
const operation = await loadOperation(stateDir, requestId, resource, owner.userId);
|
|
262
|
-
process.stderr.write(`Replaying retained ${operation.kind} operation ${requestId}.
|
|
273
|
+
process.stderr.write(`Replaying retained ${operation.kind} operation ${requestId}. Replay confirms the original operation and does not establish current state.\n`);
|
|
263
274
|
return submitOperation(client, operation);
|
|
264
275
|
}
|
|
265
276
|
}
|
package/src/operations.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { createSchema, moveSchema, publishSchema, updateSchema } from '@yargote/artifacts-contracts';
|
|
2
|
+
import { createSchema, moveSchema, publishSchema, shareSchema, unshareSchema, 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">;
|
|
@@ -97,6 +97,28 @@ export declare const operationSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
97
97
|
version: z.ZodLiteral<1>;
|
|
98
98
|
resource: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
|
|
99
99
|
ownerId: z.ZodString;
|
|
100
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
101
|
+
kind: z.ZodLiteral<"share">;
|
|
102
|
+
command: z.ZodObject<{
|
|
103
|
+
requestId: z.ZodString;
|
|
104
|
+
artifactId: z.ZodString;
|
|
105
|
+
email: z.ZodPipe<z.ZodString, z.ZodEmail>;
|
|
106
|
+
notify: z.ZodOptional<z.ZodBoolean>;
|
|
107
|
+
requireNew: z.ZodOptional<z.ZodLiteral<true>>;
|
|
108
|
+
}, z.core.$strict>;
|
|
109
|
+
version: z.ZodLiteral<1>;
|
|
110
|
+
resource: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
|
|
111
|
+
ownerId: z.ZodString;
|
|
112
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
113
|
+
kind: z.ZodLiteral<"unshare">;
|
|
114
|
+
command: z.ZodObject<{
|
|
115
|
+
requestId: z.ZodString;
|
|
116
|
+
artifactId: z.ZodString;
|
|
117
|
+
shareId: z.ZodString;
|
|
118
|
+
}, z.core.$strict>;
|
|
119
|
+
version: z.ZodLiteral<1>;
|
|
120
|
+
resource: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
|
|
121
|
+
ownerId: z.ZodString;
|
|
100
122
|
}, z.core.$strict>], "kind">;
|
|
101
123
|
export type PreparedOperation = z.infer<typeof operationSchema>;
|
|
102
124
|
export type Mutation = {
|
|
@@ -111,11 +133,33 @@ export type Mutation = {
|
|
|
111
133
|
} | {
|
|
112
134
|
kind: 'move';
|
|
113
135
|
command: z.input<typeof moveSchema>;
|
|
136
|
+
} | {
|
|
137
|
+
kind: 'share';
|
|
138
|
+
command: z.input<typeof shareSchema>;
|
|
139
|
+
} | {
|
|
140
|
+
kind: 'unshare';
|
|
141
|
+
command: z.input<typeof unshareSchema>;
|
|
114
142
|
};
|
|
115
143
|
export declare function operationPath(stateDir: string, resource: string, requestId: string): string;
|
|
116
144
|
export declare function retainOperation(stateDir: string, resource: string, ownerId: string, mutation: Mutation): Promise<PreparedOperation>;
|
|
117
145
|
export declare function loadOperation(stateDir: string, requestId: string, resource: string, ownerId: string): Promise<PreparedOperation>;
|
|
118
|
-
export declare function submitOperation(client: ArtifactHttpClient, operation: PreparedOperation): Promise<{
|
|
146
|
+
export declare function submitOperation(client: ArtifactHttpClient, operation: PreparedOperation): Promise<void> | Promise<{
|
|
147
|
+
shareId: string;
|
|
148
|
+
artifactId: string;
|
|
149
|
+
kind: "email";
|
|
150
|
+
value: string;
|
|
151
|
+
createdAt: string;
|
|
152
|
+
notification?: {
|
|
153
|
+
status: "requested";
|
|
154
|
+
} | {
|
|
155
|
+
status: "skipped";
|
|
156
|
+
reason: "disabled";
|
|
157
|
+
} | {
|
|
158
|
+
status: "skipped";
|
|
159
|
+
reason: "rate_limited";
|
|
160
|
+
retryAt: string;
|
|
161
|
+
} | undefined;
|
|
162
|
+
}> | Promise<{
|
|
119
163
|
artifactId: string;
|
|
120
164
|
project: string | null;
|
|
121
165
|
}> | Promise<{
|
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, moveSchema, publishSchema, updateSchema } from '@yargote/artifacts-contracts';
|
|
6
|
+
import { createSchema, moveSchema, publishSchema, shareSchema, unshareSchema, updateSchema } from '@yargote/artifacts-contracts';
|
|
7
7
|
import { canonicalResource } from '@yargote/artifacts-contracts/http';
|
|
8
8
|
const binding = {
|
|
9
9
|
version: z.literal(1),
|
|
@@ -15,6 +15,8 @@ export const operationSchema = z.discriminatedUnion('kind', [
|
|
|
15
15
|
z.strictObject({ ...binding, kind: z.literal('update'), command: updateSchema }),
|
|
16
16
|
z.strictObject({ ...binding, kind: z.literal('publish'), command: publishSchema }),
|
|
17
17
|
z.strictObject({ ...binding, kind: z.literal('move'), command: moveSchema }),
|
|
18
|
+
z.strictObject({ ...binding, kind: z.literal('share'), command: shareSchema }),
|
|
19
|
+
z.strictObject({ ...binding, kind: z.literal('unshare'), command: unshareSchema }),
|
|
18
20
|
]);
|
|
19
21
|
export function operationPath(stateDir, resource, requestId) {
|
|
20
22
|
createSchema.shape.requestId.parse(requestId);
|
|
@@ -88,5 +90,9 @@ export function submitOperation(client, operation) {
|
|
|
88
90
|
case 'update': return client.update(operation.command);
|
|
89
91
|
case 'publish': return client.publish(operation.command);
|
|
90
92
|
case 'move': return client.move(operation.command);
|
|
93
|
+
case 'share': return client.share(operation.command);
|
|
94
|
+
case 'unshare': return client.unshare(operation.command);
|
|
91
95
|
}
|
|
96
|
+
const exhaustive = operation;
|
|
97
|
+
throw new Error(`Unsupported retained operation: ${exhaustive}`);
|
|
92
98
|
}
|