@markmdev/pebble 0.1.7 → 0.1.9

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/dist/cli/index.js CHANGED
@@ -512,7 +512,7 @@ function truncate(str, maxLength) {
512
512
  function pad(str, width) {
513
513
  return str.padEnd(width);
514
514
  }
515
- function formatIssuePrettyWithBlocking(issue, blocking) {
515
+ function formatIssueDetailPretty(issue, ctx) {
516
516
  const lines = [];
517
517
  lines.push(`${issue.id} - ${issue.title}`);
518
518
  lines.push("\u2500".repeat(60));
@@ -527,13 +527,38 @@ function formatIssuePrettyWithBlocking(issue, blocking) {
527
527
  lines.push("Description:");
528
528
  lines.push(issue.description);
529
529
  }
530
+ if (ctx.children.length > 0) {
531
+ const closedChildren = ctx.children.filter((c) => c.status === "closed");
532
+ lines.push("");
533
+ lines.push(`Children (${closedChildren.length}/${ctx.children.length} done):`);
534
+ for (const child of ctx.children) {
535
+ const statusIcon = child.status === "closed" ? "\u2713" : child.status === "in_progress" ? "\u25B6" : "\u25CB";
536
+ lines.push(` ${statusIcon} ${child.id} - ${child.title} [${child.status}]`);
537
+ }
538
+ }
530
539
  if (issue.blockedBy.length > 0) {
531
540
  lines.push("");
532
541
  lines.push(`Blocked by: ${issue.blockedBy.join(", ")}`);
533
542
  }
534
- if (blocking.length > 0) {
543
+ if (ctx.blocking.length > 0) {
544
+ lines.push("");
545
+ lines.push(`Blocking: ${ctx.blocking.map((i) => i.id).join(", ")}`);
546
+ }
547
+ if (ctx.verifications.length > 0) {
548
+ const closedVerifications = ctx.verifications.filter((v) => v.status === "closed");
549
+ lines.push("");
550
+ lines.push(`Verifications (${closedVerifications.length}/${ctx.verifications.length} done):`);
551
+ for (const v of ctx.verifications) {
552
+ const statusIcon = v.status === "closed" ? "\u2713" : "\u25CB";
553
+ lines.push(` ${statusIcon} ${v.id} - ${v.title} [${v.status}]`);
554
+ }
555
+ } else if (issue.status === "pending_verification") {
556
+ lines.push("");
557
+ lines.push("Verifications: None found (status may be stale)");
558
+ }
559
+ if (ctx.related.length > 0) {
535
560
  lines.push("");
536
- lines.push(`Blocking: ${blocking.map((i) => i.id).join(", ")}`);
561
+ lines.push(`Related: ${ctx.related.map((r) => r.id).join(", ")}`);
537
562
  }
538
563
  if (issue.comments.length > 0) {
539
564
  lines.push("");
@@ -549,6 +574,20 @@ function formatIssuePrettyWithBlocking(issue, blocking) {
549
574
  lines.push(`Updated: ${new Date(issue.updatedAt).toLocaleString()}`);
550
575
  return lines.join("\n");
551
576
  }
577
+ function outputIssueDetail(issue, ctx, pretty) {
578
+ if (pretty) {
579
+ console.log(formatIssueDetailPretty(issue, ctx));
580
+ } else {
581
+ const output = {
582
+ ...issue,
583
+ blocking: ctx.blocking.map((i) => i.id),
584
+ children: ctx.children.map((i) => ({ id: i.id, title: i.title, status: i.status })),
585
+ verifications: ctx.verifications.map((i) => ({ id: i.id, title: i.title, status: i.status })),
586
+ related: ctx.related.map((i) => i.id)
587
+ };
588
+ console.log(formatJson(output));
589
+ }
590
+ }
552
591
  function formatIssueListPretty(issues) {
553
592
  if (issues.length === 0) {
554
593
  return "No issues found.";
@@ -625,17 +664,6 @@ function formatErrorPretty(error) {
625
664
  const message = error instanceof Error ? error.message : error;
626
665
  return `Error: ${message}`;
627
666
  }
628
- function outputIssueWithBlocking(issue, blocking, pretty) {
629
- if (pretty) {
630
- console.log(formatIssuePrettyWithBlocking(issue, blocking));
631
- } else {
632
- const output = {
633
- ...issue,
634
- blocking: blocking.map((i) => i.id)
635
- };
636
- console.log(formatJson(output));
637
- }
638
- }
639
667
  function outputMutationSuccess(id, pretty) {
640
668
  if (pretty) {
641
669
  console.log(`\u2713 ${id}`);
@@ -1233,7 +1261,10 @@ function showCommand(program2) {
1233
1261
  throw new Error(`Issue not found: ${id}`);
1234
1262
  }
1235
1263
  const blocking = getBlocking(resolvedId);
1236
- outputIssueWithBlocking(issue, blocking, pretty);
1264
+ const children = issue.type === "epic" ? getChildren(resolvedId) : [];
1265
+ const verifications = getVerifications(resolvedId);
1266
+ const related = getRelated(resolvedId);
1267
+ outputIssueDetail(issue, { blocking, children, verifications, related }, pretty);
1237
1268
  } catch (error) {
1238
1269
  outputError(error, pretty);
1239
1270
  }
@@ -2072,9 +2103,26 @@ data: ${message}
2072
2103
  results.push({ id: issueId, success: false, error: "Cannot close epic with open children" });
2073
2104
  continue;
2074
2105
  }
2106
+ const pendingVerifications = getVerifications(issueId).filter((v) => v.status !== "closed");
2107
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
2108
+ if (pendingVerifications.length > 0) {
2109
+ const updateEvent = {
2110
+ type: "update",
2111
+ issueId,
2112
+ timestamp,
2113
+ data: { status: "pending_verification" }
2114
+ };
2115
+ appendEvent(updateEvent, pebbleDir);
2116
+ results.push({
2117
+ id: issueId,
2118
+ success: true,
2119
+ error: `Moved to pending_verification (${pendingVerifications.length} verification(s) pending)`
2120
+ });
2121
+ continue;
2122
+ }
2075
2123
  const event = {
2076
2124
  issueId,
2077
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2125
+ timestamp,
2078
2126
  type: "close",
2079
2127
  data: { reason: "Bulk close" }
2080
2128
  };
@@ -2170,7 +2218,7 @@ data: ${message}
2170
2218
  issue = localIssue;
2171
2219
  targetFile = path2.join(pebbleDir, "issues.jsonl");
2172
2220
  }
2173
- const { title, type, priority, status, description, parent } = req.body;
2221
+ const { title, type, priority, status, description, parent, relatedTo } = req.body;
2174
2222
  const updates = {};
2175
2223
  if (title !== void 0) {
2176
2224
  if (typeof title !== "string" || title.trim() === "") {
@@ -2229,6 +2277,28 @@ data: ${message}
2229
2277
  }
2230
2278
  updates.parent = parent;
2231
2279
  }
2280
+ if (relatedTo !== void 0) {
2281
+ if (!Array.isArray(relatedTo)) {
2282
+ res.status(400).json({ error: "relatedTo must be an array" });
2283
+ return;
2284
+ }
2285
+ for (const relatedId of relatedTo) {
2286
+ if (isMultiWorktree()) {
2287
+ const found = findIssueInSources(relatedId, issueFiles);
2288
+ if (!found) {
2289
+ res.status(400).json({ error: `Related issue not found: ${relatedId}` });
2290
+ return;
2291
+ }
2292
+ } else {
2293
+ const relatedIssue = getIssue(relatedId);
2294
+ if (!relatedIssue) {
2295
+ res.status(400).json({ error: `Related issue not found: ${relatedId}` });
2296
+ return;
2297
+ }
2298
+ }
2299
+ }
2300
+ updates.relatedTo = relatedTo;
2301
+ }
2232
2302
  if (Object.keys(updates).length === 0) {
2233
2303
  res.status(400).json({ error: "No valid updates provided" });
2234
2304
  return;
@@ -2286,6 +2356,30 @@ data: ${message}
2286
2356
  }
2287
2357
  const { reason } = req.body;
2288
2358
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
2359
+ let pendingVerifications = [];
2360
+ if (isMultiWorktree()) {
2361
+ const allIssues = mergeIssuesFromFiles(issueFiles);
2362
+ pendingVerifications = allIssues.filter(
2363
+ (i) => i.verifies === issueId && i.status !== "closed"
2364
+ );
2365
+ } else {
2366
+ pendingVerifications = getVerifications(issueId).filter((v) => v.status !== "closed");
2367
+ }
2368
+ if (pendingVerifications.length > 0) {
2369
+ const updateEvent = {
2370
+ type: "update",
2371
+ issueId,
2372
+ timestamp,
2373
+ data: { status: "pending_verification" }
2374
+ };
2375
+ appendEventToFile(updateEvent, targetFile);
2376
+ const updatedIssue = { ...issue, status: "pending_verification", updatedAt: timestamp };
2377
+ res.json({
2378
+ ...updatedIssue,
2379
+ _pendingVerifications: pendingVerifications.map((v) => ({ id: v.id, title: v.title }))
2380
+ });
2381
+ return;
2382
+ }
2289
2383
  const event = {
2290
2384
  type: "close",
2291
2385
  issueId,
@@ -3160,6 +3254,14 @@ function initCommand(program2) {
3160
3254
  var program = new Command();
3161
3255
  program.name("pebble").description("A lightweight JSONL-based issue tracker").version("0.1.0");
3162
3256
  program.option("-P, --pretty", "Human-readable output (default: JSON)");
3257
+ program.option("--json", "JSON output (this is the default, flag not needed)");
3258
+ program.hook("preAction", () => {
3259
+ const opts = program.opts();
3260
+ if (opts.json) {
3261
+ console.error("Note: --json flag is unnecessary. JSON is the default output format.");
3262
+ console.error("Use --pretty (-P) for human-readable output.");
3263
+ }
3264
+ });
3163
3265
  createCommand(program);
3164
3266
  updateCommand(program);
3165
3267
  closeCommand(program);