@bretwardjames/ghp-core 0.9.0 → 0.11.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/index.cjs CHANGED
@@ -337,6 +337,10 @@ var PROJECT_FIELDS_QUERY = `
337
337
  ... on ProjectV2IterationField {
338
338
  id
339
339
  name
340
+ configuration {
341
+ iterations { id title }
342
+ completedIterations { id title }
343
+ }
340
344
  }
341
345
  }
342
346
  }
@@ -1276,6 +1280,21 @@ var GitHubAPI = class {
1276
1280
  return false;
1277
1281
  }
1278
1282
  }
1283
+ /**
1284
+ * Move an issue to a target status in its project.
1285
+ * Returns { success, error? } — does not throw.
1286
+ */
1287
+ async moveIssueToStatus(repo, issueNumber, targetStatus) {
1288
+ const item = await this.findItemByNumber(repo, issueNumber);
1289
+ if (!item) return { success: false, error: `Issue #${issueNumber} not found in any project` };
1290
+ if (item.status === targetStatus) return { success: true };
1291
+ const statusField = await this.getStatusField(item.projectId);
1292
+ if (!statusField) return { success: false, error: "Could not find Status field on project" };
1293
+ const option = statusField.options.find((o) => o.name === targetStatus);
1294
+ if (!option) return { success: false, error: `Status "${targetStatus}" not found. Available: ${statusField.options.map((o) => o.name).join(", ")}` };
1295
+ const updated = await this.updateItemStatus(item.projectId, item.id, statusField.fieldId, option.id);
1296
+ return updated ? { success: true } : { success: false, error: "Failed to update status" };
1297
+ }
1279
1298
  /**
1280
1299
  * Find an item by issue number - direct lookup via issue's projectItems
1281
1300
  * Much faster than iterating through all project items
@@ -1350,28 +1369,48 @@ var GitHubAPI = class {
1350
1369
  async getProjectFields(projectId) {
1351
1370
  if (!this.graphqlWithAuth) throw new Error("Not authenticated");
1352
1371
  const response = await this.graphqlWithRetry(PROJECT_FIELDS_QUERY, { projectId });
1353
- return response.node.fields.nodes.map((f) => ({
1354
- id: f.id,
1355
- name: f.name,
1356
- type: f.__typename.replace("ProjectV2", "").replace("Field", ""),
1357
- options: f.options
1358
- }));
1372
+ return response.node.fields.nodes.map((f) => {
1373
+ let options = f.options;
1374
+ if (f.configuration) {
1375
+ const all = [...f.configuration.iterations, ...f.configuration.completedIterations];
1376
+ options = all.map((i) => ({ id: i.id, name: i.title }));
1377
+ }
1378
+ return {
1379
+ id: f.id,
1380
+ name: f.name,
1381
+ type: f.__typename.replace("ProjectV2", "").replace("Field", ""),
1382
+ options
1383
+ };
1384
+ });
1359
1385
  }
1360
1386
  /**
1361
- * Set a field value on a project item
1387
+ * Set a field value on a project item.
1388
+ * Routes SingleSelect fields through the inline mutation pattern
1389
+ * (passing the option ID as a scalar variable) since GitHub's API
1390
+ * does not reliably deserialize ProjectV2FieldValue input objects.
1362
1391
  */
1363
1392
  async setFieldValue(projectId, itemId, fieldId, value) {
1364
1393
  if (!this.graphqlWithAuth) throw new Error("Not authenticated");
1365
1394
  try {
1366
- await this.graphqlWithRetry(UPDATE_ITEM_FIELD_MUTATION, {
1367
- projectId,
1368
- itemId,
1369
- fieldId,
1370
- value
1371
- });
1372
- return true;
1373
- } catch {
1374
- return false;
1395
+ if (value.singleSelectOptionId) {
1396
+ await this.graphqlWithRetry(UPDATE_ITEM_STATUS_MUTATION, {
1397
+ projectId,
1398
+ itemId,
1399
+ fieldId,
1400
+ optionId: value.singleSelectOptionId
1401
+ });
1402
+ } else {
1403
+ await this.graphqlWithRetry(UPDATE_ITEM_FIELD_MUTATION, {
1404
+ projectId,
1405
+ itemId,
1406
+ fieldId,
1407
+ value
1408
+ });
1409
+ }
1410
+ return { success: true };
1411
+ } catch (error) {
1412
+ const message = error instanceof Error ? error.message : String(error);
1413
+ return { success: false, error: message };
1375
1414
  }
1376
1415
  }
