Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ packages/native-sdk/bin/native-sdk-*
packages/native-sdk/npm/*/bin/
# SDK payload mirrored into the npm package at pack time (copy-framework.js)
packages/native-sdk/src/
packages/native-sdk/assets/
packages/native-sdk/skills/
packages/native-sdk/skill-data/
packages/native-sdk/build/
Expand Down
1 change: 1 addition & 0 deletions packages/native-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"types": "./native-sdk.d.ts",
"files": [
"bin/native.js",
"assets",
"skill-data",
"skills",
"src",
Expand Down
39 changes: 39 additions & 0 deletions packages/native-sdk/scripts/check-framework-sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const repoRoot = join(projectRoot, '..', '..');
const mirrors = [
{ source: 'src', target: 'src' },
{ source: 'build', target: 'build' },
{ source: 'assets', target: 'assets' },
{ source: 'build.zig', target: 'build.zig' },
{ source: 'build.zig.zon', target: 'build.zig.zon' },
{ source: 'app.zon', target: 'app.zon' },
Expand Down Expand Up @@ -85,6 +86,44 @@ for (const mirror of mirrors) {
compareEntries(join(repoRoot, mirror.source), join(projectRoot, mirror.target));
}

// Every file build/app.zig resolves from the installed package via
// dep.path must actually ship with the package: it has to exist in the
// staged mirror and sit under an entry of package.json "files", or every
// generated app build fails on a missing input after install. Literals
// reach dep.path directly, through the externalModule helper, and through
// an inline switch, so collect all three forms.
function collectDepPathLiterals(source) {
const literals = new Set();
for (const match of source.matchAll(/dep\.path\(\s*"([^"]+)"\s*\)/g)) {
literals.add(match[1]);
}
for (const match of source.matchAll(/externalModule\(\s*b\s*,\s*dep\s*,[^)]*?"([^"]+)"\s*\)/g)) {
literals.add(match[1]);
}
for (const match of source.matchAll(/dep\.path\(\s*switch\s*\([^)]*\)\s*\{([^}]*)\}/g)) {
for (const literal of match[1].matchAll(/"([^"]+)"/g)) {
literals.add(literal[1]);
}
}
return [...literals].sort();
}

const appZigPath = join(repoRoot, 'build', 'app.zig');
const packageFiles = JSON.parse(readFileSync(join(projectRoot, 'package.json'), 'utf8')).files ?? [];

function coveredByFiles(literal) {
return packageFiles.some((entry) => literal === entry || literal.startsWith(`${entry}/`));
}

for (const literal of collectDepPathLiterals(readFileSync(appZigPath, 'utf8'))) {
if (!existsSync(join(projectRoot, literal))) {
addError(`build/app.zig dep.path("${literal}") is missing from the package mirror`);
}
if (!coveredByFiles(literal)) {
addError(`build/app.zig dep.path("${literal}") is not covered by package.json "files"`);
}
}

if (errors.length > 0) {
console.error('Package framework mirror is out of sync.');
for (const error of errors.slice(0, 20)) {
Expand Down
6 changes: 4 additions & 2 deletions packages/native-sdk/scripts/copy-framework.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
// an app build graph needs from its `native_sdk` path dependency: src/
// (the SDK modules), build/ + build.zig + build.zig.zon (the dependency's
// build script that `addApp` lives in), app.zon (the SDK's own manifest,
// which its build script reads at configure time), and the agent skills.
// which its build script reads at configure time), assets/ (files the
// build graph resolves from the dependency, e.g. the Windows application
// manifest build/app.zig wires via dep.path), and the agent skills.
// With the payload in the package, `native init && native dev` work
// offline right after install.

Expand All @@ -17,7 +19,7 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
const projectRoot = join(__dirname, '..');
const repoRoot = join(projectRoot, '..', '..');

for (const dir of ['src', 'build', 'skills', 'skill-data']) {
for (const dir of ['src', 'build', 'assets', 'skills', 'skill-data']) {
const source = join(repoRoot, dir);
const target = join(projectRoot, dir);
rmSync(target, { recursive: true, force: true });
Expand Down
Loading