diff --git a/package-lock.json b/package-lock.json index 4830c5d91a..731f314ce0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16199,9 +16199,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.12", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", - "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", "funding": [ { "type": "github", @@ -16952,9 +16952,9 @@ } }, "node_modules/postcss": { - "version": "8.5.16", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.16.tgz", - "integrity": "sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==", + "version": "8.5.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.23.tgz", + "integrity": "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==", "funding": [ { "type": "opencollective", @@ -16971,7 +16971,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.12", + "nanoid": "^3.3.16", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -19509,9 +19509,9 @@ } }, "node_modules/tar": { - "version": "7.5.19", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.19.tgz", - "integrity": "sha512-4LeEWl96twnS2Q7Bz4MGqgazLqO+hJN63GZxXoIqh1T3VweYD997gbU1ItNsQafqqXTXd5WFyFdReLtwvRBNiw==", + "version": "7.5.22", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.22.tgz", + "integrity": "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { diff --git a/package.json b/package.json index 39bce03ad6..b14e80c9f4 100644 --- a/package.json +++ b/package.json @@ -108,7 +108,7 @@ "test:smoke:browser:install": "playwright install chromium", "test:smoke:browser": "node --experimental-strip-types scripts/smoke-ui-browser.ts", "pretest:ci": "npm run check-node-version", - "test:ci": "git diff --check && npm run actionlint && npm run lint:composite-actions && npm run db:migrations:check && npm run db:schema-drift:check && npm run selfhost:env-reference:check && npm run miner:env-reference:check && npm run selfhost:validate-observability && npm run cf-typegen:check && npm run build --workspace @loopover/engine && npm run build --workspace @loopover/discovery-index && npm run build:mcp && npm run build:miner && npm run typecheck && npm run test:coverage && npm run test:engine-parity && npm run test:live-gate-parity && npm run test:driver-parity && npm run test --workspace @loopover/engine && npm run test:workers && npm run test:mcp-pack && npm run test:miner-pack && npm run test:engine-pack && npm run test:ui-kit-pack && npm run test:miner-deployment-docs-audit && npm run rees:test && npm run ui:openapi:check && npm run ui:openapi:settings-parity && npm run ui:version-audit && npm run docs:drift-check && npm run coverage-boltons:check && npm run branding-drift:check && npm run manifest:drift-check && npm run engine-parity:drift-check && npm run engines-nvmrc:check && npm run release-manifest:sync:check && npm run command-reference:check && npm run ui:lint && npm run ui:typecheck && npm run ui:test && npm run ui:build", + "test:ci": "git diff --check && npm run actionlint && npm run lint:composite-actions && npm run db:migrations:check && npm run db:schema-drift:check && npm run selfhost:env-reference:check && npm run miner:env-reference:check && npm run selfhost:validate-observability && npm run cf-typegen:check && npm run build --workspace @loopover/engine && npm run build --workspace @loopover/discovery-index && npm run build:mcp && npm run build:miner && npm run build --workspace @loopover/ui-kit && npm run typecheck && npm run test:coverage && npm run test:engine-parity && npm run test:live-gate-parity && npm run test:driver-parity && npm run test --workspace @loopover/engine && npm run test:workers && npm run test:mcp-pack && npm run test:miner-pack && npm run test:engine-pack && npm run test:ui-kit-pack && npm run test:miner-deployment-docs-audit && npm run rees:test && npm run ui:openapi:check && npm run ui:openapi:settings-parity && npm run ui:version-audit && npm run docs:drift-check && npm run coverage-boltons:check && npm run branding-drift:check && npm run manifest:drift-check && npm run engine-parity:drift-check && npm run engines-nvmrc:check && npm run release-manifest:sync:check && npm run command-reference:check && npm run ui:lint && npm run ui:typecheck && npm run ui:test && npm run ui:build", "test:release": "npm run test:ci && npm run changelog:check", "test:release:mcp": "npm run test:ci", "test:watch": "vitest", @@ -174,12 +174,13 @@ "@lovable.dev/vite-plugin-hmr-gate": "1.1.2", "esbuild": "^0.28.1", "ws": "^8.21.0", - "tar": "^7.5.19", + "tar": "^7.5.21", "js-yaml": "^4.3.0", "adm-zip": "^0.6.0", "fast-uri": "^3.1.4", "@hono/node-server": "^2.0.8", "sharp": "^0.35.0", + "postcss": "^8.5.18", "lovable-tagger@1.2.0": { "esbuild": "^0.28.1" }, diff --git a/packages/loopover-mcp/bin/loopover-mcp.ts b/packages/loopover-mcp/bin/loopover-mcp.ts index 0fb025d8b1..4baef27098 100644 --- a/packages/loopover-mcp/bin/loopover-mcp.ts +++ b/packages/loopover-mcp/bin/loopover-mcp.ts @@ -1673,14 +1673,26 @@ function stdioToolDescription(name: any) { return tool.description; } -/* v8 ignore next 8 -- the CLI dispatch runs only in the launched process (runAsCliEntrypoint); an in-process +/* v8 ignore next 5 -- draining stdout/stderr before exit only matters for the real launched process writing to + an OS pipe (large output can exceed the pipe's buffer, and a POSIX pipe write is asynchronous); the + in-process test harness below never spawns a subprocess, so this never runs there. */ +function flushStdio(): Promise { + const drained = (stream: NodeJS.WriteStream) => + stream.writableLength > 0 ? new Promise((resolve) => stream.once("drain", resolve)) : Promise.resolve(); + return Promise.all([drained(process.stdout), drained(process.stderr)]).then(() => undefined); +} + +/* v8 ignore next 11 -- the CLI dispatch runs only in the launched process (runAsCliEntrypoint); an in-process unit importer keeps it false and drives runCli/maintainCli directly instead (mcp-cli-plan-issues.test.ts). */ if (runAsCliEntrypoint && cliArgs[0] !== "--stdio") { try { const exitCode = await runCli(cliArgs); + await flushStdio(); process.exit(typeof exitCode === "number" ? exitCode : 0); } catch (error) { - process.exit(reportCliFailure(argsWantJson(cliArgs), describeCliError(error), 1)); + const code = reportCliFailure(argsWantJson(cliArgs), describeCliError(error), 1); + await flushStdio(); + process.exit(code); } } diff --git a/test/unit/miner-package-skeleton.test.ts b/test/unit/miner-package-skeleton.test.ts index adc2297008..686dee33ee 100644 --- a/test/unit/miner-package-skeleton.test.ts +++ b/test/unit/miner-package-skeleton.test.ts @@ -52,16 +52,25 @@ describe("loopover-miner package skeleton (#2287)", () => { expect(miner.scripts["build:verify"]).toBe("node scripts/check-syntax.mjs"); }); - it("build:verify's syntax check actually covers the CLI bin entry points, not just lib/", () => { - // The pre-split build script explicitly node --check'd bin/loopover-miner.js and - // bin/loopover-miner-mcp.js by name; the glob-driven replacement must still reach them. Requires a - // prior build (dist/bin, dist/lib populated) -- same precondition as every other test in this file - // that reads real compiled output, and as the package's own real `npm run build`. - const result = spawnSync("node", ["scripts/check-syntax.mjs"], { cwd: minerRoot, encoding: "utf8" }); - expect(result.status).toBe(0); - expect(result.stdout).toContain("node --check passed for all"); - expect(result.stdout).toMatch(/passed for all \d+ files in dist\/bin\/ and dist\/lib\//); - }); + it( + "build:verify's syntax check actually covers the CLI bin entry points, not just lib/", + () => { + // The pre-split build script explicitly node --check'd bin/loopover-miner.js and + // bin/loopover-miner-mcp.js by name; the glob-driven replacement must still reach them. Requires a + // prior build (dist/bin, dist/lib populated) -- same precondition as every other test in this file + // that reads real compiled output, and as the package's own real `npm run build`. + // Genuinely real subprocess work (node --check over every dist/bin+dist/lib file), no redundancy to + // cut -- 5.5s in isolation but can exceed the default 15s testTimeout under the full suite's parallel + // load. 60000ms matches the same evidence-based ceiling already used for this repo's other + // real-subprocess timeout flakes (agent-sdk-driver.test.ts, miner-attempt-worktree.test.ts, + // miner-repo-clone.test.ts, #6869/#6871). + const result = spawnSync("node", ["scripts/check-syntax.mjs"], { cwd: minerRoot, encoding: "utf8" }); + expect(result.status).toBe(0); + expect(result.stdout).toContain("node --check passed for all"); + expect(result.stdout).toMatch(/passed for all \d+ files in dist\/bin\/ and dist\/lib\//); + }, + 60000, + ); it("starts the CLI bin with a node shebang", () => { const bin = readFileSync(join(minerRoot, "dist/bin/loopover-miner.js"), "utf8");