shapeup-cli 0.8.1 → 0.9.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cc0a67b4cc8086fc7ba5a2984d6be2b2eab9041ce4efe344e3030840e4cb6c21
4
- data.tar.gz: 2ae7641ddd1b78c4777200191c168e9d7b461785f552b598715864cf9555e4b9
3
+ metadata.gz: ecb0aff2791935bf727f5afbb283ec92bb181325bb57b8ba0d6778d05b18db26
4
+ data.tar.gz: 8f938f4be9b1dafc98c44916bcf539b936ba89fa0ca9c245cf78b1531c6a64c6
5
5
  SHA512:
6
- metadata.gz: 508c56acc3c2b28de638e76ac8ec7d5771daca19a5c083392cb876b4b2a8f6293c45205b158a55507ad7509f9be152b83c57a61cd2a90678967c9697e680c030
7
- data.tar.gz: c39c3a4ad91d481aee6cc60ed58eb30b21396323ef0de3f619e9f38564e63b67b9860dd4d445301354fee55217e107aa9cdf86d817baa083677b8e6df9b19e08
6
+ metadata.gz: f337c2f8aade0196c9cdaff8f48d7e10a4216736844e7b2381aa348dcc0855a12d8a0d3ee557fee7778599f1ab8bb15399676afcf87c8150b446e54e5328d323
7
+ data.tar.gz: 517305b0931a662d4b3b8a4cfb2910a3a879b64bfce4d303edaf7da7cf390a6f0c2c8f1155ab9f2f0261ec64c6ef69574fed070f564c0ad0b9f8b9ebe820149f
@@ -100,6 +100,14 @@ module ShapeupCli
100
100
  value
101
101
  end
102
102
 
103
+ def extract_options(flag)
104
+ values = []
105
+ while (value = extract_option(flag))
106
+ values << value
107
+ end
108
+ values
109
+ end
110
+
103
111
  # Get the first positional arg (not a flag)
104
112
  def positional_arg(position = 0)
105
113
  positionals = @remaining.reject { |a| a.start_with?("--") }
@@ -20,7 +20,8 @@ module ShapeupCli
20
20
  { name: "pitch", type: "string", usage: "Pitch ID" },
21
21
  { name: "scope", type: "string", usage: "Scope ID" },
22
22
  { name: "task", type: "string", usage: "Task ID" },
23
- { name: "parent", type: "string", usage: "Comment ID to reply under" }
23
+ { name: "parent", type: "string", usage: "Comment ID to reply under" },
24
+ { name: "attach", type: "string", usage: "Image to show under the comment (repeatable). Local ![description](path) images in the text are attached too" }
24
25
  ],
