@rune-kit/rune 2.3.3 → 2.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.
Files changed (77) hide show
  1. package/README.md +86 -17
  2. package/compiler/__tests__/pack-split.test.js +141 -1
  3. package/compiler/__tests__/parser.test.js +147 -55
  4. package/compiler/__tests__/scripts-bundling.test.js +283 -0
  5. package/compiler/__tests__/skill-index.test.js +218 -0
  6. package/compiler/__tests__/tier-override.test.js +41 -0
  7. package/compiler/adapters/antigravity.js +71 -53
  8. package/compiler/adapters/codex.js +4 -0
  9. package/compiler/adapters/cursor.js +4 -0
  10. package/compiler/adapters/generic.js +4 -0
  11. package/compiler/adapters/openclaw.js +4 -0
  12. package/compiler/adapters/opencode.js +4 -0
  13. package/compiler/adapters/windsurf.js +4 -0
  14. package/compiler/bin/rune.js +355 -355
  15. package/compiler/doctor.js +11 -1
  16. package/compiler/emitter.js +678 -386
  17. package/compiler/parser.js +267 -247
  18. package/compiler/transforms/scripts-path.js +18 -0
  19. package/extensions/zalo/PACK.md +20 -1
  20. package/extensions/zalo/references/conversation-management.md +214 -0
  21. package/extensions/zalo/references/eval-scenarios.md +157 -0
  22. package/extensions/zalo/references/listen-mode.md +237 -0
  23. package/extensions/zalo/references/mcp-production.md +274 -0
  24. package/extensions/zalo/references/multi-account-proxy.md +224 -0
  25. package/extensions/zalo/references/vietqr-banking.md +160 -0
  26. package/hooks/hooks.json +12 -0
  27. package/hooks/intent-router/index.cjs +108 -0
  28. package/hooks/pre-tool-guard/index.cjs +177 -68
  29. package/package.json +63 -64
  30. package/skills/brainstorm/SKILL.md +2 -0
  31. package/skills/cook/SKILL.md +661 -648
  32. package/skills/debug/SKILL.md +394 -392
  33. package/skills/deploy/SKILL.md +2 -0
  34. package/skills/fix/SKILL.md +283 -281
  35. package/skills/marketing/SKILL.md +3 -0
  36. package/skills/onboard/SKILL.md +7 -0
  37. package/skills/plan/SKILL.md +344 -342
  38. package/skills/preflight/SKILL.md +362 -360
  39. package/skills/review/SKILL.md +491 -489
  40. package/skills/scout/SKILL.md +1 -0
  41. package/skills/sentinel/SKILL.md +319 -296
  42. package/skills/sentinel/references/auth-crypto-reference.md +192 -0
  43. package/skills/sentinel/references/desktop-security.md +201 -0
  44. package/skills/sentinel/references/supply-chain.md +160 -0
  45. package/skills/session-bridge/SKILL.md +1 -0
  46. package/skills/slides/SKILL.md +142 -0
  47. package/skills/slides/scripts/build-deck.js +158 -0
  48. package/skills/team/SKILL.md +1 -0
  49. package/skills/test/SKILL.md +587 -585
  50. package/skills/verification/SKILL.md +1 -0
  51. package/skills/watchdog/SKILL.md +2 -0
  52. package/docs/ANTIGRAVITY-GAP-ANALYSIS.md +0 -369
  53. package/docs/ARCHITECTURE.md +0 -332
  54. package/docs/COMMUNITY-PACKS.md +0 -109
  55. package/docs/CONTRIBUTING-L4.md +0 -215
  56. package/docs/CROSS-IDE-ANALYSIS.md +0 -164
  57. package/docs/EXTENSION-TEMPLATE.md +0 -126
  58. package/docs/MESH-RULES.md +0 -34
  59. package/docs/MULTI-PLATFORM.md +0 -804
  60. package/docs/SKILL-DEPTH-AUDIT.md +0 -191
  61. package/docs/SKILL-TEMPLATE.md +0 -118
  62. package/docs/TRADE-MATRIX.md +0 -327
  63. package/docs/VERSIONING.md +0 -91
  64. package/docs/VISION.md +0 -263
  65. package/docs/assets/demo-subtitles.srt +0 -215
  66. package/docs/assets/end-card.html +0 -276
  67. package/docs/assets/mesh-diagram.html +0 -654
  68. package/docs/assets/thumbnail.html +0 -295
  69. package/docs/guides/cli.md +0 -403
  70. package/docs/guides/index.html +0 -1450
  71. package/docs/index.html +0 -1005
  72. package/docs/references/claudekit-analysis.md +0 -414
  73. package/docs/references/voltagent-analysis.md +0 -189
  74. package/docs/script.js +0 -495
  75. package/docs/skills/index.html +0 -832
  76. package/docs/style.css +0 -958
  77. package/docs/video-demo-plan.md +0 -172
