carrick 0.3.92 → 0.3.94

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 (45) hide show
  1. package/README.md +2 -1
  2. package/dist/auth/oauth.d.ts +8 -0
  3. package/dist/auth/oauth.js +9 -1
  4. package/dist/auth/oauth.js.map +1 -1
  5. package/dist/auth/read.d.ts +5 -0
  6. package/dist/auth/read.js +11 -1
  7. package/dist/auth/read.js.map +1 -1
  8. package/dist/auth/run.d.ts +10 -0
  9. package/dist/auth/run.js +16 -0
  10. package/dist/auth/run.js.map +1 -1
  11. package/dist/init/connect.d.ts +19 -7
  12. package/dist/init/connect.js +29 -16
  13. package/dist/init/connect.js.map +1 -1
  14. package/dist/init/projects.d.ts +16 -3
  15. package/dist/init/projects.js +27 -18
  16. package/dist/init/projects.js.map +1 -1
  17. package/dist/init/remove.js +28 -5
  18. package/dist/init/remove.js.map +1 -1
  19. package/dist/init/repo-copies.d.ts +56 -0
  20. package/dist/init/repo-copies.js +241 -0
  21. package/dist/init/repo-copies.js.map +1 -0
  22. package/dist/init/repos.d.ts +27 -0
  23. package/dist/init/repos.js +67 -0
  24. package/dist/init/repos.js.map +1 -1
  25. package/dist/init/run.d.ts +109 -48
  26. package/dist/init/run.js +331 -154
  27. package/dist/init/run.js.map +1 -1
  28. package/dist/init/task-skills.d.ts +6 -6
  29. package/dist/init/task-skills.js +9 -9
  30. package/dist/init/task-skills.js.map +1 -1
  31. package/package.json +6 -6
  32. package/sidecar/dist/src/capture/check-probe.d.ts +6 -1
  33. package/sidecar/dist/src/capture/check-probe.js +7 -2
  34. package/sidecar/dist/src/capture/index.d.ts +1 -0
  35. package/sidecar/dist/src/capture/index.js +1 -0
  36. package/sidecar/dist/src/index.js +8 -2
  37. package/sidecar/dist/src/retype.d.ts +46 -4
  38. package/sidecar/dist/src/retype.js +108 -19
  39. package/sidecar/dist/src/type-inferrer.d.ts +33 -0
  40. package/sidecar/dist/src/type-inferrer.js +211 -1
  41. package/sidecar/dist/src/types.d.ts +20 -1
  42. package/sidecar/dist/src/unwidened.d.ts +101 -0
  43. package/sidecar/dist/src/unwidened.js +272 -0
  44. package/sidecar/dist/src/validators.d.ts +10 -0
  45. package/sidecar/dist/src/validators.js +1 -0
