@oss-autopilot/core 3.13.4 → 3.14.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.
Files changed (85) hide show
  1. package/README.md +3 -3
  2. package/dist/cli-registry.js +50 -83
  3. package/dist/cli.bundle.cjs +110 -107
  4. package/dist/cli.js +5 -4
  5. package/dist/commands/comments.js +44 -10
  6. package/dist/commands/config.d.ts +2 -0
  7. package/dist/commands/config.js +50 -2
  8. package/dist/commands/curated-list.d.ts +17 -0
  9. package/dist/commands/curated-list.js +25 -0
  10. package/dist/commands/daily.d.ts +7 -1
  11. package/dist/commands/daily.js +136 -57
  12. package/dist/commands/dashboard-cache.d.ts +69 -0
  13. package/dist/commands/dashboard-cache.js +219 -0
  14. package/dist/commands/dashboard-data.d.ts +18 -10
  15. package/dist/commands/dashboard-data.js +35 -7
  16. package/dist/commands/dashboard-gist-sync.d.ts +93 -0
  17. package/dist/commands/dashboard-gist-sync.js +237 -0
  18. package/dist/commands/dashboard-server.d.ts +6 -10
  19. package/dist/commands/dashboard-server.js +148 -341
  20. package/dist/commands/features.js +6 -0
  21. package/dist/commands/guidelines.d.ts +6 -0
  22. package/dist/commands/guidelines.js +7 -0
  23. package/dist/commands/index.d.ts +2 -5
  24. package/dist/commands/index.js +2 -4
  25. package/dist/commands/init.d.ts +2 -0
  26. package/dist/commands/init.js +7 -1
  27. package/dist/commands/list-mark-done.js +6 -21
  28. package/dist/commands/list-move-tier.js +3 -5
  29. package/dist/commands/locate-issue-list.d.ts +25 -0
  30. package/dist/commands/locate-issue-list.js +67 -0
  31. package/dist/commands/merge-loop.d.ts +63 -0
  32. package/dist/commands/merge-loop.js +157 -0
  33. package/dist/commands/repo-vet.js +40 -1
  34. package/dist/commands/scout-bridge.d.ts +35 -2
  35. package/dist/commands/scout-bridge.js +65 -13
  36. package/dist/commands/search.d.ts +4 -6
  37. package/dist/commands/search.js +58 -11
  38. package/dist/commands/setup.d.ts +2 -0
  39. package/dist/commands/setup.js +56 -2
  40. package/dist/commands/skip-file-parser.d.ts +23 -0
  41. package/dist/commands/skip-file-parser.js +23 -10
  42. package/dist/commands/startup.d.ts +1 -6
  43. package/dist/commands/startup.js +25 -59
  44. package/dist/commands/track.d.ts +2 -2
  45. package/dist/commands/track.js +2 -2
  46. package/dist/commands/vet-list.js +4 -0
  47. package/dist/core/config-registry.js +36 -0
  48. package/dist/core/daily-logic.d.ts +25 -2
  49. package/dist/core/daily-logic.js +58 -3
  50. package/dist/core/gist-health.d.ts +81 -0
  51. package/dist/core/gist-health.js +39 -0
  52. package/dist/core/gist-state-store.d.ts +3 -1
  53. package/dist/core/gist-state-store.js +7 -2
  54. package/dist/core/github-stats.d.ts +2 -2
  55. package/dist/core/github-stats.js +20 -4
  56. package/dist/core/index.d.ts +4 -3
  57. package/dist/core/index.js +4 -3
  58. package/dist/core/issue-conversation.js +8 -2
  59. package/dist/core/issue-grading.d.ts +9 -0
  60. package/dist/core/issue-grading.js +9 -0
  61. package/dist/core/pagination.d.ts +27 -0
  62. package/dist/core/pagination.js +23 -5
  63. package/dist/core/pr-comments-fetcher.d.ts +7 -0
  64. package/dist/core/pr-comments-fetcher.js +19 -8
  65. package/dist/core/pr-monitor.d.ts +2 -0
  66. package/dist/core/pr-monitor.js +26 -9
  67. package/dist/core/repo-score-manager.d.ts +2 -2
  68. package/dist/core/repo-score-manager.js +3 -3
  69. package/dist/core/repo-vet.d.ts +2 -2
  70. package/dist/core/repo-vet.js +1 -1
  71. package/dist/core/review-analysis.d.ts +19 -0
  72. package/dist/core/review-analysis.js +28 -0
  73. package/dist/core/state-schema.d.ts +43 -6
  74. package/dist/core/state-schema.js +81 -4
  75. package/dist/core/state.d.ts +36 -5
  76. package/dist/core/state.js +177 -28
  77. package/dist/core/strategy.js +6 -5
  78. package/dist/core/types.d.ts +8 -0
  79. package/dist/core/untrusted-content.d.ts +45 -0
  80. package/dist/core/untrusted-content.js +54 -0
  81. package/dist/formatters/json.d.ts +81 -7
  82. package/dist/formatters/json.js +55 -2
  83. package/package.json +2 -2
  84. package/dist/commands/shelve.d.ts +0 -45
  85. package/dist/commands/shelve.js +0 -54