@@ -0,0 +1,192 @@
1
+ # Auth & Cryptography Reference
2
+
3
+ > Loaded by `sentinel` when authentication, password hashing, encryption, or token management patterns detected.
4
+
5
+ ---
6
+
7
+ ## Password Hashing
8
+
9
+ ### Recommended: Argon2id
10
+
11
+ ```javascript
12
+ import { hash, verify } from '@node-rs/argon2';
13
+
14
+ // Hash — use these parameters minimum
15
+ const hashed = await hash(password, {
16
+ memoryCost: 65536, // 64 MB
17
+ timeCost: 3, // 3 iterations
18
+ parallelism: 4, // 4 threads
19
+ outputLen: 32, // 32 bytes
20
+ });
21
+
22
+ // Verify
23
+ const valid = await verify(hashed, password);
24
+ ```
25
+
26
+ ### Acceptable: bcrypt
27
+
28
+ ```javascript
29
+ import bcrypt from 'bcrypt';
30
+
31
+ const ROUNDS = 12; // minimum 12, never below 10
32
+ const hashed = await bcrypt.hash(password, ROUNDS);
33
+ const valid = await bcrypt.compare(password, hashed);
34
+ ```
35
+
36
+ ### Severity Table
37
+
38
+ | Algorithm | Verdict | Action |
39
+ |-----------|---------|--------|
40
+ | Argon2id | PASS | Preferred |
41
+ | bcrypt (rounds ≥ 12) | PASS | Acceptable |
42
+ | bcrypt (rounds < 10) | WARN | Increase rounds |
43
+ | scrypt | WARN | Prefer Argon2id |
44
+ | SHA-256/SHA-512 + salt | BLOCK | Not a password hash |
45
+ | MD5 / SHA-1 | BLOCK | Broken, must replace |
46
+ | Plaintext | BLOCK | Critical vulnerability |
47
+
48
+ ---
49
+
50
+ ## JWT Best Practices
51
+
52
+ ### Token Lifecycle
53
+
54
+ ```javascript
55
+ // Access token: short-lived (15 min)
56
+ const accessToken = jwt.sign(
57
+ { sub: user.id, role: user.role },
58
+ process.env.JWT_SECRET,
59
+ { expiresIn: '15m', algorithm: 'HS256' }
60
+ );
61
+
62
+ // Refresh token: longer (7 days), stored in HttpOnly cookie
63
+ const refreshToken = jwt.sign(
64
+ { sub: user.id, type: 'refresh' },
65
+ process.env.JWT_REFRESH_SECRET,
66
+ { expiresIn: '7d' }
67
+ );
68
+
69
+ res.cookie('refresh_token', refreshToken, {
70
+ httpOnly: true, // No JavaScript access
71
+ secure: true, // HTTPS only
72
+ sameSite: 'strict', // No cross-site
73
+ maxAge: 7 * 24 * 60 * 60 * 1000,
74
+ path: '/api/auth/refresh', // Only sent to refresh endpoint
75
+ });
76
+ ```
77
+
78
+ ### JWT BLOCK Patterns
79
+
80
+ | Pattern | Severity | Fix |
81
+ |---------|----------|-----|
82
+ | `algorithm: 'none'` | BLOCK | Always specify algorithm |
83
+ | No `expiresIn` | BLOCK | Tokens MUST expire |
84
+ | Secret < 32 chars | WARN | Use 256-bit minimum |
85
+ | JWT in localStorage | WARN | Use HttpOnly cookie for refresh |
86
+ | No audience/issuer validation | WARN | Add `aud` and `iss` claims |
87
+
88
+ ---
89
+
90
+ ## OAuth2 with PKCE
91
+
92
+ ```javascript
93
+ // 1. Generate PKCE challenge
94
+ const codeVerifier = crypto.randomBytes(32).toString('base64url');
95
+ const codeChallenge = crypto
96
+ .createHash('sha256')
97
+ .update(codeVerifier)
98
+ .digest('base64url');
99
+
100
+ // 2. Authorization URL
101
+ const authUrl = new URL('https://provider.com/authorize');
102
+ authUrl.searchParams.set('response_type', 'code');
103
+ authUrl.searchParams.set('client_id', CLIENT_ID);
104
+ authUrl.searchParams.set('redirect_uri', REDIRECT_URI);
105
+ authUrl.searchParams.set('code_challenge', codeChallenge);
106
+ authUrl.searchParams.set('code_challenge_method', 'S256');
107
+ authUrl.searchParams.set('state', crypto.randomBytes(16).toString('hex'));
108
+
109
+ // 3. Exchange code (callback) — include code_verifier
110
+ const tokenResponse = await fetch('https://provider.com/token', {
111
+ method: 'POST',
112
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
113
+ body: new URLSearchParams({
114
+ grant_type: 'authorization_code',
115
+ code: authorizationCode,
116
+ redirect_uri: REDIRECT_URI,
117
+ client_id: CLIENT_ID,
118
+ code_verifier: codeVerifier, // Proves we initiated the flow
119
+ }),
120
+ });
121
+ ```
122
+
123
+ ---
124
+
125
+ ## Encryption (Data at Rest)
126
+
127
+ ### AES-256-GCM (Recommended)
128
+
129
+ ```javascript
130
+ import { createCipheriv, createDecipheriv, randomBytes } from 'crypto';
131
+
132
+ const ALGORITHM = 'aes-256-gcm';
133
+ const KEY = Buffer.from(process.env.ENCRYPTION_KEY, 'hex'); // 32 bytes
134
+
135
+ function encrypt(plaintext) {
136
+ const iv = randomBytes(16);
137
+ const cipher = createCipheriv(ALGORITHM, KEY, iv);
138
+ const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
139
+ const tag = cipher.getAuthTag();
140
+ // Store: iv + tag + ciphertext (all needed for decryption)
141
+ return Buffer.concat([iv, tag, encrypted]).toString('base64');
142
+ }
143
+
144
+ function decrypt(encoded) {
145
+ const buffer = Buffer.from(encoded, 'base64');
146
+ const iv = buffer.subarray(0, 16);
147
+ const tag = buffer.subarray(16, 32);
148
+ const ciphertext = buffer.subarray(32);
149
+ const decipher = createDecipheriv(ALGORITHM, KEY, iv);
150
+ decipher.setAuthTag(tag);
151
+ return decipher.update(ciphertext) + decipher.final('utf8');
152
+ }
153
+ ```
154
+
155
+ ### Crypto Rules
156
+
157
+ | Use Case | Algorithm | BLOCK If |
158
+ |----------|-----------|----------|
159
+ | Password storage | Argon2id / bcrypt | MD5, SHA-*, plaintext |
160
+ | Data encryption | AES-256-GCM | AES-ECB, DES, RC4 |
161
+ | Integrity check | SHA-256 | MD5, SHA-1 |
162
+ | Signatures | HMAC-SHA256 | Custom MAC |
163
+ | Random tokens | `crypto.randomBytes()` | `Math.random()` |
164
+ | Key derivation | scrypt / HKDF | Simple hash |
165
+
166
+ ---
167
+
168
+ ## Fail-Closed Principle
169
+
170
+ Errors MUST deny access, never grant it:
171
+
172
+ ```javascript
173
+ // BAD: fail-open — error grants access
174
+ function authorize(user) {
175
+ try {
176
+ return checkPermission(user);
177
+ } catch {
178
+ return true; // BLOCK: error = access granted
179
+ }
180
+ }
181
+
182
+ // GOOD: fail-closed — error denies access
183
+ function authorize(user) {
184
+ try {
185
+ return checkPermission(user);
186
+ } catch {
187
+ return false; // Error = denied
188
+ }
189
+ }
190
+ ```
191
+
192
+ **BLOCK pattern**: Any catch/except block that returns `true`, `next()`, or allows continuation on auth/permission check failure.
@@ -0,0 +1,201 @@
1
+ # Desktop App Security Reference
2
+
3
+ > Loaded by `sentinel` when Electron or Tauri project detected (package.json contains `electron`, `@tauri-apps/cli`, or `tauri.conf.json` exists).
4
+
5
+ ---
6
+
7
+ ## Electron Security
8
+
9
+ ### Secure BrowserWindow Config
10
+
11
+ Every BrowserWindow MUST use:
12
+
13
+ ```javascript
14
+ const win = new BrowserWindow({
15
+ webPreferences: {
16
+ contextIsolation: true, // REQUIRED — separates preload from page
17
+ nodeIntegration: false, // REQUIRED — no Node in renderer
18
+ sandbox: true, // REQUIRED — OS-level sandbox
19
+ webSecurity: true, // REQUIRED — enforce same-origin
20
+ allowRunningInsecureContent: false,
21
+ experimentalFeatures: false,
22
+ }
23
+ });
24
+ ```
25
+
26
+ **BLOCK if any of these are wrong:**
27
+ - `contextIsolation: false` — renderer can access Node APIs
28
+ - `nodeIntegration: true` — XSS = full system compromise
29
+ - `sandbox: false` — no OS isolation
30
+ - `webSecurity: false` — disables same-origin policy
31
+
32
+ ### Preload Script (Minimal Surface)
33
+
34
+ Expose only specific functions, never blanket APIs:
35
+
36
+ ```javascript
37
+ // preload.js — GOOD: minimal, typed API
38
+ const { contextBridge, ipcRenderer } = require('electron');
39
+
40
+ contextBridge.exposeInMainWorld('api', {
41
+ readFile: (path) => ipcRenderer.invoke('fs:read', path),
42
+ saveFile: (path, data) => ipcRenderer.invoke('fs:save', path, data),
43
+ // NEVER expose: ipcRenderer.send, ipcRenderer.on, require, process
44
+ });
45
+ ```
46
+
47
+ ### IPC Validation
48
+
49
+ Validate BOTH sender identity and message content:
50
+
51
+ ```javascript
52
+ // main.js — validate IPC
53
+ ipcMain.handle('fs:read', async (event, filePath) => {
54
+ // 1. Verify sender
55
+ if (event.senderFrame.url !== 'app://./index.html') {
56
+ throw new Error('Unauthorized IPC sender');
57
+ }
58
+
59
+ // 2. Validate input
60
+ const resolved = path.resolve(filePath);
61
+ if (!resolved.startsWith(ALLOWED_DIR)) {
62
+ throw new Error('Path traversal blocked');
63
+ }
64
+
65
+ return fs.readFileSync(resolved, 'utf-8');
66
+ });
67
+ ```
68
+
69
+ ### Deep Link Validation
70
+
71
+ ```javascript
72
+ // Validate protocol handler input
73
+ app.setAsDefaultProtocolClient('myapp');
74
+
75
+ app.on('open-url', (event, url) => {
76
+ event.preventDefault();
77
+
78
+ const parsed = new URL(url);
79
+ const ALLOWED_HOSTS = ['app.example.com'];
80
+ const ALLOWED_PROTOCOLS = ['myapp:'];
81
+
82
+ if (!ALLOWED_PROTOCOLS.includes(parsed.protocol)) return;
83
+ if (parsed.host && !ALLOWED_HOSTS.includes(parsed.host)) return;
84
+ if (url.length > 2048) return; // Length limit
85
+
86
+ handleDeepLink(parsed);
87
+ });
88
+ ```
89
+
90
+ ### Electron Vulnerability Checklist
91
+
92
+ | Check | BLOCK if |
93
+ |-------|----------|
94
+ | `nodeIntegration` | `true` in any window |
95
+ | `contextIsolation` | `false` in any window |
96
+ | `sandbox` | `false` in any window |
97
+ | `webSecurity` | `false` |
98
+ | Preload exposes `ipcRenderer.send` | Direct IPC channel exposed |
99
+ | IPC handler missing sender check | No `event.senderFrame` validation |
100
+ | `shell.openExternal` unvalidated | User-controlled URLs passed directly |
101
+ | Auto-updater over HTTP | Not using HTTPS or missing signature check |
102
+ | `webview` tag without sandbox | Embedded content without isolation |
103
+ | Deep links unvalidated | No protocol/host allowlist |
104
+
105
+ ---
106
+
107
+ ## Tauri Security
108
+
109
+ ### Command Security
110
+
111
+ ```rust
112
+ // GOOD: Strict typing + validation
113
+ #[tauri::command]
114
+ fn read_file(path: String) -> Result<String, String> {
115
+ let canonical = std::fs::canonicalize(&path)
116
+ .map_err(|e| e.to_string())?;
117
+
118
+ // Validate path is within allowed directory
119
+ if !canonical.starts_with("/allowed/dir") {
120
+ return Err("Access denied".into());
121
+ }
122
+
123
+ std::fs::read_to_string(canonical)
124
+ .map_err(|e| e.to_string())
125
+ }
126
+ ```
127
+
128
+ ### Scope Configuration
129
+
130
+ ```json
131
+ // tauri.conf.json — restrictive scopes
132
+ {
133
+ "tauri": {
134
+ "allowlist": {
135
+ "fs": {
136
+ "scope": ["$APPDATA/*", "$RESOURCE/*"],
137
+ "readFile": true,
138
+ "writeFile": true
139
+ },
140
+ "http": {
141
+ "scope": ["https://api.example.com/*"]
142
+ },
143
+ "shell": {
144
+ "open": true,
145
+ "scope": []
146
+ }
147
+ }
148
+ }
149
+ }
150
+ ```
151
+
152
+ **BLOCK if:**
153
+ - `fs.scope: ["**"]` — unrestricted filesystem access
154
+ - `http.scope: ["https://**"]` — any HTTPS target
155
+ - `shell.scope` contains executable paths without validation
156
+
157
+ ### Tauri Vulnerability Checklist
158
+
159
+ | Check | BLOCK if |
160
+ |-------|----------|
161
+ | `fs.scope` | Contains `**` or `/` (unrestricted) |
162
+ | `http.scope` | Broad wildcard allowing arbitrary hosts |
163
+ | `shell` commands | Unrestricted `execute` scope |
164
+ | CSP missing | No Content-Security-Policy in `tauri.conf.json` |
165
+ | `invoke()` handler | Missing input validation or type checking |
166
+
167
+ ---
168
+
169
+ ## Common Desktop Patterns
170
+
171
+ ### Code Signing
172
+
173
+ Always sign releases — unsigned apps trigger OS warnings and can be tampered with:
174
+
175
+ - **Windows**: EV code signing certificate (hardware token)
176
+ - **macOS**: Developer ID certificate + notarization (`xcrun notarytool`)
177
+ - **Linux**: GPG signing for packages
178
+
179
+ ### Secure Auto-Update
180
+
181
+ ```
182
+ 1. Check for update over HTTPS
183
+ 2. Verify digital signature of update package
184
+ 3. Verify SHA-256 checksum
185
+ 4. Prompt user before installing (never silent)
186
+ 5. Graceful fallback if update fails
187
+ ```
188
+
189
+ ### Credential Storage
190
+
191
+ ```javascript
192
+ // Electron — use safeStorage (OS keychain)
193
+ const { safeStorage } = require('electron');
194
+
195
+ if (safeStorage.isEncryptionAvailable()) {
196
+ const encrypted = safeStorage.encryptString(token);
197
+ // Store encrypted buffer, never plaintext
198
+ }
199
+ ```
200
+
201
+ **BLOCK**: Storing credentials in `localStorage`, plain files, or `electron-store` without encryption.
@@ -0,0 +1,160 @@
1
+ # Supply Chain Security Reference
2
+
3
+ > Loaded by `sentinel` when dependency changes detected (package.json, package-lock.json, requirements.txt, Cargo.toml modified).
4
+
5
+ ---
6
+
7
+ ## Dependency Audit
8
+
9
+ ### Required Checks
10
+
11
+ On every dependency change, verify:
12
+
13
+ ```bash
14
+ # Node.js
15
+ npm audit --audit-level=high
16
+ npm audit signatures # Verify registry signatures
17
+
18
+ # Python
19
+ pip-audit
20
+ safety check
21
+
22
+ # Rust
23
+ cargo audit
24
+ ```
25
+
26
+ **BLOCK**: Any `high` or `critical` severity vulnerability in direct dependencies.
27
+ **WARN**: `high`/`critical` in transitive dependencies.
28
+
29
+ ---
30
+
31
+ ## Lock File Rules
32
+
33
+ | Rule | Severity |
34
+ |------|----------|
35
+ | Lock file not committed | BLOCK |
36
+ | Lock file deleted | BLOCK |
37
+ | Lock file modified without package.json change | WARN (investigate) |
38
+ | Multiple lock files (package-lock + yarn.lock) | WARN |
39
+
40
+ Lock files pin exact versions. Without them, builds are non-reproducible and vulnerable to supply chain attacks.
41
+
42
+ ---
43
+
44
+ ## Typosquatting Prevention
45
+
46
+ Before adding ANY new dependency, check:
47
+
48
+ | Signal | Example | Risk |
49
+ |--------|---------|------|
50
+ | Name differs by 1 char | `lodsh` vs `lodash` | Typosquat |
51
+ | Extra hyphen/underscore | `react-domm` | Typosquat |
52
+ | Scoped look-alike | `@react/core` vs `react` | Impersonation |
53
+ | Very new package | Published < 7 days ago | Suspicious |
54
+ | Low download count | < 100 weekly downloads | Unvetted |
55
+ | No repository URL | Missing `repository` field | Cannot verify source |
56
+
57
+ ### Scan Pattern
58
+
59
+ ```javascript
60
+ // sentinel should flag new dependencies added to package.json
61
+ // Check against known package names for close matches
62
+ const KNOWN_PACKAGES = ['lodash', 'express', 'react', 'axios', ...];
63
+
64
+ function checkTyposquat(name) {
65
+ for (const known of KNOWN_PACKAGES) {
66
+ if (levenshteinDistance(name, known) === 1) {
67
+ return { risk: 'HIGH', similar: known };
68
+ }
69
+ }
70
+ }
71
+ ```
72
+
73
+ ---
74
+
75
+ ## Version Pinning Strategy
76
+
77
+ | Dependency Type | Strategy | Why |
78
+ |----------------|----------|-----|
79
+ | Direct (production) | `^` semver (default) | Balance updates + stability |
80
+ | Security-critical | Exact pin (`1.2.3`) | Prevent unexpected changes |
81
+ | Dev tools | `^` semver | Less risk, want updates |
82
+ | CDN resources | SRI hash required | Tamper detection |
83
+
84
+ ### Subresource Integrity (SRI)
85
+
86
+ For any CDN-loaded script or stylesheet:
87
+
88
+ ```html
89
+ <!-- GOOD: SRI hash verifies integrity -->
90
+ <script
91
+ src="https://cdn.example.com/lib.js"
92
+ integrity="sha384-abc123..."
93
+ crossorigin="anonymous"
94
+ ></script>
95
+
96
+ <!-- BLOCK: CDN resource without SRI -->
97
+ <script src="https://cdn.example.com/lib.js"></script>
98
+ ```
99
+
100
+ ---
101
+
102
+ ## npm Security Hardening
103
+
104
+ | Practice | Priority |
105
+ |----------|----------|
106
+ | Enable 2FA on npm account | BLOCK (maintainers) |
107
+ | Use scoped packages (`@org/pkg`) | Recommended |
108
+ | `npm audit` in CI pipeline | Required |
109
+ | `npm audit signatures` | Recommended |
110
+ | Review `postinstall` scripts | Required for new deps |
111
+ | Use `--ignore-scripts` for untrusted packages | Recommended |
112
+
113
+ ### Dangerous Install Scripts
114
+
115
+ **WARN** when a newly added package has `postinstall`, `preinstall`, or `install` scripts:
116
+
117
+ ```json
118
+ // package.json of dependency — review these carefully
119
+ {
120
+ "scripts": {
121
+ "postinstall": "node setup.js" // What does this run?
122
+ }
123
+ }
124
+ ```
125
+
126
+ ---
127
+
128
+ ## Automated Dependency Updates
129
+
130
+ Configure one of:
131
+
132
+ ```yaml
133
+ # .github/dependabot.yml
134
+ version: 2
135
+ updates:
136
+ - package-ecosystem: npm
137
+ directory: /
138
+ schedule:
139
+ interval: weekly
140
+ open-pull-requests-limit: 10
141
+ reviewers:
142
+ - security-team
143
+ ```
144
+
145
+ **WARN** if no automated dependency update tool is configured (Dependabot, Renovate, or Snyk).
146
+
147
+ ---
148
+
149
+ ## Security Checklist for New Dependencies
150
+
151
+ Before approving a new dependency:
152
+
153
+ - [ ] Package name is correct (not a typosquat)
154
+ - [ ] Has significant download count (>1K/week for niche, >10K for common)
155
+ - [ ] Repository URL exists and matches claimed source
156
+ - [ ] No known vulnerabilities (`npm audit`)
157
+ - [ ] License is compatible
158
+ - [ ] Install scripts reviewed (if any)
159
+ - [ ] Maintainer has 2FA enabled (check npm profile)
160
+ - [ ] Not abandoned (last publish < 12 months)
@@ -8,6 +8,7 @@ metadata:
8
8
  model: haiku