25
26
  examples: [
26
27
  "shapeup comments list --issue 42",
@@ -62,10 +63,15 @@ module ShapeupCli
62
63
  def add
63
64
  type, id = resolve_commentable
64
65
  parent = extract_option("--parent")
65
- text = positional_arg(1) || abort('Usage: shapeup comments add --issue <id> [--parent <comment_id>] "Comment text"')
66
+ attach_paths = extract_options("--attach")
67
+ text = positional_arg(1) || abort('Usage: shapeup comments add --issue <id> [--parent <comment_id>] [--attach <image>] "Comment text"')
68
+
69
+ text, images = local_images_in(text)
70
+ images += attach_paths.map { |path| [ path, nil ] }
66
71
 
67
72
  arguments = { commentable_type: type, commentable_id: id.to_s, content: text }
68
73
  arguments[:parent_id] = parent.to_s if parent
74
+ arguments[:attachments] = images.map { |path, alt| upload_image(path, alt) } if images.any?
69
75
  result = call_tool("create_comment", **arguments)
70
76
 
71
77
  render result,
@@ -103,6 +109,35 @@ module ShapeupCli
103
109
  render result, summary: "Reacted #{emoji} to comment ##{comment_id}"
104
110
  end
105
111
 
112
+ IMAGE_TYPES = { ".png" => "image/png", ".jpg" => "image/jpeg", ".jpeg" => "image/jpeg", ".gif" => "image/gif", ".webp" => "image/webp" }.freeze
113
+ IMAGE_MAX_SIZE = 10 * 1024 * 1024
114
+ MARKDOWN_IMAGE = /!\[([^\]]*)\]\(([^)\s]+)\)\n?/
115
+
116
+ def local_images_in(text)
117
+ images = []
118
+ text = text.gsub(MARKDOWN_IMAGE) do |markdown|
119
+ alt, path = $1, $2
120
+ if path.match?(%r{\A[a-z][a-z0-9+.-]*://}i) || !File.file?(path)
121
+ markdown
122
+ else
123
+ images << [ path, alt ]
124
+ ""
125
+ end
126
+ end
127
+ [ text.strip, images ]
128
+ end
129
+
130
+ def upload_image(path, alt)
131
+ abort "No such file: #{path}" unless File.file?(path)
132
+ content_type = IMAGE_TYPES[File.extname(path).downcase] or abort "Only PNG, JPEG, GIF and WebP images can be attached: #{path}"
133
+ abort "Images can be at most 10 MB: #{path}" if File.size(path) > IMAGE_MAX_SIZE
134
+
135
+ data = [ File.binread(path) ].pack("m0")
136
+ uploaded = Output.extract_data(call_tool("upload_attachment", filename: File.basename(path), content_type: content_type, data: data))
137
+
138
+ { attachment: uploaded["attachment"], alt: alt.to_s.empty? ? File.basename(path, ".*").tr("-_", " ") : alt }
139
+ end
140
+
106
141
  def resolve_commentable
107
142
  issue = extract_option("--issue")
108
143
  pitch = extract_option("--pitch")
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ShapeupCli
4
- VERSION = "0.8.1"
4
+ VERSION = "0.9.0"
5
5
  end
@@ -222,6 +222,7 @@ Branch on `retryable` to decide retry-vs-abandon; `false` means "no known reason
222
222
  | Watch the inbox as JSON lines | `SHAPEUP_PROFILE=<agent> shapeup connect` |
223
223
  | Reply under a comment | `shapeup comments add --issue <id> --parent <comment_id> "Reply"` |
224
224
  | React to a comment | `shapeup comments react <comment_id> 👀` |
225
+ | Attach screenshots to a comment | `shapeup comments add --issue <id> "Text ![What it shows](./shot.png)"` or `--attach shot.png` |
225
226
 
226
227
  ## Common Workflows
227
228
 
@@ -142,13 +142,20 @@ Give the subagent this, filled in:
142
142
  > commit there. Never push, deploy, merge or delete branches unless the owner said so in this
143
143
  > session.
144
144
  > 4. If the ask is unclear or you are blocked, ask on the issue rather than guess.
145
- > 5. Reply once, under the comment that asked:
145
+ > 5. If the work changes anything people see, show it. Use whatever browser tool you have to take
146
+ > screenshots of each place it touches, before (from the main branch) and after (from yours),
147
+ > at the size people use it and on a phone when it matters. Save them as PNG files outside the
148
+ > repository, with names that say what they show.
149
+ > 6. Reply once, under the comment that asked:
146
150
  > `shapeup --profile <profile> comments add --issue <issue.id> --parent <reply_to.comment_id> "<reply>"`
147
151
  > (leave out `--parent` when `reply_to.comment_id` is null). Start with `@<requester.name>`.
148
152
  > Say what changed, the branch and commit, how you checked it, and anything still open.
149
- > Keep it short and plain.
150
- > 6. Then take it out of the inbox: `shapeup --profile <profile> inbox done <id>`.
151
- > 7. Report back in one line.
153
+ > Keep it short and plain. Put each screenshot in the reply as a local Markdown image,
154
+ > `![Toolbar after the fix, on a phone](/tmp/toolbar-after-phone.png)`: the CLI uploads it and
155
+ > the words in brackets become its description for people who can't see it, so write them
156
+ > properly. Mention anyone the requester asked you to hand over to.
157
+ > 7. Then take it out of the inbox: `shapeup --profile <profile> inbox done <id>`.
158
+ > 8. Report back in one line.
152
159
 
153
160
  ## Rules
154
161
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shapeup-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ShapeUp