fix: retain Google provider dependencies in desktop builds
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
/** Real installed Pi/Google SDK only; no provider stubs, keys, or generation. */
|
||||
import assert from "node:assert/strict";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import * as fs from "node:fs";
|
||||
import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
import { describe, it } from "node:test";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const script = fileURLToPath(new URL("../scripts/smoke-provider-runtime.mjs", import.meta.url));
|
||||
const checkout = fileURLToPath(new URL("..", import.meta.url));
|
||||
const run = (payload: string) => spawnSync(process.execPath, [script, "--standalone", payload], { encoding: "utf8", timeout: 40_000 });
|
||||
|
||||
describe("offline native Pi Google initialization gate", () => {
|
||||
it("reaches the sentinel for direct Google and Google-backed OpenCode adapters using the real SDK", () => {
|
||||
// This is an unbundled positive control, NOT proof of standalone completeness.
|
||||
const result = run(checkout);
|
||||
assert.equal(result.status, 0, String(result.stderr));
|
||||
for (const provider of ["google", "opencode", "opencode-go"]) assert.ok(String(result.stdout).includes(`${provider}: native lazy Google adapter reached onPayload`));
|
||||
assert.match(String(result.stdout), /zero network attempts/);
|
||||
});
|
||||
it("rejects a missing Pi entry instead of treating any error as success", () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), "lh-provider-missing-"));
|
||||
try {
|
||||
const result = run(root);
|
||||
assert.equal(result.status, 1);
|
||||
assert.doesNotMatch(String(result.stdout), /initialization passed/);
|
||||
assert.match(String(result.stderr), /MODULE_NOT_FOUND|ENOENT/);
|
||||
assert.deepEqual(fs.readdirSync(root), [], "gate modified the payload");
|
||||
} finally { fs.rmSync(root, { recursive: true, force: true }); }
|
||||
});
|
||||
it("rejects an otherwise complete SDK outside the payload (no host fallback)", () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), "lh-provider-escape-"));
|
||||
try {
|
||||
fs.symlinkSync(path.join(checkout, "node_modules"), path.join(root, "node_modules"), process.platform === "win32" ? "junction" : "dir");
|
||||
const result = run(root);
|
||||
assert.equal(result.status, 1);
|
||||
assert.match(String(result.stderr), /dependency escaped standalone payload/);
|
||||
assert.doesNotMatch(String(result.stdout), /initialization passed/);
|
||||
} finally { fs.rmSync(root, { recursive: true, force: true }); }
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,62 @@
|
||||
/** JS matcher + config-policy regressions; native Turbopack needs the real payload gate. */
|
||||
import assert from "node:assert/strict";
|
||||
import { createRequire } from "node:module";
|
||||
import { describe, it } from "node:test";
|
||||
import nextConfig from "../next.config.ts";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
// Use Next's actual bundled matcher, not a different glob implementation.
|
||||
const picomatch = require("next/dist/compiled/picomatch");
|
||||
const { makeIgnoreFn } = require("next/dist/build/collect-build-traces");
|
||||
const patterns = nextConfig.outputFileTracingExcludes!["*"];
|
||||
|
||||
describe("standalone JavaScript tracing exclusions and native workaround policy", () => {
|
||||
for (const windows of [false, true]) {
|
||||
const root = windows ? "C:\\build\\learnharness" : "/build/learnharness";
|
||||
const file = (relative: string) => root + (windows ? "\\" : "/") + (windows ? relative.replaceAll("/", "\\") : relative);
|
||||
const ignored = picomatch(patterns, { contains: true, dot: true, windows });
|
||||
it(`excludes genuine data directories and secrets (${windows ? "Windows" : "POSIX"})`, () => {
|
||||
for (const relative of ["data/canary.json", "nested/data/private.json", "auth.json", ".env", ".env.local"]) {
|
||||
assert.equal(ignored(file(relative)), true, relative);
|
||||
}
|
||||
// The explicit includes remain necessary: this raw ignore still matches SDK data.
|
||||
assert.equal(ignored(file("node_modules/@earendil-works/pi-ai/dist/providers/data/models.json")), true);
|
||||
assert.ok(nextConfig.outputFileTracingIncludes!["*"]!.includes("node_modules/@earendil-works/pi-ai/dist/providers/data/**/*"));
|
||||
});
|
||||
it(`does not confuse dependency suffixes with data directories (${windows ? "Windows" : "POSIX"})`, () => {
|
||||
for (const relative of ["node_modules/gcp-metadata/build/src/index.js", "node_modules/form-data/lib/form_data.js", "node_modules/@swc/helpers/_/_ts_metadata.js", "node_modules/@swc/helpers/_/_ts_metadata/index.js", "node_modules/somedata/runtime.js"]) {
|
||||
assert.equal(ignored(file(relative)), false, relative);
|
||||
assert.equal(picomatch("data/**/*", { contains: true, dot: true, windows })(file("node_modules/gcp-metadata/build/src/index.js")), true, "old pattern must reproduce the bug");
|
||||
}
|
||||
});
|
||||
}
|
||||
it("uses the installed Next JavaScript early-ignore function on the host platform", () => {
|
||||
const root = process.cwd();
|
||||
const ignore = makeIgnoreFn(root, patterns);
|
||||
assert.equal(ignore(`${root}/data/private.json`), true);
|
||||
assert.equal(ignore(`${root}/node_modules/gcp-metadata/build/src/index.js`), false);
|
||||
});
|
||||
it("preserves all secret exclusions exactly", () => {
|
||||
assert.deepEqual(patterns, ["**/data/**/*", "auth.json", ".env*"]);
|
||||
});
|
||||
it("retains exactly the narrow native-Turbopack closure workaround and existing runtime includes", () => {
|
||||
assert.deepEqual(nextConfig.outputFileTracingIncludes!["*"], [
|
||||
"node_modules/@puppeteer/browsers/lib/browser-data/**/*.js",
|
||||
"node_modules/pdfjs-dist/legacy/**/*",
|
||||
"node_modules/pdfjs-dist/standard_fonts/**/*",
|
||||
"node_modules/@napi-rs/canvas-*/**/*",
|
||||
"node_modules/@resvg/resvg-js-*/**/*",
|
||||
"node_modules/@earendil-works/pi-ai/dist/providers/data/**/*",
|
||||
"node_modules/@earendil-works/pi-agent-core/dist/**/*.json",
|
||||
"node_modules/gcp-metadata/**/*",
|
||||
"node_modules/json-bigint/**/*",
|
||||
"node_modules/bignumber.js/**/*",
|
||||
]);
|
||||
});
|
||||
it("limits the workaround to its three packages, never learner data or unrelated dependencies", () => {
|
||||
const closure = nextConfig.outputFileTracingIncludes!["*"]!.slice(-3);
|
||||
const included = picomatch(closure, { dot: true });
|
||||
for (const file of ["node_modules/gcp-metadata/build/src/index.js", "node_modules/json-bigint/lib/parse.js", "node_modules/bignumber.js/bignumber.js"]) assert.equal(included(file), true, file);
|
||||
for (const file of ["data/private.json", "nested/data/private.json", "auth.json", ".env.local", "node_modules/unrelated/runtime.js", "node_modules/gcp-metadata-lookalike/index.js"]) assert.equal(included(file), false, file);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user