@mmnto/cli 1.67.1 → 1.69.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.
@@ -0,0 +1,251 @@
1
+ /**
2
+ * ADR-111 Stage-1 Extract — the live CLI `ReviewThreadSource` adapter (slice 5a,
3
+ * mmnto-ai/totem#2201).
4
+ *
5
+ * Core defines the `ReviewThreadSource` port and stays network-free + LLM-free +
6
+ * deterministic; THIS file is the IO-at-the-edge implementation that wraps the
7
+ * GitHub GraphQL `reviewThreads` API behind that port. It fetches a PR's merge
8
+ * commit + its review threads (each carrying `isResolved` / `isOutdated`), maps
9
+ * them to the provider-neutral `ReviewThreadContent`, and SURFACES the per-thread
10
+ * resolution flags to core. It does NOT filter resolved/outdated threads — the
11
+ * contract-owner ruling is "surface, don't filter": core decides eligibility and
12
+ * drop-ledgers every rejection (§8 "every rejection ledgered"). A server-side or
13
+ * client-side `isResolved:false` pre-filter is FORBIDDEN here.
14
+ *
15
+ * Error contract (the discriminated `FetchResult`, §6): a per-PR failure is NEVER
16
+ * thrown — the orchestrator iterates the whole train slice and must not abort on
17
+ * one bad PR. Network / not-found → `{kind:'unreachable'}`; a malformed or
18
+ * unmappable payload → `{kind:'unparseable'}`. The mining run continues; the loud
19
+ * drop is core's job.
20
+ *
21
+ * Reuses the established `gh` CLI exec pattern (Tenet-21 — no bespoke GraphQL
22
+ * client). The `exec` seam is injectable so the query-spy + mapping tests run
23
+ * fully offline (no network, CI-locked).
24
+ */
25
+ import { z } from 'zod';
26
+ // ─── Named constants ─────────────────────────────────
27
+ /** gh exec timeout (ms). */
28
+ const GH_TIMEOUT_MS = 60_000;
29
+ /** 10MB — handles large review-thread payloads without ENOBUFS. */
30
+ const GH_MAX_BUFFER = 10 * 1024 * 1024;
31
+ /**
32
+ * Page size for `reviewThreads(first:)` / `comments(first:)`. A single page is
33
+ * fetched; if GitHub reports more, the adapter fails LOUD (`unparseable`) rather
34
+ * than silently truncating the corpus (§6 no-silent-shrink). The Gate-1 corpus
35
+ * PRs are small reviewed PRs, comfortably within one page.
36
+ *
37
+ * TODO(#2199): paginate reviewThreads/comments past one page if a future corpus
38
+ * PR ever exceeds PAGE_SIZE.
39
+ */
40
+ const PAGE_SIZE = 100;
41
+ // ─── GraphQL response schema (Zod at the IO boundary only) ───────────────────
42
+ const PageInfoSchema = z.object({ hasNextPage: z.boolean() });
43
+ const GqlCommentSchema = z.object({
44
+ // `author` is null for deleted/ghost accounts — coerce downstream to ''.
45
+ author: z.object({ login: z.string() }).nullable(),
46
+ body: z.string(),
47
+ });
48
+ const GqlReviewThreadSchema = z.object({
49
+ isResolved: z.boolean(),
50
+ isOutdated: z.boolean(),
51
+ path: z.string(),
52
+ comments: z.object({
53
+ pageInfo: PageInfoSchema,
54
+ nodes: z.array(GqlCommentSchema),
55
+ }),
56
+ });
57
+ const GqlResponseSchema = z.object({
58
+ data: z.object({
59
+ repository: z
60
+ .object({
61
+ pullRequest: z
62
+ .object({
63
+ mergeCommit: z.object({ oid: z.string() }).nullable(),
64
+ reviewThreads: z.object({
65
+ pageInfo: PageInfoSchema,
66
+ nodes: z.array(GqlReviewThreadSchema),
67
+ }),
68
+ })
69
+ .nullable(),
70
+ })
71
+ .nullable(),
72
+ }),
73
+ });
74
+ // ─── Query construction (structurally requests isResolved + isOutdated) ──────
75
+ /**
76
+ * Build the `reviewThreads` GraphQL query. It REQUESTS `isResolved` and
77
+ * `isOutdated` per thread (so core HAS the signal to decide on) — it deliberately
78
+ * does NOT add an `isResolved: false` server-side filter (the "surface, don't
79
+ * filter" ruling; the query-spy test asserts both halves). Exported for the
80
+ * query-spy test.
81
+ */
82
+ export function buildReviewThreadsQuery(owner, name, pr) {
83
+ return `query {
84
+ repository(owner: ${JSON.stringify(owner)}, name: ${JSON.stringify(name)}) {
85
+ pullRequest(number: ${pr}) {
86
+ mergeCommit { oid }
87
+ reviewThreads(first: ${PAGE_SIZE}) {
88
+ pageInfo { hasNextPage }
89
+ nodes {
90
+ isResolved
91
+ isOutdated
92
+ path
93
+ comments(first: ${PAGE_SIZE}) {
94
+ pageInfo { hasNextPage }
95
+ nodes {
96
+ author { login }
97
+ body
98
+ }
99
+ }
100
+ }
101
+ }
102
+ }
103
+ }
104
+ }`;
105
+ }
106
+ /**
107
+ * Lazy-load `safeExec` and bind it to a `gh`-backed `GhExec` for `cwd`. The
108
+ * dynamic import keeps the heavy core barrel off the CLI startup path (the
109
+ * spine-windtunnel.ts convention).
110
+ */
111
+ async function loadDefaultExec(cwd) {
112
+ const { safeExec } = await import('@mmnto/totem');
113
+ return (command, args) => safeExec(command, args, {
114
+ cwd,
115
+ timeout: GH_TIMEOUT_MS,
116
+ maxBuffer: GH_MAX_BUFFER,
117
+ env: { ...process.env, GH_PROMPT_DISABLED: '1' },
118
+ });
119
+ }
120
+ // ─── Mapping ─────────────────────────────────────────
121
+ /**
122
+ * Map a validated GraphQL response to the surviving `ReviewThread[]` with their
123
+ * resolution flags surfaced. Pure — exported for the mapping test. A null author
124
+ * (deleted/ghost) coerces to '' (`isBotIdentity('')` is false, so it stays a
125
+ * human-author '' that core's empty-body / count logic handles correctly; the
126
+ * body still gates inclusion).
127
+ */
128
+ export function mapThreads(nodes) {
129
+ return nodes.map((t) => ({
130
+ path: t.path,
131
+ // SURFACE the flags — never filter on them here (core decides).
132
+ isResolved: t.isResolved,
133
+ isOutdated: t.isOutdated,
134
+ comments: t.comments.nodes.map((c) => ({
135
+ author: c.author?.login ?? '',
136
+ body: c.body,
137
+ })),
138
+ }));
139
+ }
140
+ /**
141
+ * The live `ReviewThreadSource`. Constructible + exported now (slice 5a); wiring
142
+ * it into the spine orchestrator's `run` command is slice 5c.
143
+ */
144
+ export class ReviewThreadSourceAdapter {
145
+ owner;
146
+ name;
147
+ cwd;
148
+ /** Injected exec seam (tests); when absent the default is lazy-loaded once via `execPromise`. */
149
+ injectedExec;
150
+ /**
151
+ * Memoized lazy-load of the default `gh`-backed exec (real runs). Memoizes the
152
+ * PROMISE, not the resolved value, so concurrent `fetch()` calls on one adapter
153
+ * instance share a single `loadDefaultExec` instead of racing a `!this.exec`
154
+ * guard (CR #2207 — was benign since dynamic import is idempotent, now explicit).
155
+ */
156
+ execPromise;
157
+ constructor(opts) {
158
+ this.owner = opts.owner;
159
+ this.name = opts.name;
160
+ this.cwd = opts.cwd ?? process.cwd();
161
+ this.injectedExec = opts.exec;
162
+ }
163
+ /** Resolve the exec seam: the injected one (tests), else the memoized lazy-loaded default. */
164
+ resolveExec() {
165
+ if (this.injectedExec)
166
+ return Promise.resolve(this.injectedExec);
167
+ this.execPromise ??= loadDefaultExec(this.cwd);
168
+ return this.execPromise;
169
+ }
170
+ async fetch(pr) {
171
+ const query = buildReviewThreadsQuery(this.owner, this.name, pr);
172
+ const exec = await this.resolveExec();
173
+ // totem-context: this catch does NOT silently degrade — it is the §6 port
174
+ // contract. A per-PR IO failure (network/404/auth) is reified into the
175
+ // discriminated FetchResult ('unreachable') and surfaced LOUDLY to core,
176
+ // which drop-ledgers it (a creditable FM-i drop). Re-throwing would abort the
177
+ // whole mining run on one bad PR, violating the orchestrator's train-slice
178
+ // sweep. The loud-fail lives in core's ledger, not a thrown exception.
179
+ let raw;
180
+ try {
181
+ raw = exec('gh', ['api', 'graphql', '-f', `query=${query}`]);
182
+ // totem-context: intentional §6 port contract — reify IO failure into the discriminated FetchResult, surfaced loudly to core's drop ledger; never swallowed.
183
+ }
184
+ catch (err) {
185
+ return {
186
+ kind: 'unreachable',
187
+ detail: `gh graphql fetch failed for PR #${pr}: ${err instanceof Error ? err.message : String(err)}`,
188
+ };
189
+ }
190
+ // totem-context: intentional — same §6 port contract as above. A malformed /
191
+ // unmappable payload is reified into FetchResult ('unparseable', a route
192
+ // distinct from 'unreachable') and surfaced LOUDLY to core for drop-ledgering,
193
+ // not swallowed. Re-throwing would abort the orchestrator's whole train-slice
194
+ // sweep on one bad payload.
195
+ let parsed;
196
+ try {
197
+ parsed = GqlResponseSchema.parse(JSON.parse(raw));
198
+ // totem-context: intentional §6 port contract — reify the unparseable payload into the discriminated FetchResult, surfaced loudly to core's drop ledger; never swallowed.
199
+ }
200
+ catch (err) {
201
+ return {
202
+ kind: 'unparseable',
203
+ detail: `review-thread payload unparseable for PR #${pr}: ${err instanceof Error ? err.message : String(err)}`,
204
+ };
205
+ }
206
+ // Distinguish a null repository (repo inaccessible / token lacks scope) from a
207
+ // null pullRequest (PR genuinely not found): both are `unreachable`, but they
208
+ // need different diagnostic leads, so the detail strings differ (CR + Greptile
209
+ // #2207 — a shared `!pull` guard would send a token-scope failure chasing a
210
+ // non-existent PR).
211
+ const repo = parsed.data.repository;
212
+ if (!repo) {
213
+ return {
214
+ kind: 'unreachable',
215
+ detail: `repository ${this.owner}/${this.name} not found or inaccessible (check owner/name + token scope) while fetching PR #${pr}`,
216
+ };
217
+ }
218
+ const pull = repo.pullRequest;
219
+ if (!pull) {
220
+ return { kind: 'unreachable', detail: `PR #${pr} not found in ${this.owner}/${this.name}` };
221
+ }
222
+ // A merged train PR MUST have a merge commit (the provenance SHA core needs).
223
+ // Its absence is an unusable payload, not a fetch failure → 'unparseable'.
224
+ const mergeCommitSha = pull.mergeCommit?.oid?.toLowerCase();
225
+ if (!mergeCommitSha) {
226
+ return { kind: 'unparseable', detail: `PR #${pr} has no merge commit oid` };
227
+ }
228
+ // No-silent-shrink (§6): if the payload was paginated past one page, fail
229
+ // LOUD rather than mining a partial thread set.
230
+ if (pull.reviewThreads.pageInfo.hasNextPage) {
231
+ return {
232
+ kind: 'unparseable',
233
+ detail: `PR #${pr} has more than ${PAGE_SIZE} review threads (pagination unsupported)`,
234
+ };
235
+ }
236
+ for (const t of pull.reviewThreads.nodes) {
237
+ if (t.comments.pageInfo.hasNextPage) {
238
+ return {
239
+ kind: 'unparseable',
240
+ detail: `PR #${pr} has a review thread with more than ${PAGE_SIZE} comments (pagination unsupported)`,
241
+ };
242
+ }
243
+ }
244
+ const threads = mapThreads(pull.reviewThreads.nodes);
245
+ return {
246
+ kind: 'ok',
247
+ content: { pr, mergeCommitSha, threads },
248
+ };
249
+ }
250
+ }
251
+ //# sourceMappingURL=spine-review-thread-source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spine-review-thread-source.js","sourceRoot":"","sources":["../../src/commands/spine-review-thread-source.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=spine-review-thread-source.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spine-review-thread-source.test.d.ts","sourceRoot":"","sources":["../../src/commands/spine-review-thread-source.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,284 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { buildReviewThreadsQuery, mapThreads, ReviewThreadSourceAdapter, } from './spine-review-thread-source.js';
3
+ // ─── Helpers ─────────────────────────────────────────
4
+ const OWNER = 'mmnto-ai';
5
+ const NAME = 'totem';
6
+ const MERGE_OID = 'a'.repeat(40);
7
+ /** A well-formed GraphQL response payload (string, as `gh` returns). */
8
+ function okPayload(opts) {
9
+ const threads = (opts?.threads ?? []).map((t) => ({
10
+ isResolved: t.isResolved ?? false,
11
+ isOutdated: t.isOutdated ?? false,
12
+ path: t.path ?? 'packages/core/src/x.ts',
13
+ comments: {
14
+ pageInfo: { hasNextPage: t.commentsHasNext ?? false },
15
+ nodes: (t.comments ?? [{ login: 'jane', body: 'a note' }]).map((c) => ({
16
+ author: c.login === null ? null : { login: c.login },
17
+ body: c.body,
18
+ })),
19
+ },
20
+ }));
21
+ return JSON.stringify({
22
+ data: {
23
+ repository: {
24
+ pullRequest: {
25
+ mergeCommit: opts?.mergeOid === null ? null : { oid: opts?.mergeOid ?? MERGE_OID },
26
+ reviewThreads: {
27
+ pageInfo: { hasNextPage: opts?.threadsHasNext ?? false },
28
+ nodes: threads,
29
+ },
30
+ },
31
+ },
32
+ },
33
+ });
34
+ }
35
+ /** An exec stub that records the args it was called with and returns a fixed payload. */
36
+ function stubExec(payload) {
37
+ const calls = [];
38
+ const fn = ((_command, args) => {
39
+ calls.push(args);
40
+ return payload;
41
+ });
42
+ fn.calls = calls;
43
+ return fn;
44
+ }
45
+ // ─── Query construction (the reframed agy fold-2: query-spy) ─────────────────
46
+ describe('buildReviewThreadsQuery', () => {
47
+ it('REQUESTS isResolved and isOutdated on reviewThreads (so core has the signal)', () => {
48
+ const q = buildReviewThreadsQuery(OWNER, NAME, 42);
49
+ expect(q).toContain('reviewThreads');
50
+ expect(q).toContain('isResolved');
51
+ expect(q).toContain('isOutdated');
52
+ expect(q).toContain('mergeCommit');
53
+ });
54
+ it('does NOT pre-filter with isResolved:false — surface, not filter (contract B)', () => {
55
+ const q = buildReviewThreadsQuery(OWNER, NAME, 42);
56
+ // The "surface, don't filter" ruling: no server-side resolution filter.
57
+ expect(q).not.toMatch(/isResolved\s*:\s*false/);
58
+ // requestArguments use parentheses, e.g. reviewThreads(first: 100) — there
59
+ // must be no boolean argument predicate on isResolved.
60
+ expect(q).not.toMatch(/reviewThreads\([^)]*isResolved/);
61
+ });
62
+ it('embeds owner/name as JSON-escaped strings and the numeric PR', () => {
63
+ const q = buildReviewThreadsQuery(OWNER, NAME, 7);
64
+ expect(q).toContain('owner: "mmnto-ai"');
65
+ expect(q).toContain('name: "totem"');
66
+ expect(q).toContain('pullRequest(number: 7)');
67
+ });
68
+ });
69
+ describe('ReviewThreadSourceAdapter — query-spy through fetch', () => {
70
+ it('passes a query that requests the resolution fields to gh', async () => {
71
+ const exec = stubExec(okPayload({ threads: [{}] }));
72
+ const adapter = new ReviewThreadSourceAdapter({ owner: OWNER, name: NAME, exec });
73
+ await adapter.fetch(99);
74
+ expect(exec.calls).toHaveLength(1);
75
+ const args = exec.calls[0];
76
+ expect(args[0]).toBe('api');
77
+ expect(args[1]).toBe('graphql');
78
+ const queryArg = args.find((a) => a.startsWith('query='));
79
+ expect(queryArg).toBeDefined();
80
+ expect(queryArg).toContain('isResolved');
81
+ expect(queryArg).toContain('isOutdated');
82
+ expect(queryArg).not.toMatch(/reviewThreads\([^)]*isResolved/);
83
+ });
84
+ });
85
+ // ─── Mapping ─────────────────────────────────────────
86
+ describe('mapThreads', () => {
87
+ it('surfaces per-thread isResolved/isOutdated flags (does not filter)', () => {
88
+ const mapped = mapThreads([
89
+ {
90
+ isResolved: true,
91
+ isOutdated: false,
92
+ path: 'a.ts',
93
+ comments: {
94
+ pageInfo: { hasNextPage: false },
95
+ nodes: [{ author: { login: 'jane' }, body: 'x' }],
96
+ },
97
+ },
98
+ {
99
+ isResolved: false,
100
+ isOutdated: true,
101
+ path: 'b.ts',
102
+ comments: {
103
+ pageInfo: { hasNextPage: false },
104
+ nodes: [{ author: { login: 'john' }, body: 'y' }],
105
+ },
106
+ },
107
+ ]);
108
+ // BOTH threads are present — nothing filtered out (surface, not filter).
109
+ expect(mapped).toHaveLength(2);
110
+ expect(mapped[0]).toMatchObject({ path: 'a.ts', isResolved: true, isOutdated: false });
111
+ expect(mapped[1]).toMatchObject({ path: 'b.ts', isResolved: false, isOutdated: true });
112
+ });
113
+ it('coerces a null author (deleted/ghost) to an empty login', () => {
114
+ const mapped = mapThreads([
115
+ {
116
+ isResolved: false,
117
+ isOutdated: false,
118
+ path: 'a.ts',
119
+ comments: {
120
+ pageInfo: { hasNextPage: false },
121
+ nodes: [{ author: null, body: 'ghost note' }],
122
+ },
123
+ },
124
+ ]);
125
+ expect(mapped[0].comments[0].author).toBe('');
126
+ expect(mapped[0].comments[0].body).toBe('ghost note');
127
+ });
128
+ });
129
+ // ─── fetch() — payload → ReviewThreadContent + failure mapping ────────────────
130
+ describe('ReviewThreadSourceAdapter.fetch — success mapping', () => {
131
+ it('maps a GraphQL payload to ReviewThreadContent with per-thread flags', async () => {
132
+ const exec = stubExec(okPayload({
133
+ mergeOid: MERGE_OID,
134
+ threads: [
135
+ {
136
+ isResolved: false,
137
+ isOutdated: false,
138
+ path: 'x.ts',
139
+ comments: [{ login: 'jane', body: 'eligible' }],
140
+ },
141
+ {
142
+ isResolved: true,
143
+ isOutdated: false,
144
+ path: 'y.ts',
145
+ comments: [{ login: 'john', body: 'resolved' }],
146
+ },
147
+ ],
148
+ }));
149
+ const adapter = new ReviewThreadSourceAdapter({ owner: OWNER, name: NAME, exec });
150
+ const result = await adapter.fetch(123);
151
+ expect(result.kind).toBe('ok');
152
+ if (result.kind !== 'ok')
153
+ return;
154
+ expect(result.content.pr).toBe(123);
155
+ expect(result.content.mergeCommitSha).toBe(MERGE_OID);
156
+ expect(result.content.threads).toHaveLength(2);
157
+ expect(result.content.threads[0]).toMatchObject({ isResolved: false, isOutdated: false });
158
+ expect(result.content.threads[1]).toMatchObject({ isResolved: true, isOutdated: false });
159
+ });
160
+ it('lowercases the merge commit oid (provenance canonical form)', async () => {
161
+ const exec = stubExec(okPayload({ mergeOid: 'A'.repeat(40), threads: [{}] }));
162
+ const adapter = new ReviewThreadSourceAdapter({ owner: OWNER, name: NAME, exec });
163
+ const result = await adapter.fetch(1);
164
+ expect(result.kind).toBe('ok');
165
+ if (result.kind !== 'ok')
166
+ return;
167
+ expect(result.content.mergeCommitSha).toBe('a'.repeat(40));
168
+ });
169
+ });
170
+ describe('ReviewThreadSourceAdapter.fetch — failure mapping (§6 discriminated)', () => {
171
+ it('a thrown gh error (network/404/auth) maps to unreachable, never throws', async () => {
172
+ // totem-context: this `new Error` SIMULATES an external `gh`/network throw the
173
+ // adapter must catch — it is the third-party error under test, not a
174
+ // Totem-originated one, so it deliberately carries no [Totem Error] prefix.
175
+ const throwingExec = () => {
176
+ throw new Error('gh: HTTP 404: Not Found');
177
+ };
178
+ const adapter = new ReviewThreadSourceAdapter({ owner: OWNER, name: NAME, exec: throwingExec });
179
+ const result = await adapter.fetch(404);
180
+ expect(result.kind).toBe('unreachable');
181
+ if (result.kind === 'unreachable')
182
+ expect(result.detail).toContain('404');
183
+ });
184
+ it('invalid JSON maps to unparseable, never throws', async () => {
185
+ const adapter = new ReviewThreadSourceAdapter({
186
+ owner: OWNER,
187
+ name: NAME,
188
+ exec: stubExec('not json at all'),
189
+ });
190
+ const result = await adapter.fetch(1);
191
+ expect(result.kind).toBe('unparseable');
192
+ });
193
+ it('a schema-mismatched payload maps to unparseable', async () => {
194
+ const adapter = new ReviewThreadSourceAdapter({
195
+ owner: OWNER,
196
+ name: NAME,
197
+ exec: stubExec(JSON.stringify({ data: { repository: { pullRequest: { wrong: true } } } })),
198
+ });
199
+ const result = await adapter.fetch(1);
200
+ expect(result.kind).toBe('unparseable');
201
+ });
202
+ it('a missing pullRequest maps to unreachable (PR not found)', async () => {
203
+ const adapter = new ReviewThreadSourceAdapter({
204
+ owner: OWNER,
205
+ name: NAME,
206
+ exec: stubExec(JSON.stringify({ data: { repository: { pullRequest: null } } })),
207
+ });
208
+ const result = await adapter.fetch(1);
209
+ expect(result.kind).toBe('unreachable');
210
+ // PR-not-found detail names the PR, not the repository (CR + Greptile #2207).
211
+ if (result.kind === 'unreachable')
212
+ expect(result.detail).toContain('not found in');
213
+ });
214
+ it('a null repository (inaccessible / token scope) maps to unreachable with a repo-specific detail', async () => {
215
+ const adapter = new ReviewThreadSourceAdapter({
216
+ owner: OWNER,
217
+ name: NAME,
218
+ exec: stubExec(JSON.stringify({ data: { repository: null } })),
219
+ });
220
+ const result = await adapter.fetch(1);
221
+ expect(result.kind).toBe('unreachable');
222
+ // Distinct from PR-not-found: the detail leads with the repository, not the PR
223
+ // (CR + Greptile #2207 — don't send a token-scope failure chasing a missing PR).
224
+ if (result.kind === 'unreachable') {
225
+ expect(result.detail).toContain('repository');
226
+ expect(result.detail).toContain('token scope');
227
+ }
228
+ });
229
+ it('a null merge commit (unmerged / missing) maps to unparseable', async () => {
230
+ const adapter = new ReviewThreadSourceAdapter({
231
+ owner: OWNER,
232
+ name: NAME,
233
+ exec: stubExec(okPayload({ mergeOid: null, threads: [{}] })),
234
+ });
235
+ const result = await adapter.fetch(1);
236
+ expect(result.kind).toBe('unparseable');
237
+ if (result.kind === 'unparseable')
238
+ expect(result.detail).toContain('merge commit');
239
+ });
240
+ it('paginated review threads fail loud as unparseable (no silent shrink)', async () => {
241
+ const adapter = new ReviewThreadSourceAdapter({
242
+ owner: OWNER,
243
+ name: NAME,
244
+ exec: stubExec(okPayload({ threads: [{}], threadsHasNext: true })),
245
+ });
246
+ const result = await adapter.fetch(1);
247
+ expect(result.kind).toBe('unparseable');
248
+ if (result.kind === 'unparseable')
249
+ expect(result.detail).toContain('review threads');
250
+ });
251
+ it('paginated comments within a thread fail loud as unparseable', async () => {
252
+ const adapter = new ReviewThreadSourceAdapter({
253
+ owner: OWNER,
254
+ name: NAME,
255
+ exec: stubExec(okPayload({ threads: [{ commentsHasNext: true }] })),
256
+ });
257
+ const result = await adapter.fetch(1);
258
+ expect(result.kind).toBe('unparseable');
259
+ if (result.kind === 'unparseable')
260
+ expect(result.detail).toContain('comments');
261
+ });
262
+ });
263
+ describe('ReviewThreadSourceAdapter.fetch — determinism', () => {
264
+ it('identical payload → identical FetchResult', async () => {
265
+ const payload = okPayload({
266
+ threads: [
267
+ { isResolved: false, comments: [{ login: 'jane', body: 'a' }] },
268
+ { isResolved: true, comments: [{ login: 'john', body: 'b' }] },
269
+ ],
270
+ });
271
+ const a = await new ReviewThreadSourceAdapter({
272
+ owner: OWNER,
273
+ name: NAME,
274
+ exec: stubExec(payload),
275
+ }).fetch(5);
276
+ const b = await new ReviewThreadSourceAdapter({
277
+ owner: OWNER,
278
+ name: NAME,
279
+ exec: stubExec(payload),
280
+ }).fetch(5);
281
+ expect(a).toEqual(b);
282
+ });
283
+ });
284
+ //# sourceMappingURL=spine-review-thread-source.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spine-review-thread-source.test.js","sourceRoot":"","sources":["../../src/commands/spine-review-thread-source.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmnto/cli",
3
- "version": "1.67.1",
3
+ "version": "1.69.0",
4
4
  "description": "CLI for Totem — AI persistent memory and context layer",
5
5
  "type": "module",
6
6
  "engines": {
@@ -28,7 +28,7 @@
28
28
  "smol-toml": "^1.6.1",
29
29
  "yaml": "^2.4.0",
30
30
  "zod": "^3.24.0",
31
- "@mmnto/totem": "1.67.1"
31
+ "@mmnto/totem": "1.69.0"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@anthropic-ai/sdk": "^0.98.0",