@@ -20,7 +20,13 @@ export interface JsonOutput<T = unknown> {
20
20
  * (#1433): machine consumers of mutating --json commands must see that
21
21
  * the mutation will not sync. Set once per process from the CLI bootstrap
22
22
  * via {@link setEnvelopeGistWarning}; envelope-level (not data-level) so
23
- * per-command output schemas are untouched. */
23
+ * per-command output schemas are untouched.
24
+ *
25
+ * Omitted when the command's own payload already carries the same
26
+ * condition as a structured `warnings[{phase:'gist-init'}]` entry (#1444):
27
+ * commands that own a warnings[] array (`daily`) report gist degradation
28
+ * exactly once, there. Consumers should check `data.warnings` first and
29
+ * fall back to this field for commands without a warnings array. */
24
30
  gistInitWarning?: string;
25
31
  }
26
32
  /** Set (or clear) the gist degradation warning carried by every subsequent
@@ -60,12 +66,12 @@ export interface CompactRepoGroup {
60
66
  * See `DailyWarning` and issue #1042 for the rationale — keeping this a
61
67
  * fixed union so downstream consumers can switch on it without drift.
62
68
  */
63
- export type DailyWarningPhase = 'fetch' | 'repo-scores' | 'analytics' | 'scout-sync' | 'partition' | 'dismiss-filter' | 'gist-init' | 'gist-checkpoint' | 'gist-staleness' | 'state-load';
69
+ export type DailyWarningPhase = 'fetch' | 'repo-scores' | 'analytics' | 'merge-loop' | 'partition' | 'dismiss-filter' | 'gist-init' | 'gist-checkpoint' | 'gist-staleness' | 'state-load';
64
70
  /**
65
71
  * A single non-fatal failure surfaced from the `daily` pipeline. Unlike
66
72
  * `PRCheckFailure` (which is scoped to per-PR fetch errors), this covers
67
73
  * ancillary fetches that previously demoted to a log-only `warn()` — repo
68
- * metadata, monthly analytics, scout sync, Gist checkpoint, etc.
74
+ * metadata, monthly analytics, Gist checkpoint, etc.
69
75
  *
70
76
  * `timestamp` and `details` are optional structured extensions added in
71
77
  * #1193 so staleness warnings can carry `lastSuccessfulRefresh` /
@@ -91,6 +97,23 @@ export interface StalenessLike {
91
97
  detectedAt: string;
92
98
  }
93
99
  export declare function buildStalenessWarning(info: StalenessLike): DailyWarning;
100
+ /**
101
+ * One curated-list entry auto-marked done because its PR merged (#1463).
102
+ * Produced by the daily merge-loop reconciliation (commands/merge-loop.ts):
103
+ * a recently merged PR's URL was found inside a list entry's block (the
104
+ * entry line or an indented sub-bullet), and the entry was struck through
105
+ * via the same transform `list-mark-done` uses.
106
+ */
107
+ export interface MergedPRListUpdate {
108
+ /** The merged PR whose detection triggered the auto-mark. */
109
+ prUrl: string;
110
+ /** URL on the struck entry line (usually the issue URL the PR resolved). */
111
+ issueUrl: string;
112
+ /** Curated-list file that was updated. */
113
+ listPath: string;
114
+ /** True if the parent `### repo/name` heading was also struck through. */
115
+ repoHeadingStruck: boolean;
116
+ }
94
117
  export interface DailyOutput {
95
118
  digest: DailyDigestCompact;
96
119
  capacity: CapacityAssessment;
@@ -105,7 +128,7 @@ export interface DailyOutput {
105
128
  failures: PRCheckFailure[];
106
129
  /**
107
130
  * Non-fatal warnings from ancillary pipeline phases (repo metadata,
108
- * analytics, scout sync, Gist checkpoint, etc.). Always an array — empty
131
+ * analytics, Gist checkpoint, etc.). Always an array — empty
109
132
  * on clean runs. See #1042.
110
133
  */
111
134
  warnings: DailyWarning[];
@@ -116,6 +139,13 @@ export interface DailyOutput {
116
139
  * absent or null on runs where the gate stays silent.
117
140
  */
118
141
  strategySummary?: import('../core/strategy.js').StrategyResult | null;
142
+ /**
143
+ * Curated-list entries auto-marked done this run because their PR merged
144
+ * (#1463). Present only when at least one entry was actually struck —
145
+ * merge-free runs (and runs with no curated list / no matching entry)
146
+ * omit the field entirely so existing consumers and goldens see no change.
147
+ */
148
+ listUpdates?: MergedPRListUpdate[];
119
149
  }
120
150
  /**
121
151
  * Compact version of DailyOutput for reduced JSON payload size (#763).
@@ -145,6 +175,8 @@ export interface CompactDailyOutput {
145
175
  warnings: DailyWarning[];
146
176
  /** Periodic strategy snapshot, threaded through compact mode for parity. See {@link DailyOutput.strategySummary}. */
147
177
  strategySummary?: import('../core/strategy.js').StrategyResult | null;
178
+ /** Curated-list entries auto-marked done this run (#1463). See {@link DailyOutput.listUpdates}. */
179
+ listUpdates?: MergedPRListUpdate[];
148
180
  }
149
181
  /**
150
182
  * Strip a full DailyOutput down to the compact subset (#763).
@@ -185,7 +217,7 @@ export declare const StatusOutputSchema: z.ZodObject<{
185
217
  fetch: "fetch";
186
218
  "repo-scores": "repo-scores";
187
219
  analytics: "analytics";
188
- "scout-sync": "scout-sync";
220
+ "merge-loop": "merge-loop";
189
221
  partition: "partition";
190
222
  "dismiss-filter": "dismiss-filter";
191
223
  "gist-init": "gist-init";
@@ -401,7 +433,7 @@ export declare const DailyOutputSchema: z.ZodObject<{
401
433
  fetch: "fetch";
402
434
  "repo-scores": "repo-scores";
403
435
  analytics: "analytics";
404
- "scout-sync": "scout-sync";
436
+ "merge-loop": "merge-loop";
405
437
  partition: "partition";
406
438
  "dismiss-filter": "dismiss-filter";
407
439
  "gist-init": "gist-init";
@@ -458,6 +490,12 @@ export declare const DailyOutputSchema: z.ZodObject<{
458
490
  avoidPatterns: z.ZodArray<z.ZodString>;
459
491
  }, z.core.$loose>;
460
492
  }, z.core.$loose>>>;
493
+ listUpdates: z.ZodOptional<z.ZodArray<z.ZodObject<{
494
+ prUrl: z.ZodString;
495
+ issueUrl: z.ZodString;
496
+ listPath: z.ZodString;
497
+ repoHeadingStruck: z.ZodBoolean;
498
+ }, z.core.$strip>>>;
461
499
  }, z.core.$strip>;
462
500
  export declare const CompactDailyOutputSchema: z.ZodObject<{
463
501
  digest: z.ZodObject<{
@@ -549,7 +587,7 @@ export declare const CompactDailyOutputSchema: z.ZodObject<{
549
587
  fetch: "fetch";
550
588
  "repo-scores": "repo-scores";
551
589
  analytics: "analytics";
552
- "scout-sync": "scout-sync";
590
+ "merge-loop": "merge-loop";
553
591
  partition: "partition";
554
592
  "dismiss-filter": "dismiss-filter";
555
593
  "gist-init": "gist-init";
@@ -606,6 +644,12 @@ export declare const CompactDailyOutputSchema: z.ZodObject<{
606
644
  avoidPatterns: z.ZodArray<z.ZodString>;
607
645
  }, z.core.$loose>;
608
646
  }, z.core.$loose>>>;
647
+ listUpdates: z.ZodOptional<z.ZodArray<z.ZodObject<{
648
+ prUrl: z.ZodString;
649
+ issueUrl: z.ZodString;
650
+ listPath: z.ZodString;
651
+ repoHeadingStruck: z.ZodBoolean;
652
+ }, z.core.$strip>>>;
609
653
  }, z.core.$strip>;
610
654
  export declare const SearchOutputSchema: z.ZodObject<{
611
655
  candidates: z.ZodArray<z.ZodObject<{
@@ -666,6 +710,7 @@ export declare const SearchOutputSchema: z.ZodObject<{
666
710
  aiPolicyBlocklist: z.ZodArray<z.ZodString>;
667
711
  hiddenOwnPRCount: z.ZodNumber;
668
712
  rateLimitWarning: z.ZodOptional<z.ZodString>;
713
+ skipListUnavailable: z.ZodOptional<z.ZodBoolean>;
669
714
  }, z.core.$strip>;
670
715
  export declare const FeaturesOutputSchema: z.ZodObject<{
671
716
  quickWins: z.ZodArray<z.ZodObject<{
@@ -887,10 +932,12 @@ export declare const ClaimOutputSchema: z.ZodObject<{
887
932
  commentUrl: z.ZodString;
888
933
  issueUrl: z.ZodString;
889
934
  gistSyncWarning: z.ZodOptional<z.ZodString>;
935
+ stateSaveWarning: z.ZodOptional<z.ZodString>;
890
936
  }, z.core.$strip>;
891
937
  export declare const InitOutputSchema: z.ZodObject<{
892
938
  username: z.ZodString;
893
939
  message: z.ZodString;
940
+ gistSyncWarning: z.ZodOptional<z.ZodString>;
894
941
  }, z.core.$strip>;
895
942
  export declare const ManifestOutputSchema: z.ZodObject<{
896
943
  schemaVersion: z.ZodLiteral<1>;
@@ -908,6 +955,7 @@ export declare const SetupOutputSchema: z.ZodUnion<readonly [z.ZodObject<{
908
955
  success: z.ZodLiteral<true>;
909
956
  settings: z.ZodRecord<z.ZodString, z.ZodString>;
910
957
  warnings: z.ZodOptional<z.ZodArray<z.ZodString>>;
958
+ gistSyncWarning: z.ZodOptional<z.ZodString>;
911
959
  }, z.core.$strip>, z.ZodObject<{
912
960
  setupComplete: z.ZodLiteral<true>;
913
961
  config: z.ZodObject<{
@@ -942,6 +990,7 @@ export declare const ConfigCommandOutputSchema: z.ZodUnion<readonly [z.ZodObject
942
990
  success: z.ZodLiteral<true>;
943
991
  key: z.ZodString;
944
992
  value: z.ZodString;
993
+ gistSyncWarning: z.ZodOptional<z.ZodString>;
945
994
  }, z.core.$strip>, z.ZodObject<{
946
995
  keys: z.ZodArray<z.ZodObject<{}, z.core.$loose>>;
947
996
  }, z.core.$strip>]>;
@@ -1004,6 +1053,7 @@ export declare const RepoVetOutputSchema: z.ZodObject<{
1004
1053
  proceed_with_caution: "proceed_with_caution";
1005
1054
  avoid: "avoid";
1006
1055
  }>;
1056
+ historyScore: z.ZodOptional<z.ZodNumber>;
1007
1057
  }, z.core.$strip>;
1008
1058
  /**
1009
1059
  * The CLI wrapper renames the core function's `repo` metadata object to
@@ -1248,6 +1298,12 @@ export interface SearchOutput {
1248
1298
  hiddenOwnPRCount: number;
1249
1299
  /** Present when rate limits affected the search — either low pre-flight quota or mid-search rate limit hits (#100). */
1250
1300
  rateLimitWarning?: string;
1301
+ /**
1302
+ * Set when the configured skipped-issues file exists but could not be read
1303
+ * (#1448). The search ran with an EMPTY skip list, so explicitly-skipped
1304
+ * issues may appear in `candidates`. Absent on success.
1305
+ */
1306
+ skipListUnavailable?: boolean;
1251
1307
  }
1252
1308
  /** Horizon classification stamped on each features-mode candidate. */
1253
1309
  export type FeaturesHorizon = 'quick-win' | 'bigger-bet';
@@ -1285,6 +1341,13 @@ export interface IssueListInfo {
1285
1341
  availableCount: number;
1286
1342
  completedCount: number;
1287
1343
  skippedIssuesPath?: string;
1344
+ /**
1345
+ * Set when the issue list file was detected but could not be read (#1448).
1346
+ * In that case `availableCount`/`completedCount` are 0 because the content
1347
+ * was unreadable, NOT because the list is empty — consumers should not
1348
+ * treat the counts as authoritative. Absent on success.
1349
+ */
1350
+ readError?: string;
1288
1351
  }
1289
1352
  /**
1290
1353
  * Output of the startup command (combines auth, setup, daily, dashboard, issue list).
@@ -1398,6 +1461,11 @@ export interface VetListOutput {
1398
1461
  };
1399
1462
  pruneResult?: {
1400
1463
  removedCount: number;
1464
+ /**
1465
+ * Set when the prune read/write failed (#1448); `removedCount` is 0 in
1466
+ * that case and the list file is unchanged. Absent on a successful prune.
1467
+ */
1468
+ error?: string;
1401
1469
  };
1402
1470
  }
