@agent-native/core 0.77.11 → 0.77.12
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/corpus/core/CHANGELOG.md +6 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/cli/create.ts +65 -15
- package/corpus/core/src/cli/sync-builder-starter-manifest.ts +261 -65
- package/corpus/templates/clips/actions/finalize-recording.ts +1 -1
- package/corpus/templates/clips/desktop/src/app.tsx +35 -19
- package/corpus/templates/clips/desktop/src/overlays/toolbar.tsx +38 -1
- package/corpus/templates/clips/desktop/src/styles.css +35 -0
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +343 -14
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +53 -15
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/sync-builder-starter-manifest.d.ts +36 -2
- package/dist/cli/sync-builder-starter-manifest.d.ts.map +1 -1
- package/dist/cli/sync-builder-starter-manifest.js +180 -37
- package/dist/cli/sync-builder-starter-manifest.js.map +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/server/agent-engine-api-key-route.d.ts +2 -2
- package/package.json +1 -1
package/corpus/core/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @agent-native/core
|
|
2
2
|
|
|
3
|
+
## 0.77.12
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 67dba9b: Sync builder-agent-native-starter toolchain files (React Router config, Vite config, server plugins, etc.) alongside the manifest so dependency bumps from templates/chat do not leave the starter in a broken state. Standalone UI scaffolds re-declare tsconfig `paths` and `baseUrl` for `@/*` resolution; headless scaffolds omit `baseUrl` for TS 6 tsgo compatibility. Netlify post-process now rewrites unindented template build commands.
|
|
8
|
+
|
|
3
9
|
## 0.77.11
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/corpus/core/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.77.
|
|
3
|
+
"version": "0.77.12",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -27,19 +27,7 @@ const STANDALONE_EXACT_DEPENDENCY_OVERRIDES: Record<string, string> = {
|
|
|
27
27
|
"@react-router/fs-routes": "8.0.1",
|
|
28
28
|
"react-router": "8.0.1",
|
|
29
29
|
};
|
|
30
|
-
const SENTRY_MINIMUM_RELEASE_AGE_EXCLUDES = [
|
|
31
|
-
'"@sentry/browser"',
|
|
32
|
-
'"@sentry/browser-utils"',
|
|
33
|
-
'"@sentry/conventions"',
|
|
34
|
-
'"@sentry/core"',
|
|
35
|
-
'"@sentry/feedback"',
|
|
36
|
-
'"@sentry/node"',
|
|
37
|
-
'"@sentry/node-core"',
|
|
38
|
-
'"@sentry/opentelemetry"',
|
|
39
|
-
'"@sentry/replay"',
|
|
40
|
-
'"@sentry/replay-canvas"',
|
|
41
|
-
'"@sentry/server-utils"',
|
|
42
|
-
];
|
|
30
|
+
const SENTRY_MINIMUM_RELEASE_AGE_EXCLUDES = ['"@sentry/*"'];
|
|
43
31
|
const FIRST_PARTY_TARBALL_SYMLINK_EXCLUDES = [
|
|
44
32
|
"*/CLAUDE.md",
|
|
45
33
|
"*/.claude/skills",
|
|
@@ -978,6 +966,7 @@ function postProcessStandalone(
|
|
|
978
966
|
const appTitle = appTitleForScaffold(name);
|
|
979
967
|
replacePlaceholders(targetDir, name, appTitle);
|
|
980
968
|
rewriteTrackingAppId(targetDir, name, templateName);
|
|
969
|
+
rewriteAgentChatAppId(targetDir, name, templateName);
|
|
981
970
|
fixPackageJsonName(targetDir, name, templateName);
|
|
982
971
|
fixWebManifestName(targetDir, name, templateName);
|
|
983
972
|
rewriteNetlifyToml(targetDir, name, "standalone");
|
|
@@ -1078,9 +1067,40 @@ function postProcessStandalone(
|
|
|
1078
1067
|
}
|
|
1079
1068
|
} catch {}
|
|
1080
1069
|
|
|
1070
|
+
fixStandaloneTsconfig(targetDir, templateName);
|
|
1071
|
+
|
|
1081
1072
|
setupAgentSymlinks(targetDir);
|
|
1082
1073
|
}
|
|
1083
1074
|
|
|
1075
|
+
function fixStandaloneTsconfig(targetDir: string, templateName?: string): void {
|
|
1076
|
+
const tsconfigPath = path.join(targetDir, "tsconfig.json");
|
|
1077
|
+
if (!fs.existsSync(tsconfigPath)) return;
|
|
1078
|
+
try {
|
|
1079
|
+
const tsconfig = JSON.parse(fs.readFileSync(tsconfigPath, "utf-8")) as {
|
|
1080
|
+
compilerOptions?: Record<string, unknown>;
|
|
1081
|
+
};
|
|
1082
|
+
tsconfig.compilerOptions ??= {};
|
|
1083
|
+
const hasUiApp =
|
|
1084
|
+
templateName !== "headless" && fs.existsSync(path.join(targetDir, "app"));
|
|
1085
|
+
const paths = {
|
|
1086
|
+
...((tsconfig.compilerOptions.paths as Record<string, string[]>) ?? {}),
|
|
1087
|
+
};
|
|
1088
|
+
paths["*"] ??= ["./*"];
|
|
1089
|
+
if (hasUiApp) {
|
|
1090
|
+
paths["@/*"] ??= ["./app/*"];
|
|
1091
|
+
paths["@shared/*"] ??= ["./shared/*"];
|
|
1092
|
+
// Child baseUrl anchors @/* for apps extending legacy core tsconfig bases
|
|
1093
|
+
// that still ship baseUrl. Headless scaffolds omit it so raw tsgo --noEmit
|
|
1094
|
+
// keeps working under TS 6.
|
|
1095
|
+
tsconfig.compilerOptions.baseUrl = ".";
|
|
1096
|
+
} else {
|
|
1097
|
+
delete tsconfig.compilerOptions.baseUrl;
|
|
1098
|
+
}
|
|
1099
|
+
tsconfig.compilerOptions.paths = paths;
|
|
1100
|
+
fs.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}\n`);
|
|
1101
|
+
} catch {}
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1084
1104
|
/* ─────────────────────────────────────────────────────────────────────────
|
|
1085
1105
|
* Prompting helpers
|
|
1086
1106
|
* ───────────────────────────────────────────────────────────────────────── */
|
|
@@ -1734,7 +1754,7 @@ function rewriteNetlifyToml(
|
|
|
1734
1754
|
|
|
1735
1755
|
try {
|
|
1736
1756
|
let content = fs.readFileSync(netlifyPath, "utf-8");
|
|
1737
|
-
const originalCommand = content.match(
|
|
1757
|
+
const originalCommand = content.match(/^\s*command = "([^"]*)"$/m)?.[1];
|
|
1738
1758
|
const usesUnpooledDatabase =
|
|
1739
1759
|
originalCommand?.includes("NETLIFY_DATABASE_URL_UNPOOLED") ?? false;
|
|
1740
1760
|
const buildCommand =
|
|
@@ -1754,7 +1774,7 @@ function rewriteNetlifyToml(
|
|
|
1754
1774
|
: ".netlify/functions-internal";
|
|
1755
1775
|
|
|
1756
1776
|
content = content
|
|
1757
|
-
.replace(/^
|
|
1777
|
+
.replace(/^(\s*)command = ".*"$/m, `$1command = "${command}"`)
|
|
1758
1778
|
.replace(
|
|
1759
1779
|
/publish = "templates\/[^"]+\/dist"/g,
|
|
1760
1780
|
`publish = "${publishPath}"`,
|
|
@@ -1776,6 +1796,36 @@ function rewriteNetlifyToml(
|
|
|
1776
1796
|
} catch {}
|
|
1777
1797
|
}
|
|
1778
1798
|
|
|
1799
|
+
function rewriteAgentChatAppId(
|
|
1800
|
+
appDir: string,
|
|
1801
|
+
appName: string,
|
|
1802
|
+
templateName?: string,
|
|
1803
|
+
): void {
|
|
1804
|
+
const pluginPath = path.join(appDir, "server", "plugins", "agent-chat.ts");
|
|
1805
|
+
if (!fs.existsSync(pluginPath)) return;
|
|
1806
|
+
|
|
1807
|
+
try {
|
|
1808
|
+
const content = fs.readFileSync(pluginPath, "utf-8");
|
|
1809
|
+
const sourceAppIds = ["chat", "starter"];
|
|
1810
|
+
if (templateName && templateName !== appName) {
|
|
1811
|
+
sourceAppIds.push(templateName);
|
|
1812
|
+
}
|
|
1813
|
+
const pattern = new RegExp(
|
|
1814
|
+
`(appId:\\s*)(["'])(${sourceAppIds.map(escapeRegExp).join("|")})\\2`,
|
|
1815
|
+
);
|
|
1816
|
+
if (!pattern.test(content)) return;
|
|
1817
|
+
|
|
1818
|
+
const next = content.replace(
|
|
1819
|
+
pattern,
|
|
1820
|
+
(_match, prefix: string, quote: string) =>
|
|
1821
|
+
`${prefix}${quote}${appName}${quote}`,
|
|
1822
|
+
);
|
|
1823
|
+
if (next !== content) {
|
|
1824
|
+
fs.writeFileSync(pluginPath, next);
|
|
1825
|
+
}
|
|
1826
|
+
} catch {}
|
|
1827
|
+
}
|
|
1828
|
+
|
|
1779
1829
|
function rewriteTrackingAppId(
|
|
1780
1830
|
appDir: string,
|
|
1781
1831
|
appName: string,
|
|
@@ -8,8 +8,45 @@ import { _postProcessStandalone } from "./create.js";
|
|
|
8
8
|
export const STARTER_APP_NAME = "builder-agent-native-starter";
|
|
9
9
|
export const CHAT_TEMPLATE = "chat";
|
|
10
10
|
|
|
11
|
+
/** Toolchain files that must track templates/chat or typecheck/build drift. */
|
|
12
|
+
export const STARTER_TOOLCHAIN_SYNC_PATHS = [
|
|
13
|
+
"react-router.config.ts",
|
|
14
|
+
"vite.config.ts",
|
|
15
|
+
"tsconfig.json",
|
|
16
|
+
"ssr-entry.ts",
|
|
17
|
+
"app/vite-env.d.ts",
|
|
18
|
+
"app/routes.ts",
|
|
19
|
+
"server/routes/[...page].get.ts",
|
|
20
|
+
// server/plugins/* are intentionally excluded: starter keeps its own
|
|
21
|
+
// systemPrompt and auth marketing copy; post-process only rewrites appId/title.
|
|
22
|
+
"server/middleware/auth.ts",
|
|
23
|
+
"components.json",
|
|
24
|
+
".oxfmtrc.json",
|
|
25
|
+
"netlify.toml",
|
|
26
|
+
] as const;
|
|
27
|
+
|
|
28
|
+
export type StarterToolchainSyncPath =
|
|
29
|
+
(typeof STARTER_TOOLCHAIN_SYNC_PATHS)[number];
|
|
30
|
+
|
|
11
31
|
type PackageJson = Record<string, unknown>;
|
|
12
32
|
|
|
33
|
+
export type StandaloneChatSnapshot = {
|
|
34
|
+
cleanup: () => void;
|
|
35
|
+
dir: string;
|
|
36
|
+
packageJson: PackageJson;
|
|
37
|
+
pnpmWorkspaceYaml: string | null;
|
|
38
|
+
toolchainFiles: Map<StarterToolchainSyncPath, string>;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export function listStarterSyncPaths(): string[] {
|
|
42
|
+
return [
|
|
43
|
+
"package.json",
|
|
44
|
+
"pnpm-lock.yaml",
|
|
45
|
+
"pnpm-workspace.yaml",
|
|
46
|
+
...STARTER_TOOLCHAIN_SYNC_PATHS,
|
|
47
|
+
];
|
|
48
|
+
}
|
|
49
|
+
|
|
13
50
|
export function findAgentNativeRoot(startDir = process.cwd()): string {
|
|
14
51
|
let dir = path.resolve(startDir);
|
|
15
52
|
for (let i = 0; i < 12; i++) {
|
|
@@ -31,32 +68,62 @@ export function findAgentNativeRoot(startDir = process.cwd()): string {
|
|
|
31
68
|
);
|
|
32
69
|
}
|
|
33
70
|
|
|
34
|
-
export function
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
71
|
+
export function collectStarterToolchainFiles(
|
|
72
|
+
canonicalDir: string,
|
|
73
|
+
): Map<StarterToolchainSyncPath, string> {
|
|
74
|
+
const files = new Map<StarterToolchainSyncPath, string>();
|
|
75
|
+
for (const relativePath of STARTER_TOOLCHAIN_SYNC_PATHS) {
|
|
76
|
+
const absolutePath = path.join(canonicalDir, relativePath);
|
|
77
|
+
if (!fs.existsSync(absolutePath)) continue;
|
|
78
|
+
files.set(relativePath, fs.readFileSync(absolutePath, "utf-8"));
|
|
79
|
+
}
|
|
80
|
+
return files;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function createStandaloneChatSnapshot(
|
|
84
|
+
repoRoot?: string,
|
|
85
|
+
): StandaloneChatSnapshot {
|
|
38
86
|
const root = repoRoot ?? findAgentNativeRoot();
|
|
39
87
|
const chatTemplateDir = path.join(root, "templates", CHAT_TEMPLATE);
|
|
40
88
|
const tempDir = fs.mkdtempSync(
|
|
41
89
|
path.join(os.tmpdir(), "an-builder-starter-sync-"),
|
|
42
90
|
);
|
|
43
91
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
_postProcessStandalone(STARTER_APP_NAME, tempDir, CHAT_TEMPLATE);
|
|
92
|
+
fs.cpSync(chatTemplateDir, tempDir, { recursive: true });
|
|
93
|
+
_postProcessStandalone(STARTER_APP_NAME, tempDir, CHAT_TEMPLATE);
|
|
47
94
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
95
|
+
const packageJson = JSON.parse(
|
|
96
|
+
fs.readFileSync(path.join(tempDir, "package.json"), "utf-8"),
|
|
97
|
+
) as PackageJson;
|
|
51
98
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
99
|
+
const workspacePath = path.join(tempDir, "pnpm-workspace.yaml");
|
|
100
|
+
const pnpmWorkspaceYaml = fs.existsSync(workspacePath)
|
|
101
|
+
? fs.readFileSync(workspacePath, "utf-8")
|
|
102
|
+
: null;
|
|
56
103
|
|
|
57
|
-
|
|
104
|
+
return {
|
|
105
|
+
cleanup: () => {
|
|
106
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
107
|
+
},
|
|
108
|
+
dir: tempDir,
|
|
109
|
+
packageJson,
|
|
110
|
+
pnpmWorkspaceYaml,
|
|
111
|
+
toolchainFiles: collectStarterToolchainFiles(tempDir),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function generateStandaloneChatManifest(repoRoot?: string): {
|
|
116
|
+
packageJson: PackageJson;
|
|
117
|
+
pnpmWorkspaceYaml: string | null;
|
|
118
|
+
} {
|
|
119
|
+
const snapshot = createStandaloneChatSnapshot(repoRoot);
|
|
120
|
+
try {
|
|
121
|
+
return {
|
|
122
|
+
packageJson: snapshot.packageJson,
|
|
123
|
+
pnpmWorkspaceYaml: snapshot.pnpmWorkspaceYaml,
|
|
124
|
+
};
|
|
58
125
|
} finally {
|
|
59
|
-
|
|
126
|
+
snapshot.cleanup();
|
|
60
127
|
}
|
|
61
128
|
}
|
|
62
129
|
|
|
@@ -144,73 +211,185 @@ function stableJson(value: unknown): string {
|
|
|
144
211
|
return `${JSON.stringify(value, null, 2)}\n`;
|
|
145
212
|
}
|
|
146
213
|
|
|
214
|
+
export type StarterToolchainSyncChange = {
|
|
215
|
+
relativePath: StarterToolchainSyncPath;
|
|
216
|
+
changed: boolean;
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
export function diffStarterToolchainFiles(
|
|
220
|
+
starterDir: string,
|
|
221
|
+
canonicalFiles: Map<StarterToolchainSyncPath, string>,
|
|
222
|
+
): StarterToolchainSyncChange[] {
|
|
223
|
+
return STARTER_TOOLCHAIN_SYNC_PATHS.map((relativePath) => {
|
|
224
|
+
const canonicalContent = canonicalFiles.get(relativePath) ?? null;
|
|
225
|
+
const targetPath = path.join(starterDir, relativePath);
|
|
226
|
+
const existingContent = fs.existsSync(targetPath)
|
|
227
|
+
? fs.readFileSync(targetPath, "utf-8")
|
|
228
|
+
: null;
|
|
229
|
+
return {
|
|
230
|
+
relativePath,
|
|
231
|
+
changed: existingContent !== canonicalContent,
|
|
232
|
+
};
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export function applyStarterToolchainSync(
|
|
237
|
+
starterDir: string,
|
|
238
|
+
canonicalFiles: Map<StarterToolchainSyncPath, string>,
|
|
239
|
+
): StarterToolchainSyncChange[] {
|
|
240
|
+
const changes: StarterToolchainSyncChange[] = [];
|
|
241
|
+
for (const relativePath of STARTER_TOOLCHAIN_SYNC_PATHS) {
|
|
242
|
+
const canonicalContent = canonicalFiles.get(relativePath) ?? null;
|
|
243
|
+
const targetPath = path.join(starterDir, relativePath);
|
|
244
|
+
const existingContent = fs.existsSync(targetPath)
|
|
245
|
+
? fs.readFileSync(targetPath, "utf-8")
|
|
246
|
+
: null;
|
|
247
|
+
const changed = existingContent !== canonicalContent;
|
|
248
|
+
if (changed) {
|
|
249
|
+
if (canonicalContent === null) {
|
|
250
|
+
if (fs.existsSync(targetPath)) {
|
|
251
|
+
fs.unlinkSync(targetPath);
|
|
252
|
+
}
|
|
253
|
+
} else {
|
|
254
|
+
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
255
|
+
fs.writeFileSync(targetPath, canonicalContent);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
changes.push({ relativePath, changed });
|
|
259
|
+
}
|
|
260
|
+
return changes;
|
|
261
|
+
}
|
|
262
|
+
|
|
147
263
|
export type SyncStarterManifestResult = {
|
|
148
264
|
changed: boolean;
|
|
265
|
+
packageChanged: boolean;
|
|
266
|
+
workspaceChanged: boolean;
|
|
149
267
|
packageJson: PackageJson;
|
|
150
268
|
pnpmWorkspaceYaml: string | null;
|
|
269
|
+
toolchainChanges: StarterToolchainSyncChange[];
|
|
270
|
+
changedToolchainPaths: StarterToolchainSyncPath[];
|
|
151
271
|
};
|
|
152
272
|
|
|
153
|
-
export function
|
|
273
|
+
export function resolveStarterPaths(options: {
|
|
274
|
+
starterDir?: string;
|
|
275
|
+
starterPackageJsonPath?: string;
|
|
276
|
+
starterPnpmWorkspacePath?: string;
|
|
277
|
+
}): {
|
|
278
|
+
starterDir: string;
|
|
154
279
|
starterPackageJsonPath: string;
|
|
280
|
+
starterPnpmWorkspacePath: string;
|
|
281
|
+
} {
|
|
282
|
+
if (options.starterDir) {
|
|
283
|
+
return {
|
|
284
|
+
starterDir: path.resolve(options.starterDir),
|
|
285
|
+
starterPackageJsonPath: path.join(
|
|
286
|
+
path.resolve(options.starterDir),
|
|
287
|
+
"package.json",
|
|
288
|
+
),
|
|
289
|
+
starterPnpmWorkspacePath: path.join(
|
|
290
|
+
path.resolve(options.starterDir),
|
|
291
|
+
"pnpm-workspace.yaml",
|
|
292
|
+
),
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
if (!options.starterPackageJsonPath) {
|
|
296
|
+
throw new Error("Provide --starter-dir or --starter-package-json.");
|
|
297
|
+
}
|
|
298
|
+
const starterPackageJsonPath = path.resolve(options.starterPackageJsonPath);
|
|
299
|
+
return {
|
|
300
|
+
starterDir: path.dirname(starterPackageJsonPath),
|
|
301
|
+
starterPackageJsonPath,
|
|
302
|
+
starterPnpmWorkspacePath:
|
|
303
|
+
options.starterPnpmWorkspacePath ??
|
|
304
|
+
path.join(path.dirname(starterPackageJsonPath), "pnpm-workspace.yaml"),
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export function syncStarterManifestFiles(options: {
|
|
309
|
+
starterDir?: string;
|
|
310
|
+
starterPackageJsonPath?: string;
|
|
155
311
|
starterPnpmWorkspacePath?: string;
|
|
156
312
|
repoRoot?: string;
|
|
157
313
|
write?: boolean;
|
|
158
314
|
}): SyncStarterManifestResult {
|
|
159
|
-
const {
|
|
160
|
-
|
|
315
|
+
const { starterDir, starterPackageJsonPath, starterPnpmWorkspacePath } =
|
|
316
|
+
resolveStarterPaths(options);
|
|
317
|
+
const snapshot = createStandaloneChatSnapshot(options.repoRoot);
|
|
161
318
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
319
|
+
try {
|
|
320
|
+
const starterPackageJson = JSON.parse(
|
|
321
|
+
fs.readFileSync(starterPackageJsonPath, "utf-8"),
|
|
322
|
+
) as PackageJson;
|
|
323
|
+
const mergedPackageJson = mergeStarterManifest(
|
|
324
|
+
starterPackageJson,
|
|
325
|
+
snapshot.packageJson,
|
|
326
|
+
);
|
|
166
327
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
options.starterPnpmWorkspacePath &&
|
|
170
|
-
fs.existsSync(options.starterPnpmWorkspacePath)
|
|
171
|
-
? fs.readFileSync(options.starterPnpmWorkspacePath, "utf-8")
|
|
328
|
+
const existingWorkspace = fs.existsSync(starterPnpmWorkspacePath)
|
|
329
|
+
? fs.readFileSync(starterPnpmWorkspacePath, "utf-8")
|
|
172
330
|
: null;
|
|
173
331
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
if (
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
)
|
|
332
|
+
const workspaceChanged = workspaceFileSyncChanged(
|
|
333
|
+
existingWorkspace,
|
|
334
|
+
snapshot.pnpmWorkspaceYaml,
|
|
335
|
+
);
|
|
336
|
+
const packageChanged =
|
|
337
|
+
stableJson(starterPackageJson) !== stableJson(mergedPackageJson);
|
|
338
|
+
const toolchainChanges = diffStarterToolchainFiles(
|
|
339
|
+
starterDir,
|
|
340
|
+
snapshot.toolchainFiles,
|
|
341
|
+
);
|
|
342
|
+
const changedToolchainPaths = toolchainChanges
|
|
343
|
+
.filter((change) => change.changed)
|
|
344
|
+
.map((change) => change.relativePath);
|
|
345
|
+
const changed =
|
|
346
|
+
packageChanged || workspaceChanged || changedToolchainPaths.length > 0;
|
|
347
|
+
|
|
348
|
+
if (options.write && changed) {
|
|
349
|
+
if (packageChanged) {
|
|
350
|
+
fs.writeFileSync(starterPackageJsonPath, stableJson(mergedPackageJson));
|
|
351
|
+
}
|
|
352
|
+
if (workspaceChanged) {
|
|
353
|
+
applyWorkspaceFileSync(
|
|
354
|
+
starterPnpmWorkspacePath,
|
|
355
|
+
snapshot.pnpmWorkspaceYaml,
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
if (changedToolchainPaths.length > 0) {
|
|
359
|
+
applyStarterToolchainSync(starterDir, snapshot.toolchainFiles);
|
|
360
|
+
}
|
|
195
361
|
}
|
|
196
|
-
}
|
|
197
362
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
363
|
+
return {
|
|
364
|
+
changed,
|
|
365
|
+
packageChanged,
|
|
366
|
+
workspaceChanged,
|
|
367
|
+
packageJson: mergedPackageJson,
|
|
368
|
+
pnpmWorkspaceYaml: snapshot.pnpmWorkspaceYaml,
|
|
369
|
+
toolchainChanges,
|
|
370
|
+
changedToolchainPaths,
|
|
371
|
+
};
|
|
372
|
+
} finally {
|
|
373
|
+
snapshot.cleanup();
|
|
374
|
+
}
|
|
203
375
|
}
|
|
204
376
|
|
|
205
377
|
export function parseSyncStarterManifestArgs(argv: string[]): {
|
|
206
|
-
command: "merge" | "generate";
|
|
378
|
+
command: "merge" | "generate" | "paths";
|
|
379
|
+
starterDir?: string;
|
|
207
380
|
starterPackageJsonPath?: string;
|
|
208
381
|
starterPnpmWorkspacePath?: string;
|
|
209
382
|
write: boolean;
|
|
210
383
|
repoRoot?: string;
|
|
211
384
|
} {
|
|
212
385
|
const [commandRaw, ...rest] = argv;
|
|
213
|
-
const command =
|
|
386
|
+
const command =
|
|
387
|
+
commandRaw === "generate"
|
|
388
|
+
? "generate"
|
|
389
|
+
: commandRaw === "paths"
|
|
390
|
+
? "paths"
|
|
391
|
+
: "merge";
|
|
392
|
+
let starterDir: string | undefined;
|
|
214
393
|
let starterPackageJsonPath: string | undefined;
|
|
215
394
|
let starterPnpmWorkspacePath: string | undefined;
|
|
216
395
|
let write = false;
|
|
@@ -222,6 +401,10 @@ export function parseSyncStarterManifestArgs(argv: string[]): {
|
|
|
222
401
|
write = true;
|
|
223
402
|
continue;
|
|
224
403
|
}
|
|
404
|
+
if (arg === "--starter-dir") {
|
|
405
|
+
starterDir = rest[++i];
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
225
408
|
if (arg === "--starter-package-json") {
|
|
226
409
|
starterPackageJsonPath = rest[++i];
|
|
227
410
|
continue;
|
|
@@ -237,14 +420,15 @@ export function parseSyncStarterManifestArgs(argv: string[]): {
|
|
|
237
420
|
throw new Error(`Unknown argument: ${arg}`);
|
|
238
421
|
}
|
|
239
422
|
|
|
240
|
-
if (command === "merge" && !starterPackageJsonPath) {
|
|
423
|
+
if (command === "merge" && !starterDir && !starterPackageJsonPath) {
|
|
241
424
|
throw new Error(
|
|
242
|
-
"merge requires --starter-package-json <path> [--starter-pnpm-workspace <path>] [--write] [--repo-root <path>]",
|
|
425
|
+
"merge requires --starter-dir <path> or --starter-package-json <path> [--starter-pnpm-workspace <path>] [--write] [--repo-root <path>]",
|
|
243
426
|
);
|
|
244
427
|
}
|
|
245
428
|
|
|
246
429
|
return {
|
|
247
430
|
command,
|
|
431
|
+
starterDir,
|
|
248
432
|
starterPackageJsonPath,
|
|
249
433
|
starterPnpmWorkspacePath,
|
|
250
434
|
write,
|
|
@@ -267,25 +451,37 @@ export function runSyncStarterManifestCli(argv: string[]): number {
|
|
|
267
451
|
return 0;
|
|
268
452
|
}
|
|
269
453
|
|
|
454
|
+
if (args.command === "paths") {
|
|
455
|
+
for (const syncPath of listStarterSyncPaths()) {
|
|
456
|
+
process.stdout.write(`${syncPath}\n`);
|
|
457
|
+
}
|
|
458
|
+
return 0;
|
|
459
|
+
}
|
|
460
|
+
|
|
270
461
|
const result = syncStarterManifestFiles({
|
|
271
|
-
|
|
462
|
+
starterDir: args.starterDir,
|
|
463
|
+
starterPackageJsonPath: args.starterPackageJsonPath,
|
|
272
464
|
starterPnpmWorkspacePath: args.starterPnpmWorkspacePath,
|
|
273
465
|
repoRoot: args.repoRoot,
|
|
274
466
|
write: args.write,
|
|
275
467
|
});
|
|
276
468
|
|
|
277
469
|
if (result.changed) {
|
|
470
|
+
const updatedPaths = [
|
|
471
|
+
...(result.packageChanged ? ["package.json"] : []),
|
|
472
|
+
...(result.workspaceChanged ? ["pnpm-workspace.yaml"] : []),
|
|
473
|
+
...result.changedToolchainPaths,
|
|
474
|
+
];
|
|
475
|
+
const summary = updatedPaths.length ? ` (${updatedPaths.join(", ")})` : "";
|
|
278
476
|
console.log(
|
|
279
477
|
args.write
|
|
280
|
-
?
|
|
281
|
-
:
|
|
478
|
+
? `Updated builder-agent-native-starter from templates/chat${summary}.`
|
|
479
|
+
: `builder-agent-native-starter is out of date with templates/chat${summary}.`,
|
|
282
480
|
);
|
|
283
481
|
return args.write ? 0 : 1;
|
|
284
482
|
}
|
|
285
483
|
|
|
286
|
-
console.log(
|
|
287
|
-
"builder-agent-native-starter manifest already matches templates/chat.",
|
|
288
|
-
);
|
|
484
|
+
console.log("builder-agent-native-starter already matches templates/chat.");
|
|
289
485
|
return 0;
|
|
290
486
|
}
|
|
291
487
|
|
|
@@ -349,7 +349,7 @@ export default defineAction({
|
|
|
349
349
|
|
|
350
350
|
if (!hasPlayableMp4Metadata(uploadData)) {
|
|
351
351
|
const err = new Error(
|
|
352
|
-
"Recorded MP4 is
|
|
352
|
+
"Recorded MP4 is corrupted or incomplete and cannot be recovered. Please record again.",
|
|
353
353
|
);
|
|
354
354
|
try {
|
|
355
355
|
captureRouteError(err, {
|
|
@@ -103,6 +103,7 @@ interface PendingNativeUpload {
|
|
|
103
103
|
lastAttemptAt?: string | null;
|
|
104
104
|
lastError?: string | null;
|
|
105
105
|
retryCount: number;
|
|
106
|
+
corrupt?: boolean;
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
type PendingDesktopUpload = PendingNativeUpload | PendingBrowserRecordingUpload;
|
|
@@ -2474,25 +2475,40 @@ function PendingUploadBanner({
|
|
|
2474
2475
|
<IconDownload size={14} stroke={2} />
|
|
2475
2476
|
</button>
|
|
2476
2477
|
) : null}
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2478
|
+
{latest.kind === "native" && latest.corrupt ? (
|
|
2479
|
+
<button
|
|
2480
|
+
type="button"
|
|
2481
|
+
className="pending-upload-discard"
|
|
2482
|
+
disabled={actionsDisabled}
|
|
2483
|
+
onClick={() => onDiscard(latest)}
|
|
2484
|
+
aria-label="Discard corrupted clip"
|
|
2485
|
+
title="This clip is corrupted and cannot be recovered. Discard it and record again."
|
|
2486
|
+
>
|
|
2487
|
+
<IconTrash size={14} stroke={2} />
|
|
2488
|
+
</button>
|
|
2489
|
+
) : (
|
|
2490
|
+
<>
|
|
2491
|
+
<button
|
|
2492
|
+
type="button"
|
|
2493
|
+
className="pending-upload-retry"
|
|
2494
|
+
disabled={actionsDisabled}
|
|
2495
|
+
onClick={() => onRetry(latest)}
|
|
2496
|
+
>
|
|
2497
|
+
<IconRefresh size={14} stroke={2} />
|
|
2498
|
+
{retrying ? "Retrying" : "Retry"}
|
|
2499
|
+
</button>
|
|
2500
|
+
<button
|
|
2501
|
+
type="button"
|
|
2502
|
+
className="pending-upload-discard"
|
|
2503
|
+
disabled={actionsDisabled}
|
|
2504
|
+
onClick={() => onDiscard(latest)}
|
|
2505
|
+
aria-label="Discard saved local clip"
|
|
2506
|
+
title="Discard saved local clip"
|
|
2507
|
+
>
|
|
2508
|
+
<IconTrash size={14} stroke={2} />
|
|
2509
|
+
</button>
|
|
2510
|
+
</>
|
|
2511
|
+
)}
|
|
2496
2512
|
</div>
|
|
2497
2513
|
</div>
|
|
2498
2514
|
);
|