@oss-autopilot/core 3.13.3 → 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 +17 -3
  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 +155 -222
  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 +89 -6
  82. package/dist/formatters/json.js +65 -1
  83. package/package.json +2 -2
  84. package/dist/commands/shelve.d.ts +0 -45
  85. package/dist/commands/shelve.js +0 -54
@@ -16,7 +16,22 @@ export interface JsonOutput<T = unknown> {
16
16
  error?: string;
17
17
  errorCode?: ErrorCode;
18
18
  timestamp: string;
19
+ /** Present when the process is gist-configured but running local-only
20
+ * (#1433): machine consumers of mutating --json commands must see that
21
+ * the mutation will not sync. Set once per process from the CLI bootstrap
22
+ * via {@link setEnvelopeGistWarning}; envelope-level (not data-level) so
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. */
30
+ gistInitWarning?: string;
19
31
  }
32
+ /** Set (or clear) the gist degradation warning carried by every subsequent
33
+ * JSON envelope. Exported for the CLI bootstrap and for test isolation. */
34
+ export declare function setEnvelopeGistWarning(warning: string | null): void;
20
35
  /**
21
36
  * Deduplicated daily digest for JSON output (#287).
22
37
  *
@@ -51,12 +66,12 @@ export interface CompactRepoGroup {
51
66
  * See `DailyWarning` and issue #1042 for the rationale — keeping this a
52
67
  * fixed union so downstream consumers can switch on it without drift.
53
68
  */
54
- 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';
55
70
  /**
56
71
  * A single non-fatal failure surfaced from the `daily` pipeline. Unlike
57
72
  * `PRCheckFailure` (which is scoped to per-PR fetch errors), this covers
58
73
  * ancillary fetches that previously demoted to a log-only `warn()` — repo
59
- * metadata, monthly analytics, scout sync, Gist checkpoint, etc.
74
+ * metadata, monthly analytics, Gist checkpoint, etc.
60
75
  *
61
76
  * `timestamp` and `details` are optional structured extensions added in
62
77
  * #1193 so staleness warnings can carry `lastSuccessfulRefresh` /
@@ -82,6 +97,23 @@ export interface StalenessLike {
82
97
  detectedAt: string;
83
98
  }
84
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
+ }
85
117
  export interface DailyOutput {
86
118
  digest: DailyDigestCompact;
87
119
  capacity: CapacityAssessment;
@@ -96,7 +128,7 @@ export interface DailyOutput {
96
128
  failures: PRCheckFailure[];
97
129
  /**
98
130
  * Non-fatal warnings from ancillary pipeline phases (repo metadata,
99
- * analytics, scout sync, Gist checkpoint, etc.). Always an array — empty
131
+ * analytics, Gist checkpoint, etc.). Always an array — empty
100
132
  * on clean runs. See #1042.
101
133
  */
102
134
  warnings: DailyWarning[];
@@ -107,6 +139,13 @@ export interface DailyOutput {
107
139
  * absent or null on runs where the gate stays silent.
108
140
  */
109
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[];
110
149
  }
111
150
  /**
112
151
  * Compact version of DailyOutput for reduced JSON payload size (#763).
@@ -136,6 +175,8 @@ export interface CompactDailyOutput {
136
175
  warnings: DailyWarning[];
137
176
  /** Periodic strategy snapshot, threaded through compact mode for parity. See {@link DailyOutput.strategySummary}. */
138
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[];
139
180
  }
