diff --git a/.github/labels.yml b/.github/labels.yml new file mode 100644 index 00000000..8115e0f7 --- /dev/null +++ b/.github/labels.yml @@ -0,0 +1,66 @@ +- name: "type: bug" + color: d73a4a + description: Bug report +- name: "type: enhancement" + color: a2eeef + description: Feature or enhancement +- name: "type: docs" + color: 0075ca + description: Documentation changes +- name: "type: spec/design" + color: bfd4f2 + description: Specification or design discussion +- name: "type: tooling" + color: c2e0c6 + description: Tooling or developer experience +- name: "type: test" + color: e4e669 + description: Tests or fixtures +- name: "area: xtask" + color: 5319e7 + description: Rust xtask tooling +- name: "area: schemas" + color: 6e5494 + description: JSON Schemas and examples +- name: "area: diagrams" + color: 0e8a16 + description: Mermaid diagrams and tooling +- name: "area: ci" + color: fef2c0 + description: CI/CD workflows +- name: "area: build" + color: 1d76db + description: Build, Makefile, toolchain +- name: "area: determinism" + color: 0366d6 + description: Deterministic projections and encodings +- name: "area: privacy" + color: 6f42c1 + description: Privacy / ciphertext handling concerns +- name: "area: governance" + color: 0052cc + description: Governance model and docs +- name: "priority: p0" + color: b60205 + description: Critical priority +- name: "priority: p1" + color: d93f0b + description: High priority +- name: "priority: p2" + color: fbca04 + description: Normal priority +- name: "status: blocked" + color: 000000 + description: Blocked on dependency +- name: "needs: info" + color: cfd3d7 + description: Needs more information +- name: "needs: repro" + color: cfd3d7 + description: Needs minimal reproduction +- name: good first issue + color: 7057ff + description: Good for newcomers +- name: help wanted + color: 008672 + description: Help appreciated diff --git a/.github/workflows/label-sync.yml b/.github/workflows/label-sync.yml new file mode 100644 index 00000000..7e5122ef --- /dev/null +++ b/.github/workflows/label-sync.yml @@ -0,0 +1,22 @@ +name: Label Sync + +on: + push: + paths: + - .github/labels.yml + workflow_dispatch: + +permissions: + contents: read + issues: write + +jobs: + sync: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Sync labels from .github/labels.yml + uses: crazy-max/ghaction-github-labeler@v5 + with: + yaml_file: .github/labels.yml + skip_delete: true diff --git a/scripts/mermaid/generate.mjs b/scripts/mermaid/generate.mjs index 170af05c..5781a963 100644 --- a/scripts/mermaid/generate.mjs +++ b/scripts/mermaid/generate.mjs @@ -195,6 +195,14 @@ async function hasLocal(cmdPath) { try { await fs.access(cmdPath); return true; } catch { return false; } } +async function ensureLocalMmdc() { + const cliVer = await resolveMermaidCliVersion(); + const bin = binPath('mmdc'); + if (await hasLocal(bin)) return bin; + await run('npm', ['i', '--no-save', `@mermaid-js/mermaid-cli@${cliVer}`], { cwd: repoRoot }, 300000); + return bin; +} + async function renderTask(task, mmdcPath) { const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'gatos-mmd-')); try { @@ -227,7 +235,20 @@ async function renderTask(task, mmdcPath) { if (await hasLocal(mmdcPath)) { await run(mmdcPath, argsLocal, {}, timeoutMs); } else { - await run('npx', argsNpx, {}, timeoutMs); + try { + await run('npx', argsNpx, {}, timeoutMs); + } catch (e) { + const msg = String(e && e.message || e || ''); + // Retry by installing locally if npx failed (seen as exit code 126 in CI under concurrency) + if (msg.includes('exited with code 126') || msg.includes('exited with code')) { + const local = await ensureLocalMmdc().catch(() => null); + if (local) { + await run(local, argsLocal, {}, timeoutMs); + return; + } + } + throw e; + } } } finally { // Clean up temporary directory regardless of success/failure @@ -385,7 +406,19 @@ async function main() { return; } - const mmdcPath = binPath('mmdc'); + // Warm up a local mmdc to avoid repeated concurrent npx executions which can + // occasionally fail under CI with exit 126 due to cache races. When the + // local binary is present we always prefer it; otherwise we fall back to npx. + let mmdcPath = binPath('mmdc'); + try { + const cliVer = await resolveMermaidCliVersion(); + if (!(await hasLocal(mmdcPath))) { + await run('npm', ['i', '--no-save', `@mermaid-js/mermaid-cli@${cliVer}`], { cwd: repoRoot }, 300000); + } + } catch (e) { + // Do not fail generation if warmup install fails; we'll fall back to npx. + } + mmdcPath = binPath('mmdc'); if (verifyOnly) { const errors = await verifyTasks(tasks); if (errors.length) {