9
9
  group: state
10
10
  tools: "Read, Write, Edit, Glob, Grep"
11
+ listen: phase.complete
11
12
  ---
12
13
 
13
14
  # session-bridge
@@ -0,0 +1,142 @@
1
+ ---
2
+ name: slides
3
+ description: Generate Marp-compatible slide decks from structured JSON schema. Converts context into presentations for tech talks, sprint demos, and tutorials.
4
+ metadata:
5
+ author: runedev
6
+ version: "0.1.0"
7
+ layer: L3
8
+ model: sonnet
9
+ group: media
10
+ tools: "Read, Write, Bash"
11
+ ---
12
+
13
+ # slides
14
+
15
+ ## Purpose
16
+
17
+ Generates structured slide decks as Marp-compatible markdown. The agent analyzes context (feature, sprint, tutorial) and produces a JSON slide schema, then calls `build-deck.js` to convert it to presentation-ready markdown. The script standardizes output format — preventing agent freestyle errors when context runs low.
18
+
19
+ ## Triggers
20
+
21
+ - User says "create slides", "make presentation", "demo deck", "sprint review slides", "tech talk"
22
+ - `/rune slides` — manual invocation
23
+ - Called by other skills needing presentation output
24
+
25
+ ## Called By (inbound)
26
+
27
+ - `marketing` (L2): launch presentations, product demos
28
+ - `video-creator` (L3): slide-based video storyboards
29
+ - User: direct invocation
30
+
31
+ ## Calls (outbound)
32
+
33
+ None — pure L3 utility.
34
+
35
+ ## Executable Instructions
36
+
37
+ ### Step 1: Analyze Context
38
+
39
+ Determine the presentation type from the user's request:
40
+
41
+ | Context | Template | Typical Slides |
42
+ |---------|----------|---------------|
43
+ | Feature demo | Demo walkthrough | Problem → Solution → Architecture → Live demo → Next steps |
44
+ | Sprint review | Sprint summary | Goals → Completed → Metrics → Blockers → Next sprint |
45
+ | Tech talk | Teaching format | Hook → Concept → Deep dive → Code examples → Takeaways |
46
+ | Tutorial | Step-by-step | Intro → Prerequisites → Step 1-N → Summary → Resources |
47
+ | Pitch | Persuasion | Problem → Market → Solution → Traction → Ask |
48
+
49
+ ### Step 2: Generate JSON Schema
50
+
51
+ Create a JSON file following this schema:
52
+
53
+ ```json
54
+ {
55
+ "title": "Presentation Title",
56
+ "author": "Author Name (optional)",
57
+ "theme": "default|gaia|uncover",
58
+ "slides": [
59
+ {
60
+ "type": "title|content|code|diagram|image|quote|section",
61
+ "heading": "Slide Heading",
62
+ "body": "Markdown body text",
63
+ "notes": "Speaker notes (optional)",
64
+ "code": { "lang": "javascript", "source": "console.log('hi')" },
65
+ "diagram": "graph LR; A-->B"
66
+ }
67
+ ]
68
+ }
69
+ ```
70
+
71
+ **Slide types:**
72
+ - `title` — opening slide with `# heading`
73
+ - `content` — standard slide with `## heading` + body
74
+ - `code` — slide with syntax-highlighted code block
75
+ - `diagram` — slide with Mermaid diagram
76
+ - `image` — slide with image reference in body
77
+ - `quote` — slide with blockquote formatting
78
+ - `section` — section divider with `# heading`
79
+
80
+ Save the JSON to a temporary file (e.g., `slides.json`).
81
+
82
+ ### Step 3: Build Deck
83
+
84
+ Execute the build script:
85
+
86
+ ```bash
87
+ node {scripts_dir}/build-deck.js --input slides.json --output deck.md
88
+ ```
89
+
90
+ The script outputs Marp-compatible markdown with:
91
+ - Marp frontmatter (`marp: true`, theme)
92
+ - Slide separators (`---`)
93
+ - Speaker notes as HTML comments
94
+ - Code blocks with language hints
95
+ - Mermaid diagram blocks
96
+
97
+ ### Step 4: Present Result
98
+
99
+ Show the user:
100
+ 1. The generated `deck.md` file path
101
+ 2. How to preview: `npx @marp-team/marp-cli deck.md --preview` (or any Marp viewer)
102
+ 3. How to export PDF: `npx @marp-team/marp-cli deck.md --pdf`
103
+
104
+ **Fallback**: If `{scripts_dir}/build-deck.js` is unavailable, generate the Marp markdown directly — the script is an optimization, not a hard dependency.
105
+
106
+ ## Output Format
107
+
108
+ ```markdown
109
+ ---
110
+ marp: true
111
+ theme: default
112
+ ---
113
+
114
+ # Presentation Title
115
+
116
+ Author Name
117
+
118
+ ---
119
+
120
+ ## Slide Heading
121
+
122
+ Slide body content
123
+
124
+ <!-- notes: Speaker notes here -->
125
+ ```
126
+
127
+ ## Sharp Edges
128
+
129
+ | Failure Mode | Severity | Mitigation |
130
+ |---|---|---|
131
+ | build-deck.js not found | LOW | Agent generates Marp markdown directly (fallback) |
132
+ | Invalid JSON input | MEDIUM | Script exits 1 with parse error — agent fixes JSON and retries |
133
+ | Marp not installed | LOW | Script outputs plain .md — user installs Marp CLI separately |
134
+ | Too many slides (>30) | MEDIUM | Agent should split into multiple decks or summarize |
135
+
136
+ ## Constraints
137
+
138
+ 1. Output MUST be valid Marp markdown (parseable by `@marp-team/marp-cli`)
139
+ 2. DO NOT embed build-deck.js source in this skill — call it via `{scripts_dir}`
140
+ 3. DO NOT require Marp installation — output is standard markdown that Marp can consume
141
+ 4. Keep slide count reasonable (5-15 for demos, 10-25 for talks)
142
+ 5. Always include speaker notes for non-trivial slides