@oss-autopilot/core 3.12.0 → 3.13.1

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.
@@ -18,6 +18,9 @@
18
18
  *
19
19
  * - `runComments` (commands/comments.ts): review / inline / discussion
20
20
  * comment bodies in the `comments` CLI `--json` + MCP tool output.
21
+ * - `deduplicateDigest` (formatters/json.ts) and the MCP PR resources:
22
+ * `openPRs[].lastMaintainerComment.body` via {@link fenceFetchedPR}
23
+ * (#1420).
21
24
  * - `fetchPRCommentBundle` (core/pr-comments-fetcher.ts): bundle bodies
22
25
  * feeding `guidelines fetch-corpus` (agent-only consumer).
23
26
  * - `toDailyOutput` (commands/daily.ts): `commentedIssues[].lastResponseBody`
@@ -132,3 +135,25 @@ export function safeExtractFromFence(text) {
132
135
  return text;
133
136
  }
134
137
  }
138
+ /**
139
+ * Fence the attacker-controllable maintainer-comment excerpt on a FetchedPR
140
+ * for agent-facing serialization (#1420). Applied at the serialization
141
+ * boundary (daily/startup --json via deduplicateDigest, MCP PR resources)
142
+ * rather than at fetch time: extractMaintainerActionHints parses the RAW
143
+ * body inside the pipeline, and human surfaces (dashboard SPA, CLI text
144
+ * mode) must not render fence markup. Returns a copy; never mutates.
145
+ */
146
+ export function fenceFetchedPR(pr) {
147
+ if (!pr.lastMaintainerComment)
148
+ return pr;
149
+ return {
150
+ ...pr,
151
+ lastMaintainerComment: {
152
+ ...pr.lastMaintainerComment,
153
+ body: wrapUntrustedContent(pr.lastMaintainerComment.body, `${pr.repo}#${pr.number}`, {
154
+ author: pr.lastMaintainerComment.author,
155
+ source: 'pr-comment',
156
+ }),
157
+ },
158
+ };
159
+ }
@@ -648,6 +648,7 @@ export declare const SearchOutputSchema: z.ZodObject<{
648
648
  }, z.core.$strip>>;
649
649
  boostScore: z.ZodOptional<z.ZodNumber>;
650
650
  boostReasons: z.ZodOptional<z.ZodArray<z.ZodString>>;
651
+ diversitySlot: z.ZodOptional<z.ZodBoolean>;
651
652
  }, z.core.$strip>>;
652
653
  excludedRepos: z.ZodArray<z.ZodString>;
653
654
  aiPolicyBlocklist: z.ZodArray<z.ZodString>;
@@ -707,6 +708,7 @@ export declare const FeaturesOutputSchema: z.ZodObject<{
707
708
  }, z.core.$strip>>;
708
709
  boostScore: z.ZodOptional<z.ZodNumber>;
709
710
  boostReasons: z.ZodOptional<z.ZodArray<z.ZodString>>;
