@bdsqqq/lnr-cli 1.3.0 → 1.3.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bdsqqq/lnr-cli",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "cli for linear issue tracking",
5
5
  "type": "module",
6
6
  "private": false,
@@ -228,61 +228,27 @@ async function handleUpdateIssue(
228
228
  exitWithError(`issue ${identifier} not found`, undefined, EXIT_CODES.NOT_FOUND);
229
229
  }
230
230
 
231
- if (input.comment) {
232
- await addComment(client, issue.id, input.comment);
233
- console.log(`commented on ${identifier}`);
234
- return;
231
+ // Upfront validation: required flags
232
+ if (input.editComment && !input.text) {
233
+ exitWithError("--text is required with --edit-comment");
235
234
  }
236
-
237
- if (input.editComment) {
238
- if (!input.text) {
239
- exitWithError("--text is required with --edit-comment");
240
- }
241
- await updateComment(client, input.editComment, input.text);
242
- console.log(`updated comment ${input.editComment.slice(0, 8)}`);
243
- return;
235
+ if (input.replyTo && !input.text) {
236
+ exitWithError("--text is required with --reply-to");
244
237
  }
245
-
246
- if (input.replyTo) {
247
- if (!input.text) {
248
- exitWithError("--text is required with --reply-to");
249
- }
250
- await replyToComment(client, issue.id, input.replyTo, input.text);
251
- console.log(`replied to comment ${input.replyTo.slice(0, 8)}`);
252
- return;
238
+ if (input.react && !input.emoji) {
239
+ exitWithError("--emoji is required with --react");
253
240
  }
254
241
 
255
- if (input.deleteComment) {
256
- await deleteComment(client, input.deleteComment);
257
- console.log(`deleted comment ${input.deleteComment.slice(0, 8)}`);
258
- return;
242
+ // Upfront validation: mutual exclusivity for comment operations
243
+ const commentOpCount = [input.comment, input.editComment, input.replyTo, input.deleteComment].filter(Boolean).length;
244
+ if (commentOpCount > 1) {
245
+ exitWithError("only one comment operation allowed per invocation", "use --comment, --edit-comment, --reply-to, or --delete-comment separately");
259
246
  }
260
247
 
261
- if (input.archive) {
262
- await archiveIssue(client, issue.id);
263
- console.log(`archived ${identifier}`);
264
- return;
265
- }
266
-
267
- if (input.react) {
268
- if (!input.emoji) {
269
- exitWithError("--emoji is required with --react");
270
- }
271
- const success = await createReaction(client, input.react, input.emoji);
272
- if (!success) {
273
- exitWithError(`failed to add reaction to comment ${input.react.slice(0, 8)}`);
274
- }
275
- console.log(`added reaction ${input.emoji} to comment ${input.react.slice(0, 8)}`);
276
- return;
277
- }
278
-
279
- if (input.unreact) {
280
- const success = await deleteReaction(client, input.unreact);
281
- if (!success) {
282
- exitWithError(`reaction ${input.unreact.slice(0, 8)} not found`, undefined, EXIT_CODES.NOT_FOUND);
283
- }
284
- console.log(`removed reaction ${input.unreact.slice(0, 8)}`);
285
- return;
248
+ // Upfront validation: mutual exclusivity for reaction operations
249
+ const reactionOpCount = [input.react, input.unreact].filter(Boolean).length;
250
+ if (reactionOpCount > 1) {
251
+ exitWithError("only one reaction operation allowed per invocation", "use --react or --unreact separately");
286
252
  }
287
253
 
288
254
  const updatePayload: Record<string, unknown> = {};
@@ -421,6 +387,50 @@ async function handleUpdateIssue(
421
387
  }
422
388
  console.log(`${identifier} now relates to ${input.relatesTo}`);
423
389
  }
390
+
391
+ // Comment operations (mutually exclusive, validated above)
392
+ if (input.comment) {
393
+ await addComment(client, issue.id, input.comment);
394
+ console.log(`commented on ${identifier}`);
395
+ }
396
+
397
+ if (input.editComment) {
398
+ await updateComment(client, input.editComment, input.text!);
399
+ console.log(`updated comment ${input.editComment.slice(0, 8)}`);
400
+ }
401
+
402
+ if (input.replyTo) {
403
+ await replyToComment(client, issue.id, input.replyTo, input.text!);
404
+ console.log(`replied to comment ${input.replyTo.slice(0, 8)}`);
405
+ }
406
+
407
+ if (input.deleteComment) {
408
+ await deleteComment(client, input.deleteComment);
409
+ console.log(`deleted comment ${input.deleteComment.slice(0, 8)}`);
410
+ }
411
+
412
+ // Reaction operations (mutually exclusive, validated above)
413
+ if (input.react) {
414
+ const success = await createReaction(client, input.react, input.emoji!);
415
+ if (!success) {
416
+ exitWithError(`failed to add reaction to comment ${input.react.slice(0, 8)}`);
417
+ }
418
+ console.log(`added reaction ${input.emoji} to comment ${input.react.slice(0, 8)}`);
419
+ }
420
+
421
+ if (input.unreact) {
422
+ const success = await deleteReaction(client, input.unreact);
423
+ if (!success) {
424
+ exitWithError(`reaction ${input.unreact.slice(0, 8)} not found`, undefined, EXIT_CODES.NOT_FOUND);
425
+ }
426
+ console.log(`removed reaction ${input.unreact.slice(0, 8)}`);
427
+ }
428
+
429
+ // Archive last (restricts further edits)
430
+ if (input.archive) {
431
+ await archiveIssue(client, issue.id);
432
+ console.log(`archived ${identifier}`);
433
+ }
424
434
  } catch (error) {
425
435
  handleApiError(error);
426
436
  }