1403
1471
  /** Output of the vet command */
@@ -1500,6 +1568,12 @@ export interface ClaimOutput {
1500
1568
  issueUrl: string;
1501
1569
  /** Set when the post-mutation Gist checkpoint failed; the local mutation succeeded (#1370). */
1502
1570
  gistSyncWarning?: string;
1571
+ /**
1572
+ * Set when the claim comment posted to GitHub but saving the tracked issue
1573
+ * to local state threw (#1448) — the claim is live but UNTRACKED, so daily
1574
+ * runs will not monitor it. Absent on success.
1575
+ */
1576
+ stateSaveWarning?: string;
1503
1577
  }
1504
1578
  /** Info about a local git clone (#84) */
1505
1579
  export interface LocalRepoInfo {
@@ -42,6 +42,7 @@ export function toCompactDailyOutput(output) {
42
42
  failureCount: output.failures.length,
43
43
  warnings: output.warnings,
44
44
  strategySummary: output.strategySummary,
45
+ listUpdates: output.listUpdates,
45
46
  };
46
47
  }
47
48
  /**
@@ -96,7 +97,7 @@ const DailyWarningPhaseSchema = z.enum([
96
97
  'fetch',
97
98
  'repo-scores',
98
99
  'analytics',
99
- 'scout-sync',
100
+ 'merge-loop',
100
101
  'partition',
101
102
  'dismiss-filter',
102
103
  'gist-init',
@@ -292,6 +293,13 @@ export const AttentionSummarySchema = z.object({
292
293
  dormantFollowup: z.number().int().nonnegative(),
293
294
  waiting: z.number().int().nonnegative(),
294
295
  });
296
+ /** Mirrors {@link MergedPRListUpdate} (#1463). */
297
+ const MergedPRListUpdateSchema = z.object({
298
+ prUrl: z.string(),
299
+ issueUrl: z.string(),
300
+ listPath: z.string(),
301
+ repoHeadingStruck: z.boolean(),
302
+ });
295
303
  export const DailyOutputSchema = z.object({
296
304
  digest: DailyDigestCompactSchema,
297
305
  capacity: CapacityAssessmentSchema,
@@ -305,6 +313,7 @@ export const DailyOutputSchema = z.object({
305
313
  failures: z.array(PRCheckFailurePassthroughSchema),
306
314
  warnings: z.array(DailyWarningSchema),
307
315
  strategySummary: StrategyResultSchema.nullable().optional(),
316
+ listUpdates: z.array(MergedPRListUpdateSchema).optional(),
308
317
  });
309
318
  export const CompactDailyOutputSchema = z.object({
310
319
  digest: DailyDigestCompactSchema,
@@ -317,6 +326,7 @@ export const CompactDailyOutputSchema = z.object({
317
326
  failureCount: z.number().int().nonnegative(),
318
327
  warnings: z.array(DailyWarningSchema),
319
328
  strategySummary: StrategyResultSchema.nullable().optional(),
329
+ listUpdates: z.array(MergedPRListUpdateSchema).optional(),
320
330
  });
321
331
  // ── Search output schema (#1147) ─────────────────────────────────────
322
332
  const SearchPrioritySchema = z.enum(['merged_pr', 'preferred_org', 'starred', 'normal']);
@@ -377,6 +387,9 @@ export const SearchOutputSchema = z.object({
377
387
  aiPolicyBlocklist: z.array(z.string()),
378
388
  hiddenOwnPRCount: z.number().int().nonnegative(),
379
389
  rateLimitWarning: z.string().optional(),
390
+ // Skip file unreadable — search ran with an empty skip list (#1448).
391
+ // Optional: absent on clean runs.
392
+ skipListUnavailable: z.boolean().optional(),
380
393
  });
381
394
  // ── Features output schema (scout 0.9.0 #97/#98/#99) ─────────────────
382
395
  //
@@ -482,10 +495,15 @@ export const ClaimOutputSchema = z.object({
482
495
  issueUrl: z.string(),
483
496
  // Post-mutation Gist checkpoint failure (#1370). Optional: absent on clean runs.
484
497
  gistSyncWarning: z.string().optional(),
498
+ // Claim comment posted but local state save threw — claim is live but
499
+ // untracked (#1448). Optional: absent on clean runs.
500
+ stateSaveWarning: z.string().optional(),
485
501
  });
486
502
  export const InitOutputSchema = z.object({
487
503
  username: z.string(),
488
504
  message: z.string(),
505
+ // Post-mutation Gist checkpoint failure (#1440). Optional: absent on clean runs.
506
+ gistSyncWarning: z.string().optional(),
489
507
  });
490
508
  // ── #1190: plugin → CLI contract ─────────────────────────────────────
491
509
  //
@@ -508,6 +526,8 @@ const SetupSetOutputSchema = z.object({
508
526
  success: z.literal(true),
509
527
  settings: z.record(z.string(), z.string()),
510
528
  warnings: z.array(z.string()).optional(),
529
+ // Post-mutation Gist checkpoint failure (#1440). Optional: absent on clean runs.
530
+ gistSyncWarning: z.string().optional(),
511
531
  });
512
532
  const SetupCompleteOutputSchema = z.object({
513
533
  setupComplete: z.literal(true),
@@ -544,6 +564,8 @@ const ConfigSetOutputSchema = z.object({
544
564
  success: z.literal(true),
545
565
  key: z.string(),
546
566
  value: z.string(),
567
+ // Post-mutation Gist checkpoint failure (#1440). Optional: absent on clean runs.
568
+ gistSyncWarning: z.string().optional(),
547
569
  });
548
570
  const ConfigListKeysOutputSchema = z.object({
549
571
  keys: z.array(ConfigKeyDefSchema),
@@ -626,6 +648,21 @@ export const RepoVetOutputSchema = z.object({
626
648
  }),
627
649
  rubricScore: z.number(),
628
650
  rubricVerdict: z.enum(['recommended', 'proceed_with_caution', 'avoid']),
651
+ /**
652
+ * Score components (#1465): two distinct 1–10 numbers share this envelope.
653
+ * `rubricScore` above is the fresh HEALTH score (the repo's current public
654
+ * signals, weighted per docs/repo-scores.md §Health score — the name
655
+ * predates the split and is kept for back-compat). `historyScore` is the
656
+ * cached HISTORY score: the user's own merge outcomes in this repo, from
657
+ * `state.repoScores` (repo-score-manager.ts). Absent when the user has no
658
+ * cached score for the repo. They diverge whenever repo health changed
659
+ * since the user's last merge there — consumers must never present one as
660
+ * the other. Deliberately unbounded like the persisted RepoScore.score
661
+ * source (state-schema validates plain z.number(); v1-era state was
662
+ * migrated verbatim) — bounds here would turn a legacy out-of-range
663
+ * stored score into a hard --json contract throw (#1465 review).
664
+ */
665
+ historyScore: z.number().optional(),
629
666
  });
630
667
  const ComplianceCheckSchema = z.object({
631
668
  status: z.enum(['pass', 'warn', 'fail']),
@@ -730,6 +767,22 @@ export function toCompactStartupOutput(output) {
730
767
  issueList: output.issueList,
731
768
  };
732
769
  }
770
+ /**
771
+ * True when the command's own payload already reports gist-init degradation
772
+ * as a structured `warnings[{phase:'gist-init'}]` entry (#1444). The same
773
+ * condition used to be double-reported in a single `daily --json` payload —
774
+ * `envelope.gistInitWarning` AND `data.warnings` carried it in two prose
775
+ * variants — so the envelope suppresses its duplicate when the structured
776
+ * entry is present. Keyed on the warning's phase (not its prose) so the two
777
+ * surfaces cannot drift apart again.
778
+ */
779
+ function dataCarriesGistInitWarning(data) {
780
+ if (data === null || typeof data !== 'object')
781
+ return false;
782
+ const warnings = data.warnings;
783
+ return (Array.isArray(warnings) &&
784
+ warnings.some((w) => w !== null && typeof w === 'object' && w.phase === 'gist-init'));
785
+ }
733
786
  /**
734
787
  * Wrap data in a standard JSON output envelope
735
788
  */
@@ -738,7 +791,7 @@ export function jsonSuccess(data) {
738
791
  success: true,
739
792
  data,
740
793
  timestamp: new Date().toISOString(),
741
- ...(envelopeGistWarning ? { gistInitWarning: envelopeGistWarning } : {}),
794
+ ...(envelopeGistWarning && !dataCarriesGistInitWarning(data) ? { gistInitWarning: envelopeGistWarning } : {}),
742
795
  };
743
796
  }
744
797
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oss-autopilot/core",
3
- "version": "3.13.4",
3
+ "version": "3.14.0",
4
4
  "description": "CLI and core library for managing open source contributions",
5
5
  "type": "module",
6
6
  "bin": {
@@ -61,7 +61,7 @@
61
61
  "devDependencies": {
62
62
  "@types/node": "^25.9.3",
63
63
  "@vitest/coverage-v8": "^4.1.8",
64
- "esbuild": "^0.28.0",
64
+ "esbuild": "^0.28.1",
65
65
  "tsx": "^4.22.4",
66
66
  "typedoc": "^0.28.19",
67
67
  "typescript": "^5.9.3",
@@ -1,45 +0,0 @@
1
- /**
2
- * Shelve/Unshelve commands
3
- * Manages shelving PRs to exclude them from capacity and actionable issues.
4
- * Shelved PRs are auto-unshelved when a maintainer engages.
5
- *
6
- * Note: The CLI and MCP shelve/unshelve commands delegate to runMove(),
7
- * which also clears status overrides. These functions match that behavior
8
- * to keep the library API consistent.
9
- */
10
- import { PR_URL_PATTERN } from './validation.js';
11
- export interface ShelveOutput {
12
- shelved: boolean;
13
- url: string;
14
- /** Set when the post-mutation Gist checkpoint failed; the local mutation succeeded (#1370). */
15
- gistSyncWarning?: string;
16
- }
17
- export interface UnshelveOutput {
18
- unshelved: boolean;
19
- url: string;
20
- /** Set when the post-mutation Gist checkpoint failed; the local mutation succeeded (#1370). */
21
- gistSyncWarning?: string;
22
- }
23
- export { PR_URL_PATTERN };
24
- /**
25
- * Shelve a PR, hiding it from daily digest and capacity calculations.
26
- *
27
- * @param options - Shelve options
28
- * @param options.prUrl - Full GitHub PR URL
29
- * @returns Whether the PR was newly shelved (false if already shelved)
30
- * @throws {ValidationError} If the URL is not a valid GitHub PR URL
31
- */
32
- export declare function runShelve(options: {
33
- prUrl: string;
34
- }): Promise<ShelveOutput>;
35
- /**
36
- * Unshelve a PR, restoring it to the daily digest.
37
- *
38
- * @param options - Unshelve options
39
- * @param options.prUrl - Full GitHub PR URL
40
- * @returns Whether the PR was removed from the shelf (false if not shelved)
41
- * @throws {ValidationError} If the URL is not a valid GitHub PR URL
42
- */
43
- export declare function runUnshelve(options: {
44
- prUrl: string;
45
- }): Promise<UnshelveOutput>;
@@ -1,54 +0,0 @@
1
- /**
2
- * Shelve/Unshelve commands
3
- * Manages shelving PRs to exclude them from capacity and actionable issues.
4
- * Shelved PRs are auto-unshelved when a maintainer engages.
5
- *
6
- * Note: The CLI and MCP shelve/unshelve commands delegate to runMove(),
7
- * which also clears status overrides. These functions match that behavior
8
- * to keep the library API consistent.
9
- */
10
- import { getStateManager, maybeCheckpoint } from '../core/index.js';
11
- import { PR_URL_PATTERN, validateGitHubUrl, validateUrl } from './validation.js';
12
- const MODULE = 'shelve';
13
- // Re-export for backward compatibility with tests
14
- export { PR_URL_PATTERN };
15
- /**
16
- * Shelve a PR, hiding it from daily digest and capacity calculations.
17
- *
18
- * @param options - Shelve options
19
- * @param options.prUrl - Full GitHub PR URL
20
- * @returns Whether the PR was newly shelved (false if already shelved)
21
- * @throws {ValidationError} If the URL is not a valid GitHub PR URL
22
- */
23
- export async function runShelve(options) {
24
- validateUrl(options.prUrl);
25
- validateGitHubUrl(options.prUrl, PR_URL_PATTERN, 'PR');
26
- const stateManager = getStateManager();
27
- let added = false;
28
- stateManager.batch(() => {
29
- added = stateManager.shelvePR(options.prUrl);
30
- stateManager.clearStatusOverride(options.prUrl);
31
- });
32
- const gistSyncWarning = await maybeCheckpoint(stateManager, MODULE);
33
- return { shelved: added, url: options.prUrl, ...(gistSyncWarning ? { gistSyncWarning } : {}) };
34
- }
35
- /**
36
- * Unshelve a PR, restoring it to the daily digest.
37
- *
38
- * @param options - Unshelve options
39
- * @param options.prUrl - Full GitHub PR URL
40
- * @returns Whether the PR was removed from the shelf (false if not shelved)
41
- * @throws {ValidationError} If the URL is not a valid GitHub PR URL
42
- */
43
- export async function runUnshelve(options) {
44
- validateUrl(options.prUrl);
45
- validateGitHubUrl(options.prUrl, PR_URL_PATTERN, 'PR');
46
- const stateManager = getStateManager();
47
- let removed = false;
48
- stateManager.batch(() => {
49
- removed = stateManager.unshelvePR(options.prUrl);
50
- stateManager.clearStatusOverride(options.prUrl);
51
- });
52
- const gistSyncWarning = await maybeCheckpoint(stateManager, MODULE);
53
- return { unshelved: removed, url: options.prUrl, ...(gistSyncWarning ? { gistSyncWarning } : {}) };
54
- }