1377
1416
  /**
@@ -2627,31 +2666,41 @@ var SYNCABLE_KEYS = [
2627
2666
  "mainBranch",
2628
2667
  "branchPattern",
2629
2668
  "startWorkingStatus",
2630
- "doneStatus"
2669
+ "doneStatus",
2670
+ "prOpenedStatus",
2671
+ "prMergedStatus"
2631
2672
  ];
2632
2673
  var SETTING_DISPLAY_NAMES = {
2633
2674
  mainBranch: "Main Branch",
2634
2675
  branchPattern: "Branch Name Pattern",
2635
2676
  startWorkingStatus: "Start Working Status",
2636
- doneStatus: "Done/PR Merged Status"
2677
+ doneStatus: "Done Status",
2678
+ prOpenedStatus: "PR Opened Status",
2679
+ prMergedStatus: "PR Merged Status"
2637
2680
  };
2638
2681
  var VSCODE_TO_CLI_MAP = {
2639
2682
  "mainBranch": "mainBranch",
2640
2683
  "branchNamePattern": "branchPattern",
2641
2684
  "startWorkingStatus": "startWorkingStatus",
2642
- "prMergedStatus": "doneStatus"
2685
+ "doneStatus": "doneStatus",
2686
+ "prOpenedStatus": "prOpenedStatus",
2687
+ "prMergedStatus": "prMergedStatus"
2643
2688
  };
2644
2689
  var CLI_TO_VSCODE_MAP = {
2645
2690
  mainBranch: "mainBranch",
2646
2691
  branchPattern: "branchNamePattern",
2647
2692
  startWorkingStatus: "startWorkingStatus",
2648
- doneStatus: "prMergedStatus"
2693
+ doneStatus: "doneStatus",
2694
+ prOpenedStatus: "prOpenedStatus",
2695
+ prMergedStatus: "prMergedStatus"
2649
2696
  };
2650
2697
  var DEFAULT_VALUES = {
2651
2698
  mainBranch: "main",
2652
2699
  branchPattern: "{user}/{number}-{title}",
2653
2700
  startWorkingStatus: "In Progress",
2654
- doneStatus: "Done"
2701
+ doneStatus: "Done",
2702
+ prOpenedStatus: "In Review",
2703
+ prMergedStatus: "Ready for Beta"
2655
2704
  };
2656
2705
  function normalizeVSCodeSettings(vscodeSettings) {
2657
2706
  const result = {};
package/dist/index.d.cts CHANGED
@@ -539,6 +539,14 @@ declare class GitHubAPI {
539
539
  * Update an item's status
540
540
  */
541
541
  updateItemStatus(projectId: string, itemId: string, fieldId: string, optionId: string): Promise<boolean>;
542
+ /**
543
+ * Move an issue to a target status in its project.
544
+ * Returns { success, error? } — does not throw.
545
+ */
546
+ moveIssueToStatus(repo: RepoInfo, issueNumber: number, targetStatus: string): Promise<{
547
+ success: boolean;
548
+ error?: string;
549
+ }>;
542
550
  /**
543
551
  * Find an item by issue number - direct lookup via issue's projectItems
544
552
  * Much faster than iterating through all project items
@@ -557,13 +565,21 @@ declare class GitHubAPI {
557
565
  }>;
558
566
  }>>;
559
567
  /**
560
- * Set a field value on a project item
568
+ * Set a field value on a project item.
569
+ * Routes SingleSelect fields through the inline mutation pattern
570
+ * (passing the option ID as a scalar variable) since GitHub's API
571
+ * does not reliably deserialize ProjectV2FieldValue input objects.
561
572
  */
562
573
  setFieldValue(projectId: string, itemId: string, fieldId: string, value: {
563
574
  text?: string;
564
575
  number?: number;
565
576
  singleSelectOptionId?: string;
566
- }): Promise<boolean>;
577
+ date?: string;
578
+ iterationId?: string;
579
+ }): Promise<{
580
+ success: boolean;
581
+ error?: string;
582
+ }>;
567
583
  /**
568
584
  * Create a new issue
569
585
  */
@@ -1013,7 +1029,7 @@ declare function buildOrgProjectUrl(org: string, projectNumber: number): string;
1013
1029
  * The canonical setting keys used in sync operations.
1014
1030
  * These are the CLI key names (used as the canonical form).
1015
1031
  */
