carrick 0.3.53
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/LICENSE.md +99 -0
- package/README.md +79 -0
- package/bin/carrick.mjs +168 -0
- package/dist/channel.d.ts +16 -0
- package/dist/channel.js +37 -0
- package/dist/channel.js.map +1 -0
- package/dist/cli.d.ts +29 -0
- package/dist/cli.js +60 -0
- package/dist/cli.js.map +1 -0
- package/dist/contract.d.ts +154 -0
- package/dist/contract.js +141 -0
- package/dist/contract.js.map +1 -0
- package/dist/diagnostics.d.ts +54 -0
- package/dist/diagnostics.js +199 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/hook/post-edit.d.ts +13 -0
- package/dist/hook/post-edit.js +76 -0
- package/dist/hook/post-edit.js.map +1 -0
- package/dist/hook/session-start.d.ts +2 -0
- package/dist/hook/session-start.js +44 -0
- package/dist/hook/session-start.js.map +1 -0
- package/dist/init/identity.d.ts +20 -0
- package/dist/init/identity.js +60 -0
- package/dist/init/identity.js.map +1 -0
- package/dist/init/repos.d.ts +19 -0
- package/dist/init/repos.js +46 -0
- package/dist/init/repos.js.map +1 -0
- package/dist/init/run.d.ts +11 -0
- package/dist/init/run.js +228 -0
- package/dist/init/run.js.map +1 -0
- package/dist/init/settings.d.ts +50 -0
- package/dist/init/settings.js +138 -0
- package/dist/init/settings.js.map +1 -0
- package/dist/log.d.ts +2 -0
- package/dist/log.js +35 -0
- package/dist/log.js.map +1 -0
- package/dist/native.d.ts +48 -0
- package/dist/native.js +127 -0
- package/dist/native.js.map +1 -0
- package/dist/render.d.ts +65 -0
- package/dist/render.js +334 -0
- package/dist/render.js.map +1 -0
- package/dist/root.d.ts +30 -0
- package/dist/root.js +82 -0
- package/dist/root.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +255 -0
- package/dist/server.js.map +1 -0
- package/dist/templates.d.ts +18 -0
- package/dist/templates.js +66 -0
- package/dist/templates.js.map +1 -0
- package/package.json +72 -0
- package/plugin/.claude-plugin/plugin.json +6 -0
- package/plugin/.lsp.json +14 -0
- package/plugin/hooks/hooks.json +27 -0
- package/sidecar/dist/src/bundler.d.ts +141 -0
- package/sidecar/dist/src/bundler.js +680 -0
- package/sidecar/dist/src/capture/anchors.d.ts +61 -0
- package/sidecar/dist/src/capture/anchors.js +1132 -0
- package/sidecar/dist/src/capture/api.d.ts +378 -0
- package/sidecar/dist/src/capture/api.js +10 -0
- package/sidecar/dist/src/capture/augmentations.d.ts +20 -0
- package/sidecar/dist/src/capture/augmentations.js +60 -0
- package/sidecar/dist/src/capture/check-classify.d.ts +58 -0
- package/sidecar/dist/src/capture/check-classify.js +189 -0
- package/sidecar/dist/src/capture/check-deep.d.ts +32 -0
- package/sidecar/dist/src/capture/check-deep.js +91 -0
- package/sidecar/dist/src/capture/check-poison.d.ts +40 -0
- package/sidecar/dist/src/capture/check-poison.js +155 -0
- package/sidecar/dist/src/capture/check-probe.d.ts +70 -0
- package/sidecar/dist/src/capture/check-probe.js +147 -0
- package/sidecar/dist/src/capture/check-scrub.d.ts +31 -0
- package/sidecar/dist/src/capture/check-scrub.js +71 -0
- package/sidecar/dist/src/capture/check-workspace.d.ts +52 -0
- package/sidecar/dist/src/capture/check-workspace.js +218 -0
- package/sidecar/dist/src/capture/check.d.ts +39 -0
- package/sidecar/dist/src/capture/check.js +450 -0
- package/sidecar/dist/src/capture/deep-walk.d.ts +62 -0
- package/sidecar/dist/src/capture/deep-walk.js +243 -0
- package/sidecar/dist/src/capture/index.d.ts +36 -0
- package/sidecar/dist/src/capture/index.js +477 -0
- package/sidecar/dist/src/capture/lockfile.d.ts +48 -0
- package/sidecar/dist/src/capture/lockfile.js +490 -0
- package/sidecar/dist/src/capture/machinery.d.ts +59 -0
- package/sidecar/dist/src/capture/machinery.js +160 -0
- package/sidecar/dist/src/capture/node-builder.d.ts +37 -0
- package/sidecar/dist/src/capture/node-builder.js +123 -0
- package/sidecar/dist/src/capture/paths-rewrite.d.ts +34 -0
- package/sidecar/dist/src/capture/paths-rewrite.js +100 -0
- package/sidecar/dist/src/capture/self-check.d.ts +38 -0
- package/sidecar/dist/src/capture/self-check.js +317 -0
- package/sidecar/dist/src/capture/specifiers.d.ts +39 -0
- package/sidecar/dist/src/capture/specifiers.js +56 -0
- package/sidecar/dist/src/definition-resolver.d.ts +57 -0
- package/sidecar/dist/src/definition-resolver.js +153 -0
- package/sidecar/dist/src/index.d.ts +14 -0
- package/sidecar/dist/src/index.js +564 -0
- package/sidecar/dist/src/monorepo-builder.d.ts +129 -0
- package/sidecar/dist/src/monorepo-builder.js +584 -0
- package/sidecar/dist/src/project-loader.d.ts +130 -0
- package/sidecar/dist/src/project-loader.js +399 -0
- package/sidecar/dist/src/type-inferrer.d.ts +940 -0
- package/sidecar/dist/src/type-inferrer.js +3540 -0
- package/sidecar/dist/src/type-structural-expander.d.ts +61 -0
- package/sidecar/dist/src/type-structural-expander.js +283 -0
- package/sidecar/dist/src/type-text-canonicalizer.d.ts +40 -0
- package/sidecar/dist/src/type-text-canonicalizer.js +297 -0
- package/sidecar/dist/src/types.d.ts +669 -0
- package/sidecar/dist/src/types.js +5 -0
- package/sidecar/dist/src/validators.d.ts +2214 -0
- package/sidecar/dist/src/validators.js +336 -0
- package/sidecar/package.json +6 -0
- package/templates/carrick.json +7 -0
- package/templates/carrick.yml +45 -0
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod validators for the sidecar message protocol
|
|
3
|
+
* These validators ensure incoming JSON messages are correctly typed
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// Inference Kind Schema
|
|
8
|
+
// ============================================================================
|
|
9
|
+
export const InferKindSchema = z.enum([
|
|
10
|
+
'function_return',
|
|
11
|
+
'expression',
|
|
12
|
+
'call_result',
|
|
13
|
+
'variable',
|
|
14
|
+
'response_body',
|
|
15
|
+
'request_body',
|
|
16
|
+
'signature_return',
|
|
17
|
+
'function_param',
|
|
18
|
+
'receiver_type',
|
|
19
|
+
]);
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// Extraction Config Schemas (New)
|
|
22
|
+
// ============================================================================
|
|
23
|
+
const ExtractionRuleSchema = z.object({
|
|
24
|
+
wrapperSymbols: z.array(z.string()).optional(),
|
|
25
|
+
machineryIndicators: z.array(z.string()).optional(),
|
|
26
|
+
originModuleGlobs: z.array(z.string()).optional(),
|
|
27
|
+
payloadGenericIndex: z.number().int().nonnegative().optional(),
|
|
28
|
+
payloadPropertyPath: z.array(z.string()).optional(),
|
|
29
|
+
unwrapRecursively: z.boolean().optional(),
|
|
30
|
+
// Nonnegative, not positive: the Rust side accepts a model-emitted
|
|
31
|
+
// maxDepth of 0 (a harmless no-op rule), and one rule rejected here would
|
|
32
|
+
// fail the entire infer request.
|
|
33
|
+
maxDepth: z.number().int().nonnegative().optional(),
|
|
34
|
+
});
|
|
35
|
+
const ExtractionConfigSchema = z.object({
|
|
36
|
+
rules: z.array(ExtractionRuleSchema),
|
|
37
|
+
});
|
|
38
|
+
// ============================================================================
|
|
39
|
+
// Tsconfig Snapshot Schema
|
|
40
|
+
// ============================================================================
|
|
41
|
+
const TsconfigSnapshotSchema = z.object({
|
|
42
|
+
compilerOptions: z.object({
|
|
43
|
+
module: z.string().optional(),
|
|
44
|
+
moduleResolution: z.string().optional(),
|
|
45
|
+
target: z.string().optional(),
|
|
46
|
+
lib: z.array(z.string()).optional(),
|
|
47
|
+
types: z.array(z.string()).optional(),
|
|
48
|
+
typeRoots: z.array(z.string()).optional(),
|
|
49
|
+
jsx: z.string().optional(),
|
|
50
|
+
strict: z.boolean().optional(),
|
|
51
|
+
esModuleInterop: z.boolean().optional(),
|
|
52
|
+
skipLibCheck: z.boolean().optional(),
|
|
53
|
+
declaration: z.boolean().optional(),
|
|
54
|
+
declarationMap: z.boolean().optional(),
|
|
55
|
+
paths: z.record(z.array(z.string())).optional(),
|
|
56
|
+
baseUrl: z.string().optional(),
|
|
57
|
+
}).passthrough(),
|
|
58
|
+
});
|
|
59
|
+
// ============================================================================
|
|
60
|
+
// Pinned Dependency Snapshot Schema
|
|
61
|
+
// ============================================================================
|
|
62
|
+
const PinnedDependencySnapshotSchema = z.record(z.string());
|
|
63
|
+
// ============================================================================
|
|
64
|
+
// Repo Metadata Schema
|
|
65
|
+
// ============================================================================
|
|
66
|
+
const RepoMetadataSchema = z.object({
|
|
67
|
+
repoName: z.string().min(1, 'Repo name cannot be empty'),
|
|
68
|
+
dependencies: PinnedDependencySnapshotSchema,
|
|
69
|
+
tsconfig: TsconfigSnapshotSchema,
|
|
70
|
+
extractionConfig: ExtractionConfigSchema.optional(),
|
|
71
|
+
surfaceContent: z.string().optional(),
|
|
72
|
+
});
|
|
73
|
+
// ============================================================================
|
|
74
|
+
// Symbol Request Schema
|
|
75
|
+
// ============================================================================
|
|
76
|
+
export const SymbolRequestSchema = z.object({
|
|
77
|
+
symbol_name: z.string().min(1, 'Symbol name cannot be empty'),
|
|
78
|
+
source_file: z.string().min(1, 'Source file cannot be empty'),
|
|
79
|
+
alias: z.string().optional(),
|
|
80
|
+
// #248: SDL list depth to wrap the bundled element type in (`Order` → `Order[]`).
|
|
81
|
+
// No upper bound here deliberately: a batch invalid at this schema layer
|
|
82
|
+
// fails the *whole* bundle request (see the `maxDepth` note above), which
|
|
83
|
+
// is worse than one bad symbol. The bundler enforces MAX_ARRAY_DEPTH
|
|
84
|
+
// per-symbol instead, so an over-bound depth becomes a normal
|
|
85
|
+
// `symbol_failures` entry rather than sinking every other symbol in the
|
|
86
|
+
// batch.
|
|
87
|
+
array_depth: z.number().int().nonnegative().optional(),
|
|
88
|
+
});
|
|
89
|
+
// ============================================================================
|
|
90
|
+
// Infer Request Item Schema
|
|
91
|
+
// ============================================================================
|
|
92
|
+
export const InferRequestItemSchema = z.object({
|
|
93
|
+
file_path: z.string().min(1, 'File path cannot be empty'),
|
|
94
|
+
line_number: z.number().int().positive('Line number must be positive'),
|
|
95
|
+
span_start: z.number().int().nonnegative('Span start must be non-negative').optional(),
|
|
96
|
+
span_end: z.number().int().nonnegative('Span end must be non-negative').optional(),
|
|
97
|
+
expression_text: z.string().optional(),
|
|
98
|
+
expression_line: z.number().int().positive('Expression line must be positive').optional(),
|
|
99
|
+
infer_kind: InferKindSchema,
|
|
100
|
+
alias: z.string().optional(),
|
|
101
|
+
param_name: z.string().optional(),
|
|
102
|
+
});
|
|
103
|
+
/**
|
|
104
|
+
* Per-item locator validation for infer requests.
|
|
105
|
+
*
|
|
106
|
+
* This is deliberately NOT part of the envelope schema: real runs batch
|
|
107
|
+
* every alias of a repo into one infer request, and a single bad item
|
|
108
|
+
* must produce a per-item error (the alias then pads to `unknown`
|
|
109
|
+
* downstream), not reject the whole batch.
|
|
110
|
+
*
|
|
111
|
+
* Returns an error message, or null when the item is valid.
|
|
112
|
+
*/
|
|
113
|
+
export function validateInferRequestItem(item) {
|
|
114
|
+
if (item.span_start !== undefined &&
|
|
115
|
+
item.span_end !== undefined &&
|
|
116
|
+
item.span_end < item.span_start) {
|
|
117
|
+
return 'span_end must be greater than or equal to span_start';
|
|
118
|
+
}
|
|
119
|
+
const hasSpan = item.span_start !== undefined && item.span_end !== undefined;
|
|
120
|
+
const hasText = item.expression_text !== undefined;
|
|
121
|
+
// Function-anchored inference (function_return for file-based routes,
|
|
122
|
+
// signature_return / function_param for the signature pass) locates the
|
|
123
|
+
// function by line_number alone, so it does not require a span or text.
|
|
124
|
+
// response_body / request_body also accept a line-only anchor: for a
|
|
125
|
+
// named-handler route registration the scanner falls back to the registration
|
|
126
|
+
// line, and the inferrer follows that line to the handler (`handlerAtLine`).
|
|
127
|
+
// Worst case the line resolves nothing and the alias pads to `unknown` — the
|
|
128
|
+
// same outcome rejection produced, but now the resolvable cases get through.
|
|
129
|
+
const lineOnlyOk = item.infer_kind === 'function_return' ||
|
|
130
|
+
item.infer_kind === 'signature_return' ||
|
|
131
|
+
item.infer_kind === 'function_param' ||
|
|
132
|
+
item.infer_kind === 'response_body' ||
|
|
133
|
+
item.infer_kind === 'request_body';
|
|
134
|
+
if (!hasSpan && !hasText && !lineOnlyOk) {
|
|
135
|
+
return 'at least one of (span_start + span_end) or expression_text is required';
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
// ============================================================================
|
|
140
|
+
// Payload Definition Schema (New)
|
|
141
|
+
// ============================================================================
|
|
142
|
+
const SourceLocationSchema = z.object({
|
|
143
|
+
file_path: z.string(),
|
|
144
|
+
start_line: z.number(),
|
|
145
|
+
end_line: z.number(),
|
|
146
|
+
start_column: z.number().optional(),
|
|
147
|
+
end_column: z.number().optional(),
|
|
148
|
+
});
|
|
149
|
+
const PayloadDefinitionSchema = z.object({
|
|
150
|
+
alias: z.string().min(1, 'Alias cannot be empty'),
|
|
151
|
+
type_string: z.string().min(1, 'Type string cannot be empty'),
|
|
152
|
+
source_file: z.string().optional(),
|
|
153
|
+
source_location: SourceLocationSchema.optional(),
|
|
154
|
+
});
|
|
155
|
+
// ============================================================================
|
|
156
|
+
// Compatibility Check Schema (New)
|
|
157
|
+
// ============================================================================
|
|
158
|
+
const CompatibilityCheckSchema = z.object({
|
|
159
|
+
source_repo: z.string().min(1, 'Source repo cannot be empty'),
|
|
160
|
+
source_alias: z.string().min(1, 'Source alias cannot be empty'),
|
|
161
|
+
target_repo: z.string().min(1, 'Target repo cannot be empty'),
|
|
162
|
+
target_alias: z.string().min(1, 'Target alias cannot be empty'),
|
|
163
|
+
direction: z.enum(['source_extends_target', 'target_extends_source', 'bidirectional']),
|
|
164
|
+
});
|
|
165
|
+
// ============================================================================
|
|
166
|
+
// Action-specific Request Schemas
|
|
167
|
+
// ============================================================================
|
|
168
|
+
const BaseRequestSchema = z.object({
|
|
169
|
+
request_id: z.string().min(1, 'Request ID cannot be empty'),
|
|
170
|
+
});
|
|
171
|
+
export const InitRequestSchema = BaseRequestSchema.extend({
|
|
172
|
+
action: z.literal('init'),
|
|
173
|
+
repo_root: z.string().min(1, 'Repo root cannot be empty'),
|
|
174
|
+
tsconfig_path: z.string().optional(),
|
|
175
|
+
tsconfig_snapshot: TsconfigSnapshotSchema.optional(),
|
|
176
|
+
pinned_dependencies: PinnedDependencySnapshotSchema.optional(),
|
|
177
|
+
});
|
|
178
|
+
export const BundleRequestSchema = BaseRequestSchema.extend({
|
|
179
|
+
action: z.literal('bundle'),
|
|
180
|
+
symbols: z.array(SymbolRequestSchema).min(1, 'At least one symbol is required'),
|
|
181
|
+
});
|
|
182
|
+
export const EmitSurfaceRequestSchema = BaseRequestSchema.extend({
|
|
183
|
+
action: z.literal('emit_surface'),
|
|
184
|
+
repo_name: z.string().min(1, 'Repo name cannot be empty'),
|
|
185
|
+
payloads: z.array(PayloadDefinitionSchema).min(1, 'At least one payload is required'),
|
|
186
|
+
output_path: z.string().min(1, 'Output path cannot be empty'),
|
|
187
|
+
});
|
|
188
|
+
/** v2 "tsc as serializer" capture (contract in ./capture/api.ts). */
|
|
189
|
+
const AnchorOriginSchema = z.enum(['llm-symbol', 'deterministic-infer', 'anchor-backfill']);
|
|
190
|
+
const CaptureAnchorRequestSchema = z.discriminatedUnion('kind', [
|
|
191
|
+
z.object({
|
|
192
|
+
kind: z.literal('symbol'),
|
|
193
|
+
alias: z.string().min(1),
|
|
194
|
+
symbol_name: z.string().min(1),
|
|
195
|
+
source_file: z.string().min(1),
|
|
196
|
+
anchor_origin: AnchorOriginSchema,
|
|
197
|
+
array_depth: z.number().int().nonnegative().optional(),
|
|
198
|
+
}),
|
|
199
|
+
z.object({
|
|
200
|
+
kind: z.literal('handler_return'),
|
|
201
|
+
alias: z.string().min(1),
|
|
202
|
+
symbol_name: z.string().min(1),
|
|
203
|
+
source_file: z.string().min(1),
|
|
204
|
+
anchor_origin: AnchorOriginSchema,
|
|
205
|
+
}),
|
|
206
|
+
z.object({
|
|
207
|
+
kind: z.literal('infer'),
|
|
208
|
+
alias: z.string().min(1),
|
|
209
|
+
source_file: z.string().min(1),
|
|
210
|
+
anchor_origin: AnchorOriginSchema,
|
|
211
|
+
span_start: z.number().int().nonnegative().optional(),
|
|
212
|
+
span_end: z.number().int().nonnegative().optional(),
|
|
213
|
+
line_number: z.number().int().positive().optional(),
|
|
214
|
+
expression_text: z.string().optional(),
|
|
215
|
+
unwrap: z.enum(['awaited', 'none']).optional(),
|
|
216
|
+
}),
|
|
217
|
+
z.object({
|
|
218
|
+
kind: z.literal('literal'),
|
|
219
|
+
alias: z.string().min(1),
|
|
220
|
+
type_text: z.string().min(1),
|
|
221
|
+
anchor_origin: AnchorOriginSchema,
|
|
222
|
+
}),
|
|
223
|
+
]);
|
|
224
|
+
export const CaptureV2RequestSchema = BaseRequestSchema.extend({
|
|
225
|
+
action: z.literal('capture_v2'),
|
|
226
|
+
repo_root: z.string().min(1, 'Repo root cannot be empty'),
|
|
227
|
+
service_name: z.string().min(1, 'Service name cannot be empty'),
|
|
228
|
+
anchors: z.array(CaptureAnchorRequestSchema).min(1, 'At least one anchor is required'),
|
|
229
|
+
out_dir: z.string().min(1, 'Output dir cannot be empty'),
|
|
230
|
+
tsconfig_path: z.string().optional(),
|
|
231
|
+
});
|
|
232
|
+
const CheckStubInputSchema = z.object({
|
|
233
|
+
service_name: z.string().min(1),
|
|
234
|
+
stub_dir: z.string().min(1),
|
|
235
|
+
});
|
|
236
|
+
const CheckPairEndpointSchema = z.object({
|
|
237
|
+
service_name: z.string().min(1),
|
|
238
|
+
alias: z.string().min(1),
|
|
239
|
+
});
|
|
240
|
+
const CheckPairSpecSchema = z.object({
|
|
241
|
+
pair_key: z.string().min(1),
|
|
242
|
+
protocol: z.enum(['http', 'graphql', 'socket', 'pubsub']),
|
|
243
|
+
type_kind: z.enum(['request', 'response', 'both']),
|
|
244
|
+
producer: CheckPairEndpointSchema,
|
|
245
|
+
consumer: CheckPairEndpointSchema,
|
|
246
|
+
});
|
|
247
|
+
export const CheckV2RequestSchema = BaseRequestSchema.extend({
|
|
248
|
+
action: z.literal('check_v2'),
|
|
249
|
+
stubs: z.array(CheckStubInputSchema).min(1, 'At least one stub is required'),
|
|
250
|
+
pairs: z.array(CheckPairSpecSchema).min(1, 'At least one pair is required'),
|
|
251
|
+
workspace_root: z.string().optional(),
|
|
252
|
+
keep_workspace: z.boolean().optional(),
|
|
253
|
+
});
|
|
254
|
+
export const InferRequestSchema = BaseRequestSchema.extend({
|
|
255
|
+
action: z.literal('infer'),
|
|
256
|
+
requests: z.array(InferRequestItemSchema).min(1, 'At least one infer request is required'),
|
|
257
|
+
extraction_config: ExtractionConfigSchema.optional(),
|
|
258
|
+
});
|
|
259
|
+
export const BuildWorkspaceRequestSchema = BaseRequestSchema.extend({
|
|
260
|
+
action: z.literal('build_workspace'),
|
|
261
|
+
repos: z.array(RepoMetadataSchema).min(1, 'At least one repo is required'),
|
|
262
|
+
workspace_root: z.string().optional(),
|
|
263
|
+
});
|
|
264
|
+
export const CheckCompatibilityRequestSchema = BaseRequestSchema.extend({
|
|
265
|
+
action: z.literal('check_compatibility'),
|
|
266
|
+
workspace_root: z.string().min(1, 'Workspace root cannot be empty'),
|
|
267
|
+
checks: z.array(CompatibilityCheckSchema).min(1, 'At least one check is required'),
|
|
268
|
+
});
|
|
269
|
+
export const HealthRequestSchema = BaseRequestSchema.extend({
|
|
270
|
+
action: z.literal('health'),
|
|
271
|
+
});
|
|
272
|
+
export const ShutdownRequestSchema = BaseRequestSchema.extend({
|
|
273
|
+
action: z.literal('shutdown'),
|
|
274
|
+
});
|
|
275
|
+
export const ResolveDefinitionsRequestSchema = BaseRequestSchema.extend({
|
|
276
|
+
action: z.literal('resolve_definitions'),
|
|
277
|
+
stub_dir: z.string().min(1, 'Stub dir cannot be empty'),
|
|
278
|
+
aliases: z.array(z.string().min(1)).min(1, 'At least one alias is required'),
|
|
279
|
+
});
|
|
280
|
+
// ============================================================================
|
|
281
|
+
// Discriminated Union Schema
|
|
282
|
+
// ============================================================================
|
|
283
|
+
/**
|
|
284
|
+
* The main sidecar request schema - a discriminated union on the 'action' field
|
|
285
|
+
*/
|
|
286
|
+
export const SidecarRequestSchema = z.discriminatedUnion('action', [
|
|
287
|
+
InitRequestSchema,
|
|
288
|
+
BundleRequestSchema,
|
|
289
|
+
EmitSurfaceRequestSchema,
|
|
290
|
+
CaptureV2RequestSchema,
|
|
291
|
+
CheckV2RequestSchema,
|
|
292
|
+
InferRequestSchema,
|
|
293
|
+
BuildWorkspaceRequestSchema,
|
|
294
|
+
CheckCompatibilityRequestSchema,
|
|
295
|
+
ResolveDefinitionsRequestSchema,
|
|
296
|
+
HealthRequestSchema,
|
|
297
|
+
ShutdownRequestSchema,
|
|
298
|
+
]);
|
|
299
|
+
/**
|
|
300
|
+
* Validates and parses incoming JSON into a typed SidecarRequest
|
|
301
|
+
*
|
|
302
|
+
* @param json - The raw JSON value to parse
|
|
303
|
+
* @returns ParseResult with either the typed request or an error message
|
|
304
|
+
*/
|
|
305
|
+
export function parseRequest(json) {
|
|
306
|
+
const result = SidecarRequestSchema.safeParse(json);
|
|
307
|
+
if (result.success) {
|
|
308
|
+
return {
|
|
309
|
+
success: true,
|
|
310
|
+
request: result.data,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
// Format Zod errors nicely
|
|
314
|
+
const errorMessages = result.error.issues.map((issue) => {
|
|
315
|
+
const path = issue.path.join('.');
|
|
316
|
+
return path ? `${path}: ${issue.message}` : issue.message;
|
|
317
|
+
});
|
|
318
|
+
return {
|
|
319
|
+
success: false,
|
|
320
|
+
error: `Invalid request: ${errorMessages.join('; ')}`,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Validates and parses incoming JSON, throwing on error
|
|
325
|
+
*
|
|
326
|
+
* @param json - The raw JSON value to parse
|
|
327
|
+
* @returns The typed SidecarRequest
|
|
328
|
+
* @throws Error if validation fails
|
|
329
|
+
*/
|
|
330
|
+
export function parseRequestOrThrow(json) {
|
|
331
|
+
const result = parseRequest(json);
|
|
332
|
+
if (!result.success) {
|
|
333
|
+
throw new Error(result.error);
|
|
334
|
+
}
|
|
335
|
+
return result.request;
|
|
336
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: Carrick
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [{{DEFAULT_BRANCH}}]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [{{DEFAULT_BRANCH}}]
|
|
8
|
+
# Carrick Cloud sends this when a sibling repo in the same project changes
|
|
9
|
+
# on its main branch, so this repo's cross-repo results catch up without
|
|
10
|
+
# anyone pushing. If you add deploy steps to this file, gate them on
|
|
11
|
+
# github.event_name so a sibling change never deploys this repo.
|
|
12
|
+
repository_dispatch:
|
|
13
|
+
types: [carrick-sibling-updated]
|
|
14
|
+
# Rescan on demand (Actions tab, or: gh workflow run carrick.yml). After a
|
|
15
|
+
# Carrick release the index only refreshes on the next scan.
|
|
16
|
+
workflow_dispatch:
|
|
17
|
+
inputs:
|
|
18
|
+
full-scan:
|
|
19
|
+
description: >-
|
|
20
|
+
Re-analyze every file instead of reusing the cached answer for a file
|
|
21
|
+
that has not changed. Slower and costs a full analysis; ask for it
|
|
22
|
+
when Carrick has started extracting something it did not extract
|
|
23
|
+
before, so the cache holds answers from before it could.
|
|
24
|
+
type: boolean
|
|
25
|
+
default: false
|
|
26
|
+
|
|
27
|
+
permissions:
|
|
28
|
+
# Mint a short-lived OIDC token Carrick exchanges for keyless upload auth
|
|
29
|
+
# (no upload secret to configure).
|
|
30
|
+
id-token: write
|
|
31
|
+
contents: read
|
|
32
|
+
|
|
33
|
+
jobs:
|
|
34
|
+
carrick:
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v4
|
|
38
|
+
# Full git history lets Carrick diff against the last scan and run incrementally.
|
|
39
|
+
with:
|
|
40
|
+
fetch-depth: 0
|
|
41
|
+
- uses: {{ACTION_REF}}
|
|
42
|
+
with:
|
|
43
|
+
# Empty on every trigger but workflow_dispatch, which is the point:
|
|
44
|
+
# a full re-analysis is asked for, never carried by a push.
|
|
45
|
+
full-scan: ${{ inputs.full-scan }}
|