@agentuity/migrate 3.0.0-alpha.6 → 3.0.0-beta.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.
- package/dist/detect-v3.d.ts.map +1 -1
- package/dist/detect-v3.js +4 -3
- package/dist/detect-v3.js.map +1 -1
- package/dist/migrate-v3.d.ts.map +1 -1
- package/dist/migrate-v3.js +188 -5
- package/dist/migrate-v3.js.map +1 -1
- package/dist/transforms/v3/agents.d.ts +10 -3
- package/dist/transforms/v3/agents.d.ts.map +1 -1
- package/dist/transforms/v3/agents.js +256 -7
- package/dist/transforms/v3/agents.js.map +1 -1
- package/dist/transforms/v3/package-json.d.ts +2 -0
- package/dist/transforms/v3/package-json.d.ts.map +1 -1
- package/dist/transforms/v3/package-json.js +48 -2
- package/dist/transforms/v3/package-json.js.map +1 -1
- package/dist/transforms/v3/routes.d.ts +63 -4
- package/dist/transforms/v3/routes.d.ts.map +1 -1
- package/dist/transforms/v3/routes.js +131 -15
- package/dist/transforms/v3/routes.js.map +1 -1
- package/dist/transforms/v3/schema-to-zod.d.ts +18 -0
- package/dist/transforms/v3/schema-to-zod.d.ts.map +1 -0
- package/dist/transforms/v3/schema-to-zod.js +140 -0
- package/dist/transforms/v3/schema-to-zod.js.map +1 -0
- package/package.json +3 -4
- package/src/detect-v3.ts +5 -3
- package/src/migrate-v3.ts +208 -4
- package/src/transforms/v3/agents.ts +289 -7
- package/src/transforms/v3/package-json.ts +52 -2
- package/src/transforms/v3/routes.ts +195 -7
- package/src/transforms/v3/schema-to-zod.ts +162 -0
|
@@ -27,14 +27,49 @@ export interface RouteServiceTransformResult {
|
|
|
27
27
|
* @param servicesRelativePath - Relative import path to services module (e.g., '../services')
|
|
28
28
|
*/
|
|
29
29
|
/**
|
|
30
|
-
* Remove all imports from @agentuity/runtime
|
|
31
|
-
*
|
|
30
|
+
* Remove all imports from @agentuity/runtime and re-route individual symbols
|
|
31
|
+
* to their v3 replacements where applicable.
|
|
32
|
+
*
|
|
33
|
+
* Recognised re-routes:
|
|
34
|
+
* - `Env` → local types file (generated elsewhere)
|
|
35
|
+
* - `validator` → dropped (v3 has no equivalent middleware; callers
|
|
36
|
+
* now parse input via zod inline)
|
|
37
|
+
* - everything else → dropped silently (deprecation stubs)
|
|
38
|
+
*
|
|
39
|
+
* Returns the rewritten source plus flags for each recognised symbol so the
|
|
40
|
+
* caller can emit the replacement imports in the right order.
|
|
32
41
|
*/
|
|
33
|
-
export
|
|
42
|
+
export interface RuntimeImportCleanup {
|
|
43
|
+
source: string;
|
|
44
|
+
removed: boolean;
|
|
45
|
+
/** Whether `Env` was imported from @agentuity/runtime */
|
|
46
|
+
needsEnvType: boolean;
|
|
47
|
+
/** Whether `validator` (the Agentuity validator helper) was imported */
|
|
48
|
+
hadAgentuityValidator: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function removeRuntimeImports(source: string): RuntimeImportCleanup {
|
|
52
|
+
let needsEnvType = false;
|
|
53
|
+
let hadAgentuityValidator = false;
|
|
54
|
+
let removed = false;
|
|
55
|
+
|
|
56
|
+
// Match both `import { ... } from '@agentuity/runtime'` and
|
|
57
|
+
// `import type { ... } from '@agentuity/runtime'` (incl. multiline).
|
|
34
58
|
const pattern =
|
|
35
|
-
/import\s+(?:type\s+)?\{[^}]
|
|
36
|
-
const
|
|
37
|
-
|
|
59
|
+
/import\s+(?:type\s+)?\{([^}]*)\}\s*from\s*['"]@agentuity\/runtime['"]\s*;?\s*\n?/g;
|
|
60
|
+
const output = source.replace(pattern, (_match, inner: string) => {
|
|
61
|
+
removed = true;
|
|
62
|
+
const names = inner
|
|
63
|
+
.split(',')
|
|
64
|
+
.map((s) => s.trim())
|
|
65
|
+
.map((s) => s.replace(/^type\s+/, ''))
|
|
66
|
+
.filter(Boolean);
|
|
67
|
+
if (names.includes('Env')) needsEnvType = true;
|
|
68
|
+
if (names.includes('validator')) hadAgentuityValidator = true;
|
|
69
|
+
return '';
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return { source: output, removed, needsEnvType, hadAgentuityValidator };
|
|
38
73
|
}
|
|
39
74
|
|
|
40
75
|
export function transformRouteServices(
|
|
@@ -51,6 +86,33 @@ export function transformRouteServices(
|
|
|
51
86
|
if (runtimeCleanup.removed) {
|
|
52
87
|
output = runtimeCleanup.source;
|
|
53
88
|
changes.push('Removed @agentuity/runtime imports');
|
|
89
|
+
|
|
90
|
+
// Re-route Env to the generated types file
|
|
91
|
+
if (runtimeCleanup.needsEnvType) {
|
|
92
|
+
output = insertAfterImports(output, "import type { Env } from '../types/hono-env';");
|
|
93
|
+
changes.push("Added: import type { Env } from '../types/hono-env'");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Strip v2-era validator middleware calls that have no v3 equivalent.
|
|
97
|
+
const stripped = stripAgentuityValidators(output);
|
|
98
|
+
if (stripped.changed) {
|
|
99
|
+
output = stripped.source;
|
|
100
|
+
changes.push(...stripped.changes);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Rewrite v2-era agent method calls in route files.
|
|
105
|
+
const agentRewrite = rewriteV2AgentMethods(output);
|
|
106
|
+
if (agentRewrite.changed) {
|
|
107
|
+
output = agentRewrite.source;
|
|
108
|
+
changes.push(...agentRewrite.changes);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Stub out c.var.thread / c.var.sessionId — v2 concepts with no v3 replacement.
|
|
112
|
+
const stubRewrite = stubV2HonoContext(output);
|
|
113
|
+
if (stubRewrite.changed) {
|
|
114
|
+
output = stubRewrite.source;
|
|
115
|
+
changes.push(...stubRewrite.changes);
|
|
54
116
|
}
|
|
55
117
|
|
|
56
118
|
if (usage.accessPattern === 'c.var') {
|
|
@@ -161,7 +223,133 @@ export function computeServicesRelativePath(projectDir: string, sourceFilePath:
|
|
|
161
223
|
// Helpers
|
|
162
224
|
// ---------------------------------------------------------------------------
|
|
163
225
|
|
|
164
|
-
|
|
226
|
+
/**
|
|
227
|
+
* Rewrite v2-era agent method invocations to plain function calls in route
|
|
228
|
+
* files.
|
|
229
|
+
*
|
|
230
|
+
* translate.run(data) → translate(data)
|
|
231
|
+
* translate.validator() → /* stripped above * /
|
|
232
|
+
*
|
|
233
|
+
* We also rewrite `c.req.valid('json')` → `await c.req.json()` — the former
|
|
234
|
+
* was the output of the v2 validator middleware that we stripped.
|
|
235
|
+
*/
|
|
236
|
+
export function rewriteV2AgentMethods(source: string): {
|
|
237
|
+
source: string;
|
|
238
|
+
changed: boolean;
|
|
239
|
+
changes: string[];
|
|
240
|
+
} {
|
|
241
|
+
let output = source;
|
|
242
|
+
const changes: string[] = [];
|
|
243
|
+
|
|
244
|
+
// <agent>.run(x) → <agent>(x)
|
|
245
|
+
const before1 = output;
|
|
246
|
+
output = output.replace(
|
|
247
|
+
/\b([A-Za-z_$][A-Za-z0-9_$]*)\.run\(/g,
|
|
248
|
+
(_m, name: string) => `${name}(`
|
|
249
|
+
);
|
|
250
|
+
if (output !== before1) {
|
|
251
|
+
changes.push('Rewrote <agent>.run(…) → <agent>(…)');
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// c.req.valid('json') → (await c.req.json())
|
|
255
|
+
const before2 = output;
|
|
256
|
+
output = output.replace(/\bc\.req\.valid\(\s*['"]json['"]\s*\)/g, '(await c.req.json())');
|
|
257
|
+
if (output !== before2) {
|
|
258
|
+
changes.push("Rewrote c.req.valid('json') → await c.req.json()");
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return { source: output, changed: changes.length > 0, changes };
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Stub out v2-era Hono context variables that no longer exist in v3.
|
|
266
|
+
*
|
|
267
|
+
* v3's Services interface only includes storage clients (kv, vector, stream,
|
|
268
|
+
* etc.). Thread state, sessionId, and app-level state were removed when v3
|
|
269
|
+
* dropped the createApp() abstraction.
|
|
270
|
+
*/
|
|
271
|
+
export function stubV2HonoContext(source: string): {
|
|
272
|
+
source: string;
|
|
273
|
+
changed: boolean;
|
|
274
|
+
changes: string[];
|
|
275
|
+
} {
|
|
276
|
+
let output = source;
|
|
277
|
+
const changes = new Set<string>();
|
|
278
|
+
|
|
279
|
+
// c.var.thread.* — stub out the whole chain as `(undefined as any)`.
|
|
280
|
+
//
|
|
281
|
+
// The chain can include:
|
|
282
|
+
// • Dotted property access: c.var.thread.state
|
|
283
|
+
// • Generic type arguments: .get<HistoryEntry[]>
|
|
284
|
+
// • Call sites: .get<T>('key')
|
|
285
|
+
// • Multiple chained calls: .state.push(…).something()
|
|
286
|
+
//
|
|
287
|
+
// We do this greedily by chaining an alternation until we hit a terminator.
|
|
288
|
+
const before1 = output;
|
|
289
|
+
output = output.replace(
|
|
290
|
+
/c\.var\.thread(?:\.[A-Za-z0-9_$]+|<[^>]*>|\([^()]*\))*/g,
|
|
291
|
+
'(undefined as any) /* v3: c.var.thread removed */'
|
|
292
|
+
);
|
|
293
|
+
if (output !== before1) {
|
|
294
|
+
changes.add('Stubbed c.var.thread.* (removed in v3)');
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const before2 = output;
|
|
298
|
+
output = output.replace(
|
|
299
|
+
/c\.var\.sessionId\b/g,
|
|
300
|
+
"('v3-no-session-id' as string) /* v3: c.var.sessionId removed */"
|
|
301
|
+
);
|
|
302
|
+
if (output !== before2) {
|
|
303
|
+
changes.add('Stubbed c.var.sessionId (removed in v3)');
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return { source: output, changed: changes.size > 0, changes: [...changes] };
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Strip v2 validator middleware from a source string.
|
|
311
|
+
*
|
|
312
|
+
* Removes two shapes:
|
|
313
|
+
* - `validator({ input: ... })` / `validator({ output: ... })` imported
|
|
314
|
+
* from @agentuity/runtime (used as Hono middleware)
|
|
315
|
+
* - `<agent>.validator()` — the auto-generated method on v2 agents used as
|
|
316
|
+
* middleware on routes that forward to the agent
|
|
317
|
+
*
|
|
318
|
+
* Both become comments so the file parses but the user can see where to wire
|
|
319
|
+
* up manual validation (typically via `zod.parse(await c.req.json())`).
|
|
320
|
+
*/
|
|
321
|
+
export function stripAgentuityValidators(source: string): {
|
|
322
|
+
source: string;
|
|
323
|
+
changed: boolean;
|
|
324
|
+
changes: string[];
|
|
325
|
+
} {
|
|
326
|
+
let output = source;
|
|
327
|
+
const changes: string[] = [];
|
|
328
|
+
|
|
329
|
+
// validator({ ... }), — tolerate whitespace/newlines
|
|
330
|
+
const before1 = output;
|
|
331
|
+
output = output.replace(
|
|
332
|
+
/\s*validator\(\s*\{[\s\S]*?\}\s*\)\s*,?/g,
|
|
333
|
+
' /* v3: validator() removed — validate inline with zod */ '
|
|
334
|
+
);
|
|
335
|
+
if (output !== before1) {
|
|
336
|
+
changes.push('Stripped Agentuity validator() middleware calls');
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// <agent>.validator(),
|
|
340
|
+
const before2 = output;
|
|
341
|
+
output = output.replace(
|
|
342
|
+
/\s*[A-Za-z_$][A-Za-z0-9_$]*\.validator\(\s*\)\s*,?/g,
|
|
343
|
+
' /* v3: agent.validator() removed — parse input with zod */ '
|
|
344
|
+
);
|
|
345
|
+
if (output !== before2) {
|
|
346
|
+
changes.push('Stripped <agent>.validator() middleware calls');
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
return { source: output, changed: changes.length > 0, changes };
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
export function insertAfterImports(source: string, importLine: string): string {
|
|
165
353
|
const sf = ts.createSourceFile('temp.ts', source, ts.ScriptTarget.ESNext, true);
|
|
166
354
|
|
|
167
355
|
let lastImportEnd = -1;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transform: port `@agentuity/schema` usage to `zod`.
|
|
3
|
+
*
|
|
4
|
+
* v3 still ships @agentuity/schema but the idiomatic path for user-owned
|
|
5
|
+
* schemas is zod. The migrate tool replaces the import and the `s.*`
|
|
6
|
+
* namespace calls so downstream code parses with zod at runtime.
|
|
7
|
+
*
|
|
8
|
+
* Conservative mapping — we do not try to handle every edge case. Advanced
|
|
9
|
+
* shapes (e.g. s.toJSONSchema) are flagged with a TODO comment for manual
|
|
10
|
+
* review rather than silently mistranslated.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export interface SchemaToZodResult {
|
|
14
|
+
source: string;
|
|
15
|
+
changed: boolean;
|
|
16
|
+
changes: string[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const BUILDERS = [
|
|
20
|
+
'object',
|
|
21
|
+
'string',
|
|
22
|
+
'number',
|
|
23
|
+
'boolean',
|
|
24
|
+
'null_',
|
|
25
|
+
'undefined_',
|
|
26
|
+
'unknown',
|
|
27
|
+
'any',
|
|
28
|
+
'array',
|
|
29
|
+
'record',
|
|
30
|
+
'literal',
|
|
31
|
+
'optional',
|
|
32
|
+
'nullable',
|
|
33
|
+
'enum',
|
|
34
|
+
'union',
|
|
35
|
+
'coerceString',
|
|
36
|
+
'coerceNumber',
|
|
37
|
+
'coerceBoolean',
|
|
38
|
+
'coerceDate',
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
export function schemaToZod(source: string): SchemaToZodResult {
|
|
42
|
+
let output = source;
|
|
43
|
+
const changes: string[] = [];
|
|
44
|
+
|
|
45
|
+
// 1. Import swap: `import { s } from '@agentuity/schema'` → `import { z } from 'zod'`.
|
|
46
|
+
const importBefore = output;
|
|
47
|
+
output = output.replace(
|
|
48
|
+
/import\s*\{\s*s\s*\}\s*from\s*['"]@agentuity\/schema['"]\s*;?/g,
|
|
49
|
+
"import { z } from 'zod';"
|
|
50
|
+
);
|
|
51
|
+
if (output !== importBefore) {
|
|
52
|
+
changes.push(
|
|
53
|
+
"Replaced `import { s } from '@agentuity/schema'` with `import { z } from 'zod'`"
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Also handle `import type { Schema } from '@agentuity/schema'` which is
|
|
58
|
+
// vestigial — the type isn't used anywhere we care about in the scaffold.
|
|
59
|
+
// Drop it rather than try to translate.
|
|
60
|
+
const typeImportBefore = output;
|
|
61
|
+
output = output.replace(
|
|
62
|
+
/import\s+type\s*\{[^}]*\}\s*from\s*['"]@agentuity\/schema['"]\s*;?\s*\n?/g,
|
|
63
|
+
''
|
|
64
|
+
);
|
|
65
|
+
if (output !== typeImportBefore) {
|
|
66
|
+
changes.push('Removed type imports from @agentuity/schema');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// If this file didn't use schema at all, bail early.
|
|
70
|
+
if (changes.length === 0 && !/\bs\s*\./.test(output)) {
|
|
71
|
+
return { source: output, changed: false, changes: [] };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// 2. s.<builder>(…) → z.<builder>(…).
|
|
75
|
+
let replacedBuilders = 0;
|
|
76
|
+
for (const name of BUILDERS) {
|
|
77
|
+
const pattern = new RegExp(`(^|[^A-Za-z0-9_$.])s\\.${name}(?=\\b)`, 'g');
|
|
78
|
+
output = output.replace(pattern, (_m, pre: string) => {
|
|
79
|
+
replacedBuilders++;
|
|
80
|
+
if (name.startsWith('coerce')) {
|
|
81
|
+
const prim = name.slice('coerce'.length).toLowerCase();
|
|
82
|
+
return `${pre}z.coerce.${prim}`;
|
|
83
|
+
}
|
|
84
|
+
// The @agentuity/schema names `null_` and `undefined_` map to zod's
|
|
85
|
+
// keyword-named functions `null`/`undefined` but those are reserved,
|
|
86
|
+
// so zod exposes them as methods on the `z` object just fine.
|
|
87
|
+
let mapped = name;
|
|
88
|
+
if (name === 'null_') mapped = 'null';
|
|
89
|
+
if (name === 'undefined_') mapped = 'undefined';
|
|
90
|
+
return `${pre}z.${mapped}`;
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
if (replacedBuilders > 0) {
|
|
94
|
+
changes.push(`Replaced ${replacedBuilders} s.<builder>() call(s) with z.<builder>()`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// 3. Type helpers.
|
|
98
|
+
const typeBefore = output;
|
|
99
|
+
output = output.replace(/\bs\.infer\b/g, 'z.infer');
|
|
100
|
+
if (output !== typeBefore) {
|
|
101
|
+
changes.push('Replaced s.infer<…> with z.infer<…>');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// 4. Advanced APIs we can't safely auto-translate: s.toJSONSchema.
|
|
105
|
+
const jsonSchemaBefore = output;
|
|
106
|
+
output = output.replace(
|
|
107
|
+
/\bs\.toJSONSchema\b/g,
|
|
108
|
+
'/* TODO: replace with zodToJsonSchema() from `zod-to-json-schema`, or use `.toJSON()` on zod v4 */ (null as any)'
|
|
109
|
+
);
|
|
110
|
+
if (output !== jsonSchemaBefore) {
|
|
111
|
+
changes.push('Stubbed s.toJSONSchema — requires manual swap to a zod equivalent');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 5. @agentuity/schema's s.union(a, b, c) is variadic; zod's z.union takes
|
|
115
|
+
// an array. Rewrite call sites with 2+ args to z.union([a, b, c]).
|
|
116
|
+
const unionBefore = output;
|
|
117
|
+
output = rewriteZUnionCalls(output);
|
|
118
|
+
if (output !== unionBefore) {
|
|
119
|
+
changes.push('Rewrote z.union(a, b, c) → z.union([a, b, c])');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return { source: output, changed: changes.length > 0, changes };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Walk `z.union(…)` call sites and wrap the args in an array literal unless
|
|
127
|
+
* they already are one. We scan with a brace-depth counter so nested parens
|
|
128
|
+
* and generic type arguments don't confuse us.
|
|
129
|
+
*/
|
|
130
|
+
function rewriteZUnionCalls(source: string): string {
|
|
131
|
+
const needle = 'z.union(';
|
|
132
|
+
let output = '';
|
|
133
|
+
let i = 0;
|
|
134
|
+
while (i < source.length) {
|
|
135
|
+
const idx = source.indexOf(needle, i);
|
|
136
|
+
if (idx < 0) {
|
|
137
|
+
output += source.slice(i);
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
output += source.slice(i, idx) + needle;
|
|
141
|
+
let depth = 1;
|
|
142
|
+
let j = idx + needle.length;
|
|
143
|
+
const start = j;
|
|
144
|
+
while (j < source.length && depth > 0) {
|
|
145
|
+
const ch = source[j];
|
|
146
|
+
if (ch === '(') depth++;
|
|
147
|
+
else if (ch === ')') {
|
|
148
|
+
depth--;
|
|
149
|
+
if (depth === 0) break;
|
|
150
|
+
}
|
|
151
|
+
j++;
|
|
152
|
+
}
|
|
153
|
+
const argsStr = source.slice(start, j);
|
|
154
|
+
if (argsStr.trimStart().startsWith('[')) {
|
|
155
|
+
output += argsStr + ')';
|
|
156
|
+
} else {
|
|
157
|
+
output += '[' + argsStr + '])';
|
|
158
|
+
}
|
|
159
|
+
i = j + 1;
|
|
160
|
+
}
|
|
161
|
+
return output;
|
|
162
|
+
}
|