@agent-native/core 0.128.2 → 0.128.4

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 (35) hide show
  1. package/corpus/core/CHANGELOG.md +13 -0
  2. package/corpus/core/package.json +1 -1
  3. package/corpus/core/src/client/chat/legacy-chart-shorthand.tsx +479 -0
  4. package/corpus/core/src/client/chat/markdown-renderer.tsx +23 -3
  5. package/corpus/core/src/extensions/actions.ts +1 -1
  6. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +12 -0
  7. package/corpus/templates/analytics/actions/generate-chart.ts +2 -2
  8. package/corpus/templates/chat/README.md +2 -0
  9. package/dist/client/chat/legacy-chart-shorthand.d.ts +29 -0
  10. package/dist/client/chat/legacy-chart-shorthand.d.ts.map +1 -0
  11. package/dist/client/chat/legacy-chart-shorthand.js +330 -0
  12. package/dist/client/chat/legacy-chart-shorthand.js.map +1 -0
  13. package/dist/client/chat/markdown-renderer.d.ts.map +1 -1
  14. package/dist/client/chat/markdown-renderer.js +8 -2
  15. package/dist/client/chat/markdown-renderer.js.map +1 -1
  16. package/dist/collab/struct-routes.d.ts +1 -1
  17. package/dist/extensions/actions.js +1 -1
  18. package/dist/extensions/actions.js.map +1 -1
  19. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  20. package/dist/observability/routes.d.ts +1 -1
  21. package/dist/provider-api/actions/custom-provider-registration.d.ts +14 -14
  22. package/dist/provider-api/actions/provider-api.d.ts +8 -8
  23. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  24. package/dist/templates/chat/README.md +2 -0
  25. package/package.json +3 -3
  26. package/src/client/chat/legacy-chart-shorthand.tsx +479 -0
  27. package/src/client/chat/markdown-renderer.tsx +23 -3
  28. package/src/extensions/actions.ts +1 -1
  29. package/src/templates/chat/README.md +2 -0
  30. package/corpus/core/src/cli/sync-builder-starter-manifest.ts +0 -631
  31. package/dist/cli/sync-builder-starter-manifest.d.ts +0 -79
  32. package/dist/cli/sync-builder-starter-manifest.d.ts.map +0 -1
  33. package/dist/cli/sync-builder-starter-manifest.js +0 -426
  34. package/dist/cli/sync-builder-starter-manifest.js.map +0 -1
  35. package/src/cli/sync-builder-starter-manifest.ts +0 -631
@@ -32,6 +32,13 @@ import { NEW_CHAT_ACTION_HREF } from "../error-format.js";
32
32
  import { HighlightedCodeBlock as SharedHighlightedCodeBlock } from "../HighlightedCodeBlock.js";
33
33
  import { IframeEmbed, parseEmbedBody } from "../IframeEmbed.js";
34
34
  import { cn } from "../utils.js";
35
+ import {
36
+ LEGACY_CHART_SHORTHAND_LANG,
37
+ LegacyChartShorthandChart,
38
+ LegacyChartShorthandFallback,
39
+ parseLegacyChartShorthand,
40
+ wrapLegacyChartShorthandLines,
41
+ } from "./legacy-chart-shorthand.js";
35
42
 
36
43
  // ─── Lazy markdown loader ────────────────────────────────────────────────────
37
44
  // react-markdown + remark-gfm are deferred so they stay off the critical path
@@ -284,6 +291,19 @@ export const markdownComponents = {
284
291
  <IframeEmbed {...(parsed as Parameters<typeof IframeEmbed>[0])} />
285
292
  );
286
293
  }
294
+ if (
295
+ new RegExp(`\\blanguage-${LEGACY_CHART_SHORTHAND_LANG}\\b`).test(
296
+ className,
297
+ )
298
+ ) {
299
+ const body = extractCodeText(childProps.children).replace(/\n$/, "");
300
+ const parsed = parseLegacyChartShorthand(body);
301
+ return parsed ? (
302
+ <LegacyChartShorthandChart parsed={parsed} />
303
+ ) : (
304
+ <LegacyChartShorthandFallback text={body} />
305
+ );
306
+ }
287
307
  const langMatch = className.match(/\blanguage-([\w+-]+)\b/);
