@oss-autopilot/core 3.4.1 → 3.6.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 (58) hide show
  1. package/dist/cli-registry.js +99 -0
  2. package/dist/cli.bundle.cjs +112 -105
  3. package/dist/commands/compliance-score.d.ts +21 -0
  4. package/dist/commands/compliance-score.js +156 -0
  5. package/dist/commands/daily.d.ts +8 -0
  6. package/dist/commands/daily.js +21 -0
  7. package/dist/commands/index.d.ts +6 -0
  8. package/dist/commands/index.js +6 -0
  9. package/dist/commands/list-mark-done.d.ts +48 -0
  10. package/dist/commands/list-mark-done.js +213 -0
  11. package/dist/commands/parse-list.js +86 -9
  12. package/dist/commands/repo-vet.d.ts +21 -0
  13. package/dist/commands/repo-vet.js +215 -0
  14. package/dist/commands/startup.js +41 -1
  15. package/dist/core/anti-llm-policy.d.ts +42 -13
  16. package/dist/core/anti-llm-policy.js +102 -13
  17. package/dist/core/ci-analysis.d.ts +32 -1
  18. package/dist/core/ci-analysis.js +92 -0
  19. package/dist/core/ci-enforced-tools.d.ts +35 -0
  20. package/dist/core/ci-enforced-tools.js +109 -0
  21. package/dist/core/comment-decision.d.ts +72 -0
  22. package/dist/core/comment-decision.js +74 -0
  23. package/dist/core/compliance-score.d.ts +127 -0
  24. package/dist/core/compliance-score.js +277 -0
  25. package/dist/core/config-registry.js +12 -0
  26. package/dist/core/contributing.d.ts +52 -0
  27. package/dist/core/contributing.js +139 -0
  28. package/dist/core/errors.d.ts +19 -0
  29. package/dist/core/errors.js +54 -0
  30. package/dist/core/extraction-categories.d.ts +55 -0
  31. package/dist/core/extraction-categories.js +108 -0
  32. package/dist/core/follow-up-history.d.ts +41 -0
  33. package/dist/core/follow-up-history.js +71 -0
  34. package/dist/core/gist-state-store.d.ts +30 -7
  35. package/dist/core/gist-state-store.js +87 -11
  36. package/dist/core/issue-conversation.js +1 -0
  37. package/dist/core/issue-effort.d.ts +29 -0
  38. package/dist/core/issue-effort.js +41 -0
  39. package/dist/core/maintainer-hints.d.ts +23 -0
  40. package/dist/core/maintainer-hints.js +36 -0
  41. package/dist/core/pr-monitor.d.ts +1 -1
  42. package/dist/core/pr-monitor.js +31 -11
  43. package/dist/core/pr-quality-rubric.d.ts +70 -0
  44. package/dist/core/pr-quality-rubric.js +121 -0
  45. package/dist/core/repo-vet.d.ts +90 -0
  46. package/dist/core/repo-vet.js +178 -0
  47. package/dist/core/state-schema.d.ts +77 -0
  48. package/dist/core/state-schema.js +84 -0
  49. package/dist/core/state.d.ts +7 -0
  50. package/dist/core/state.js +10 -0
  51. package/dist/core/strategy.d.ts +95 -0
  52. package/dist/core/strategy.js +270 -0
  53. package/dist/core/types.d.ts +51 -0
  54. package/dist/core/workflow-state.d.ts +56 -0
  55. package/dist/core/workflow-state.js +101 -0
  56. package/dist/formatters/json.d.ts +252 -0
  57. package/dist/formatters/json.js +153 -0
  58. package/package.json +1 -1
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Workflow-state helpers (#1280).
3
+ *
4
+ * Centralizes the read/write logic for `state.workflowState`. Used
5
+ * by `draft-first-workflow.md`, `work-through-issues.md`, and
6
+ * `pre-commit-review.md` to record pause points and offer
7
+ * Resume / Restart / Discard at the next `/oss` invocation.
8
+ *
9
+ * Pure functions — callers manage state I/O. Same architectural
10
+ * shape as the recent #1277 (follow-up-history) helpers.
11
+ */
12
+ /**
13
+ * Snapshot the user's current workflow position. Returns the
14
+ * patched state; callers persist via `StateManager.save()` (or the
15
+ * gist `checkpoint()` path).
16
+ */
17
+ export function recordWorkflowPause(state, next, now = new Date()) {
18
+ const incoming = {
19
+ ...next,
20
+ lastUpdatedAt: now.toISOString(),
21
+ };
22
+ return { ...state, workflowState: incoming };
23
+ }
24
+ /**
25
+ * Read the current workflow snapshot, or null when no pause is
26
+ * recorded.
27
+ */
28
+ export function getWorkflowState(state) {
29
+ return state.workflowState ?? null;
30
+ }
31
+ /**
32
+ * Discard the current pause snapshot. Used by:
33
+ * - the workflow completing normally,
34
+ * - the user picking "Discard and start fresh" at the resume
35
+ * prompt,
36
+ * - any consumer that detects the snapshot has gone stale (branch
37
+ * deleted, repo no longer reachable).
38
+ */
39
+ export function clearWorkflowState(state) {
40
+ if (!state.workflowState)
41
+ return state;
42
+ const { workflowState: _drop, ...rest } = state;
43
+ return rest;
44
+ }
45
+ /**
46
+ * Append a step name to `completedSteps` and update `currentStep`
47
+ * to the supplied next step. Convenience wrapper around the immer-
48
+ * style read/replace pattern. Returns the patched state.
49
+ */
50
+ export function advanceWorkflowStep(state, nextStep, now = new Date()) {
51
+ const ws = state.workflowState;
52
+ if (!ws)
53
+ return state;
54
+ if (ws.currentStep === nextStep)
55
+ return state;
56
+ const completed = [...ws.completedSteps];
57
+ if (!completed.includes(ws.currentStep))
58
+ completed.push(ws.currentStep);
59
+ return {
60
+ ...state,
61
+ workflowState: {
62
+ ...ws,
63
+ currentStep: nextStep,
64
+ completedSteps: completed,
65
+ lastUpdatedAt: now.toISOString(),
66
+ },
67
+ };
68
+ }
69
+ /**
70
+ * Merge per-step data into `stepData` without overwriting other
71
+ * keys. Useful when a workflow's resume needs to restore non-trivial
72
+ * context (skipped compliance items, last review pass count, etc.).
73
+ */
74
+ export function setStepData(state, step, data, now = new Date()) {
75
+ const ws = state.workflowState;
76
+ if (!ws)
77
+ return state;
78
+ return {
79
+ ...state,
80
+ workflowState: {
81
+ ...ws,
82
+ stepData: { ...ws.stepData, [step]: data },
83
+ lastUpdatedAt: now.toISOString(),
84
+ },
85
+ };
86
+ }
87
+ /**
88
+ * Read step data for a specific step, or undefined when none was
89
+ * stored. Callers typically narrow the unknown via a type guard.
90
+ */
91
+ export function getStepData(state, step) {
92
+ return state.workflowState?.stepData[step];
93
+ }
94
+ /**
95
+ * Whether the recorded pause is on the supplied workflow. Useful
96
+ * for the router to decide whether to offer Resume vs ignore the
97
+ * snapshot when the current `/oss` invocation is unrelated.
98
+ */
99
+ export function isPausedIn(state, workflowName) {
100
+ return state.workflowState?.workflowName === workflowName;
101
+ }
@@ -97,6 +97,13 @@ export interface DailyOutput {
97
97
  * on clean runs. See #1042.
98
98
  */
99
99
  warnings: DailyWarning[];
100
+ /**
101
+ * Periodic contribution-strategy snapshot (#1270). Populated when the
102
+ * cadence trigger fires AND the user has crossed the merge floor. The
103
+ * `/oss` action menu renders this inline ahead of the action options;
104
+ * absent or null on runs where the gate stays silent.
105
+ */
106
+ strategySummary?: import('../core/strategy.js').StrategyResult | null;
100
107
  }
101
108
  /**
102
109
  * Compact version of DailyOutput for reduced JSON payload size (#763).
@@ -122,6 +129,8 @@ export interface CompactDailyOutput {
122
129
  * the `--compact` payload. See #1042.
123
130
  */
124
131
  warnings: DailyWarning[];
132
+ /** Periodic strategy snapshot, threaded through compact mode for parity. See {@link DailyOutput.strategySummary}. */
133
+ strategySummary?: import('../core/strategy.js').StrategyResult | null;
125
134
  }