@@ -0,0 +1,101 @@
1
+ /**
2
+ * The unwidened reading of a producer's response (carrick#1516).
3
+ *
4
+ * A handler that returns `{ scope: row.parentId ? 'specific' : 'all' }` sends
5
+ * one of two strings, but its inferred return type says `scope: string`:
6
+ * TypeScript widens a literal that lands in a mutable position (an object
7
+ * property, an array element, a function's return). The index publishes that
8
+ * widened type, so a consumer declaring `scope: 'all' | 'specific'` is judged
9
+ * against a `string` the handler never sends.
10
+ *
11
+ * The published type stays what the compiler inferred. Beside it, this reads
12
+ * the SAME inference again with every literal on the handler's path marked
13
+ * `as const`, which is the compiler's own way of saying "keep this literal's
14
+ * type". A const-asserted literal is a regular literal type, and only fresh
15
+ * literal types widen, so the re-read inference is the handler's return with
16
+ * nothing widened: `'all' | 'specific'` for the conditional, `true`/`false`
17
+ * for a discriminant, `2 | 1` for a numeric choice. No rule of ours decides
18
+ * what a literal becomes; the compiler infers the return again.
19
+ *
20
+ * The judge uses the reading only to classify a mismatch the published type
21
+ * already raised: when this narrower type fits the consumer, the pair is
22
+ * reported as the producer's type being wider than what it sends, not as a
23
+ * break.
24
+ *
25
+ * Soundness rests on three things:
26
+ *
27
+ * - **A literal that feeds a mutable binding keeps its widening.** `let s =
28
+ * 'a'` can later hold `'b'`, so its type really is `string`; the literals
29
+ * that initialise a `let`/`var` are never marked. Nor is a parameter's
30
+ * default: it decides what callers may pass, and a caller the path does not
31
+ * reach could pass another value.
32
+ * - **No new diagnostic on the handler's path.** A marked literal that is
33
+ * later changed (an object built with `'a'` and then assigned `'b'`) makes
34
+ * the compiler report the assignment. Every file holding a function on the
35
+ * path is type-checked before and after, and any diagnostic the marking adds
36
+ * drops the reading for every request whose path includes that function.
37
+ * - **The re-read came from the same place.** The inference is re-run from
38
+ * the request, so its locator runs again; the reading is kept only when it
39
+ * read the same node it read the first time.
40
+ *
41
+ * The path is the function the inference read (or the function around the
42
+ * payload expression it read), plus every source function it calls whose
43
+ * return type is inferred rather than declared, transitively: a controller
44
+ * that returns `this.service.list()` sends what `list` returns. A callee with
45
+ * a declared return type is not followed; that declaration is the contract.
46
+ */
47
+ import { Node } from 'ts-morph';
48
+ import type { SourceFile } from 'ts-morph';
49
+ /** One insertion into a file's ORIGINAL text. */
50
+ export interface Insertion {
51
+ pos: number;
52
+ text: string;
53
+ /**
54
+ * An opener sits before the literal it wraps, a closer after it. At one
55
+ * position a closer (ending the previous literal) comes before an opener.
56
+ */
57
+ closes: boolean;
58
+ }
59
+ /** A function on a request's path, by its original span. */
60
+ export interface PathFunction {
61
+ file: SourceFile;
62
+ start: number;
63
+ end: number;
64
+ }
65
+ /** One diagnostic a file's type-check reported. */
66
+ export interface FileDiagnostic {
67
+ /** Start position in the file it was reported on. */
68
+ start: number;
69
+ code: number;
70
+ message: string;
71
+ }
72
+ /**
73
+ * The functions on the path of a read node: the function it is (or sits in),
74
+ * then every un-annotated source function called from those, breadth first.
75
+ * A read node outside any function is its own path.
76
+ */
77
+ export declare function pathOf(read: Node): Node[];
78
+ /**
79
+ * The insertions that mark every literal inside `fn` whose widening the
80
+ * reading drops. Positions are original-file positions.
81
+ */
82
+ export declare function literalInsertions(fn: Node): Insertion[];
83
+ /** Deduplicated, in text order (a closer before an opener at one position). */
84
+ export declare function normalise(insertions: Insertion[]): Insertion[];
85
+ export declare function applyInsertions(text: string, insertions: Insertion[]): string;
86
+ /**
87
+ * Where an original position lands in the rewritten text. A START keeps an
88
+ * opener at its own position outside (so a span starting on a marked literal
89
+ * covers its parentheses); an END takes every insertion at its position in.
90
+ */
91
+ export declare function mapForward(pos: number, insertions: Insertion[], side: 'start' | 'end'): number;
92
+ /** The original position a rewritten one came from; inside an insertion, its position. */
93
+ export declare function mapBack(pos: number, insertions: Insertion[]): number;
94
+ /** Syntactic and semantic diagnostics reported in this file. */
95
+ export declare function fileDiagnostics(sourceFile: SourceFile): FileDiagnostic[];
96
+ /**
97
+ * Original positions of the diagnostics `after` holds that `before` does not,
98
+ * matched by original position and code. A diagnostic whose message changed
99
+ * because a type narrowed is the same diagnostic.
100
+ */
101
+ export declare function addedDiagnostics(before: FileDiagnostic[], after: FileDiagnostic[], insertions: Insertion[]): number[];
@@ -0,0 +1,272 @@
1
+ /**
2
+ * The unwidened reading of a producer's response (carrick#1516).
3
+ *
4
+ * A handler that returns `{ scope: row.parentId ? 'specific' : 'all' }` sends
5
+ * one of two strings, but its inferred return type says `scope: string`:
6
+ * TypeScript widens a literal that lands in a mutable position (an object
7
+ * property, an array element, a function's return). The index publishes that
8
+ * widened type, so a consumer declaring `scope: 'all' | 'specific'` is judged
9
+ * against a `string` the handler never sends.
10
+ *
11
+ * The published type stays what the compiler inferred. Beside it, this reads
12
+ * the SAME inference again with every literal on the handler's path marked
13
+ * `as const`, which is the compiler's own way of saying "keep this literal's
14
+ * type". A const-asserted literal is a regular literal type, and only fresh
15
+ * literal types widen, so the re-read inference is the handler's return with
16
+ * nothing widened: `'all' | 'specific'` for the conditional, `true`/`false`
17
+ * for a discriminant, `2 | 1` for a numeric choice. No rule of ours decides
18
+ * what a literal becomes; the compiler infers the return again.
19
+ *
20
+ * The judge uses the reading only to classify a mismatch the published type
21
+ * already raised: when this narrower type fits the consumer, the pair is
22
+ * reported as the producer's type being wider than what it sends, not as a
23
+ * break.
24
+ *
25
+ * Soundness rests on three things:
26
+ *
27
+ * - **A literal that feeds a mutable binding keeps its widening.** `let s =
28
+ * 'a'` can later hold `'b'`, so its type really is `string`; the literals
29
+ * that initialise a `let`/`var` are never marked. Nor is a parameter's
30
+ * default: it decides what callers may pass, and a caller the path does not
31
+ * reach could pass another value.
32
+ * - **No new diagnostic on the handler's path.** A marked literal that is
33
+ * later changed (an object built with `'a'` and then assigned `'b'`) makes
34
+ * the compiler report the assignment. Every file holding a function on the
35
+ * path is type-checked before and after, and any diagnostic the marking adds
36
+ * drops the reading for every request whose path includes that function.
37
+ * - **The re-read came from the same place.** The inference is re-run from
38
+ * the request, so its locator runs again; the reading is kept only when it
39
+ * read the same node it read the first time.
40
+ *
41
+ * The path is the function the inference read (or the function around the
42
+ * payload expression it read), plus every source function it calls whose
43
+ * return type is inferred rather than declared, transitively: a controller
44
+ * that returns `this.service.list()` sends what `list` returns. A callee with
45
+ * a declared return type is not followed; that declaration is the contract.
46
+ */
47
+ import { Node, SyntaxKind, ts } from 'ts-morph';
48
+ /** How many calls deep the path follows an un-annotated callee. */
49
+ const MAX_FOLLOW_DEPTH = 3;
50
+ /** Functions one request's path may hold before following stops. */
51
+ const MAX_PATH_FUNCTIONS = 32;
52
+ const OPEN = '(';
53
+ const CLOSE = ' as const)';
54
+ /**
55
+ * The functions on the path of a read node: the function it is (or sits in),
56
+ * then every un-annotated source function called from those, breadth first.
57
+ * A read node outside any function is its own path.
58
+ */
59
+ export function pathOf(read) {
60
+ const root = isFunctionWithBody(read) ? read : read.getFirstAncestor(isFunctionWithBody) ?? read;
61
+ const seen = new Set([root]);
62
+ const out = [root];
63
+ let frontier = [root];
64
+ for (let depth = 0; depth < MAX_FOLLOW_DEPTH && frontier.length > 0; depth++) {
65
+ const next = [];
66
+ for (const fn of frontier) {
67
+ for (const callee of calleesOf(fn)) {
68
+ if (seen.has(callee) || out.length >= MAX_PATH_FUNCTIONS)
69
+ continue;
70
+ seen.add(callee);
71
+ out.push(callee);
72
+ next.push(callee);
73
+ }
74
+ }
75
+ frontier = next;
76
+ }
77
+ return out;
78
+ }
79
+ /**
80
+ * The source functions `fn` calls whose return type the compiler inferred. A
81
+ * declared return type is the callee's contract: nothing in it was widened,
82
+ * and marking its literals could only cost the reading a diagnostic.
83
+ */
84
+ function calleesOf(fn) {
85
+ const out = [];
86
+ for (const call of fn.getDescendantsOfKind(SyntaxKind.CallExpression)) {
87
+ const node = call.getProject().getTypeChecker().getResolvedSignature(call)?.getDeclaration();
88
+ if (!node || !isFunctionWithBody(node) || hasDeclaredReturn(node))
89
+ continue;
90
+ const file = node.getSourceFile();
91
+ if (file.isDeclarationFile() || file.isFromExternalLibrary() || file.isInNodeModules())
92
+ continue;
93
+ out.push(node);
94
+ }
95
+ return out;
96
+ }
97
+ function isFunctionWithBody(node) {
98
+ return ((Node.isFunctionDeclaration(node) ||
99
+ Node.isMethodDeclaration(node) ||
100
+ Node.isArrowFunction(node) ||
101
+ Node.isFunctionExpression(node)) &&
102
+ node.getBody() !== undefined);
103
+ }
104
+ function hasDeclaredReturn(node) {
105
+ return ((Node.isFunctionDeclaration(node) ||
106
+ Node.isMethodDeclaration(node) ||
107
+ Node.isArrowFunction(node) ||
108
+ Node.isFunctionExpression(node)) &&
109
+ node.getReturnTypeNode() !== undefined);
110
+ }
111
+ /**
112
+ * The insertions that mark every literal inside `fn` whose widening the
113
+ * reading drops. Positions are original-file positions.
114
+ */
115
+ export function literalInsertions(fn) {
116
+ const out = [];
117
+ const visit = (node) => {
118
+ // A type states no value, and a parameter's default decides what its
119
+ // callers may pass, not what the function returns.
120
+ if (Node.isTypeNode(node) || Node.isParameterDeclaration(node))
121
+ return;
122
+ if (isMarkableLiteral(node)) {
123
+ out.push({ pos: node.getStart(), text: OPEN, closes: false });
124
+ out.push({ pos: node.getEnd(), text: CLOSE, closes: true });
125
+ return;
126
+ }
127
+ node.forEachChild(visit);
128
+ };
129
+ visit(fn);
130
+ return out;
131
+ }
132
+ /** Whether `node` is a literal value the reading marks `as const`. */
133
+ function isMarkableLiteral(node) {
134
+ const kind = node.getKind();
135
+ const literal = kind === SyntaxKind.StringLiteral ||
136
+ kind === SyntaxKind.NumericLiteral ||
137
+ kind === SyntaxKind.BigIntLiteral ||
138
+ kind === SyntaxKind.NoSubstitutionTemplateLiteral ||
139
+ kind === SyntaxKind.TrueKeyword ||
140
+ kind === SyntaxKind.FalseKeyword ||
141
+ // `-1` is marked whole: `-(1 as const)` is a `number`, and the visit
142
+ // never reaches the `1` inside it.
143
+ (Node.isPrefixUnaryExpression(node) &&
144
+ node.getOperatorToken() === SyntaxKind.MinusToken &&
145
+ (Node.isNumericLiteral(node.getOperand()) || Node.isBigIntLiteral(node.getOperand())));
146
+ if (!literal)
147
+ return false;
148
+ const parent = node.getParent();
149
+ if (!parent)
150
+ return false;
151
+ // Syntax, not a value: a quoted property name, a tagged template's text.
152
+ if (parent.getNameNode?.() === node)
153
+ return false;
154
+ if (Node.isTaggedTemplateExpression(parent))
155
+ return false;
156
+ return !initialisesMutableBinding(node);
157
+ }
158
+ /**
159
+ * Whether the literal becomes the value of a `let`/`var` binding, which can
160
+ * later hold another one, so its type really is the widened one. Reached
161
+ * through the expressions that pass a value through unchanged.
162
+ */
163
+ function initialisesMutableBinding(literal) {
164
+ let node = literal;
165
+ for (;;) {
166
+ const parent = node.getParent();
167
+ if (!parent)
168
+ return false;
169
+ if (Node.isParenthesizedExpression(parent) ||
170
+ (Node.isConditionalExpression(parent) && parent.getCondition() !== node) ||
171
+ (Node.isBinaryExpression(parent) && passesOperandThrough(parent.getOperatorToken().getKind()))) {
172
+ node = parent;
173
+ continue;
174
+ }
175
+ if (!Node.isVariableDeclaration(parent) || parent.getInitializer() !== node)
176
+ return false;
177
+ const list = parent.getParent();
178
+ return Node.isVariableDeclarationList(list) && (list.getFlags() & ts.NodeFlags.Const) === 0;
179
+ }
180
+ }
181
+ /** Binary operators whose value is one of their operands. */
182
+ function passesOperandThrough(kind) {
183
+ return (kind === SyntaxKind.BarBarToken ||
184
+ kind === SyntaxKind.QuestionQuestionToken ||
185
+ kind === SyntaxKind.AmpersandAmpersandToken ||
186
+ kind === SyntaxKind.CommaToken);
187
+ }
188
+ /** Deduplicated, in text order (a closer before an opener at one position). */
189
+ export function normalise(insertions) {
190
+ const seen = new Set();
191
+ const out = [];
192
+ for (const insertion of insertions) {
193
+ const k = `${insertion.pos}:${insertion.closes}`;
194
+ if (seen.has(k))
195
+ continue;
196
+ seen.add(k);
197
+ out.push(insertion);
198
+ }
199
+ return out.sort((a, b) => a.pos - b.pos || Number(b.closes) - Number(a.closes));
200
+ }
201
+ export function applyInsertions(text, insertions) {
202
+ let out = '';
203
+ let cursor = 0;
204
+ for (const insertion of insertions) {
205
+ out += text.slice(cursor, insertion.pos) + insertion.text;
206
+ cursor = insertion.pos;
207
+ }
208
+ return out + text.slice(cursor);
209
+ }
210
+ /**
211
+ * Where an original position lands in the rewritten text. A START keeps an
212
+ * opener at its own position outside (so a span starting on a marked literal
213
+ * covers its parentheses); an END takes every insertion at its position in.
214
+ */
215
+ export function mapForward(pos, insertions, side) {
216
+ let shift = 0;
217
+ for (const insertion of insertions) {
218
+ if (insertion.pos < pos || (insertion.pos === pos && (side === 'end' || insertion.closes))) {
219
+ shift += insertion.text.length;
220
+ }
221
+ }
222
+ return pos + shift;
223
+ }
224
+ /** The original position a rewritten one came from; inside an insertion, its position. */
225
+ export function mapBack(pos, insertions) {
226
+ let shift = 0;
227
+ for (const insertion of insertions) {
228
+ const at = insertion.pos + shift;
229
+ if (pos < at)
230
+ break;
231
+ if (pos < at + insertion.text.length)
232
+ return insertion.pos;
233
+ shift += insertion.text.length;
234
+ }
235
+ return pos - shift;
236
+ }
237
+ /** Syntactic and semantic diagnostics reported in this file. */
238
+ export function fileDiagnostics(sourceFile) {
239
+ const program = sourceFile.getProject().getProgram().compilerObject;
240
+ const node = sourceFile.compilerNode;
241
+ return [...program.getSyntacticDiagnostics(node), ...program.getSemanticDiagnostics(node)]
242
+ .filter((d) => d.file === node && d.start !== undefined)
243
+ .map((d) => ({
244
+ start: d.start,
245
+ code: d.code,
246
+ message: ts.flattenDiagnosticMessageText(d.messageText, ' '),
247
+ }));
248
+ }
249
+ /**
250
+ * Original positions of the diagnostics `after` holds that `before` does not,
251
+ * matched by original position and code. A diagnostic whose message changed
252
+ * because a type narrowed is the same diagnostic.
253
+ */
254
+ export function addedDiagnostics(before, after, insertions) {
255
+ const remaining = new Map();
256
+ for (const d of before) {
257
+ const k = `${d.start}:${d.code}`;
258
+ remaining.set(k, (remaining.get(k) ?? 0) + 1);
259
+ }
260
+ const added = [];
261
+ for (const d of after) {
262
+ const start = mapBack(d.start, insertions);
263
+ const k = `${start}:${d.code}`;
264
+ const left = remaining.get(k) ?? 0;
265
+ if (left > 0) {
266
+ remaining.set(k, left - 1);
267
+ continue;
268
+ }
269
+ added.push(start);
270
+ }
271
+ return added;
272
+ }
@@ -1142,6 +1142,7 @@ export declare const RetypeCheckRequestSchema: z.ZodObject<{
1142
1142
  expression_text: z.ZodOptional<z.ZodString>;
1143
1143
  expression_line: z.ZodOptional<z.ZodNumber>;
1144
1144
  producer_type: z.ZodString;
1145
+ producer_unwidened_type: z.ZodOptional<z.ZodString>;
1145
1146
  wire: z.ZodBoolean;
1146
1147
  }, "strip", z.ZodTypeAny, {
1147
1148
  wire: boolean;
@@ -1153,6 +1154,7 @@ export declare const RetypeCheckRequestSchema: z.ZodObject<{
1153
1154
  span_end?: number | undefined;
1154
1155
  expression_text?: string | undefined;
1155
1156
  expression_line?: number | undefined;
1157
+ producer_unwidened_type?: string | undefined;
1156
1158
  }, {
1157
1159
  wire: boolean;
1158
1160
  file_path: string;
@@ -1163,6 +1165,7 @@ export declare const RetypeCheckRequestSchema: z.ZodObject<{
1163
1165
  span_end?: number | undefined;
1164
1166
  expression_text?: string | undefined;
1165
1167
  expression_line?: number | undefined;
1168
+ producer_unwidened_type?: string | undefined;
1166
1169
  }>, "many">;
1167
1170
  budget_ms: z.ZodOptional<z.ZodNumber>;
1168
1171
  }, "strip", z.ZodTypeAny, {
@@ -1178,6 +1181,7 @@ export declare const RetypeCheckRequestSchema: z.ZodObject<{
1178
1181
  span_end?: number | undefined;
1179
1182
  expression_text?: string | undefined;
1180
1183
  expression_line?: number | undefined;
1184
+ producer_unwidened_type?: string | undefined;
1181
1185
  }[];
1182
1186
  budget_ms?: number | undefined;
1183
1187
  }, {
@@ -1193,6 +1197,7 @@ export declare const RetypeCheckRequestSchema: z.ZodObject<{
1193
1197
  span_end?: number | undefined;
1194
1198
  expression_text?: string | undefined;
1195
1199
  expression_line?: number | undefined;
1200
+ producer_unwidened_type?: string | undefined;
1196
1201
  }[];
1197
1202
  budget_ms?: number | undefined;
1198
1203
  }>;
@@ -2247,6 +2252,7 @@ export declare const SidecarRequestSchema: z.ZodDiscriminatedUnion<"action", [z.
2247
2252
  expression_text: z.ZodOptional<z.ZodString>;
2248
2253
  expression_line: z.ZodOptional<z.ZodNumber>;
2249
2254
  producer_type: z.ZodString;
2255
+ producer_unwidened_type: z.ZodOptional<z.ZodString>;
2250
2256
  wire: z.ZodBoolean;
2251
2257
  }, "strip", z.ZodTypeAny, {
2252
2258
  wire: boolean;
@@ -2258,6 +2264,7 @@ export declare const SidecarRequestSchema: z.ZodDiscriminatedUnion<"action", [z.
2258
2264
  span_end?: number | undefined;
2259
2265
  expression_text?: string | undefined;
2260
2266
  expression_line?: number | undefined;
2267
+ producer_unwidened_type?: string | undefined;
2261
2268
  }, {
2262
2269
  wire: boolean;
2263
2270
  file_path: string;
@@ -2268,6 +2275,7 @@ export declare const SidecarRequestSchema: z.ZodDiscriminatedUnion<"action", [z.
2268
2275
  span_end?: number | undefined;
2269
2276
  expression_text?: string | undefined;
2270
2277
  expression_line?: number | undefined;
2278
+ producer_unwidened_type?: string | undefined;
2271
2279
  }>, "many">;
2272
2280
  budget_ms: z.ZodOptional<z.ZodNumber>;
2273
2281
  }, "strip", z.ZodTypeAny, {
@@ -2283,6 +2291,7 @@ export declare const SidecarRequestSchema: z.ZodDiscriminatedUnion<"action", [z.
2283
2291
  span_end?: number | undefined;
2284
2292
  expression_text?: string | undefined;
2285
2293
  expression_line?: number | undefined;
2294
+ producer_unwidened_type?: string | undefined;
2286
2295
  }[];
2287
2296
  budget_ms?: number | undefined;
2288
2297
  }, {
@@ -2298,6 +2307,7 @@ export declare const SidecarRequestSchema: z.ZodDiscriminatedUnion<"action", [z.
2298
2307
  span_end?: number | undefined;
2299
2308
  expression_text?: string | undefined;
2300
2309
  expression_line?: number | undefined;
2310
+ producer_unwidened_type?: string | undefined;
2301
2311
  }[];
2302
2312
  budget_ms?: number | undefined;
2303
2313
  }>, z.ZodObject<{
@@ -292,6 +292,7 @@ const RetypeItemSchema = z.object({
292
292
  expression_text: z.string().optional(),
293
293
  expression_line: z.number().int().positive().optional(),
294
294
  producer_type: z.string().min(1),
295
+ producer_unwidened_type: z.string().min(1).optional(),
295
296
  wire: z.boolean(),
296
297
  });
297
298
  export const RetypeCheckRequestSchema = BaseRequestSchema.extend({