288
308
  if (langMatch) {
289
309
  const code = extractCodeText(childProps.children).replace(/\n$/, "");
@@ -589,7 +609,7 @@ export const MemoizedMarkdownBlock = React.memo(function MemoizedMarkdownBlock({
589
609
  components={markdownComponents}
590
610
  urlTransform={markdownUrlTransform}
591
611
  >
592
- {blockText}
612
+ {wrapLegacyChartShorthandLines(blockText)}
593
613
  </ReactMarkdown>
594
614
  );
595
615
  });
@@ -642,7 +662,7 @@ export function SmoothMarkdownText({
642
662
  components={markdownComponents}
643
663
  urlTransform={markdownUrlTransform}
644
664
  >
645
- {split.tail}
665
+ {wrapLegacyChartShorthandLines(split.tail)}
646
666
  </ReactMarkdown>
647
667
  ) : null}
648
668
  </>
@@ -653,7 +673,7 @@ export function SmoothMarkdownText({
653
673
  components={markdownComponents}
654
674
  urlTransform={markdownUrlTransform}
655
675
  >
656
- {visibleText}
676
+ {wrapLegacyChartShorthandLines(visibleText)}
657
677
  </ReactMarkdown>
658
678
  )
659
679
  ) : (
@@ -623,7 +623,7 @@ export function createExtensionActionEntries(): Record<string, ActionEntry> {
623
623
  "update-extension": {
624
624
  tool: {
625
625
  description:
626
- 'Update an existing sandboxed Alpine.js mini-app extension. Pass exactly three fields: `id`, `operation`, and `payloadJson`. `payloadJson` is a JSON object encoded as a string so model gateways cannot fill its optional members with invalid empty placeholders. For operation="edit", pass {"edits":[...]} or {"patches":[...]} and optional format=true. For operation="replace", pass exactly one of content, contentFromAttachment, or contentFromWorkspaceFile; use this operation only for a user-requested broad visual rewrite or complete replacement body. For operation="metadata", pass name, description, or icon. Change sharing through set-resource-visibility instead. If the user is viewing the extension, use the extensionId from <current-screen> or <current-url> directly.',
626
+ 'Update an existing sandboxed Alpine.js mini-app extension. Pass exactly three fields: `id`, `operation`, and `payloadJson`. `payloadJson` is a JSON object encoded as a string so model gateways cannot fill its optional members with invalid empty placeholders. For operation="edit", pass {"edits":[...]} or {"patches":[...]} and optional format=true — prefer several small, targeted edits over one large one; a single edit/replace body over roughly 8KB risks the model truncating its own payloadJson mid-generation, which arrives here as an empty or malformed call that must be retried from scratch. For operation="replace", pass exactly one of content, contentFromAttachment, or contentFromWorkspaceFile; use this operation only for a user-requested broad visual rewrite or complete replacement body. Do not inline large static datasets (full metric histories, big arrays) into the HTML/JS body — store them with extension-data-set and fetch them at runtime via extensionData.list()/get() instead, so edits stay small regardless of dataset size. For operation="metadata", pass name, description, or icon. Change sharing through set-resource-visibility instead. If the user is viewing the extension, use the extensionId from <current-screen> or <current-url> directly.',
627
627
  parameters: {
628
628
  type: "object",
629
629
  properties: {
@@ -30,3 +30,5 @@ pnpm dev
30
30
  ```
31
31
 
32
32
  Full docs: [agent-native.com/docs/template-chat](https://agent-native.com/docs/template-chat).
33
+
34
+ <!-- vendor-branch mirror end-to-end test — safe to remove -->
@@ -1,631 +0,0 @@
1
- import fs from "node:fs";
2
- import os from "node:os";
3
- import path from "node:path";
4
- import { fileURLToPath } from "node:url";
5
-
6
- import {
7
- isMigrationManifestActive,
8
- readMigrationManifest,
9
- } from "../package-lifecycle/migration-manifest.js";
10
- import { _postProcessStandalone } from "./create.js";
11
- import { runMigrationCodemods } from "./migration-codemod.js";
12
-
13
- export const STARTER_APP_NAME = "builder-agent-native-starter";
14
- export const CHAT_TEMPLATE = "chat";
15
-
16
- /** Toolchain files that must track templates/chat or typecheck/build drift. */
17
- export const STARTER_TOOLCHAIN_SYNC_PATHS = [
18
- "react-router.config.ts",
19
- "vite.config.ts",
20
- "tsconfig.json",
21
- "ssr-entry.ts",
22
- "app/vite-env.d.ts",
23
- "app/routes.ts",
24
- "server/routes/[...page].get.ts",
25
- // server/plugins/* are intentionally excluded: starter keeps its own
26
- // systemPrompt and auth marketing copy; post-process only rewrites appId/title.
27
- "server/middleware/auth.ts",
28
- "components.json",
29
- ".oxfmtrc.json",
30
- "netlify.toml",
31
- ] as const;
32
-
33
- export const STARTER_SOURCE_MIGRATION_PATHS = [
34
- ":(glob)**/*.ts",
35
- ":(glob)**/*.tsx",
36
- ] as const;
37
-
38
- const STANDALONE_SNAPSHOT_EXCLUDED_TOP_LEVEL = new Set([
39
- ".deploy-tmp",
40
- ".env",
41
- ".env.local",
42
- ".generated",
43
- ".netlify",
44
- ".output",
45
- ".react-router",
46
- "build",
47
- "data",
48
- "dist",
49
- "node_modules",
50
- ]);
51
-
52
- export type StarterToolchainSyncPath =
53
- (typeof STARTER_TOOLCHAIN_SYNC_PATHS)[number];
54
-
55
- type PackageJson = Record<string, unknown>;
56
-
57
- export type StandaloneChatSnapshot = {
58
- cleanup: () => void;
59
- dir: string;
60
- packageJson: PackageJson;
61
- pnpmWorkspaceYaml: string | null;
62
- toolchainFiles: Map<StarterToolchainSyncPath, string>;
63
- };
64
-
65
- export function listStarterSyncPaths(): string[] {
66
- return [
67
- "package.json",
68
- "pnpm-lock.yaml",
69
- "pnpm-workspace.yaml",
70
- ...STARTER_TOOLCHAIN_SYNC_PATHS,
71
- ...STARTER_SOURCE_MIGRATION_PATHS,
72
- ];
73
- }
74
-
75
- export function migrateStarterSources(options: {
76
- starterDir: string;
77
- repoRoot: string;
78
- coreVersion: string | null;
79
- write?: boolean;
80
- }): { changedPaths: string[]; warnings: string[] } {
81
- const manifestPath = path.join(
82
- options.repoRoot,
83
- "packages/core/migration-manifest.json",
84
- );
85
- const manifest = readMigrationManifest(manifestPath);
86
- if (!manifest) {
87
- throw new Error(`Could not read migration manifest at ${manifestPath}.`);
88
- }
89
- if (!isMigrationManifestActive(manifest, options.coreVersion)) {
90
- return { changedPaths: [], warnings: [] };
91
- }
92
-
93
- const result = runMigrationCodemods({
94
- root: options.starterDir,
95
- manifests: [manifest],
96
- apply: options.write,
97
- // Checked-in migration targets are validated by the manifest guard before
98
- // this source sync runs; starter dependencies are installed afterward.
99
- targetExists: () => true,
100
- });
101
-
102
- return {
103
- changedPaths: [
104
- ...new Set(
105
- result.changes.map((change) =>
106
- path.relative(options.starterDir, change.file),
107
- ),
108
- ),
109
- ].sort(),
110
- warnings: result.warnings,
111
- };
112
- }
113
-
114
- export function resolveStarterCoreVersion(
115
- starterPackageJson: PackageJson,
116
- repoRoot: string,
117
- ): string | null {
118
- const dependencies = starterPackageJson.dependencies;
119
- if (dependencies && typeof dependencies === "object") {
120
- const declared = (dependencies as Record<string, unknown>)[
121
- "@agent-native/core"
122
- ];
123
- if (typeof declared === "string") {
124
- const version = declared.match(/\d+\.\d+\.\d+/)?.[0];
125
- if (version) return version;
126
- }
127
- }
128
-
129
- try {
130
- const corePackageJson = JSON.parse(
131
- fs.readFileSync(
132
- path.join(repoRoot, "packages/core/package.json"),
133
- "utf-8",
134
- ),
135
- ) as { version?: unknown };
136
- return typeof corePackageJson.version === "string"
137
- ? corePackageJson.version
138
- : null;
139
- } catch {
140
- return null;
141
- }
142
- }
143
-
144
- export function findAgentNativeRoot(startDir = process.cwd()): string {
145
- let dir = path.resolve(startDir);
146
- for (let i = 0; i < 12; i++) {
147
- const chatPackageJson = path.join(
148
- dir,
149
- "templates",
150
- CHAT_TEMPLATE,
151
- "package.json",
152
- );
153
- if (fs.existsSync(chatPackageJson)) {
154
- return dir;
155
- }
156
- const parent = path.dirname(dir);
157
- if (parent === dir) break;
158
- dir = parent;
159
- }
160
- throw new Error(
161
- "Could not find agent-native repo root (expected templates/chat/package.json).",
162
- );
163
- }
164
-
165
- export function collectStarterToolchainFiles(
166
- canonicalDir: string,
167
- ): Map<StarterToolchainSyncPath, string> {
168
- const files = new Map<StarterToolchainSyncPath, string>();
169
- for (const relativePath of STARTER_TOOLCHAIN_SYNC_PATHS) {
170
- const absolutePath = path.join(canonicalDir, relativePath);
171
- if (!fs.existsSync(absolutePath)) continue;
172
- files.set(relativePath, fs.readFileSync(absolutePath, "utf-8"));
173
- }
174
- return files;
175
- }
176
-
177
- export function createStandaloneChatSnapshot(
178
- repoRoot?: string,
179
- ): StandaloneChatSnapshot {
180
- const root = repoRoot ?? findAgentNativeRoot();
181
- const chatTemplateDir = path.join(root, "templates", CHAT_TEMPLATE);
182
- const tempDir = fs.mkdtempSync(
183
- path.join(os.tmpdir(), "an-builder-starter-sync-"),
184
- );
185
-
186
- fs.cpSync(chatTemplateDir, tempDir, {
187
- recursive: true,
188
- filter: (source) =>
189
- shouldCopyStandaloneSnapshotPath(source, chatTemplateDir),
190
- });
191
- _postProcessStandalone(STARTER_APP_NAME, tempDir, CHAT_TEMPLATE);
192
-
193
- const packageJson = JSON.parse(
194
- fs.readFileSync(path.join(tempDir, "package.json"), "utf-8"),
195
- ) as PackageJson;
196
-
197
- const workspacePath = path.join(tempDir, "pnpm-workspace.yaml");
198
- const pnpmWorkspaceYaml = fs.existsSync(workspacePath)
199
- ? fs.readFileSync(workspacePath, "utf-8")
200
- : null;
201
-
202
- return {
203
- cleanup: () => {
204
- fs.rmSync(tempDir, { recursive: true, force: true });
205
- },
206
- dir: tempDir,
207
- packageJson,
208
- pnpmWorkspaceYaml,
209
- toolchainFiles: collectStarterToolchainFiles(tempDir),
210
- };
211
- }
212
-
213
- function shouldCopyStandaloneSnapshotPath(
214
- source: string,
215
- root: string,
216
- ): boolean {
217
- const relative = path.relative(root, source);
218
- if (!relative) return true;
219
- const topLevel = relative.split(path.sep)[0];
220
- return !STANDALONE_SNAPSHOT_EXCLUDED_TOP_LEVEL.has(topLevel);
221
- }
222
-
223
- export function generateStandaloneChatManifest(repoRoot?: string): {
224
- packageJson: PackageJson;
225
- pnpmWorkspaceYaml: string | null;
226
- } {
227
- const snapshot = createStandaloneChatSnapshot(repoRoot);
228
- try {
229
- return {
230
- packageJson: snapshot.packageJson,
231
- pnpmWorkspaceYaml: snapshot.pnpmWorkspaceYaml,
232
- };
233
- } finally {
234
- snapshot.cleanup();
235
- }
236
- }
237
-
238
- function mergePackageJsonRecords(
239
- canonical: Record<string, string> | undefined,
240
- starter: Record<string, string> | undefined,
241
- starterPinnedKeys: string[] = [],
242
- ): Record<string, string> {
243
- const merged = { ...(canonical ?? {}) };
244
- for (const [key, value] of Object.entries(starter ?? {})) {
245
- if (!(key in merged)) {
246
- merged[key] = value;
247
- }
248
- }
249
- for (const key of starterPinnedKeys) {
250
- const pinned = starter?.[key];
251
- if (pinned) {
252
- merged[key] = pinned;
253
- }
254
- }
255
- return merged;
256
- }
257
-
258
- export function mergeStarterManifest(
259
- starterPackageJson: PackageJson,
260
- canonicalPackageJson: PackageJson,
261
- ): PackageJson {
262
- const merged = structuredClone(canonicalPackageJson) as PackageJson;
263
-
264
- merged.name = starterPackageJson.name ?? STARTER_APP_NAME;
265
- if (typeof starterPackageJson.displayName === "string") {
266
- merged.displayName = starterPackageJson.displayName;
267
- }
268
- if (typeof starterPackageJson.description === "string") {
269
- merged.description = starterPackageJson.description;
270
- }
271
- if (starterPackageJson.private !== undefined) {
272
- merged.private = starterPackageJson.private;
273
- }
274
- if (typeof starterPackageJson.packageManager === "string") {
275
- merged.packageManager = starterPackageJson.packageManager;
276
- }
277
-
278
- merged.dependencies = mergePackageJsonRecords(
279
- canonicalPackageJson.dependencies as Record<string, string> | undefined,
280
- starterPackageJson.dependencies as Record<string, string> | undefined,
281
- ["@agent-native/core", "@agent-native/toolkit"],
282
- );
283
- merged.devDependencies = mergePackageJsonRecords(
284
- canonicalPackageJson.devDependencies as Record<string, string> | undefined,
285
- starterPackageJson.devDependencies as Record<string, string> | undefined,
286
- );
287
- merged.scripts = mergePackageJsonRecords(
288
- canonicalPackageJson.scripts as Record<string, string> | undefined,
289
- starterPackageJson.scripts as Record<string, string> | undefined,
290
- );
291
-
292
- return merged;
293
- }
294
-
295
- export function workspaceFileSyncChanged(
296
- existingWorkspace: string | null,
297
- canonicalWorkspace: string | null,
298
- ): boolean {
299
- if (canonicalWorkspace === null) {
300
- return existingWorkspace !== null;
301
- }
302
- return existingWorkspace !== canonicalWorkspace;
303
- }
304
-
305
- export function applyWorkspaceFileSync(
306
- targetPath: string,
307
- canonicalWorkspace: string | null,
308
- ): void {
309
- if (canonicalWorkspace === null) {
310
- if (fs.existsSync(targetPath)) {
311
- fs.unlinkSync(targetPath);
312
- }
313
- return;
314
- }
315
- fs.writeFileSync(targetPath, canonicalWorkspace);
316
- }
317
-
318
- function stableJson(value: unknown): string {
319
- return `${JSON.stringify(value, null, 2)}\n`;
320
- }
321
-
322
- export type StarterToolchainSyncChange = {
323
- relativePath: StarterToolchainSyncPath;
324
- changed: boolean;
325
- };
326
-
327
- export function diffStarterToolchainFiles(
328
- starterDir: string,
329
- canonicalFiles: Map<StarterToolchainSyncPath, string>,
330
- ): StarterToolchainSyncChange[] {
331
- return STARTER_TOOLCHAIN_SYNC_PATHS.map((relativePath) => {
332
- const canonicalContent = canonicalFiles.get(relativePath) ?? null;
333
- const targetPath = path.join(starterDir, relativePath);
334
- const existingContent = fs.existsSync(targetPath)
335
- ? fs.readFileSync(targetPath, "utf-8")
336
- : null;
337
- return {
338
- relativePath,
339
- changed: existingContent !== canonicalContent,
340
- };
341
- });
342
- }
343
-
344
- export function applyStarterToolchainSync(
345
- starterDir: string,
346
- canonicalFiles: Map<StarterToolchainSyncPath, string>,
347
- ): StarterToolchainSyncChange[] {
348
- const changes: StarterToolchainSyncChange[] = [];
349
- for (const relativePath of STARTER_TOOLCHAIN_SYNC_PATHS) {
350
- const canonicalContent = canonicalFiles.get(relativePath) ?? null;
351
- const targetPath = path.join(starterDir, relativePath);
352
- const existingContent = fs.existsSync(targetPath)
353
- ? fs.readFileSync(targetPath, "utf-8")
354
- : null;
355
- const changed = existingContent !== canonicalContent;
356
- if (changed) {
357
- if (canonicalContent === null) {
358
- if (fs.existsSync(targetPath)) {
359
- fs.unlinkSync(targetPath);
360
- }
361
- } else {
362
- fs.mkdirSync(path.dirname(targetPath), { recursive: true });
363
- fs.writeFileSync(targetPath, canonicalContent);
364
- }
365
- }
366
- changes.push({ relativePath, changed });
367
- }
368
- return changes;
369
- }
370
-
371
- export type SyncStarterManifestResult = {
372
- changed: boolean;
373
- packageChanged: boolean;
374
- workspaceChanged: boolean;
375
- packageJson: PackageJson;
376
- pnpmWorkspaceYaml: string | null;
377
- toolchainChanges: StarterToolchainSyncChange[];
378
- changedToolchainPaths: StarterToolchainSyncPath[];
379
- changedSourceMigrationPaths: string[];
380
- sourceMigrationWarnings: string[];
381
- };
382
-
383
- export function resolveStarterPaths(options: {
384
- starterDir?: string;
385
- starterPackageJsonPath?: string;
386
- starterPnpmWorkspacePath?: string;
387
- }): {
388
- starterDir: string;
389
- starterPackageJsonPath: string;
390
- starterPnpmWorkspacePath: string;
391
- } {
392
- if (options.starterDir) {
393
- return {
394
- starterDir: path.resolve(options.starterDir),
395
- starterPackageJsonPath: path.join(
396
- path.resolve(options.starterDir),
397
- "package.json",
398
- ),
399
- starterPnpmWorkspacePath: path.join(
400
- path.resolve(options.starterDir),
401
- "pnpm-workspace.yaml",
402
- ),
403
- };
404
- }
405
- if (!options.starterPackageJsonPath) {
406
- throw new Error("Provide --starter-dir or --starter-package-json.");
407
- }
408
- const starterPackageJsonPath = path.resolve(options.starterPackageJsonPath);
409
- return {
410
- starterDir: path.dirname(starterPackageJsonPath),
411
- starterPackageJsonPath,
412
- starterPnpmWorkspacePath:
413
- options.starterPnpmWorkspacePath ??
414
- path.join(path.dirname(starterPackageJsonPath), "pnpm-workspace.yaml"),
415
- };
416
- }
417
-
418
- export function syncStarterManifestFiles(options: {
419
- starterDir?: string;
420
- starterPackageJsonPath?: string;
421
- starterPnpmWorkspacePath?: string;
422
- repoRoot?: string;
423
- write?: boolean;
424
- }): SyncStarterManifestResult {
425
- const { starterDir, starterPackageJsonPath, starterPnpmWorkspacePath } =
426
- resolveStarterPaths(options);
427
- const snapshot = createStandaloneChatSnapshot(options.repoRoot);
428
-
429
- try {
430
- const repoRoot = options.repoRoot ?? findAgentNativeRoot();
431
- const initialStarterPackageJson = JSON.parse(
432
- fs.readFileSync(starterPackageJsonPath, "utf-8"),
433
- ) as PackageJson;
434
- const sourceMigration = migrateStarterSources({
435
- starterDir,
436
- repoRoot,
437
- coreVersion: resolveStarterCoreVersion(
438
- initialStarterPackageJson,
439
- repoRoot,
440
- ),
441
- write: options.write,
442
- });
443
- const starterPackageJson = JSON.parse(
444
- fs.readFileSync(starterPackageJsonPath, "utf-8"),
445
- ) as PackageJson;
446
- const mergedPackageJson = mergeStarterManifest(
447
- starterPackageJson,
448
- snapshot.packageJson,
449
- );
450
-
451
- const existingWorkspace = fs.existsSync(starterPnpmWorkspacePath)
452
- ? fs.readFileSync(starterPnpmWorkspacePath, "utf-8")
453
- : null;
454
-
455
- const workspaceChanged = workspaceFileSyncChanged(
456
- existingWorkspace,
457
- snapshot.pnpmWorkspaceYaml,
458
- );
459
- const packageChanged =
460
- stableJson(starterPackageJson) !== stableJson(mergedPackageJson);
461
- const toolchainChanges = diffStarterToolchainFiles(
462
- starterDir,
463
- snapshot.toolchainFiles,
464
- );
465
- const changedToolchainPaths = toolchainChanges
466
- .filter((change) => change.changed)
467
- .map((change) => change.relativePath);
468
- const changed =
469
- packageChanged ||
470
- workspaceChanged ||
471
- changedToolchainPaths.length > 0 ||
472
- sourceMigration.changedPaths.length > 0;
473
-
474
- if (options.write && changed) {
475
- if (packageChanged) {
476
- fs.writeFileSync(starterPackageJsonPath, stableJson(mergedPackageJson));
477
- }
478
- if (workspaceChanged) {
479
- applyWorkspaceFileSync(
480
- starterPnpmWorkspacePath,
481
- snapshot.pnpmWorkspaceYaml,
482
- );
483
- }
484
- if (changedToolchainPaths.length > 0) {
485
- applyStarterToolchainSync(starterDir, snapshot.toolchainFiles);
486
- }
487
- }
488
-
489
- return {
490
- changed,
491
- packageChanged,
492
- workspaceChanged,
493
- packageJson: mergedPackageJson,
494
- pnpmWorkspaceYaml: snapshot.pnpmWorkspaceYaml,
495
- toolchainChanges,
496
- changedToolchainPaths,
497
- changedSourceMigrationPaths: sourceMigration.changedPaths,
498
- sourceMigrationWarnings: sourceMigration.warnings,
499
- };
500
- } finally {
501
- snapshot.cleanup();
502
- }
503
- }
504
-
505
- export function parseSyncStarterManifestArgs(argv: string[]): {
506
- command: "merge" | "generate" | "paths";
507
- starterDir?: string;
508
- starterPackageJsonPath?: string;
509
- starterPnpmWorkspacePath?: string;
510
- write: boolean;
511
- repoRoot?: string;
512
- } {
513
- const [commandRaw, ...rest] = argv;
514
- const command =
515
- commandRaw === "generate"
516
- ? "generate"
517
- : commandRaw === "paths"
518
- ? "paths"
519
- : "merge";
520
- let starterDir: string | undefined;
521
- let starterPackageJsonPath: string | undefined;
522
- let starterPnpmWorkspacePath: string | undefined;
523
- let write = false;
524
- let repoRoot: string | undefined;
525
-
526
- for (let i = 0; i < rest.length; i++) {
527
- const arg = rest[i];
528
- if (arg === "--write") {
529
- write = true;
530
- continue;
531
- }
532
- if (arg === "--starter-dir") {
533
- starterDir = rest[++i];
534
- continue;
535
- }
536
- if (arg === "--starter-package-json") {
537
- starterPackageJsonPath = rest[++i];
538
- continue;
539
- }
540
- if (arg === "--starter-pnpm-workspace") {
541
- starterPnpmWorkspacePath = rest[++i];
542
- continue;
543
- }
544
- if (arg === "--repo-root") {
545
- repoRoot = rest[++i];
546
- continue;
547
- }
548
- throw new Error(`Unknown argument: ${arg}`);
549
- }
550
-
551
- if (command === "merge" && !starterDir && !starterPackageJsonPath) {
552
- throw new Error(
553
- "merge requires --starter-dir <path> or --starter-package-json <path> [--starter-pnpm-workspace <path>] [--write] [--repo-root <path>]",
554
- );
555
- }
556
-
557
- return {
558
- command,
559
- starterDir,
560
- starterPackageJsonPath,
561
- starterPnpmWorkspacePath,
562
- write,
563
- repoRoot,
564
- };
565
- }
566
-
567
- export function runSyncStarterManifestCli(argv: string[]): number {
568
- const args = parseSyncStarterManifestArgs(argv);
569
-
570
- if (args.command === "generate") {
571
- const { packageJson, pnpmWorkspaceYaml } = generateStandaloneChatManifest(
572
- args.repoRoot,
573
- );
574
- process.stdout.write(stableJson(packageJson));
575
- if (pnpmWorkspaceYaml) {
576
- process.stdout.write("\n--- pnpm-workspace.yaml ---\n");
577
- process.stdout.write(pnpmWorkspaceYaml);
578
- }
579
- return 0;
580
- }
581
-
582
- if (args.command === "paths") {
583
- for (const syncPath of listStarterSyncPaths()) {
584
- process.stdout.write(`${syncPath}\n`);
585
- }
586
- return 0;
587
- }
588
-
589
- const result = syncStarterManifestFiles({
590
- starterDir: args.starterDir,
591
- starterPackageJsonPath: args.starterPackageJsonPath,
592
- starterPnpmWorkspacePath: args.starterPnpmWorkspacePath,
593
- repoRoot: args.repoRoot,
594
- write: args.write,
595
- });
596
-
597
- for (const warning of result.sourceMigrationWarnings) {
598
- console.warn(`[starter migration] ${warning}`);
599
- }
600
-
601
- if (result.changed) {
602
- const updatedPaths = [
603
- ...new Set([
604
- ...(result.packageChanged ? ["package.json"] : []),
605
- ...(result.workspaceChanged ? ["pnpm-workspace.yaml"] : []),
606
- ...result.changedToolchainPaths,
607
- ...result.changedSourceMigrationPaths,
608
- ]),
609
- ];
610
- const summary = updatedPaths.length ? ` (${updatedPaths.join(", ")})` : "";
611
- console.log(
612
- args.write
613
- ? `Updated builder-agent-native-starter from templates/chat${summary}.`
614
- : `builder-agent-native-starter is out of date with templates/chat${summary}.`,
615
- );
616
- return args.write ? 0 : 1;
617
- }
618
-
619
- console.log("builder-agent-native-starter already matches templates/chat.");
620
- return 0;
621
- }
622
-
623
- const isDirectRun =
624
- process.argv[1] &&
625
- path.resolve(process.argv[1]) ===
626
- path.resolve(fileURLToPath(import.meta.url));
627
-
628
- if (isDirectRun) {
629
- const exitCode = runSyncStarterManifestCli(process.argv.slice(2));
630
- process.exit(exitCode);
631
- }