1016
- type SyncableSettingKey = 'mainBranch' | 'branchPattern' | 'startWorkingStatus' | 'doneStatus';
1032
+ type SyncableSettingKey = 'mainBranch' | 'branchPattern' | 'startWorkingStatus' | 'doneStatus' | 'prOpenedStatus' | 'prMergedStatus';
1017
1033
  /**
1018
1034
  * Settings that can be synced between CLI and VSCode.
1019
1035
  * Uses CLI key names as the canonical form.
@@ -1023,6 +1039,8 @@ interface SyncableSettings {
1023
1039
  branchPattern?: string;
1024
1040
  startWorkingStatus?: string;
1025
1041
  doneStatus?: string;
1042
+ prOpenedStatus?: string;
1043
+ prMergedStatus?: string;
1026
1044
  }
1027
1045
  /**
1028
1046
  * A source of settings (CLI or VSCode)
@@ -1179,7 +1197,7 @@ declare const PROJECT_ITEMS_QUERY = "\n query($projectId: ID!, $cursor: Strin
1179
1197
  /**
1180
1198
  * Query to get project fields (including status options)
1181
1199
  */
1182
- declare const PROJECT_FIELDS_QUERY = "\n query($projectId: ID!) {\n node(id: $projectId) {\n ... on ProjectV2 {\n fields(first: 30) {\n nodes {\n __typename\n ... on ProjectV2Field {\n id\n name\n }\n ... on ProjectV2SingleSelectField {\n id\n name\n options { id name }\n }\n ... on ProjectV2IterationField {\n id\n name\n }\n }\n }\n }\n }\n }\n";
1200
+ declare const PROJECT_FIELDS_QUERY = "\n query($projectId: ID!) {\n node(id: $projectId) {\n ... on ProjectV2 {\n fields(first: 30) {\n nodes {\n __typename\n ... on ProjectV2Field {\n id\n name\n }\n ... on ProjectV2SingleSelectField {\n id\n name\n options { id name }\n }\n ... on ProjectV2IterationField {\n id\n name\n configuration {\n iterations { id title }\n completedIterations { id title }\n }\n }\n }\n }\n }\n }\n }\n";
1183
1201
  /**
1184
1202
  * Query to get project views
1185
1203
  */
package/dist/index.d.ts CHANGED
@@ -539,6 +539,14 @@ declare class GitHubAPI {
539
539
  * Update an item's status
540
540
  */
541
541
  updateItemStatus(projectId: string, itemId: string, fieldId: string, optionId: string): Promise<boolean>;
542
+ /**
543
+ * Move an issue to a target status in its project.
544
+ * Returns { success, error? } — does not throw.
545
+ */
546
+ moveIssueToStatus(repo: RepoInfo, issueNumber: number, targetStatus: string): Promise<{
547
+ success: boolean;
548
+ error?: string;
549
+ }>;
542
550
  /**
543
551
  * Find an item by issue number - direct lookup via issue's projectItems
544
552
  * Much faster than iterating through all project items
@@ -557,13 +565,21 @@ declare class GitHubAPI {
557
565
  }>;
558
566
  }>>;
559
567
  /**
560
- * Set a field value on a project item
568
+ * Set a field value on a project item.
569
+ * Routes SingleSelect fields through the inline mutation pattern
570
+ * (passing the option ID as a scalar variable) since GitHub's API
571
+ * does not reliably deserialize ProjectV2FieldValue input objects.
561
572
  */
562
573
  setFieldValue(projectId: string, itemId: string, fieldId: string, value: {
563
574
  text?: string;
564
575
  number?: number;
565
576
  singleSelectOptionId?: string;
566
- }): Promise<boolean>;
577
+ date?: string;
578
+ iterationId?: string;
579
+ }): Promise<{
580
+ success: boolean;
581
+ error?: string;
582
+ }>;
567
583
  /**
568
584
  * Create a new issue
569
585
  */
@@ -1013,7 +1029,7 @@ declare function buildOrgProjectUrl(org: string, projectNumber: number): string;
1013
1029
  * The canonical setting keys used in sync operations.
1014
1030
  * These are the CLI key names (used as the canonical form).
1015
1031
  */
