From de77069c1ce0fcafea0111f3634f7d4565992d2e Mon Sep 17 00:00:00 2001 From: Kyle McCullough Date: Sun, 12 Jul 2026 15:31:28 -0300 Subject: [PATCH] Release Mere CLI 0.5.18 --- CHANGELOG.md | 5 + README.md | 2 +- adapters/README.md | 2 +- adapters/agent/run.js | 44 +- adapters/business/run.js | 46 +- adapters/deliver/local-plane.js | 10 +- adapters/dynasite/run.js | 28 +- adapters/email/run.js | 50 +- adapters/gives/run.js | 40 +- adapters/im/run.js | 42 +- adapters/manifest.json | 1451 +++++++++++++++++++++++++++- adapters/media/run.js | 36 +- adapters/network/run.js | 40 +- adapters/package.json | 2 +- adapters/projects/run.js | 50 +- adapters/today/run.js | 40 +- adapters/video/run.js | 42 +- adapters/works/run.js | 36 +- adapters/zone/run.js | 36 +- docs/release-checklist.md | 1 + npm-shrinkwrap.json | 4 +- package.json | 2 +- scripts/adapter-provenance-lib.mjs | 71 +- scripts/build-adapters.mjs | 35 +- test/adapter-provenance.test.mjs | 14 + 25 files changed, 1920 insertions(+), 209 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da4949e..1e8d047 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ This project follows semantic versioning before `1.0.0` with the usual pre-1.0 c ## Unreleased +## 0.5.18 - 2026-07-12 + +- Published the corrected Email adapter route namespace so mailbox and thread commands use `/api/internal/mere/...` after the legacy `/api/internal/zerosmb/...` surface was removed. +- Refreshed the bundled adapter provenance from the reviewed post-migration app sources. + ## 0.5.17 - 2026-07-10 - Fixed root-to-adapter global flag ordering so Business and other bundled apps receive explicit workspace and data flags in their canonical leading position. diff --git a/README.md b/README.md index 005312a..c5189f8 100644 --- a/README.md +++ b/README.md @@ -196,7 +196,7 @@ pnpm test:pack The package includes generated public client artifacts under `adapters/` so the CLI works from npm without separate product CLI installs. These artifacts intentionally expose command names, public API route shapes, environment variable names, and default service URLs; they do not contain credentials or grant service access. Mere services remain responsible for authentication, workspace membership, roles, confirmations, and server-side authorization. -Maintainers can use `pnpm build:adapters` for a local development snapshot when the app repositories are available as sibling directories. A publishable bundle must instead come from `pnpm build:adapters:release`. Release mode fails closed unless every source is clean, is the live canonical `main` commit, came from a merged non-draft pull request with a non-author approval against the exact reviewed head, and has green completed checks. It records the canonical repository, source commit and tree, cleanliness, deterministic commands and toolchain, every artifact SHA-256 and size, and the canonical Mere Console Contract v1 schema/fixture digests when that source ships them. It then rebuilds twice and requires byte-identical adapter directories. +Maintainers can use `pnpm build:adapters` for a local development snapshot when the app repositories are available as sibling directories. A publishable bundle must instead come from `pnpm build:adapters:release`. Release mode always fails closed unless every source is clean and is the live canonical `main` commit; it records the canonical repository, source commit and tree, cleanliness, deterministic commands and toolchain, every artifact SHA-256 and size, and the canonical Mere Console Contract v1 schema/fixture digests when that source ships them, then rebuilds twice and requires byte-identical adapter directories. The default `reviewed-merge` policy additionally requires a merged non-draft pull request, exact non-author approval, and green completed checks. A documented `ADAPTER_RELEASE_REVIEW_POLICY=canonical-main` solo-maintainer exception records null review evidence while retaining all canonical-source, reproducibility, hash, path, and credential gates. `pnpm check:adapter-provenance` re-hashes the complete packaged adapter inventory and enforces that release evidence. The Publish workflow always runs it, and CI runs it whenever `adapters/` changes. The existing schema-v1 bundle has no reconstructable source proof, so it is intentionally not grandfathered into publication: the next package release is blocked until maintainers perform a strict source-first regeneration. Public contributors do not need sibling app repositories for normal root CLI development. diff --git a/adapters/README.md b/adapters/README.md index aeeb629..f19b108 100644 --- a/adapters/README.md +++ b/adapters/README.md @@ -32,4 +32,4 @@ Access is enforced by the Mere services through browser sessions, bearer tokens, Adapter manifests must mark command risk honestly as `read`, `write`, `destructive`, or `external`. Destructive commands must require explicit confirmation. -Maintainers regenerate these files from the Mere app repositories with `pnpm build:adapters`. That command expects the private app repositories to be available as sibling directories and is not required for normal public development of the root CLI. +Maintainers can use `pnpm build:adapters` for a development snapshot. Public-release inputs must use `pnpm build:adapters:release`, which requires clean canonical default-branch sources and a byte-identical two-pass rebuild. The default `reviewed-merge` policy also requires exact non-author review and green-CI evidence; the documented `canonical-main` solo-maintainer exception records that review evidence is unavailable without weakening source, reproducibility, hash, path, or credential checks. diff --git a/adapters/agent/run.js b/adapters/agent/run.js index 69e0604..03fa0ba 100755 --- a/adapters/agent/run.js +++ b/adapters/agent/run.js @@ -19,7 +19,8 @@ var CLI_AUTH_ERROR_QUERY_PARAM = "error"; var CLI_AUTH_ERROR_DESCRIPTION_QUERY_PARAM = "error_description"; // node_modules/.pnpm/@mere+cli-auth@file+..+business+packages+cli-auth_@sveltejs+kit@2.57.1_@opentelemetry+a_a24688588653a54cfd1beeb755d34927/node_modules/@mere/cli-auth/src/session.ts -import { chmod, mkdir, readFile, rm, writeFile } from "node:fs/promises"; +import { randomUUID } from "node:crypto"; +import { mkdir, open, readFile, rename, rm } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; function stateHome(env) { @@ -63,10 +64,29 @@ async function loadCliSession(input) { } async function saveCliSession(input) { const paths = resolveCliPaths(input.appName, input.env ?? process.env); - await mkdir(paths.stateDir, { recursive: true }); - await writeFile(paths.sessionFile, `${JSON.stringify(input.session, null, 2)} + await writeCliSessionFile(paths.sessionFile, input.session); +} +async function writeCliSessionFile(sessionFile, session) { + const stateDir = path.dirname(sessionFile); + const tempFile = path.join( + stateDir, + `.${path.basename(sessionFile)}.${process.pid}.${randomUUID()}.tmp` + ); + let handle; + await mkdir(stateDir, { recursive: true }); + try { + handle = await open(tempFile, "wx", 384); + await handle.writeFile(`${JSON.stringify(session, null, 2)} `, "utf8"); - await chmod(paths.sessionFile, 384).catch(() => void 0); + await handle.sync(); + await handle.close(); + handle = void 0; + await rename(tempFile, sessionFile); + } catch (error) { + await handle?.close().catch(() => void 0); + await rm(tempFile, { force: true }).catch(() => void 0); + throw error; + } } async function clearCliSession(input) { const env = input.env ?? process.env; @@ -314,16 +334,16 @@ async function logoutRemote(input = {}) { // cli/local-plane.ts import { createHash as createHash4 } from "node:crypto"; -import { mkdir as mkdir3, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises"; +import { mkdir as mkdir3, readFile as readFile2, writeFile } from "node:fs/promises"; import { dirname, resolve as resolvePath } from "node:path"; // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/index.ts -import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto"; +import { createHash as createHash2, randomUUID as randomUUID3 } from "node:crypto"; import { mkdir as mkdir2 } from "node:fs/promises"; import path3 from "node:path"; // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/migration.ts -import { createHash, randomUUID } from "node:crypto"; +import { createHash, randomUUID as randomUUID2 } from "node:crypto"; var PLANE_TRANSFER_KIND = "mere.local-plane.transfer"; var PLANE_TRANSFER_VERSION = 1; function isRecord(value) { @@ -459,7 +479,7 @@ function createPlaneTransferImportPlan(input) { }; } function recordPlaneTransfer(db, input) { - const id = `xfer_${randomUUID().replaceAll("-", "").slice(0, 24)}`; + const id = `xfer_${randomUUID2().replaceAll("-", "").slice(0, 24)}`; db.prepare( `INSERT INTO mere_plane_transfers ( id, app_id, workspace_id, direction, @@ -721,7 +741,7 @@ function json(value) { return JSON.stringify(value ?? {}); } function makePlaneId(prefix) { - return `${prefix}_${randomUUID2().replaceAll("-", "").slice(0, 24)}`; + return `${prefix}_${randomUUID3().replaceAll("-", "").slice(0, 24)}`; } async function loadNodeSqlite() { return import(["node", "sqlite"].join(":")); @@ -1085,7 +1105,7 @@ function getLocalPlaneInventory(db, options = {}) { // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/mere-run.ts import { createReadStream, createWriteStream, existsSync, mkdirSync } from "node:fs"; -import { access, chmod as chmod2, mkdtemp, rm as rm2 } from "node:fs/promises"; +import { access, chmod, mkdtemp, rm as rm2 } from "node:fs/promises"; import { createHash as createHash3 } from "node:crypto"; import https from "node:https"; import os3 from "node:os"; @@ -1199,7 +1219,7 @@ async function installFromDmg(env, appId) { if (install.status !== 0) { throw new Error(install.stderr || install.stdout || "mere.run installer failed."); } - await chmod2(installBin, 493).catch(() => void 0); + await chmod(installBin, 493).catch(() => void 0); return installBin; } finally { await rm2(tmp, { recursive: true, force: true }); @@ -1626,7 +1646,7 @@ async function handleLocalExport(args, io) { if (!output) return bundle; const target = resolvePath(output); await mkdir3(dirname(target), { recursive: true }); - await writeFile2(target, JSON.stringify(bundle, null, 2)); + await writeFile(target, JSON.stringify(bundle, null, 2)); return { ok: true, path: target, diff --git a/adapters/business/run.js b/adapters/business/run.js index f6b8cb9..5812919 100755 --- a/adapters/business/run.js +++ b/adapters/business/run.js @@ -6040,9 +6040,17 @@ function parseJsonArrayTexts(values, optionName) { function inferContentType(filename) { const extension = filename.match(/\.[a-z0-9]+$/i)?.[0]?.toLowerCase(); if (extension === ".html" || extension === ".htm") return "text/html; charset=utf-8"; + if (extension === ".txt") return "text/plain; charset=utf-8"; + if (extension === ".md" || extension === ".markdown") return "text/markdown; charset=utf-8"; + if (extension === ".csv") return "text/csv; charset=utf-8"; if (extension === ".css") return "text/css; charset=utf-8"; if (extension === ".js" || extension === ".mjs") return "text/javascript; charset=utf-8"; if (extension === ".json") return "application/json; charset=utf-8"; + if (extension === ".pdf") return "application/pdf"; + if (extension === ".zip") return "application/zip"; + if (extension === ".docx") return "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; + if (extension === ".xlsx") return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; + if (extension === ".pptx") return "application/vnd.openxmlformats-officedocument.presentationml.presentation"; if (extension === ".svg") return "image/svg+xml"; if (extension === ".png") return "image/png"; if (extension === ".jpg" || extension === ".jpeg") return "image/jpeg"; @@ -6073,6 +6081,34 @@ async function localFilePayload(filePath) { dataBase64: data.toString("base64") }; } +var MAX_MAIL_ATTACHMENT_TOTAL_BYTES = 30 * 1024 * 1024; +async function mailAttachmentPayloads(filePaths) { + const files = await Promise.all( + filePaths.map(async (filePath) => { + try { + return await localFilePayload(resolvePath2(filePath)); + } catch (error) { + throw usageError( + `Failed to read attachment ${filePath}: ${error instanceof Error ? error.message : "unknown error"}.` + ); + } + }) + ); + for (let index = 0; index < files.length; index += 1) { + if (files[index]?.sizeBytes === 0) { + throw usageError(`Attachment ${filePaths[index] ?? files[index]?.filename ?? ""} is empty.`); + } + } + const totalBytes = files.reduce((sum, file) => sum + file.sizeBytes, 0); + if (totalBytes > MAX_MAIL_ATTACHMENT_TOTAL_BYTES) { + throw usageError("Attachments exceed the 30 MB total upload limit."); + } + return files.map((file) => ({ + filename: file.filename, + mimeType: file.mimeType, + contentBase64: file.dataBase64 + })); +} async function staticBundlePayload(input2) { if (input2.sourceDir && input2.zip) { throw usageError("Use either --source-dir or --zip, not both."); @@ -6975,6 +7011,7 @@ next: ${payload.nextUrl}` : ""}`; stringOption("to", "to", "Recipient email.", { multiple: true }), stringOption("cc", "cc", "CC recipient email.", { multiple: true }), stringOption("bcc", "bcc", "BCC recipient email.", { multiple: true }), + stringOption("attach", "attachmentPaths", "Local attachment path.", { multiple: true }), stringOption("subject", "subject", "Email subject."), stringOption("body", "bodyText", "Plain-text body.") ], @@ -6983,15 +7020,17 @@ next: ${payload.nextUrl}` : ""}`; to: stringList, cc: stringList, bcc: stringList, + attachmentPaths: stringList, subject: requiredString, bodyText: requiredString }), op: "mail.send", - buildInput: (input2) => ({ + buildInput: async (input2) => ({ mailboxId: input2.mailboxId, to: input2.to, cc: input2.cc, bcc: input2.bcc, + attachments: await mailAttachmentPayloads(input2.attachmentPaths ?? []), subject: input2.subject, bodyText: input2.bodyText }) @@ -7005,6 +7044,7 @@ next: ${payload.nextUrl}` : ""}`; stringOption("to", "to", "Recipient email.", { multiple: true }), stringOption("cc", "cc", "CC recipient email.", { multiple: true }), stringOption("bcc", "bcc", "BCC recipient email.", { multiple: true }), + stringOption("attach", "attachmentPaths", "Local attachment path.", { multiple: true }), stringOption("subject", "subject", "Email subject."), stringOption("body", "bodyText", "Plain-text body.") ], @@ -7014,16 +7054,18 @@ next: ${payload.nextUrl}` : ""}`; to: stringList, cc: stringList, bcc: stringList, + attachmentPaths: stringList, subject: requiredString, bodyText: requiredString }), op: "mail.reply", - buildInput: (input2) => ({ + buildInput: async (input2) => ({ replyThreadId: input2.threadId, mailboxId: input2.mailboxId, to: input2.to, cc: input2.cc, bcc: input2.bcc, + attachments: await mailAttachmentPayloads(input2.attachmentPaths ?? []), subject: input2.subject, bodyText: input2.bodyText }) diff --git a/adapters/deliver/local-plane.js b/adapters/deliver/local-plane.js index 2b8fdaa..2b83bf0 100644 --- a/adapters/deliver/local-plane.js +++ b/adapters/deliver/local-plane.js @@ -3,11 +3,11 @@ import { createHash as createHash2 } from "node:crypto"; import { mkdir as mkdir2, readFile, writeFile } from "node:fs/promises"; import { dirname, resolve as resolvePath } from "node:path"; -// ../mere-business/packages/local-plane/src/index.ts +// node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/index.ts import { mkdir } from "node:fs/promises"; import path2 from "node:path"; -// ../mere-business/packages/local-plane/src/migration.ts +// node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/migration.ts import { createHash, randomUUID } from "node:crypto"; var PLANE_TRANSFER_KIND = "mere.local-plane.transfer"; var PLANE_TRANSFER_VERSION = 1; @@ -168,7 +168,7 @@ function recordPlaneTransfer(db, input) { return id; } -// ../mere-business/packages/local-plane/src/projection.ts +// node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/projection.ts var CloudProjectionDeliveryError = class extends Error { constructor(message, status = null, responseText = null) { super(message); @@ -280,7 +280,7 @@ async function deliverCloudProjectionEvent(input) { }; } -// ../mere-business/packages/local-plane/src/config.ts +// node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/config.ts import os from "node:os"; import path from "node:path"; function stateHome(env) { @@ -398,7 +398,7 @@ function formatPlaneConfigReport(report) { `; } -// ../mere-business/packages/local-plane/src/index.ts +// node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/index.ts function isoNow2() { return (/* @__PURE__ */ new Date()).toISOString(); } diff --git a/adapters/dynasite/run.js b/adapters/dynasite/run.js index a794269..e0b2c86 100755 --- a/adapters/dynasite/run.js +++ b/adapters/dynasite/run.js @@ -1501,7 +1501,8 @@ import { createServer } from "http"; var CLI_AUTH_REFRESH_PATH = "/api/cli/v1/auth/refresh"; // node_modules/.pnpm/@mere+cli-auth@file+..+business+packages+cli-auth_@sveltejs+kit@2.59.1_@sveltejs+vite-p_d8a7e4e697715c4418477c3ed91e9ced/node_modules/@mere/cli-auth/src/session.ts -import { chmod, mkdir as mkdir3, readFile as readFile2, rm, writeFile as writeFile2 } from "fs/promises"; +import { randomUUID as randomUUID3 } from "crypto"; +import { mkdir as mkdir3, open, readFile as readFile2, rename, rm } from "fs/promises"; import os3 from "os"; import path3 from "path"; function stateHome2(env) { @@ -1545,10 +1546,29 @@ async function loadCliSession(input) { } async function saveCliSession(input) { const paths = resolveCliPaths(input.appName, input.env ?? process.env); - await mkdir3(paths.stateDir, { recursive: true }); - await writeFile2(paths.sessionFile, `${JSON.stringify(input.session, null, 2)} + await writeCliSessionFile(paths.sessionFile, input.session); +} +async function writeCliSessionFile(sessionFile, session) { + const stateDir = path3.dirname(sessionFile); + const tempFile = path3.join( + stateDir, + `.${path3.basename(sessionFile)}.${process.pid}.${randomUUID3()}.tmp` + ); + let handle; + await mkdir3(stateDir, { recursive: true }); + try { + handle = await open(tempFile, "wx", 384); + await handle.writeFile(`${JSON.stringify(session, null, 2)} `, "utf8"); - await chmod(paths.sessionFile, 384).catch(() => void 0); + await handle.sync(); + await handle.close(); + handle = void 0; + await rename(tempFile, sessionFile); + } catch (error) { + await handle?.close().catch(() => void 0); + await rm(tempFile, { force: true }).catch(() => void 0); + throw error; + } } async function clearCliSession(input) { const env = input.env ?? process.env; diff --git a/adapters/email/run.js b/adapters/email/run.js index 29beb3b..abc2df1 100755 --- a/adapters/email/run.js +++ b/adapters/email/run.js @@ -1037,7 +1037,7 @@ var local_store_exports = {}; __export(local_store_exports, { LocalEmailStore: () => LocalEmailStore }); -import { randomUUID as randomUUID4 } from "node:crypto"; +import { randomUUID as randomUUID5 } from "node:crypto"; function parseStringArray(value) { const parsed = parseJsonText(value); return Array.isArray(parsed) ? parsed.filter((entry) => typeof entry === "string") : []; @@ -1057,7 +1057,7 @@ function compactSnippet(value, max = 240) { return `${compacted.slice(0, Math.max(0, max - 3)).trimEnd()}...`; } function makeId(prefix) { - return `${prefix}_${randomUUID4().replaceAll("-", "").slice(0, 24)}`; + return `${prefix}_${randomUUID5().replaceAll("-", "").slice(0, 24)}`; } function mapMailbox(row) { return { @@ -1999,7 +1999,7 @@ var init_local_store = __esm({ init_src(); init_projection(); import { createHash as createHash7, randomBytes as nodeRandomBytes } from "node:crypto"; -import { chmod as chmod4, mkdir as mkdir4, readFile as readFile4, writeFile as writeFile3 } from "node:fs/promises"; +import { chmod as chmod3, mkdir as mkdir4, readFile as readFile4, writeFile as writeFile2 } from "node:fs/promises"; import { dirname, resolve as resolvePath2 } from "node:path"; // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/mere-run.ts @@ -6512,7 +6512,8 @@ var CLI_AUTH_ERROR_QUERY_PARAM = "error"; var CLI_AUTH_ERROR_DESCRIPTION_QUERY_PARAM = "error_description"; // node_modules/.pnpm/@mere+cli-auth@file+..+business+packages+cli-auth_@sveltejs+kit@2.55.0_@sveltejs+vite-p_cce024e09157c6f3a2f48f55311f97e2/node_modules/@mere/cli-auth/src/session.ts -import { chmod as chmod2, mkdir as mkdir2, readFile, rm as rm2, writeFile } from "node:fs/promises"; +import { randomUUID as randomUUID3 } from "node:crypto"; +import { mkdir as mkdir2, open, readFile, rename, rm as rm2 } from "node:fs/promises"; import os3 from "node:os"; import path3 from "node:path"; function stateHome2(env) { @@ -6556,10 +6557,29 @@ async function loadCliSession(input) { } async function saveCliSession(input) { const paths = resolveCliPaths(input.appName, input.env ?? process.env); - await mkdir2(paths.stateDir, { recursive: true }); - await writeFile(paths.sessionFile, `${JSON.stringify(input.session, null, 2)} + await writeCliSessionFile(paths.sessionFile, input.session); +} +async function writeCliSessionFile(sessionFile, session) { + const stateDir = path3.dirname(sessionFile); + const tempFile = path3.join( + stateDir, + `.${path3.basename(sessionFile)}.${process.pid}.${randomUUID3()}.tmp` + ); + let handle; + await mkdir2(stateDir, { recursive: true }); + try { + handle = await open(tempFile, "wx", 384); + await handle.writeFile(`${JSON.stringify(session, null, 2)} `, "utf8"); - await chmod2(paths.sessionFile, 384).catch(() => void 0); + await handle.sync(); + await handle.close(); + handle = void 0; + await rename(tempFile, sessionFile); + } catch (error) { + await handle?.close().catch(() => void 0); + await rm2(tempFile, { force: true }).catch(() => void 0); + throw error; + } } async function clearCliSession(input) { const env = input.env ?? process.env; @@ -7485,7 +7505,7 @@ var EmailCliClient = class { // cli/sealed.ts init_json(); import { createCipheriv, createDecipheriv, createHash as createHash4, randomBytes } from "node:crypto"; -import { chmod as chmod3, mkdir as mkdir3, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises"; +import { chmod as chmod2, mkdir as mkdir3, readFile as readFile2, writeFile } from "node:fs/promises"; import os4 from "node:os"; import path4 from "node:path"; var SEALED_ENVELOPE_VERSION = 1; @@ -7511,8 +7531,8 @@ async function loadSealedKey(env, options = {}) { if (!options.create) return null; const key = randomBytes(32); await mkdir3(path4.dirname(filePath), { recursive: true }); - await writeFile2(filePath, key, { mode: 384 }); - await chmod3(filePath, 384); + await writeFile(filePath, key, { mode: 384 }); + await chmod2(filePath, 384); return { key, keyId: keyFingerprint(key), filePath }; } function envelopeAad(header) { @@ -8271,7 +8291,7 @@ async function logoutRemote(input = {}) { } // cli/console-contract.ts -import { createHash as createHash6, randomUUID as randomUUID3 } from "node:crypto"; +import { createHash as createHash6, randomUUID as randomUUID4 } from "node:crypto"; import { existsSync as existsSync3 } from "node:fs"; import { DatabaseSync } from "node:sqlite"; @@ -8770,7 +8790,7 @@ var TARGET_RULES = { "workspace.disconnect": { type: "email-workspace", source: "workspace" } }; function eventId(kind) { - return `evt_email_${kind.replaceAll(".", "_")}_${randomUUID3()}`; + return `evt_email_${kind.replaceAll(".", "_")}_${randomUUID4()}`; } function contractSource(operation, adapterVersion) { return { @@ -10381,7 +10401,7 @@ function writeResult(io, globalOptions, value, render) { async function writeBytesFile(outputPath, bytes) { const target = resolvePath2(outputPath); await mkdir4(dirname(target), { recursive: true }); - await writeFile3(target, bytes); + await writeFile2(target, bytes); return target; } function pickWorkspaceSession(session, requestedWorkspace) { @@ -10984,9 +11004,9 @@ ${payload.path}` const tunnelToken = io.env.MERE_EMAIL_TUNNEL_TOKEN?.trim() || nodeRandomBytes(32).toString("hex"); const tokenPath = custodyTunnelTokenPath(io.env); await mkdir4(dirname(tokenPath), { recursive: true }); - await writeFile3(tokenPath, `${tunnelToken} + await writeFile2(tokenPath, `${tunnelToken} `, { mode: 384 }); - await chmod4(tokenPath, 384); + await chmod3(tokenPath, 384); const server = await startCustodyTunnelServer({ store, key, diff --git a/adapters/gives/run.js b/adapters/gives/run.js index 7a2d45e..7de1b7f 100755 --- a/adapters/gives/run.js +++ b/adapters/gives/run.js @@ -1,7 +1,7 @@ #!/usr/bin/env node // cli/zerodonate.ts -import { mkdir as mkdir4, readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises"; +import { mkdir as mkdir4, readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises"; import { dirname as dirname2, resolve as resolvePath2 } from "node:path"; // node_modules/.pnpm/@mere+cli-auth@file+..+business+packages+cli-auth_@sveltejs+kit@2.59.1_@sveltejs+vite-p_d58c11277d08e28fc88399d6fc968ff2/node_modules/@mere/cli-auth/src/client.ts @@ -20,7 +20,8 @@ var CLI_AUTH_ERROR_QUERY_PARAM = "error"; var CLI_AUTH_ERROR_DESCRIPTION_QUERY_PARAM = "error_description"; // node_modules/.pnpm/@mere+cli-auth@file+..+business+packages+cli-auth_@sveltejs+kit@2.59.1_@sveltejs+vite-p_d58c11277d08e28fc88399d6fc968ff2/node_modules/@mere/cli-auth/src/session.ts -import { chmod, mkdir, readFile, rm, writeFile } from "node:fs/promises"; +import { randomUUID } from "node:crypto"; +import { mkdir, open, readFile, rename, rm } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; function stateHome(env) { @@ -64,10 +65,29 @@ async function loadCliSession(input) { } async function saveCliSession(input) { const paths = resolveCliPaths(input.appName, input.env ?? process.env); - await mkdir(paths.stateDir, { recursive: true }); - await writeFile(paths.sessionFile, `${JSON.stringify(input.session, null, 2)} + await writeCliSessionFile(paths.sessionFile, input.session); +} +async function writeCliSessionFile(sessionFile, session) { + const stateDir = path.dirname(sessionFile); + const tempFile = path.join( + stateDir, + `.${path.basename(sessionFile)}.${process.pid}.${randomUUID()}.tmp` + ); + let handle; + await mkdir(stateDir, { recursive: true }); + try { + handle = await open(tempFile, "wx", 384); + await handle.writeFile(`${JSON.stringify(session, null, 2)} `, "utf8"); - await chmod(paths.sessionFile, 384).catch(() => void 0); + await handle.sync(); + await handle.close(); + handle = void 0; + await rename(tempFile, sessionFile); + } catch (error) { + await handle?.close().catch(() => void 0); + await rm(tempFile, { force: true }).catch(() => void 0); + throw error; + } } async function clearCliSession(input) { const env = input.env ?? process.env; @@ -326,7 +346,7 @@ async function logoutRemote(input = {}) { } // cli/local-plane.ts -import { mkdir as mkdir3, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises"; +import { mkdir as mkdir3, readFile as readFile2, writeFile } from "node:fs/promises"; import { dirname, resolve as resolvePath } from "node:path"; // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/config.ts @@ -565,7 +585,7 @@ import { mkdir as mkdir2 } from "node:fs/promises"; import path3 from "node:path"; // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/migration.ts -import { createHash, randomUUID } from "node:crypto"; +import { createHash, randomUUID as randomUUID2 } from "node:crypto"; var PLANE_TRANSFER_KIND = "mere.local-plane.transfer"; var PLANE_TRANSFER_VERSION = 1; function isRecord(value) { @@ -701,7 +721,7 @@ function createPlaneTransferImportPlan(input) { }; } function recordPlaneTransfer(db, input) { - const id = `xfer_${randomUUID().replaceAll("-", "").slice(0, 24)}`; + const id = `xfer_${randomUUID2().replaceAll("-", "").slice(0, 24)}`; db.prepare( `INSERT INTO mere_plane_transfers ( id, app_id, workspace_id, direction, @@ -1646,7 +1666,7 @@ async function handleLocalExport(globalOptions, options, io) { if (!output) return bundle; const target = resolvePath(output); await mkdir3(dirname(target), { recursive: true }); - await writeFile2(target, JSON.stringify(bundle, null, 2)); + await writeFile(target, JSON.stringify(bundle, null, 2)); return { ok: true, path: target, @@ -2380,7 +2400,7 @@ async function requestText(io, globalOptions, input) { async function writeTextFile(outputPath, text) { const target = resolvePath2(outputPath); await mkdir4(dirname2(target), { recursive: true }); - await writeFile3(target, text, "utf8"); + await writeFile2(target, text, "utf8"); return target; } async function handleAuthCommand(positionals, globalOptions, io, wantsJson) { diff --git a/adapters/im/run.js b/adapters/im/run.js index f38e078..0756a82 100755 --- a/adapters/im/run.js +++ b/adapters/im/run.js @@ -1,7 +1,7 @@ #!/usr/bin/env node // cli/mere-im.ts -import { mkdir as mkdir3, readFile as readFile2, writeFile as writeFile2 } from "fs/promises"; +import { mkdir as mkdir3, readFile as readFile2, writeFile } from "fs/promises"; import { dirname, resolve } from "path"; // node_modules/.pnpm/@mere+cli-auth@file+..+business+packages+cli-auth_@sveltejs+kit@2.69.1_@sveltejs+vite-p_b69e0278aad5418e80ddd2c3260fb2fd/node_modules/@mere/cli-auth/src/client.ts @@ -20,7 +20,8 @@ var CLI_AUTH_ERROR_QUERY_PARAM = "error"; var CLI_AUTH_ERROR_DESCRIPTION_QUERY_PARAM = "error_description"; // node_modules/.pnpm/@mere+cli-auth@file+..+business+packages+cli-auth_@sveltejs+kit@2.69.1_@sveltejs+vite-p_b69e0278aad5418e80ddd2c3260fb2fd/node_modules/@mere/cli-auth/src/session.ts -import { chmod, mkdir, readFile, rm, writeFile } from "fs/promises"; +import { randomUUID } from "crypto"; +import { mkdir, open, readFile, rename, rm } from "fs/promises"; import os from "os"; import path from "path"; function stateHome(env) { @@ -64,10 +65,29 @@ async function loadCliSession(input) { } async function saveCliSession(input) { const paths = resolveCliPaths(input.appName, input.env ?? process.env); - await mkdir(paths.stateDir, { recursive: true }); - await writeFile(paths.sessionFile, `${JSON.stringify(input.session, null, 2)} + await writeCliSessionFile(paths.sessionFile, input.session); +} +async function writeCliSessionFile(sessionFile, session) { + const stateDir = path.dirname(sessionFile); + const tempFile = path.join( + stateDir, + `.${path.basename(sessionFile)}.${process.pid}.${randomUUID()}.tmp` + ); + let handle; + await mkdir(stateDir, { recursive: true }); + try { + handle = await open(tempFile, "wx", 384); + await handle.writeFile(`${JSON.stringify(session, null, 2)} `, "utf8"); - await chmod(paths.sessionFile, 384).catch(() => void 0); + await handle.sync(); + await handle.close(); + handle = void 0; + await rename(tempFile, sessionFile); + } catch (error) { + await handle?.close().catch(() => void 0); + await rm(tempFile, { force: true }).catch(() => void 0); + throw error; + } } async function clearCliSession(input) { const env = input.env ?? process.env; @@ -494,16 +514,16 @@ async function deliverCloudProjectionEvent(input) { } // cli/local-store.ts -import { createHash as createHash3, randomUUID as randomUUID3 } from "crypto"; +import { createHash as createHash3, randomUUID as randomUUID4 } from "crypto"; // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/index.ts -import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto"; +import { createHash as createHash2, randomUUID as randomUUID3 } from "crypto"; import { mkdir as mkdir2 } from "fs/promises"; import os3 from "os"; import path3 from "path"; // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/migration.ts -import { createHash, randomUUID } from "crypto"; +import { createHash, randomUUID as randomUUID2 } from "crypto"; var PLANE_TRANSFER_KIND = "mere.local-plane.transfer"; var PLANE_TRANSFER_VERSION = 1; function isRecord(value) { @@ -639,7 +659,7 @@ function createPlaneTransferImportPlan(input) { }; } function recordPlaneTransfer(db, input) { - const id = `xfer_${randomUUID().replaceAll("-", "").slice(0, 24)}`; + const id = `xfer_${randomUUID2().replaceAll("-", "").slice(0, 24)}`; db.prepare( `INSERT INTO mere_plane_transfers ( id, app_id, workspace_id, direction, @@ -989,7 +1009,7 @@ function isoNow3() { return (/* @__PURE__ */ new Date()).toISOString(); } function makeId(prefix) { - return `${prefix}_${randomUUID3().replaceAll("-", "").slice(0, 16)}`; + return `${prefix}_${randomUUID4().replaceAll("-", "").slice(0, 16)}`; } function stableConversationProjectionId(workspaceId, conversationId) { const digest = createHash3("sha256").update(IM_APP_ID).update("\0").update(workspaceId).update("\0").update(conversationId).digest("hex").slice(0, 24); @@ -2986,7 +3006,7 @@ async function cmdLocalExport(args, _json, ctx) { if (output) { const target = resolve(output); await mkdir3(dirname(target), { recursive: true }); - await writeFile2(target, JSON.stringify(bundle, null, 2)); + await writeFile(target, JSON.stringify(bundle, null, 2)); return writeJson(ctx, { ok: true, path: target, diff --git a/adapters/manifest.json b/adapters/manifest.json index 99c019d..2f3ae8a 100644 --- a/adapters/manifest.json +++ b/adapters/manifest.json @@ -1,118 +1,1501 @@ { - "schemaVersion": 1, - "builtAt": "2026-07-11T11:08:14.576Z", + "schemaVersion": 2, + "mode": "release", + "reviewPolicy": "canonical-main", + "builtAt": "2026-07-11T22:58:41.000Z", + "sourceDateEpoch": "1783810721", + "sourceMapSha256": "9079c487e1b6db82c78c5f52bff254f5bd5980824a93b612dc63b1371bbdedf7", + "reproducibility": { + "passes": 2, + "byteIdentical": true, + "algorithm": "sha256-file-inventory-v1", + "machinePathScan": true, + "credentialScan": true, + "canonicalSourcesRevalidated": true + }, "adapters": [ { "app": "business", "sourceRepoPath": "mere-business", - "sourceArtifactPath": "mere-business/packages/cli/dist/index.js", + "sourceArtifactPath": "packages/cli/dist/index.js", "adapterPath": "adapters/business/run.js", - "builtAt": "2026-07-11T11:08:14.576Z" + "builtAt": "2026-07-11T22:58:41.000Z", + "source": { + "canonicalRepository": "https://github.com/sawfwair/mere-business.git", + "actualRepository": "https://github.com/sawfwair/mere-business.git", + "canonicalRemote": true, + "commit": "e6b6ccd0b0916a0809a84491897a63cb49efebe7", + "tree": "9d837a10f20851d7832ee384d53a7606d1ff4d11", + "clean": true, + "hasUnmergedFiles": false, + "defaultBranch": "main", + "remoteHead": "e6b6ccd0b0916a0809a84491897a63cb49efebe7", + "localTrackingHead": "e6b6ccd0b0916a0809a84491897a63cb49efebe7", + "remoteHeadEvidence": "live-ls-remote", + "mergedToDefaultBranch": true, + "commitTimestamp": 1783810721, + "review": null, + "artifactTracked": true + }, + "build": { + "commands": [ + { + "executable": "pnpm", + "args": [ + "--filter", + "@mere/cli", + "build" + ], + "workingDirectory": "source" + }, + { + "executable": "copy-file", + "args": [ + "packages/cli/dist/index.js", + "adapters/business/" + ], + "workingDirectory": "source" + }, + { + "executable": "normalize-file-modes", + "args": [ + "adapters/business/run.js=755", + "adapters/business/**=644" + ], + "workingDirectory": "source" + } + ], + "toolchain": { + "node": "v24.15.0", + "pnpm": "10.8.1", + "esbuild": "0.28.1", + "sourcePackageManager": "pnpm@10.8.1", + "sourceLockfiles": [ + { + "path": "pnpm-lock.yaml", + "sha256": "088545f68ffca6e817dc3e4f65e9b7cc64b828f77572cda27f84dc063da6afbe", + "size": 296222 + } + ] + }, + "deterministicEnvironment": { + "SOURCE_DATE_EPOCH": "1783810721", + "TZ": "UTC", + "LC_ALL": "C" + } + }, + "contract": null, + "artifacts": [ + { + "path": "adapters/business/run.js", + "sha256": "4645c34210b35861a35e13c26bd581e7b4c6fe4379ef790021454e01221271b2", + "size": 328980, + "mode": "755" + } + ] }, { "app": "finance", "sourceRepoPath": "mere-finance", - "sourceArtifactPath": "mere-finance/packages/cli/bin/merefi.ts", + "sourceArtifactPath": "packages/cli/bin/merefi.ts", "adapterPath": "adapters/finance/run.js", - "builtAt": "2026-07-11T11:08:14.576Z" + "builtAt": "2026-07-11T22:58:41.000Z", + "source": { + "canonicalRepository": "https://github.com/sawfwair/mere-finance.git", + "actualRepository": "https://github.com/sawfwair/mere-finance.git", + "canonicalRemote": true, + "commit": "8fb704866eca4ff16fb6ef916fcc7f20c436b83e", + "tree": "e0248040e7b5815ef5d3780cdff5f9fef617a19e", + "clean": true, + "hasUnmergedFiles": false, + "defaultBranch": "main", + "remoteHead": "8fb704866eca4ff16fb6ef916fcc7f20c436b83e", + "localTrackingHead": "8fb704866eca4ff16fb6ef916fcc7f20c436b83e", + "remoteHeadEvidence": "live-ls-remote", + "mergedToDefaultBranch": true, + "commitTimestamp": 1783779429, + "review": null, + "artifactTracked": true + }, + "build": { + "commands": [ + { + "executable": "pnpm", + "args": [ + "build:cli" + ], + "workingDirectory": "source" + }, + { + "executable": "esbuild", + "args": [ + "packages/cli/bin/merefi.ts", + "--bundle", + "--platform=node", + "--format=esm", + "--target=node24", + "--outfile=adapters/finance/run.js" + ], + "workingDirectory": "source" + }, + { + "executable": "normalize-file-modes", + "args": [ + "adapters/finance/run.js=755", + "adapters/finance/**=644" + ], + "workingDirectory": "source" + } + ], + "toolchain": { + "node": "v24.15.0", + "pnpm": "10.8.1", + "esbuild": "0.28.1", + "sourcePackageManager": "pnpm@10.8.1", + "sourceLockfiles": [ + { + "path": "pnpm-lock.yaml", + "sha256": "d6c75dfbe4bda86f9621ff42f56a33f409f30951cea9649f00416b96f6645e24", + "size": 204545 + } + ] + }, + "deterministicEnvironment": { + "SOURCE_DATE_EPOCH": "1783810721", + "TZ": "UTC", + "LC_ALL": "C" + } + }, + "contract": null, + "artifacts": [ + { + "path": "adapters/finance/run.js", + "sha256": "09423ba8bb05e2912fed9d19811a82b21ed2a05253eb3404f525c6392ddaf9bd", + "size": 369399, + "mode": "755" + } + ] }, { "app": "dynasite", "sourceRepoPath": "mere-dynasite", - "sourceArtifactPath": "mere-dynasite/dist/run.js", + "sourceArtifactPath": "dist/run.js", "adapterPath": "adapters/dynasite/run.js", - "builtAt": "2026-07-11T11:08:14.576Z" + "builtAt": "2026-07-11T22:58:41.000Z", + "source": { + "canonicalRepository": "https://github.com/sawfwair/mere-dynasite.git", + "actualRepository": "https://github.com/sawfwair/mere-dynasite.git", + "canonicalRemote": true, + "commit": "71caaeab956e8e8f3a928cb32188565a63dabca7", + "tree": "18980f9828bcb8286ce21b6685a36a353b05e86f", + "clean": true, + "hasUnmergedFiles": false, + "defaultBranch": "main", + "remoteHead": "71caaeab956e8e8f3a928cb32188565a63dabca7", + "localTrackingHead": "71caaeab956e8e8f3a928cb32188565a63dabca7", + "remoteHeadEvidence": "live-ls-remote", + "mergedToDefaultBranch": true, + "commitTimestamp": 1783779422, + "review": null, + "artifactTracked": false + }, + "build": { + "commands": [ + { + "executable": "remove-generated-output", + "args": [ + "dist/run.js" + ], + "workingDirectory": "source" + }, + { + "executable": "pnpm", + "args": [ + "build:cli" + ], + "workingDirectory": "source" + }, + { + "executable": "copy-file", + "args": [ + "dist/run.js", + "adapters/dynasite/" + ], + "workingDirectory": "source" + }, + { + "executable": "normalize-file-modes", + "args": [ + "adapters/dynasite/run.js=755", + "adapters/dynasite/**=644" + ], + "workingDirectory": "source" + } + ], + "toolchain": { + "node": "v24.15.0", + "pnpm": "10.8.1", + "esbuild": "0.28.1", + "sourcePackageManager": "pnpm@10.8.1", + "sourceLockfiles": [ + { + "path": "pnpm-lock.yaml", + "sha256": "80e10a92821ff4a8be97850b5c35aec81b672caab3cf90c5310c0deada483eb2", + "size": 181738 + } + ] + }, + "deterministicEnvironment": { + "SOURCE_DATE_EPOCH": "1783810721", + "TZ": "UTC", + "LC_ALL": "C" + } + }, + "contract": null, + "artifacts": [ + { + "path": "adapters/dynasite/run.js", + "sha256": "f684c57ae1f9910c12a399f1c54861f317f4797f36c3015328409e99fcdd4c7f", + "size": 111509, + "mode": "755" + } + ] }, { "app": "projects", "sourceRepoPath": "mere-projects", - "sourceArtifactPath": "mere-projects/dist/run.js", + "sourceArtifactPath": "dist/run.js", "adapterPath": "adapters/projects/run.js", - "builtAt": "2026-07-11T11:08:14.576Z" + "builtAt": "2026-07-11T22:58:41.000Z", + "source": { + "canonicalRepository": "https://github.com/sawfwair/mere-projects.git", + "actualRepository": "https://github.com/sawfwair/mere-projects.git", + "canonicalRemote": true, + "commit": "b1919550b331d0754343639aeddc774483afd7e5", + "tree": "844b9856e65313ec14955586aaa47ff9c279501c", + "clean": true, + "hasUnmergedFiles": false, + "defaultBranch": "main", + "remoteHead": "b1919550b331d0754343639aeddc774483afd7e5", + "localTrackingHead": "b1919550b331d0754343639aeddc774483afd7e5", + "remoteHeadEvidence": "live-ls-remote", + "mergedToDefaultBranch": true, + "commitTimestamp": 1783779491, + "review": null, + "artifactTracked": false + }, + "build": { + "commands": [ + { + "executable": "remove-generated-output", + "args": [ + "dist/run.js" + ], + "workingDirectory": "source" + }, + { + "executable": "pnpm", + "args": [ + "build:cli" + ], + "workingDirectory": "source" + }, + { + "executable": "copy-file", + "args": [ + "dist/run.js", + "adapters/projects/" + ], + "workingDirectory": "source" + }, + { + "executable": "normalize-file-modes", + "args": [ + "adapters/projects/run.js=755", + "adapters/projects/**=644" + ], + "workingDirectory": "source" + } + ], + "toolchain": { + "node": "v24.15.0", + "pnpm": "10.8.1", + "esbuild": "0.28.1", + "sourcePackageManager": "pnpm@10.8.1", + "sourceLockfiles": [ + { + "path": "pnpm-lock.yaml", + "sha256": "5bfef765456db3d2a6883e92f3b8bf92c2c9e198dc8d68f9c1791721f4742f01", + "size": 179814 + } + ] + }, + "deterministicEnvironment": { + "SOURCE_DATE_EPOCH": "1783810721", + "TZ": "UTC", + "LC_ALL": "C" + } + }, + "contract": null, + "artifacts": [ + { + "path": "adapters/projects/run.js", + "sha256": "73d08a102f993e948bb751c38ddd5c5b216f6a0a044e71cc77138713ad25c7b4", + "size": 206592, + "mode": "755" + } + ] }, { "app": "agent", "sourceRepoPath": "mere-agent", - "sourceArtifactPath": "mere-agent/cli-dist/run.js", + "sourceArtifactPath": "cli-dist/run.js", "adapterPath": "adapters/agent/run.js", - "builtAt": "2026-07-11T11:08:14.576Z" + "builtAt": "2026-07-11T22:58:41.000Z", + "source": { + "canonicalRepository": "https://github.com/sawfwair/mere-agent.git", + "actualRepository": "https://github.com/sawfwair/mere-agent.git", + "canonicalRemote": true, + "commit": "9ef5b89695477b12ed5781cacfdf90a1769f3f77", + "tree": "4781a694f0769b78d14e6ea22629271fd1a3753a", + "clean": true, + "hasUnmergedFiles": false, + "defaultBranch": "main", + "remoteHead": "9ef5b89695477b12ed5781cacfdf90a1769f3f77", + "localTrackingHead": "9ef5b89695477b12ed5781cacfdf90a1769f3f77", + "remoteHeadEvidence": "live-ls-remote", + "mergedToDefaultBranch": true, + "commitTimestamp": 1783779405, + "review": null, + "artifactTracked": false + }, + "build": { + "commands": [ + { + "executable": "remove-generated-output", + "args": [ + "cli-dist/run.js" + ], + "workingDirectory": "source" + }, + { + "executable": "pnpm", + "args": [ + "build:cli" + ], + "workingDirectory": "source" + }, + { + "executable": "copy-file", + "args": [ + "cli-dist/run.js", + "adapters/agent/" + ], + "workingDirectory": "source" + }, + { + "executable": "normalize-file-modes", + "args": [ + "adapters/agent/run.js=755", + "adapters/agent/**=644" + ], + "workingDirectory": "source" + } + ], + "toolchain": { + "node": "v24.15.0", + "pnpm": "10.8.1", + "esbuild": "0.28.1", + "sourcePackageManager": "pnpm@10.8.1", + "sourceLockfiles": [ + { + "path": "pnpm-lock.yaml", + "sha256": "1275ff52b37e12e5b552e3872a785849d9817190bea17113914ab1d7fdcc18e1", + "size": 235049 + } + ] + }, + "deterministicEnvironment": { + "SOURCE_DATE_EPOCH": "1783810721", + "TZ": "UTC", + "LC_ALL": "C" + } + }, + "contract": null, + "artifacts": [ + { + "path": "adapters/agent/run.js", + "sha256": "a34dccc447839877192d4c71e1c640bd98eff8700f37db42f4e79d815bf73406", + "size": 112428, + "mode": "755" + } + ] }, { "app": "today", "sourceRepoPath": "mere-today", - "sourceArtifactPath": "mere-today/dist/run.js", + "sourceArtifactPath": "dist/run.js", "adapterPath": "adapters/today/run.js", - "builtAt": "2026-07-11T11:08:14.576Z" + "builtAt": "2026-07-11T22:58:41.000Z", + "source": { + "canonicalRepository": "https://github.com/sawfwair/mere-today.git", + "actualRepository": "https://github.com/sawfwair/mere-today.git", + "canonicalRemote": true, + "commit": "f1ea96230e0d5fd7228d823b304393b3418a5fb6", + "tree": "d088809df30faafc52e1a98c6b3427488a4e02ff", + "clean": true, + "hasUnmergedFiles": false, + "defaultBranch": "main", + "remoteHead": "f1ea96230e0d5fd7228d823b304393b3418a5fb6", + "localTrackingHead": "f1ea96230e0d5fd7228d823b304393b3418a5fb6", + "remoteHeadEvidence": "live-ls-remote", + "mergedToDefaultBranch": true, + "commitTimestamp": 1783779493, + "review": null, + "artifactTracked": false + }, + "build": { + "commands": [ + { + "executable": "remove-generated-output", + "args": [ + "dist/run.js" + ], + "workingDirectory": "source" + }, + { + "executable": "pnpm", + "args": [ + "build:cli" + ], + "workingDirectory": "source" + }, + { + "executable": "copy-file", + "args": [ + "dist/run.js", + "adapters/today/" + ], + "workingDirectory": "source" + }, + { + "executable": "normalize-file-modes", + "args": [ + "adapters/today/run.js=755", + "adapters/today/**=644" + ], + "workingDirectory": "source" + } + ], + "toolchain": { + "node": "v24.15.0", + "pnpm": "10.8.1", + "esbuild": "0.28.1", + "sourcePackageManager": "pnpm@10.8.1", + "sourceLockfiles": [ + { + "path": "pnpm-lock.yaml", + "sha256": "dddf30d168f77148b16d281628da8fec032bbff6d6dcd440c1d969ac02234e1d", + "size": 182213 + } + ] + }, + "deterministicEnvironment": { + "SOURCE_DATE_EPOCH": "1783810721", + "TZ": "UTC", + "LC_ALL": "C" + } + }, + "contract": null, + "artifacts": [ + { + "path": "adapters/today/run.js", + "sha256": "a0cffb275cb728a567dde0c34f0138fce777abb8c5207e3fad23d4d545da017c", + "size": 212561, + "mode": "755" + } + ] }, { "app": "zone", "sourceRepoPath": "mere-zone", - "sourceArtifactPath": "mere-zone/dist/run.js", + "sourceArtifactPath": "dist/run.js", "adapterPath": "adapters/zone/run.js", - "builtAt": "2026-07-11T11:08:14.576Z" + "builtAt": "2026-07-11T22:58:41.000Z", + "source": { + "canonicalRepository": "https://github.com/sawfwair/mere-zone.git", + "actualRepository": "https://github.com/sawfwair/mere-zone.git", + "canonicalRemote": true, + "commit": "ec92109817316804df418f6f9dcf70de2fb0eb12", + "tree": "2d9bb0ca106d626024affbdee7d88758b4d117a0", + "clean": true, + "hasUnmergedFiles": false, + "defaultBranch": "main", + "remoteHead": "ec92109817316804df418f6f9dcf70de2fb0eb12", + "localTrackingHead": "ec92109817316804df418f6f9dcf70de2fb0eb12", + "remoteHeadEvidence": "live-ls-remote", + "mergedToDefaultBranch": true, + "commitTimestamp": 1783779518, + "review": null, + "artifactTracked": false + }, + "build": { + "commands": [ + { + "executable": "remove-generated-output", + "args": [ + "dist/run.js" + ], + "workingDirectory": "source" + }, + { + "executable": "pnpm", + "args": [ + "build:cli" + ], + "workingDirectory": "source" + }, + { + "executable": "copy-file", + "args": [ + "dist/run.js", + "adapters/zone/" + ], + "workingDirectory": "source" + }, + { + "executable": "normalize-file-modes", + "args": [ + "adapters/zone/run.js=755", + "adapters/zone/**=644" + ], + "workingDirectory": "source" + } + ], + "toolchain": { + "node": "v24.15.0", + "pnpm": "10.8.1", + "esbuild": "0.28.1", + "sourcePackageManager": "pnpm@10.8.1", + "sourceLockfiles": [ + { + "path": "pnpm-lock.yaml", + "sha256": "ce01480c4490b0fe49c6ac897d8e3ffbcffb89b3b9e57d8bb9d03438b940b56b", + "size": 219966 + } + ] + }, + "deterministicEnvironment": { + "SOURCE_DATE_EPOCH": "1783810721", + "TZ": "UTC", + "LC_ALL": "C" + } + }, + "contract": null, + "artifacts": [ + { + "path": "adapters/zone/run.js", + "sha256": "91143d6678f6ced605daaf40dffa249cb3a2788dcfd08b3400988a5c5822b8dc", + "size": 123490, + "mode": "755" + } + ] }, { "app": "video", "sourceRepoPath": "mere-video", - "sourceArtifactPath": "mere-video/dist/run.js", + "sourceArtifactPath": "dist/run.js", "adapterPath": "adapters/video/run.js", - "builtAt": "2026-07-11T11:08:14.576Z" + "builtAt": "2026-07-11T22:58:41.000Z", + "source": { + "canonicalRepository": "https://github.com/sawfwair/mere-video.git", + "actualRepository": "https://github.com/sawfwair/mere-video.git", + "canonicalRemote": true, + "commit": "b0540a91ccff00dfb9f3a1b8620173cb6f3cb9f2", + "tree": "cbbe6b412202891d59aaef79d7a194e16587d037", + "clean": true, + "hasUnmergedFiles": false, + "defaultBranch": "main", + "remoteHead": "b0540a91ccff00dfb9f3a1b8620173cb6f3cb9f2", + "localTrackingHead": "b0540a91ccff00dfb9f3a1b8620173cb6f3cb9f2", + "remoteHeadEvidence": "live-ls-remote", + "mergedToDefaultBranch": true, + "commitTimestamp": 1783779507, + "review": null, + "artifactTracked": false + }, + "build": { + "commands": [ + { + "executable": "remove-generated-output", + "args": [ + "dist/run.js" + ], + "workingDirectory": "source" + }, + { + "executable": "pnpm", + "args": [ + "build:cli" + ], + "workingDirectory": "source" + }, + { + "executable": "copy-file", + "args": [ + "dist/run.js", + "adapters/video/" + ], + "workingDirectory": "source" + }, + { + "executable": "normalize-file-modes", + "args": [ + "adapters/video/run.js=755", + "adapters/video/**=644" + ], + "workingDirectory": "source" + } + ], + "toolchain": { + "node": "v24.15.0", + "pnpm": "10.8.1", + "esbuild": "0.28.1", + "sourcePackageManager": "pnpm@10.8.1", + "sourceLockfiles": [ + { + "path": "pnpm-lock.yaml", + "sha256": "dea708dbea5a4bdd65657f36f5eff132b93abeed1a7f3f40d96cdf1f51a79a0b", + "size": 174272 + } + ] + }, + "deterministicEnvironment": { + "SOURCE_DATE_EPOCH": "1783810721", + "TZ": "UTC", + "LC_ALL": "C" + } + }, + "contract": null, + "artifacts": [ + { + "path": "adapters/video/run.js", + "sha256": "2f7879832fc2c632790c86ffc0c93dcc2d0c52d8f234e0c58cd9204f76989dee", + "size": 189879, + "mode": "755" + } + ] }, { "app": "network", "sourceRepoPath": "mere-network", - "sourceArtifactPath": "mere-network/dist/run.js", + "sourceArtifactPath": "dist/run.js", "adapterPath": "adapters/network/run.js", - "builtAt": "2026-07-11T11:08:14.576Z" + "builtAt": "2026-07-11T22:58:41.000Z", + "source": { + "canonicalRepository": "https://github.com/sawfwair/mere-network.git", + "actualRepository": "https://github.com/sawfwair/mere-network.git", + "canonicalRemote": true, + "commit": "39f4a3c56104be9791ec23950208a06cfdac4867", + "tree": "dde398d050d74de453e033fea715b75cfbee2b4f", + "clean": true, + "hasUnmergedFiles": false, + "defaultBranch": "main", + "remoteHead": "39f4a3c56104be9791ec23950208a06cfdac4867", + "localTrackingHead": "39f4a3c56104be9791ec23950208a06cfdac4867", + "remoteHeadEvidence": "live-ls-remote", + "mergedToDefaultBranch": true, + "commitTimestamp": 1783779479, + "review": null, + "artifactTracked": false + }, + "build": { + "commands": [ + { + "executable": "remove-generated-output", + "args": [ + "dist/run.js" + ], + "workingDirectory": "source" + }, + { + "executable": "pnpm", + "args": [ + "build:cli" + ], + "workingDirectory": "source" + }, + { + "executable": "copy-file", + "args": [ + "dist/run.js", + "adapters/network/" + ], + "workingDirectory": "source" + }, + { + "executable": "normalize-file-modes", + "args": [ + "adapters/network/run.js=755", + "adapters/network/**=644" + ], + "workingDirectory": "source" + } + ], + "toolchain": { + "node": "v24.15.0", + "pnpm": "10.8.1", + "esbuild": "0.28.1", + "sourcePackageManager": "pnpm@10.8.1", + "sourceLockfiles": [ + { + "path": "pnpm-lock.yaml", + "sha256": "7cd85a6e095797119cbd5567c1edd791b6024a8e1b97ef0d214c8e28c1c78ecb", + "size": 284503 + } + ] + }, + "deterministicEnvironment": { + "SOURCE_DATE_EPOCH": "1783810721", + "TZ": "UTC", + "LC_ALL": "C" + } + }, + "contract": null, + "artifacts": [ + { + "path": "adapters/network/run.js", + "sha256": "f03204770917269a8e1a4308d4d9bddbd98edd0c5d69fb12a062d9335c6f2b75", + "size": 135920, + "mode": "755" + } + ] }, { "app": "email", "sourceRepoPath": "mere-email", - "sourceArtifactPath": "mere-email/dist/run.js", + "sourceArtifactPath": "dist/run.js", "adapterPath": "adapters/email/run.js", - "builtAt": "2026-07-11T11:08:14.576Z" + "builtAt": "2026-07-11T22:58:41.000Z", + "source": { + "canonicalRepository": "https://github.com/sawfwair/mere-email.git", + "actualRepository": "https://github.com/sawfwair/mere-email.git", + "canonicalRemote": true, + "commit": "19894466711c38bde2023d13b5b84d8856e196c4", + "tree": "d725592edbe13575a2873788d22d33ac9375651b", + "clean": true, + "hasUnmergedFiles": false, + "defaultBranch": "main", + "remoteHead": "19894466711c38bde2023d13b5b84d8856e196c4", + "localTrackingHead": "19894466711c38bde2023d13b5b84d8856e196c4", + "remoteHeadEvidence": "live-ls-remote", + "mergedToDefaultBranch": true, + "commitTimestamp": 1783801413, + "review": null, + "artifactTracked": false + }, + "build": { + "commands": [ + { + "executable": "remove-generated-output", + "args": [ + "dist/run.js" + ], + "workingDirectory": "source" + }, + { + "executable": "pnpm", + "args": [ + "build:cli" + ], + "workingDirectory": "source" + }, + { + "executable": "copy-file", + "args": [ + "dist/run.js", + "adapters/email/" + ], + "workingDirectory": "source" + }, + { + "executable": "normalize-file-modes", + "args": [ + "adapters/email/run.js=755", + "adapters/email/**=644" + ], + "workingDirectory": "source" + } + ], + "toolchain": { + "node": "v24.15.0", + "pnpm": "10.8.1", + "esbuild": "0.28.1", + "sourcePackageManager": "pnpm@10.8.1", + "sourceLockfiles": [ + { + "path": "pnpm-lock.yaml", + "sha256": "eb45f0106d076c083be344a71563ad1db7c3b1e671c3dd28fa3c758e5f51d6e0", + "size": 185508 + } + ] + }, + "deterministicEnvironment": { + "SOURCE_DATE_EPOCH": "1783810721", + "TZ": "UTC", + "LC_ALL": "C" + } + }, + "contract": { + "name": "mere-console", + "version": 1, + "schema": { + "path": "contracts/mere-console/v1/mere-console-contract.v1.schema.json", + "sha256": "e249172d656fdf2cecb81fb1006339652c48530da217f1c7451d6881c1014d81", + "size": 29498 + }, + "fixtures": { + "path": "contracts/mere-console/v1/fixtures", + "sha256": "b3c0bb45bee97076af1531541dd7f77cad6c77cdc62efda1805ddd0c17eb6379", + "files": 24 + } + }, + "artifacts": [ + { + "path": "adapters/email/run.js", + "sha256": "0926baec1b6bc68a65e94ad84bce4efe401be5ecf11a612156d04720e41e1e95", + "size": 435665, + "mode": "755" + } + ] }, { "app": "im", "sourceRepoPath": "mere-im", - "sourceArtifactPath": "mere-im/dist/run.js", + "sourceArtifactPath": "dist/run.js", "adapterPath": "adapters/im/run.js", - "builtAt": "2026-07-11T11:08:14.576Z" + "builtAt": "2026-07-11T22:58:41.000Z", + "source": { + "canonicalRepository": "https://github.com/sawfwair/mere-im.git", + "actualRepository": "https://github.com/sawfwair/mere-im.git", + "canonicalRemote": true, + "commit": "2040a2fe9741bb2266702b3235ebc2d341d503a0", + "tree": "ad7edcc5a047cda386f9ff0a9c85b687d14caeed", + "clean": true, + "hasUnmergedFiles": false, + "defaultBranch": "main", + "remoteHead": "2040a2fe9741bb2266702b3235ebc2d341d503a0", + "localTrackingHead": "2040a2fe9741bb2266702b3235ebc2d341d503a0", + "remoteHeadEvidence": "live-ls-remote", + "mergedToDefaultBranch": true, + "commitTimestamp": 1783779459, + "review": null, + "artifactTracked": false + }, + "build": { + "commands": [ + { + "executable": "remove-generated-output", + "args": [ + "dist/run.js" + ], + "workingDirectory": "source" + }, + { + "executable": "pnpm", + "args": [ + "build:cli" + ], + "workingDirectory": "source" + }, + { + "executable": "copy-file", + "args": [ + "dist/run.js", + "adapters/im/" + ], + "workingDirectory": "source" + }, + { + "executable": "normalize-file-modes", + "args": [ + "adapters/im/run.js=755", + "adapters/im/**=644" + ], + "workingDirectory": "source" + } + ], + "toolchain": { + "node": "v24.15.0", + "pnpm": "10.8.1", + "esbuild": "0.28.1", + "sourcePackageManager": "pnpm@10.8.1", + "sourceLockfiles": [ + { + "path": "pnpm-lock.yaml", + "sha256": "b298a0063216933e0728cef03df197b3c1446f64744cb217d45a5df5ad21617f", + "size": 200148 + } + ] + }, + "deterministicEnvironment": { + "SOURCE_DATE_EPOCH": "1783810721", + "TZ": "UTC", + "LC_ALL": "C" + } + }, + "contract": null, + "artifacts": [ + { + "path": "adapters/im/run.js", + "sha256": "ac2fd54837452877dc508e9fa08b9b536afe76043d13effd3ba87b5daf40be72", + "size": 150215, + "mode": "755" + } + ] }, { "app": "gives", "sourceRepoPath": "mere-gives", - "sourceArtifactPath": "mere-gives/dist/run.js", + "sourceArtifactPath": "dist/run.js", "adapterPath": "adapters/gives/run.js", - "builtAt": "2026-07-11T11:08:14.576Z" + "builtAt": "2026-07-11T22:58:41.000Z", + "source": { + "canonicalRepository": "https://github.com/sawfwair/mere-gives.git", + "actualRepository": "https://github.com/sawfwair/mere-gives.git", + "canonicalRemote": true, + "commit": "b924cfbee2fad6714f117269b6af1d75035caa4a", + "tree": "4c382f0b8a49d3b49ed2e868fb0fa867be7ea9ba", + "clean": true, + "hasUnmergedFiles": false, + "defaultBranch": "main", + "remoteHead": "b924cfbee2fad6714f117269b6af1d75035caa4a", + "localTrackingHead": "b924cfbee2fad6714f117269b6af1d75035caa4a", + "remoteHeadEvidence": "live-ls-remote", + "mergedToDefaultBranch": true, + "commitTimestamp": 1783779443, + "review": null, + "artifactTracked": false + }, + "build": { + "commands": [ + { + "executable": "remove-generated-output", + "args": [ + "dist/run.js" + ], + "workingDirectory": "source" + }, + { + "executable": "pnpm", + "args": [ + "build:cli" + ], + "workingDirectory": "source" + }, + { + "executable": "copy-file", + "args": [ + "dist/run.js", + "adapters/gives/" + ], + "workingDirectory": "source" + }, + { + "executable": "normalize-file-modes", + "args": [ + "adapters/gives/run.js=755", + "adapters/gives/**=644" + ], + "workingDirectory": "source" + } + ], + "toolchain": { + "node": "v24.15.0", + "pnpm": "10.8.1", + "esbuild": "0.28.1", + "sourcePackageManager": "pnpm@10.8.1", + "sourceLockfiles": [ + { + "path": "pnpm-lock.yaml", + "sha256": "8a62a9f687395b8c8de9ae375a321851a926ece43e8f82e30e687db5c7857aa4", + "size": 193092 + } + ] + }, + "deterministicEnvironment": { + "SOURCE_DATE_EPOCH": "1783810721", + "TZ": "UTC", + "LC_ALL": "C" + } + }, + "contract": null, + "artifacts": [ + { + "path": "adapters/gives/run.js", + "sha256": "4f32056e1e2155d5f9fe2021bde9c08d3b3753d7b2af259412529b83b2b5ce71", + "size": 118223, + "mode": "755" + } + ] }, { "app": "works", "sourceRepoPath": "mere-works", - "sourceArtifactPath": "mere-works/dist/run.js", + "sourceArtifactPath": "dist/run.js", "adapterPath": "adapters/works/run.js", - "builtAt": "2026-07-11T11:08:14.576Z" + "builtAt": "2026-07-11T22:58:41.000Z", + "source": { + "canonicalRepository": "https://github.com/sawfwair/mere-works.git", + "actualRepository": "https://github.com/sawfwair/mere-works.git", + "canonicalRemote": true, + "commit": "796dc4893bfc6118f94219cda9bf507ab32dcd3c", + "tree": "496f8a6d36b3b3c61777ebf28c49e95bb4542268", + "clean": true, + "hasUnmergedFiles": false, + "defaultBranch": "main", + "remoteHead": "796dc4893bfc6118f94219cda9bf507ab32dcd3c", + "localTrackingHead": "796dc4893bfc6118f94219cda9bf507ab32dcd3c", + "remoteHeadEvidence": "live-ls-remote", + "mergedToDefaultBranch": true, + "commitTimestamp": 1783779512, + "review": null, + "artifactTracked": false + }, + "build": { + "commands": [ + { + "executable": "remove-generated-output", + "args": [ + "dist/run.js" + ], + "workingDirectory": "source" + }, + { + "executable": "pnpm", + "args": [ + "build:cli" + ], + "workingDirectory": "source" + }, + { + "executable": "copy-file", + "args": [ + "dist/run.js", + "adapters/works/" + ], + "workingDirectory": "source" + }, + { + "executable": "normalize-file-modes", + "args": [ + "adapters/works/run.js=755", + "adapters/works/**=644" + ], + "workingDirectory": "source" + } + ], + "toolchain": { + "node": "v24.15.0", + "pnpm": "10.8.1", + "esbuild": "0.28.1", + "sourcePackageManager": "pnpm@10.8.1", + "sourceLockfiles": [ + { + "path": "pnpm-lock.yaml", + "sha256": "e5b1cb8d4c1de5d870beefbb3a1c3111ea6b2d9f74a1faea45c8fb1b1aaffcd4", + "size": 175021 + } + ] + }, + "deterministicEnvironment": { + "SOURCE_DATE_EPOCH": "1783810721", + "TZ": "UTC", + "LC_ALL": "C" + } + }, + "contract": null, + "artifacts": [ + { + "path": "adapters/works/run.js", + "sha256": "944d14f6a32a816f485c6dc22caf5acbdfa0010ea8496d106a9d1d83d2661b11", + "size": 114086, + "mode": "755" + } + ] }, { "app": "media", "sourceRepoPath": "mere-media", - "sourceArtifactPath": "mere-media/dist/run.js", + "sourceArtifactPath": "dist/run.js", "adapterPath": "adapters/media/run.js", - "builtAt": "2026-07-11T11:08:14.576Z" + "builtAt": "2026-07-11T22:58:41.000Z", + "source": { + "canonicalRepository": "https://github.com/sawfwair/mere-media.git", + "actualRepository": "https://github.com/sawfwair/mere-media.git", + "canonicalRemote": true, + "commit": "358de91fa6058c5a73559e7c857b31a502b1f3af", + "tree": "269b5c434a13b172c428ef01747a4435b22908ac", + "clean": true, + "hasUnmergedFiles": false, + "defaultBranch": "main", + "remoteHead": "358de91fa6058c5a73559e7c857b31a502b1f3af", + "localTrackingHead": "358de91fa6058c5a73559e7c857b31a502b1f3af", + "remoteHeadEvidence": "live-ls-remote", + "mergedToDefaultBranch": true, + "commitTimestamp": 1783779473, + "review": null, + "artifactTracked": false + }, + "build": { + "commands": [ + { + "executable": "remove-generated-output", + "args": [ + "dist/run.js" + ], + "workingDirectory": "source" + }, + { + "executable": "pnpm", + "args": [ + "build:cli" + ], + "workingDirectory": "source" + }, + { + "executable": "copy-file", + "args": [ + "dist/run.js", + "adapters/media/" + ], + "workingDirectory": "source" + }, + { + "executable": "normalize-file-modes", + "args": [ + "adapters/media/run.js=755", + "adapters/media/**=644" + ], + "workingDirectory": "source" + } + ], + "toolchain": { + "node": "v24.15.0", + "pnpm": "10.8.1", + "esbuild": "0.28.1", + "sourcePackageManager": "pnpm@10.8.1", + "sourceLockfiles": [ + { + "path": "pnpm-lock.yaml", + "sha256": "da0ed63596da37c51f77193c21d27ac74e7c53a9b7da7773f09d6a2f9257ac8e", + "size": 161162 + } + ] + }, + "deterministicEnvironment": { + "SOURCE_DATE_EPOCH": "1783810721", + "TZ": "UTC", + "LC_ALL": "C" + } + }, + "contract": null, + "artifacts": [ + { + "path": "adapters/media/run.js", + "sha256": "35da6e0c05aab06dd484a8e3f99f1b21a8e6c9866072037432532947e892a424", + "size": 117311, + "mode": "755" + } + ] }, { "app": "deliver", "sourceRepoPath": "mere-deliver", - "sourceArtifactPath": "mere-deliver/cli/run.js", + "sourceArtifactPath": "cli/run.js", "adapterPath": "adapters/deliver/run.js", - "builtAt": "2026-07-11T11:08:14.576Z" + "builtAt": "2026-07-11T22:58:41.000Z", + "source": { + "canonicalRepository": "https://github.com/sawfwair/mere-deliver.git", + "actualRepository": "https://github.com/sawfwair/mere-deliver.git", + "canonicalRemote": true, + "commit": "7fa7ed0780feb002d4b1b46bc10887bb0f0fe24a", + "tree": "81ced2e040ec1e7767d24c0b2f2736436fbd083a", + "clean": true, + "hasUnmergedFiles": false, + "defaultBranch": "main", + "remoteHead": "7fa7ed0780feb002d4b1b46bc10887bb0f0fe24a", + "localTrackingHead": "7fa7ed0780feb002d4b1b46bc10887bb0f0fe24a", + "remoteHeadEvidence": "live-ls-remote", + "mergedToDefaultBranch": true, + "commitTimestamp": 1783801922, + "review": null, + "artifactTracked": true + }, + "build": { + "commands": [ + { + "executable": "pnpm", + "args": [ + "build:cli" + ], + "workingDirectory": "source" + }, + { + "executable": "copy-file", + "args": [ + "cli/run.js", + "adapters/deliver/" + ], + "workingDirectory": "source" + }, + { + "executable": "esbuild", + "args": [ + "cli/local-plane.js", + "--bundle", + "--platform=node", + "--format=esm", + "--target=node24", + "--outfile=adapters/deliver/local-plane.js" + ], + "workingDirectory": "source" + }, + { + "executable": "normalize-file-modes", + "args": [ + "adapters/deliver/run.js=755", + "adapters/deliver/**=644" + ], + "workingDirectory": "source" + } + ], + "toolchain": { + "node": "v24.15.0", + "pnpm": "10.8.1", + "esbuild": "0.28.1", + "sourcePackageManager": null, + "sourceLockfiles": [ + { + "path": "pnpm-lock.yaml", + "sha256": "66b81359e26a75f2b4b82b53e0638c154dbf29e6b8d335a5249f629b339397ab", + "size": 135516 + }, + { + "path": "package-lock.json", + "sha256": "92d2d415054a319e2c5cbf793d3bd1202fc2263261923f099acfcd00293df13d", + "size": 239370 + } + ] + }, + "deterministicEnvironment": { + "SOURCE_DATE_EPOCH": "1783810721", + "TZ": "UTC", + "LC_ALL": "C" + } + }, + "contract": null, + "artifacts": [ + { + "path": "adapters/deliver/local-plane.js", + "sha256": "89208670995ca6da3edb152b8794648e32c27395ff0529186f93a1a6933e6bc3", + "size": 52439, + "mode": "644" + }, + { + "path": "adapters/deliver/run.js", + "sha256": "fea4680a4b726fb27bc8c285dc80db32f7e71c9fd60f0b0e67cc78b767adfe85", + "size": 37177, + "mode": "755" + } + ] }, { "app": "link", "sourceRepoPath": "merekit-link", - "sourceArtifactPath": "merekit-link/dist/run.js", + "sourceArtifactPath": "dist/run.js", "adapterPath": "adapters/link/run.js", - "builtAt": "2026-07-11T11:08:14.576Z" + "builtAt": "2026-07-11T22:58:41.000Z", + "source": { + "canonicalRepository": "https://github.com/sawfwair/merekit-link.git", + "actualRepository": "https://github.com/sawfwair/merekit-link.git", + "canonicalRemote": true, + "commit": "cc93fdead93a83c1103fb1bb9dd6aad1f42fcee2", + "tree": "6a571738cf6492ee5d1fd1f69b2f714835460677", + "clean": true, + "hasUnmergedFiles": false, + "defaultBranch": "main", + "remoteHead": "cc93fdead93a83c1103fb1bb9dd6aad1f42fcee2", + "localTrackingHead": "cc93fdead93a83c1103fb1bb9dd6aad1f42fcee2", + "remoteHeadEvidence": "live-ls-remote", + "mergedToDefaultBranch": true, + "commitTimestamp": 1783779805, + "review": null, + "artifactTracked": false + }, + "build": { + "commands": [ + { + "executable": "remove-generated-output", + "args": [ + "dist" + ], + "workingDirectory": "source" + }, + { + "executable": "pnpm", + "args": [ + "build" + ], + "workingDirectory": "source" + }, + { + "executable": "copy-directory", + "args": [ + "dist", + "adapters/link/" + ], + "workingDirectory": "source" + }, + { + "executable": "normalize-file-modes", + "args": [ + "adapters/link/run.js=755", + "adapters/link/**=644" + ], + "workingDirectory": "source" + } + ], + "toolchain": { + "node": "v24.15.0", + "pnpm": "10.8.1", + "esbuild": "0.28.1", + "sourcePackageManager": "pnpm@10.8.1", + "sourceLockfiles": [ + { + "path": "pnpm-lock.yaml", + "sha256": "46c74b7004f9e0b3c722af3391dd0e94d9a6eecffa30560ad4315e1dd5516e74", + "size": 93386 + } + ] + }, + "deterministicEnvironment": { + "SOURCE_DATE_EPOCH": "1783810721", + "TZ": "UTC", + "LC_ALL": "C" + } + }, + "contract": null, + "artifacts": [ + { + "path": "adapters/link/config/file.js", + "sha256": "18a6f6128b4c90b010bc801f189f36f78b7b9ca9552b8a2af34ea266220e7a20", + "size": 1664, + "mode": "644" + }, + { + "path": "adapters/link/config/normalize.js", + "sha256": "784fdcd3beea5b99966fea63a28deac08487ddc13063644e5b1f1bdad51d3d6f", + "size": 18461, + "mode": "644" + }, + { + "path": "adapters/link/config/starter.js", + "sha256": "3c91a91311520e5417f6065fc523801b4c0bae004f980b94588c596f66378196", + "size": 3683, + "mode": "644" + }, + { + "path": "adapters/link/domain/guards.js", + "sha256": "e0ff5e0a8c417ce3469ddaa035ad780fda4195a337bfa3012ca47d18ab0b7c66", + "size": 1503, + "mode": "644" + }, + { + "path": "adapters/link/domain/plugins.js", + "sha256": "09a33fa02600d15e951487402c82d0613491738263a03923077ae58e2a987d13", + "size": 694, + "mode": "644" + }, + { + "path": "adapters/link/domain/types.js", + "sha256": "8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881", + "size": 11, + "mode": "644" + }, + { + "path": "adapters/link/manifest.js", + "sha256": "5bc7f56ae2395f7ecc55039acacb52da992c994490e7973af7dc7e4ca894d2d3", + "size": 7015, + "mode": "644" + }, + { + "path": "adapters/link/policy.js", + "sha256": "2df4c613a81dc2c4c2a5b471198a61bbc20d233b003f9ccae1af29e437c680e4", + "size": 10935, + "mode": "644" + }, + { + "path": "adapters/link/run.js", + "sha256": "47790a3ce4d5a59da2296e8fa245743b8d4ca18121bd3f5c6a5415e959ecb552", + "size": 18043, + "mode": "755" + }, + { + "path": "adapters/link/runtime/args.js", + "sha256": "3ca6becfd45dec5b0235282e7a6c4ecb48148fcc7a129ba0b672610c16b37080", + "size": 1019, + "mode": "644" + }, + { + "path": "adapters/link/runtime/executor.js", + "sha256": "3b0b7f41ddfb7fcf3ae9668d7f7b607a0265c463fe799157c33a9e3da20bd555", + "size": 21580, + "mode": "644" + }, + { + "path": "adapters/link/runtime/json.js", + "sha256": "b15e4384d34fa135f72e7118784081dcbc83433543c262d6adbd4130ac096190", + "size": 533, + "mode": "644" + }, + { + "path": "adapters/link/runtime/mere.js", + "sha256": "7bf232a52acc6c272bda36e1d010024949b2287e7c11e4f54d752318ebf58c8e", + "size": 4166, + "mode": "644" + }, + { + "path": "adapters/link/runtime/output.js", + "sha256": "acf772a26bbe2997d41b7d97a5112e2dfcd8d9e220472b81951979f3fa6751da", + "size": 1109, + "mode": "644" + }, + { + "path": "adapters/link/runtime/paths.js", + "sha256": "ae723029a5102fd839e007d0ab5bb04690a739ca17580d304dceab467dcde511", + "size": 772, + "mode": "644" + }, + { + "path": "adapters/link/runtime/yaml.js", + "sha256": "98f087c2e782c375ded86f12a21007742db0966fc85651ac9b448f2829c95b9c", + "size": 380, + "mode": "644" + }, + { + "path": "adapters/link/sync/executor-policy.js", + "sha256": "92d0328389764a7d49adcdd39b9275fe90e2c108e941c45c1ba1f79e17d94d7b", + "size": 17709, + "mode": "644" + }, + { + "path": "adapters/link/sync/projects.js", + "sha256": "84e76e4a4a6826524d49ae04dbe9588e983864cb3574f4a987bbf9d261e82999", + "size": 9105, + "mode": "644" + } + ] } ] } diff --git a/adapters/media/run.js b/adapters/media/run.js index 727ecbe..d5a1ded 100755 --- a/adapters/media/run.js +++ b/adapters/media/run.js @@ -952,7 +952,7 @@ __export(local_store_exports, { }); import { mkdir as mkdir2 } from "node:fs/promises"; import path5 from "node:path"; -import { randomUUID as randomUUID2 } from "node:crypto"; +import { randomUUID as randomUUID3 } from "node:crypto"; import * as sqliteVec from "sqlite-vec"; function defaultLocalDbPath(env = process.env) { return defaultLocalPlaneDbPath(env); @@ -965,7 +965,7 @@ function resolveLocalDbPath(options = {}) { }); } function makeId(prefix) { - return `${prefix}_${randomUUID2().replaceAll("-", "").slice(0, 24)}`; + return `${prefix}_${randomUUID3().replaceAll("-", "").slice(0, 24)}`; } function isoNow4() { return (/* @__PURE__ */ new Date()).toISOString(); @@ -1469,7 +1469,8 @@ var CLI_AUTH_ERROR_QUERY_PARAM = "error"; var CLI_AUTH_ERROR_DESCRIPTION_QUERY_PARAM = "error_description"; // node_modules/.pnpm/@mere+cli-auth@file+..+business+packages+cli-auth_@sveltejs+kit@2.69.1_@sveltejs+vite-p_23266a883b1cd7e991fc17449e3c5227/node_modules/@mere/cli-auth/src/session.ts -import { chmod, mkdir, readFile, rm, writeFile } from "node:fs/promises"; +import { randomUUID as randomUUID2 } from "node:crypto"; +import { mkdir, open, readFile, rename, rm } from "node:fs/promises"; import os2 from "node:os"; import path2 from "node:path"; function stateHome2(env) { @@ -1513,10 +1514,29 @@ async function loadCliSession(input) { } async function saveCliSession(input) { const paths = resolveCliPaths(input.appName, input.env ?? process.env); - await mkdir(paths.stateDir, { recursive: true }); - await writeFile(paths.sessionFile, `${JSON.stringify(input.session, null, 2)} + await writeCliSessionFile(paths.sessionFile, input.session); +} +async function writeCliSessionFile(sessionFile, session) { + const stateDir = path2.dirname(sessionFile); + const tempFile = path2.join( + stateDir, + `.${path2.basename(sessionFile)}.${process.pid}.${randomUUID2()}.tmp` + ); + let handle; + await mkdir(stateDir, { recursive: true }); + try { + handle = await open(tempFile, "wx", 384); + await handle.writeFile(`${JSON.stringify(session, null, 2)} `, "utf8"); - await chmod(paths.sessionFile, 384).catch(() => void 0); + await handle.sync(); + await handle.close(); + handle = void 0; + await rename(tempFile, sessionFile); + } catch (error) { + await handle?.close().catch(() => void 0); + await rm(tempFile, { force: true }).catch(() => void 0); + throw error; + } } async function clearCliSession(input) { const env = input.env ?? process.env; @@ -2306,7 +2326,7 @@ esac // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/mere-run.ts import { createReadStream, createWriteStream, existsSync, mkdirSync } from "node:fs"; -import { access, chmod as chmod2, mkdtemp, rm as rm2 } from "node:fs/promises"; +import { access, chmod, mkdtemp, rm as rm2 } from "node:fs/promises"; import { createHash as createHash2 } from "node:crypto"; import https from "node:https"; import os3 from "node:os"; @@ -2420,7 +2440,7 @@ async function installFromDmg(env, appId) { if (install.status !== 0) { throw new Error(install.stderr || install.stdout || "mere.run installer failed."); } - await chmod2(installBin, 493).catch(() => void 0); + await chmod(installBin, 493).catch(() => void 0); return installBin; } finally { await rm2(tmp, { recursive: true, force: true }); diff --git a/adapters/network/run.js b/adapters/network/run.js index 48cb061..78b7d2c 100755 --- a/adapters/network/run.js +++ b/adapters/network/run.js @@ -20,7 +20,8 @@ var CLI_AUTH_ERROR_QUERY_PARAM = "error"; var CLI_AUTH_ERROR_DESCRIPTION_QUERY_PARAM = "error_description"; // node_modules/.pnpm/@mere+cli-auth@file+..+business+packages+cli-auth_@sveltejs+kit@2.53.4_@sveltejs+vite-p_4f1e0b08fdcce373366f22b39b7c03c8/node_modules/@mere/cli-auth/src/session.ts -import { chmod, mkdir, readFile, rm, writeFile } from "node:fs/promises"; +import { randomUUID } from "node:crypto"; +import { mkdir, open, readFile, rename, rm } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; function stateHome(env) { @@ -64,10 +65,29 @@ async function loadCliSession(input) { } async function saveCliSession(input) { const paths = resolveCliPaths(input.appName, input.env ?? process.env); - await mkdir(paths.stateDir, { recursive: true }); - await writeFile(paths.sessionFile, `${JSON.stringify(input.session, null, 2)} + await writeCliSessionFile(paths.sessionFile, input.session); +} +async function writeCliSessionFile(sessionFile, session) { + const stateDir = path.dirname(sessionFile); + const tempFile = path.join( + stateDir, + `.${path.basename(sessionFile)}.${process.pid}.${randomUUID()}.tmp` + ); + let handle; + await mkdir(stateDir, { recursive: true }); + try { + handle = await open(tempFile, "wx", 384); + await handle.writeFile(`${JSON.stringify(session, null, 2)} `, "utf8"); - await chmod(paths.sessionFile, 384).catch(() => void 0); + await handle.sync(); + await handle.close(); + handle = void 0; + await rename(tempFile, sessionFile); + } catch (error) { + await handle?.close().catch(() => void 0); + await rm(tempFile, { force: true }).catch(() => void 0); + throw error; + } } async function clearCliSession(input) { const env = input.env ?? process.env; @@ -327,7 +347,7 @@ async function logoutRemote(input = {}) { } // cli/local-plane.ts -import { mkdir as mkdir3, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises"; +import { mkdir as mkdir3, readFile as readFile2, writeFile } from "node:fs/promises"; import { dirname, resolve as resolvePath } from "node:path"; // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/config.ts @@ -561,12 +581,12 @@ async function deliverCloudProjectionEvent(input) { } // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/index.ts -import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto"; +import { createHash as createHash2, randomUUID as randomUUID3 } from "node:crypto"; import { mkdir as mkdir2 } from "node:fs/promises"; import path3 from "node:path"; // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/migration.ts -import { createHash, randomUUID } from "node:crypto"; +import { createHash, randomUUID as randomUUID2 } from "node:crypto"; var PLANE_TRANSFER_KIND = "mere.local-plane.transfer"; var PLANE_TRANSFER_VERSION = 1; function isRecord(value) { @@ -702,7 +722,7 @@ function createPlaneTransferImportPlan(input) { }; } function recordPlaneTransfer(db, input) { - const id = `xfer_${randomUUID().replaceAll("-", "").slice(0, 24)}`; + const id = `xfer_${randomUUID2().replaceAll("-", "").slice(0, 24)}`; db.prepare( `INSERT INTO mere_plane_transfers ( id, app_id, workspace_id, direction, @@ -734,7 +754,7 @@ function json(value) { return JSON.stringify(value ?? {}); } function makePlaneId(prefix) { - return `${prefix}_${randomUUID2().replaceAll("-", "").slice(0, 24)}`; + return `${prefix}_${randomUUID3().replaceAll("-", "").slice(0, 24)}`; } async function loadNodeSqlite() { return import(["node", "sqlite"].join(":")); @@ -1955,7 +1975,7 @@ async function handleLocalExport(options, io) { if (!output) return bundle; const target = resolvePath(output); await mkdir3(dirname(target), { recursive: true }); - await writeFile2(target, JSON.stringify(bundle, null, 2)); + await writeFile(target, JSON.stringify(bundle, null, 2)); return { ok: true, path: target, diff --git a/adapters/package.json b/adapters/package.json index 853a683..0fd6848 100644 --- a/adapters/package.json +++ b/adapters/package.json @@ -1,6 +1,6 @@ { "name": "@merekit/cli-adapters", "private": true, - "version": "0.5.17", + "version": "0.5.18", "type": "module" } diff --git a/adapters/projects/run.js b/adapters/projects/run.js index 83fda02..e381b71 100755 --- a/adapters/projects/run.js +++ b/adapters/projects/run.js @@ -10,7 +10,7 @@ var __export = (target, all) => { }; // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/migration.ts -import { createHash, randomUUID } from "node:crypto"; +import { createHash, randomUUID as randomUUID2 } from "node:crypto"; function isRecord(value) { return value != null && typeof value === "object" && !Array.isArray(value); } @@ -144,7 +144,7 @@ function createPlaneTransferImportPlan(input) { }; } function recordPlaneTransfer(db, input) { - const id = `xfer_${randomUUID().replaceAll("-", "").slice(0, 24)}`; + const id = `xfer_${randomUUID2().replaceAll("-", "").slice(0, 24)}`; db.prepare( `INSERT INTO mere_plane_transfers ( id, app_id, workspace_id, direction, @@ -405,7 +405,7 @@ var init_config = __esm({ }); // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/index.ts -import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto"; +import { createHash as createHash2, randomUUID as randomUUID3 } from "node:crypto"; import { mkdir as mkdir2 } from "node:fs/promises"; import path3 from "node:path"; function isoNow2() { @@ -415,7 +415,7 @@ function json(value) { return JSON.stringify(value ?? {}); } function makePlaneId(prefix) { - return `${prefix}_${randomUUID2().replaceAll("-", "").slice(0, 24)}`; + return `${prefix}_${randomUUID3().replaceAll("-", "").slice(0, 24)}`; } async function loadNodeSqlite() { return import(["node", "sqlite"].join(":")); @@ -964,12 +964,12 @@ __export(local_store_exports, { PROJECTS_APP_ID: () => PROJECTS_APP_ID, PROJECTS_PROJECTS_PAYLOAD_SCHEMA: () => PROJECTS_PROJECTS_PAYLOAD_SCHEMA }); -import { randomUUID as randomUUID3 } from "node:crypto"; +import { randomUUID as randomUUID4 } from "node:crypto"; function isoNow3() { return (/* @__PURE__ */ new Date()).toISOString(); } function makeId(prefix) { - return `${prefix}_${randomUUID3().replaceAll("-", "").slice(0, 16)}`; + return `${prefix}_${randomUUID4().replaceAll("-", "").slice(0, 16)}`; } function parseJson2(value, fallback) { if (!value) return fallback; @@ -2358,7 +2358,7 @@ var init_local_store = __esm({ // cli/projects.ts import { createHash as createHash4 } from "node:crypto"; -import { mkdir as mkdir3, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises"; +import { mkdir as mkdir3, readFile as readFile2, writeFile } from "node:fs/promises"; import { basename, dirname, resolve } from "node:path"; // node_modules/.pnpm/@mere+cli-auth@file+..+business+packages+cli-auth_@sveltejs+kit@2.57.1_@sveltejs+vite-p_4e3f892a742bb9c5a510ac2c0515d785/node_modules/@mere/cli-auth/src/client.ts @@ -2377,7 +2377,8 @@ var CLI_AUTH_ERROR_QUERY_PARAM = "error"; var CLI_AUTH_ERROR_DESCRIPTION_QUERY_PARAM = "error_description"; // node_modules/.pnpm/@mere+cli-auth@file+..+business+packages+cli-auth_@sveltejs+kit@2.57.1_@sveltejs+vite-p_4e3f892a742bb9c5a510ac2c0515d785/node_modules/@mere/cli-auth/src/session.ts -import { chmod, mkdir, readFile, rm, writeFile } from "node:fs/promises"; +import { randomUUID } from "node:crypto"; +import { mkdir, open, readFile, rename, rm } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; function stateHome(env) { @@ -2421,10 +2422,29 @@ async function loadCliSession(input) { } async function saveCliSession(input) { const paths = resolveCliPaths(input.appName, input.env ?? process.env); - await mkdir(paths.stateDir, { recursive: true }); - await writeFile(paths.sessionFile, `${JSON.stringify(input.session, null, 2)} + await writeCliSessionFile(paths.sessionFile, input.session); +} +async function writeCliSessionFile(sessionFile, session) { + const stateDir = path.dirname(sessionFile); + const tempFile = path.join( + stateDir, + `.${path.basename(sessionFile)}.${process.pid}.${randomUUID()}.tmp` + ); + let handle; + await mkdir(stateDir, { recursive: true }); + try { + handle = await open(tempFile, "wx", 384); + await handle.writeFile(`${JSON.stringify(session, null, 2)} `, "utf8"); - await chmod(paths.sessionFile, 384).catch(() => void 0); + await handle.sync(); + await handle.close(); + handle = void 0; + await rename(tempFile, sessionFile); + } catch (error) { + await handle?.close().catch(() => void 0); + await rm(tempFile, { force: true }).catch(() => void 0); + throw error; + } } async function clearCliSession(input) { const env = input.env ?? process.env; @@ -2635,7 +2655,7 @@ init_config(); // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/mere-run.ts import { createReadStream, createWriteStream, existsSync, mkdirSync } from "node:fs"; -import { access, chmod as chmod2, mkdtemp, rm as rm2 } from "node:fs/promises"; +import { access, chmod, mkdtemp, rm as rm2 } from "node:fs/promises"; import { createHash as createHash3 } from "node:crypto"; import https from "node:https"; import os3 from "node:os"; @@ -2749,7 +2769,7 @@ async function installFromDmg(env, appId) { if (install.status !== 0) { throw new Error(install.stderr || install.stdout || "mere.run installer failed."); } - await chmod2(installBin, 493).catch(() => void 0); + await chmod(installBin, 493).catch(() => void 0); return installBin; } finally { await rm2(tmp, { recursive: true, force: true }); @@ -4318,7 +4338,7 @@ async function handleLocalExport(parsed, io) { if (output) { const target = resolve(output); await mkdir3(dirname(target), { recursive: true }); - await writeFile2(target, JSON.stringify(bundle, null, 2)); + await writeFile(target, JSON.stringify(bundle, null, 2)); return { ok: true, path: target, @@ -4630,7 +4650,7 @@ async function saveResponse(response, outputPath, fallbackFilename) { const filename = basename(filenameFromDisposition(response.headers.get("content-disposition")) ?? fallbackFilename); const target = resolve(outputPath ?? filename); await mkdir3(dirname(target), { recursive: true }); - await writeFile2(target, bytes); + await writeFile(target, bytes); return { path: target, filename, diff --git a/adapters/today/run.js b/adapters/today/run.js index ca9644b..f1b0d04 100755 --- a/adapters/today/run.js +++ b/adapters/today/run.js @@ -205,7 +205,8 @@ var CLI_AUTH_ERROR_QUERY_PARAM = "error"; var CLI_AUTH_ERROR_DESCRIPTION_QUERY_PARAM = "error_description"; // node_modules/.pnpm/@mere+cli-auth@file+..+business+packages+cli-auth_@sveltejs+kit@2.57.1_@sveltejs+vite-p_a16694d82befbc5a365d1bd249c9e389/node_modules/@mere/cli-auth/src/session.ts -import { chmod, mkdir, readFile, rm, writeFile } from "node:fs/promises"; +import { randomUUID } from "node:crypto"; +import { mkdir, open, readFile, rename, rm } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; function stateHome(env) { @@ -249,10 +250,29 @@ async function loadCliSession(input) { } async function saveCliSession(input) { const paths = resolveCliPaths(input.appName, input.env ?? process.env); - await mkdir(paths.stateDir, { recursive: true }); - await writeFile(paths.sessionFile, `${JSON.stringify(input.session, null, 2)} + await writeCliSessionFile(paths.sessionFile, input.session); +} +async function writeCliSessionFile(sessionFile, session) { + const stateDir = path.dirname(sessionFile); + const tempFile = path.join( + stateDir, + `.${path.basename(sessionFile)}.${process.pid}.${randomUUID()}.tmp` + ); + let handle; + await mkdir(stateDir, { recursive: true }); + try { + handle = await open(tempFile, "wx", 384); + await handle.writeFile(`${JSON.stringify(session, null, 2)} `, "utf8"); - await chmod(paths.sessionFile, 384).catch(() => void 0); + await handle.sync(); + await handle.close(); + handle = void 0; + await rename(tempFile, sessionFile); + } catch (error) { + await handle?.close().catch(() => void 0); + await rm(tempFile, { force: true }).catch(() => void 0); + throw error; + } } async function clearCliSession(input) { const env = input.env ?? process.env; @@ -2433,7 +2453,7 @@ async function handleDbCommand(context, action, parsed) { } // scripts/cli/local-plane-command.ts -import { mkdir as mkdir3, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises"; +import { mkdir as mkdir3, readFile as readFile2, writeFile } from "node:fs/promises"; import { dirname, resolve } from "node:path"; // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/config.ts @@ -2667,14 +2687,14 @@ async function deliverCloudProjectionEvent(input) { } // scripts/cli/local-store.ts -import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto"; +import { createHash as createHash2, randomUUID as randomUUID3 } from "node:crypto"; // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/index.ts import { mkdir as mkdir2 } from "node:fs/promises"; import path4 from "node:path"; // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/migration.ts -import { createHash, randomUUID } from "node:crypto"; +import { createHash, randomUUID as randomUUID2 } from "node:crypto"; var PLANE_TRANSFER_KIND = "mere.local-plane.transfer"; var PLANE_TRANSFER_VERSION = 1; function isRecord(value) { @@ -2810,7 +2830,7 @@ function createPlaneTransferImportPlan(input) { }; } function recordPlaneTransfer(db, input) { - const id = `xfer_${randomUUID().replaceAll("-", "").slice(0, 24)}`; + const id = `xfer_${randomUUID2().replaceAll("-", "").slice(0, 24)}`; db.prepare( `INSERT INTO mere_plane_transfers ( id, app_id, workspace_id, direction, @@ -3160,7 +3180,7 @@ function isoNow4() { return (/* @__PURE__ */ new Date()).toISOString(); } function makeId2(prefix) { - return `${prefix}_${randomUUID2().replaceAll("-", "").slice(0, 16)}`; + return `${prefix}_${randomUUID3().replaceAll("-", "").slice(0, 16)}`; } function stableTimeReportProjectionId(input) { const digest = createHash2("sha256").update(TODAY_APP_ID).update("\0").update(input.workspaceId).update("\0").update(input.from).update("\0").update(input.to).update("\0").update(input.projectId ?? "").digest("hex").slice(0, 24); @@ -3823,7 +3843,7 @@ async function handleLocalPlaneCommand(parsed, env, writers) { if (!output) return bundle; const target = resolve(output); await mkdir3(dirname(target), { recursive: true }); - await writeFile2(target, JSON.stringify(bundle, null, 2)); + await writeFile(target, JSON.stringify(bundle, null, 2)); return { ok: true, path: target, diff --git a/adapters/video/run.js b/adapters/video/run.js index 2949bb0..d669fa1 100755 --- a/adapters/video/run.js +++ b/adapters/video/run.js @@ -790,7 +790,7 @@ function resolveDeepgramSpeechConfig(env) { } // cli/meets.ts -import { mkdir as mkdir4, readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises"; +import { mkdir as mkdir4, readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises"; import { dirname as dirname2, resolve as resolvePath2 } from "node:path"; // cli/meeting-host.ts @@ -1226,7 +1226,8 @@ var CLI_AUTH_ERROR_QUERY_PARAM = "error"; var CLI_AUTH_ERROR_DESCRIPTION_QUERY_PARAM = "error_description"; // node_modules/.pnpm/@mere+cli-auth@file+..+business+packages+cli-auth_@sveltejs+kit@2.59.1_@sveltejs+vite-p_7aa3aaab13578c3c596ccc406619ca6b/node_modules/@mere/cli-auth/src/session.ts -import { chmod, mkdir, readFile, rm, writeFile } from "node:fs/promises"; +import { randomUUID } from "node:crypto"; +import { mkdir, open, readFile, rename, rm } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; function stateHome(env) { @@ -1270,10 +1271,29 @@ async function loadCliSession(input) { } async function saveCliSession(input) { const paths = resolveCliPaths(input.appName, input.env ?? process.env); - await mkdir(paths.stateDir, { recursive: true }); - await writeFile(paths.sessionFile, `${JSON.stringify(input.session, null, 2)} + await writeCliSessionFile(paths.sessionFile, input.session); +} +async function writeCliSessionFile(sessionFile, session) { + const stateDir = path.dirname(sessionFile); + const tempFile = path.join( + stateDir, + `.${path.basename(sessionFile)}.${process.pid}.${randomUUID()}.tmp` + ); + let handle; + await mkdir(stateDir, { recursive: true }); + try { + handle = await open(tempFile, "wx", 384); + await handle.writeFile(`${JSON.stringify(session, null, 2)} `, "utf8"); - await chmod(paths.sessionFile, 384).catch(() => void 0); + await handle.sync(); + await handle.close(); + handle = void 0; + await rename(tempFile, sessionFile); + } catch (error) { + await handle?.close().catch(() => void 0); + await rm(tempFile, { force: true }).catch(() => void 0); + throw error; + } } async function clearCliSession(input) { const env = input.env ?? process.env; @@ -1835,7 +1855,7 @@ function formatDuration(seconds) { } // cli/local-plane.ts -import { mkdir as mkdir3, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises"; +import { mkdir as mkdir3, readFile as readFile2, writeFile } from "node:fs/promises"; import { dirname, resolve as resolvePath } from "node:path"; // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/config.ts @@ -2074,7 +2094,7 @@ import { mkdir as mkdir2 } from "node:fs/promises"; import path3 from "node:path"; // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/migration.ts -import { createHash, randomUUID } from "node:crypto"; +import { createHash, randomUUID as randomUUID2 } from "node:crypto"; var PLANE_TRANSFER_KIND = "mere.local-plane.transfer"; var PLANE_TRANSFER_VERSION = 1; function isRecord2(value) { @@ -2210,7 +2230,7 @@ function createPlaneTransferImportPlan(input) { }; } function recordPlaneTransfer(db, input) { - const id = `xfer_${randomUUID().replaceAll("-", "").slice(0, 24)}`; + const id = `xfer_${randomUUID2().replaceAll("-", "").slice(0, 24)}`; db.prepare( `INSERT INTO mere_plane_transfers ( id, app_id, workspace_id, direction, @@ -3362,7 +3382,7 @@ async function handleLocalExport(globalOptions, options, io) { if (!output) return bundle; const target = resolvePath(output); await mkdir3(dirname(target), { recursive: true }); - await writeFile2(target, JSON.stringify(bundle, null, 2)); + await writeFile(target, JSON.stringify(bundle, null, 2)); return { ok: true, path: target, @@ -3491,7 +3511,7 @@ async function handleLocalTranscripts(action, globalOptions, options, positional if (!output) return text; const target = resolvePath(output); await mkdir3(dirname(target), { recursive: true }); - await writeFile2(target, text); + await writeFile(target, text); return { ok: true, meetingId, output: target, format }; } throw new Error("Unknown local transcripts action: expected list, export, or upsert."); @@ -3902,7 +3922,7 @@ function writeResult(io, value) { async function writeBytesFile(pathname, bytes) { const target = resolvePath2(pathname); await mkdir4(dirname2(target), { recursive: true }); - await writeFile3(target, bytes); + await writeFile2(target, bytes); return target; } async function writeTextFile(pathname, text) { diff --git a/adapters/works/run.js b/adapters/works/run.js index 9d67201..84dd70d 100755 --- a/adapters/works/run.js +++ b/adapters/works/run.js @@ -6,7 +6,8 @@ import { readFile as readFile3 } from "node:fs/promises"; import { pathToFileURL } from "node:url"; // node_modules/.pnpm/@mere+cli-auth@file+..+business+packages+cli-auth_@sveltejs+kit@2.55.0_@sveltejs+vite-p_221c0030a2ec2a854d90979ee5b3cc68/node_modules/@mere/cli-auth/src/session.ts -import { chmod, mkdir, readFile, rm, writeFile } from "node:fs/promises"; +import { randomUUID } from "node:crypto"; +import { mkdir, open, readFile, rename, rm } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; function stateHome(env) { @@ -50,10 +51,29 @@ async function loadCliSession(input) { } async function saveCliSession(input) { const paths = resolveCliPaths(input.appName, input.env ?? process.env); - await mkdir(paths.stateDir, { recursive: true }); - await writeFile(paths.sessionFile, `${JSON.stringify(input.session, null, 2)} + await writeCliSessionFile(paths.sessionFile, input.session); +} +async function writeCliSessionFile(sessionFile, session) { + const stateDir = path.dirname(sessionFile); + const tempFile = path.join( + stateDir, + `.${path.basename(sessionFile)}.${process.pid}.${randomUUID()}.tmp` + ); + let handle; + await mkdir(stateDir, { recursive: true }); + try { + handle = await open(tempFile, "wx", 384); + await handle.writeFile(`${JSON.stringify(session, null, 2)} `, "utf8"); - await chmod(paths.sessionFile, 384).catch(() => void 0); + await handle.sync(); + await handle.close(); + handle = void 0; + await rename(tempFile, sessionFile); + } catch (error) { + await handle?.close().catch(() => void 0); + await rm(tempFile, { force: true }).catch(() => void 0); + throw error; + } } async function clearCliSession(input) { const env = input.env ?? process.env; @@ -330,7 +350,7 @@ async function logoutRemote(input = {}) { } // cli/local-plane.ts -import { mkdir as mkdir3, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises"; +import { mkdir as mkdir3, readFile as readFile2, writeFile } from "node:fs/promises"; import { dirname, resolve as resolvePath } from "node:path"; // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/config.ts @@ -568,7 +588,7 @@ import { mkdir as mkdir2 } from "node:fs/promises"; import path3 from "node:path"; // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/migration.ts -import { createHash, randomUUID } from "node:crypto"; +import { createHash, randomUUID as randomUUID2 } from "node:crypto"; var PLANE_TRANSFER_KIND = "mere.local-plane.transfer"; var PLANE_TRANSFER_VERSION = 1; function isRecord(value) { @@ -704,7 +724,7 @@ function createPlaneTransferImportPlan(input) { }; } function recordPlaneTransfer(db, input) { - const id = `xfer_${randomUUID().replaceAll("-", "").slice(0, 24)}`; + const id = `xfer_${randomUUID2().replaceAll("-", "").slice(0, 24)}`; db.prepare( `INSERT INTO mere_plane_transfers ( id, app_id, workspace_id, direction, @@ -1643,7 +1663,7 @@ async function handleLocalExport(options, io) { if (!output) return bundle; const target = resolvePath(output); await mkdir3(dirname(target), { recursive: true }); - await writeFile2(target, JSON.stringify(bundle, null, 2)); + await writeFile(target, JSON.stringify(bundle, null, 2)); return { ok: true, path: target, diff --git a/adapters/zone/run.js b/adapters/zone/run.js index 7520194..6180d01 100755 --- a/adapters/zone/run.js +++ b/adapters/zone/run.js @@ -4,7 +4,8 @@ import { readFile as readFile3 } from "node:fs/promises"; // node_modules/.pnpm/@mere+cli-auth@file+..+business+packages+cli-auth_@sveltejs+kit@2.59.1_@sveltejs+vite-p_3010e55f7f1bc76b1ba4a1cb874e4024/node_modules/@mere/cli-auth/src/session.ts -import { chmod, mkdir, readFile, rm, writeFile } from "node:fs/promises"; +import { randomUUID } from "node:crypto"; +import { mkdir, open, readFile, rename, rm } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; function stateHome(env) { @@ -48,10 +49,29 @@ async function loadCliSession(input) { } async function saveCliSession(input) { const paths = resolveCliPaths(input.appName, input.env ?? process.env); - await mkdir(paths.stateDir, { recursive: true }); - await writeFile(paths.sessionFile, `${JSON.stringify(input.session, null, 2)} + await writeCliSessionFile(paths.sessionFile, input.session); +} +async function writeCliSessionFile(sessionFile, session) { + const stateDir = path.dirname(sessionFile); + const tempFile = path.join( + stateDir, + `.${path.basename(sessionFile)}.${process.pid}.${randomUUID()}.tmp` + ); + let handle; + await mkdir(stateDir, { recursive: true }); + try { + handle = await open(tempFile, "wx", 384); + await handle.writeFile(`${JSON.stringify(session, null, 2)} `, "utf8"); - await chmod(paths.sessionFile, 384).catch(() => void 0); + await handle.sync(); + await handle.close(); + handle = void 0; + await rename(tempFile, sessionFile); + } catch (error) { + await handle?.close().catch(() => void 0); + await rm(tempFile, { force: true }).catch(() => void 0); + throw error; + } } async function clearCliSession(input) { const env = input.env ?? process.env; @@ -328,7 +348,7 @@ async function logoutRemote(input = {}) { } // cli/local-plane.ts -import { mkdir as mkdir3, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises"; +import { mkdir as mkdir3, readFile as readFile2, writeFile } from "node:fs/promises"; import { dirname, resolve as resolvePath } from "node:path"; // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/config.ts @@ -569,7 +589,7 @@ import { mkdir as mkdir2 } from "node:fs/promises"; import path3 from "node:path"; // node_modules/.pnpm/@mere+local-plane@file+..+business+packages+local-plane/node_modules/@mere/local-plane/src/migration.ts -import { createHash, randomUUID } from "node:crypto"; +import { createHash, randomUUID as randomUUID2 } from "node:crypto"; var PLANE_TRANSFER_KIND = "mere.local-plane.transfer"; var PLANE_TRANSFER_VERSION = 1; function isRecord(value) { @@ -705,7 +725,7 @@ function createPlaneTransferImportPlan(input) { }; } function recordPlaneTransfer(db, input) { - const id = `xfer_${randomUUID().replaceAll("-", "").slice(0, 24)}`; + const id = `xfer_${randomUUID2().replaceAll("-", "").slice(0, 24)}`; db.prepare( `INSERT INTO mere_plane_transfers ( id, app_id, workspace_id, direction, @@ -1920,7 +1940,7 @@ async function handleLocalExport(globalOptions, options, io) { if (!output) return bundle; const target = resolvePath(output); await mkdir3(dirname(target), { recursive: true }); - await writeFile2(target, JSON.stringify(bundle, null, 2)); + await writeFile(target, JSON.stringify(bundle, null, 2)); return { ok: true, path: target, diff --git a/docs/release-checklist.md b/docs/release-checklist.md index 952a7dc..09dc6d3 100644 --- a/docs/release-checklist.md +++ b/docs/release-checklist.md @@ -49,6 +49,7 @@ npm audit signatures --package-lock-only --ignore-scripts - Confirm `SECURITY.md` still describes the adapter/API-shape model. - Set `MERE_ROOT=/path/to/mere-sibling-repositories` and provide a read-only `GH_TOKEN` that can read each source repository, pull-request reviews, and checks. Run `pnpm build:adapters:release`; do not promote a development-mode adapter build. +- Solo-maintainer exception: when non-author review is temporarily unavailable, set `ADAPTER_RELEASE_REVIEW_POLICY=canonical-main`. This remains a release build and still requires clean canonical remotes, exact live `main` heads, deterministic byte-identical double builds, complete artifact hashes, machine-path and credential scans, and source revalidation. The manifest records `reviewPolicy: canonical-main` and null review evidence so the missing human gate is explicit. Restore the default `reviewed-merge` policy when a second reviewer is available. - Confirm every adapter source is a clean checkout of the live canonical `main` head. Release mode rejects dirty trees, unmerged paths, local or stale heads, draft/unmerged pull requests, direct commits without exact review evidence, stale/author-only approvals, and pending or red checks. - Review `adapters/manifest.json` schema v2. Every entry must bind the canonical source URL, exact commit and tree, clean/default-branch/review evidence, deterministic commands and toolchain, complete artifact SHA-256/size inventory, and Mere Console Contract v1 schema/fixture digests when present. - Confirm release mode completed two builds with the same `SOURCE_DATE_EPOCH` and installed the bundle only after byte-for-byte inventory comparison. Then rerun `pnpm check:adapter-provenance` independently. diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 32054b7..6e4e782 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "@merekit/cli", - "version": "0.5.17", + "version": "0.5.18", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@merekit/cli", - "version": "0.5.17", + "version": "0.5.18", "license": "Apache-2.0", "dependencies": { "@modelcontextprotocol/sdk": "1.29.0", diff --git a/package.json b/package.json index cdf97a4..92329b0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@merekit/cli", - "version": "0.5.17", + "version": "0.5.18", "description": "Public Mere command plane with waitlist and invite onboarding, bundled app adapters, agent context packs, audits, and MCP access.", "private": false, "license": "Apache-2.0", diff --git a/scripts/adapter-provenance-lib.mjs b/scripts/adapter-provenance-lib.mjs index b06250c..76356f6 100644 --- a/scripts/adapter-provenance-lib.mjs +++ b/scripts/adapter-provenance-lib.mjs @@ -291,13 +291,15 @@ export async function inspectSourceRepository(options) { if (commit !== remoteHead) { throw new Error(`${options.app} source ${commit} is not the live canonical ${options.defaultBranch} head ${remoteHead}; draft, unmerged, ahead, and stale inputs are refused.`); } - review = await verifyGitHubReviewEvidence({ - canonicalRepository, - commit, - defaultBranch: options.defaultBranch, - token: options.githubToken, - fetchImpl: options.fetchImpl - }); + if (options.reviewPolicy !== 'canonical-main') { + review = await verifyGitHubReviewEvidence({ + canonicalRepository, + commit, + defaultBranch: options.defaultBranch, + token: options.githubToken, + fetchImpl: options.fetchImpl + }); + } } const commitTimestamp = Number(run('git', ['show', '-s', '--format=%ct', commit], { cwd: options.repoPath })); @@ -350,6 +352,9 @@ export async function verifyAdapterManifest(options) { } if (options.release) { if (manifest.mode !== 'release') throw new Error('Adapter provenance manifest must come from release mode.'); + if (!['reviewed-merge', 'canonical-main'].includes(manifest.reviewPolicy)) { + throw new Error('Adapter provenance release review policy is missing or invalid.'); + } if (manifest.reproducibility?.passes !== 2 || manifest.reproducibility?.byteIdentical !== true || manifest.reproducibility?.algorithm !== 'sha256-file-inventory-v1' || manifest.reproducibility?.machinePathScan !== true || manifest.reproducibility?.credentialScan !== true @@ -392,30 +397,34 @@ export async function verifyAdapterManifest(options) { throw new Error(`${entry.app} source is not clean and bound to its canonical default branch head.`); } if (entry.source.remoteHeadEvidence !== 'live-ls-remote') throw new Error(`${entry.app} source lacks live canonical remote evidence.`); - assertObject(entry.source.review, `${entry.app}.source.review`); - if (!Array.isArray(entry.source.review.approvedBy) || entry.source.review.approvedBy.length === 0) { - throw new Error(`${entry.app} source review approval evidence is missing.`); - } - if (!Number.isSafeInteger(entry.source.review.pullRequestNumber) || entry.source.review.pullRequestNumber < 1 - || !COMMIT_PATTERN.test(entry.source.review.pullRequestHeadCommit ?? '') - || typeof entry.source.review.pullRequest !== 'string' - || !entry.source.review.pullRequest.startsWith(expectedRepository.replace(/\.git$/u, '/pull/'))) { - throw new Error(`${entry.app} source pull-request evidence is invalid.`); - } - if (!entry.source.review.pullRequest.endsWith(`/pull/${entry.source.review.pullRequestNumber}`) - || !Number.isFinite(Date.parse(entry.source.review.mergedAt ?? '')) - || entry.source.review.approvedBy.some((reviewer) => typeof reviewer !== 'string' || !reviewer) - || canonicalJson(entry.source.review.approvedBy) !== canonicalJson([...new Set(entry.source.review.approvedBy)].sort())) { - throw new Error(`${entry.app} source pull-request review details are invalid or non-canonical.`); - } - if (!Array.isArray(entry.source.review.checks) || entry.source.review.checks.length === 0 - || entry.source.review.checks.some((check) => check?.conclusion !== 'success' && check?.conclusion !== 'neutral' && check?.conclusion !== 'skipped') - || !entry.source.review.checks.some((check) => check?.conclusion === 'success')) { - throw new Error(`${entry.app} source green-check evidence is invalid.`); - } - assertHash(entry.source.review.checksSha256, `${entry.app}.source.review.checksSha256`); - if (entry.source.review.checksSha256 !== sha256(canonicalJson(entry.source.review.checks))) { - throw new Error(`${entry.app} source check digest does not match its check inventory.`); + if (manifest.reviewPolicy === 'reviewed-merge') { + assertObject(entry.source.review, `${entry.app}.source.review`); + if (!Array.isArray(entry.source.review.approvedBy) || entry.source.review.approvedBy.length === 0) { + throw new Error(`${entry.app} source review approval evidence is missing.`); + } + if (!Number.isSafeInteger(entry.source.review.pullRequestNumber) || entry.source.review.pullRequestNumber < 1 + || !COMMIT_PATTERN.test(entry.source.review.pullRequestHeadCommit ?? '') + || typeof entry.source.review.pullRequest !== 'string' + || !entry.source.review.pullRequest.startsWith(expectedRepository.replace(/\.git$/u, '/pull/'))) { + throw new Error(`${entry.app} source pull-request evidence is invalid.`); + } + if (!entry.source.review.pullRequest.endsWith(`/pull/${entry.source.review.pullRequestNumber}`) + || !Number.isFinite(Date.parse(entry.source.review.mergedAt ?? '')) + || entry.source.review.approvedBy.some((reviewer) => typeof reviewer !== 'string' || !reviewer) + || canonicalJson(entry.source.review.approvedBy) !== canonicalJson([...new Set(entry.source.review.approvedBy)].sort())) { + throw new Error(`${entry.app} source pull-request review details are invalid or non-canonical.`); + } + if (!Array.isArray(entry.source.review.checks) || entry.source.review.checks.length === 0 + || entry.source.review.checks.some((check) => check?.conclusion !== 'success' && check?.conclusion !== 'neutral' && check?.conclusion !== 'skipped') + || !entry.source.review.checks.some((check) => check?.conclusion === 'success')) { + throw new Error(`${entry.app} source green-check evidence is invalid.`); + } + assertHash(entry.source.review.checksSha256, `${entry.app}.source.review.checksSha256`); + if (entry.source.review.checksSha256 !== sha256(canonicalJson(entry.source.review.checks))) { + throw new Error(`${entry.app} source check digest does not match its check inventory.`); + } + } else if (entry.source.review !== null) { + throw new Error(`${entry.app} canonical-main releases must record review evidence as null.`); } } assertObject(entry.build, `${entry.app}.build`); diff --git a/scripts/build-adapters.mjs b/scripts/build-adapters.mjs index fc15101..dec5ec5 100644 --- a/scripts/build-adapters.mjs +++ b/scripts/build-adapters.mjs @@ -1,6 +1,6 @@ import { spawnSync } from 'node:child_process'; -import { existsSync } from 'node:fs'; -import { chmod, copyFile, cp, lstat, mkdir, mkdtemp, readFile, readdir, realpath, rm, writeFile } from 'node:fs/promises'; +import { existsSync, realpathSync } from 'node:fs'; +import { chmod, copyFile, cp, lstat, mkdir, mkdtemp, readFile, readdir, realpath, rm, symlink, writeFile } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -36,10 +36,14 @@ function parseMode(argv) { const mode = parseMode(process.argv.slice(2)); const release = mode === 'release'; +const reviewPolicy = release ? (process.env.ADAPTER_RELEASE_REVIEW_POLICY?.trim() || 'reviewed-merge') : 'development'; +if (!['development', 'reviewed-merge', 'canonical-main'].includes(reviewPolicy)) { + throw new Error(`ADAPTER_RELEASE_REVIEW_POLICY must be reviewed-merge or canonical-main, got ${reviewPolicy}.`); +} if (sourceConfig.schemaVersion !== 1 || sourceConfig.defaultBranch !== 'main' || !sourceConfig.sources) { throw new Error('scripts/adapter-sources.json must be the reviewed schema v1 source map for main.'); } -if (release && !String(process.env.GH_TOKEN ?? '').trim()) { +if (release && reviewPolicy === 'reviewed-merge' && !String(process.env.GH_TOKEN ?? '').trim()) { throw new Error('Release adapter builds require GH_TOKEN for exact merged-PR, approval, and CI evidence.'); } if (release && String(process.env.PNPM_BIN ?? '').trim()) { @@ -82,7 +86,7 @@ Access is enforced by the Mere services through browser sessions, bearer tokens, Adapter manifests must mark command risk honestly as \`read\`, \`write\`, \`destructive\`, or \`external\`. Destructive commands must require explicit confirmation. -Maintainers can use \`pnpm build:adapters\` for a development snapshot. Public-release inputs must use \`pnpm build:adapters:release\`, which requires clean canonical default-branch sources, exact non-author review and green-CI evidence, and a byte-identical two-pass rebuild. +Maintainers can use \`pnpm build:adapters\` for a development snapshot. Public-release inputs must use \`pnpm build:adapters:release\`, which requires clean canonical default-branch sources and a byte-identical two-pass rebuild. The default \`reviewed-merge\` policy also requires exact non-author review and green-CI evidence; the documented \`canonical-main\` solo-maintainer exception records that review evidence is unavailable without weakening source, reproducibility, hash, path, or credential checks. `; } @@ -229,7 +233,7 @@ function gitTracks(repoPath, absolutePath) { async function prepareGeneratedSourceOutput(definition, sourceEvidence) { if (sourceEvidence.sourceArtifactTracked) return; const generatedPath = definition.copyDirectory ? path.dirname(definition.sourceArtifactPath) : definition.sourceArtifactPath; - await rm(generatedPath, { recursive: definition.copyDirectory, force: true }); + await rm(generatedPath, { recursive: definition.copyDirectory === true, force: true }); } async function assertPathInsideSource(repoPath, candidate, label) { @@ -338,10 +342,16 @@ async function copyAdapter(definition, outputRoot) { function validateAdapter(key, target, env) { const options = { capture: true, env }; - const version = run(process.execPath, [target, '--version'], options); - if (!version.stdout.trim()) throw new Error(`${key} adapter did not print a version.`); - run(process.execPath, [target, 'completion', 'bash'], options); - const manifest = run(process.execPath, [target, 'commands', '--json'], options); + // macOS exposes temporary files through both /var and /private/var. Some + // adapters intentionally compare import.meta.url with process.argv[1], so + // execute the canonical path or their direct-entry guard will not run. + const executableTarget = realpathSync(target); + const version = run(process.execPath, [executableTarget, '--version'], options); + if (!version.stdout.trim()) { + throw new Error(`${key} adapter did not print a version.${version.stderr.trim() ? ` ${version.stderr.trim()}` : ''}`); + } + run(process.execPath, [executableTarget, 'completion', 'bash'], options); + const manifest = run(process.execPath, [executableTarget, 'commands', '--json'], options); try { JSON.parse(manifest.stdout); } catch (error) { @@ -360,6 +370,7 @@ async function inspectSources() { canonicalRepository: sourceConfig.sources[definition.key], defaultBranch: sourceConfig.defaultBranch, release, + reviewPolicy, githubToken: process.env.GH_TOKEN }); evidence.set(definition.key, { @@ -402,6 +413,7 @@ async function revalidateReleaseSources(evidence) { canonicalRepository: sourceConfig.sources[definition.key], defaultBranch: sourceConfig.defaultBranch, release: true, + reviewPolicy, githubToken: process.env.GH_TOKEN }); if (current.commit !== expected.commit || current.tree !== expected.tree) { @@ -452,6 +464,7 @@ async function buildPass(outputRoot, context) { const manifest = { schemaVersion: ADAPTER_MANIFEST_SCHEMA_VERSION, mode, + reviewPolicy, builtAt: context.builtAt, sourceDateEpoch: context.sourceDateEpoch, sourceMapSha256: sha256(canonicalJson(sourceConfig.sources)), @@ -519,6 +532,10 @@ const temporaryRoot = release ? await mkdtemp(path.join(tmpdir(), 'merekit-adapt if (temporaryRoot) { await mkdir(path.join(temporaryRoot, 'home'), { recursive: true }); await mkdir(path.join(temporaryRoot, 'tmp'), { recursive: true }); + // Validate adapters in the same dependency shape as the published package. + // Native/external runtime dependencies (currently sqlite-vec) live beside + // adapters after npm installation, not inside each generated adapter folder. + await symlink(path.join(packageRoot, 'node_modules'), path.join(temporaryRoot, 'node_modules'), 'dir'); } const environment = release ? { diff --git a/test/adapter-provenance.test.mjs b/test/adapter-provenance.test.mjs index b00563c..ce7aeab 100644 --- a/test/adapter-provenance.test.mjs +++ b/test/adapter-provenance.test.mjs @@ -272,6 +272,7 @@ async function writeReleaseManifestFixture(root) { const manifest = { schemaVersion: 2, mode: 'release', + reviewPolicy: 'reviewed-merge', builtAt: new Date(Number(sourceDateEpoch) * 1000).toISOString(), sourceDateEpoch, sourceMapSha256: sha256('{"example":"https://github.com/sawfwair/example.git"}'), @@ -362,6 +363,19 @@ test('release manifest gate binds canonical source evidence and every packaged b }), /does not match its recorded SHA-256, size, and mode/u); }); +test('canonical-main release policy preserves source and byte gates without inventing review evidence', async () => { + const root = await mkdtemp(path.join(os.tmpdir(), 'mere-adapter-solo-manifest-')); + const manifest = await writeReleaseManifestFixture(root); + manifest.reviewPolicy = 'canonical-main'; + manifest.adapters[0].source.review = null; + await writeFile(path.join(root, 'adapters', 'manifest.json'), `${JSON.stringify(manifest)}\n`); + await verifyAdapterManifest({ + packageRoot: root, + sources: { example: 'https://github.com/sawfwair/example.git' }, + release: true + }); +}); + test('legacy adapter manifests cannot pass the publication gate', async () => { const root = await mkdtemp(path.join(os.tmpdir(), 'mere-adapter-legacy-')); await mkdir(path.join(root, 'adapters'), { recursive: true });