@mbe24/99problems 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,22 @@
1
+ #!/bin/sh
2
+ # Pre-commit hook: format check + clippy
3
+ # Install: this file is already at .git/hooks/pre-commit
4
+ # For new clones run: cp .githooks/pre-commit .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit
5
+
6
+ set -e
7
+
8
+ echo "→ cargo fmt --check"
9
+ cargo fmt --check || {
10
+ echo ""
11
+ echo " Formatting issues found. Run 'cargo fmt' to fix them, then re-stage."
12
+ exit 1
13
+ }
14
+
15
+ echo "→ cargo clippy"
16
+ cargo clippy --no-deps -- -D warnings || {
17
+ echo ""
18
+ echo " Clippy warnings found. Fix them before committing."
19
+ exit 1
20
+ }
21
+
22
+ echo "✓ Pre-commit checks passed"
@@ -0,0 +1,12 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120" width="120" height="120">
2
+ <rect width="120" height="120" rx="24" fill="#6D28D9"/>
3
+ <text
4
+ x="60"
5
+ y="82"
6
+ font-family="'Segoe UI', Arial, sans-serif"
7
+ font-size="68"
8
+ font-weight="800"
9
+ text-anchor="middle"
10
+ fill="#FFFFFF"
11
+ letter-spacing="-3">9P</text>
12
+ </svg>
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env node
2
+ // Builds per-platform npm packages from CI artifacts and publishes them,
3
+ // then updates + publishes the main wrapper package.
4
+ const fs = require("fs");
5
+ const path = require("path");
6
+ const { execSync } = require("child_process");
7
+
8
+ const version = process.env.VERSION?.replace(/^v/, "");
9
+ if (!version) throw new Error("VERSION env var is required (e.g. v0.1.0)");
10
+
11
+ const platforms = [
12
+ {
13
+ pkg: "@mbe24/99problems-win32-x64",
14
+ dir: "npm-win32-x64",
15
+ artifact: "artifacts/binary-x86_64-pc-windows-msvc/99problems.exe",
16
+ binary: "99problems.exe",
17
+ os: "win32",
18
+ cpu: "x64",
19
+ },
20
+ {
21
+ pkg: "@mbe24/99problems-linux-x64",
22
+ dir: "npm-linux-x64",
23
+ artifact: "artifacts/binary-x86_64-unknown-linux-gnu/99problems",
24
+ binary: "99problems",
25
+ os: "linux",
26
+ cpu: "x64",
27
+ },
28
+ {
29
+ pkg: "@mbe24/99problems-darwin-x64",
30
+ dir: "npm-darwin-x64",
31
+ artifact: "artifacts/binary-x86_64-apple-darwin/99problems",
32
+ binary: "99problems",
33
+ os: "darwin",
34
+ cpu: "x64",
35
+ },
36
+ {
37
+ pkg: "@mbe24/99problems-darwin-arm64",
38
+ dir: "npm-darwin-arm64",
39
+ artifact: "artifacts/binary-aarch64-apple-darwin/99problems",
40
+ binary: "99problems",
41
+ os: "darwin",
42
+ cpu: "arm64",
43
+ },
44
+ {
45
+ pkg: "@mbe24/99problems-linux-arm64",
46
+ dir: "npm-linux-arm64",
47
+ artifact: "artifacts/binary-aarch64-unknown-linux-gnu/99problems",
48
+ binary: "99problems",
49
+ os: "linux",
50
+ cpu: "arm64",
51
+ },
52
+ ];
53
+
54
+ for (const p of platforms) {
55
+ const pkgDir = path.join(p.dir);
56
+ fs.mkdirSync(path.join(pkgDir, "bin"), { recursive: true });
57
+
58
+ // Copy binary
59
+ fs.copyFileSync(p.artifact, path.join(pkgDir, "bin", p.binary));
60
+ if (p.os !== "win32") {
61
+ fs.chmodSync(path.join(pkgDir, "bin", p.binary), 0o755);
62
+ }
63
+
64
+ // Write package.json
65
+ const pkgJson = {
66
+ name: p.pkg,
67
+ version,
68
+ description: `${p.os}-${p.cpu} binary for @mbe24/99problems`,
69
+ os: [p.os],
70
+ cpu: [p.cpu],
71
+ main: `bin/${p.binary}`,
72
+ license: "MIT",
73
+ repository: { type: "git", url: "https://github.com/mbe24/99problems" },
74
+ };
75
+ fs.writeFileSync(
76
+ path.join(pkgDir, "package.json"),
77
+ JSON.stringify(pkgJson, null, 2) + "\n"
78
+ );
79
+
80
+ console.log(`Publishing ${p.pkg}@${version} ...`);
81
+ execSync("npm publish --access public", { cwd: pkgDir, stdio: "inherit" });
82
+ }
83
+
84
+ // Update main package.json version + optionalDependencies versions
85
+ const mainPkg = JSON.parse(fs.readFileSync("package.json", "utf8"));
86
+ mainPkg.version = version;
87
+ for (const p of platforms) {
88
+ mainPkg.optionalDependencies[p.pkg] = version;
89
+ }
90
+ fs.writeFileSync("package.json", JSON.stringify(mainPkg, null, 2) + "\n");
91
+
92
+ console.log(`Publishing @mbe24/99problems@${version} ...`);
93
+ execSync("npm publish --access public", { stdio: "inherit" });
@@ -0,0 +1,82 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 640" width="1280" height="640">
2
+ <defs>
3
+ <linearGradient id="bg" x1="0" y1="0" x2="1280" y2="640" gradientUnits="userSpaceOnUse">
4
+ <stop offset="0%" stop-color="#0F0720"/>
5
+ <stop offset="100%" stop-color="#1C0B38"/>
6
+ </linearGradient>
7
+ <radialGradient id="logoglow" cx="50%" cy="50%" r="50%">
8
+ <stop offset="0%" stop-color="#7C3AED" stop-opacity="0.4"/>
9
+ <stop offset="100%" stop-color="#7C3AED" stop-opacity="0"/>
10
+ </radialGradient>
11
+ </defs>
12
+
13
+ <!-- Background -->
14
+ <rect width="1280" height="640" fill="url(#bg)"/>
15
+
16
+ <!-- Decorative circles -->
17
+ <circle cx="1220" cy="60" r="320" fill="#6D28D9" opacity="0.07"/>
18
+ <circle cx="60" cy="610" r="220" fill="#5B21B6" opacity="0.07"/>
19
+
20
+ <!-- Soft glow behind logo -->
21
+ <ellipse cx="220" cy="320" rx="240" ry="240" fill="url(#logoglow)"/>
22
+
23
+ <!-- Logo mark -->
24
+ <rect x="70" y="180" width="300" height="300" rx="44" fill="#6D28D9"/>
25
+ <text
26
+ x="220" y="372"
27
+ font-family="'Segoe UI', Arial, sans-serif"
28
+ font-size="160" font-weight="900"
29
+ text-anchor="middle" fill="#FFFFFF"
30
+ letter-spacing="-8">9P</text>
31
+
32
+ <!-- Vertical divider -->
33
+ <line x1="440" y1="100" x2="440" y2="540" stroke="#6D28D9" stroke-width="1" opacity="0.35"/>
34
+
35
+ <!-- Title -->
36
+ <text
37
+ x="472" y="234"
38
+ font-family="'Segoe UI', Arial, sans-serif"
39
+ font-size="86" font-weight="800"
40
+ fill="#FFFFFF" letter-spacing="-3">99problems</text>
41
+
42
+ <!-- Tagline -->
43
+ <text
44
+ x="474" y="282"
45
+ font-family="'Segoe UI', Arial, sans-serif"
46
+ font-size="28" font-weight="400"
47
+ fill="#A78BFA">AI-friendly access to GitHub issues</text>
48
+
49
+ <!-- Feature pills -->
50
+ <rect x="474" y="306" width="116" height="30" rx="6" fill="#2D1260"/>
51
+ <text x="532" y="326" font-family="'Segoe UI', Arial, sans-serif" font-size="14" text-anchor="middle" fill="#C4B5FD">JSON · YAML</text>
52
+
53
+ <rect x="600" y="306" width="116" height="30" rx="6" fill="#2D1260"/>
54
+ <text x="658" y="326" font-family="'Segoe UI', Arial, sans-serif" font-size="14" text-anchor="middle" fill="#C4B5FD">5 platforms</text>
55
+
56
+ <rect x="726" y="306" width="186" height="30" rx="6" fill="#2D1260"/>
57
+ <text x="819" y="326" font-family="'Segoe UI', Arial, sans-serif" font-size="14" text-anchor="middle" fill="#C4B5FD">GitHub search syntax</text>
58
+
59
+ <!-- Terminal window -->
60
+ <rect x="472" y="352" width="762" height="216" rx="12" fill="#0D0520" stroke="#3B1D7A" stroke-width="1.5"/>
61
+
62
+ <!-- Terminal chrome bar -->
63
+ <rect x="472" y="352" width="762" height="36" rx="12" fill="#1A0A38"/>
64
+ <rect x="472" y="370" width="762" height="18" fill="#1A0A38"/>
65
+ <circle cx="502" cy="370" r="7" fill="#FF5F57"/>
66
+ <circle cx="526" cy="370" r="7" fill="#FFBD2E"/>
67
+ <circle cx="550" cy="370" r="7" fill="#28C840"/>
68
+ <text x="760" y="375" font-family="'Segoe UI', Arial, sans-serif" font-size="13" text-anchor="middle" fill="#6B4FA0">zsh</text>
69
+
70
+ <!-- Install line -->
71
+ <text x="496" y="418" font-family="'Courier New', monospace" font-size="17" fill="#6D28D9">$</text>
72
+ <text x="514" y="418" font-family="'Courier New', monospace" font-size="17" fill="#94A3B8"> npm install -g @mbe24/99problems</text>
73
+
74
+ <!-- Command line -->
75
+ <text x="496" y="458" font-family="'Courier New', monospace" font-size="17" fill="#6D28D9">$</text>
76
+ <text x="514" y="458" font-family="'Courier New', monospace" font-size="17" fill="#E2E8F0"> 99problems -q </text>
77
+ <text x="672" y="458" font-family="'Courier New', monospace" font-size="17" fill="#86EFAC">"state:closed repo:owner/repo"</text>
78
+ <text x="514" y="482" font-family="'Courier New', monospace" font-size="17" fill="#E2E8F0"> -o conversations.json</text>
79
+
80
+ <!-- Output line -->
81
+ <text x="496" y="524" font-family="'Courier New', monospace" font-size="17" fill="#34D399">✓ Wrote 262 conversations to conversations.json</text>
82
+ </svg>
@@ -0,0 +1,47 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: ["**"]
6
+ pull_request:
7
+ branches: ["**"]
8
+
9
+ env:
10
+ CARGO_TERM_COLOR: always
11
+
12
+ jobs:
13
+ test:
14
+ name: Test
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: Install Rust toolchain
20
+ uses: dtolnay/rust-toolchain@stable
21
+ with:
22
+ components: clippy, rustfmt
23
+
24
+ - name: Cache cargo registry
25
+ uses: actions/cache@v4
26
+ with:
27
+ path: |
28
+ ~/.cargo/registry
29
+ ~/.cargo/git
30
+ target
31
+ key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
32
+ restore-keys: ${{ runner.os }}-cargo-
33
+
34
+ - name: Check formatting
35
+ run: cargo fmt --check
36
+
37
+ - name: Clippy
38
+ run: cargo clippy --no-deps -- -D warnings
39
+
40
+ - name: Unit tests
41
+ run: cargo test
42
+
43
+ - name: Integration tests
44
+ if: env.GITHUB_TOKEN != ''
45
+ env:
46
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
47
+ run: cargo test -- --include-ignored
@@ -0,0 +1,115 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ workflow_dispatch:
8
+ inputs:
9
+ version:
10
+ description: "Version to release (e.g. v0.1.0)"
11
+ required: true
12
+ type: string
13
+
14
+ env:
15
+ CARGO_TERM_COLOR: always
16
+ # Resolve version from tag push or manual input
17
+ RELEASE_VERSION: ${{ github.event_name == 'workflow_dispatch' && inputs.version || github.ref_name }}
18
+
19
+ jobs:
20
+ build:
21
+ name: Build ${{ matrix.target }}
22
+ runs-on: ${{ matrix.os }}
23
+ strategy:
24
+ matrix:
25
+ include:
26
+ - target: x86_64-pc-windows-msvc
27
+ os: windows-latest
28
+ npm_pkg: "@mbe24/99problems-win32-x64"
29
+ binary: "99problems.exe"
30
+ - target: x86_64-unknown-linux-gnu
31
+ os: ubuntu-latest
32
+ npm_pkg: "@mbe24/99problems-linux-x64"
33
+ binary: "99problems"
34
+ - target: x86_64-apple-darwin
35
+ os: macos-latest
36
+ npm_pkg: "@mbe24/99problems-darwin-x64"
37
+ binary: "99problems"
38
+ - target: aarch64-apple-darwin
39
+ os: macos-latest
40
+ npm_pkg: "@mbe24/99problems-darwin-arm64"
41
+ binary: "99problems"
42
+ - target: aarch64-unknown-linux-gnu
43
+ os: ubuntu-latest
44
+ npm_pkg: "@mbe24/99problems-linux-arm64"
45
+ binary: "99problems"
46
+ use_cross: true
47
+
48
+ steps:
49
+ - uses: actions/checkout@v4
50
+
51
+ - name: Install Rust toolchain
52
+ uses: dtolnay/rust-toolchain@stable
53
+ with:
54
+ targets: ${{ matrix.target }}
55
+
56
+ - name: Cache cargo registry
57
+ uses: actions/cache@v4
58
+ with:
59
+ path: |
60
+ ~/.cargo/registry
61
+ ~/.cargo/git
62
+ target
63
+ key: ${{ runner.os }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.lock') }}
64
+ restore-keys: ${{ runner.os }}-${{ matrix.target }}-cargo-
65
+
66
+ - name: Install cross (for cross-compilation)
67
+ if: matrix.use_cross
68
+ run: cargo install cross --locked
69
+
70
+ - name: Build binary
71
+ run: ${{ matrix.use_cross && 'cross' || 'cargo' }} build --release --target ${{ matrix.target }}
72
+
73
+ - name: Upload binary artifact
74
+ uses: actions/upload-artifact@v4
75
+ with:
76
+ name: binary-${{ matrix.target }}
77
+ path: target/${{ matrix.target }}/release/${{ matrix.binary }}
78
+
79
+ publish-crates:
80
+ name: Publish to crates.io
81
+ needs: build
82
+ runs-on: ubuntu-latest
83
+ steps:
84
+ - uses: actions/checkout@v4
85
+
86
+ - name: Install Rust toolchain
87
+ uses: dtolnay/rust-toolchain@stable
88
+
89
+ - name: Publish to crates.io
90
+ env:
91
+ CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
92
+ run: cargo publish --no-verify
93
+
94
+ publish-npm:
95
+ name: Publish npm packages
96
+ needs: build
97
+ runs-on: ubuntu-latest
98
+ steps:
99
+ - uses: actions/checkout@v4
100
+
101
+ - uses: actions/setup-node@v4
102
+ with:
103
+ node-version: "20"
104
+ registry-url: "https://registry.npmjs.org"
105
+
106
+ - name: Download all binaries
107
+ uses: actions/download-artifact@v4
108
+ with:
109
+ path: artifacts/
110
+
111
+ - name: Publish platform packages and main package
112
+ env:
113
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
114
+ VERSION: ${{ env.RELEASE_VERSION }}
115
+ run: node .github/scripts/publish.js
@@ -0,0 +1,74 @@
1
+ # Contributing to 99problems
2
+
3
+ Thank you for taking the time to contribute! 🎉
4
+
5
+ ## Ways to contribute
6
+
7
+ - **Bug reports** — open an issue describing what happened and what you expected
8
+ - **Feature requests** — open an issue with the `enhancement` label
9
+ - **Pull requests** — see the workflow below
10
+
11
+ ## Development setup
12
+
13
+ ```bash
14
+ # Prerequisites: Rust stable (1.85+), cargo
15
+ git clone https://github.com/mbe24/99problems
16
+ cd 99problems
17
+
18
+ # Install the pre-commit hook (runs cargo fmt + clippy before each commit)
19
+ cp .githooks/pre-commit .git/hooks/pre-commit
20
+ chmod +x .git/hooks/pre-commit # not needed on Windows
21
+
22
+ # Build
23
+ cargo build
24
+
25
+ # Run unit tests
26
+ cargo test
27
+
28
+ # Run integration tests (requires a GitHub token)
29
+ export GITHUB_TOKEN=ghp_your_token
30
+ cargo test -- --include-ignored
31
+ ```
32
+
33
+ ## Pull request workflow
34
+
35
+ 1. Fork the repo and create a branch: `git checkout -b my-feature`
36
+ 2. Make your changes and add tests where appropriate
37
+ 3. Run `cargo test` — all tests must pass
38
+ 4. Run `cargo clippy` and `cargo fmt --check` — no new warnings
39
+ 5. Open a pull request with a clear description of what and why
40
+
41
+ ## Project structure
42
+
43
+ ```
44
+ src/
45
+ main.rs # CLI entry point (clap)
46
+ config.rs # Dotfile config loading
47
+ model.rs # Shared data types (Conversation, Comment)
48
+ source/
49
+ mod.rs # Source trait + Query builder
50
+ github_issues.rs # GitHub Issues API client
51
+ format/
52
+ mod.rs # Formatter trait
53
+ json.rs # JSON output
54
+ yaml.rs # YAML output
55
+ tests/
56
+ integration.rs # Live API tests (#[ignore] by default)
57
+ ```
58
+
59
+ ## Adding a new source
60
+
61
+ 1. Create `src/source/my_source.rs` implementing the `Source` trait
62
+ 2. Register it in `src/source/mod.rs`
63
+ 3. Add a variant to `SourceKind` in `src/main.rs`
64
+
65
+ ## Adding a new output format
66
+
67
+ 1. Create `src/format/my_format.rs` implementing the `Formatter` trait
68
+ 2. Register it in `src/format/mod.rs`
69
+ 3. Add a variant to `OutputFormat` in `src/main.rs`
70
+
71
+ ## Code of conduct
72
+
73
+ Be respectful and constructive. We follow the
74
+ [Contributor Covenant](https://www.contributor-covenant.org/version/2/1/code_of_conduct/).