1016
- type SyncableSettingKey = 'mainBranch' | 'branchPattern' | 'startWorkingStatus' | 'doneStatus';
1032
+ type SyncableSettingKey = 'mainBranch' | 'branchPattern' | 'startWorkingStatus' | 'doneStatus' | 'prOpenedStatus' | 'prMergedStatus';
1017
1033
  /**
1018
1034
  * Settings that can be synced between CLI and VSCode.
1019
1035
  * Uses CLI key names as the canonical form.
@@ -1023,6 +1039,8 @@ interface SyncableSettings {
1023
1039
  branchPattern?: string;
1024
1040
  startWorkingStatus?: string;
1025
1041
  doneStatus?: string;
1042
+ prOpenedStatus?: string;
1043
+ prMergedStatus?: string;
1026
1044
  }
1027
1045
  /**
1028
1046
  * A source of settings (CLI or VSCode)
@@ -1179,7 +1197,7 @@ declare const PROJECT_ITEMS_QUERY = "\n query($projectId: ID!, $cursor: Strin
1179
1197
  /**
1180
1198
  * Query to get project fields (including status options)
1181
1199
  */
1182
- declare const PROJECT_FIELDS_QUERY = "\n query($projectId: ID!) {\n node(id: $projectId) {\n ... on ProjectV2 {\n fields(first: 30) {\n nodes {\n __typename\n ... on ProjectV2Field {\n id\n name\n }\n ... on ProjectV2SingleSelectField {\n id\n name\n options { id name }\n }\n ... on ProjectV2IterationField {\n id\n name\n }\n }\n }\n }\n }\n }\n";
1200
+ declare const PROJECT_FIELDS_QUERY = "\n query($projectId: ID!) {\n node(id: $projectId) {\n ... on ProjectV2 {\n fields(first: 30) {\n nodes {\n __typename\n ... on ProjectV2Field {\n id\n name\n }\n ... on ProjectV2SingleSelectField {\n id\n name\n options { id name }\n }\n ... on ProjectV2IterationField {\n id\n name\n configuration {\n iterations { id title }\n completedIterations { id title }\n }\n }\n }\n }\n }\n }\n }\n";
1183
1201
  /**
1184
1202
  * Query to get project views
1185
1203
  */
package/dist/index.js CHANGED
@@ -166,6 +166,10 @@ var PROJECT_FIELDS_QUERY = `
166
166
  ... on ProjectV2IterationField {
167
167
  id
168
168
  name
169
+ configuration {
170
+ iterations { id title }
171
+ completedIterations { id title }
172
+ }
169
173
  }
170
174
  }
171
175
  }
@@ -1105,6 +1109,21 @@ var GitHubAPI = class {
1105
1109
  return false;
1106
1110
  }
1107
1111
  }
1112
+ /**
1113
+ * Move an issue to a target status in its project.
1114
+ * Returns { success, error? } — does not throw.
1115
+ */
1116
+ async moveIssueToStatus(repo, issueNumber, targetStatus) {
1117
+ const item = await this.findItemByNumber(repo, issueNumber);
1118
+ if (!item) return { success: false, error: `Issue #${issueNumber} not found in any project` };
1119
+ if (item.status === targetStatus) return { success: true };
1120
+ const statusField = await this.getStatusField(item.projectId);
1121
+ if (!statusField) return { success: false, error: "Could not find Status field on project" };
1122
+ const option = statusField.options.find((o) => o.name === targetStatus);
1123
+ if (!option) return { success: false, error: `Status "${targetStatus}" not found. Available: ${statusField.options.map((o) => o.name).join(", ")}` };
1124
+ const updated = await this.updateItemStatus(item.projectId, item.id, statusField.fieldId, option.id);
1125
+ return updated ? { success: true } : { success: false, error: "Failed to update status" };
1126
+ }
1108
1127
  /**
1109
1128
  * Find an item by issue number - direct lookup via issue's projectItems
1110
1129
  * Much faster than iterating through all project items
@@ -1179,28 +1198,48 @@ var GitHubAPI = class {
1179
1198
  async getProjectFields(projectId) {
1180
1199
  if (!this.graphqlWithAuth) throw new Error("Not authenticated");
1181
1200
  const response = await this.graphqlWithRetry(PROJECT_FIELDS_QUERY, { projectId });
1182
- return response.node.fields.nodes.map((f) => ({
1183
- id: f.id,
1184
- name: f.name,
1185
- type: f.__typename.replace("ProjectV2", "").replace("Field", ""),
1186
- options: f.options
1187
- }));
1201
+ return response.node.fields.nodes.map((f) => {
1202
+ let options = f.options;
1203
+ if (f.configuration) {
1204
+ const all = [...f.configuration.iterations, ...f.configuration.completedIterations];
1205
+ options = all.map((i) => ({ id: i.id, name: i.title }));
1206
+ }
1207
+ return {
1208
+ id: f.id,
1209
+ name: f.name,
1210
+ type: f.__typename.replace("ProjectV2", "").replace("Field", ""),
1211
+ options
1212
+ };
1213
+ });
1188
1214
  }
1189
1215
  /**
1190
- * Set a field value on a project item
1216
+ * Set a field value on a project item.
1217
+ * Routes SingleSelect fields through the inline mutation pattern
1218
+ * (passing the option ID as a scalar variable) since GitHub's API
1219
+ * does not reliably deserialize ProjectV2FieldValue input objects.
1191
1220
  */
