scrybe-cli 0.5.0__tar.gz → 0.6.1__tar.gz
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.
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/Cargo.lock +26 -16
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/Cargo.toml +12 -11
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/PKG-INFO +3 -3
- {scrybe_cli-0.5.0/scrybe-cli → scrybe_cli-0.6.1}/README.md +2 -2
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/pyproject.toml +1 -1
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/python/scrybe_cli/__init__.py +9 -2
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-cli/Cargo.toml +0 -2
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1/scrybe-cli}/README.md +2 -2
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-cli/src/main.rs +171 -78
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-cli/src/rpc_client.rs +2 -1
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-cli/tests/rpc_socket.rs +50 -43
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-core/README.md +6 -3
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-core/src/ast.rs +220 -10
- scrybe_cli-0.6.1/scrybe-core/src/change.rs +830 -0
- scrybe_cli-0.6.1/scrybe-core/src/content.rs +236 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-core/src/document.rs +27 -8
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-core/src/error.rs +2 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-core/src/lib.rs +7 -3
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-mcp-server/Cargo.toml +0 -1
- scrybe_cli-0.6.1/scrybe-mcp-server/README.md +57 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-mcp-server/pyproject.toml +1 -1
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-mcp-server/python/scrybe_mcp_server/__init__.py +8 -1
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-mcp-server/src/lib.rs +3 -3
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-mcp-server/src/main.rs +3 -4
- scrybe_cli-0.6.1/scrybe-mcp-server/src/server.rs +779 -0
- scrybe_cli-0.6.1/scrybe-mcp-server/tests/fixtures/call_invalid_args.json +28 -0
- scrybe_cli-0.6.1/scrybe-mcp-server/tests/fixtures/call_lint_success.json +40 -0
- scrybe_cli-0.6.1/scrybe-mcp-server/tests/fixtures/call_no_live_app.json +30 -0
- scrybe_cli-0.6.1/scrybe-mcp-server/tests/fixtures/call_remote_app_error.json +32 -0
- scrybe_cli-0.6.1/scrybe-mcp-server/tests/fixtures/call_unknown_tool.json +19 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-mcp-server/tests/live_app_open.rs +44 -16
- scrybe_cli-0.6.1/scrybe-mcp-server/tests/mcp_contract.rs +336 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-mermaid/README.md +24 -9
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-mermaid/pyproject.toml +1 -1
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-mermaid/src/codec.rs +200 -4
- scrybe_cli-0.6.1/scrybe-mermaid/src/error.rs +31 -0
- scrybe_cli-0.6.1/scrybe-mermaid/src/lib.rs +233 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-mermaid/tests/test_python_quickstart.py +24 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-render/src/html.rs +60 -0
- scrybe_cli-0.6.1/scrybe-rpc/src/client.rs +544 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-rpc/src/lib.rs +123 -16
- scrybe_cli-0.6.1/scrybe-rpc/tests/wire_contract.rs +338 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-tools/Cargo.toml +5 -0
- scrybe_cli-0.6.1/scrybe-tools/src/figures.rs +562 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-tools/src/lib.rs +82 -22
- scrybe_cli-0.6.1/scrybe-tools/src/schema.rs +103 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-tools/src/tools/editor.rs +173 -17
- scrybe_cli-0.6.1/scrybe-tools/src/tools/export.rs +404 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-tools/src/tools/lint.rs +27 -19
- scrybe_cli-0.6.1/scrybe-tools/src/tools/mermaid.rs +581 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-tools/src/tools/mod.rs +10 -1
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-tools/src/tools/render.rs +11 -12
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-tools/src/tools/tabs.rs +27 -21
- scrybe_cli-0.6.1/scrybe-tools/src/tools/ui.rs +443 -0
- scrybe_cli-0.5.0/scrybe-core/src/change.rs +0 -304
- scrybe_cli-0.5.0/scrybe-core/src/content.rs +0 -73
- scrybe_cli-0.5.0/scrybe-mcp-server/README.md +0 -66
- scrybe_cli-0.5.0/scrybe-mcp-server/src/server.rs +0 -451
- scrybe_cli-0.5.0/scrybe-mcp-server/src/tools.rs +0 -1245
- scrybe_cli-0.5.0/scrybe-mermaid/src/error.rs +0 -16
- scrybe_cli-0.5.0/scrybe-mermaid/src/lib.rs +0 -119
- scrybe_cli-0.5.0/scrybe-rpc/src/client.rs +0 -184
- scrybe_cli-0.5.0/scrybe-tools/src/tools/mermaid.rs +0 -201
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/python/scrybe_cli/py.typed +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-cli/src/lib.rs +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-cli/src/wrap.rs +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-core/Cargo.toml +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-core/src/plugin.rs +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-core/src/workspace.rs +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-mcp-server/python/scrybe_mcp_server/py.typed +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-mcp-server/tests/docx_packaging.rs +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-mermaid/Cargo.toml +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-mermaid/python/scrybe_mermaid/__init__.py +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-mermaid/python/scrybe_mermaid/py.typed +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-mermaid-render/Cargo.toml +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-mermaid-render/README.md +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-mermaid-render/examples/provenance_drive.rs +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-mermaid-render/src/lib.rs +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-render/Cargo.toml +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-render/README.md +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-render/src/lib.rs +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-render/src/math.rs +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-render/src/mermaid.rs +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-render/src/theme.rs +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-render/src/themes/dark.css +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-render/src/themes/default.css +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-render/src/themes/solarized.css +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-rpc/Cargo.toml +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-rpc/README.md +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-tools/README.md +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-tools/examples/render_drive.rs +0 -0
- {scrybe_cli-0.5.0 → scrybe_cli-0.6.1}/scrybe-tools/src/lint.rs +0 -0
|
@@ -3906,7 +3906,7 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
|
|
3906
3906
|
|
|
3907
3907
|
[[package]]
|
|
3908
3908
|
name = "scrybe-app"
|
|
3909
|
-
version = "0.
|
|
3909
|
+
version = "0.6.1"
|
|
3910
3910
|
dependencies = [
|
|
3911
3911
|
"anyhow",
|
|
3912
3912
|
"dirs 5.0.1",
|
|
@@ -3916,6 +3916,7 @@ dependencies = [
|
|
|
3916
3916
|
"scrybe-mcp-server",
|
|
3917
3917
|
"scrybe-render",
|
|
3918
3918
|
"scrybe-rpc",
|
|
3919
|
+
"scrybe-tools",
|
|
3919
3920
|
"scrybe-vcs",
|
|
3920
3921
|
"serde",
|
|
3921
3922
|
"serde_json",
|
|
@@ -3933,11 +3934,10 @@ dependencies = [
|
|
|
3933
3934
|
|
|
3934
3935
|
[[package]]
|
|
3935
3936
|
name = "scrybe-cli"
|
|
3936
|
-
version = "0.
|
|
3937
|
+
version = "0.6.1"
|
|
3937
3938
|
dependencies = [
|
|
3938
3939
|
"anyhow",
|
|
3939
3940
|
"clap",
|
|
3940
|
-
"hex",
|
|
3941
3941
|
"scrybe-core",
|
|
3942
3942
|
"scrybe-mcp-server",
|
|
3943
3943
|
"scrybe-mermaid",
|
|
@@ -3946,14 +3946,13 @@ dependencies = [
|
|
|
3946
3946
|
"scrybe-tools",
|
|
3947
3947
|
"serde",
|
|
3948
3948
|
"serde_json",
|
|
3949
|
-
"sha2",
|
|
3950
3949
|
"tracing",
|
|
3951
3950
|
"tracing-subscriber",
|
|
3952
3951
|
]
|
|
3953
3952
|
|
|
3954
3953
|
[[package]]
|
|
3955
3954
|
name = "scrybe-core"
|
|
3956
|
-
version = "0.
|
|
3955
|
+
version = "0.6.1"
|
|
3957
3956
|
dependencies = [
|
|
3958
3957
|
"anyhow",
|
|
3959
3958
|
"blake3",
|
|
@@ -3970,7 +3969,7 @@ dependencies = [
|
|
|
3970
3969
|
|
|
3971
3970
|
[[package]]
|
|
3972
3971
|
name = "scrybe-mcp-client"
|
|
3973
|
-
version = "0.
|
|
3972
|
+
version = "0.6.1"
|
|
3974
3973
|
dependencies = [
|
|
3975
3974
|
"anyhow",
|
|
3976
3975
|
"dirs 5.0.1",
|
|
@@ -3985,7 +3984,7 @@ dependencies = [
|
|
|
3985
3984
|
|
|
3986
3985
|
[[package]]
|
|
3987
3986
|
name = "scrybe-mcp-server"
|
|
3988
|
-
version = "0.
|
|
3987
|
+
version = "0.6.1"
|
|
3989
3988
|
dependencies = [
|
|
3990
3989
|
"anyhow",
|
|
3991
3990
|
"clap",
|
|
@@ -4001,12 +4000,11 @@ dependencies = [
|
|
|
4001
4000
|
"tokio",
|
|
4002
4001
|
"tracing",
|
|
4003
4002
|
"tracing-subscriber",
|
|
4004
|
-
"which",
|
|
4005
4003
|
]
|
|
4006
4004
|
|
|
4007
4005
|
[[package]]
|
|
4008
4006
|
name = "scrybe-mermaid"
|
|
4009
|
-
version = "0.
|
|
4007
|
+
version = "0.6.1"
|
|
4010
4008
|
dependencies = [
|
|
4011
4009
|
"anyhow",
|
|
4012
4010
|
"base64 0.22.1",
|
|
@@ -4023,7 +4021,7 @@ dependencies = [
|
|
|
4023
4021
|
|
|
4024
4022
|
[[package]]
|
|
4025
4023
|
name = "scrybe-mermaid-render"
|
|
4026
|
-
version = "0.
|
|
4024
|
+
version = "0.6.1"
|
|
4027
4025
|
dependencies = [
|
|
4028
4026
|
"anyhow",
|
|
4029
4027
|
"hex",
|
|
@@ -4033,7 +4031,7 @@ dependencies = [
|
|
|
4033
4031
|
|
|
4034
4032
|
[[package]]
|
|
4035
4033
|
name = "scrybe-py"
|
|
4036
|
-
version = "0.
|
|
4034
|
+
version = "0.6.1"
|
|
4037
4035
|
dependencies = [
|
|
4038
4036
|
"anyhow",
|
|
4039
4037
|
"pyo3",
|
|
@@ -4045,9 +4043,17 @@ dependencies = [
|
|
|
4045
4043
|
"tracing",
|
|
4046
4044
|
]
|
|
4047
4045
|
|
|
4046
|
+
[[package]]
|
|
4047
|
+
name = "scrybe-ratatui"
|
|
4048
|
+
version = "0.6.1"
|
|
4049
|
+
dependencies = [
|
|
4050
|
+
"ratatui",
|
|
4051
|
+
"scrybe-core",
|
|
4052
|
+
]
|
|
4053
|
+
|
|
4048
4054
|
[[package]]
|
|
4049
4055
|
name = "scrybe-render"
|
|
4050
|
-
version = "0.
|
|
4056
|
+
version = "0.6.1"
|
|
4051
4057
|
dependencies = [
|
|
4052
4058
|
"anyhow",
|
|
4053
4059
|
"pulldown-cmark",
|
|
@@ -4060,7 +4066,7 @@ dependencies = [
|
|
|
4060
4066
|
|
|
4061
4067
|
[[package]]
|
|
4062
4068
|
name = "scrybe-rpc"
|
|
4063
|
-
version = "0.
|
|
4069
|
+
version = "0.6.1"
|
|
4064
4070
|
dependencies = [
|
|
4065
4071
|
"serde",
|
|
4066
4072
|
"serde_json",
|
|
@@ -4069,8 +4075,9 @@ dependencies = [
|
|
|
4069
4075
|
|
|
4070
4076
|
[[package]]
|
|
4071
4077
|
name = "scrybe-tools"
|
|
4072
|
-
version = "0.
|
|
4078
|
+
version = "0.6.1"
|
|
4073
4079
|
dependencies = [
|
|
4080
|
+
"anyhow",
|
|
4074
4081
|
"scrybe-core",
|
|
4075
4082
|
"scrybe-mermaid",
|
|
4076
4083
|
"scrybe-mermaid-render",
|
|
@@ -4078,24 +4085,27 @@ dependencies = [
|
|
|
4078
4085
|
"scrybe-rpc",
|
|
4079
4086
|
"serde",
|
|
4080
4087
|
"serde_json",
|
|
4088
|
+
"tempfile",
|
|
4081
4089
|
"thiserror 2.0.18",
|
|
4082
4090
|
"uuid",
|
|
4091
|
+
"which",
|
|
4083
4092
|
]
|
|
4084
4093
|
|
|
4085
4094
|
[[package]]
|
|
4086
4095
|
name = "scrybe-tui"
|
|
4087
|
-
version = "0.
|
|
4096
|
+
version = "0.6.1"
|
|
4088
4097
|
dependencies = [
|
|
4089
4098
|
"anyhow",
|
|
4090
4099
|
"clap",
|
|
4091
4100
|
"crossterm",
|
|
4092
4101
|
"ratatui",
|
|
4093
4102
|
"scrybe-core",
|
|
4103
|
+
"scrybe-ratatui",
|
|
4094
4104
|
]
|
|
4095
4105
|
|
|
4096
4106
|
[[package]]
|
|
4097
4107
|
name = "scrybe-vcs"
|
|
4098
|
-
version = "0.
|
|
4108
|
+
version = "0.6.1"
|
|
4099
4109
|
dependencies = [
|
|
4100
4110
|
"anyhow",
|
|
4101
4111
|
"chrono",
|
|
@@ -6,7 +6,7 @@ members = ["scrybe-core", "scrybe-render", "scrybe-mcp-server", "scrybe-mermaid"
|
|
|
6
6
|
# `version.workspace = true`, so a release bumps all crates in lock-step
|
|
7
7
|
# from one place. (See RELEASE.md; issue #128.)
|
|
8
8
|
[workspace.package]
|
|
9
|
-
version = "0.
|
|
9
|
+
version = "0.6.1"
|
|
10
10
|
|
|
11
11
|
# Workspace-level dependency pins keep all crates in lock-step.
|
|
12
12
|
[workspace.dependencies]
|
|
@@ -60,16 +60,17 @@ tauri-build = { version = "2", features = [] }
|
|
|
60
60
|
# Internal crates — version pinned (=) so cargo publish accepts the
|
|
61
61
|
# tarballs (path-deps without versions are rejected at publish time).
|
|
62
62
|
# Workspace lock-step: every release bumps all members together.
|
|
63
|
-
scrybe-core = { path = "scrybe-core", version = "=0.
|
|
64
|
-
scrybe-render = { path = "scrybe-render", version = "=0.
|
|
65
|
-
scrybe-mcp-client = { path = "scrybe-mcp-client", version = "=0.
|
|
66
|
-
scrybe-mcp-server = { path = "scrybe-mcp-server", version = "=0.
|
|
67
|
-
scrybe-mermaid = { path = "scrybe-mermaid", version = "=0.
|
|
68
|
-
scrybe-vcs = { path = "scrybe-vcs", version = "=0.
|
|
69
|
-
scrybe-py = { path = "scrybe-py", version = "=0.
|
|
70
|
-
scrybe-rpc = { path = "scrybe-rpc", version = "=0.
|
|
71
|
-
scrybe-tools = { path = "scrybe-tools", version = "=0.
|
|
72
|
-
scrybe-
|
|
63
|
+
scrybe-core = { path = "scrybe-core", version = "=0.6.1" }
|
|
64
|
+
scrybe-render = { path = "scrybe-render", version = "=0.6.1" }
|
|
65
|
+
scrybe-mcp-client = { path = "scrybe-mcp-client", version = "=0.6.1" }
|
|
66
|
+
scrybe-mcp-server = { path = "scrybe-mcp-server", version = "=0.6.1" }
|
|
67
|
+
scrybe-mermaid = { path = "scrybe-mermaid", version = "=0.6.1" }
|
|
68
|
+
scrybe-vcs = { path = "scrybe-vcs", version = "=0.6.1" }
|
|
69
|
+
scrybe-py = { path = "scrybe-py", version = "=0.6.1" }
|
|
70
|
+
scrybe-rpc = { path = "scrybe-rpc", version = "=0.6.1" }
|
|
71
|
+
scrybe-tools = { path = "scrybe-tools", version = "=0.6.1" }
|
|
72
|
+
scrybe-ratatui = { path = "scrybe-ratatui", version = "=0.6.1" }
|
|
73
|
+
scrybe-mermaid-render = { path = "scrybe-mermaid-render", version = "=0.6.1" }
|
|
73
74
|
|
|
74
75
|
# Adopted pure-Rust Mermaid → SVG renderer (#132 spike-Pass, 2026-07-17).
|
|
75
76
|
# SVG-only by default here; the `png` feature (resvg) is opted into per-crate.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scrybe-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.1
|
|
4
4
|
Summary: Scrybe CLI — headless Markdown render/lint/mermaid tool (binary wheel)
|
|
5
5
|
Home-Page: https://github.com/hartsock/scrybe
|
|
6
6
|
License: Apache-2.0
|
|
@@ -39,8 +39,8 @@ also the launcher for the Tauri GUI app: `scrybe file.md` locates the
|
|
|
39
39
|
| `scrybe render [FILE]` | Render Markdown to HTML (stdin → stdout by default); `--theme`, `--full-html`, `--output` |
|
|
40
40
|
| `scrybe lint FILE` | Word count, headings, code blocks, broken links; `--json` for machine output; exits 1 if broken links found |
|
|
41
41
|
| `scrybe mermaid embed PNG SOURCE` | Embed Mermaid source into PNG iTXt chunk |
|
|
42
|
-
| `scrybe mermaid extract PNG` | Print embedded Mermaid source |
|
|
43
|
-
| `scrybe mermaid verify PNG` | Verify SHA-256 integrity of embedded source; exits 1 if tampered |
|
|
42
|
+
| `scrybe mermaid extract PNG` | Print embedded Mermaid source, verifying its SHA-256 by default; exit 2 if tampered, `--unverified` to skip the check (forensics) |
|
|
43
|
+
| `scrybe mermaid verify PNG` | Verify SHA-256 integrity of embedded source; exits 1 if tampered or digest missing |
|
|
44
44
|
| `scrybe open [PATH]` | Launch the Scrybe GUI, optionally at a file or directory |
|
|
45
45
|
| `scrybe version` | Print version and active feature flags |
|
|
46
46
|
| `scrybe [PATH]` | Bare invocation with a path injects `open` automatically |
|
|
@@ -29,8 +29,8 @@ also the launcher for the Tauri GUI app: `scrybe file.md` locates the
|
|
|
29
29
|
| `scrybe render [FILE]` | Render Markdown to HTML (stdin → stdout by default); `--theme`, `--full-html`, `--output` |
|
|
30
30
|
| `scrybe lint FILE` | Word count, headings, code blocks, broken links; `--json` for machine output; exits 1 if broken links found |
|
|
31
31
|
| `scrybe mermaid embed PNG SOURCE` | Embed Mermaid source into PNG iTXt chunk |
|
|
32
|
-
| `scrybe mermaid extract PNG` | Print embedded Mermaid source |
|
|
33
|
-
| `scrybe mermaid verify PNG` | Verify SHA-256 integrity of embedded source; exits 1 if tampered |
|
|
32
|
+
| `scrybe mermaid extract PNG` | Print embedded Mermaid source, verifying its SHA-256 by default; exit 2 if tampered, `--unverified` to skip the check (forensics) |
|
|
33
|
+
| `scrybe mermaid verify PNG` | Verify SHA-256 integrity of embedded source; exits 1 if tampered or digest missing |
|
|
34
34
|
| `scrybe open [PATH]` | Launch the Scrybe GUI, optionally at a file or directory |
|
|
35
35
|
| `scrybe version` | Print version and active feature flags |
|
|
36
36
|
| `scrybe [PATH]` | Bare invocation with a path injects `open` automatically |
|
|
@@ -4,7 +4,7 @@ This package installs the `scrybe` command on your PATH, providing
|
|
|
4
4
|
render, lint, mermaid embed/extract, and the GUI integration RPC client.
|
|
5
5
|
|
|
6
6
|
For programmatic Python library access (Document, render_markdown,
|
|
7
|
-
|
|
7
|
+
ContentDigest, etc.), install scrybe-py:
|
|
8
8
|
|
|
9
9
|
pip install scrybe-py
|
|
10
10
|
>>> import scrybe
|
|
@@ -30,7 +30,12 @@ except ImportError:
|
|
|
30
30
|
# Soft dependency on scrybe-py: re-export when present so users can drive
|
|
31
31
|
# the Rust library directly without juggling two imports.
|
|
32
32
|
try:
|
|
33
|
-
from scrybe import
|
|
33
|
+
from scrybe import ( # type: ignore[import-not-found]
|
|
34
|
+
ContentDigest,
|
|
35
|
+
ContentId, # deprecated alias for ContentDigest
|
|
36
|
+
Document,
|
|
37
|
+
render_markdown,
|
|
38
|
+
)
|
|
34
39
|
|
|
35
40
|
_SCRYBE_LIB_AVAILABLE = True
|
|
36
41
|
except ImportError:
|
|
@@ -52,12 +57,14 @@ except ImportError:
|
|
|
52
57
|
def __call__(self, *args: object, **kwargs: object) -> None:
|
|
53
58
|
raise ImportError(f"{self._name}: {_MISSING_MSG}")
|
|
54
59
|
|
|
60
|
+
ContentDigest = _Missing("ContentDigest") # type: ignore[assignment,misc]
|
|
55
61
|
ContentId = _Missing("ContentId") # type: ignore[assignment,misc]
|
|
56
62
|
Document = _Missing("Document") # type: ignore[assignment,misc]
|
|
57
63
|
render_markdown = _Missing("render_markdown") # type: ignore[assignment]
|
|
58
64
|
|
|
59
65
|
|
|
60
66
|
__all__ = [
|
|
67
|
+
"ContentDigest",
|
|
61
68
|
"ContentId",
|
|
62
69
|
"Document",
|
|
63
70
|
"render_markdown",
|
|
@@ -29,8 +29,8 @@ also the launcher for the Tauri GUI app: `scrybe file.md` locates the
|
|
|
29
29
|
| `scrybe render [FILE]` | Render Markdown to HTML (stdin → stdout by default); `--theme`, `--full-html`, `--output` |
|
|
30
30
|
| `scrybe lint FILE` | Word count, headings, code blocks, broken links; `--json` for machine output; exits 1 if broken links found |
|
|
31
31
|
| `scrybe mermaid embed PNG SOURCE` | Embed Mermaid source into PNG iTXt chunk |
|
|
32
|
-
| `scrybe mermaid extract PNG` | Print embedded Mermaid source |
|
|
33
|
-
| `scrybe mermaid verify PNG` | Verify SHA-256 integrity of embedded source; exits 1 if tampered |
|
|
32
|
+
| `scrybe mermaid extract PNG` | Print embedded Mermaid source, verifying its SHA-256 by default; exit 2 if tampered, `--unverified` to skip the check (forensics) |
|
|
33
|
+
| `scrybe mermaid verify PNG` | Verify SHA-256 integrity of embedded source; exits 1 if tampered or digest missing |
|
|
34
34
|
| `scrybe open [PATH]` | Launch the Scrybe GUI, optionally at a file or directory |
|
|
35
35
|
| `scrybe version` | Print version and active feature flags |
|
|
36
36
|
| `scrybe [PATH]` | Bare invocation with a path injects `open` automatically |
|
|
@@ -288,10 +288,17 @@ enum Command {
|
|
|
288
288
|
|
|
289
289
|
/// Extract Mermaid source from a PNG iTXt metadata chunk.
|
|
290
290
|
///
|
|
291
|
-
/// Top-level shortcut for `scrybe mermaid extract`. Same args
|
|
291
|
+
/// Top-level shortcut for `scrybe mermaid extract`. Same args and exit
|
|
292
|
+
/// codes: 0 = success, 1 = extraction failed (no payload / unreadable
|
|
293
|
+
/// PNG), 2 = verification failed (stored sha256 does not match the
|
|
294
|
+
/// extracted source).
|
|
292
295
|
Extract {
|
|
293
296
|
#[arg(value_name = "PNG")]
|
|
294
297
|
png: std::path::PathBuf,
|
|
298
|
+
/// Skip digest verification and print the raw stored source
|
|
299
|
+
/// (forensics on tampered payloads).
|
|
300
|
+
#[arg(long)]
|
|
301
|
+
unverified: bool,
|
|
295
302
|
},
|
|
296
303
|
|
|
297
304
|
/// Print version and active feature flags.
|
|
@@ -309,10 +316,21 @@ enum MermaidCmd {
|
|
|
309
316
|
#[arg(short, long)]
|
|
310
317
|
out: Option<std::path::PathBuf>,
|
|
311
318
|
},
|
|
312
|
-
/// Extract Mermaid source from a PNG.
|
|
319
|
+
/// Extract Mermaid source from a PNG, verifying its sha256 by default.
|
|
320
|
+
///
|
|
321
|
+
/// The stored digest is checked against a freshly-computed hash of the
|
|
322
|
+
/// extracted source. Exit codes: 0 = success (a payload with no stored
|
|
323
|
+
/// digest prints a note to stderr), 1 = extraction failed (no payload /
|
|
324
|
+
/// unreadable PNG), 2 = verification failed (tampered — stored sha256
|
|
325
|
+
/// does not match the extracted source). Use --unverified to skip the
|
|
326
|
+
/// check and print the raw stored source for forensics.
|
|
313
327
|
Extract {
|
|
314
328
|
#[arg(value_name = "PNG")]
|
|
315
329
|
png: std::path::PathBuf,
|
|
330
|
+
/// Skip digest verification and print the raw stored source
|
|
331
|
+
/// (forensics on tampered payloads).
|
|
332
|
+
#[arg(long)]
|
|
333
|
+
unverified: bool,
|
|
316
334
|
},
|
|
317
335
|
/// Verify the sha256 integrity of the embedded Mermaid source in a PNG.
|
|
318
336
|
///
|
|
@@ -336,6 +354,20 @@ enum MermaidCmd {
|
|
|
336
354
|
#[arg(short, long, value_name = "OUT")]
|
|
337
355
|
out: std::path::PathBuf,
|
|
338
356
|
},
|
|
357
|
+
/// Export every Mermaid diagram in a document to sibling PNG figures.
|
|
358
|
+
///
|
|
359
|
+
/// For `foo.md`, writes `foo_fig_01.png`, `foo_fig_02.png`, … next to the
|
|
360
|
+
/// document in document order; each PNG embeds its Mermaid source (uuid +
|
|
361
|
+
/// sha256) so it round-trips via `scrybe mermaid extract`. Pure-Rust
|
|
362
|
+
/// rendering (no `mmdc`) via the shared `export_figures` tool.
|
|
363
|
+
Export {
|
|
364
|
+
/// Markdown document whose Mermaid diagrams to export.
|
|
365
|
+
#[arg(value_name = "FILE")]
|
|
366
|
+
input: std::path::PathBuf,
|
|
367
|
+
/// Output JSON (`{count, figures}`) instead of one path per line.
|
|
368
|
+
#[arg(long)]
|
|
369
|
+
json: bool,
|
|
370
|
+
},
|
|
339
371
|
}
|
|
340
372
|
|
|
341
373
|
/// Known subcommand names. Anything else in argv[1] is treated as a path to open.
|
|
@@ -443,12 +475,12 @@ fn main() -> anyhow::Result<()> {
|
|
|
443
475
|
for bl in &report.broken_links {
|
|
444
476
|
eprintln!(" - [{}]({})", bl.text, bl.url);
|
|
445
477
|
}
|
|
446
|
-
// Also print content
|
|
478
|
+
// Also print the content digest.
|
|
447
479
|
eprintln!(
|
|
448
|
-
"{:<30} {} (
|
|
480
|
+
"{:<30} {} (digest {})",
|
|
449
481
|
"File:",
|
|
450
482
|
input.display(),
|
|
451
|
-
doc.
|
|
483
|
+
doc.content_digest()
|
|
452
484
|
);
|
|
453
485
|
}
|
|
454
486
|
|
|
@@ -465,35 +497,42 @@ fn main() -> anyhow::Result<()> {
|
|
|
465
497
|
std::fs::write(&dest, &embedded)?;
|
|
466
498
|
println!("Embedded into {}", dest.display());
|
|
467
499
|
}
|
|
468
|
-
MermaidCmd::Extract { png } => {
|
|
469
|
-
|
|
470
|
-
let payload = scrybe_mermaid::extract(&bytes)?;
|
|
471
|
-
println!("{}", payload.source);
|
|
500
|
+
MermaidCmd::Extract { png, unverified } => {
|
|
501
|
+
run_mermaid_extract(&png, unverified)?;
|
|
472
502
|
}
|
|
473
503
|
MermaidCmd::Verify { png } => {
|
|
474
504
|
let bytes = std::fs::read(&png)?;
|
|
505
|
+
// `extract` verifies by default — a mismatch is a typed error.
|
|
475
506
|
match scrybe_mermaid::extract(&bytes) {
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
hasher.update(payload.source.as_bytes());
|
|
485
|
-
let computed = hex::encode(hasher.finalize());
|
|
486
|
-
|
|
487
|
-
if computed == payload.sha256 {
|
|
488
|
-
println!("OK — sha256 {} matches embedded source", &computed[..16]);
|
|
489
|
-
} else {
|
|
507
|
+
Ok(payload) => match &payload.verification {
|
|
508
|
+
scrybe_mermaid::VerificationStatus::Verified { digest, .. } => {
|
|
509
|
+
println!(
|
|
510
|
+
"OK — sha256 {} matches embedded source",
|
|
511
|
+
digest_short(digest)
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
scrybe_mermaid::VerificationStatus::NoDigest => {
|
|
490
515
|
eprintln!(
|
|
491
|
-
"
|
|
492
|
-
&payload.sha256[..16],
|
|
493
|
-
&computed[..16]
|
|
516
|
+
"MISSING — payload carries no sha256 digest; nothing to verify"
|
|
494
517
|
);
|
|
495
518
|
std::process::exit(1);
|
|
496
519
|
}
|
|
520
|
+
},
|
|
521
|
+
Err(scrybe_mermaid::MermaidError::VerificationFailed {
|
|
522
|
+
expected,
|
|
523
|
+
actual,
|
|
524
|
+
..
|
|
525
|
+
}) => {
|
|
526
|
+
eprintln!(
|
|
527
|
+
"TAMPERED — stored sha256 {} does not match computed {}",
|
|
528
|
+
digest_short(&expected),
|
|
529
|
+
digest_short(&actual)
|
|
530
|
+
);
|
|
531
|
+
std::process::exit(1);
|
|
532
|
+
}
|
|
533
|
+
Err(e) => {
|
|
534
|
+
eprintln!("scrybe mermaid verify: failed to extract payload: {e}");
|
|
535
|
+
std::process::exit(1);
|
|
497
536
|
}
|
|
498
537
|
}
|
|
499
538
|
}
|
|
@@ -517,6 +556,28 @@ fn main() -> anyhow::Result<()> {
|
|
|
517
556
|
println!(" uuid {}", d["uuid"].as_str().unwrap_or(""));
|
|
518
557
|
println!(" sha256 {}", d["sha256"].as_str().unwrap_or(""));
|
|
519
558
|
}
|
|
559
|
+
MermaidCmd::Export { input, json } => {
|
|
560
|
+
let reg = scrybe_tools::Registry::default();
|
|
561
|
+
let outcome = reg.call(
|
|
562
|
+
"export_figures",
|
|
563
|
+
&scrybe_tools::Ctx::headless(),
|
|
564
|
+
&serde_json::json!({ "path": input.to_string_lossy() }),
|
|
565
|
+
)?;
|
|
566
|
+
if let Some(err) = outcome.tool_error {
|
|
567
|
+
eprintln!("scrybe mermaid export: {}", err.message);
|
|
568
|
+
std::process::exit(1);
|
|
569
|
+
}
|
|
570
|
+
let d = &outcome.data;
|
|
571
|
+
if json {
|
|
572
|
+
println!("{}", serde_json::to_string_pretty(d)?);
|
|
573
|
+
} else {
|
|
574
|
+
let figures = d["figures"].as_array().cloned().unwrap_or_default();
|
|
575
|
+
for f in &figures {
|
|
576
|
+
println!("{}", f["path"].as_str().unwrap_or(""));
|
|
577
|
+
}
|
|
578
|
+
println!("{} figure(s)", d["count"].as_u64().unwrap_or(0));
|
|
579
|
+
}
|
|
580
|
+
}
|
|
520
581
|
},
|
|
521
582
|
|
|
522
583
|
Command::Open { path } => match path {
|
|
@@ -526,13 +587,11 @@ fn main() -> anyhow::Result<()> {
|
|
|
526
587
|
// the "one tab, one file, refresh on re-open" semantics.
|
|
527
588
|
match rpc_client::send("open", serde_json::json!({"path": canon.to_string_lossy()}))
|
|
528
589
|
{
|
|
529
|
-
Ok(
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
},
|
|
535
|
-
Err(e) if e.contains("no Scrybe running") => {
|
|
590
|
+
Ok(_) => println!("Opening {} in Scrybe", canon.display()),
|
|
591
|
+
Err(scrybe_rpc::ClientError::Remote(e)) => {
|
|
592
|
+
anyhow::bail!("scrybe open failed: {} ({})", e.message, e.code)
|
|
593
|
+
}
|
|
594
|
+
Err(e) if e.is_not_running() => {
|
|
536
595
|
// Fall through to launching the app.
|
|
537
596
|
launch_scrybe(Some(&canon)).map_err(|e| anyhow::anyhow!("{e}"))?;
|
|
538
597
|
println!("Opening {} in Scrybe", canon.display());
|
|
@@ -552,28 +611,23 @@ fn main() -> anyhow::Result<()> {
|
|
|
552
611
|
Command::Save { path } => {
|
|
553
612
|
let canon = path.canonicalize().unwrap_or_else(|_| path.clone());
|
|
554
613
|
match rpc_client::send("save", serde_json::json!({"path": canon.to_string_lossy()})) {
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
.and_then(|r| r.get("bytes"))
|
|
564
|
-
.and_then(serde_json::Value::as_u64);
|
|
565
|
-
match bytes {
|
|
566
|
-
Some(b) => println!("Saved {} ({b} bytes)", canon.display()),
|
|
567
|
-
None => println!("Saved {}", canon.display()),
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
// Not open: silent no-op per the documented CLI contract.
|
|
571
|
-
Some(e) if e.code == scrybe_rpc::ERR_TAB_NOT_OPEN => {}
|
|
572
|
-
Some(e) => {
|
|
573
|
-
anyhow::bail!("scrybe save failed: {} ({})", e.message, e.code)
|
|
614
|
+
// Reply-correlated save reports { path, bytes, was_dirty };
|
|
615
|
+
// an older app replies the legacy {applied} ack with no
|
|
616
|
+
// byte count — don't fabricate one.
|
|
617
|
+
Ok(result) => {
|
|
618
|
+
let bytes = result.get("bytes").and_then(serde_json::Value::as_u64);
|
|
619
|
+
match bytes {
|
|
620
|
+
Some(b) => println!("Saved {} ({b} bytes)", canon.display()),
|
|
621
|
+
None => println!("Saved {}", canon.display()),
|
|
574
622
|
}
|
|
575
|
-
}
|
|
576
|
-
|
|
623
|
+
}
|
|
624
|
+
// Not open: silent no-op per the documented CLI contract.
|
|
625
|
+
Err(scrybe_rpc::ClientError::Remote(e))
|
|
626
|
+
if e.code == scrybe_rpc::ERR_TAB_NOT_OPEN => {}
|
|
627
|
+
Err(scrybe_rpc::ClientError::Remote(e)) => {
|
|
628
|
+
anyhow::bail!("scrybe save failed: {} ({})", e.message, e.code)
|
|
629
|
+
}
|
|
630
|
+
Err(e) if e.is_not_running() => {
|
|
577
631
|
// Silent no-op per design: nothing open, nothing to save.
|
|
578
632
|
}
|
|
579
633
|
Err(e) => anyhow::bail!("scrybe save failed: {e}"),
|
|
@@ -586,13 +640,11 @@ fn main() -> anyhow::Result<()> {
|
|
|
586
640
|
"close",
|
|
587
641
|
serde_json::json!({"path": canon.to_string_lossy()}),
|
|
588
642
|
) {
|
|
589
|
-
Ok(
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
},
|
|
595
|
-
Err(e) if e.contains("no Scrybe running") => {
|
|
643
|
+
Ok(_) => println!("Closed {}", canon.display()),
|
|
644
|
+
Err(scrybe_rpc::ClientError::Remote(e)) => {
|
|
645
|
+
anyhow::bail!("scrybe close failed: {} ({})", e.message, e.code)
|
|
646
|
+
}
|
|
647
|
+
Err(e) if e.is_not_running() => {
|
|
596
648
|
// Silent no-op.
|
|
597
649
|
}
|
|
598
650
|
Err(e) => anyhow::bail!("scrybe close failed: {e}"),
|
|
@@ -646,13 +698,11 @@ fn main() -> anyhow::Result<()> {
|
|
|
646
698
|
}
|
|
647
699
|
Command::Quit { force } => {
|
|
648
700
|
match rpc_client::send("quit", serde_json::json!({"force": force})) {
|
|
649
|
-
Ok(
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
},
|
|
655
|
-
Err(e) if e.contains("no Scrybe running") => {
|
|
701
|
+
Ok(_) => println!("Quitting Scrybe"),
|
|
702
|
+
Err(scrybe_rpc::ClientError::Remote(e)) => {
|
|
703
|
+
anyhow::bail!("scrybe quit failed: {} ({})", e.message, e.code)
|
|
704
|
+
}
|
|
705
|
+
Err(e) if e.is_not_running() => {
|
|
656
706
|
// Silent no-op.
|
|
657
707
|
}
|
|
658
708
|
Err(e) => anyhow::bail!("scrybe quit failed: {e}"),
|
|
@@ -687,11 +737,9 @@ fn main() -> anyhow::Result<()> {
|
|
|
687
737
|
std::fs::write(&dest, &embedded)?;
|
|
688
738
|
println!("Embedded into {}", dest.display());
|
|
689
739
|
}
|
|
690
|
-
Command::Extract { png } => {
|
|
740
|
+
Command::Extract { png, unverified } => {
|
|
691
741
|
// Top-level alias for `mermaid extract` — same code path.
|
|
692
|
-
|
|
693
|
-
let payload = scrybe_mermaid::extract(&bytes)?;
|
|
694
|
-
println!("{}", payload.source);
|
|
742
|
+
run_mermaid_extract(&png, unverified)?;
|
|
695
743
|
}
|
|
696
744
|
|
|
697
745
|
Command::Version => {
|
|
@@ -702,6 +750,49 @@ fn main() -> anyhow::Result<()> {
|
|
|
702
750
|
Ok(())
|
|
703
751
|
}
|
|
704
752
|
|
|
753
|
+
// ---------------------------------------------------------------------------
|
|
754
|
+
// Mermaid extract handler (shared by `mermaid extract` and top-level `extract`)
|
|
755
|
+
// ---------------------------------------------------------------------------
|
|
756
|
+
|
|
757
|
+
/// First 16 hex chars of a digest for display — safe on short or garbage
|
|
758
|
+
/// stored values (attacker-controlled input must never panic the CLI).
|
|
759
|
+
fn digest_short(d: &str) -> &str {
|
|
760
|
+
d.get(..16).unwrap_or(d)
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
/// Extract embedded Mermaid source from `png` and print it.
|
|
764
|
+
///
|
|
765
|
+
/// Verifies the stored sha256 against the extracted source by default.
|
|
766
|
+
/// Exit codes: 0 = success (no-digest payloads print a stderr note),
|
|
767
|
+
/// 1 = extraction failure (no payload / unreadable PNG, via the returned
|
|
768
|
+
/// error), 2 = verification failure (tampered).
|
|
769
|
+
fn run_mermaid_extract(png: &std::path::Path, unverified: bool) -> anyhow::Result<()> {
|
|
770
|
+
let bytes = std::fs::read(png)?;
|
|
771
|
+
|
|
772
|
+
if unverified {
|
|
773
|
+
// Forensics path: raw stored fields, no digest check.
|
|
774
|
+
let payload = scrybe_mermaid::extract_unverified(&bytes)?;
|
|
775
|
+
println!("{}", payload.source);
|
|
776
|
+
return Ok(());
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
match scrybe_mermaid::extract(&bytes) {
|
|
780
|
+
Ok(payload) => {
|
|
781
|
+
if !payload.is_verified() {
|
|
782
|
+
eprintln!("note: payload carries no sha256 digest — source is unverified");
|
|
783
|
+
}
|
|
784
|
+
println!("{}", payload.source);
|
|
785
|
+
Ok(())
|
|
786
|
+
}
|
|
787
|
+
Err(e @ scrybe_mermaid::MermaidError::VerificationFailed { .. }) => {
|
|
788
|
+
eprintln!("scrybe mermaid extract: {e}");
|
|
789
|
+
eprintln!("(use --unverified to print the stored source anyway)");
|
|
790
|
+
std::process::exit(2);
|
|
791
|
+
}
|
|
792
|
+
Err(e) => Err(e.into()),
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
705
796
|
// ---------------------------------------------------------------------------
|
|
706
797
|
// Phase 2 read-side handlers
|
|
707
798
|
// ---------------------------------------------------------------------------
|
|
@@ -711,13 +802,15 @@ fn require_running_gui<F: FnOnce(serde_json::Value) -> anyhow::Result<()>>(
|
|
|
711
802
|
params: serde_json::Value,
|
|
712
803
|
on_ok: F,
|
|
713
804
|
) -> anyhow::Result<()> {
|
|
805
|
+
// The client types every failure (A3): in-band app errors are `Remote`,
|
|
806
|
+
// no-app is `is_not_running()`, and malformed replies arrive pre-typed
|
|
807
|
+
// (envelope/frame/JSON violations) — no message-text matching anywhere.
|
|
714
808
|
match rpc_client::send(method, params) {
|
|
715
|
-
Ok(
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
Err(e) if e.contains("no Scrybe running") => {
|
|
809
|
+
Ok(result) => on_ok(result),
|
|
810
|
+
Err(scrybe_rpc::ClientError::Remote(e)) => {
|
|
811
|
+
anyhow::bail!("scrybe {method}: {} ({})", e.message, e.code)
|
|
812
|
+
}
|
|
813
|
+
Err(e) if e.is_not_running() => {
|
|
721
814
|
anyhow::bail!(
|
|
722
815
|
"scrybe {method}: no Scrybe running — start the app first, or open the file with `scrybe <path>`"
|
|
723
816
|
)
|