711
+ diversitySlot: z.ZodOptional<z.ZodBoolean>;
710
712
  horizon: z.ZodEnum<{
711
713
  "quick-win": "quick-win";
712
714
  "bigger-bet": "bigger-bet";
@@ -764,6 +766,7 @@ export declare const FeaturesOutputSchema: z.ZodObject<{
764
766
  }, z.core.$strip>>;
765
767
  boostScore: z.ZodOptional<z.ZodNumber>;
766
768
  boostReasons: z.ZodOptional<z.ZodArray<z.ZodString>>;
769
+ diversitySlot: z.ZodOptional<z.ZodBoolean>;
767
770
  horizon: z.ZodEnum<{
768
771
  "quick-win": "quick-win";
769
772
  "bigger-bet": "bigger-bet";
@@ -816,7 +819,7 @@ export declare const ListMarkDoneOutputSchema: z.ZodObject<{
816
819
  url: z.ZodString;
817
820
  repoHeadingStruck: z.ZodBoolean;
818
821
  remainingUnderRepo: z.ZodNumber;
819
- reason: z.ZodOptional<z.ZodString>;
822
+ reason: z.ZodOptional<z.ZodLiteral<"already marked done">>;
820
823
  }, z.core.$strip>;
821
824
  export declare const VerifyIssueOutputSchema: z.ZodObject<{
822
825
  url: z.ZodString;
@@ -1216,6 +1219,12 @@ export interface SearchCandidate {
1216
1219
  * opportunities (open PR + no updates for 30+ days, scout 0.9.0 #97).
1217
1220
  */
1218
1221
  linkedPR?: CandidateLinkedPR;
1222
+ /** Strategy-bias sort boost from scout (#1244); absent when unboosted. */
1223
+ boostScore?: number;
1224
+ /** Human-readable boost explanations, e.g. "repo affinity: vercel/next.js". */
1225
+ boostReasons?: string[];
1226
+ /** True when this candidate filled a diversity slot (#1244). */
1227
+ diversitySlot?: boolean;
1219
1228
  }
1220
1229
  export interface SearchOutput {
1221
1230
  candidates: SearchCandidate[];
@@ -3,6 +3,7 @@
3
3
  * Provides structured output that can be consumed by scripts and plugins
4
4
  */
5
5
  import { z } from 'zod';
6
+ import { fenceFetchedPR } from '../core/untrusted-content.js';
6
7
  export function buildStalenessWarning(info) {
7
8
  return {
8
9
  phase: 'gist-staleness',
@@ -43,7 +44,10 @@ export function deduplicateDigest(digest) {
43
44
  const toUrls = (prs) => prs.map((pr) => pr.url);
44
45
  return {
45
46
  generatedAt: digest.generatedAt,
46
- openPRs: digest.openPRs,
47
+ // lastMaintainerComment.body is attacker-controllable on any public PR;
48
+ // fence it at this agent-facing serialization boundary (#1420). The
49
+ // digest itself keeps the raw body for pipeline parsing and human UIs.
50
+ openPRs: digest.openPRs.map(fenceFetchedPR),
47
51
  needsAddressingPRs: toUrls(digest.needsAddressingPRs),
48
52
  waitingOnMaintainerPRs: toUrls(digest.waitingOnMaintainerPRs),
49
53
  recentlyClosedPRs: digest.recentlyClosedPRs,
@@ -353,6 +357,9 @@ const SearchCandidateSchema = z.object({
353
357
  */
354
358
  boostScore: z.number().optional(),
355
359
  boostReasons: z.array(z.string()).optional(),
360
+ /** True when this candidate filled a diversity slot (#1244) — surfaced so
361
+ * the user can see the counterweight working, not just its absence. */
362
+ diversitySlot: z.boolean().optional(),
356
363
  });
357
364
  export const SearchOutputSchema = z.object({
358
365
  candidates: z.array(SearchCandidateSchema),
@@ -421,7 +428,10 @@ export const ListMarkDoneOutputSchema = z.object({
421
428
  url: z.string(),
422
429
  repoHeadingStruck: z.boolean(),
423
430
  remainingUnderRepo: z.number().int().nonnegative(),
424
- reason: z.string().optional(),
431
+ // #1406: not-found now throws before the success envelope, so the only
432
+ // reachable no-op reason is the idempotent one. Pinned so a new quiet
433
+ // no-op path trips the #1105 runtime validator instead of shipping silently.
434
+ reason: z.literal('already marked done').optional(),
425
435
  });
426
436
  // verify-issue (#1353, #1354): mirrors {@link IssueVerification} from
427
437
  // core/issue-verification.ts. Strict shape — additional keys must be added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oss-autopilot/core",
3
- "version": "3.12.0",
3
+ "version": "3.13.1",
4
4
  "description": "CLI and core library for managing open source contributions",
5
5
  "type": "module",
6
6
  "bin": {
@@ -54,7 +54,7 @@
54
54
  "dependencies": {
55
55
  "@octokit/plugin-throttling": "^11.0.3",
56
56
  "@octokit/rest": "^22.0.1",
57
- "@oss-scout/core": "^0.11.0",
57
+ "@oss-scout/core": "^1.1.0",
58
58
  "commander": "^15.0.0",
59
59
  "zod": "^4.4.3"
60
60
  },
@@ -72,7 +72,7 @@
72
72
  "bundle": "esbuild src/cli.ts --bundle --platform=node --target=node22 --format=cjs --minify --sourcemap --outfile=dist/cli.bundle.cjs",
73
73
  "start": "tsx src/cli.ts",
74
74
  "dev": "tsx watch src/cli.ts",
75
- "typecheck": "tsc --noEmit",
75
+ "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.tests.json",
76
76
  "test": "vitest run",
77
77
  "test:coverage": "vitest run --coverage",
78
78
  "test:watch": "vitest",