Merge remote-tracking branch 'origin/master' into codex/simp-session-log-representation
This commit is contained in:
8
.editorconfig
Normal file
8
.editorconfig
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Editor-side declaration of the repo's text conventions. Pairs with
|
||||||
|
# .gitattributes: that file pins what GIT produces (LF checkouts), this one
|
||||||
|
# pins what EDITORS write to disk — the one path git's filters cannot reach.
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
7
.gitattributes
vendored
Normal file
7
.gitattributes
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# The repo's canonical text form is LF, enforced at checkout too: no smudge
|
||||||
|
# boundary between working tree and repo, so byte-level gates (verify-*
|
||||||
|
# comparisons, blob hashing, coverage offsets) see one form on every host.
|
||||||
|
# If a file class ever genuinely needs CRLF in the working tree (.bat/.cmd
|
||||||
|
# for cmd.exe), add a `*.bat text eol=crlf` override AFTER this line — the
|
||||||
|
# in-repo form stays LF; CRLF becomes checkout-time presentation only.
|
||||||
|
* text=auto eol=lf
|
||||||
25
.github/workflows/ci.yml
vendored
25
.github/workflows/ci.yml
vendored
@@ -160,6 +160,29 @@ jobs:
|
|||||||
- name: Run complete keyless Python suite
|
- name: Run complete keyless Python suite
|
||||||
run: uv run --python 3.10 --group test --project python/sdk pytest
|
run: uv run --python 3.10 --group test --project python/sdk pytest
|
||||||
|
|
||||||
|
# Windows build lane: install + `pnpm run build` (tsc -b + tsdown) on native
|
||||||
|
# Windows. Windows path/shell support is still partial, so this lane covers
|
||||||
|
# the build surface only — tests and gates are not run here yet. Wired into
|
||||||
|
# all-checks-passed so a native-Windows build regression cannot land silently.
|
||||||
|
windows-build:
|
||||||
|
runs-on: windows-2025
|
||||||
|
name: windows / build
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v6
|
||||||
|
with:
|
||||||
|
node-version: ${{ env.PRIMARY_NODE_VERSION }}
|
||||||
|
|
||||||
|
- name: Enable corepack (pnpm)
|
||||||
|
run: corepack enable
|
||||||
|
|
||||||
|
- name: Install (immutable)
|
||||||
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Build (tsc -b + tsdown)
|
||||||
|
run: pnpm run build
|
||||||
|
|
||||||
# Single stable required check for branch protection: require "all checks
|
# Single stable required check for branch protection: require "all checks
|
||||||
# passed" instead of enumerating matrix legs whose names change as lanes and
|
# passed" instead of enumerating matrix legs whose names change as lanes and
|
||||||
# node versions evolve. Every other job in THIS workflow must be listed in
|
# node versions evolve. Every other job in THIS workflow must be listed in
|
||||||
@@ -171,7 +194,7 @@ jobs:
|
|||||||
all-checks-passed:
|
all-checks-passed:
|
||||||
name: all checks passed
|
name: all checks passed
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [node-24, node-compat, python-sdk]
|
needs: [node-24, node-compat, python-sdk, windows-build]
|
||||||
if: always()
|
if: always()
|
||||||
steps:
|
steps:
|
||||||
- name: Fail if any needed job did not succeed
|
- name: Fail if any needed job did not succeed
|
||||||
|
|||||||
@@ -125,7 +125,12 @@ try {
|
|||||||
})
|
})
|
||||||
|
|
||||||
try {
|
try {
|
||||||
execFileSync('node_modules/.bin/tsc', ['-b', join(tmp, 'tsconfig.json')], { cwd: root, stdio: 'pipe' })
|
// tsc's JS entry via the current node, not the .bin shim: the extensionless
|
||||||
|
// shim is not spawnable on Windows (the CVE-2024-27980 class the sibling
|
||||||
|
// scripts hit), and the .cmd variant would need shell:true, which
|
||||||
|
// concatenates args UNESCAPED — a hazard for the temp project path. The JS
|
||||||
|
// entry behaves identically on every platform.
|
||||||
|
execFileSync(process.execPath, ['node_modules/typescript/bin/tsc', '-b', join(tmp, 'tsconfig.json')], { cwd: root, stdio: 'pipe' })
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
const failed = error as { stdout?: Buffer; stderr?: Buffer }
|
const failed = error as { stdout?: Buffer; stderr?: Buffer }
|
||||||
const out = `${failed.stdout?.toString() ?? ''}${failed.stderr?.toString() ?? ''}`
|
const out = `${failed.stdout?.toString() ?? ''}${failed.stderr?.toString() ?? ''}`
|
||||||
|
|||||||
@@ -6,8 +6,16 @@ import { join } from 'node:path'
|
|||||||
const git = spawnSync('git', ['rev-parse', '--git-dir'], { stdio: 'ignore' })
|
const git = spawnSync('git', ['rev-parse', '--git-dir'], { stdio: 'ignore' })
|
||||||
if (git.status !== 0) process.exit(0)
|
if (git.status !== 0) process.exit(0)
|
||||||
|
|
||||||
const lefthook = join(process.cwd(), 'node_modules', '.bin', process.platform === 'win32' ? 'lefthook.cmd' : 'lefthook')
|
const isWindows = process.platform === 'win32'
|
||||||
|
const lefthook = join(process.cwd(), 'node_modules', '.bin', isWindows ? 'lefthook.cmd' : 'lefthook')
|
||||||
if (!existsSync(lefthook)) process.exit(0)
|
if (!existsSync(lefthook)) process.exit(0)
|
||||||
|
|
||||||
const result = spawnSync(lefthook, ['install', '--force'], { stdio: 'inherit' })
|
// On Windows the bin shim is a `.cmd` file, and recent Node (CVE-2024-27980)
|
||||||
|
// refuses to launch `.cmd`/`.bat` via spawn without `shell: true` — it returns
|
||||||
|
// `EINVAL` with a null status, which would otherwise fail postinstall. Quote
|
||||||
|
// the path because a shell re-parses the command line and the path may contain
|
||||||
|
// spaces. POSIX needs no shell: the extensionless shim is directly executable.
|
||||||
|
const result = isWindows
|
||||||
|
? spawnSync(`"${lefthook}"`, ['install', '--force'], { stdio: 'inherit', shell: true })
|
||||||
|
: spawnSync(lefthook, ['install', '--force'], { stdio: 'inherit' })
|
||||||
process.exit(result.status ?? 1)
|
process.exit(result.status ?? 1)
|
||||||
|
|||||||
@@ -12,6 +12,13 @@ const CONCURRENCY_ENV = 'DSH_PUBLINT_CONCURRENCY'
|
|||||||
const root = resolve(import.meta.dirname, '..')
|
const root = resolve(import.meta.dirname, '..')
|
||||||
const packagesRoot = resolve(root, 'packages')
|
const packagesRoot = resolve(root, 'packages')
|
||||||
|
|
||||||
|
// Run publint's JS CLI through the current node, not the .bin shim: the
|
||||||
|
// extensionless shim isn't spawnable on Windows (CVE-2024-27980) and the .cmd
|
||||||
|
// variant needs shell:true, which space-joins args UNESCAPED (DEP0190) and
|
||||||
|
// breaks when the repo path contains spaces. The JS entry is identical on every
|
||||||
|
// platform (`bin` is `./src/cli.js` per publint's package.json).
|
||||||
|
const publintCli = resolve(root, 'node_modules/publint/src/cli.js')
|
||||||
|
|
||||||
type PublintResult =
|
type PublintResult =
|
||||||
| { path: string; status: 'passed'; stdout: string; stderr: string }
|
| { path: string; status: 'passed'; stdout: string; stderr: string }
|
||||||
| { path: string; status: 'failed'; stdout: string; stderr: string; message: string }
|
| { path: string; status: 'failed'; stdout: string; stderr: string; message: string }
|
||||||
@@ -50,7 +57,7 @@ function outputText(value: unknown): string {
|
|||||||
|
|
||||||
async function runPublint(path: string): Promise<PublintResult> {
|
async function runPublint(path: string): Promise<PublintResult> {
|
||||||
try {
|
try {
|
||||||
const { stdout, stderr } = await execFileAsync('node_modules/.bin/publint', [path], {
|
const { stdout, stderr } = await execFileAsync(process.execPath, [publintCli, path], {
|
||||||
cwd: root,
|
cwd: root,
|
||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
maxBuffer: 10 * 1024 * 1024,
|
maxBuffer: 10 * 1024 * 1024,
|
||||||
|
|||||||
@@ -143,7 +143,11 @@ try {
|
|||||||
.join('\n')
|
.join('\n')
|
||||||
writeFileSync(resolve(tmp, 'index.ts'), `${imports}\n`)
|
writeFileSync(resolve(tmp, 'index.ts'), `${imports}\n`)
|
||||||
|
|
||||||
execFileSync(resolve(root, 'node_modules/.bin/tsc'), ['-p', resolve(tmp, 'tsconfig.json'), '--pretty', 'false'], {
|
// tsc's JS entry via the current node, not the .bin shim: the extensionless
|
||||||
|
// shim isn't spawnable on Windows (CVE-2024-27980) and the .cmd variant needs
|
||||||
|
// shell:true, which space-joins args UNESCAPED (DEP0190) — a hazard for the
|
||||||
|
// temp tsconfig path. The JS entry behaves identically on every platform.
|
||||||
|
execFileSync(process.execPath, ['node_modules/typescript/bin/tsc', '-p', resolve(tmp, 'tsconfig.json'), '--pretty', 'false'], {
|
||||||
cwd: root,
|
cwd: root,
|
||||||
stdio: 'pipe',
|
stdio: 'pipe',
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user