@markmdev/pebble 0.1.23 → 0.2.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/dist/cli/index.js CHANGED
@@ -13,9 +13,9 @@ import { fileURLToPath as fileURLToPath2 } from "url";
13
13
  import { dirname as dirname2, join as join3 } from "path";
14
14
 
15
15
  // src/shared/types.ts
16
- var ISSUE_TYPES = ["task", "bug", "epic", "verification"];
16
+ var ISSUE_TYPES = ["task", "bug", "epic"];
17
17
  var PRIORITIES = [0, 1, 2, 3, 4];
18
- var STATUSES = ["open", "in_progress", "blocked", "pending_verification", "closed"];
18
+ var STATUSES = ["open", "in_progress", "blocked", "closed"];
19
19
  var EVENT_TYPES = ["create", "update", "close", "reopen", "comment", "delete", "restore"];
20
20
  var PRIORITY_LABELS = {
21
21
  0: "critical",
@@ -28,14 +28,12 @@ var STATUS_LABELS = {
28
28
  open: "Open",
29
29
  in_progress: "In Progress",
30
30
  blocked: "Blocked",
31
- pending_verification: "Pending Verification",
32
31
  closed: "Closed"
33
32
  };
34
33
  var TYPE_LABELS = {
35
34
  task: "Task",
36
35
  bug: "Bug",
37
- epic: "Epic",
38
- verification: "Verification"
36
+ epic: "Epic"
39
37
  };
40
38
 
41
39
  // src/cli/lib/storage.ts
@@ -290,7 +288,6 @@ function computeState(events) {
290
288
  parent: createEvent.data.parent,
291
289
  blockedBy: [],
292
290
  relatedTo: [],
293
- verifies: createEvent.data.verifies,
294
291
  comments: [],
295
292
  createdAt: event.timestamp,
296
293
  updatedAt: event.timestamp,
@@ -467,7 +464,7 @@ function getReady() {
467
464
  if (issue.deleted) {
468
465
  return false;
469
466
  }
470
- if (issue.status === "closed" || issue.status === "pending_verification") {
467
+ if (issue.status === "closed") {
471
468
  return false;
472
469
  }
473
470
  for (const blockerId of issue.blockedBy) {
@@ -476,12 +473,6 @@ function getReady() {
476
473
  return false;
477
474
  }
478
475
  }
479
- if (issue.type === "verification" && issue.verifies) {
480
- const target = state.get(issue.verifies);
481
- if (!target || target.status !== "closed") {
482
- return false;
483
- }
484
- }
485
476
  return true;
486
477
  });
487
478
  }
@@ -573,11 +564,6 @@ function getChildren(epicId, includeDeleted = false) {
573
564
  (issue) => issue.parent === epicId && (includeDeleted || !issue.deleted)
574
565
  );
575
566
  }