140
181
  /**
141
182
  * Strip a full DailyOutput down to the compact subset (#763).
@@ -176,7 +217,7 @@ export declare const StatusOutputSchema: z.ZodObject<{
176
217
  fetch: "fetch";
177
218
  "repo-scores": "repo-scores";
178
219
  analytics: "analytics";
179
- "scout-sync": "scout-sync";
220
+ "merge-loop": "merge-loop";
180
221
  partition: "partition";
181
222
  "dismiss-filter": "dismiss-filter";
182
223
  "gist-init": "gist-init";
@@ -392,7 +433,7 @@ export declare const DailyOutputSchema: z.ZodObject<{
392
433
  fetch: "fetch";
393
434
  "repo-scores": "repo-scores";
394
435
  analytics: "analytics";
395
- "scout-sync": "scout-sync";
436
+ "merge-loop": "merge-loop";
396
437
  partition: "partition";
397
438
  "dismiss-filter": "dismiss-filter";
398
439
  "gist-init": "gist-init";
@@ -449,6 +490,12 @@ export declare const DailyOutputSchema: z.ZodObject<{
449
490
  avoidPatterns: z.ZodArray<z.ZodString>;
450
491
  }, z.core.$loose>;
451
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>>>;
452
499
  }, z.core.$strip>;
453
500
  export declare const CompactDailyOutputSchema: z.ZodObject<{
454
501
  digest: z.ZodObject<{
@@ -540,7 +587,7 @@ export declare const CompactDailyOutputSchema: z.ZodObject<{
540
587
  fetch: "fetch";
541
588
  "repo-scores": "repo-scores";
542
589
  analytics: "analytics";
543
- "scout-sync": "scout-sync";
590
+ "merge-loop": "merge-loop";
544
591
  partition: "partition";
545
592
  "dismiss-filter": "dismiss-filter";
546
593
  "gist-init": "gist-init";
@@ -597,6 +644,12 @@ export declare const CompactDailyOutputSchema: z.ZodObject<{
597
644
  avoidPatterns: z.ZodArray<z.ZodString>;
598
645
  }, z.core.$loose>;
599
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>>>;
600
653
  }, z.core.$strip>;
601
654
  export declare const SearchOutputSchema: z.ZodObject<{
602
655
  candidates: z.ZodArray<z.ZodObject<{
@@ -657,6 +710,7 @@ export declare const SearchOutputSchema: z.ZodObject<{
657
710
  aiPolicyBlocklist: z.ZodArray<z.ZodString>;
658
711
  hiddenOwnPRCount: z.ZodNumber;
659
712
  rateLimitWarning: z.ZodOptional<z.ZodString>;
713
+ skipListUnavailable: z.ZodOptional<z.ZodBoolean>;
660
714
  }, z.core.$strip>;
661
715
  export declare const FeaturesOutputSchema: z.ZodObject<{
662
716
  quickWins: z.ZodArray<z.ZodObject<{
@@ -878,10 +932,12 @@ export declare const ClaimOutputSchema: z.ZodObject<{
878
932
  commentUrl: z.ZodString;
879
933
  issueUrl: z.ZodString;
880
934
  gistSyncWarning: z.ZodOptional<z.ZodString>;
935
+ stateSaveWarning: z.ZodOptional<z.ZodString>;
881
936
  }, z.core.$strip>;
882
937
  export declare const InitOutputSchema: z.ZodObject<{
883
938
  username: z.ZodString;
884
939
  message: z.ZodString;
940
+ gistSyncWarning: z.ZodOptional<z.ZodString>;
885
941
  }, z.core.$strip>;
886
942
  export declare const ManifestOutputSchema: z.ZodObject<{
887
943
  schemaVersion: z.ZodLiteral<1>;
@@ -899,6 +955,7 @@ export declare const SetupOutputSchema: z.ZodUnion<readonly [z.ZodObject<{
899
955
  success: z.ZodLiteral<true>;
900
956
  settings: z.ZodRecord<z.ZodString, z.ZodString>;
901
957
  warnings: z.ZodOptional<z.ZodArray<z.ZodString>>;
958
+ gistSyncWarning: z.ZodOptional<z.ZodString>;
902
959
  }, z.core.$strip>, z.ZodObject<{
903
960
  setupComplete: z.ZodLiteral<true>;
904
961
  config: z.ZodObject<{
@@ -933,6 +990,7 @@ export declare const ConfigCommandOutputSchema: z.ZodUnion<readonly [z.ZodObject
933
990
  success: z.ZodLiteral<true>;
934
991
  key: z.ZodString;
935
992
  value: z.ZodString;
993
+ gistSyncWarning: z.ZodOptional<z.ZodString>;
936
994
  }, z.core.$strip>, z.ZodObject<{
937
995
  keys: z.ZodArray<z.ZodObject<{}, z.core.$loose>>;
938
996
  }, z.core.$strip>]>;
@@ -995,6 +1053,7 @@ export declare const RepoVetOutputSchema: z.ZodObject<{
995
1053
  proceed_with_caution: "proceed_with_caution";
996
1054
  avoid: "avoid";
997
1055
  }>;
1056
+ historyScore: z.ZodOptional<z.ZodNumber>;
998
1057
  }, z.core.$strip>;
999
1058
  /**
1000
1059
  * The CLI wrapper renames the core function's `repo` metadata object to
@@ -1239,6 +1298,12 @@ export interface SearchOutput {
1239
1298
  hiddenOwnPRCount: number;
1240
1299
  /** Present when rate limits affected the search — either low pre-flight quota or mid-search rate limit hits (#100). */
