@pixelhop/dit 0.3.0 → 0.4.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 CHANGED
@@ -116,11 +116,15 @@ dit upload --project marketing-site --review pr-1234 \
116
116
 
117
117
  `--review` takes either an existing `rev_…` id or your own reference — a PR number, a run
118
118
  id, anything stable. A reference that has been seen before reuses that review, so a job
119
- that runs twice on the same PR adds revisions instead of a second review. `--project`
119
+ that runs twice on the same PR adds screens to the existing review. To update an existing
120
+ screen, use `dit revision --artifact <id>` instead. `--project`
120
121
  takes the project slug or its `prj_…` id.
121
122
 
122
123
  Per-capture context, all optional: `--route /checkout`, `--viewport 390x844@3`,
123
- `--scenario "logged out"`, `--title`. Pass `--json` for the machine-readable form; the
124
+ `--scenario "logged out"`, `--title`, `--description`, and `--group`. Give each screen a
125
+ clear title and describe what the reviewer should check. These flags apply to every file
126
+ in a command; use separate commands with the same `--round` key when titles, descriptions
127
+ or viewports differ. Pass `--json` for the machine-readable form; the
124
128
  default prints the review URL and the Markdown block to paste into a PR.
125
129
 
126
130
  Images are sniffed by magic bytes (PNG, JPEG, WebP, GIF) and their dimensions read from
@@ -128,6 +132,42 @@ the file, so a mislabelled extension does not matter. For MP4 and WebM the CLI s
128
132
  to `ffprobe` for duration and dimensions, and to `ffmpeg` for a poster frame — both are
129
133
  optional. Without them the upload still succeeds, with a warning, minus the poster.
130
134
 
135
+ ### Design alternatives
136
+
137
+ Use the same `--group` name within a review for alternatives to the same design. Upload
138
+ options separately so each has its own title, description, artifact ID and revision history:
139
+
140
+ ```bash
141
+ dit upload --project marketing-site --review pr-1234 --file checkout-a.png \
142
+ --title "Checkout — compact" --description "Shorter form with an inline order summary" \
143
+ --group "Checkout layout" --round checkout-options --summary "Two checkout layouts to compare"
144
+ dit upload --project marketing-site --review pr-1234 --file checkout-b.png \
145
+ --title "Checkout — split" --description "Form and order summary side by side" \
146
+ --group "Checkout layout" --round checkout-options
147
+ ```
148
+
149
+ Use `--json` to get artifact IDs and keep them for later `revision` commands. A variation group
150
+ connects alternatives; a round groups a batch of changes. The human chooses the preferred
151
+ option.
152
+
153
+ ### Review rounds
154
+
155
+ Each upload or revision command creates one round; an upload includes all of its files. Use the same
156
+ `--round` key on upload and revision commands to group one batch of changes:
157
+
158
+ ```sh
159
+ dit revision --artifact art_123 --file overview.png --round polish-2 --summary "Tightened spacing and simplified the mobile header"
160
+ dit upload --project my-app --review rev_123 --file mobile.png --round polish-2
161
+ ```
162
+
163
+ Use a new key for the next batch. Historical round keys cannot be extended after a
164
+ new round starts. The first declaration supplies the round's optional summary.
165
+ Review rounds track evidence; screen titles, choices and feedback retain their
166
+ current state. Older uploads are shown as an Earlier uploads baseline.
167
+ Rounds let the reviewer step through the evidence timeline. Their Updated filter and
168
+ Mark as seen state are personal: agents must not clear them or verify the review.
169
+ After a feedback pass, reply, mark the relevant threads addressed, and return the review URL.
170
+
131
171
  ### `dit feedback`
132
172
 
