opencode-skills-collection 3.1.6 → 3.1.8
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/bundled-skills/.antigravity-install-manifest.json +9 -1
- package/bundled-skills/007/scripts/scanners/dependency_scanner.py +2 -2
- package/bundled-skills/arrowspace/SKILL.md +116 -0
- package/bundled-skills/docs/contributors/quality-bar.md +1 -0
- package/bundled-skills/docs/contributors/skill-anatomy.md +19 -3
- package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
- package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
- package/bundled-skills/docs/maintainers/categorization-implementation.md +14 -24
- package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
- package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
- package/bundled-skills/docs/maintainers/smart-auto-categorization.md +24 -25
- package/bundled-skills/docs/users/bundles.md +1 -1
- package/bundled-skills/docs/users/claude-code-skills.md +1 -1
- package/bundled-skills/docs/users/faq.md +5 -5
- package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
- package/bundled-skills/docs/users/getting-started.md +1 -1
- package/bundled-skills/docs/users/kiro-integration.md +1 -1
- package/bundled-skills/docs/users/local-config.md +11 -11
- package/bundled-skills/docs/users/specialized-plugin-roadmap.md +3 -3
- package/bundled-skills/docs/users/usage.md +4 -4
- package/bundled-skills/docs/users/visual-guide.md +4 -4
- package/bundled-skills/docs/vietnamese/BUNDLES.vi.md +1 -1
- package/bundled-skills/docs/vietnamese/CONTRIBUTING.vi.md +15 -9
- package/bundled-skills/docs/vietnamese/FAQ.vi.md +30 -20
- package/bundled-skills/docs/vietnamese/GETTING_STARTED.vi.md +22 -14
- package/bundled-skills/docs/vietnamese/QUALITY_BAR.vi.md +9 -4
- package/bundled-skills/docs/vietnamese/README.vi.md +29 -30
- package/bundled-skills/docs/vietnamese/SKILLS_README.vi.md +3 -3
- package/bundled-skills/docs/vietnamese/SKILL_ANATOMY.vi.md +33 -5
- package/bundled-skills/docs/vietnamese/TRANSLATION_PLAN.vi.md +1 -1
- package/bundled-skills/docs/vietnamese/VISUAL_GUIDE.vi.md +17 -18
- package/bundled-skills/docx-official/ooxml/scripts/pack.py +12 -0
- package/bundled-skills/docx-official/ooxml/scripts/unpack.py +28 -7
- package/bundled-skills/docx-official/ooxml/scripts/validation/base.py +18 -13
- package/bundled-skills/docx-official/ooxml/scripts/validation/docx.py +6 -6
- package/bundled-skills/docx-official/ooxml/scripts/validation/pptx.py +6 -6
- package/bundled-skills/emil-design-eng/SKILL.md +702 -0
- package/bundled-skills/gh-image/SKILL.md +122 -0
- package/bundled-skills/github-actions-debugger/SKILL.md +99 -0
- package/bundled-skills/hugging-face-model-trainer/scripts/convert_to_gguf.py +3 -2
- package/bundled-skills/infinity/SKILL.md +173 -0
- package/bundled-skills/loki-mode/autonomy/run.sh +17 -8
- package/bundled-skills/loki-mode/examples/todo-app-generated/backend/package-lock.json +17 -13
- package/bundled-skills/loki-mode/examples/todo-app-generated/backend/package.json +3 -3
- package/bundled-skills/loki-mode/examples/todo-app-generated/frontend/package-lock.json +9 -9
- package/bundled-skills/loki-mode/examples/todo-app-generated/frontend/package.json +2 -2
- package/bundled-skills/macos-spm-app-packaging/assets/templates/setup_dev_signing.sh +11 -8
- package/bundled-skills/macos-spm-app-packaging/assets/templates/sign-and-notarize.sh +10 -5
- package/bundled-skills/pptx-official/ooxml/scripts/pack.py +12 -0
- package/bundled-skills/pptx-official/ooxml/scripts/unpack.py +28 -7
- package/bundled-skills/pptx-official/ooxml/scripts/validation/base.py +18 -13
- package/bundled-skills/pptx-official/ooxml/scripts/validation/docx.py +6 -6
- package/bundled-skills/pptx-official/ooxml/scripts/validation/pptx.py +6 -6
- package/bundled-skills/premium-3d-website/SKILL.md +133 -0
- package/bundled-skills/review-animations/SKILL.md +139 -0
- package/bundled-skills/review-animations/STANDARDS.md +188 -0
- package/bundled-skills/skill-creator/scripts/package_skill.py +11 -1
- package/package.json +1 -1
- package/skills_index.json +132 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gh-image
|
|
3
|
+
description: "Upload local images to GitHub and get canonical user-attachments embed URLs; use when asked to attach a screenshot to a PR, issue, or comment, or to embed before/after images in a README."
|
|
4
|
+
category: developer-tools
|
|
5
|
+
risk: safe
|
|
6
|
+
source: community
|
|
7
|
+
source_type: community
|
|
8
|
+
source_repo: drogers0/gh-image
|
|
9
|
+
date_added: "2026-06-25"
|
|
10
|
+
author: drogers0
|
|
11
|
+
license: MIT
|
|
12
|
+
license_source: "https://github.com/drogers0/gh-image/blob/main/LICENSE"
|
|
13
|
+
tags:
|
|
14
|
+
- github
|
|
15
|
+
- images
|
|
16
|
+
- screenshots
|
|
17
|
+
- gh-extension
|
|
18
|
+
- cli
|
|
19
|
+
tools:
|
|
20
|
+
- claude-code
|
|
21
|
+
- codex-cli
|
|
22
|
+
- cursor
|
|
23
|
+
- gemini-cli
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# Upload images to GitHub (gh-image)
|
|
27
|
+
|
|
28
|
+
GitHub has **no public API** for image uploads — the web UI uses an internal
|
|
29
|
+
endpoint that mints `user-attachments` URLs scoped to the repo's visibility.
|
|
30
|
+
[`gh-image`](https://github.com/drogers0/gh-image) (MIT, © drogers0) replicates
|
|
31
|
+
that flow as a `gh` CLI extension, so an agent can upload a local image from the
|
|
32
|
+
terminal and get a ready-to-embed Markdown image line back.
|
|
33
|
+
|
|
34
|
+
## Overview
|
|
35
|
+
|
|
36
|
+
This skill drives `gh-image` to turn a local image file into a hosted GitHub
|
|
37
|
+
`user-attachments` URL, then embeds that URL into a pull request, issue, or
|
|
38
|
+
comment. It is the missing "attach a screenshot" capability for terminal agents.
|
|
39
|
+
|
|
40
|
+
## When to Use This Skill
|
|
41
|
+
|
|
42
|
+
Use this skill when asked to:
|
|
43
|
+
|
|
44
|
+
- "Attach a screenshot to the PR" or "add an image to the PR description"
|
|
45
|
+
- "Put this image in the issue" / "comment with these screenshots"
|
|
46
|
+
- "Show the test results / before-and-after in the PR"
|
|
47
|
+
- Embed any local image into GitHub Markdown without leaving the terminal
|
|
48
|
+
|
|
49
|
+
## How It Works
|
|
50
|
+
|
|
51
|
+
### Step 1: Verify prerequisites
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
gh auth status # gh installed & authenticated
|
|
55
|
+
gh extension list | grep -q 'drogers0/gh-image' \
|
|
56
|
+
|| gh extension install drogers0/gh-image # idempotent install
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`gh-image` does **not** use the `gh` token for the upload (that endpoint rejects
|
|
60
|
+
tokens). It needs a GitHub `user_session` cookie, resolved in this order:
|
|
61
|
+
`--token <value>` flag → `GH_SESSION_TOKEN` env var (use in CI/headless) → a
|
|
62
|
+
logged-in browser's cookie store (default for local use).
|
|
63
|
+
|
|
64
|
+
### Step 2: Upload
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# Use an absolute path; --repo is optional inside a repo working dir.
|
|
68
|
+
gh image "/abs/path/screenshot.png" --repo <owner>/<repo>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`gh image` prints Markdown to **stdout**, one line per image:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+

|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Capture that output — it is the embeddable reference.
|
|
78
|
+
|
|
79
|
+
### Step 3: Embed into the PR / issue / comment
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
MD="$(gh image "/abs/path/shot.png" --repo owner/repo)"
|
|
83
|
+
BODY="$(gh pr view <pr> --repo owner/repo --json body -q .body)"
|
|
84
|
+
printf '%s\n\n## Screenshots\n\n%s\n' "$BODY" "$MD" \
|
|
85
|
+
| gh pr edit <pr> --repo owner/repo --body-file -
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Use `gh pr comment`, `gh issue edit`, or `gh issue comment` with `--body-file -`
|
|
89
|
+
for other targets. Always pass `--body-file -` (not inline `--body`) so multi-line
|
|
90
|
+
bodies and special characters can't break shell quoting.
|
|
91
|
+
|
|
92
|
+
### Step 4: Verify
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
gh pr view <pr> --repo owner/repo --json body -q .body # confirm URL present
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Examples
|
|
99
|
+
|
|
100
|
+
- **Attach a CleanShot screenshot to PR #42:** upload the file, append it under a
|
|
101
|
+
`## Screenshots` heading in the PR body.
|
|
102
|
+
- **Embed before/after images in a README:** upload both, paste the two Markdown
|
|
103
|
+
lines into the README at the relevant section.
|
|
104
|
+
|
|
105
|
+
## Best Practices
|
|
106
|
+
|
|
107
|
+
- Resolve globs to absolute paths first; quote paths with spaces/Unicode.
|
|
108
|
+
- For display sizing, embed an HTML tag instead of bare Markdown:
|
|
109
|
+
`<img width="800" src="https://github.com/user-attachments/assets/<uuid>" />`.
|
|
110
|
+
- In CI, set `GH_SESSION_TOKEN` from a dedicated bot account.
|
|
111
|
+
|
|
112
|
+
## Limitations
|
|
113
|
+
|
|
114
|
+
- **Session cookie required.** A `user_session` cookie grants full account access
|
|
115
|
+
(not scoped like a PAT) — treat it like a password; use a bot account in CI.
|
|
116
|
+
- **Write access to the target repo is required**; orgs that enforce SAML SSO need
|
|
117
|
+
the session authorized at `https://github.com/orgs/<org>/sso` first.
|
|
118
|
+
- **Private-repo images stay private:** the `user-attachments` URL inherits repo
|
|
119
|
+
visibility, so an anonymous fetch on a private repo returns 404/403 by design.
|
|
120
|
+
- **Windows + Chrome 127+** cannot read cookies (library limitation) — use another
|
|
121
|
+
browser or `GH_SESSION_TOKEN`.
|
|
122
|
+
- The skill embeds the Markdown itself; `gh-image` only prints the URL.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: github-actions-debugger
|
|
3
|
+
description: "Specialized skill for diagnosing, analyzing, and fixing failing GitHub Actions workflows by parsing run logs and pipeline definitions."
|
|
4
|
+
category: devops
|
|
5
|
+
risk: safe
|
|
6
|
+
source: community
|
|
7
|
+
source_type: community
|
|
8
|
+
date_added: "2026-06-25"
|
|
9
|
+
author: Owais
|
|
10
|
+
tags: [github-actions, ci-cd, devops, debugging, workflows]
|
|
11
|
+
tools: [claude, cursor, gemini, antigravity]
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# GitHub Actions Pipeline Debugger
|
|
15
|
+
|
|
16
|
+
## Overview
|
|
17
|
+
|
|
18
|
+
This skill is designed to act as an expert CI/CD diagnostician. It focuses specifically on reading raw logs from failed GitHub Actions, identifying the root cause of the crash or failure, and outputting the precise YAML or code changes required to fix the pipeline.
|
|
19
|
+
|
|
20
|
+
## When to Use
|
|
21
|
+
|
|
22
|
+
- Use when a GitHub Actions workflow fails unexpectedly and the error log is long, obscure, or misleading.
|
|
23
|
+
- Use when debugging dependency mismatch errors, missing secrets, caching issues, or runner environment problems in CI.
|
|
24
|
+
- Use to optimize slow pipelines by identifying bottlenecks in workflow steps.
|
|
25
|
+
- Use to update and modernize deprecated actions or workflow syntax.
|
|
26
|
+
|
|
27
|
+
## How It Works
|
|
28
|
+
|
|
29
|
+
1. **Log Ingestion & Redaction:** Analyze the provided GitHub Actions workflow log (often exported as a raw text file or pasted directly). **CRITICAL SAFETY REQUIREMENT:** The user/agent must redact all sensitive credentials, secrets, tokens, private keys, and internal system paths from the logs before pasting or uploading them.
|
|
30
|
+
2. **Context Mapping:** Cross-reference the failure point with the specific step and job in the `.github/workflows/*.yml` definition.
|
|
31
|
+
3. **Root Cause Analysis:** Identify if the failure is due to:
|
|
32
|
+
- Missing or misconfigured secrets (`${{ secrets.API_KEY }}`).
|
|
33
|
+
- Node/Python/OS environment version mismatches.
|
|
34
|
+
- Flaky tests or timeout limits.
|
|
35
|
+
- Syntax errors in bash scripts run within the `run:` block.
|
|
36
|
+
- Invalid action versions or deprecated actions.
|
|
37
|
+
4. **Resolution Proposal:** Provide a direct `diff` of the `.yml` file or the underlying script that needs to be modified.
|
|
38
|
+
|
|
39
|
+
## Best Practices
|
|
40
|
+
|
|
41
|
+
- **Provide Full Context:** Always review both the workflow definition (`.yml` file) and the failure log simultaneously to ensure accurate diagnosis.
|
|
42
|
+
- **Check Action Versions:** Many failures are caused by deprecated runtime versions (e.g., Node.js 16) in older third-party actions (e.g., `actions/checkout@v2`). Always recommend upgrading to the latest major versions (e.g., `v4`).
|
|
43
|
+
- **Permissions Audit:** Ensure the workflow has the correct `permissions:` block if it's attempting to write to the repository, packages, or deploy environments.
|
|
44
|
+
- **Reproducibility:** If a test fails in CI but passes locally, investigate environment differences such as timezone, headless browser state, memory limits, or parallel execution race conditions.
|
|
45
|
+
|
|
46
|
+
## Examples
|
|
47
|
+
|
|
48
|
+
### Example 1: Fixing a Deprecated Node.js Action Version Error
|
|
49
|
+
**Failing Log:**
|
|
50
|
+
```text
|
|
51
|
+
Warning: The Go/Node.js/Python version used by this action is deprecated.
|
|
52
|
+
Error: Node.js 16 actions are deprecated. Please update to use Node.js 20.
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Proposed Fix Diff:**
|
|
56
|
+
```diff
|
|
57
|
+
- name: Checkout Code
|
|
58
|
+
- uses: actions/checkout@v2
|
|
59
|
+
+ uses: actions/checkout@v4
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Example 2: Diagnosing and Fixing a Missing Repository Secret
|
|
63
|
+
**Failing Log:**
|
|
64
|
+
```text
|
|
65
|
+
Run npm run deploy
|
|
66
|
+
npm run deploy
|
|
67
|
+
shell: /usr/bin/bash -e {0}
|
|
68
|
+
Error: API Key is required for deployment. Process exited with code 1.
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Proposed Fix Diff:**
|
|
72
|
+
```diff
|
|
73
|
+
- name: Deploy App
|
|
74
|
+
run: npm run deploy
|
|
75
|
+
+ env:
|
|
76
|
+
+ DEPLOY_API_KEY: ${{ secrets.DEPLOY_API_KEY }}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Security & Safety Notes
|
|
80
|
+
|
|
81
|
+
- **Credential Exposure & Raw Log Redaction**: Under no circumstances should raw logs containing unmasked secrets, private URLs, deployment targets, or tokens be processed without prior redaction. Always ensure the user or agent redacts all sensitive info before ingestion.
|
|
82
|
+
- **Dry-Run Mode**: When recommending modifications to bash script steps inside workflows, ensure you suggest adding flags like `--dry-run` or staging execution where possible to prevent unintended side effects in downstream environments during debugging.
|
|
83
|
+
|
|
84
|
+
## Limitations
|
|
85
|
+
|
|
86
|
+
- The skill cannot securely read repository secrets. It can only infer missing or malformed secrets if the log complains about undefined environment variables or authentication failures.
|
|
87
|
+
- It cannot execute the GitHub action itself to test the fix; validation requires pushing the proposed fix to the repository and triggering a workflow run.
|
|
88
|
+
- Network-related transient failures (e.g., a package registry being down temporarily) might be incorrectly diagnosed as structural workflow issues if not carefully analyzed.
|
|
89
|
+
|
|
90
|
+
## Common Pitfalls
|
|
91
|
+
|
|
92
|
+
- **Ignoring Transient Failures**: Mistaking temporary network dropouts or registry downtime (e.g., npm or pip install errors) for actual code or configuration bugs. Always check if a rerun succeeds before attempting heavy changes.
|
|
93
|
+
- **Hardcoding Tokens**: Fixing authentication errors by hardcoding secrets or API tokens directly into the YAML files instead of utilizing GitHub Secrets (`${{ secrets.SECRET_NAME }}`).
|
|
94
|
+
- **Overlooking Caching Side Effects**: Forgetting that outdated cache keys can keep corrupt dependencies loaded. If dependency installation is failing, try running a job with actions caching bypassed.
|
|
95
|
+
|
|
96
|
+
## Related Skills
|
|
97
|
+
|
|
98
|
+
- `@devops-troubleshooter` - General DevOps and infrastructure issue resolution.
|
|
99
|
+
- `@cicd-automation-workflow-automate` - For creating new CI/CD pipelines from scratch.
|
|
@@ -132,6 +132,7 @@ ADAPTER_MODEL = require_hf_id(os.environ.get("ADAPTER_MODEL", "evalstate/qwen-ca
|
|
|
132
132
|
BASE_MODEL = require_hf_id(os.environ.get("BASE_MODEL", "Qwen/Qwen2.5-0.5B"), "BASE_MODEL")
|
|
133
133
|
OUTPUT_REPO = require_hf_id(os.environ.get("OUTPUT_REPO", "evalstate/qwen-capybara-medium-gguf"), "OUTPUT_REPO")
|
|
134
134
|
username = require_hf_id(os.environ.get("HF_USERNAME", ADAPTER_MODEL.split('/')[0]), "HF_USERNAME")
|
|
135
|
+
TRUST_REMOTE_CODE = os.environ.get("TRUST_REMOTE_CODE", "").strip().lower() in {"1", "true", "yes"}
|
|
135
136
|
|
|
136
137
|
print(f"\n📦 Configuration:")
|
|
137
138
|
print(f" Base model: {BASE_MODEL}")
|
|
@@ -147,7 +148,7 @@ try:
|
|
|
147
148
|
BASE_MODEL,
|
|
148
149
|
dtype=torch.float16,
|
|
149
150
|
device_map="auto",
|
|
150
|
-
trust_remote_code=
|
|
151
|
+
trust_remote_code=TRUST_REMOTE_CODE,
|
|
151
152
|
)
|
|
152
153
|
print(" ✅ Base model loaded")
|
|
153
154
|
except Exception as e:
|
|
@@ -169,7 +170,7 @@ except Exception as e:
|
|
|
169
170
|
|
|
170
171
|
try:
|
|
171
172
|
# Load tokenizer
|
|
172
|
-
tokenizer = AutoTokenizer.from_pretrained(ADAPTER_MODEL, trust_remote_code=
|
|
173
|
+
tokenizer = AutoTokenizer.from_pretrained(ADAPTER_MODEL, trust_remote_code=TRUST_REMOTE_CODE)
|
|
173
174
|
print(" ✅ Tokenizer loaded")
|
|
174
175
|
except Exception as e:
|
|
175
176
|
print(f" ❌ Failed to load tokenizer: {e}")
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: infinity
|
|
3
|
+
description: "Enforces a strict input boundary protocol (detect, classify, filter, verify) to ensure untrusted data never reaches business logic raw."
|
|
4
|
+
risk: safe
|
|
5
|
+
source: community
|
|
6
|
+
date_added: "2026-06-23"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# infinity — Input Boundary & Validation Protocol
|
|
10
|
+
|
|
11
|
+
## Core Philosophy
|
|
12
|
+
|
|
13
|
+
> Nothing untrusted ever reaches the core — it is stopped before contact. No external data touches the codebase raw. Every boundary where data enters the system must have a filter.
|
|
14
|
+
|
|
15
|
+
The #1 source of silent bugs, crashes, and vulnerabilities is external data that arrives in an unexpected shape and gets used directly without checking. This skill enforces a filter layer at every entry point, every time.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## When to Use This Skill
|
|
20
|
+
|
|
21
|
+
- Use when you need to handle an API response
|
|
22
|
+
- Use when reading user input or adding a form handler
|
|
23
|
+
- Use when working with environment variables or CLI arguments
|
|
24
|
+
- Use when parsing webhooks or reading from the filesystem
|
|
25
|
+
- Use when any code calls `.body`, `.params`, `.query`, `.env`, `fs.read`, or a third-party SDK response
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## The Four Phases
|
|
30
|
+
|
|
31
|
+
### PHASE 1 — Boundary Detection
|
|
32
|
+
|
|
33
|
+
Before writing or modifying any code that involves external data, the AI must identify and list every entry point in scope:
|
|
34
|
+
|
|
35
|
+
- HTTP request bodies, headers, query params
|
|
36
|
+
- User form inputs and UI-submitted data
|
|
37
|
+
- Environment variables and config files
|
|
38
|
+
- Third-party API responses
|
|
39
|
+
- Webhook payloads
|
|
40
|
+
- File reads from disk
|
|
41
|
+
- CLI arguments
|
|
42
|
+
- Database query results from external sources
|
|
43
|
+
- WebSocket messages
|
|
44
|
+
|
|
45
|
+
> **The AI must not write any data-handling logic until every entry point in scope is listed.**
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
### PHASE 2 — Classify Each Input
|
|
50
|
+
|
|
51
|
+
For every entry point identified, the AI classifies it into one of three trust levels:
|
|
52
|
+
|
|
53
|
+
| Level | Definition | Examples |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| `TRUSTED` | Internal constants, hardcoded values, your own compile-time config | Enum values, hardcoded defaults, internal constants |
|
|
56
|
+
| `SEMI-TRUSTED` | Your own internal services, internal APIs, controlled infrastructure | Internal microservice responses, your own database reads |
|
|
57
|
+
| `UNTRUSTED` | Anything from users, the internet, third parties, or the filesystem | User input, external API responses, uploaded files, env vars, CLI args |
|
|
58
|
+
|
|
59
|
+
> **Rule:** `TRUSTED` inputs may be used directly. `SEMI-TRUSTED` and `UNTRUSTED` inputs must pass through a filter layer before any use.
|
|
60
|
+
|
|
61
|
+
The AI outputs this classification before writing any handling code:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
INFINITY — BOUNDARY MAP
|
|
65
|
+
─────────────────────────────────────────
|
|
66
|
+
Entry Point | Trust Level | Filter Required
|
|
67
|
+
─────────────────────────────────────────
|
|
68
|
+
req.body.email | UNTRUSTED | ✓ format + sanitize
|
|
69
|
+
process.env.API_KEY | UNTRUSTED | ✓ presence + non-empty
|
|
70
|
+
internalService.getData()| SEMI-TRUSTED | ✓ schema validate
|
|
71
|
+
PAGINATION_LIMIT = 20 | TRUSTED | ✗ none needed
|
|
72
|
+
─────────────────────────────────────────
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
### PHASE 3 — Mandatory Filter Layer
|
|
78
|
+
|
|
79
|
+
Every `UNTRUSTED` and `SEMI-TRUSTED` input must pass through validation before it reaches any business logic, storage, or rendering. The AI must apply the right filter type for the right context:
|
|
80
|
+
|
|
81
|
+
**Type Checking**
|
|
82
|
+
- Verify the input is the expected type before using it
|
|
83
|
+
- Never assume a string is a string, a number is a number, or an array is an array
|
|
84
|
+
|
|
85
|
+
**Schema Validation**
|
|
86
|
+
- For objects and API responses, validate shape before accessing nested fields
|
|
87
|
+
- If a required field is missing, reject — do not use a fallback that hides the problem
|
|
88
|
+
|
|
89
|
+
**Sanitization**
|
|
90
|
+
- Strip or escape content before rendering to UI (prevent XSS)
|
|
91
|
+
- Normalize strings before storage (trim whitespace, consistent casing where appropriate)
|
|
92
|
+
|
|
93
|
+
**Presence & Format Checks**
|
|
94
|
+
- Env vars: must exist and be non-empty before use
|
|
95
|
+
- IDs and tokens: must match expected format before use
|
|
96
|
+
|
|
97
|
+
**Rejection Rule**
|
|
98
|
+
- On invalid input: reject explicitly and return a clear error
|
|
99
|
+
- Never silently use bad data with a fallback
|
|
100
|
+
- Never let bad data pass through to fix itself "downstream"
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
// WRONG — using raw input directly
|
|
104
|
+
const user = await db.find(req.params.id);
|
|
105
|
+
|
|
106
|
+
// RIGHT — validate before use
|
|
107
|
+
const id = req.params.id;
|
|
108
|
+
if (!id || typeof id !== 'string' || !isValidUUID(id)) {
|
|
109
|
+
return res.status(400).json({ error: 'Invalid ID format' });
|
|
110
|
+
}
|
|
111
|
+
const user = await db.find(id);
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
### PHASE 4 — Self-Check Before Done
|
|
117
|
+
|
|
118
|
+
Before the AI declares any data-handling code complete, it traces each entry point and confirms:
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
INFINITY — VERIFICATION
|
|
122
|
+
─────────────────────────────────────────
|
|
123
|
+
Entry Point | Filter Exists | Filter Type
|
|
124
|
+
─────────────────────────────────────────
|
|
125
|
+
req.body.email | ✓ YES | format + sanitize
|
|
126
|
+
process.env.API_KEY | ✓ YES | presence check
|
|
127
|
+
internalService.getData()| ✓ YES | schema validation
|
|
128
|
+
─────────────────────────────────────────
|
|
129
|
+
Unfiltered inputs reaching logic: NONE ✓
|
|
130
|
+
─────────────────────────────────────────
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
If any `UNTRUSTED` or `SEMI-TRUSTED` input reaches logic, storage, or rendering without a filter — the AI flags it. It does not silently pass.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Hard Rules (Never Violated)
|
|
138
|
+
|
|
139
|
+
- **No raw external data in business logic.** Ever.
|
|
140
|
+
- **No silent fallbacks on bad input.** Reject explicitly.
|
|
141
|
+
- **No assuming shape.** Even if the API "always" returns a string — validate it.
|
|
142
|
+
- **No skipping env var checks.** Missing env vars must fail loudly at startup, not silently at runtime.
|
|
143
|
+
- **No partial filtering.** If you validate presence but not format, it is not filtered.
|
|
144
|
+
- **No filtering in the wrong place.** Filters go at the entry point — not somewhere downstream after the data has already been used once.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## What This Skill Prevents
|
|
149
|
+
|
|
150
|
+
- SQL injection via unvalidated query params
|
|
151
|
+
- Crashes from unexpected API response shapes
|
|
152
|
+
- XSS from unescaped user content rendered to UI
|
|
153
|
+
- Silent failures from missing env variables discovered at runtime
|
|
154
|
+
- Type errors from assuming external data matches expected shape
|
|
155
|
+
- Security vulnerabilities from untrusted data reaching sensitive operations
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Quick Reference
|
|
160
|
+
|
|
161
|
+
| Phase | Action | Writes Code? |
|
|
162
|
+
|---|---|---|
|
|
163
|
+
| 1 — Detect | List all entry points in scope | ❌ No |
|
|
164
|
+
| 2 — Classify | Assign trust level to each input | ❌ No |
|
|
165
|
+
| 3 — Filter | Write filter layer for all UNTRUSTED + SEMI-TRUSTED | ✅ Yes |
|
|
166
|
+
| 4 — Verify | Trace each input, confirm filter exists | ❌ No |
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Limitations
|
|
171
|
+
|
|
172
|
+
- Does not apply to purely internal logic with no external data involvement.
|
|
173
|
+
- May add verbosity to trivial scripts where strict validation is not required.
|
|
@@ -711,21 +711,30 @@ generate_dashboard() {
|
|
|
711
711
|
if (seconds < 3600) return Math.floor(seconds / 60) + 'm';
|
|
712
712
|
return Math.floor(seconds / 3600) + 'h ' + Math.floor((seconds % 3600) / 60) + 'm';
|
|
713
713
|
}
|
|
714
|
+
function escapeHtml(value) {
|
|
715
|
+
return String(value ?? '').replace(/[&<>"']/g, (char) => ({
|
|
716
|
+
'&': '&',
|
|
717
|
+
'<': '<',
|
|
718
|
+
'>': '>',
|
|
719
|
+
'"': '"',
|
|
720
|
+
"'": '''
|
|
721
|
+
})[char]);
|
|
722
|
+
}
|
|
714
723
|
function renderAgent(agent) {
|
|
715
724
|
const modelClass = getModelClass(agent.model);
|
|
716
|
-
const modelName = agent.model || 'Sonnet 4.5';
|
|
717
|
-
const agentType = agent.agent_type || 'general-purpose';
|
|
725
|
+
const modelName = escapeHtml(agent.model || 'Sonnet 4.5');
|
|
726
|
+
const agentType = escapeHtml(agent.agent_type || 'general-purpose');
|
|
718
727
|
const status = agent.status === 'completed' ? 'completed' : 'active';
|
|
719
|
-
const currentTask = agent.current_task || (agent.tasks_completed && agent.tasks_completed.length > 0
|
|
728
|
+
const currentTask = escapeHtml(agent.current_task || (agent.tasks_completed && agent.tasks_completed.length > 0
|
|
720
729
|
? 'Completed: ' + agent.tasks_completed.join(', ')
|
|
721
|
-
: 'Initializing...');
|
|
730
|
+
: 'Initializing...'));
|
|
722
731
|
const duration = formatDuration(agent.spawned_at);
|
|
723
732
|
const tasksCount = agent.tasks_completed ? agent.tasks_completed.length : 0;
|
|
724
733
|
|
|
725
734
|
return `
|
|
726
735
|
<div class="agent-card">
|
|
727
736
|
<div class="agent-header">
|
|
728
|
-
<div class="agent-id">${agent.agent_id || 'Unknown'}</div>
|
|
737
|
+
<div class="agent-id">${escapeHtml(agent.agent_id || 'Unknown')}</div>
|
|
729
738
|
<div class="model-badge ${modelClass}">${modelName}</div>
|
|
730
739
|
</div>
|
|
731
740
|
<div class="agent-type">${agentType}</div>
|
|
@@ -740,9 +749,9 @@ generate_dashboard() {
|
|
|
740
749
|
}
|
|
741
750
|
function renderTask(task) {
|
|
742
751
|
const payload = task.payload || {};
|
|
743
|
-
const title = payload.description || payload.action || task.type || 'Task';
|
|
744
|
-
const error = task.lastError ? `<div class="error">${task.lastError}</div>` : '';
|
|
745
|
-
return `<div class="task"><div class="id">${task.id}</div><span class="type">${task.type || 'general'}</span><div class="title">${title}</div>${error}</div>`;
|
|
752
|
+
const title = escapeHtml(payload.description || payload.action || task.type || 'Task');
|
|
753
|
+
const error = task.lastError ? `<div class="error">${escapeHtml(task.lastError)}</div>` : '';
|
|
754
|
+
return `<div class="task"><div class="id">${escapeHtml(task.id)}</div><span class="type">${escapeHtml(task.type || 'general')}</span><div class="title">${title}</div>${error}</div>`;
|
|
746
755
|
}
|
|
747
756
|
async function loadData() {
|
|
748
757
|
const [pending, progress, completed, failed, agents] = await Promise.all([
|
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
"name": "todo-app-backend",
|
|
9
9
|
"version": "1.0.0",
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"better-sqlite3": "^12.
|
|
12
|
-
"cors": "^2.8.
|
|
11
|
+
"better-sqlite3": "^12.10.0",
|
|
12
|
+
"cors": "^2.8.6",
|
|
13
13
|
"express": "^4.18.2",
|
|
14
|
-
"express-rate-limit": "^8.5.
|
|
14
|
+
"express-rate-limit": "^8.5.2",
|
|
15
15
|
"ip-address": "^10.2.0"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
@@ -303,9 +303,9 @@
|
|
|
303
303
|
"license": "MIT"
|
|
304
304
|
},
|
|
305
305
|
"node_modules/better-sqlite3": {
|
|
306
|
-
"version": "12.
|
|
307
|
-
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.
|
|
308
|
-
"integrity": "sha512-
|
|
306
|
+
"version": "12.10.0",
|
|
307
|
+
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.10.0.tgz",
|
|
308
|
+
"integrity": "sha512-CyzaZRQKyHkB2ZInfTTl2nvT33EbDpjkLEbE8/Zck3Ll6O0qqvuGdrJ45HgtH+HykRg88ITY3AdreBGN70aBSQ==",
|
|
309
309
|
"hasInstallScript": true,
|
|
310
310
|
"license": "MIT",
|
|
311
311
|
"dependencies": {
|
|
@@ -313,7 +313,7 @@
|
|
|
313
313
|
"prebuild-install": "^7.1.1"
|
|
314
314
|
},
|
|
315
315
|
"engines": {
|
|
316
|
-
"node": "20.x || 22.x || 23.x || 24.x || 25.x"
|
|
316
|
+
"node": "20.x || 22.x || 23.x || 24.x || 25.x || 26.x"
|
|
317
317
|
}
|
|
318
318
|
},
|
|
319
319
|
"node_modules/bindings": {
|
|
@@ -459,9 +459,9 @@
|
|
|
459
459
|
"license": "MIT"
|
|
460
460
|
},
|
|
461
461
|
"node_modules/cors": {
|
|
462
|
-
"version": "2.8.
|
|
463
|
-
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.
|
|
464
|
-
"integrity": "sha512-
|
|
462
|
+
"version": "2.8.6",
|
|
463
|
+
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz",
|
|
464
|
+
"integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==",
|
|
465
465
|
"license": "MIT",
|
|
466
466
|
"dependencies": {
|
|
467
467
|
"object-assign": "^4",
|
|
@@ -469,6 +469,10 @@
|
|
|
469
469
|
},
|
|
470
470
|
"engines": {
|
|
471
471
|
"node": ">= 0.10"
|
|
472
|
+
},
|
|
473
|
+
"funding": {
|
|
474
|
+
"type": "opencollective",
|
|
475
|
+
"url": "https://opencollective.com/express"
|
|
472
476
|
}
|
|
473
477
|
},
|
|
474
478
|
"node_modules/create-require": {
|
|
@@ -688,9 +692,9 @@
|
|
|
688
692
|
}
|
|
689
693
|
},
|
|
690
694
|
"node_modules/express-rate-limit": {
|
|
691
|
-
"version": "8.5.
|
|
692
|
-
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.
|
|
693
|
-
"integrity": "sha512-
|
|
695
|
+
"version": "8.5.2",
|
|
696
|
+
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.2.tgz",
|
|
697
|
+
"integrity": "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==",
|
|
694
698
|
"license": "MIT",
|
|
695
699
|
"dependencies": {
|
|
696
700
|
"ip-address": "^10.2.0"
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
"dev": "ts-node src/index.ts"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"better-sqlite3": "^12.
|
|
13
|
-
"cors": "^2.8.
|
|
12
|
+
"better-sqlite3": "^12.10.0",
|
|
13
|
+
"cors": "^2.8.6",
|
|
14
14
|
"express": "^4.18.2",
|
|
15
|
-
"express-rate-limit": "^8.5.
|
|
15
|
+
"express-rate-limit": "^8.5.2",
|
|
16
16
|
"ip-address": "^10.2.0"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"version": "1.0.0",
|
|
10
10
|
"license": "ISC",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"react": "^19.2.
|
|
13
|
-
"react-dom": "^19.2.
|
|
12
|
+
"react": "^19.2.7",
|
|
13
|
+
"react-dom": "^19.2.7"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
16
|
"@types/react": "^19.2.7",
|
|
@@ -814,24 +814,24 @@
|
|
|
814
814
|
}
|
|
815
815
|
},
|
|
816
816
|
"node_modules/react": {
|
|
817
|
-
"version": "19.2.
|
|
818
|
-
"resolved": "https://registry.npmjs.org/react/-/react-19.2.
|
|
819
|
-
"integrity": "sha512-
|
|
817
|
+
"version": "19.2.7",
|
|
818
|
+
"resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz",
|
|
819
|
+
"integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==",
|
|
820
820
|
"license": "MIT",
|
|
821
821
|
"engines": {
|
|
822
822
|
"node": ">=0.10.0"
|
|
823
823
|
}
|
|
824
824
|
},
|
|
825
825
|
"node_modules/react-dom": {
|
|
826
|
-
"version": "19.2.
|
|
827
|
-
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.
|
|
828
|
-
"integrity": "sha512-
|
|
826
|
+
"version": "19.2.7",
|
|
827
|
+
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz",
|
|
828
|
+
"integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==",
|
|
829
829
|
"license": "MIT",
|
|
830
830
|
"dependencies": {
|
|
831
831
|
"scheduler": "^0.27.0"
|
|
832
832
|
},
|
|
833
833
|
"peerDependencies": {
|
|
834
|
-
"react": "^19.2.
|
|
834
|
+
"react": "^19.2.7"
|
|
835
835
|
}
|
|
836
836
|
},
|
|
837
837
|
"node_modules/rolldown": {
|
|
@@ -14,8 +14,13 @@ fi
|
|
|
14
14
|
|
|
15
15
|
echo "Creating self-signed certificate '$CERT_NAME'..."
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
TEMP_DIR=$(mktemp -d)
|
|
18
|
+
chmod 700 "$TEMP_DIR"
|
|
19
|
+
TEMP_CONFIG="$TEMP_DIR/dev.cnf"
|
|
20
|
+
KEY_PATH="$TEMP_DIR/dev.key"
|
|
21
|
+
CRT_PATH="$TEMP_DIR/dev.crt"
|
|
22
|
+
P12_PATH="$TEMP_DIR/dev.p12"
|
|
23
|
+
trap 'rm -rf "$TEMP_DIR"' EXIT
|
|
19
24
|
|
|
20
25
|
cat > "$TEMP_CONFIG" <<EOFCONF
|
|
21
26
|
[ req ]
|
|
@@ -34,18 +39,16 @@ extendedKeyUsage = codeSigning
|
|
|
34
39
|
EOFCONF
|
|
35
40
|
|
|
36
41
|
openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 \
|
|
37
|
-
-nodes -keyout
|
|
42
|
+
-nodes -keyout "$KEY_PATH" -out "$CRT_PATH" \
|
|
38
43
|
-config "$TEMP_CONFIG" 2>/dev/null
|
|
39
44
|
|
|
40
|
-
openssl pkcs12 -export -out
|
|
41
|
-
-inkey
|
|
45
|
+
openssl pkcs12 -export -out "$P12_PATH" \
|
|
46
|
+
-inkey "$KEY_PATH" -in "$CRT_PATH" \
|
|
42
47
|
-passout pass: 2>/dev/null
|
|
43
48
|
|
|
44
|
-
security import
|
|
49
|
+
security import "$P12_PATH" -k ~/Library/Keychains/login.keychain-db \
|
|
45
50
|
-T /usr/bin/codesign -T /usr/bin/security
|
|
46
51
|
|
|
47
|
-
rm -f /tmp/dev.{key,crt,p12}
|
|
48
|
-
|
|
49
52
|
echo ""
|
|
50
53
|
echo "Trust this certificate for code signing in Keychain Access."
|
|
51
54
|
echo "Then export in your shell profile:"
|