1241
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;
1242
1307
  }
1243
1308
  /** Horizon classification stamped on each features-mode candidate. */
1244
1309
  export type FeaturesHorizon = 'quick-win' | 'bigger-bet';
@@ -1276,6 +1341,13 @@ export interface IssueListInfo {
1276
1341
  availableCount: number;
1277
1342
  completedCount: number;
1278
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;
1279
1351
  }
1280
1352
  /**
1281
1353
  * Output of the startup command (combines auth, setup, daily, dashboard, issue list).
@@ -1389,6 +1461,11 @@ export interface VetListOutput {
1389
1461
  };
1390
1462
  pruneResult?: {
1391
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;
1392
1469
  };
1393
1470
  }
1394
1471
  /** Output of the vet command */
@@ -1491,6 +1568,12 @@ export interface ClaimOutput {
1491
1568
  issueUrl: string;
1492
1569
  /** Set when the post-mutation Gist checkpoint failed; the local mutation succeeded (#1370). */
1493
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;
1494
1577
  }
1495
1578
  /** Info about a local git clone (#84) */
1496
1579
  export interface LocalRepoInfo {
@@ -4,6 +4,15 @@
4
4
  */
5
5
  import { z } from 'zod';
6
6
  import { fenceFetchedPR } from '../core/untrusted-content.js';
7
+ // Process-level gist degradation warning threaded into every JSON envelope
8
+ // (#1433). The CLI preAction bootstrap sets it; one-shot processes never
9
+ // clear it (the whole invocation runs degraded or it doesn't).
10
+ let envelopeGistWarning = null;
11
+ /** Set (or clear) the gist degradation warning carried by every subsequent
12
+ * JSON envelope. Exported for the CLI bootstrap and for test isolation. */
13
+ export function setEnvelopeGistWarning(warning) {
14
+ envelopeGistWarning = warning;
15
+ }
7
16
  export function buildStalenessWarning(info) {
8
17
  return {
9
18
  phase: 'gist-staleness',
@@ -33,6 +42,7 @@ export function toCompactDailyOutput(output) {
33
42
  failureCount: output.failures.length,
34
43
  warnings: output.warnings,
35
44
  strategySummary: output.strategySummary,
45
+ listUpdates: output.listUpdates,
36
46
  };
37
47
  }
38
48
  /**
@@ -87,7 +97,7 @@ const DailyWarningPhaseSchema = z.enum([
87
97
  'fetch',
88
98
  'repo-scores',
89
99
  'analytics',
90
- 'scout-sync',
100
+ 'merge-loop',
91
101
  'partition',
92
102
  'dismiss-filter',
93
103
  'gist-init',
@@ -283,6 +293,13 @@ export const AttentionSummarySchema = z.object({
283
293
  dormantFollowup: z.number().int().nonnegative(),
284
294
  waiting: z.number().int().nonnegative(),
285
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
+ });
286
303
  export const DailyOutputSchema = z.object({
287
304
  digest: DailyDigestCompactSchema,
288
305
  capacity: CapacityAssessmentSchema,
@@ -296,6 +313,7 @@ export const DailyOutputSchema = z.object({
296
313
  failures: z.array(PRCheckFailurePassthroughSchema),
297
314
  warnings: z.array(DailyWarningSchema),
298
315
  strategySummary: StrategyResultSchema.nullable().optional(),
316
+ listUpdates: z.array(MergedPRListUpdateSchema).optional(),
299
317
  });
300
318
  export const CompactDailyOutputSchema = z.object({
301
319
  digest: DailyDigestCompactSchema,
@@ -308,6 +326,7 @@ export const CompactDailyOutputSchema = z.object({
308
326
  failureCount: z.number().int().nonnegative(),
309
327
  warnings: z.array(DailyWarningSchema),
310
328
  strategySummary: StrategyResultSchema.nullable().optional(),
329
+ listUpdates: z.array(MergedPRListUpdateSchema).optional(),
311
330
  });
312
331
  // ── Search output schema (#1147) ─────────────────────────────────────
313
332
  const SearchPrioritySchema = z.enum(['merged_pr', 'preferred_org', 'starred', 'normal']);
@@ -368,6 +387,9 @@ export const SearchOutputSchema = z.object({
368
387
  aiPolicyBlocklist: z.array(z.string()),
369
388
  hiddenOwnPRCount: z.number().int().nonnegative(),
370
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(),
371
393
  });
372
394
  // ── Features output schema (scout 0.9.0 #97/#98/#99) ─────────────────
373
395
  //
@@ -473,10 +495,15 @@ export const ClaimOutputSchema = z.object({
473
495
  issueUrl: z.string(),
474
496
  // Post-mutation Gist checkpoint failure (#1370). Optional: absent on clean runs.
475
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(),
476
501
  });
477
502
  export const InitOutputSchema = z.object({
478
503
  username: z.string(),
479
504
  message: z.string(),
505
+ // Post-mutation Gist checkpoint failure (#1440). Optional: absent on clean runs.
506
+ gistSyncWarning: z.string().optional(),
480
507
  });
481
508
  // ── #1190: plugin → CLI contract ─────────────────────────────────────
482
509
  //
@@ -499,6 +526,8 @@ const SetupSetOutputSchema = z.object({
499
526
  success: z.literal(true),
500
527
  settings: z.record(z.string(), z.string()),
501
528
  warnings: z.array(z.string()).optional(),
529
+ // Post-mutation Gist checkpoint failure (#1440). Optional: absent on clean runs.
530
+ gistSyncWarning: z.string().optional(),
502
531
  });
503
532
  const SetupCompleteOutputSchema = z.object({
504
533
  setupComplete: z.literal(true),
@@ -535,6 +564,8 @@ const ConfigSetOutputSchema = z.object({
535
564
  success: z.literal(true),
536
565
  key: z.string(),
537
566
  value: z.string(),
567
+ // Post-mutation Gist checkpoint failure (#1440). Optional: absent on clean runs.
568
+ gistSyncWarning: z.string().optional(),
538
569
  });
539
570
  const ConfigListKeysOutputSchema = z.object({
540
571
  keys: z.array(ConfigKeyDefSchema),
@@ -617,6 +648,21 @@ export const RepoVetOutputSchema = z.object({
617
648
  }),
618
649
  rubricScore: z.number(),
619
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(),
620
666
  });
621
667
  const ComplianceCheckSchema = z.object({
622
668
  status: z.enum(['pass', 'warn', 'fail']),
@@ -721,6 +767,22 @@ export function toCompactStartupOutput(output) {
721
767
  issueList: output.issueList,
722
768
  };
723
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
+ }
724
786
  /**
725
787
  * Wrap data in a standard JSON output envelope
726
788
  */
@@ -729,6 +791,7 @@ export function jsonSuccess(data) {
729
791
  success: true,
730
792
  data,
731
793
  timestamp: new Date().toISOString(),
794
+ ...(envelopeGistWarning && !dataCarriesGistInitWarning(data) ? { gistInitWarning: envelopeGistWarning } : {}),
732
795
  };
733
796
  }
734
797
  /**
@@ -740,6 +803,7 @@ export function jsonError(message, errorCode) {
740
803
  error: message,
741
804
  errorCode,
742
805
  timestamp: new Date().toISOString(),
806
+ ...(envelopeGistWarning ? { gistInitWarning: envelopeGistWarning } : {}),
743
807
  };
744
808
  }
745
809
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oss-autopilot/core",
3
- "version": "3.13.3",
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
- }