576
- function getVerifications(issueId) {
577
- const events = readEvents();
578
- const state = computeState(events);
579
- return Array.from(state.values()).filter((issue) => issue.verifies === issueId);
580
- }
581
567
  function hasOpenChildren(epicId) {
582
568
  const children = getChildren(epicId);
583
569
  return children.some((child) => child.status !== "closed");
@@ -588,28 +574,15 @@ function getNewlyUnblocked(closedIssueId) {
588
574
  const result = [];
589
575
  for (const issue of state.values()) {
590
576
  if (issue.status === "closed") continue;
591
- let isUnblockedByThis = false;
592
577
  if (issue.blockedBy.includes(closedIssueId)) {
593
578
  const allBlockersClosed = issue.blockedBy.every((blockerId) => {
594
579
  const blocker = state.get(blockerId);
595
580
  return blocker?.status === "closed";
596
581
  });
597
582
  if (allBlockersClosed) {
598
- isUnblockedByThis = true;
583
+ result.push(issue);
599
584
  }
600
585
  }
601
- if (issue.type === "verification" && issue.verifies === closedIssueId) {
602
- const allBlockersClosed = issue.blockedBy.every((blockerId) => {
603
- const blocker = state.get(blockerId);
604
- return blocker?.status === "closed";
605
- });
606
- if (allBlockersClosed) {
607
- isUnblockedByThis = true;
608
- }
609
- }
610
- if (isUnblockedByThis) {
611
- result.push(issue);
612
- }
613
586
  }
614
587
  return result;
615
588
  }
@@ -798,10 +771,8 @@ function formatIssueDetailPretty(issue, ctx) {
798
771
  }
799
772
  if (ctx.children.length > 0) {
800
773
  const closedChildren = ctx.children.filter((c) => c.status === "closed");
801
- const pendingChildren = ctx.children.filter((c) => c.status === "pending_verification");
802
- const pendingStr = pendingChildren.length > 0 ? ` (${pendingChildren.length} pending verification)` : "";
803
774
  lines.push("");
804
- lines.push(`Children (${closedChildren.length}/${ctx.children.length} done${pendingStr}):`);
775
+ lines.push(`Children (${closedChildren.length}/${ctx.children.length} done):`);
805
776
  for (const child of ctx.children) {
806
777
  const statusIcon = child.status === "closed" ? "\u2713" : child.status === "in_progress" ? "\u25B6" : "\u25CB";
807
778
  lines.push(` ${statusIcon} ${child.id} - ${child.title} [${child.status}]`);
@@ -815,18 +786,6 @@ function formatIssueDetailPretty(issue, ctx) {
815
786
  lines.push("");
816
787
  lines.push(`Blocking: ${ctx.blocking.map((i) => i.id).join(", ")}`);
817
788
  }
818
- if (ctx.verifications.length > 0) {
819
- const closedVerifications = ctx.verifications.filter((v) => v.status === "closed");
820
- lines.push("");
821
- lines.push(`Verifications (${closedVerifications.length}/${ctx.verifications.length} done):`);
822
- for (const v of ctx.verifications) {
823
- const statusIcon = v.status === "closed" ? "\u2713" : "\u25CB";
824
- lines.push(` ${statusIcon} ${v.id} - ${v.title} [${v.status}]`);
825
- }
826
- } else if (issue.status === "pending_verification") {
827
- lines.push("");
828
- lines.push("Verifications: None found (status may be stale)");
829
- }
830
789
  if (ctx.related.length > 0) {
831
790
  lines.push("");
832
791
  lines.push(`Related: ${ctx.related.map((r) => r.id).join(", ")}`);
@@ -853,7 +812,6 @@ function outputIssueDetail(issue, ctx, pretty) {
853
812
  ...issue,
854
813
  blocking: ctx.blocking.map((i) => i.id),
855
814
  children: ctx.children.map((i) => ({ id: i.id, title: i.title, status: i.status })),
856
- verifications: ctx.verifications.map((i) => ({ id: i.id, title: i.title, status: i.status })),
857
815
  related: ctx.related.map((i) => i.id),
858
816
  ...ctx.ancestry && ctx.ancestry.length > 0 && { ancestry: ctx.ancestry }
859
817
  };
@@ -939,8 +897,9 @@ function formatErrorPretty(error) {
939
897
  function outputMutationSuccess(id, pretty, extra) {
940
898
  if (pretty) {
941
899
  const notes = [];
942
- if (extra?.parentReopened) {
943
- notes.push(`parent ${extra.parentReopened.id} reopened`);
900
+ if (extra?.parentsReopened?.length) {
901
+ const ids = extra.parentsReopened.map((p) => p.id).join(", ");
902
+ notes.push(`reopened: ${ids}`);
944
903
  }
945
904
  if (extra?.blockersReopened?.length) {
946
905
  const ids = extra.blockersReopened.map((b) => b.id).join(", ");
@@ -953,8 +912,8 @@ function outputMutationSuccess(id, pretty, extra) {
953
912
  }
954
913
  } else {
955
914
  const result = { id, success: true };
956
- if (extra?.parentReopened) {
957
- result._parentReopened = extra.parentReopened;
915
+ if (extra?.parentsReopened?.length) {
916
+ result._parentsReopened = extra.parentsReopened;
958
917
  }
959
918
  if (extra?.blockersReopened?.length) {
960
919
  result._blockersReopened = extra.blockersReopened;
@@ -1020,7 +979,7 @@ function formatIssueTreePretty(nodes, sectionHeader) {
1020
979
  const totalCount = nodes.reduce((sum, node) => sum + countAll(node), 0);
1021
980
  const formatNode = (node, prefix, isLast, isRoot) => {
1022
981
  const connector = isRoot ? "" : isLast ? "\u2514\u2500 " : "\u251C\u2500 ";
1023
- const statusIcon = node.status === "closed" ? "\u2713" : node.status === "in_progress" ? "\u25B6" : node.status === "pending_verification" ? "\u23F3" : "\u25CB";
982
+ const statusIcon = node.status === "closed" ? "\u2713" : node.status === "in_progress" ? "\u25B6" : "\u25CB";
1024
983
  const statusText = STATUS_LABELS[node.status].toLowerCase();
1025
984
  const relativeTime = node.statusChangedAt ? formatRelativeTime(node.statusChangedAt) : formatRelativeTime(node.createdAt);
1026
985
  lines.push(`${prefix}${connector}${statusIcon} ${node.id}: ${node.title} [${node.type}] P${node.priority} ${statusText} ${relativeTime}`);
@@ -1071,7 +1030,7 @@ function formatIssueListVerbose(issues, sectionHeader) {
1071
1030
  lines.push("");
1072
1031
  }
1073
1032
  for (const info of issues) {
1074
- const { issue, blocking, children, verifications, blockers, ancestry } = info;
1033
+ const { issue, blocking, children, blockers, ancestry } = info;
1075
1034
  const statusTime = issue.statusChangedAt ? formatRelativeTime(issue.statusChangedAt) : formatRelativeTime(issue.createdAt);
1076
1035
  lines.push(`${issue.id}: ${issue.title}`);
1077
1036
  lines.push(` Type: ${formatType(issue.type)} | Priority: P${issue.priority} | Status: ${formatStatus(issue.status)} (${statusTime})`);
@@ -1086,7 +1045,7 @@ function formatIssueListVerbose(issues, sectionHeader) {
1086
1045
  lines.push(` Blocked by: ${blockers.join(", ")}`);
1087
1046
  }
1088
1047
  if (issue.type === "epic" && children > 0) {
1089
- lines.push(` Children: ${children} | Verifications: ${verifications}`);
1048
+ lines.push(` Children: ${children}`);
1090
1049
  }
1091
1050
  lines.push("");
1092
1051
  }
@@ -1099,11 +1058,10 @@ function outputIssueListVerbose(issues, pretty, sectionHeader, limitInfo) {
1099
1058
  console.log(formatLimitMessage(limitInfo));
1100
1059
  }
1101
1060
  } else {
1102
- const output = issues.map(({ issue, blocking, children, verifications, blockers, ancestry }) => ({
1061
+ const output = issues.map(({ issue, blocking, children, blockers, ancestry }) => ({
1103
1062
  ...issue,
1104
1063
  blocking,
1105
1064
  childrenCount: issue.type === "epic" ? children : void 0,
1106
- verificationsCount: verifications,
1107
1065
  ...blockers && { openBlockers: blockers },
1108
1066
  ...ancestry.length > 0 && { ancestry }
1109
1067
  }));
@@ -1117,19 +1075,17 @@ function outputIssueListVerbose(issues, pretty, sectionHeader, limitInfo) {
1117
1075
 
1118
1076
  // src/cli/commands/create.ts
1119
1077
  function createCommand(program2) {
1120
- program2.command("create <title>").description("Create a new issue").option("-t, --type <type>", "Issue type (task, bug, epic, verification)", "task").option("-p, --priority <priority>", "Priority (0-4)", "2").option("-d, --description <desc>", "Description").option("--parent <id>", "Parent issue ID").option("--verifies <id>", "ID of issue this verifies (sets type to verification)").option("--blocked-by <ids>", "Comma-separated IDs of issues that block this one").option("--blocks <ids>", "Comma-separated IDs of issues this one will block").action(async (title, options) => {
1078
+ program2.command("create <title>").description("Create a new issue").option("-t, --type <type>", "Issue type (task, bug, epic)", "task").option("-p, --priority <priority>", "Priority (0-4)", "2").option("-d, --description <desc>", "Description").option("--parent <id>", "Parent issue ID").option("--blocked-by <ids>", "Comma-separated IDs of issues that block this one").option("--blocks <ids>", "Comma-separated IDs of issues this one will block").addHelpText("after", `
1079
+ Notes:
1080
+ IDs support partial matching (e.g., "abc" matches "PROJ-abc123")
1081
+ Creating a child under a closed parent auto-reopens the parent chain
1082
+ `).action(async (title, options) => {
1121
1083
  const pretty = program2.opts().pretty ?? false;
1122
1084
  try {
1123
- let type = options.type;
1124
- if (options.verifies && type !== "verification") {
1125
- type = "verification";
1126
- }
1085
+ const type = options.type;
1127
1086
  if (!ISSUE_TYPES.includes(type)) {
1128
1087
  throw new Error(`Invalid type: ${type}. Must be one of: ${ISSUE_TYPES.join(", ")}`);
1129
1088
  }
1130
- if (type === "verification" && !options.verifies) {
1131
- throw new Error("Verification issues require --verifies <id> to specify the issue being verified");
1132
- }
1133
1089
  const priority = parseInt(options.priority, 10);
1134
1090
  if (!PRIORITIES.includes(priority)) {
1135
1091
  throw new Error(`Invalid priority: ${options.priority}. Must be 0-4`);
@@ -1137,33 +1093,27 @@ function createCommand(program2) {
1137
1093
  const pebbleDir = getOrCreatePebbleDir();
1138
1094
  const config = getConfig(pebbleDir);
1139
1095
  let parentId;
1140
- let parentReopened;
1096
+ const parentsReopened = [];
1141
1097
  if (options.parent) {
1142
1098
  parentId = resolveId(options.parent);
1143
1099
  const parent = getIssue(parentId);
1144
1100
  if (!parent) {
1145
1101
  throw new Error(`Parent issue not found: ${options.parent}`);
1146
1102
  }
1147
- if (parent.type === "verification") {
1148
- throw new Error(`Verification issues cannot be parents`);
1149
- }
1150
- if (parent.status === "closed") {
1151
- const reopenEvent = {
1152
- type: "reopen",
1153
- issueId: parentId,
1154
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1155
- data: { reason: "Reopened to add child" }
1156
- };
1157
- appendEvent(reopenEvent, pebbleDir);
1158
- parentReopened = { id: parentId, title: parent.title };
1159
- }
1160
- }
1161
- let verifiesId;
1162
- if (options.verifies) {
1163
- verifiesId = resolveId(options.verifies);
1164
- const target = getIssue(verifiesId);
1165
- if (!target) {
1166
- throw new Error(`Target issue not found: ${options.verifies}`);
1103
+ const state = getComputedState();
1104
+ let current = state.get(parentId);
1105
+ while (current) {
1106
+ if (current.status === "closed") {
1107
+ const reopenEvent = {
1108
+ type: "reopen",
1109
+ issueId: current.id,
1110
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1111
+ data: { reason: "Reopened to add descendant" }
1112
+ };
1113
+ appendEvent(reopenEvent, pebbleDir);
1114
+ parentsReopened.push({ id: current.id, title: current.title });
1115
+ }
1116
+ current = current.parent ? state.get(current.parent) : void 0;
1167
1117
  }
1168
1118
  }
1169
1119
  const blockedByIds = [];
@@ -1212,8 +1162,7 @@ function createCommand(program2) {
1212
1162
  type,
1213
1163
  priority,
1214
1164
  description: options.description,
1215
- parent: parentId,
1216
- verifies: verifiesId
1165
+ parent: parentId
1217
1166
  }
1218
1167
  };
1219
1168
  appendEvent(event, pebbleDir);
@@ -1246,7 +1195,7 @@ function createCommand(program2) {
1246
1195
  };
1247
1196
  appendEvent(depEvent, pebbleDir);
1248
1197
  }
1249
- const extra = parentReopened || blockersReopened.length > 0 ? { parentReopened, blockersReopened: blockersReopened.length > 0 ? blockersReopened : void 0 } : void 0;
1198
+ const extra = parentsReopened.length > 0 || blockersReopened.length > 0 ? { parentsReopened: parentsReopened.length > 0 ? parentsReopened : void 0, blockersReopened: blockersReopened.length > 0 ? blockersReopened : void 0 } : void 0;
1250
1199
  outputMutationSuccess(id, pretty, extra);
1251
1200
  } catch (error) {
1252
1201
  outputError(error, pretty);
@@ -1256,7 +1205,7 @@ function createCommand(program2) {
1256
1205
 
1257
1206
  // src/cli/commands/update.ts
1258
1207
  function updateCommand(program2) {
1259
- program2.command("update <ids...>").description("Update issues. Supports multiple IDs.").option("--status <status>", "Status (open, in_progress, blocked, closed)").option("--priority <priority>", "Priority (0-4)").option("--title <title>", "Title").option("--description <desc>", "Description").option("--parent <id>", 'Parent issue ID (use "null" to remove parent)').action(async (ids, options) => {
1208
+ program2.command("update <ids...>").description("Update issues. Supports multiple IDs.").option("--status <status>", "Status (open, in_progress, blocked)").option("--priority <priority>", "Priority (0-4)").option("--title <title>", "Title").option("--description <desc>", "Description").option("--parent <id>", 'Parent issue ID (use "null" to remove parent)').action(async (ids, options) => {
1260
1209
  const pretty = program2.opts().pretty ?? false;
1261
1210
  try {
1262
1211
  const pebbleDir = getOrCreatePebbleDir();
@@ -1290,7 +1239,7 @@ function updateCommand(program2) {
1290
1239
  data.description = options.description;
1291
1240
  hasChanges = true;
1292
1241
  }
1293
- let parentReopened;
1242
+ const parentsReopened = [];
1294
1243
  if (options.parent !== void 0) {
1295
1244
  if (options.parent.toLowerCase() === "null") {
1296
1245
  data.parent = "";
@@ -1300,18 +1249,20 @@ function updateCommand(program2) {
1300
1249
  if (!parentIssue) {
1301
1250
  throw new Error(`Parent issue not found: ${options.parent}`);
1302
1251
  }
1303
- if (parentIssue.type === "verification") {
1304
- throw new Error(`Verification issues cannot be parents`);
1305
- }
1306
- if (parentIssue.status === "closed") {
1307
- const reopenEvent = {
1308
- type: "reopen",
1309
- issueId: parentId,
1310
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1311
- data: { reason: "Reopened to add child" }
1312
- };
1313
- appendEvent(reopenEvent, pebbleDir);
1314
- parentReopened = { id: parentId, title: parentIssue.title };
1252
+ const state = getComputedState();
1253
+ let current = state.get(parentId);
1254
+ while (current) {
1255
+ if (current.status === "closed") {
1256
+ const reopenEvent = {
1257
+ type: "reopen",
1258
+ issueId: current.id,
1259
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1260
+ data: { reason: "Reopened to add descendant" }
1261
+ };
1262
+ appendEvent(reopenEvent, pebbleDir);
1263
+ parentsReopened.push({ id: current.id, title: current.title });
1264
+ }
1265
+ current = current.parent ? state.get(current.parent) : void 0;
1315
1266
  }
1316
1267
  data.parent = parentId;
1317
1268
  }
@@ -1350,7 +1301,7 @@ function updateCommand(program2) {
1350
1301
  if (allIds.length === 1) {
1351
1302
  const result = results[0];
1352
1303
  if (result.success) {
1353
- outputMutationSuccess(result.id, pretty, parentReopened ? { parentReopened } : void 0);
1304
+ outputMutationSuccess(result.id, pretty, parentsReopened.length > 0 ? { parentsReopened } : void 0);
1354
1305
  } else {
1355
1306
  throw new Error(result.error || "Unknown error");
1356
1307
  }
@@ -1417,25 +1368,6 @@ function closeCommand(program2) {
1417
1368
  };
1418
1369
  appendEvent(commentEvent, pebbleDir);
1419
1370
  }
1420
- const pendingVerifications = getVerifications(resolvedId).filter((v) => v.status !== "closed");
1421
- if (pendingVerifications.length > 0) {
1422
- const updateEvent = {
1423
- type: "update",
1424
- issueId: resolvedId,
1425
- timestamp,
1426
- data: {
1427
- status: "pending_verification"
1428
- }
1429
- };
1430
- appendEvent(updateEvent, pebbleDir);
1431
- results.push({
1432
- id: resolvedId,
1433
- success: true,
1434
- status: "pending_verification",
1435
- pendingVerifications: pendingVerifications.map((v) => ({ id: v.id, title: v.title }))
1436
- });
1437
- continue;
1438
- }
1439
1371
  const closeEvent = {
1440
1372
  type: "close",
1441
1373
  issueId: resolvedId,
@@ -1446,31 +1378,10 @@ function closeCommand(program2) {
1446
1378
  };
1447
1379
  appendEvent(closeEvent, pebbleDir);
1448
1380
  const unblocked = getNewlyUnblocked(resolvedId);
1449
- let autoClosed;
1450
- if (issue.verifies) {
1451
- const targetIssue = getIssue(issue.verifies);
1452
- if (targetIssue && targetIssue.status === "pending_verification") {
1453
- const remainingVerifications = getVerifications(issue.verifies).filter((v) => v.status !== "closed");
1454
- if (remainingVerifications.length === 0) {
1455
- const autoCloseEvent = {
1456
- type: "close",
1457
- issueId: issue.verifies,
1458
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1459
- data: {
1460
- reason: "All verifications completed"
1461
- }
1462
- };
1463
- appendEvent(autoCloseEvent, pebbleDir);
1464
- autoClosed = { id: targetIssue.id, title: targetIssue.title };
1465
- }
1466
- }
1467
- }
1468
1381
  results.push({
1469
1382
  id: resolvedId,
1470
1383
  success: true,
1471
- status: "closed",
1472
- unblocked: unblocked.length > 0 ? unblocked.map((i) => ({ id: i.id, title: i.title })) : void 0,
1473
- autoClosed
1384
+ unblocked: unblocked.length > 0 ? unblocked.map((i) => ({ id: i.id, title: i.title })) : void 0
1474
1385
  });
1475
1386
  } catch (error) {
1476
1387
  results.push({ id, success: false, error: error.message });
@@ -1480,38 +1391,19 @@ function closeCommand(program2) {
1480
1391
  const result = results[0];
1481
1392
  if (result.success) {
1482
1393
  if (pretty) {
1483
- if (result.status === "pending_verification") {
1484
- console.log(`\u23F3 ${result.id} \u2192 pending_verification`);
1485
- console.log(`
1486
- Pending verifications:`);
1487
- for (const v of result.pendingVerifications || []) {
1488
- console.log(` \u2022 ${v.id} - ${v.title}`);
1489
- }
1394
+ console.log(`\u2713 ${result.id}`);
1395
+ if (result.unblocked && result.unblocked.length > 0) {
1490
1396
  console.log(`
1491
- Run: pb verifications ${result.id}`);
1492
- } else {
1493
- console.log(`\u2713 ${result.id}`);
1494
- if (result.unblocked && result.unblocked.length > 0) {
1495
- console.log(`
1496
1397
  Unblocked:`);
1497
- for (const u of result.unblocked) {
1498
- console.log(` \u2192 ${u.id} - ${u.title}`);
1499
- }
1500
- }
1501
- if (result.autoClosed) {
1502
- console.log(`
1503
- \u2713 ${result.autoClosed.id} auto-closed (all verifications complete)`);
1398
+ for (const u of result.unblocked) {
1399
+ console.log(` \u2192 ${u.id} - ${u.title}`);
1504
1400
  }
1505
1401
  }
1506
1402
  } else {
1507
1403
  console.log(formatJson({
1508
1404
  id: result.id,
1509
1405
  success: true,
1510
- status: result.status,
1511
- ...result.pendingVerifications && { pendingVerifications: result.pendingVerifications },
1512
- ...result.pendingVerifications && { hint: `pb verifications ${result.id}` },
1513
- ...result.unblocked && { unblocked: result.unblocked },
1514
- ...result.autoClosed && { autoClosed: result.autoClosed }
1406
+ ...result.unblocked && { unblocked: result.unblocked }
1515
1407
  }));
1516
1408
  }
1517
1409
  } else {
@@ -1521,21 +1413,10 @@ Unblocked:`);
1521
1413
  if (pretty) {
1522
1414
  for (const result of results) {
1523
1415
  if (result.success) {
1524
- if (result.status === "pending_verification") {
1525
- console.log(`\u23F3 ${result.id} \u2192 pending_verification`);
1526
- for (const v of result.pendingVerifications || []) {
1527
- console.log(` \u2022 ${v.id} - ${v.title}`);
1528
- }
1529
- console.log(` Run: pb verifications ${result.id}`);
1530
- } else {
1531
- console.log(`\u2713 ${result.id}`);
1532
- if (result.unblocked && result.unblocked.length > 0) {
1533
- for (const u of result.unblocked) {
1534
- console.log(` \u2192 ${u.id} - ${u.title}`);
1535
- }
1536
- }
1537
- if (result.autoClosed) {
1538
- console.log(` \u2713 ${result.autoClosed.id} auto-closed (all verifications complete)`);
1416
+ console.log(`\u2713 ${result.id}`);
1417
+ if (result.unblocked && result.unblocked.length > 0) {
1418
+ for (const u of result.unblocked) {
1419
+ console.log(` \u2192 ${u.id} - ${u.title}`);
1539
1420
  }
1540
1421
  }
1541
1422
  } else {
@@ -1546,12 +1427,8 @@ Unblocked:`);
1546
1427
  console.log(formatJson(results.map((r) => ({
1547
1428
  id: r.id,
1548
1429
  success: r.success,
1549
- status: r.status,
1550
1430
  ...r.error && { error: r.error },
1551
- ...r.pendingVerifications && { pendingVerifications: r.pendingVerifications },
1552
- ...r.pendingVerifications && { hint: `pb verifications ${r.id}` },
1553
- ...r.unblocked && { unblocked: r.unblocked },
1554
- ...r.autoClosed && { autoClosed: r.autoClosed }
1431
+ ...r.unblocked && { unblocked: r.unblocked }
1555
1432
  }))));
1556
1433
  }
1557
1434
  }
@@ -1671,13 +1548,6 @@ function deleteCommand(program2) {
1671
1548
  alreadyQueued.add(desc.id);
1672
1549
  }
1673
1550
  }
1674
- const verifications = getVerifications(resolvedId);
1675
- for (const v of verifications) {
1676
- if (!alreadyQueued.has(v.id) && !v.deleted) {
1677
- toDelete.push({ id: v.id, cascade: true });
1678
- alreadyQueued.add(v.id);
1679
- }
1680
- }
1681
1551
  } catch (error) {
1682
1552
  results.push({ id, success: false, error: error.message });
1683
1553
  }
@@ -1888,7 +1758,7 @@ function claimCommand(program2) {
1888
1758
 
1889
1759
  // src/cli/commands/list.ts
1890
1760
  function listCommand(program2) {
1891
- program2.command("list").description("List issues").option("--status <status>", "Filter by status").option("-t, --type <type>", "Filter by type").option("--priority <priority>", "Filter by priority").option("--parent <id>", "Filter by parent epic").option("-v, --verbose", "Show expanded details (parent, children, blocking, verifications)").option("--flat", "Show flat list instead of hierarchical tree").option("--limit <n>", "Max issues to return (default: 30)").option("--all", "Show all issues (no limit)").action(async (options) => {
1761
+ program2.command("list").description("List issues").option("--status <status>", "Filter by status").option("-t, --type <type>", "Filter by type").option("--priority <priority>", "Filter by priority").option("--parent <id>", "Filter by parent epic").option("-v, --verbose", "Show expanded details (parent, children, blocking)").option("--flat", "Show flat list instead of hierarchical tree").option("--limit <n>", "Max issues to return (default: 30)").option("--all", "Show all issues (no limit)").action(async (options) => {
1892
1762
  const pretty = program2.opts().pretty ?? false;
1893
1763
  try {
1894
1764
  getOrCreatePebbleDir();
@@ -1936,7 +1806,6 @@ function listCommand(program2) {
1936
1806
  issue,
1937
1807
  blocking: getBlocking(issue.id).map((i) => i.id),
1938
1808
  children: getChildren(issue.id).length,
1939
- verifications: getVerifications(issue.id).length,
1940
1809
  ancestry: getAncestryChain(issue.id, state)
1941
1810
  };
1942
1811
  });
@@ -1973,11 +1842,10 @@ function showCommand(program2) {
1973
1842
  }
1974
1843
  const blocking = getBlocking(resolvedId);
1975
1844
  const children = issue.type === "epic" ? getChildren(resolvedId) : [];
1976
- const verifications = getVerifications(resolvedId);
1977
1845
  const related = getRelated(resolvedId);
1978
1846
  const state = getComputedState();
1979
1847
  const ancestry = getAncestryChain(resolvedId, state);
1980
- outputIssueDetail(issue, { blocking, children, verifications, related, ancestry }, pretty);
1848
+ outputIssueDetail(issue, { blocking, children, related, ancestry }, pretty);
1981
1849
  } catch (error) {
1982
1850
  outputError(error, pretty);
1983
1851
  }
@@ -1986,7 +1854,7 @@ function showCommand(program2) {
1986
1854
 
1987
1855
  // src/cli/commands/ready.ts
1988
1856
  function readyCommand(program2) {
1989
- program2.command("ready").description("Show issues ready for work (no open blockers)").option("-v, --verbose", "Show expanded details (parent, children, blocking, verifications)").option("-t, --type <type>", "Filter by type: task, bug, epic, verification").option("--limit <n>", "Max issues to return (default: 30)").option("--all", "Show all issues (no limit)").action(async (options) => {
1857
+ program2.command("ready").description("Show issues ready for work (no open blockers)").option("-v, --verbose", "Show expanded details (parent, children, blocking)").option("-t, --type <type>", "Filter by type: task, bug, epic").option("--limit <n>", "Max issues to return (default: 30)").option("--all", "Show all issues (no limit)").action(async (options) => {
1990
1858
  const pretty = program2.opts().pretty ?? false;
1991
1859
  try {
1992
1860
  getOrCreatePebbleDir();
@@ -2016,7 +1884,6 @@ function readyCommand(program2) {
2016
1884
  issue,
2017
1885
  blocking: getBlocking(issue.id).map((i) => i.id),
2018
1886
  children: getChildren(issue.id).length,
2019
- verifications: getVerifications(issue.id).length,
2020
1887
  ancestry: getAncestryChain(issue.id, state)
2021
1888
  };
2022
1889
  });
@@ -2057,7 +1924,6 @@ function blockedCommand(program2) {
2057
1924
  issue,
2058
1925
  blocking: getBlocking(issue.id).map((i) => i.id),
2059
1926
  children: getChildren(issue.id).length,
2060
- verifications: getVerifications(issue.id).length,
2061
1927
  blockers: openBlockers,
2062
1928
  ancestry: getAncestryChain(issue.id, state)
2063
1929
  };
@@ -2075,7 +1941,14 @@ function blockedCommand(program2) {
2075
1941
  // src/cli/commands/dep.ts
2076
1942
  function depCommand(program2) {
2077
1943
  const dep = program2.command("dep").description("Manage dependencies");
2078
- dep.command("add <id> [blockerId]").description("Add a blocking dependency. Use --needs or --blocks for self-documenting syntax.").option("--needs <id>", "Issue that must be completed first (first arg needs this)").option("--blocks <id>", "Issue that this blocks (first arg blocks this)").action(async (id, blockerId, options) => {
1944
+ dep.command("add <id> [blockerId]").description("Add a blocking dependency: <id> is blocked by [blockerId]").option("--needs <id>", "Issue that must be completed first (first arg needs this)").option("--blocks <id>", "Issue that this blocks (first arg blocks this)").addHelpText("after", `
1945
+ Examples:
1946
+ pb dep add B A B is blocked by A (A must close before B is ready)
1947
+ pb dep add B --needs A Same as above, self-documenting
1948
+ pb dep add A --blocks B Same effect: B is blocked by A
1949
+
1950
+ Think: "B needs A" \u2192 pb dep add B A
1951
+ `).action(async (id, blockerId, options) => {
2079
1952
  const pretty = program2.opts().pretty ?? false;
2080
1953
  try {
2081
1954
  if (options.needs && options.blocks) {
@@ -2274,7 +2147,7 @@ function depCommand(program2) {
2274
2147
  outputError(error, pretty);
2275
2148
  }
2276
2149
  });
2277
- dep.command("tree <id>").description("Show issue tree (children, verifications, and full hierarchy)").action(async (id) => {
2150
+ dep.command("tree <id>").description("Show issue tree (children and full hierarchy)").action(async (id) => {
2278
2151
  const pretty = program2.opts().pretty ?? false;
2279
2152
  try {
2280
2153
  const resolvedId = resolveId(id);
@@ -2303,7 +2176,7 @@ function buildIssueTree2(issueId, state) {
2303
2176
  const buildChildren = (id, visited2) => {
2304
2177
  const children = [];
2305
2178
  for (const [, i] of state) {
2306
- if ((i.parent === id || i.verifies === id) && !visited2.has(i.id)) {
2179
+ if (i.parent === id && !visited2.has(i.id)) {
2307
2180
  visited2.add(i.id);
2308
2181
  const nodeChildren = buildChildren(i.id, visited2);
2309
2182
  children.push({
@@ -2339,7 +2212,7 @@ function buildIssueTree2(issueId, state) {
2339
2212
  if (!parentIssue) break;
2340
2213
  const siblings = [];
2341
2214
  for (const [, i] of state) {
2342
- if ((i.parent === parentIssue.id || i.verifies === parentIssue.id) && i.id !== currentIssue.id) {
2215
+ if (i.parent === parentIssue.id && i.id !== currentIssue.id) {
2343
2216
  siblings.push({
2344
2217
  id: i.id,
2345
2218
  title: i.title,
@@ -2372,7 +2245,7 @@ function formatIssueTreePretty2(node) {
2372
2245
  const lines = [];
2373
2246
  const formatNode = (n, prefix, isLast, isRoot) => {
2374
2247
  const connector = isRoot ? "" : isLast ? "\u2514\u2500 " : "\u251C\u2500 ";
2375
- const statusIcon = n.status === "closed" ? "\u2713" : n.status === "in_progress" ? "\u25B6" : n.status === "pending_verification" ? "\u23F3" : "\u25CB";
2248
+ const statusIcon = n.status === "closed" ? "\u2713" : n.status === "in_progress" ? "\u25B6" : "\u25CB";
2376
2249
  const marker = n.isTarget ? " \u25C0" : "";
2377
2250
  lines.push(`${prefix}${connector}${statusIcon} ${n.id}: ${n.title} [${n.type}] P${n.priority}${marker}`);
2378
2251
  const children = n.children ?? [];
@@ -2850,26 +2723,27 @@ data: ${message}
2850
2723
  res.status(400).json({ error: "Priority must be 0-4" });
2851
2724
  return;
2852
2725
  }
2853
- let parentReopened;
2726
+ const parentsReopened = [];
2854
2727
  if (parent) {
2855
2728
  const parentIssue = getIssue(parent);
2856
2729
  if (!parentIssue) {
2857
2730
  res.status(400).json({ error: `Parent issue not found: ${parent}` });
2858
2731
  return;
2859
2732
  }
2860
- if (parentIssue.type === "verification") {
2861
- res.status(400).json({ error: "Verification issues cannot be parents" });
2862
- return;
2863
- }
2864
- if (parentIssue.status === "closed") {
2865
- const reopenEvent = {
2866
- type: "reopen",
2867
- issueId: parent,
2868
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2869
- data: { reason: "Reopened to add child" }
2870
- };
2871
- appendEvent(reopenEvent, pebbleDir);
2872
- parentReopened = { id: parent, title: parentIssue.title };
2733
+ const state = getComputedState();
2734
+ let current = state.get(parent);
2735
+ while (current) {
2736
+ if (current.status === "closed") {
2737
+ const reopenEvent = {
2738
+ type: "reopen",
2739
+ issueId: current.id,
2740
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2741
+ data: { reason: "Reopened to add descendant" }
2742
+ };
2743
+ appendEvent(reopenEvent, pebbleDir);
2744
+ parentsReopened.push({ id: current.id, title: current.title });
2745
+ }
2746
+ current = current.parent ? state.get(current.parent) : void 0;
2873
2747
  }
2874
2748
  }
2875
2749
  const issueId = generateId(config.prefix);
@@ -2897,7 +2771,7 @@ data: ${message}
2897
2771
  appendEvent(parentUpdateEvent, pebbleDir);
2898
2772
  }
2899
2773
  const issue = getIssue(issueId);
2900
- const result = parentReopened ? { ...issue, _parentReopened: parentReopened } : issue;
2774
+ const result = parentsReopened.length > 0 ? { ...issue, _parentsReopened: parentsReopened } : issue;
2901
2775
  res.status(201).json(result);
2902
2776
  } catch (error) {
2903
2777
  res.status(500).json({ error: error.message });
@@ -2928,23 +2802,7 @@ data: ${message}
2928
2802
  results.push({ id: issueId, success: false, error: "Cannot close issue with open children" });
2929
2803
  continue;
2930
2804
  }
2931
- const pendingVerifications = getVerifications(issueId).filter((v) => v.status !== "closed");
2932
2805
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
2933
- if (pendingVerifications.length > 0) {
2934
- const updateEvent = {
2935
- type: "update",
2936
- issueId,
2937
- timestamp,
2938
- data: { status: "pending_verification" }
2939
- };
2940
- appendEvent(updateEvent, pebbleDir);
2941
- results.push({
2942
- id: issueId,
2943
- success: true,
2944
- error: `Moved to pending_verification (${pendingVerifications.length} verification(s) pending)`
2945
- });
2946
- continue;
2947
- }
2948
2806
  const event = {
2949
2807
  issueId,
2950
2808
  timestamp,
@@ -2975,7 +2833,7 @@ data: ${message}
2975
2833
  return;
2976
2834
  }
2977
2835
  if (updates.status) {
2978
- const validStatuses = ["open", "in_progress", "blocked", "pending_verification"];
2836
+ const validStatuses = ["open", "in_progress", "blocked"];
2979
2837
  if (!validStatuses.includes(updates.status)) {
2980
2838
  res.status(400).json({
2981
2839
  error: `Invalid status: ${updates.status}. Use close endpoint to close issues.`
@@ -3120,20 +2978,12 @@ data: ${message}
3120
2978
  res.status(400).json({ error: `Parent issue not found: ${parent}` });
3121
2979
  return;
3122
2980
  }
3123
- if (parentFound.issue.type === "verification") {
3124
- res.status(400).json({ error: "Verification issues cannot be parents" });
3125
- return;
3126
- }
3127
2981
  } else {
3128
2982
  const parentIssue = getIssue(parent);
3129
2983
  if (!parentIssue) {
3130
2984
  res.status(400).json({ error: `Parent issue not found: ${parent}` });
3131
2985
  return;
3132
2986
  }
3133
- if (parentIssue.type === "verification") {
3134
- res.status(400).json({ error: "Verification issues cannot be parents" });
3135
- return;
3136
- }
3137
2987
  }
3138
2988
  }
3139
2989
  updates.parent = parent;
@@ -3238,30 +3088,6 @@ data: ${message}
3238
3088
  }
3239
3089
  const { reason } = req.body;
3240
3090
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
3241
- let pendingVerifications = [];
3242
- if (isMultiWorktree()) {
3243
- const allIssues = mergeIssuesFromFiles(issueFiles);
3244
- pendingVerifications = allIssues.filter(
3245
- (i) => i.verifies === issueId && i.status !== "closed"
3246
- );
3247
- } else {
3248
- pendingVerifications = getVerifications(issueId).filter((v) => v.status !== "closed");
3249
- }
3250
- if (pendingVerifications.length > 0) {
3251
- const updateEvent = {
3252
- type: "update",
3253
- issueId,
3254
- timestamp,
3255
- data: { status: "pending_verification" }
3256
- };
3257
- appendEventToFile(updateEvent, targetFile);
3258
- const updatedIssue = { ...issue, status: "pending_verification", updatedAt: timestamp };
3259
- res.json({
3260
- ...updatedIssue,
3261
- _pendingVerifications: pendingVerifications.map((v) => ({ id: v.id, title: v.title }))
3262
- });
3263
- return;
3264
- }
3265
3091
  const event = {
3266
3092
  type: "close",
3267
3093
  issueId,
@@ -3269,49 +3095,11 @@ data: ${message}
3269
3095
  data: { reason }
3270
3096
  };
3271
3097
  appendEventToFile(event, targetFile);
3272
- let autoClosed;
3273
- if (issue.verifies) {
3274
- let targetIssue;
3275
- let targetVerifications = [];
3276
- if (isMultiWorktree()) {
3277
- const found = findIssueInSources(issue.verifies, issueFiles);
3278
- if (found) {
3279
- targetIssue = found.issue;
3280
- const allIssues = mergeIssuesFromFiles(issueFiles);
3281
- targetVerifications = allIssues.filter(
3282
- (i) => i.verifies === issue.verifies && i.status !== "closed"
3283
- );
3284
- }
3285
- } else {
3286
- targetIssue = getIssue(issue.verifies);
3287
- targetVerifications = getVerifications(issue.verifies).filter((v) => v.status !== "closed");
3288
- }
3289
- if (targetIssue && targetIssue.status === "pending_verification" && targetVerifications.length === 0) {
3290
- const autoCloseEvent = {
3291
- type: "close",
3292
- issueId: issue.verifies,
3293
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3294
- data: { reason: "All verifications completed" }
3295
- };
3296
- if (isMultiWorktree()) {
3297
- const targetFound = findIssueInSources(issue.verifies, issueFiles);
3298
- if (targetFound) {
3299
- appendEventToFile(autoCloseEvent, targetFound.targetFile);
3300
- }
3301
- } else {
3302
- const pebbleDir = getOrCreatePebbleDir();
3303
- appendEventToFile(autoCloseEvent, path3.join(pebbleDir, "issues.jsonl"));
3304
- }
3305
- autoClosed = { id: targetIssue.id, title: targetIssue.title };
3306
- }
3307
- }
3308
3098
  if (isMultiWorktree()) {
3309
3099
  const updated = findIssueInSources(issueId, issueFiles);
3310
- const result = updated?.issue || { ...issue, status: "closed", updatedAt: timestamp };
3311
- res.json(autoClosed ? { ...result, _autoClosed: autoClosed } : result);
3100
+ res.json(updated?.issue || { ...issue, status: "closed", updatedAt: timestamp });
3312
3101
  } else {
3313
- const result = getIssue(issueId);
3314
- res.json(autoClosed ? { ...result, _autoClosed: autoClosed } : result);
3102
+ res.json(getIssue(issueId));
3315
3103
  }
3316
3104
  } catch (error) {
3317
3105
  res.status(500).json({ error: error.message });
@@ -3408,13 +3196,6 @@ data: ${message}
3408
3196
  alreadyQueued.add(desc.id);
3409
3197
  }
3410
3198
  }
3411
- const verifications = getVerifications(issueId);
3412
- for (const v of verifications) {
3413
- if (!alreadyQueued.has(v.id) && !v.deleted) {
3414
- toDelete.push({ id: v.id, cascade: true });
3415
- alreadyQueued.add(v.id);
3416
- }
3417
- }
3418
3199
  const cleanupReferences = (deletedId) => {
3419
3200
  for (const [id, iss] of state) {
3420
3201
  if (id === deletedId || iss.deleted) continue;
@@ -4000,23 +3781,11 @@ function countChildren(epicId) {
4000
3781
  return {
4001
3782
  total: children.length,
4002
3783
  done: children.filter((c) => c.status === "closed").length,
4003
- pending_verification: children.filter((c) => c.status === "pending_verification").length,
4004
3784
  in_progress: children.filter((c) => c.status === "in_progress").length,
4005
3785
  open: children.filter((c) => c.status === "open").length,
4006
3786
  blocked: children.filter((c) => c.status === "blocked").length
4007
3787
  };
4008
3788
  }
4009
- function countVerifications(epicId) {
4010
- const children = getChildren(epicId);
4011
- let total = 0;
4012
- let done = 0;
4013
- for (const child of children) {
4014
- const verifications = getVerifications(child.id);
4015
- total += verifications.length;
4016
- done += verifications.filter((v) => v.status === "closed").length;
4017
- }
4018
- return { total, done };
4019
- }
4020
3789
  function getIssueComments(issueId) {
4021
3790
  const events = readEvents();
4022
3791
  return events.filter((e) => e.type === "comment" && e.issueId === issueId).sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()).map((e) => ({ text: e.data.text, timestamp: e.timestamp, source: e.source }));
@@ -4069,13 +3838,10 @@ function formatSummaryPretty(summaries, sectionHeader) {
4069
3838
  lines.push(`## ${sectionHeader} (${summaries.length})`);
4070
3839
  lines.push("");
4071
3840
  for (const summary of summaries) {
4072
- const { children, verifications } = summary;
3841
+ const { children } = summary;
4073
3842
  lines.push(`${summary.id}: ${summary.title}`);
4074
3843
  lines.push(` Created: ${formatRelativeTime(summary.createdAt)} | Updated: ${formatRelativeTime(summary.updatedAt)}`);
4075
- const pendingStr = children.pending_verification > 0 ? ` (${children.pending_verification} pending verification)` : "";
4076
- const issueCount = `Issues: ${children.done}/${children.total} done${pendingStr}`;
4077
- const verifCount = `Verifications: ${verifications.done}/${verifications.total} done`;
4078
- lines.push(` ${issueCount} | ${verifCount}`);
3844
+ lines.push(` Issues: ${children.done}/${children.total} done`);
4079
3845
  if (summary.parent) {
4080
3846
  lines.push(` Parent: ${summary.parent.id} (${summary.parent.title})`);
4081
3847
  }
@@ -4103,8 +3869,7 @@ function summaryCommand(program2) {
4103
3869
  status: epic.status,
4104
3870
  createdAt: epic.createdAt,
4105
3871
  updatedAt: epic.updatedAt,
4106
- children: countChildren(epic.id),
4107
- verifications: countVerifications(epic.id)
3872
+ children: countChildren(epic.id)
4108
3873
  };
4109
3874
  if (epic.parent) {
4110
3875
  const parentIssue = getIssue(epic.parent);
@@ -4400,63 +4165,6 @@ function searchCommand(program2) {
4400
4165
  });
4401
4166
  }
4402
4167
 
4403
- // src/cli/commands/verifications.ts
4404
- function verificationsCommand(program2) {
4405
- program2.command("verifications <id>").description("List verification issues for a given issue").option("--limit <n>", "Max verifications to return (default: 30)").option("--all", "Show all verifications (no limit)").action(async (id, options) => {
4406
- const pretty = program2.opts().pretty ?? false;
4407
- try {
4408
- getOrCreatePebbleDir();
4409
- const resolvedId = resolveId(id);
4410
- const issue = getIssue(resolvedId);
4411
- if (!issue) {
4412
- throw new Error(`Issue not found: ${id}`);
4413
- }
4414
- let verifications = getVerifications(resolvedId);
4415
- verifications.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
4416
- const total = verifications.length;
4417
- const limit = options.all ? 0 : options.limit ? parseInt(options.limit, 10) : 30;
4418
- if (limit > 0 && verifications.length > limit) {
4419
- verifications = verifications.slice(0, limit);
4420
- }
4421
- const limitInfo = {
4422
- total,
4423
- shown: verifications.length,
4424
- limited: limit > 0 && total > limit
4425
- };
4426
- if (pretty) {
4427
- if (verifications.length === 0) {
4428
- console.log(`No verifications for ${resolvedId}`);
4429
- } else {
4430
- console.log(`Verifications for ${resolvedId} "${issue.title}"`);
4431
- console.log("\u2500".repeat(50));
4432
- for (const v of verifications) {
4433
- const status = v.status === "closed" ? "\u2713" : "\u25CB";
4434
- console.log(` ${status} ${v.id} - ${v.title}`);
4435
- }
4436
- console.log("");
4437
- console.log(`Total: ${verifications.length} verification(s)`);
4438
- if (limitInfo.limited) {
4439
- console.log(formatLimitMessage(limitInfo));
4440
- }
4441
- }
4442
- } else {
4443
- const output = {
4444
- issueId: resolvedId,
4445
- verifications: verifications.map((v) => ({
4446
- id: v.id,
4447
- title: v.title,
4448
- status: v.status
4449
- })),
4450
- ...limitInfo.limited && { _meta: limitInfo }
4451
- };
4452
- console.log(formatJson(output));
4453
- }
4454
- } catch (error) {
4455
- outputError(error, pretty);
4456
- }
4457
- });
4458
- }
4459
-
4460
4168
  // src/cli/commands/init.ts
4461
4169
  import * as path6 from "path";
4462
4170
  function initCommand(program2) {
@@ -4485,7 +4193,7 @@ var __filename2 = fileURLToPath2(import.meta.url);
4485
4193
  var __dirname2 = dirname2(__filename2);
4486
4194
  var packageJson = JSON.parse(readFileSync2(join3(__dirname2, "../../package.json"), "utf-8"));
4487
4195
  var program = new Command();
4488
- program.name("pebble").description("A lightweight JSONL-based issue tracker").version(packageJson.version);
4196
+ program.name("pebble").description("A lightweight JSONL-based issue tracker").version(packageJson.version).addHelpText("after", '\nAll commands accept partial IDs (e.g., "abc" matches "PROJ-abc123")');
4489
4197
  program.option("-P, --pretty", "Human-readable output (default: JSON)");
4490
4198
  program.option("--json", "JSON output (this is the default, flag not needed)");
4491
4199
  program.option("--local", "Use local .pebble directory even in a git worktree");
@@ -4514,7 +4222,6 @@ mergeCommand(program);
4514
4222
  summaryCommand(program);
4515
4223
  historyCommand(program);
4516
4224
  searchCommand(program);
4517
- verificationsCommand(program);
4518
4225
  initCommand(program);
4519
4226
  program.parse();
4520
4227
  //# sourceMappingURL=index.js.map