pi-pr-review 1.10.4 → 1.10.6
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.
- package/CHANGELOG.md +14 -0
- package/README.md +8 -6
- package/extensions/review-table.ts +106 -130
- package/lib/pr-review-publish.ts +343 -187
- package/package.json +24 -2
- package/prompts/pr-review.md +4 -2
- package/.github/workflows/pull-request.yml +0 -55
- package/.github/workflows/release-please.yml +0 -105
- package/.release-please-manifest.json +0 -3
- package/RELEASING.md +0 -29
- package/release-please-config.json +0 -24
- package/scripts/verify-release-version.mjs +0 -66
- package/tests/pr-review-concurrency.test.ts +0 -45
- package/tests/pr-review-context.test.ts +0 -66
- package/tests/pr-review-extension-lifecycle.test.ts +0 -696
- package/tests/pr-review-focus-view.test.ts +0 -235
- package/tests/pr-review-focus.test.ts +0 -250
- package/tests/pr-review-loop.test.ts +0 -167
- package/tests/pr-review-policy.test.ts +0 -95
- package/tests/pr-review-prompt.test.ts +0 -207
- package/tests/pr-review-publish.test.ts +0 -804
- package/tests/pr-review-registration.test.ts +0 -157
- package/tests/pr-review-subprocess.test.ts +0 -440
- package/tests/pr-review-telemetry.test.ts +0 -179
- package/tests/pr-review-thinking.test.ts +0 -83
- package/tests/pr-review-tool-gate.test.ts +0 -125
- package/tests/pr-review-verify.test.ts +0 -826
- package/tests/pr-self-review.test.ts +0 -342
- package/tests/release-version.test.ts +0 -63
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.10.6](https://github.com/10ego/pi-pr-review/compare/v1.10.5...v1.10.6) (2026-07-17)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **publish:** simplify reliable review posting ([#31](https://github.com/10ego/pi-pr-review/issues/31)) ([7d93560](https://github.com/10ego/pi-pr-review/commit/7d935604b620a51b04708633da7c4dc0850d6096))
|
|
9
|
+
|
|
10
|
+
## [1.10.5](https://github.com/10ego/pi-pr-review/compare/v1.10.4...v1.10.5) (2026-07-17)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Miscellaneous Chores
|
|
14
|
+
|
|
15
|
+
* **release:** harden Node 24 automation ([#32](https://github.com/10ego/pi-pr-review/issues/32)) ([6b670b3](https://github.com/10ego/pi-pr-review/commit/6b670b3a1e33f3f2392027ae79c159afd9738690))
|
|
16
|
+
|
|
3
17
|
## [1.10.4](https://github.com/10ego/pi-pr-review/compare/v1.10.3...v1.10.4) (2026-07-15)
|
|
4
18
|
|
|
5
19
|
|
package/README.md
CHANGED
|
@@ -182,21 +182,23 @@ Publishing is off by default.
|
|
|
182
182
|
/pr-review-config auto_post_reviews=true
|
|
183
183
|
```
|
|
184
184
|
|
|
185
|
-
The extension—not the model—owns publishing.
|
|
185
|
+
The extension—not the model—owns publishing. After a successful review, it caches one validated completed review per repository and PR in the current Pi session. `autoPostReviews` and `--comment` publish that cached review after completion; `--no-comment` suppresses publication for the run.
|
|
186
186
|
|
|
187
|
-
If the agent's final review is not valid exact-contract JSON, the extension logs the
|
|
187
|
+
If the agent's final review is not valid exact-contract JSON, the extension logs the reason and automatically asks the same agent to correct its completed output once, with tools disabled and the original posting authority unchanged. An invalid correction, a tool call, or overlapping input stops publication rather than starting another correction loop.
|
|
188
188
|
|
|
189
|
-
|
|
189
|
+
You can publish the cache later with `/pr-review-publish 123`, or directly ask the agent to “post the inline review,” “post it as an inline review,” or “publish the review for PR #123.” The extension handles that request directly before an agent turn. `/pr-review-publish` and a matching direct request publish only the cache; they never start or rerun review agents. Unnumbered direct requests select the latest cached review for the current repository. Only fresh interactive/RPC input can use the direct path.
|
|
190
190
|
|
|
191
|
-
|
|
191
|
+
Every authorized publish path builds one `COMMENT` payload and sends at most one GitHub review `POST`; it never submits `APPROVE` or `REQUEST_CHANGES` and never retries a rejected write with a fallback POST. For a current, open PR, the first 50 eligible P0–P3 findings with valid, unique diff anchors are inline. All other findings that pass content validation stay in the top-level review body, including nits, off-diff findings, unavailable diff metadata, duplicate anchors, and overflow. Stale or authorized non-open reviews are body-only.
|
|
192
192
|
|
|
193
|
-
|
|
193
|
+
The same safety gates apply to every path: captured posting authority, exact repository/PR/review binding, safe locations, no reserved review markers, bounded bodies and payloads, current-head and stale policy, draft and lifecycle checks, non-open authorization, same-head duplicate detection, and a final head check. Unknown or invalid states fail closed before a write.
|
|
194
|
+
|
|
195
|
+
Stale publication is enabled by default through `allowStalePublish: true`; disable it with `/pr-review-config allow_stale_publish=false`. Automatic posting and `/pr-review-publish` use the setting captured when the review starts unless the command supplies the explicit override:
|
|
194
196
|
|
|
195
197
|
```text
|
|
196
198
|
/pr-review-publish 123 --allow-stale
|
|
197
199
|
```
|
|
198
200
|
|
|
199
|
-
Inline comments are always disabled for stale reviews because the original anchors may no longer be valid
|
|
201
|
+
A matching direct request permits stale publication. Inline comments are always disabled for stale reviews because the original anchors may no longer be valid; the body identifies both the reviewed and current commit. The session-backed cache survives extension reloads and session resumes and remains bound to the originating session instance and repository.
|
|
200
202
|
|
|
201
203
|
## Optional verification
|
|
202
204
|
|
|
@@ -39,9 +39,7 @@ import {
|
|
|
39
39
|
type AutoPostResolution,
|
|
40
40
|
type CompletedReviewRecord,
|
|
41
41
|
type CompletedReviewSessionIdentity,
|
|
42
|
-
type RepositoryBinding,
|
|
43
42
|
type ReviewInvocation,
|
|
44
|
-
type ReviewLike,
|
|
45
43
|
} from "../lib/pr-review-publish.ts";
|
|
46
44
|
import {
|
|
47
45
|
ReviewLoopCoordinator,
|
|
@@ -379,51 +377,48 @@ function notifyPublishResult(
|
|
|
379
377
|
}
|
|
380
378
|
}
|
|
381
379
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
380
|
+
type ReviewPublicationOrigin =
|
|
381
|
+
| { readonly kind: "frozen-invocation" }
|
|
382
|
+
| { readonly kind: "publish-command"; readonly stalePolicy: "frozen" | "allow-stale" }
|
|
383
|
+
| { readonly kind: "direct-request" };
|
|
384
|
+
|
|
385
|
+
async function publishCompletedReview(
|
|
386
|
+
record: CompletedReviewRecord,
|
|
387
|
+
origin: ReviewPublicationOrigin,
|
|
385
388
|
ctx: ExtensionContext,
|
|
386
|
-
expectedRepository?: RepositoryBinding,
|
|
387
389
|
): Promise<void> {
|
|
388
|
-
const
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
if (!authority.publish) return;
|
|
394
|
-
const parsed = parsePublishableReview(text);
|
|
395
|
-
if (!parsed.review) {
|
|
396
|
-
ctx.ui.notify(`PR review was not posted: ${parsed.error}`, "error");
|
|
397
|
-
return;
|
|
398
|
-
}
|
|
399
|
-
const bindingError = validateReviewInvocation(parsed.review, invocation);
|
|
400
|
-
if (bindingError) {
|
|
401
|
-
ctx.ui.notify(`PR review was not posted: ${bindingError}`, "error");
|
|
390
|
+
const decision = origin.kind === "frozen-invocation"
|
|
391
|
+
? decideReviewPublication(record.invocation)
|
|
392
|
+
: undefined;
|
|
393
|
+
if (decision?.error) {
|
|
394
|
+
ctx.ui.notify(`PR review was not posted: ${decision.error}`, "error");
|
|
402
395
|
return;
|
|
403
396
|
}
|
|
404
|
-
if (!
|
|
405
|
-
const
|
|
397
|
+
if (decision && !decision.publish) return;
|
|
398
|
+
const explicitStale = origin.kind === "direct-request" ||
|
|
399
|
+
(origin.kind === "publish-command" && origin.stalePolicy === "allow-stale");
|
|
400
|
+
const allowStale = explicitStale || record.invocation.allowStalePublish;
|
|
401
|
+
const source = decision?.source ?? (origin.kind === "frozen-invocation"
|
|
402
|
+
? "frozen invocation"
|
|
403
|
+
: origin.kind === "direct-request"
|
|
404
|
+
? "direct user request"
|
|
405
|
+
: origin.stalePolicy === "allow-stale" ? "publish-only --allow-stale" : "publish-only");
|
|
406
|
+
|
|
407
|
+
const headSha = record.review.pr?.head_sha;
|
|
406
408
|
if (typeof headSha !== "string") {
|
|
407
|
-
ctx.ui.notify("PR review was not posted: final JSON is missing pr.head_sha", "error");
|
|
408
|
-
return;
|
|
409
|
-
}
|
|
410
|
-
if (!expectedRepository) {
|
|
411
|
-
ctx.ui.notify(
|
|
412
|
-
"PR review was not posted because its repository identity could not be established before caching; no publish-only cache is available. Rerun /pr-review when GitHub repository lookup is working.",
|
|
413
|
-
"error",
|
|
414
|
-
);
|
|
409
|
+
ctx.ui.notify("PR review was not posted: cached final JSON is missing pr.head_sha", "error");
|
|
415
410
|
return;
|
|
416
411
|
}
|
|
417
412
|
const result = await publishPullReview({
|
|
418
413
|
cwd: ctx.cwd,
|
|
419
|
-
prNumber: invocation.prNumber,
|
|
414
|
+
prNumber: record.invocation.prNumber,
|
|
420
415
|
headSha,
|
|
421
|
-
allowNonOpen: invocation.allowNonOpen,
|
|
422
|
-
allowStale
|
|
423
|
-
expectedRepository,
|
|
424
|
-
review:
|
|
416
|
+
allowNonOpen: record.invocation.allowNonOpen,
|
|
417
|
+
allowStale,
|
|
418
|
+
expectedRepository: record.repository,
|
|
419
|
+
review: record.review,
|
|
425
420
|
});
|
|
426
|
-
notifyPublishResult(result,
|
|
421
|
+
notifyPublishResult(result, source, ctx);
|
|
427
422
|
}
|
|
428
423
|
|
|
429
424
|
export default function registerReviewTable(
|
|
@@ -447,15 +442,41 @@ export default function registerReviewTable(
|
|
|
447
442
|
}
|
|
448
443
|
restoreCompletedReviewBranch(completedReviews, ctx.sessionManager.getBranch(), session);
|
|
449
444
|
};
|
|
450
|
-
|
|
451
|
-
| {
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
445
|
+
type PendingCompletion =
|
|
446
|
+
| { readonly record: CompletedReviewRecord; readonly session?: CompletedReviewSessionIdentity }
|
|
447
|
+
| { readonly error: string };
|
|
448
|
+
let pendingCompletion: PendingCompletion | undefined;
|
|
449
|
+
const completionError = (invocation: ReviewInvocation, failure?: string): PendingCompletion | undefined => {
|
|
450
|
+
const decision = decideReviewPublication(invocation);
|
|
451
|
+
const error = decision.error ?? (decision.publish ? failure : undefined);
|
|
452
|
+
return error ? { error } : undefined;
|
|
453
|
+
};
|
|
454
|
+
const resolveCompletion = async (
|
|
455
|
+
parsed: ReturnType<typeof parsePublishableReview>,
|
|
456
|
+
invocation: ReviewInvocation,
|
|
457
|
+
ctx: ExtensionContext,
|
|
458
|
+
): Promise<PendingCompletion | undefined> => {
|
|
459
|
+
if (!parsed.review) return completionError(invocation, parsed.error ?? "final review JSON is invalid");
|
|
460
|
+
const bindingError = validateReviewInvocation(parsed.review, invocation);
|
|
461
|
+
if (bindingError) return completionError(invocation, bindingError);
|
|
462
|
+
if (!shouldPublishReview(parsed.review)) return completionError(invocation);
|
|
463
|
+
try {
|
|
464
|
+
const repository = await resolveRepositoryBinding(ctx.cwd);
|
|
465
|
+
// Cache before publication preflight; persist after Pi stores the assistant message.
|
|
466
|
+
const record = completedReviews.remember(parsed.review, invocation, repository);
|
|
467
|
+
const session = sessionIdentity(ctx);
|
|
468
|
+
if (!session) {
|
|
469
|
+
ctx.ui.notify("Completed review cache will not survive reload: session identity is unavailable", "warning");
|
|
470
|
+
}
|
|
471
|
+
return session ? { record, session } : { record };
|
|
472
|
+
} catch (error) {
|
|
473
|
+
ctx.ui.notify(`Completed review is not available to publish-only: ${String(error)}`, "warning");
|
|
474
|
+
return completionError(
|
|
475
|
+
invocation,
|
|
476
|
+
"its repository identity could not be established before caching; no publish-only cache is available. Rerun /pr-review when GitHub repository lookup is working.",
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
};
|
|
459
480
|
let outputRepairAttempted = false;
|
|
460
481
|
let outputRepairCancelled = false;
|
|
461
482
|
const telemetryTracker = new ReviewTelemetryTracker();
|
|
@@ -469,44 +490,24 @@ export default function registerReviewTable(
|
|
|
469
490
|
}
|
|
470
491
|
};
|
|
471
492
|
|
|
472
|
-
type
|
|
473
|
-
|
|
474
|
-
| { error: string };
|
|
475
|
-
const publishCachedReview = async (
|
|
493
|
+
type CachedReviewResolution = { record: CompletedReviewRecord } | { error: string };
|
|
494
|
+
const resolveCachedReview = async (
|
|
476
495
|
requestedPrNumber: number | undefined,
|
|
477
|
-
allowStaleOverride: boolean | undefined,
|
|
478
496
|
ctx: ExtensionContext,
|
|
479
|
-
): Promise<
|
|
480
|
-
let repository: RepositoryBinding;
|
|
497
|
+
): Promise<CachedReviewResolution> => {
|
|
481
498
|
try {
|
|
482
|
-
repository = await resolveRepositoryBinding(ctx.cwd);
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
? completedReviews.latest(repository)
|
|
488
|
-
: completedReviews.get(requestedPrNumber, repository);
|
|
489
|
-
if (!completed) {
|
|
499
|
+
const repository = await resolveRepositoryBinding(ctx.cwd);
|
|
500
|
+
const record = requestedPrNumber === undefined
|
|
501
|
+
? completedReviews.latest(repository)
|
|
502
|
+
: completedReviews.get(requestedPrNumber, repository);
|
|
503
|
+
if (record) return { record };
|
|
490
504
|
const target = requestedPrNumber === undefined ? "the latest PR" : `PR #${requestedPrNumber}`;
|
|
491
505
|
return {
|
|
492
506
|
error: `No completed review for ${target} is cached for this repository in the current extension session. Publishing never starts or reruns a review.`,
|
|
493
507
|
};
|
|
508
|
+
} catch (error) {
|
|
509
|
+
return { error: `Cannot resolve the current GitHub repository: ${String(error)}` };
|
|
494
510
|
}
|
|
495
|
-
const prNumber = completed.invocation.prNumber;
|
|
496
|
-
const headSha = completed.review.pr?.head_sha;
|
|
497
|
-
if (typeof headSha !== "string") return { error: "Cached PR review is missing pr.head_sha" };
|
|
498
|
-
const allowStale = allowStaleOverride ?? completed.invocation.allowStalePublish;
|
|
499
|
-
return {
|
|
500
|
-
result: await publishPullReview({
|
|
501
|
-
cwd: ctx.cwd,
|
|
502
|
-
prNumber,
|
|
503
|
-
headSha,
|
|
504
|
-
allowNonOpen: completed.invocation.allowNonOpen,
|
|
505
|
-
allowStale,
|
|
506
|
-
expectedRepository: completed.repository,
|
|
507
|
-
review: completed.review,
|
|
508
|
-
}),
|
|
509
|
-
};
|
|
510
511
|
};
|
|
511
512
|
|
|
512
513
|
pi.registerCommand("pr-review-publish", {
|
|
@@ -535,20 +536,15 @@ export default function registerReviewTable(
|
|
|
535
536
|
);
|
|
536
537
|
return;
|
|
537
538
|
}
|
|
538
|
-
const
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
ctx,
|
|
542
|
-
);
|
|
543
|
-
if ("error" in published) {
|
|
544
|
-
ctx.ui.notify(published.error, "error");
|
|
539
|
+
const resolved = await resolveCachedReview(parsed.prNumber, ctx);
|
|
540
|
+
if ("error" in resolved) {
|
|
541
|
+
ctx.ui.notify(resolved.error, "error");
|
|
545
542
|
return;
|
|
546
543
|
}
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
parsed.allowStale ? "
|
|
550
|
-
|
|
551
|
-
);
|
|
544
|
+
await publishCompletedReview(resolved.record, {
|
|
545
|
+
kind: "publish-command",
|
|
546
|
+
stalePolicy: parsed.allowStale ? "allow-stale" : "frozen",
|
|
547
|
+
}, ctx);
|
|
552
548
|
},
|
|
553
549
|
});
|
|
554
550
|
|
|
@@ -630,9 +626,9 @@ export default function registerReviewTable(
|
|
|
630
626
|
);
|
|
631
627
|
return { action: "handled" as const };
|
|
632
628
|
}
|
|
633
|
-
const
|
|
634
|
-
if ("error" in
|
|
635
|
-
else
|
|
629
|
+
const resolved = await resolveCachedReview(directPublish.prNumber, ctx);
|
|
630
|
+
if ("error" in resolved) ctx.ui.notify(resolved.error, "error");
|
|
631
|
+
else await publishCompletedReview(resolved.record, { kind: "direct-request" }, ctx);
|
|
636
632
|
return { action: "handled" as const };
|
|
637
633
|
}
|
|
638
634
|
if (loopCoordinator.phase() === "awaiting_confirmation") {
|
|
@@ -699,24 +695,21 @@ export default function registerReviewTable(
|
|
|
699
695
|
const pending = pendingCompletion;
|
|
700
696
|
pendingCompletion = undefined;
|
|
701
697
|
if (!pending) return;
|
|
702
|
-
if (
|
|
698
|
+
if ("error" in pending) {
|
|
699
|
+
ctx.ui.notify(`PR review was not posted: ${pending.error}`, "error");
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
if (pending.session) {
|
|
703
703
|
const currentSession = sessionIdentity(ctx);
|
|
704
|
-
if (
|
|
705
|
-
!currentSession ||
|
|
706
|
-
currentSession.id !== pending.session.id ||
|
|
707
|
-
currentSession.startedAt !== pending.session.startedAt
|
|
708
|
-
) {
|
|
704
|
+
if (!currentSession || currentSession.id !== pending.session.id || currentSession.startedAt !== pending.session.startedAt) {
|
|
709
705
|
ctx.ui.notify("Completed review was not persisted or posted because the session identity changed", "warning");
|
|
710
706
|
return;
|
|
711
707
|
}
|
|
712
708
|
const leaf = ctx.sessionManager.getLeafEntry();
|
|
713
|
-
const
|
|
714
|
-
? assistantText(leaf.message as { content?: MessagePart[] })
|
|
715
|
-
: "";
|
|
716
|
-
const leafReview = parsePublishableReview(leafText).review;
|
|
717
|
-
const reviewEntryId = leaf?.type === "message" && leaf.message.role === "assistant" && leafReview
|
|
718
|
-
? leaf.id
|
|
709
|
+
const leafReview = leaf?.type === "message" && leaf.message.role === "assistant"
|
|
710
|
+
? parsePublishableReview(assistantText(leaf.message as { content?: MessagePart[] })).review
|
|
719
711
|
: undefined;
|
|
712
|
+
const reviewEntryId = leafReview ? leaf?.id : undefined;
|
|
720
713
|
try {
|
|
721
714
|
// Persist before any GitHub preflight so a failed post always remains retryable.
|
|
722
715
|
pi.appendEntry(
|
|
@@ -727,7 +720,7 @@ export default function registerReviewTable(
|
|
|
727
720
|
ctx.ui.notify(`Completed review cache will not survive an extension reload: ${String(error)}`, "warning");
|
|
728
721
|
}
|
|
729
722
|
}
|
|
730
|
-
await
|
|
723
|
+
await publishCompletedReview(pending.record, { kind: "frozen-invocation" }, ctx);
|
|
731
724
|
});
|
|
732
725
|
|
|
733
726
|
pi.on("message_end", async (event, ctx) => {
|
|
@@ -777,7 +770,7 @@ export default function registerReviewTable(
|
|
|
777
770
|
return;
|
|
778
771
|
}
|
|
779
772
|
|
|
780
|
-
|
|
773
|
+
const publishable = active ? parsePublishableReview(text) : undefined;
|
|
781
774
|
if (active && !publishable?.review && !outputRepairAttempted) {
|
|
782
775
|
const error = publishable?.error ?? "final review JSON is invalid";
|
|
783
776
|
if (loopCoordinator.suspendToolsForRepair()) {
|
|
@@ -810,36 +803,19 @@ export default function registerReviewTable(
|
|
|
810
803
|
outputRepairCancelled = false;
|
|
811
804
|
persistTelemetry("terminal_response");
|
|
812
805
|
}
|
|
813
|
-
const review =
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
!validateReviewInvocation(publishable.review, invocation) &&
|
|
822
|
-
shouldPublishReview(publishable.review)
|
|
823
|
-
) {
|
|
824
|
-
try {
|
|
825
|
-
repository = await resolveRepositoryBinding(ctx.cwd);
|
|
826
|
-
// Cache before publication preflight; persist after Pi stores the assistant message.
|
|
827
|
-
record = completedReviews.remember(publishable.review, invocation, repository);
|
|
828
|
-
session = sessionIdentity(ctx);
|
|
829
|
-
if (!session) {
|
|
830
|
-
ctx.ui.notify("Completed review cache will not survive reload: session identity is unavailable", "warning");
|
|
831
|
-
}
|
|
832
|
-
} catch (error) {
|
|
833
|
-
ctx.ui.notify(`Completed review is not available to publish-only: ${String(error)}`, "warning");
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
pendingCompletion = { text, invocation, repository, record, session };
|
|
837
|
-
}
|
|
806
|
+
const review = publishable?.review
|
|
807
|
+
? publishable.review as Review
|
|
808
|
+
: active
|
|
809
|
+
? null
|
|
810
|
+
: text.trim()
|
|
811
|
+
? parseReview(text)
|
|
812
|
+
: null;
|
|
813
|
+
if (invocation) pendingCompletion = await resolveCompletion(publishable!, invocation, ctx);
|
|
838
814
|
if (!review) return; // not a renderable /pr-review JSON payload — leave untouched
|
|
839
815
|
|
|
840
816
|
// Keep raw JSON for automation; only prettify for interactive terminals.
|
|
841
817
|
if (ctx.mode !== "tui") return;
|
|
842
|
-
const nonText =
|
|
818
|
+
const nonText = event.message.content.filter((part) => part.type !== "text");
|
|
843
819
|
return {
|
|
844
820
|
message: {
|
|
845
821
|
...event.message,
|