133
173
  ```bash
package/dist/args.d.ts CHANGED
@@ -16,7 +16,11 @@ export type CliArgs = ({
16
16
  review: string;
17
17
  files: string[];
18
18
  } & RuntimeFlags & JsonFlag & {
19
+ round?: string;
20
+ summary?: string;
19
21
  title?: string;
22
+ description?: string;
23
+ group?: string;
20
24
  commit?: string;
21
25
  branch?: string;
22
26
  route?: string;
@@ -38,6 +42,8 @@ export type CliArgs = ({
38
42
  command: "revision";
39
43
  artifact: string;
40
44
  file: string;
45
+ round?: string;
46
+ summary?: string;
41
47
  } & RuntimeFlags & JsonFlag) | ({
42
48
  command: "markdown";
43
49
  review: string;
package/dist/args.js CHANGED
@@ -7,11 +7,15 @@ const runtimeOptions = {
7
7
  };
8
8
  const commandOptions = {
9
9
  upload: {
10
+ round: { type: "string" },
11
+ summary: { type: "string" },
10
12
  ...runtimeOptions,
11
13
  project: { type: "string" },
12
14
  review: { type: "string" },
13
15
  file: { type: "string", multiple: true },
14
16
  title: { type: "string" },
17
+ description: { type: "string" },
18
+ group: { type: "string" },
15
19
  commit: { type: "string" },
16
20
  branch: { type: "string" },
17
21
  route: { type: "string" },
@@ -36,6 +40,8 @@ const commandOptions = {
36
40
  message: { type: "string" },
37
41
  },
38
42
  revision: {
43
+ round: { type: "string" },
44
+ summary: { type: "string" },
39
45
  ...runtimeOptions,
40
46
  artifact: { type: "string" },
41
47
  file: { type: "string" },
@@ -98,7 +104,11 @@ export function parseCliArgs(argv) {
98
104
  project: required(values, "project", name),
99
105
  review: required(values, "review", name),
100
106
  files,
107
+ ...optional(values, "round"),
108
+ ...optional(values, "summary"),
101
109
  ...optional(values, "title"),
110
+ ...optional(values, "description"),
111
+ ...optional(values, "group"),
102
112
  ...optional(values, "commit"),
103
113
  ...optional(values, "branch"),
104
114
  ...optional(values, "route"),
@@ -156,6 +166,8 @@ export function parseCliArgs(argv) {
156
166
  command: name,
157
167
  artifact: required(values, "artifact", name),
158
168
  file: required(values, "file", name),
169
+ ...optional(values, "round"),
170
+ ...optional(values, "summary"),
159
171
  ...(values.json ? { json: true } : {}),
160
172
  ...runtime,
161
173
  };
package/dist/index.js CHANGED
@@ -22,7 +22,7 @@ Commands:
22
22
  feedback --review <ref|id> [--status open|addressed|resolved|all] [--json]
23
23
  reply --thread <id> --message <text>
24
24
  address --thread <id> [--message <text>]
25
- revision --artifact <id> --file <path> [--json]
25
+ revision --artifact <id> --file <path> [--round <key>] [--summary <text>] [--json]
26
26
  markdown --review <ref|id>
27
27
  project create --name <name> [--json]
28
28
 
@@ -35,6 +35,19 @@ Global options:
35
35
  Upload options:
36
36
  --title <text> --commit <sha> --branch <name> --route <path>
37
37
  --viewport <WIDTHxHEIGHT[@SCALE]> --scenario <name> --json
38
+ --description <text> --group <name> Context and alternatives for the same design
39
+ --round <key> --summary <text> Group uploads into a review round with a change summary
40
+
41
+ Review workflow:
42
+ Give screens a clear --title and --description. Upload flags apply to every file.
43
+ Alternatives: upload each option with a distinct title and the same --group name.
44
+ Existing screen: use revision --artifact <id> to retain its history and notes.
45
+ One feedback pass: share a --round key across upload and revision commands.
46
+ Use a new key for the next pass; older rounds cannot be extended once a new one starts.
47
+ The first command sets --summary. Without --round, each command creates a round.
48
+ Reuse --review for the same PR; upload adds screens, revision updates a screen.
49
+ Read feedback --json, fix, upload revisions, reply, then address the threads.
50
+ Humans choose preferred designs, mark updates as seen, and verify reviews.
38
51
  `;
39
52
  async function main() {
40
53
  const args = parseCliArgs(process.argv.slice(2));
@@ -1,3 +1,4 @@
1
+ import { randomUUID } from "node:crypto";
1
2
  import { getCatalog, resolveProject, resolveReview } from "./catalog.js";
2
3
  import { ApiError } from "./errors.js";
3
4
  import { prepareMedia } from "./media.js";
@@ -62,6 +63,7 @@ async function upload(args, client, output) {
62
63
  },
63
64
  });
64
65
  }
66
+ const roundKey = args.round ?? randomUUID();
65
67
  const completions = [];
66
68
  for (const file of args.files) {
67
69
  const prepared = await prepareMedia(file, output.warn);
@@ -69,9 +71,13 @@ async function upload(args, client, output) {
69
71
  completions.push(await declareUploadComplete(client, prepared, {
70
72
  path: "/v1/artifacts/uploads",
71
73
  declaration: {
74
+ roundKey,
75
+ ...(args.summary ? { roundSummary: args.summary } : {}),
72
76
  reviewId: reviewPayload.review.id,
73
77
  kind: prepared.kind,
74
78
  title: args.title ?? stripExtension(prepared.name),
79
+ ...(args.description ? { description: args.description } : {}),
80
+ ...(args.group ? { variationGroup: args.group } : {}),
75
81
  ...(args.route ? { route: args.route } : {}),
76
82
  ...(args.viewport ? { viewport: args.viewport } : {}),
77
83
  ...(args.commit ? { commit: args.commit } : {}),
@@ -100,7 +106,10 @@ async function revision(args, client, output) {
100
106
  try {
101
107
  const completion = await declareUploadComplete(client, prepared, {
102
108
  path: `/v1/artifacts/${encodeURIComponent(args.artifact)}/revisions`,
103
- declaration: {},
109
+ declaration: {
110
+ roundKey: args.round ?? randomUUID(),
111
+ ...(args.summary ? { roundSummary: args.summary } : {}),
112
+ },
104
113
  });
105
114
  if (args.json) {
106
115
  output.out(printJson(completion));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixelhop/dit",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Did It Though? CLI for coding agents — upload PR screenshots and videos, pull structured feedback back",
5
5
  "keywords": [
6
6
  "agents",