1192
1221
  async setFieldValue(projectId, itemId, fieldId, value) {
1193
1222
  if (!this.graphqlWithAuth) throw new Error("Not authenticated");
1194
1223
  try {
1195
- await this.graphqlWithRetry(UPDATE_ITEM_FIELD_MUTATION, {
1196
- projectId,
1197
- itemId,
1198
- fieldId,
1199
- value
1200
- });
1201
- return true;
1202
- } catch {
1203
- return false;
1224
+ if (value.singleSelectOptionId) {
1225
+ await this.graphqlWithRetry(UPDATE_ITEM_STATUS_MUTATION, {
1226
+ projectId,
1227
+ itemId,
1228
+ fieldId,
1229
+ optionId: value.singleSelectOptionId
1230
+ });
1231
+ } else {
1232
+ await this.graphqlWithRetry(UPDATE_ITEM_FIELD_MUTATION, {
1233
+ projectId,
1234
+ itemId,
1235
+ fieldId,
1236
+ value
1237
+ });
1238
+ }
1239
+ return { success: true };
1240
+ } catch (error) {
1241
+ const message = error instanceof Error ? error.message : String(error);
1242
+ return { success: false, error: message };
1204
1243
  }
1205
1244
  }
1206
1245
  /**
@@ -2456,31 +2495,41 @@ var SYNCABLE_KEYS = [
2456
2495
  "mainBranch",
2457
2496
  "branchPattern",
2458
2497
  "startWorkingStatus",
2459
- "doneStatus"
2498
+ "doneStatus",
2499
+ "prOpenedStatus",
2500
+ "prMergedStatus"
2460
2501
  ];
2461
2502
  var SETTING_DISPLAY_NAMES = {
2462
2503
  mainBranch: "Main Branch",
2463
2504
  branchPattern: "Branch Name Pattern",
2464
2505
  startWorkingStatus: "Start Working Status",
2465
- doneStatus: "Done/PR Merged Status"
2506
+ doneStatus: "Done Status",
2507
+ prOpenedStatus: "PR Opened Status",
2508
+ prMergedStatus: "PR Merged Status"
2466
2509
  };
2467
2510
  var VSCODE_TO_CLI_MAP = {
2468
2511
  "mainBranch": "mainBranch",
2469
2512
  "branchNamePattern": "branchPattern",
2470
2513
  "startWorkingStatus": "startWorkingStatus",
2471
- "prMergedStatus": "doneStatus"
2514
+ "doneStatus": "doneStatus",
2515
+ "prOpenedStatus": "prOpenedStatus",
2516
+ "prMergedStatus": "prMergedStatus"
2472
2517
  };
2473
2518
  var CLI_TO_VSCODE_MAP = {
2474
2519
  mainBranch: "mainBranch",
2475
2520
  branchPattern: "branchNamePattern",
2476
2521
  startWorkingStatus: "startWorkingStatus",
2477
- doneStatus: "prMergedStatus"
2522
+ doneStatus: "doneStatus",
2523
+ prOpenedStatus: "prOpenedStatus",
2524
+ prMergedStatus: "prMergedStatus"
2478
2525
  };
2479
2526
  var DEFAULT_VALUES = {
2480
2527
  mainBranch: "main",
2481
2528
  branchPattern: "{user}/{number}-{title}",
2482
2529
  startWorkingStatus: "In Progress",
2483
- doneStatus: "Done"
2530
+ doneStatus: "Done",
2531
+ prOpenedStatus: "In Review",
2532
+ prMergedStatus: "Ready for Beta"
2484
2533
  };
2485
2534
  function normalizeVSCodeSettings(vscodeSettings) {
2486
2535
  const result = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bretwardjames/ghp-core",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "Shared core library for GitHub Projects tools",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",