@mrclrchtr/supi-review 1.4.0 → 1.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 (43) hide show
  1. package/README.md +53 -59
  2. package/package.json +2 -9
  3. package/src/git.ts +107 -1
  4. package/src/history/collect.ts +210 -0
  5. package/src/history/synthesize.ts +109 -0
  6. package/src/model.ts +100 -0
  7. package/src/review.ts +204 -342
  8. package/src/target/packet.ts +216 -0
  9. package/src/tool/brief-runner.ts +269 -0
  10. package/src/tool/review-runner.ts +434 -0
  11. package/src/tool/runner-types.ts +29 -12
  12. package/src/tool/schemas.ts +31 -0
  13. package/src/types.ts +87 -48
  14. package/src/ui/flow.ts +302 -0
  15. package/src/ui/format-content.ts +22 -16
  16. package/src/ui/progress-widget.ts +40 -40
  17. package/src/ui/renderer.ts +38 -21
  18. package/src/ui/theme-type.ts +16 -0
  19. package/node_modules/@mrclrchtr/supi-core/README.md +0 -107
  20. package/node_modules/@mrclrchtr/supi-core/package.json +0 -44
  21. package/node_modules/@mrclrchtr/supi-core/src/api.ts +0 -83
  22. package/node_modules/@mrclrchtr/supi-core/src/config/config-settings.ts +0 -76
  23. package/node_modules/@mrclrchtr/supi-core/src/config/config.ts +0 -186
  24. package/node_modules/@mrclrchtr/supi-core/src/context/context-messages.ts +0 -119
  25. package/node_modules/@mrclrchtr/supi-core/src/context/context-provider-registry.ts +0 -36
  26. package/node_modules/@mrclrchtr/supi-core/src/context/context-tag.ts +0 -31
  27. package/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +0 -255
  28. package/node_modules/@mrclrchtr/supi-core/src/extension.ts +0 -1
  29. package/node_modules/@mrclrchtr/supi-core/src/index.ts +0 -83
  30. package/node_modules/@mrclrchtr/supi-core/src/project-roots.ts +0 -170
  31. package/node_modules/@mrclrchtr/supi-core/src/registry-utils.ts +0 -54
  32. package/node_modules/@mrclrchtr/supi-core/src/session-utils.ts +0 -29
  33. package/node_modules/@mrclrchtr/supi-core/src/settings/settings-command.ts +0 -15
  34. package/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +0 -41
  35. package/node_modules/@mrclrchtr/supi-core/src/settings/settings-ui.ts +0 -226
  36. package/node_modules/@mrclrchtr/supi-core/src/terminal.ts +0 -60
  37. package/src/briefs.ts +0 -101
  38. package/src/profiles.ts +0 -52
  39. package/src/prompts.ts +0 -116
  40. package/src/settings.ts +0 -246
  41. package/src/tool/runner.ts +0 -432
  42. package/src/tool/target-resolution.ts +0 -102
  43. package/src/ui/ui.ts +0 -208
package/src/model.ts ADDED
@@ -0,0 +1,100 @@
1
+ import type { Model } from "@earendil-works/pi-ai";
2
+ import { type ExtensionContext, SettingsManager } from "@earendil-works/pi-coding-agent";
3
+ import type { ReviewModelSelection } from "./types.ts";
4
+
5
+ /** Build the canonical `provider/modelId` string used throughout the review flow. */
6
+ export function toCanonicalModelId(
7
+ model: Pick<NonNullable<ExtensionContext["model"]>, "provider" | "id">,
8
+ ): string {
9
+ return `${model.provider}/${model.id}`;
10
+ }
11
+
12
+ /**
13
+ * List review models using Pi's scoped model configuration only.
14
+ *
15
+ * If no scoped model patterns are configured, the review picker is intentionally empty.
16
+ */
17
+ export function getSelectableReviewModels(
18
+ ctx: Pick<ExtensionContext, "cwd" | "modelRegistry" | "model">,
19
+ enabledModelPatterns = SettingsManager.create(ctx.cwd).getEnabledModels(),
20
+ ): ReviewModelSelection[] {
21
+ if (!enabledModelPatterns || enabledModelPatterns.length === 0) {
22
+ return [];
23
+ }
24
+
25
+ const byCanonicalId = new Map<string, ReviewModelSelection>();
26
+ const availableModels = filterByEnabledModels(
27
+ enabledModelPatterns,
28
+ ctx.modelRegistry.getAvailable(),
29
+ );
30
+
31
+ const addModel = (
32
+ // biome-ignore lint/suspicious/noExplicitAny: Model<any> is pi's canonical type
33
+ model: Model<any>,
34
+ isCurrent: boolean,
35
+ ) => {
36
+ const canonicalId = toCanonicalModelId(model);
37
+ const existing = byCanonicalId.get(canonicalId);
38
+ if (existing) {
39
+ if (isCurrent) existing.isCurrent = true;
40
+ return;
41
+ }
42
+
43
+ byCanonicalId.set(canonicalId, {
44
+ canonicalId,
45
+ provider: model.provider,
46
+ id: model.id,
47
+ model,
48
+ label: model.name ?? canonicalId,
49
+ description: canonicalId,
50
+ isCurrent,
51
+ });
52
+ };
53
+
54
+ if (ctx.model && matchModelPatterns(ctx.model, enabledModelPatterns)) {
55
+ addModel(ctx.model, true);
56
+ }
57
+
58
+ for (const model of availableModels) {
59
+ addModel(
60
+ model,
61
+ ctx.model ? toCanonicalModelId(model) === toCanonicalModelId(ctx.model) : false,
62
+ );
63
+ }
64
+
65
+ return Array.from(byCanonicalId.values()).sort((a, b) => {
66
+ if (a.isCurrent !== b.isCurrent) return a.isCurrent ? -1 : 1;
67
+ return a.canonicalId.localeCompare(b.canonicalId);
68
+ });
69
+ }
70
+
71
+ function filterByEnabledModels<T extends { provider: string; id: string }>(
72
+ patterns: string[],
73
+ models: T[],
74
+ ): T[] {
75
+ return models.filter((model) => matchModelPatterns(model, patterns));
76
+ }
77
+
78
+ function matchModelPatterns(model: { provider: string; id: string }, patterns: string[]): boolean {
79
+ return patterns.some((pattern) => matchModelPattern(model, pattern));
80
+ }
81
+
82
+ function matchModelPattern(model: { provider: string; id: string }, pattern: string): boolean {
83
+ const canonicalId = `${model.provider}/${model.id}`;
84
+ if (pattern.includes("/")) {
85
+ return simpleGlobMatch(canonicalId, pattern);
86
+ }
87
+ return simpleGlobMatch(model.id, pattern) || simpleGlobMatch(canonicalId, pattern);
88
+ }
89
+
90
+ function simpleGlobMatch(text: string, pattern: string): boolean {
91
+ if (!pattern.includes("*") && !pattern.includes("?")) {
92
+ return text.toLowerCase() === pattern.toLowerCase();
93
+ }
94
+
95
+ const regex = pattern
96
+ .replace(/[.+^${}()|[\]\\]/g, "\\$&")
97
+ .replace(/\*/g, ".*")
98
+ .replace(/\?/g, ".");
99
+ return new RegExp(`^${regex}$`, "i").test(text);
100
+ }