diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 000000000..49dbd4cf9 --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +# Auto-format staged code with oxfmt before each commit, so the CI `format` job +# (`oxfmt --check .`) can never fail on a commit that originated here. Activated +# by `git config core.hooksPath .githooks`, which `bun run bootstrap` sets for +# every fresh checkout / agent worktree. +# +# Behaviour: formats the staged JS/TS/JSON files in place and re-stages them. +# oxfmt honours `.oxfmtrc.json` `ignorePatterns` even for explicitly-passed +# paths, so generated/vendored files (bun.lock, routeTree.gen.ts, ...) are +# skipped automatically. +# +# NUL-delimited end to end (handles spaces/newlines in paths) and compatible +# with the bash 3.2 that ships on macOS, so no `mapfile`. A shell variable +# cannot hold NUL bytes, so the staged list is read into an array directly. +# +# Caveat: a file that is only partially staged (staged hunk + a separate +# unstaged hunk in the same file) gets fully re-staged after formatting. Agent +# flows stage whole files (`git add -A`), so this is not a concern in practice. + +set -euo pipefail + +cd "$(git rev-parse --show-toplevel)" + +oxfmt="node_modules/.bin/oxfmt" +if [[ ! -x "$oxfmt" ]]; then + echo "pre-commit: oxfmt not found ($oxfmt) - run 'bun run bootstrap'; skipping format." >&2 + exit 0 +fi + +# Staged Added/Copied/Modified/Renamed files, restricted to extensions oxfmt +# formats. Read NUL records into an array (no NUL-in-variable bug). +files=() +while IFS= read -r -d '' f; do + case "$f" in + *.ts | *.tsx | *.mts | *.cts | *.js | *.jsx | *.mjs | *.cjs | *.json | *.jsonc) + files+=("$f") + ;; + esac +done < <(git diff --cached --name-only --diff-filter=ACMR -z) + +((${#files[@]})) || exit 0 + +# Format in place, then re-stage whatever oxfmt may have rewritten. +# --no-error-on-unmatched-pattern keeps the hook from failing when every staged +# file is ignored by .oxfmtrc.json. +"$oxfmt" --write --no-error-on-unmatched-pattern "${files[@]}" +git add -- "${files[@]}" diff --git a/packages/core/cli/package.json b/packages/core/cli/package.json index e9f58c766..e02474f3d 100644 --- a/packages/core/cli/package.json +++ b/packages/core/cli/package.json @@ -23,6 +23,7 @@ ".": "./src/index.ts" }, "publishConfig": { + "access": "public", "exports": { ".": { "import": { @@ -30,8 +31,7 @@ "default": "./dist/index.js" } } - }, - "access": "public" + } }, "scripts": { "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", diff --git a/packages/core/config/package.json b/packages/core/config/package.json index a2ded694a..a01b40d83 100644 --- a/packages/core/config/package.json +++ b/packages/core/config/package.json @@ -19,6 +19,7 @@ ".": "./src/index.ts" }, "publishConfig": { + "access": "public", "exports": { ".": { "import": { @@ -26,8 +27,7 @@ "default": "./dist/index.js" } } - }, - "access": "public" + } }, "scripts": { "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", diff --git a/packages/core/execution/package.json b/packages/core/execution/package.json index 4173b1c6d..88f3a0009 100644 --- a/packages/core/execution/package.json +++ b/packages/core/execution/package.json @@ -20,6 +20,7 @@ "./promise": "./src/promise.ts" }, "publishConfig": { + "access": "public", "exports": { ".": { "import": { @@ -33,8 +34,7 @@ "default": "./dist/core.js" } } - }, - "access": "public" + } }, "scripts": { "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", diff --git a/packages/core/integrations-registry/package.json b/packages/core/integrations-registry/package.json index 44456c112..26511416d 100644 --- a/packages/core/integrations-registry/package.json +++ b/packages/core/integrations-registry/package.json @@ -20,6 +20,7 @@ ".": "./src/index.ts" }, "publishConfig": { + "access": "public", "exports": { ".": { "import": { @@ -27,8 +28,7 @@ "default": "./dist/index.js" } } - }, - "access": "public" + } }, "scripts": { "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", diff --git a/packages/core/sdk/package.json b/packages/core/sdk/package.json index 1c8430712..b318481c1 100644 --- a/packages/core/sdk/package.json +++ b/packages/core/sdk/package.json @@ -28,6 +28,7 @@ "./public-origin": "./src/public-origin.ts" }, "publishConfig": { + "access": "public", "exports": { ".": { "import": { @@ -83,8 +84,7 @@ "default": "./dist/public-origin.js" } } - }, - "access": "public" + } }, "scripts": { "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", diff --git a/packages/core/vite-plugin/package.json b/packages/core/vite-plugin/package.json index d8dfac836..22aae8890 100644 --- a/packages/core/vite-plugin/package.json +++ b/packages/core/vite-plugin/package.json @@ -23,6 +23,7 @@ } }, "publishConfig": { + "access": "public", "exports": { ".": { "import": { @@ -30,8 +31,7 @@ "default": "./dist/index.js" } } - }, - "access": "public" + } }, "scripts": { "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", diff --git a/packages/kernel/core/package.json b/packages/kernel/core/package.json index 17cb18c9f..4ae6a5096 100644 --- a/packages/kernel/core/package.json +++ b/packages/kernel/core/package.json @@ -19,6 +19,7 @@ ".": "./src/index.ts" }, "publishConfig": { + "access": "public", "exports": { ".": { "import": { @@ -26,8 +27,7 @@ "default": "./dist/index.js" } } - }, - "access": "public" + } }, "scripts": { "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", diff --git a/packages/kernel/runtime-quickjs/package.json b/packages/kernel/runtime-quickjs/package.json index 0d886c180..0896805fc 100644 --- a/packages/kernel/runtime-quickjs/package.json +++ b/packages/kernel/runtime-quickjs/package.json @@ -19,6 +19,7 @@ ".": "./src/index.ts" }, "publishConfig": { + "access": "public", "exports": { ".": { "import": { @@ -26,8 +27,7 @@ "default": "./dist/index.js" } } - }, - "access": "public" + } }, "scripts": { "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", diff --git a/packages/plugins/desktop-settings/package.json b/packages/plugins/desktop-settings/package.json index cc766ff3e..b2b05839d 100644 --- a/packages/plugins/desktop-settings/package.json +++ b/packages/plugins/desktop-settings/package.json @@ -20,6 +20,7 @@ "./client": "./src/client.tsx" }, "publishConfig": { + "access": "public", "exports": { "./server": { "import": { @@ -33,8 +34,7 @@ "default": "./dist/client.js" } } - }, - "access": "public" + } }, "scripts": { "build": "tsup", diff --git a/packages/plugins/example/package.json b/packages/plugins/example/package.json index 45ebbb303..488d2ccbf 100644 --- a/packages/plugins/example/package.json +++ b/packages/plugins/example/package.json @@ -21,6 +21,7 @@ "./shared": "./src/shared.ts" }, "publishConfig": { + "access": "public", "exports": { "./server": { "import": { @@ -40,8 +41,7 @@ "default": "./dist/shared.js" } } - }, - "access": "public" + } }, "scripts": { "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", diff --git a/packages/plugins/file-secrets/package.json b/packages/plugins/file-secrets/package.json index bcfbf732a..0e02900d0 100644 --- a/packages/plugins/file-secrets/package.json +++ b/packages/plugins/file-secrets/package.json @@ -20,6 +20,7 @@ "./promise": "./src/promise.ts" }, "publishConfig": { + "access": "public", "exports": { ".": { "import": { @@ -33,8 +34,7 @@ "default": "./dist/core.js" } } - }, - "access": "public" + } }, "scripts": { "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", diff --git a/packages/plugins/google/package.json b/packages/plugins/google/package.json index ba5379814..dff35716f 100644 --- a/packages/plugins/google/package.json +++ b/packages/plugins/google/package.json @@ -23,6 +23,7 @@ "./client": "./src/react/plugin-client.tsx" }, "publishConfig": { + "access": "public", "exports": { ".": { "import": { @@ -42,8 +43,7 @@ "default": "./dist/client.js" } } - }, - "access": "public" + } }, "scripts": { "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", diff --git a/packages/plugins/graphql/package.json b/packages/plugins/graphql/package.json index d69119197..c6736d58e 100644 --- a/packages/plugins/graphql/package.json +++ b/packages/plugins/graphql/package.json @@ -25,6 +25,7 @@ "./testing": "./src/testing/index.ts" }, "publishConfig": { + "access": "public", "exports": { ".": { "import": { @@ -50,8 +51,7 @@ "default": "./dist/testing.js" } } - }, - "access": "public" + } }, "scripts": { "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", diff --git a/packages/plugins/keychain/package.json b/packages/plugins/keychain/package.json index f4160085f..2ddb7b5ca 100644 --- a/packages/plugins/keychain/package.json +++ b/packages/plugins/keychain/package.json @@ -20,6 +20,7 @@ "./promise": "./src/promise.ts" }, "publishConfig": { + "access": "public", "exports": { ".": { "import": { @@ -33,8 +34,7 @@ "default": "./dist/core.js" } } - }, - "access": "public" + } }, "scripts": { "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", diff --git a/packages/plugins/mcp/package.json b/packages/plugins/mcp/package.json index c6ee01021..2d51f5597 100644 --- a/packages/plugins/mcp/package.json +++ b/packages/plugins/mcp/package.json @@ -25,6 +25,7 @@ "./testing": "./src/testing/index.ts" }, "publishConfig": { + "access": "public", "exports": { ".": { "import": { @@ -50,8 +51,7 @@ "default": "./dist/testing.js" } } - }, - "access": "public" + } }, "scripts": { "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", diff --git a/packages/plugins/microsoft/package.json b/packages/plugins/microsoft/package.json index 45f35d5db..d3d60aed8 100644 --- a/packages/plugins/microsoft/package.json +++ b/packages/plugins/microsoft/package.json @@ -23,6 +23,7 @@ "./client": "./src/react/plugin-client.tsx" }, "publishConfig": { + "access": "public", "exports": { ".": { "import": { @@ -42,8 +43,7 @@ "default": "./dist/client.js" } } - }, - "access": "public" + } }, "scripts": { "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", diff --git a/packages/plugins/onepassword/package.json b/packages/plugins/onepassword/package.json index c30fec111..7ba86b757 100644 --- a/packages/plugins/onepassword/package.json +++ b/packages/plugins/onepassword/package.json @@ -23,6 +23,7 @@ "./client": "./src/react/plugin-client.tsx" }, "publishConfig": { + "access": "public", "exports": { ".": { "import": { @@ -42,8 +43,7 @@ "default": "./dist/client.js" } } - }, - "access": "public" + } }, "scripts": { "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", diff --git a/packages/plugins/openapi/package.json b/packages/plugins/openapi/package.json index 2602e4837..12887f36e 100644 --- a/packages/plugins/openapi/package.json +++ b/packages/plugins/openapi/package.json @@ -25,6 +25,7 @@ "./testing": "./src/testing/index.ts" }, "publishConfig": { + "access": "public", "exports": { ".": { "import": { @@ -50,8 +51,7 @@ "default": "./dist/testing.js" } } - }, - "access": "public" + } }, "scripts": { "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", diff --git a/packages/plugins/toolkits/package.json b/packages/plugins/toolkits/package.json index 2858a6d9d..880751288 100644 --- a/packages/plugins/toolkits/package.json +++ b/packages/plugins/toolkits/package.json @@ -21,6 +21,7 @@ "./shared": "./src/shared.ts" }, "publishConfig": { + "access": "public", "exports": { "./server": { "import": { @@ -40,8 +41,7 @@ "default": "./dist/shared.js" } } - }, - "access": "public" + } }, "scripts": { "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", diff --git a/packages/plugins/workos-vault/package.json b/packages/plugins/workos-vault/package.json index 191bc70ed..1f1017918 100644 --- a/packages/plugins/workos-vault/package.json +++ b/packages/plugins/workos-vault/package.json @@ -23,6 +23,7 @@ "./testing": "./src/sdk/testing.ts" }, "publishConfig": { + "access": "public", "exports": { ".": { "import": { @@ -42,8 +43,7 @@ "default": "./dist/testing.js" } } - }, - "access": "public" + } }, "scripts": { "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", diff --git a/scripts/bootstrap.ts b/scripts/bootstrap.ts index 923d868d7..347044f7f 100644 --- a/scripts/bootstrap.ts +++ b/scripts/bootstrap.ts @@ -31,4 +31,10 @@ if (!existsSync(resolve(repoRoot, "node_modules/.bin/vitest"))) { throw new Error("bootstrap: vitest missing after install — bun install likely failed"); } +// Point git at the tracked .githooks dir so the pre-commit hook auto-formats +// staged code with oxfmt. hooksPath is local config, never cloned or copied +// into worktrees, so every fresh checkout and agent worktree must re-set it; +// without it, unformatted commits slip through and CI's `format` job fails. +run("git hooks", "git", ["config", "core.hooksPath", ".githooks"]); + console.log("\n[bootstrap] done — `cd e2e && bun run test` runs the full suite.");