omegon 0.6.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.
- package/.gitattributes +3 -0
- package/AGENTS.md +16 -0
- package/LICENSE +15 -0
- package/README.md +289 -0
- package/bin/pi.mjs +30 -0
- package/extensions/00-secrets/index.ts +1126 -0
- package/extensions/01-auth/auth.ts +401 -0
- package/extensions/01-auth/index.ts +289 -0
- package/extensions/auto-compact.ts +42 -0
- package/extensions/bootstrap/deps.ts +291 -0
- package/extensions/bootstrap/index.ts +811 -0
- package/extensions/chronos/chronos.sh +487 -0
- package/extensions/chronos/index.ts +148 -0
- package/extensions/cleave/assessment.ts +754 -0
- package/extensions/cleave/bridge.ts +31 -0
- package/extensions/cleave/conflicts.ts +250 -0
- package/extensions/cleave/dispatcher.ts +808 -0
- package/extensions/cleave/guardrails.ts +426 -0
- package/extensions/cleave/index.ts +3121 -0
- package/extensions/cleave/lifecycle-emitter.ts +20 -0
- package/extensions/cleave/openspec.ts +811 -0
- package/extensions/cleave/planner.ts +260 -0
- package/extensions/cleave/review.ts +579 -0
- package/extensions/cleave/skills.ts +355 -0
- package/extensions/cleave/types.ts +261 -0
- package/extensions/cleave/workspace.ts +861 -0
- package/extensions/cleave/worktree.ts +243 -0
- package/extensions/core-renderers.ts +253 -0
- package/extensions/dashboard/context-gauge.ts +58 -0
- package/extensions/dashboard/file-watch.ts +14 -0
- package/extensions/dashboard/footer.ts +1145 -0
- package/extensions/dashboard/git.ts +185 -0
- package/extensions/dashboard/index.ts +478 -0
- package/extensions/dashboard/memory-audit.ts +34 -0
- package/extensions/dashboard/overlay-data.ts +705 -0
- package/extensions/dashboard/overlay.ts +365 -0
- package/extensions/dashboard/render-utils.ts +54 -0
- package/extensions/dashboard/types.ts +191 -0
- package/extensions/dashboard/uri-helper.ts +45 -0
- package/extensions/debug.ts +69 -0
- package/extensions/defaults.ts +282 -0
- package/extensions/design-tree/dashboard-state.ts +161 -0
- package/extensions/design-tree/design-card.ts +362 -0
- package/extensions/design-tree/index.ts +2130 -0
- package/extensions/design-tree/lifecycle-emitter.ts +41 -0
- package/extensions/design-tree/tree.ts +1607 -0
- package/extensions/design-tree/types.ts +163 -0
- package/extensions/distill.ts +127 -0
- package/extensions/effort/index.ts +395 -0
- package/extensions/effort/tiers.ts +146 -0
- package/extensions/effort/types.ts +105 -0
- package/extensions/lib/git-state.ts +227 -0
- package/extensions/lib/local-models.ts +157 -0
- package/extensions/lib/model-preferences.ts +51 -0
- package/extensions/lib/model-routing.ts +720 -0
- package/extensions/lib/operator-fallback.ts +205 -0
- package/extensions/lib/operator-profile.ts +360 -0
- package/extensions/lib/slash-command-bridge.ts +253 -0
- package/extensions/lib/typebox-helpers.ts +16 -0
- package/extensions/local-inference/index.ts +727 -0
- package/extensions/mcp-bridge/README.md +220 -0
- package/extensions/mcp-bridge/index.ts +951 -0
- package/extensions/mcp-bridge/lib.ts +365 -0
- package/extensions/mcp-bridge/mcp.json +3 -0
- package/extensions/mcp-bridge/package.json +11 -0
- package/extensions/model-budget.ts +752 -0
- package/extensions/offline-driver.ts +403 -0
- package/extensions/openspec/archive-gate.ts +164 -0
- package/extensions/openspec/branch-cleanup.ts +64 -0
- package/extensions/openspec/dashboard-state.ts +50 -0
- package/extensions/openspec/index.ts +1917 -0
- package/extensions/openspec/lifecycle-emitter.ts +65 -0
- package/extensions/openspec/lifecycle-files.ts +70 -0
- package/extensions/openspec/lifecycle.ts +50 -0
- package/extensions/openspec/reconcile.ts +187 -0
- package/extensions/openspec/spec.ts +1385 -0
- package/extensions/openspec/types.ts +98 -0
- package/extensions/project-memory/DESIGN-global-mind.md +198 -0
- package/extensions/project-memory/README.md +202 -0
- package/extensions/project-memory/api-types.ts +382 -0
- package/extensions/project-memory/compaction-policy.ts +29 -0
- package/extensions/project-memory/core.ts +164 -0
- package/extensions/project-memory/embeddings.ts +230 -0
- package/extensions/project-memory/extraction-v2.ts +861 -0
- package/extensions/project-memory/factstore.ts +2177 -0
- package/extensions/project-memory/index.ts +3459 -0
- package/extensions/project-memory/injection-metrics.ts +91 -0
- package/extensions/project-memory/jsonl-io.ts +12 -0
- package/extensions/project-memory/lifecycle.ts +331 -0
- package/extensions/project-memory/migration.ts +293 -0
- package/extensions/project-memory/package.json +9 -0
- package/extensions/project-memory/sci-renderers.ts +7 -0
- package/extensions/project-memory/template.ts +103 -0
- package/extensions/project-memory/triggers.ts +52 -0
- package/extensions/project-memory/types.ts +102 -0
- package/extensions/render/composition/fonts/Inter-Bold.ttf +0 -0
- package/extensions/render/composition/fonts/Inter-Regular.ttf +0 -0
- package/extensions/render/composition/fonts/Tomorrow-Bold.ttf +0 -0
- package/extensions/render/composition/fonts/Tomorrow-Regular.ttf +0 -0
- package/extensions/render/composition/package-lock.json +534 -0
- package/extensions/render/composition/package.json +22 -0
- package/extensions/render/composition/render.mjs +246 -0
- package/extensions/render/composition/test-comp.tsx +87 -0
- package/extensions/render/composition/types.ts +24 -0
- package/extensions/render/excalidraw/UPSTREAM.md +81 -0
- package/extensions/render/excalidraw/elements.ts +764 -0
- package/extensions/render/excalidraw/index.ts +66 -0
- package/extensions/render/excalidraw/types.ts +223 -0
- package/extensions/render/excalidraw-renderer/pyproject.toml +8 -0
- package/extensions/render/excalidraw-renderer/render_excalidraw.py +182 -0
- package/extensions/render/excalidraw-renderer/render_template.html +59 -0
- package/extensions/render/index.ts +830 -0
- package/extensions/render/native-diagrams/index.ts +57 -0
- package/extensions/render/native-diagrams/motifs.ts +542 -0
- package/extensions/render/native-diagrams/raster.ts +8 -0
- package/extensions/render/native-diagrams/scene.ts +75 -0
- package/extensions/render/native-diagrams/spec.ts +204 -0
- package/extensions/render/native-diagrams/svg.ts +116 -0
- package/extensions/sci-ui.ts +304 -0
- package/extensions/session-log.ts +174 -0
- package/extensions/shared-state.ts +146 -0
- package/extensions/spinner-verbs.ts +91 -0
- package/extensions/style.ts +281 -0
- package/extensions/terminal-title.ts +191 -0
- package/extensions/tool-profile/index.ts +291 -0
- package/extensions/tool-profile/profiles.ts +290 -0
- package/extensions/types.d.ts +9 -0
- package/extensions/vault/index.ts +185 -0
- package/extensions/version-check.ts +90 -0
- package/extensions/view/index.ts +859 -0
- package/extensions/view/uri-resolver.ts +148 -0
- package/extensions/web-search/index.ts +182 -0
- package/extensions/web-search/providers.ts +121 -0
- package/extensions/web-ui/index.ts +110 -0
- package/extensions/web-ui/server.ts +265 -0
- package/extensions/web-ui/state.ts +462 -0
- package/extensions/web-ui/static/index.html +145 -0
- package/extensions/web-ui/types.ts +284 -0
- package/package.json +76 -0
- package/prompts/init.md +75 -0
- package/prompts/new-repo.md +54 -0
- package/prompts/oci-login.md +56 -0
- package/prompts/status.md +50 -0
- package/settings.json +4 -0
- package/skills/cleave/SKILL.md +218 -0
- package/skills/git/SKILL.md +209 -0
- package/skills/git/_reference/ci-validation.md +204 -0
- package/skills/oci/SKILL.md +338 -0
- package/skills/openspec/SKILL.md +346 -0
- package/skills/pi-extensions/SKILL.md +191 -0
- package/skills/pi-tui/SKILL.md +517 -0
- package/skills/python/SKILL.md +189 -0
- package/skills/rust/SKILL.md +268 -0
- package/skills/security/SKILL.md +206 -0
- package/skills/style/SKILL.md +264 -0
- package/skills/typescript/SKILL.md +225 -0
- package/skills/vault/SKILL.md +102 -0
- package/themes/alpharius-legacy.json +85 -0
- package/themes/alpharius.conf +59 -0
- package/themes/alpharius.json +88 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: python
|
|
3
|
+
description: Python development guidance. Covers project setup (pyproject.toml, src/ layout), testing (pytest), linting (ruff), type checking (mypy), packaging, venv management, and CI/CD patterns. Use when creating, modifying, or debugging Python code.
|
|
4
|
+
guardrails:
|
|
5
|
+
- name: typecheck
|
|
6
|
+
cmd: mypy src/
|
|
7
|
+
timeout: 60
|
|
8
|
+
condition: file_exists(pyproject.toml)
|
|
9
|
+
- name: lint
|
|
10
|
+
cmd: ruff check .
|
|
11
|
+
timeout: 30
|
|
12
|
+
condition: file_exists(pyproject.toml)
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Python Development Skill
|
|
16
|
+
|
|
17
|
+
Conventions, tooling, and patterns for Python development.
|
|
18
|
+
|
|
19
|
+
## Core Conventions
|
|
20
|
+
|
|
21
|
+
- **Python 3.11+** minimum
|
|
22
|
+
- **src/ layout** (PEP 517) for all packages
|
|
23
|
+
- **pyproject.toml** is the single config file — no `.cfg`, `.ini`, or separate `.toml`
|
|
24
|
+
- **venv + pip** for environment management — no poetry, no conda
|
|
25
|
+
- **Makefile** (or justfile) wraps all dev commands
|
|
26
|
+
- **Editable install**: `pip install -e ".[dev]"` for development
|
|
27
|
+
|
|
28
|
+
## Project Scaffold
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
<project>/
|
|
32
|
+
├── pyproject.toml # All config: build, deps, ruff, mypy, pytest
|
|
33
|
+
├── Makefile # Dev workflow: test, lint, format, typecheck, validate
|
|
34
|
+
├── src/<package>/ # Source code (src/ layout)
|
|
35
|
+
│ ├── __init__.py # __version__ = "0.1.0"
|
|
36
|
+
│ └── ...
|
|
37
|
+
├── tests/
|
|
38
|
+
│ ├── conftest.py # Shared fixtures
|
|
39
|
+
│ └── test_*.py
|
|
40
|
+
└── .github/workflows/ci.yml
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Build backend choice:**
|
|
44
|
+
| Project Type | Backend |
|
|
45
|
+
|-------------|---------|
|
|
46
|
+
| Library / CLI tool | hatchling |
|
|
47
|
+
| Daemon / application | setuptools |
|
|
48
|
+
|
|
49
|
+
## Tooling Quick Reference
|
|
50
|
+
|
|
51
|
+
### Ruff (Linting + Formatting)
|
|
52
|
+
|
|
53
|
+
```toml
|
|
54
|
+
[tool.ruff]
|
|
55
|
+
line-length = 100
|
|
56
|
+
target-version = "py311"
|
|
57
|
+
|
|
58
|
+
[tool.ruff.lint]
|
|
59
|
+
select = ["E", "F", "I", "UP", "B", "SIM", "RUF"]
|
|
60
|
+
ignore = ["E501"]
|
|
61
|
+
|
|
62
|
+
[tool.ruff.lint.per-file-ignores]
|
|
63
|
+
"__init__.py" = ["F401"]
|
|
64
|
+
|
|
65
|
+
[tool.ruff.lint.isort]
|
|
66
|
+
known-first-party = ["<package>"]
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
ruff check . # Lint
|
|
71
|
+
ruff check --fix . # Lint + auto-fix
|
|
72
|
+
ruff format . # Format (replaces black)
|
|
73
|
+
ruff format --check . # Format check (CI)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Mypy (Type Checking)
|
|
77
|
+
|
|
78
|
+
**New projects** — use `strict = true`.
|
|
79
|
+
**Projects with untyped deps** — use `ignore_missing_imports = true`, `disallow_untyped_defs = false`.
|
|
80
|
+
|
|
81
|
+
```toml
|
|
82
|
+
[tool.mypy]
|
|
83
|
+
python_version = "3.11"
|
|
84
|
+
strict = true
|
|
85
|
+
warn_return_any = true
|
|
86
|
+
warn_unused_ignores = true
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Pytest
|
|
90
|
+
|
|
91
|
+
```toml
|
|
92
|
+
[tool.pytest.ini_options]
|
|
93
|
+
testpaths = ["tests"]
|
|
94
|
+
addopts = "-v --strict-markers"
|
|
95
|
+
asyncio_mode = "auto"
|
|
96
|
+
markers = [
|
|
97
|
+
"slow: marks tests as slow",
|
|
98
|
+
"smoke: quick validation tests",
|
|
99
|
+
"integration: requires external services",
|
|
100
|
+
]
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**Key commands:**
|
|
104
|
+
```bash
|
|
105
|
+
pytest # All tests
|
|
106
|
+
pytest -m smoke # Quick validation only
|
|
107
|
+
pytest -m "not slow" # Skip slow tests
|
|
108
|
+
pytest -x # Stop on first failure
|
|
109
|
+
pytest --lf # Rerun last failures
|
|
110
|
+
pytest -k "test_connect" # Name pattern
|
|
111
|
+
pytest --cov=src --cov-report=term-missing # Coverage
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Virtual Environment
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
python3 -m venv .venv
|
|
118
|
+
source .venv/bin/activate
|
|
119
|
+
pip install --upgrade pip
|
|
120
|
+
pip install -e ".[dev]"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Testing Patterns
|
|
124
|
+
|
|
125
|
+
### Async Tests
|
|
126
|
+
|
|
127
|
+
With `asyncio_mode = "auto"`, async tests work without decorators:
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
async def test_connection():
|
|
131
|
+
client = await connect()
|
|
132
|
+
assert client.is_connected
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Python Idioms
|
|
136
|
+
|
|
137
|
+
| Pattern | Convention |
|
|
138
|
+
|---------|-----------|
|
|
139
|
+
| Paths | `pathlib.Path`, never `os.path` |
|
|
140
|
+
| Data models | `dataclasses` for internal, Pydantic at validation boundaries |
|
|
141
|
+
| Imports | stdlib / third-party / local (ruff `I` rule enforces) |
|
|
142
|
+
| Async | `asyncio.gather` for concurrency, `asyncio.wait_for` for timeouts |
|
|
143
|
+
| Logging | `logging.getLogger(__name__)` |
|
|
144
|
+
| Entry points | `def main() -> int:` registered via `[project.scripts]` |
|
|
145
|
+
| Version | Single source in `__init__.py`, read by build backend |
|
|
146
|
+
|
|
147
|
+
## Packaging
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
python -m build # Produces dist/*.whl + dist/*.tar.gz
|
|
151
|
+
twine upload dist/* # Publish to PyPI
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Use trusted publishing (OIDC) via `pypa/gh-action-pypi-publish` in CI.
|
|
155
|
+
|
|
156
|
+
## CI/CD Template
|
|
157
|
+
|
|
158
|
+
```yaml
|
|
159
|
+
name: CI
|
|
160
|
+
on: [push, pull_request]
|
|
161
|
+
jobs:
|
|
162
|
+
test:
|
|
163
|
+
runs-on: ubuntu-latest
|
|
164
|
+
strategy:
|
|
165
|
+
matrix:
|
|
166
|
+
python-version: ["3.11", "3.12"]
|
|
167
|
+
steps:
|
|
168
|
+
- uses: actions/checkout@v4
|
|
169
|
+
- uses: actions/setup-python@v5
|
|
170
|
+
with:
|
|
171
|
+
python-version: ${{ matrix.python-version }}
|
|
172
|
+
- run: pip install -e ".[dev]"
|
|
173
|
+
- run: ruff format --check .
|
|
174
|
+
- run: ruff check .
|
|
175
|
+
- run: mypy src/
|
|
176
|
+
- run: pytest --cov=src --cov-report=term-missing
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Common Gotchas
|
|
180
|
+
|
|
181
|
+
| Issue | Fix |
|
|
182
|
+
|-------|-----|
|
|
183
|
+
| Import from src/ fails | `pip install -e ".[dev]"` |
|
|
184
|
+
| `ModuleNotFoundError` in tests | Check `testpaths`, verify conftest.py exists |
|
|
185
|
+
| Async test hangs | Missing `await`, or add `asyncio.wait_for` timeout |
|
|
186
|
+
| Type stubs missing | Add `types-<pkg>` to dev deps, or `ignore_missing_imports` |
|
|
187
|
+
| Version mismatch | Single source: `__version__` in `__init__.py`, read by build backend |
|
|
188
|
+
</content>
|
|
189
|
+
</invoke>
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rust
|
|
3
|
+
description: Rust development guidance including Zellij WASM plugin development. Covers project setup (Cargo.toml), testing, clippy, rustfmt, CI/CD patterns, and the zellij-tile plugin API. Use when creating, modifying, or debugging Rust code or Zellij plugins.
|
|
4
|
+
guardrails:
|
|
5
|
+
- name: clippy
|
|
6
|
+
cmd: cargo clippy -- -D warnings
|
|
7
|
+
timeout: 120
|
|
8
|
+
condition: file_exists(Cargo.toml)
|
|
9
|
+
- name: test
|
|
10
|
+
cmd: cargo test
|
|
11
|
+
timeout: 120
|
|
12
|
+
condition: file_exists(Cargo.toml)
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Rust Development Skill
|
|
16
|
+
|
|
17
|
+
Conventions for Rust development, with a dedicated section for Zellij WASM plugin development.
|
|
18
|
+
|
|
19
|
+
## Core Conventions
|
|
20
|
+
|
|
21
|
+
- **Rust stable** toolchain (`rustup default stable`)
|
|
22
|
+
- **Cargo** for build, test, lint, format — no external build tools needed
|
|
23
|
+
- **clippy** for linting, **rustfmt** for formatting
|
|
24
|
+
- **Edition 2021** minimum
|
|
25
|
+
- Workspace layout for multi-crate projects, single `Cargo.toml` otherwise
|
|
26
|
+
|
|
27
|
+
## Project Scaffold
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
<project>/
|
|
31
|
+
├── Cargo.toml # Package metadata, deps, lint config
|
|
32
|
+
├── rustfmt.toml # max_width = 100
|
|
33
|
+
├── src/
|
|
34
|
+
│ ├── lib.rs # Library root (or main.rs for binary)
|
|
35
|
+
│ └── ...
|
|
36
|
+
├── tests/
|
|
37
|
+
│ └── integration_test.rs
|
|
38
|
+
└── .github/workflows/ci.yml
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Tooling Quick Reference
|
|
42
|
+
|
|
43
|
+
### Clippy (Linting)
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
cargo clippy # Lint
|
|
47
|
+
cargo clippy -- -D warnings # Warnings as errors (CI)
|
|
48
|
+
cargo clippy --all-targets # Include tests/benches
|
|
49
|
+
cargo clippy --fix # Auto-fix
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Project config in `Cargo.toml`:
|
|
53
|
+
```toml
|
|
54
|
+
[lints.clippy]
|
|
55
|
+
pedantic = { level = "warn", priority = -1 }
|
|
56
|
+
unwrap_used = "warn"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Rustfmt (Formatting)
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
cargo fmt # Format
|
|
63
|
+
cargo fmt -- --check # Check only (CI)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Build & Test
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
cargo build # Debug build
|
|
70
|
+
cargo build --release # Release build
|
|
71
|
+
cargo test # All tests
|
|
72
|
+
cargo test -- --nocapture # Show println output
|
|
73
|
+
cargo test test_name # Specific test
|
|
74
|
+
cargo test --lib # Unit tests only
|
|
75
|
+
cargo test --test integration_test # Specific integration test
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Other Useful Commands
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
cargo doc --open # Generate and browse docs
|
|
82
|
+
cargo audit # Security vulnerability check
|
|
83
|
+
cargo tree # Dependency tree
|
|
84
|
+
cargo expand # Macro expansion
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Testing Patterns
|
|
88
|
+
|
|
89
|
+
### Unit Tests (in-module)
|
|
90
|
+
|
|
91
|
+
```rust
|
|
92
|
+
#[cfg(test)]
|
|
93
|
+
mod tests {
|
|
94
|
+
use super::*;
|
|
95
|
+
|
|
96
|
+
#[test]
|
|
97
|
+
fn test_parse_valid() {
|
|
98
|
+
let result = parse("input");
|
|
99
|
+
assert_eq!(result, expected);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Async Tests (tokio)
|
|
105
|
+
|
|
106
|
+
```rust
|
|
107
|
+
#[tokio::test]
|
|
108
|
+
async fn test_async_op() {
|
|
109
|
+
let result = fetch_data().await;
|
|
110
|
+
assert!(result.is_ok());
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Error Handling
|
|
115
|
+
|
|
116
|
+
| Context | Pattern |
|
|
117
|
+
|---------|---------|
|
|
118
|
+
| Libraries | `thiserror::Error` derive for custom error types |
|
|
119
|
+
| Applications | `anyhow::Result` for ergonomic error propagation |
|
|
120
|
+
| Unwrap | Never in library code; `expect("reason")` in main/tests only |
|
|
121
|
+
|
|
122
|
+
## Common Dependencies
|
|
123
|
+
|
|
124
|
+
| Crate | Purpose |
|
|
125
|
+
|-------|---------|
|
|
126
|
+
| `serde` + `serde_json` | Serialization |
|
|
127
|
+
| `tokio` | Async runtime |
|
|
128
|
+
| `anyhow` / `thiserror` | Error handling |
|
|
129
|
+
| `clap` | CLI parsing |
|
|
130
|
+
| `tracing` | Structured logging |
|
|
131
|
+
|
|
132
|
+
## CI/CD
|
|
133
|
+
|
|
134
|
+
```yaml
|
|
135
|
+
name: CI
|
|
136
|
+
on: [push, pull_request]
|
|
137
|
+
jobs:
|
|
138
|
+
check:
|
|
139
|
+
runs-on: ubuntu-latest
|
|
140
|
+
steps:
|
|
141
|
+
- uses: actions/checkout@v4
|
|
142
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
143
|
+
- run: cargo fmt -- --check
|
|
144
|
+
- run: cargo clippy -- -D warnings
|
|
145
|
+
- run: cargo test
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Zellij WASM Plugin Development
|
|
151
|
+
|
|
152
|
+
Zellij plugins are Rust crates compiled to `wasm32-wasip1`, loaded by the Zellij multiplexer. The `zellij-tile` crate provides the plugin API.
|
|
153
|
+
|
|
154
|
+
### Setup
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
rustup target add wasm32-wasip1
|
|
158
|
+
cargo build --release --target wasm32-wasip1
|
|
159
|
+
# Output: target/wasm32-wasip1/release/<name>.wasm
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Plugin Cargo.toml
|
|
163
|
+
|
|
164
|
+
```toml
|
|
165
|
+
[dependencies]
|
|
166
|
+
zellij-tile = "0.41" # Match your Zellij version
|
|
167
|
+
serde = { version = "1", features = ["derive"] }
|
|
168
|
+
serde_json = "1"
|
|
169
|
+
|
|
170
|
+
[profile.release]
|
|
171
|
+
opt-level = "s" # Optimize for WASM size
|
|
172
|
+
lto = true
|
|
173
|
+
strip = true
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Plugin Lifecycle
|
|
177
|
+
|
|
178
|
+
```rust
|
|
179
|
+
use zellij_tile::prelude::*;
|
|
180
|
+
|
|
181
|
+
#[derive(Default)]
|
|
182
|
+
struct MyPlugin { /* state */ }
|
|
183
|
+
|
|
184
|
+
impl ZellijPlugin for MyPlugin {
|
|
185
|
+
fn load(&mut self, config: BTreeMap<String, String>) {
|
|
186
|
+
subscribe(&[EventType::Timer, EventType::Key]);
|
|
187
|
+
request_permission(&[PermissionType::ReadApplicationState]);
|
|
188
|
+
set_timeout(10.0);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
fn update(&mut self, event: Event) -> bool {
|
|
192
|
+
match event {
|
|
193
|
+
Event::Timer(_) => { set_timeout(10.0); true }
|
|
194
|
+
_ => false,
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
fn render(&mut self, rows: usize, cols: usize) {
|
|
199
|
+
print!("status: ok");
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
fn pipe(&mut self, pipe_message: PipeMessage) -> bool {
|
|
203
|
+
false
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
register_plugin!(MyPlugin);
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Permissions
|
|
211
|
+
|
|
212
|
+
| Permission | Allows |
|
|
213
|
+
|-----------|--------|
|
|
214
|
+
| `ReadApplicationState` | Query panes, tabs, session info |
|
|
215
|
+
| `ChangeApplicationState` | Create/close panes/tabs, switch focus |
|
|
216
|
+
| `RunCommands` | Execute commands in panes |
|
|
217
|
+
| `OpenFiles` | Open files in editor panes |
|
|
218
|
+
| `WriteToStdin` | Write to pane stdin |
|
|
219
|
+
| `ReadCliPipes` | Receive `zellij pipe` messages |
|
|
220
|
+
|
|
221
|
+
### External Communication via Pipes
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
echo '{"status":"ok"}' | zellij pipe --plugin "file:plugin.wasm" --name "update"
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Plugin handles in `fn pipe()`. Primary pattern for bridging external events into WASM plugins (WASM can't open sockets directly).
|
|
228
|
+
|
|
229
|
+
### Loading in KDL Layouts
|
|
230
|
+
|
|
231
|
+
```kdl
|
|
232
|
+
pane size=1 borderless=true {
|
|
233
|
+
plugin location="file:/path/to/plugin.wasm"
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### WASM Constraints
|
|
238
|
+
|
|
239
|
+
| Limitation | Workaround |
|
|
240
|
+
|-----------|------------|
|
|
241
|
+
| No sockets | `zellij pipe` bridge from external script |
|
|
242
|
+
| No threads | `ZellijWorker` for background work |
|
|
243
|
+
| No system clock | `set_timeout()` for time-based logic |
|
|
244
|
+
| Binary size | `opt-level = "s"`, LTO, strip |
|
|
245
|
+
|
|
246
|
+
## Debugging
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
cargo test -- --nocapture # Show test output
|
|
250
|
+
RUST_BACKTRACE=1 cargo test # Full backtraces
|
|
251
|
+
RUST_LOG=debug cargo run # With tracing/env_logger
|
|
252
|
+
|
|
253
|
+
# WASM plugins
|
|
254
|
+
tail -f /tmp/zellij-*/zellij-log/zellij.log
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Common Gotchas
|
|
258
|
+
|
|
259
|
+
| Issue | Fix |
|
|
260
|
+
|-------|-----|
|
|
261
|
+
| `wasm32-wasip1` not found | `rustup target add wasm32-wasip1` |
|
|
262
|
+
| Plugin won't load | Check Zellij version matches `zellij-tile` crate version |
|
|
263
|
+
| Clippy too noisy | Tune via `[lints.clippy]` in Cargo.toml |
|
|
264
|
+
| WASM binary too large | `opt-level = "s"`, `lto = true`, `strip = true` |
|
|
265
|
+
| Can't open sockets in WASM | Use `zellij pipe` bridge pattern |
|
|
266
|
+
| Plugin doesn't re-render | Return `true` from `update()` or `pipe()` |
|
|
267
|
+
</content>
|
|
268
|
+
</invoke>
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: security
|
|
3
|
+
description: Security checklist for code review and implementation. Covers input escaping, injection prevention, path traversal, process safety, dependency integrity, and secrets management. Load when working on user-facing code, template rendering, or process spawning.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Security Skill
|
|
7
|
+
|
|
8
|
+
Defensive coding practices. Apply these checks during implementation and review.
|
|
9
|
+
|
|
10
|
+
## Input Escaping
|
|
11
|
+
|
|
12
|
+
### Never interpolate user input into templates, scripts, or SQL
|
|
13
|
+
|
|
14
|
+
```rust
|
|
15
|
+
// ❌ XSS: user-controlled value injected into JS string
|
|
16
|
+
let js = format!("var id = '{}';", user_input);
|
|
17
|
+
|
|
18
|
+
// ✅ Escape special characters before interpolation
|
|
19
|
+
fn escape_js_string(s: &str) -> String {
|
|
20
|
+
s.replace('\\', "\\\\")
|
|
21
|
+
.replace('\'', "\\'")
|
|
22
|
+
.replace('"', "\\\"")
|
|
23
|
+
.replace('<', "\\x3c")
|
|
24
|
+
.replace('>', "\\x3e")
|
|
25
|
+
.replace('\n', "\\n")
|
|
26
|
+
.replace('\r', "\\r")
|
|
27
|
+
}
|
|
28
|
+
let js = format!("var id = '{}';", escape_js_string(user_input));
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
// ❌ Template injection
|
|
33
|
+
const html = `<div>${userInput}</div>`;
|
|
34
|
+
|
|
35
|
+
// ✅ Escape HTML entities
|
|
36
|
+
function escapeHtml(s: string): string {
|
|
37
|
+
return s.replace(/&/g, "&").replace(/</g, "<")
|
|
38
|
+
.replace(/>/g, ">").replace(/"/g, """);
|
|
39
|
+
}
|
|
40
|
+
const html = `<div>${escapeHtml(userInput)}</div>`;
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Context matters — escape for the target language
|
|
44
|
+
|
|
45
|
+
| Context | Escape | Characters |
|
|
46
|
+
|---------|--------|------------|
|
|
47
|
+
| HTML body | HTML entities | `& < > "` |
|
|
48
|
+
| HTML attribute | HTML entities + quote | `& < > " '` |
|
|
49
|
+
| JavaScript string | JS escapes | `\ ' " < > \n \r` |
|
|
50
|
+
| URL parameter | `encodeURIComponent` | All non-unreserved |
|
|
51
|
+
| SQL | Parameterized queries | Never interpolate |
|
|
52
|
+
| Shell command | Avoid if possible | Use `spawn(cmd, [args])` not `exec(string)` |
|
|
53
|
+
|
|
54
|
+
## Path Traversal
|
|
55
|
+
|
|
56
|
+
### Validate that resolved paths stay within the expected root
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
// ❌ User can escape with ../../etc/passwd
|
|
60
|
+
const filePath = join(rootDir, userInput);
|
|
61
|
+
|
|
62
|
+
// ✅ Resolve and verify containment
|
|
63
|
+
const resolved = resolve(rootDir, userInput);
|
|
64
|
+
if (!resolved.startsWith(resolve(rootDir) + sep) && resolved !== resolve(rootDir)) {
|
|
65
|
+
throw new Error("Path traversal attempt");
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
```rust
|
|
70
|
+
// ❌ No validation
|
|
71
|
+
let path = root.join(&user_path);
|
|
72
|
+
|
|
73
|
+
// ✅ Canonicalize and check prefix
|
|
74
|
+
let canonical = path.canonicalize()?;
|
|
75
|
+
if !canonical.starts_with(&root.canonicalize()?) {
|
|
76
|
+
return Err("Path traversal".into());
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Reject suspicious path components
|
|
81
|
+
|
|
82
|
+
- `..` segments
|
|
83
|
+
- Null bytes (`%00`, `\0`)
|
|
84
|
+
- Absolute paths when relative expected
|
|
85
|
+
- Symlinks that escape the root (use `canonicalize`/`realpath`)
|
|
86
|
+
|
|
87
|
+
## Process Spawning
|
|
88
|
+
|
|
89
|
+
### Use `spawn` with argument arrays, never shell interpolation
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
// ❌ Shell injection via userInput
|
|
93
|
+
execSync(`grep ${userInput} file.txt`);
|
|
94
|
+
|
|
95
|
+
// ✅ Arguments are not shell-interpreted
|
|
96
|
+
spawn("grep", [userInput, "file.txt"], { stdio: "pipe" });
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Never use `stdio: "inherit"` in TUI applications
|
|
100
|
+
|
|
101
|
+
Inherited stdio corrupts the terminal UI. Always use `"pipe"` or `"ignore"`.
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// ❌ Corrupts TUI
|
|
105
|
+
spawn("some-tool", [], { stdio: "inherit" });
|
|
106
|
+
|
|
107
|
+
// ✅ Capture or discard
|
|
108
|
+
spawn("some-tool", [], { stdio: "pipe" });
|
|
109
|
+
spawn("some-tool", [], { stdio: "ignore" }); // fire-and-forget
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Limit `pkill`/`killall` scope
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
// ❌ Matches any process with "serve" in its command line
|
|
116
|
+
execSync("pkill -f 'ollama serve'");
|
|
117
|
+
|
|
118
|
+
// ✅ Track the PID you spawned and kill that specifically
|
|
119
|
+
if (child) { child.kill("SIGTERM"); child = null; }
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Set timeouts on child processes
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
const child = spawn("cmd", args);
|
|
126
|
+
const timer = setTimeout(() => {
|
|
127
|
+
child.kill("SIGTERM");
|
|
128
|
+
}, 300_000); // 5 min timeout
|
|
129
|
+
|
|
130
|
+
child.on("exit", () => clearTimeout(timer));
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Dependency Integrity
|
|
134
|
+
|
|
135
|
+
### Pin CDN resources with Subresource Integrity (SRI)
|
|
136
|
+
|
|
137
|
+
```html
|
|
138
|
+
<!-- ❌ No integrity check — CDN compromise = XSS -->
|
|
139
|
+
<script src="https://cdn.example.com/lib.js"></script>
|
|
140
|
+
|
|
141
|
+
<!-- ✅ SRI hash — browser rejects tampered content -->
|
|
142
|
+
<script src="https://cdn.example.com/lib.js"
|
|
143
|
+
integrity="sha384-abc123..."
|
|
144
|
+
crossorigin="anonymous"></script>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Prefer bundling over CDN for offline-first tools
|
|
148
|
+
|
|
149
|
+
```rust
|
|
150
|
+
// ✅ Bundle at compile time — no network dependency
|
|
151
|
+
const JS: &str = include_str!("../static/lib.min.js");
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
// ✅ Import from node_modules, bundler handles it
|
|
156
|
+
import { force } from "force-graph";
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Secrets Management
|
|
160
|
+
|
|
161
|
+
- **Never hardcode secrets** — use environment variables or secret managers.
|
|
162
|
+
- **Never log secrets** — mask or omit sensitive values from log output.
|
|
163
|
+
- **Never commit secrets** — use `.gitignore` and pre-commit hooks.
|
|
164
|
+
- **Rotate on exposure** — if a secret appears in a commit, rotate immediately.
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
// ❌ Hardcoded
|
|
168
|
+
const apiKey = "sk-abc123";
|
|
169
|
+
|
|
170
|
+
// ✅ Environment variable
|
|
171
|
+
const apiKey = process.env.API_KEY;
|
|
172
|
+
if (!apiKey) throw new Error("API_KEY not set");
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## TOCTOU (Time-of-Check to Time-of-Use)
|
|
176
|
+
|
|
177
|
+
When you check a condition and then act on it, the condition may change between check and action.
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
// ❌ TOCTOU: file may be deleted between check and read
|
|
181
|
+
if (existsSync(path)) {
|
|
182
|
+
const data = readFileSync(path); // may throw ENOENT
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// ✅ Just try the operation and handle the error
|
|
186
|
+
try {
|
|
187
|
+
const data = readFileSync(path);
|
|
188
|
+
} catch (err) {
|
|
189
|
+
if ((err as NodeJS.ErrnoException).code === "ENOENT") {
|
|
190
|
+
// file doesn't exist — handle gracefully
|
|
191
|
+
} else throw err;
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Checklist
|
|
196
|
+
|
|
197
|
+
Before submitting code that handles external input:
|
|
198
|
+
|
|
199
|
+
- [ ] All user/external input is escaped for its target context
|
|
200
|
+
- [ ] File paths are validated against a root directory
|
|
201
|
+
- [ ] Child processes use argument arrays, not shell strings
|
|
202
|
+
- [ ] No `stdio: "inherit"` in TUI-hosted code
|
|
203
|
+
- [ ] CDN resources have SRI hashes or are bundled locally
|
|
204
|
+
- [ ] No secrets in source code or logs
|
|
205
|
+
- [ ] Error messages don't leak internal paths or stack traces to end users
|
|
206
|
+
- [ ] Timeouts set on all network requests and child processes
|