Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .githooks/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/sh
# Workflow counterparts: .github/workflows/ci.yml and .github/workflows/release.yml

set -eu

just check
just test

if command -v npm >/dev/null 2>&1; then
(cd scrybe-app && npm ci && npm run build)
else
echo "npm not found; skipping TypeScript build"
fi
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Hook parity counterpart: .githooks/pre-push
name: CI

# Runs on self-hosted ARC runners for fast feedback on lint and tests.
Expand Down
33 changes: 29 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Hook parity counterpart: .githooks/pre-push
name: Release

on:
Expand Down Expand Up @@ -97,9 +98,9 @@ jobs:

**Python (all platforms):**
```bash
pip install scrybe.ai # full toolkit (library + CLI + MCP server + mermaid)
pip install scrybe.ai # full toolkit (library + CLI + MCP server + mermaid + docx)
# or pick individual pieces:
pip install scrybe-cli scrybe-mcp-server scrybe-py scrybe-mermaid
pip install scrybe-cli scrybe-mcp-server scrybe-py scrybe-mermaid scrybe-plugin-docx
```

### What's new
Expand Down Expand Up @@ -196,6 +197,29 @@ jobs:
name: meta-scrybe-ai
path: scrybe-meta/dist/*

# ── Pure-Python docx exporter package ────────────────────────────────────

build-docx:
name: Package (scrybe-plugin-docx)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Install build tooling
run: python -m pip install --upgrade build

- name: Build sdist + wheel
working-directory: scrybe-plugin-docx
run: python -m build --outdir dist

- uses: actions/upload-artifact@v4
with:
name: package-scrybe-plugin-docx
path: scrybe-plugin-docx/dist/*

# ── Publish to PyPI (trusted publishing — OIDC, per-package) ──────────────
#
# One job per PyPI project so a missing-publisher 403 on one doesn't abort
Expand All @@ -210,7 +234,7 @@ jobs:

publish-pypi:
name: Publish ${{ matrix.package.name }}
needs: [build-wheels, build-sdists, build-meta]
needs: [build-wheels, build-sdists, build-meta, build-docx]
runs-on: ubuntu-latest
environment: pypi
permissions:
Expand All @@ -228,6 +252,7 @@ jobs:
- { name: scrybe-py, glob: scrybe_py-* }
- { name: scrybe-mcp-server, glob: scrybe_mcp_server-* }
- { name: scrybe-mermaid, glob: scrybe_mermaid-* }
- { name: scrybe-plugin-docx, glob: scrybe_plugin_docx-* }

steps:
- name: Download all artifacts
Expand Down Expand Up @@ -285,7 +310,7 @@ jobs:
publish-crates:
name: Publish ${{ matrix.crate.name }} → crates.io
if: startsWith(github.ref, 'refs/tags/')
needs: [build-wheels, build-sdists, build-meta]
needs: [build-wheels, build-sdists, build-meta, build-docx]
runs-on: scrybe-k3s
strategy:
fail-fast: false # let independent leaves keep going if one of them fails
Expand Down
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ as MCP peers. Scrybe is itself an MCP server, drivable by external agents.
### Python (PyPI)

```bash
pip install scrybe.ai # full Python toolkit (library + CLI + MCP server + mermaid)
pip install scrybe.ai # full Python toolkit (library + CLI + MCP server + mermaid + docx)
```

Or pick individual components:
Expand All @@ -24,6 +24,7 @@ pip install scrybe-py # PyO3 library — exposes `import scrybe`
pip install scrybe-cli # `scrybe` command-line tool
pip install scrybe-mcp-server # standalone MCP server binary
pip install scrybe-mermaid # PNG iTXt codec for embedded Mermaid sources
pip install scrybe-plugin-docx # Word (.docx) exporter
```

### Rust (crates.io)
Expand Down Expand Up @@ -77,7 +78,8 @@ git clone https://github.com/hartsock/scrybe
cd scrybe
just build # all crates
just dev # Tauri dev server (requires Node)
just install # build + install to ~/Applications and ~/venv/bin
just install # build + install the app and runtime tools to ~/Applications and ~/venv/bin
just install-app # same app install path, including the Word exporter
just check # full lint + test suite
```

Expand All @@ -104,11 +106,12 @@ Python on the outside, Rust on the inside.

| Package | Install | What |
|---|---|---|
| `scrybe.ai` | `pip install scrybe.ai` | Metapackage — pulls in the four wheels below |
| `scrybe.ai` | `pip install scrybe.ai` | Metapackage — pulls in the packages below |
| `scrybe-py` | `pip install scrybe-py` | PyO3 library — `import scrybe` |
| `scrybe-cli` | `pip install scrybe-cli` | `scrybe` CLI binary |
| `scrybe-mcp-server` | `pip install scrybe-mcp-server` | `scrybe-mcp-server` binary |
| `scrybe-mermaid` | `pip install scrybe-mermaid` | PNG iTXt codec |
| `scrybe-plugin-docx` | `pip install scrybe-plugin-docx` | Word (.docx) exporter |

### crates.io

Expand Down
27 changes: 22 additions & 5 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,37 @@ clean:
cargo clean

# Full install: build app + all Python packages into ~/venv, bundle to ~/Applications
install: app
rm -f ~/venv/bin/scrybe ~/venv/bin/scrybe-app ~/venv/bin/scrybe-mcp-server
install: install-app

# Install the desktop app plus its runtime Python tools.
install-app: app install-python-toolkit
rm -rf ~/Applications/Scrybe.app
rm -f ~/venv/bin/scrybe-app
mkdir -p ~/venv/bin
cp target/release/bundle/macos/Scrybe.app/Contents/MacOS/scrybe-app ~/venv/bin/scrybe-app
mkdir -p ~/Applications
cp -R target/release/bundle/macos/Scrybe.app ~/Applications/
cd scrybe-mcp-server && ~/venv/bin/maturin develop --release
cd scrybe-cli && ~/venv/bin/maturin develop --release

# Alias for people looking for the app-specific install recipe.
app-install: install-app

# Install the Python toolkit entry points the app shells out to at runtime.
install-python-toolkit:
mkdir -p ~/venv/bin
rm -f ~/venv/bin/scrybe ~/venv/bin/scrybe-mcp-server ~/venv/bin/scrybe-docx
cd scrybe-py && VIRTUAL_ENV="$HOME/venv" ~/venv/bin/maturin develop --release
cd scrybe-mermaid && VIRTUAL_ENV="$HOME/venv" ~/venv/bin/maturin develop --release
cd scrybe-mcp-server && VIRTUAL_ENV="$HOME/venv" ~/venv/bin/maturin develop --release
cd scrybe-cli && VIRTUAL_ENV="$HOME/venv" ~/venv/bin/maturin develop --release
cd scrybe-plugin-docx && ~/venv/bin/python -m pip install -e .

# Install all Python packages in editable/dev mode (compiles Rust binaries)
editable:
pip install -e .
cd scrybe-py && maturin develop --release
cd scrybe-mermaid && maturin develop --release
cd scrybe-mcp-server && maturin develop --release
cd scrybe-cli && maturin develop --release
cd scrybe-plugin-docx && python -m pip install -e .

# Build the Tauri desktop app (requires npm install first)
app:
Expand Down
4 changes: 4 additions & 0 deletions scrybe-app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,7 @@ cargo test -p scrybe-app

On macOS the production build produces `scrybe-app/target/release/bundle/macos/Scrybe.app`.
Install to `~/Applications/Scrybe.app` for the CLI launcher to find it automatically.

From the repository root, `just install-app` builds and installs the desktop app
and the Python runtime tools it shells out to, including the Word (`.docx`)
exporter.
72 changes: 66 additions & 6 deletions scrybe-app/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -795,14 +795,52 @@ fn poll_set_vim() -> Option<String> {
poll_signal("/tmp/scrybe-set-vim.txt")
}

fn executable_name(stem: &str) -> String {
if cfg!(windows) {
format!("{stem}.exe")
} else {
stem.to_string()
}
}

fn home_venv_bin(name: &str) -> Option<std::path::PathBuf> {
let bin_dir = if cfg!(windows) { "Scripts" } else { "bin" };
dirs::home_dir().map(|home| home.join("venv").join(bin_dir).join(name))
}

fn existing_file(path: std::path::PathBuf) -> Option<String> {
if path.is_file() {
Some(path.to_string_lossy().into_owned())
} else {
None
}
}

/// Locate the `scrybe-docx` CLI (from the `scrybe-plugin-docx` package).
fn which_scrybe_docx() -> Result<String, String> {
which::which("scrybe-docx")
.map(|p| p.to_string_lossy().into_owned())
.map_err(|_| {
"scrybe-docx not found on PATH. Install with: pip install scrybe-plugin-docx"
.to_string()
})
if let Ok(path) = std::env::var("SCRYBE_DOCX_BIN") {
if let Some(path) = existing_file(std::path::PathBuf::from(path)) {
return Ok(path);
}
}

let name = executable_name("scrybe-docx");
if let Ok(exe) = std::env::current_exe() {
if let Some(path) = existing_file(exe.with_file_name(&name)) {
return Ok(path);
}
}
if let Ok(path) = which::which(&name) {
return Ok(path.to_string_lossy().into_owned());
}
if let Some(path) = home_venv_bin(&name).and_then(existing_file) {
return Ok(path);
}

Err(
"scrybe-docx not found. Reinstall the Scrybe Python toolkit with docx export support or set SCRYBE_DOCX_BIN to the exporter executable."
.to_string(),
)
}

/// Export Markdown `content` to a Word (.docx) file at `output` by shelling
Expand Down Expand Up @@ -1092,4 +1130,26 @@ mod tests {
assert!(!bak.exists());
assert!(!bp.exists());
}

#[test]
fn docx_binary_name_is_platform_specific() {
let name = executable_name("scrybe-docx");
if cfg!(windows) {
assert_eq!(name, "scrybe-docx.exe");
} else {
assert_eq!(name, "scrybe-docx");
}
}

#[test]
fn existing_file_returns_candidate_path() {
let dir = tempfile::tempdir().expect("tempdir");
let path = dir.path().join(executable_name("scrybe-docx"));
std::fs::write(&path, "#!/bin/sh\n").expect("seed exporter");

assert_eq!(
existing_file(path.clone()),
Some(path.to_string_lossy().into_owned())
);
}
}
4 changes: 4 additions & 0 deletions scrybe-mcp-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ tracing.workspace = true
tracing-subscriber.workspace = true
tokio.workspace = true
clap.workspace = true
which.workspace = true

[dev-dependencies]
tempfile = "3"

[lints]
workspace = true
Loading
Loading