shapeup-cli 0.8.1 → 0.10.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 +4 -4
- data/lib/shapeup_cli/commands/base.rb +8 -0
- data/lib/shapeup_cli/commands/comments.rb +32 -4
- data/lib/shapeup_cli/version.rb +1 -1
- data/skills/shapeup/SKILL.md +1 -0
- data/skills/shapeup-connect/SKILL.md +31 -6
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f7f49a40c881c3e40aa1749a419a41139d02a5c3066113e851efecf544cddc84
|
|
4
|
+
data.tar.gz: baa1415c2d57ea6aeeb74c4562e67773041ddd72ad9d27667bf34756faca8e56
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 83fb9f6f9978710170a847e270469de2b7b0d57381adb4751a0748db279477e6780d2ca87176f1f787a06cd89c5594e7cd65533c773d6b7fb12b7d0f3ee3747d
|
|
7
|
+
data.tar.gz: '098b476ae487d54975b7726227407462452da622fb5a7b188de2bd72d42a902dfc10f2fe474874eda44069b2014b5ea7d725a021e8cd988e90c7f8fa009faf11'
|
|
@@ -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  images in the text are attached too" }
|
|
24
25
|
],
|
|
25
26
|
examples: [
|
|
26
27
|
"shapeup comments list --issue 42",
|
|
@@ -62,10 +63,12 @@ module ShapeupCli
|
|
|
62
63
|
def add
|
|
63
64
|
type, id = resolve_commentable
|
|
64
65
|
parent = extract_option("--parent")
|
|
65
|
-
|
|
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"')
|
|
66
68
|
|
|
67
|
-
arguments = { commentable_type: type, commentable_id: id.to_s, content: text }
|
|
69
|
+
arguments = { commentable_type: type, commentable_id: id.to_s, content: place_local_images(text) }
|
|
68
70
|
arguments[:parent_id] = parent.to_s if parent
|
|
71
|
+
arguments[:attachments] = attach_paths.map { |path| upload_image(path, nil) } if attach_paths.any?
|
|
69
72
|
result = call_tool("create_comment", **arguments)
|
|
70
73
|
|
|
71
74
|
render result,
|
|
@@ -79,7 +82,7 @@ module ShapeupCli
|
|
|
79
82
|
comment_id = positional_arg(1) || abort('Usage: shapeup comments edit <comment_id> "New text"')
|
|
80
83
|
text = positional_arg(2) || abort('Usage: shapeup comments edit <comment_id> "New text"')
|
|
81
84
|
|
|
82
|
-
result = call_tool("update_comment", comment_id: comment_id.to_s, content: text)
|
|
85
|
+
result = call_tool("update_comment", comment_id: comment_id.to_s, content: place_local_images(text))
|
|
83
86
|
|
|
84
87
|
render result, summary: "Comment ##{comment_id} updated"
|
|
85
88
|
end
|
|
@@ -103,6 +106,31 @@ module ShapeupCli
|
|
|
103
106
|
render result, summary: "Reacted #{emoji} to comment ##{comment_id}"
|
|
104
107
|
end
|
|
105
108
|
|
|
109
|
+
IMAGE_TYPES = { ".png" => "image/png", ".jpg" => "image/jpeg", ".jpeg" => "image/jpeg", ".gif" => "image/gif", ".webp" => "image/webp" }.freeze
|
|
110
|
+
IMAGE_MAX_SIZE = 10 * 1024 * 1024
|
|
111
|
+
MARKDOWN_IMAGE = /!\[([^\]]*)\]\(([^)\s]+)(?:\s+"([^"]*)")?\)/
|
|
112
|
+
|
|
113
|
+
def place_local_images(text)
|
|
114
|
+
text.gsub(MARKDOWN_IMAGE) do |markdown|
|
|
115
|
+
alt, path, caption = $1, $2, $3
|
|
116
|
+
next markdown if path.match?(%r{\A[a-z][a-z0-9+.-]*:}i) || !File.file?(path)
|
|
117
|
+
|
|
118
|
+
uploaded = upload_image(path, alt)
|
|
119
|
+
%(![#{uploaded[:alt]}](attachment:#{uploaded[:attachment]}#{%( "#{caption}") if caption}))
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def upload_image(path, alt)
|
|
124
|
+
abort "No such file: #{path}" unless File.file?(path)
|
|
125
|
+
content_type = IMAGE_TYPES[File.extname(path).downcase] or abort "Only PNG, JPEG, GIF and WebP images can be attached: #{path}"
|
|
126
|
+
abort "Images can be at most 10 MB: #{path}" if File.size(path) > IMAGE_MAX_SIZE
|
|
127
|
+
|
|
128
|
+
data = [ File.binread(path) ].pack("m0")
|
|
129
|
+
uploaded = Output.extract_data(call_tool("upload_attachment", filename: File.basename(path), content_type: content_type, data: data))
|
|
130
|
+
|
|
131
|
+
{ attachment: uploaded["attachment"], alt: alt.to_s.empty? ? File.basename(path, ".*").tr("-_", " ") : alt }
|
|
132
|
+
end
|
|
133
|
+
|
|
106
134
|
def resolve_commentable
|
|
107
135
|
issue = extract_option("--issue")
|
|
108
136
|
pitch = extract_option("--pitch")
|
data/lib/shapeup_cli/version.rb
CHANGED
data/skills/shapeup/SKILL.md
CHANGED
|
@@ -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 "` (stays where you put it; images on consecutive lines sit side by side) or `--attach shot.png` (added at the end) |
|
|
225
226
|
|
|
226
227
|
## Common Workflows
|
|
227
228
|
|
|
@@ -142,13 +142,38 @@ 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.
|
|
145
|
+
> 5. If the work changes anything people see, compare it the way a careful reviewer would:
|
|
146
|
+
> - From your diff, list the screens and states it touches, including the ones it could break.
|
|
147
|
+
> - Run the main branch beside yours: check main out into a git worktree outside this
|
|
148
|
+
> repository and start it on a second port, so both are up at once. How to start and sign in
|
|
149
|
+
> to the app should be in the project's CLAUDE.md or README; if it isn't, ask on the issue.
|
|
150
|
+
> - With whatever browser tool you have, capture each screen in both, at the same size and with
|
|
151
|
+
> the same content, plus a phone width and dark mode where they matter. Save PNGs outside the
|
|
152
|
+
> repository, named for what they show.
|
|
153
|
+
> - Stop the second server and remove the worktree when you're done.
|
|
154
|
+
> 6. Reply once, under the comment that asked:
|
|
146
155
|
> `shapeup --profile <profile> comments add --issue <issue.id> --parent <reply_to.comment_id> "<reply>"`
|
|
147
|
-
> (leave out `--parent` when `reply_to.comment_id` is null). Start with `@<requester.name
|
|
148
|
-
>
|
|
149
|
-
>
|
|
150
|
-
>
|
|
151
|
-
>
|
|
156
|
+
> (leave out `--parent` when `reply_to.comment_id` is null). Start with `@<requester.name>`,
|
|
157
|
+
> then say what changed, the branch and commit, and how you checked it. Keep it plain.
|
|
158
|
+
>
|
|
159
|
+
> When you have screenshots, write the rest like a review: a `## heading` per area, a line on
|
|
160
|
+
> what changed there, then its before and after as local Markdown images on consecutive lines,
|
|
161
|
+
> so they sit side by side:
|
|
162
|
+
>
|
|
163
|
+
> ```markdown
|
|
164
|
+
> ## Toolbar
|
|
165
|
+
> Looks the same. Dropdowns now open with focus on the first item.
|
|
166
|
+
>
|
|
167
|
+
> 
|
|
168
|
+
> 
|
|
169
|
+
> ```
|
|
170
|
+
>
|
|
171
|
+
> The CLI uploads each image where it stands. The words in brackets are its description for
|
|
172
|
+
> people who can't see it, so say what it shows; the quoted word is its caption. End with a
|
|
173
|
+
> `## Worth a look` section for anything that seems off, and mention whoever the requester asked
|
|
174
|
+
> you to hand over to.
|
|
175
|
+
> 7. Then take it out of the inbox: `shapeup --profile <profile> inbox done <id>`.
|
|
176
|
+
> 8. Report back in one line.
|
|
152
177
|
|
|
153
178
|
## Rules
|
|
154
179
|
|