126
135
  /**
127
136
  * Strip a full DailyOutput down to the compact subset (#763).
@@ -275,6 +284,50 @@ export declare const DailyOutputSchema: z.ZodObject<{
275
284
  timestamp: z.ZodOptional<z.ZodString>;
276
285
  details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
277
286
  }, z.core.$strip>>;
287
+ strategySummary: z.ZodOptional<z.ZodNullable<z.ZodObject<{
288
+ profile: z.ZodObject<{
289
+ style: z.ZodEnum<{
290
+ maintainer: "maintainer";
291
+ explorer: "explorer";
292
+ specialist: "specialist";
293
+ generalist: "generalist";
294
+ }>;
295
+ totalPRs: z.ZodNumber;
296
+ mergedCount: z.ZodNumber;
297
+ mergeRate: z.ZodNumber;
298
+ primaryLanguages: z.ZodArray<z.ZodString>;
299
+ favoriteRepos: z.ZodArray<z.ZodString>;
300
+ }, z.core.$loose>;
301
+ capacity: z.ZodObject<{
302
+ openPRCount: z.ZodNumber;
303
+ dormantPRCount: z.ZodNumber;
304
+ dormantRepoCount: z.ZodNumber;
305
+ overExtended: z.ZodBoolean;
306
+ suggestedAction: z.ZodUnion<readonly [z.ZodLiteral<"open_more">, z.ZodLiteral<"follow_up_dormant">, z.ZodLiteral<"wait_on_maintainers">, z.ZodNull]>;
307
+ }, z.core.$loose>;
308
+ patterns: z.ZodObject<{
309
+ prTypeDistribution: z.ZodObject<{
310
+ docs: z.ZodNumber;
311
+ fixes: z.ZodNumber;
312
+ features: z.ZodNumber;
313
+ refactors: z.ZodNumber;
314
+ tests: z.ZodNumber;
315
+ other: z.ZodNumber;
316
+ }, z.core.$loose>;
317
+ trajectoryDirection: z.ZodEnum<{
318
+ growing: "growing";
319
+ steady: "steady";
320
+ declining: "declining";
321
+ }>;
322
+ averagePRSize: z.ZodNumber;
323
+ }, z.core.$loose>;
324
+ recommendations: z.ZodObject<{
325
+ languages: z.ZodArray<z.ZodString>;
326
+ repos: z.ZodArray<z.ZodString>;
327
+ issueTypes: z.ZodArray<z.ZodString>;
328
+ avoidPatterns: z.ZodArray<z.ZodString>;
329
+ }, z.core.$loose>;
330
+ }, z.core.$loose>>>;
278
331
  }, z.core.$strip>;
279
332
  export declare const CompactDailyOutputSchema: z.ZodObject<{
280
333
  digest: z.ZodObject<{
@@ -371,6 +424,50 @@ export declare const CompactDailyOutputSchema: z.ZodObject<{
371
424
  timestamp: z.ZodOptional<z.ZodString>;
372
425
  details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
373
426
  }, z.core.$strip>>;
427
+ strategySummary: z.ZodOptional<z.ZodNullable<z.ZodObject<{
428
+ profile: z.ZodObject<{
429
+ style: z.ZodEnum<{
430
+ maintainer: "maintainer";
431
+ explorer: "explorer";
432
+ specialist: "specialist";
433
+ generalist: "generalist";
434
+ }>;
435
+ totalPRs: z.ZodNumber;
436
+ mergedCount: z.ZodNumber;
437
+ mergeRate: z.ZodNumber;
438
+ primaryLanguages: z.ZodArray<z.ZodString>;
439
+ favoriteRepos: z.ZodArray<z.ZodString>;
440
+ }, z.core.$loose>;
441
+ capacity: z.ZodObject<{
442
+ openPRCount: z.ZodNumber;
443
+ dormantPRCount: z.ZodNumber;
444
+ dormantRepoCount: z.ZodNumber;
445
+ overExtended: z.ZodBoolean;
446
+ suggestedAction: z.ZodUnion<readonly [z.ZodLiteral<"open_more">, z.ZodLiteral<"follow_up_dormant">, z.ZodLiteral<"wait_on_maintainers">, z.ZodNull]>;
447
+ }, z.core.$loose>;
448
+ patterns: z.ZodObject<{
449
+ prTypeDistribution: z.ZodObject<{
450
+ docs: z.ZodNumber;
451
+ fixes: z.ZodNumber;
452
+ features: z.ZodNumber;
453
+ refactors: z.ZodNumber;
454
+ tests: z.ZodNumber;
455
+ other: z.ZodNumber;
456
+ }, z.core.$loose>;
457
+ trajectoryDirection: z.ZodEnum<{
458
+ growing: "growing";
459
+ steady: "steady";
460
+ declining: "declining";
461
+ }>;
462
+ averagePRSize: z.ZodNumber;
463
+ }, z.core.$loose>;
464
+ recommendations: z.ZodObject<{
465
+ languages: z.ZodArray<z.ZodString>;
466
+ repos: z.ZodArray<z.ZodString>;
467
+ issueTypes: z.ZodArray<z.ZodString>;
468
+ avoidPatterns: z.ZodArray<z.ZodString>;
469
+ }, z.core.$loose>;
470
+ }, z.core.$loose>>>;
374
471
  }, z.core.$strip>;
375
472
  export declare const SearchOutputSchema: z.ZodObject<{
376
473
  candidates: z.ZodArray<z.ZodObject<{
@@ -454,6 +551,14 @@ export declare const ListMoveTierOutputSchema: z.ZodObject<{
454
551
  count: z.ZodNumber;
455
552
  reason: z.ZodOptional<z.ZodString>;
456
553
  }, z.core.$strip>;
554
+ export declare const ListMarkDoneOutputSchema: z.ZodObject<{
555
+ marked: z.ZodBoolean;
556
+ filePath: z.ZodString;
557
+ url: z.ZodString;
558
+ repoHeadingStruck: z.ZodBoolean;
559
+ remainingUnderRepo: z.ZodNumber;
560
+ reason: z.ZodOptional<z.ZodString>;
561
+ }, z.core.$strip>;
457
562
  export declare const PostOutputSchema: z.ZodObject<{
458
563
  commentUrl: z.ZodString;
459
564
  url: z.ZodString;
@@ -534,6 +639,134 @@ export declare const PRTemplateOutputSchema: z.ZodObject<{
534
639
  source: z.ZodNullable<z.ZodString>;
535
640
  error: z.ZodOptional<z.ZodString>;
536
641
  }, z.core.$strip>;
642
+ export declare const RepoVetOutputSchema: z.ZodObject<{
643
+ repoSlug: z.ZodString;
644
+ fetchedAt: z.ZodString;
645
+ repoMeta: z.ZodObject<{
646
+ stars: z.ZodNumber;
647
+ forks: z.ZodNumber;
648
+ openIssues: z.ZodNumber;
649
+ watchers: z.ZodNumber;
650
+ isArchived: z.ZodBoolean;
651
+ lastPushed: z.ZodString;
652
+ createdAt: z.ZodString;
653
+ }, z.core.$strip>;
654
+ prMergeTime: z.ZodObject<{
655
+ avgDays: z.ZodNullable<z.ZodNumber>;
656
+ medianDays: z.ZodNullable<z.ZodNumber>;
657
+ sampleSize: z.ZodNumber;
658
+ sourceWindowDays: z.ZodLiteral<90>;
659
+ }, z.core.$strip>;
660
+ mergeRate: z.ZodObject<{
661
+ merged: z.ZodNumber;
662
+ opened: z.ZodNumber;
663
+ percent: z.ZodNullable<z.ZodNumber>;
664
+ windowDays: z.ZodLiteral<90>;
665
+ }, z.core.$strip>;
666
+ maintainerActivity: z.ZodObject<{
667
+ lastCommitISO: z.ZodNullable<z.ZodString>;
668
+ contributorsLast90d: z.ZodNumber;
669
+ lastReleaseISO: z.ZodNullable<z.ZodString>;
670
+ }, z.core.$strip>;
671
+ communityHealth: z.ZodObject<{
672
+ contributing: z.ZodBoolean;
673
+ issueTemplates: z.ZodBoolean;
674
+ prTemplate: z.ZodBoolean;
675
+ codeOfConduct: z.ZodBoolean;
676
+ incomplete: z.ZodOptional<z.ZodBoolean>;
677
+ }, z.core.$strip>;
678
+ rubricScore: z.ZodNumber;
679
+ rubricVerdict: z.ZodEnum<{
680
+ recommended: "recommended";
681
+ proceed_with_caution: "proceed_with_caution";
682
+ avoid: "avoid";
683
+ }>;
684
+ }, z.core.$strip>;
685
+ /**
686
+ * The CLI wrapper renames the core function's `repo` metadata object to
687
+ * `repoMeta` so the top-level slug doesn't collide with it. The TS type
688
+ * is derived from the Zod schema so any drift between schema and type
689
+ * fails at compile time.
690
+ */
691
+ export type RepoVetOutput = z.infer<typeof RepoVetOutputSchema>;
692
+ export declare const ComplianceScoreOutputSchema: z.ZodObject<{
693
+ pr: z.ZodObject<{
694
+ repo: z.ZodString;
695
+ number: z.ZodNumber;
696
+ title: z.ZodString;
697
+ url: z.ZodString;
698
+ }, z.core.$strip>;
699
+ score: z.ZodNumber;
700
+ rating: z.ZodEnum<{
701
+ ready: "ready";
702
+ minor: "minor";
703
+ fix_first: "fix_first";
704
+ significant_work: "significant_work";
705
+ }>;
706
+ emoji: z.ZodEnum<{
707
+ "\uD83C\uDF1F": "🌟";
708
+ "\u2705": "✅";
709
+ "\u26A0\uFE0F": "⚠️";
710
+ "\u274C": "❌";
711
+ }>;
712
+ checks: z.ZodObject<{
713
+ issueReference: z.ZodObject<{
714
+ status: z.ZodEnum<{
715
+ fail: "fail";
716
+ pass: "pass";
717
+ warn: "warn";
718
+ }>;
719
+ weight: z.ZodNumber;
720
+ detail: z.ZodString;
721
+ }, z.core.$strip>;
722
+ description: z.ZodObject<{
723
+ status: z.ZodEnum<{
724
+ fail: "fail";
725
+ pass: "pass";
726
+ warn: "warn";
727
+ }>;
728
+ weight: z.ZodNumber;
729
+ detail: z.ZodString;
730
+ }, z.core.$strip>;
731
+ focusedChanges: z.ZodObject<{
732
+ status: z.ZodEnum<{
733
+ fail: "fail";
734
+ pass: "pass";
735
+ warn: "warn";
736
+ }>;
737
+ weight: z.ZodNumber;
738
+ detail: z.ZodString;
739
+ }, z.core.$strip>;
740
+ tests: z.ZodObject<{
741
+ status: z.ZodEnum<{
742
+ fail: "fail";
743
+ pass: "pass";
744
+ warn: "warn";
745
+ }>;
746
+ weight: z.ZodNumber;
747
+ detail: z.ZodString;
748
+ }, z.core.$strip>;
749
+ title: z.ZodObject<{
750
+ status: z.ZodEnum<{
751
+ fail: "fail";
752
+ pass: "pass";
753
+ warn: "warn";
754
+ }>;
755
+ weight: z.ZodNumber;
756
+ detail: z.ZodString;
757
+ }, z.core.$strip>;
758
+ branch: z.ZodObject<{
759
+ status: z.ZodEnum<{
760
+ fail: "fail";
761
+ pass: "pass";
762
+ warn: "warn";
763
+ }>;
764
+ weight: z.ZodNumber;
765
+ detail: z.ZodString;
766
+ }, z.core.$strip>;
767
+ }, z.core.$strip>;
768
+ }, z.core.$strip>;
769
+ export type ComplianceScoreOutput = z.infer<typeof ComplianceScoreOutputSchema>;
537
770
  export declare const ParseIssueListOutputSchema: z.ZodObject<{
538
771
  available: z.ZodArray<z.ZodObject<{
539
772
  repo: z.ZodString;
@@ -696,6 +929,25 @@ export interface StartupOutput {
696
929
  * a structured signal to surface or recover from the failure.
697
930
  */
698
931
  dashboardError?: string;
932
+ /**
933
+ * Status of the dashboard SPA build that ran (or didn't) before this
934
+ * startup invocation (#1293). Populated by the workflow shell via
935
+ * `OSS_DASHBOARD_BUILD_STATUS`; absent when the CLI is invoked outside
936
+ * the plugin workflow:
937
+ * - `'fresh'` — built artifact was up-to-date, no rebuild attempted.
938
+ * - `'rebuilt'` — rebuild ran and succeeded.
939
+ * - `'failed'` — rebuild ran and failed; `dashboardUrl` may serve stale
940
+ * or missing assets until the build is fixed.
941
+ * - `'missing-pnpm'` — rebuild was needed but pnpm (required for the
942
+ * workspace dependency) was unavailable.
943
+ */
944
+ dashboardBuildStatus?: 'fresh' | 'rebuilt' | 'failed' | 'missing-pnpm';
945
+ /**
946
+ * Last few lines of the dashboard build log when `dashboardBuildStatus`
947
+ * is `'failed'` or `'missing-pnpm'`. Surfaced by the workflow as a
948
+ * one-line warning so the user sees what broke without leaving `/oss`.
949
+ */
950
+ dashboardBuildErrorTail?: string;
699
951
  issueList?: IssueListInfo;
700
952
  }
701
953
  /**
@@ -30,6 +30,7 @@ export function toCompactDailyOutput(output) {
30
30
  commentedIssues: output.commentedIssues,
31
31
  failureCount: output.failures.length,
32
32
  warnings: output.warnings,
33
+ strategySummary: output.strategySummary,
33
34
  };
34
35
  }
35
36
  /**
@@ -198,6 +199,65 @@ const CompactRepoGroupSchema = z.object({
198
199
  });
199
200
  // DailyWarning schemas were hoisted above StatusOutputSchema (#1193) so the
200
201
  // status output can reference them without `z.lazy()`.
202
+ // Mirrors {@link StrategyResult} in core/strategy.ts. Kept passthrough on the
203
+ // inner objects so additive shape changes there don't break Zod validation
204
+ // before the schema catches up — drift on required keys still fails.
205
+ const StrategyResultSchema = z
206
+ .object({
207
+ profile: z
208
+ .object({
209
+ style: z.enum(['maintainer', 'explorer', 'specialist', 'generalist']),
210
+ totalPRs: z.number().int().nonnegative(),
211
+ mergedCount: z.number().int().nonnegative(),
212
+ mergeRate: z.number(),
213
+ primaryLanguages: z.array(z.string()),
214
+ favoriteRepos: z.array(z.string()),
215
+ })
216
+ .passthrough(),
217
+ capacity: z
218
+ .object({
219
+ openPRCount: z.number().int().nonnegative(),
220
+ dormantPRCount: z.number().int().nonnegative(),
221
+ dormantRepoCount: z.number().int().nonnegative(),
222
+ overExtended: z.boolean(),
223
+ suggestedAction: z.union([
224
+ z.literal('open_more'),
225
+ z.literal('follow_up_dormant'),
226
+ z.literal('wait_on_maintainers'),
227
+ z.null(),
228
+ ]),
229
+ })
230
+ .passthrough(),
231
+ patterns: z
232
+ .object({
233
+ // Closed set on the six required PR-type buckets — drift on any
234
+ // of these breaks the snapshot rendering. `.passthrough()` allows
235
+ // additive growth (e.g., a future 'security' bucket) without a
236
+ // schema bump, but a typo on `features` → `feauters` fails here.
237
+ prTypeDistribution: z
238
+ .object({
239
+ docs: z.number(),
240
+ fixes: z.number(),
241
+ features: z.number(),
242
+ refactors: z.number(),
243
+ tests: z.number(),
244
+ other: z.number(),
245
+ })
246
+ .passthrough(),
247
+ trajectoryDirection: z.enum(['growing', 'steady', 'declining']),
248
+ averagePRSize: z.number(),
249
+ })
250
+ .passthrough(),
251
+ recommendations: z
252
+ .object({
253
+ languages: z.array(z.string()),
254
+ repos: z.array(z.string()),
255
+ issueTypes: z.array(z.string()),
256
+ avoidPatterns: z.array(z.string()),
257
+ })
258
+ .passthrough(),
259
+ })
260
+ .passthrough();
201
261
  export const DailyOutputSchema = z.object({
202
262
  digest: DailyDigestCompactSchema,
203
263
  capacity: CapacityAssessmentSchema,
@@ -209,6 +269,7 @@ export const DailyOutputSchema = z.object({
209
269
  repoGroups: z.array(CompactRepoGroupSchema),
210
270
  failures: z.array(PRCheckFailurePassthroughSchema),
211
271
  warnings: z.array(DailyWarningSchema),
272
+ strategySummary: StrategyResultSchema.nullable().optional(),
212
273
  });
213
274
  export const CompactDailyOutputSchema = z.object({
214
275
  digest: DailyDigestCompactSchema,
@@ -219,6 +280,7 @@ export const CompactDailyOutputSchema = z.object({
219
280
  commentedIssues: z.array(CommentedIssuePassthroughSchema),
220
281
  failureCount: z.number().int().nonnegative(),
221
282
  warnings: z.array(DailyWarningSchema),
283
+ strategySummary: StrategyResultSchema.nullable().optional(),
222
284
  });
223
285
  // ── Search output schema (#1147) ─────────────────────────────────────
224
286
  const SearchPrioritySchema = z.enum(['merged_pr', 'preferred_org', 'starred', 'normal']);
@@ -287,6 +349,18 @@ export const ListMoveTierOutputSchema = z.object({
287
349
  count: z.number().int().nonnegative(),
288
350
  reason: z.string().optional(),
289
351
  });
352
+ // list-mark-done (#1299): mirrors {@link MarkDoneOutput} from the command
353
+ // module. Strict shape — additional keys must be added here AND in the
354
+ // command output, otherwise the validator's `parse()` rejects the response
355
+ // before it reaches consumers.
356
+ export const ListMarkDoneOutputSchema = z.object({
357
+ marked: z.boolean(),
358
+ filePath: z.string(),
359
+ url: z.string(),
360
+ repoHeadingStruck: z.boolean(),
361
+ remainingUnderRepo: z.number().int().nonnegative(),
362
+ reason: z.string().optional(),
363
+ });
290
364
  // ── #1155: Zod coverage for remaining CLI commands ───────────────────
291
365
  export const PostOutputSchema = z.object({
292
366
  commentUrl: z.string(),
@@ -376,6 +450,85 @@ export const PRTemplateOutputSchema = z.object({
376
450
  source: z.string().nullable(),
377
451
  error: z.string().optional(),
378
452
  });
453
+ /**
454
+ * Output of the `repo-vet` CLI command (#1271, follow-up to #1242).
455
+ *
456
+ * Validates the full nested shape so a refactor that drops or
457
+ * mis-types one of these fields trips `outputJsonValidated` rather
458
+ * than silently shipping a broken envelope (#1245 contract pattern,
459
+ * matching `ComplianceScoreOutputSchema` below).
460
+ */
461
+ const RepoVetMetaSchema = z.object({
462
+ stars: z.number(),
463
+ forks: z.number(),
464
+ openIssues: z.number(),
465
+ watchers: z.number(),
466
+ isArchived: z.boolean(),
467
+ lastPushed: z.string(),
468
+ createdAt: z.string(),
469
+ });
470
+ export const RepoVetOutputSchema = z.object({
471
+ repoSlug: z.string(),
472
+ fetchedAt: z.string(),
473
+ repoMeta: RepoVetMetaSchema,
474
+ prMergeTime: z.object({
475
+ avgDays: z.number().nullable(),
476
+ medianDays: z.number().nullable(),
477
+ sampleSize: z.number().int().nonnegative(),
478
+ sourceWindowDays: z.literal(90),
479
+ }),
480
+ mergeRate: z.object({
481
+ merged: z.number().int().nonnegative(),
482
+ opened: z.number().int().nonnegative(),
483
+ percent: z.number().nullable(),
484
+ windowDays: z.literal(90),
485
+ }),
486
+ maintainerActivity: z.object({
487
+ lastCommitISO: z.string().nullable(),
488
+ contributorsLast90d: z.number().int().nonnegative(),
489
+ lastReleaseISO: z.string().nullable(),
490
+ }),
491
+ communityHealth: z.object({
492
+ contributing: z.boolean(),
493
+ issueTemplates: z.boolean(),
494
+ prTemplate: z.boolean(),
495
+ codeOfConduct: z.boolean(),
496
+ /**
497
+ * True when at least one community-health probe failed for a non-404
498
+ * reason (auth, rate-limit, 5xx). The boolean flags above stay
499
+ * `false` for unprobed paths in that case, so consumers should treat
500
+ * the false flags as "could not determine" rather than "confirmed
501
+ * absent" when this is set.
502
+ */
503
+ incomplete: z.boolean().optional(),
504
+ }),
505
+ rubricScore: z.number(),
506
+ rubricVerdict: z.enum(['recommended', 'proceed_with_caution', 'avoid']),
507
+ });
508
+ const ComplianceCheckSchema = z.object({
509
+ status: z.enum(['pass', 'warn', 'fail']),
510
+ weight: z.number(),
511
+ detail: z.string(),
512
+ });
513
+ export const ComplianceScoreOutputSchema = z.object({
514
+ pr: z.object({
515
+ repo: z.string(),
516
+ number: z.number().int().nonnegative(),
517
+ title: z.string(),
518
+ url: z.string(),
519
+ }),
520
+ score: z.number().int().min(0).max(100),
521
+ rating: z.enum(['ready', 'minor', 'fix_first', 'significant_work']),
522
+ emoji: z.enum(['🌟', '✅', '⚠️', '❌']),
523
+ checks: z.object({
524
+ issueReference: ComplianceCheckSchema,
525
+ description: ComplianceCheckSchema,
526
+ focusedChanges: ComplianceCheckSchema,
527
+ tests: ComplianceCheckSchema,
528
+ title: ComplianceCheckSchema,
529
+ branch: ComplianceCheckSchema,
530
+ }),
531
+ });
379
532
  const ParsedIssueItemSchema = z.object({
380
533
  repo: z.string(),
381
534
  number: z.number(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oss-autopilot/core",
3
- "version": "3.4.1",
3
+ "version": "3.6.0",
4
4
  "description": "CLI and core library for managing open source contributions",
5
5
  "type": "module",
6
6
  "bin": {