opencode-skills-collection 3.1.14 → 3.1.16
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 +36 -1
- package/bundled-skills/007/scripts/full_audit.py +34 -22
- package/bundled-skills/007/scripts/quick_scan.py +24 -15
- package/bundled-skills/007/scripts/scanners/dependency_scanner.py +31 -19
- package/bundled-skills/007/scripts/scanners/injection_scanner.py +24 -14
- package/bundled-skills/007/scripts/scanners/secrets_scanner.py +24 -14
- package/bundled-skills/007/scripts/score_calculator.py +25 -13
- package/bundled-skills/2slides-ppt-generator/scripts/download_slides_pages_voices.py +15 -1
- package/bundled-skills/aegisops-ai/SKILL.md +1 -1
- package/bundled-skills/agent-self-scheduling/SKILL.md +88 -0
- package/bundled-skills/alpha-vantage/SKILL.md +3 -1
- package/bundled-skills/anti-sleep/SKILL.md +90 -0
- package/bundled-skills/api-security-best-practices/SKILL.md +1 -1
- package/bundled-skills/app-store-optimization/SKILL.md +7 -0
- package/bundled-skills/audio-transcriber/scripts/transcribe.py +17 -4
- package/bundled-skills/azure-mgmt-botservice-py/SKILL.md +2 -1
- package/bundled-skills/azure-resource-manager-mysql-dotnet/SKILL.md +2 -1
- package/bundled-skills/azure-resource-manager-postgresql-dotnet/SKILL.md +2 -1
- package/bundled-skills/azure-resource-manager-sql-dotnet/SKILL.md +2 -1
- package/bundled-skills/biopython/SKILL.md +2 -1
- package/bundled-skills/brain-to-docs/SKILL.md +54 -0
- package/bundled-skills/browser-harness/SKILL.md +220 -0
- package/bundled-skills/browser-harness/references/install.md +132 -0
- package/bundled-skills/bumblebee/scripts/render_report.py +16 -3
- package/bundled-skills/bun-development/SKILL.md +1 -1
- package/bundled-skills/cc-skill-security-review/SKILL.md +2 -2
- package/bundled-skills/claude-monitor/scripts/monitor.py +15 -2
- package/bundled-skills/cmux/SKILL.md +250 -0
- package/bundled-skills/code-polish/SKILL.md +192 -0
- package/bundled-skills/code-review-checklist/SKILL.md +1 -1
- package/bundled-skills/codex-subagent/SKILL.md +117 -0
- package/bundled-skills/competitor-analysis/scripts/capture_screenshots.mjs +24 -3
- package/bundled-skills/competitor-analysis/scripts/compile_report.mjs +13 -2
- package/bundled-skills/competitor-analysis/scripts/extract_vs_names.mjs +23 -2
- package/bundled-skills/competitor-analysis/scripts/gate_candidates.mjs +21 -0
- package/bundled-skills/competitor-analysis/scripts/list_urls.mjs +23 -2
- package/bundled-skills/competitor-analysis/scripts/merge_partials.mjs +24 -3
- package/bundled-skills/container-security-hardening/SKILL.md +1 -1
- package/bundled-skills/content-creator/scripts/brand_voice_analyzer.py +15 -1
- package/bundled-skills/content-creator/scripts/seo_optimizer.py +15 -1
- package/bundled-skills/context-kit/SKILL.md +135 -0
- package/bundled-skills/cyber-audit/SKILL.md +138 -0
- package/bundled-skills/deepapi/SKILL.md +649 -0
- package/bundled-skills/delegating-to-agents/SKILL.md +64 -0
- package/bundled-skills/developer-signup-flow/SKILL.md +1 -1
- package/bundled-skills/diary/scripts/fetch_diaries.py +14 -1
- package/bundled-skills/diary/scripts/prepare_context.py +15 -2
- package/bundled-skills/diary/scripts/sync_to_notion.py +14 -1
- package/bundled-skills/dispatch/SKILL.md +19 -7
- package/bundled-skills/distribute-skill-to-all-agents/SKILL.md +85 -0
- 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/repo-growth-seo.md +3 -3
- package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
- 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/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/usage.md +4 -4
- package/bundled-skills/docs/users/visual-guide.md +4 -4
- package/bundled-skills/docx-official/ooxml/scripts/pack.py +30 -3
- package/bundled-skills/docx-official/ooxml/scripts/unpack.py +16 -3
- package/bundled-skills/drizzle-migration-conflict/scripts/check_drizzle_migrations.py +27 -17
- package/bundled-skills/ecl-harness-engineer/agents/creator-config.md +17 -3
- package/bundled-skills/ecl-harness-engineer/references/environment-detection-guide.md +9 -5
- package/bundled-skills/effective-agent-skills/SKILL.md +333 -0
- package/bundled-skills/electron-development/SKILL.md +6 -2
- package/bundled-skills/environment-setup-guide/SKILL.md +2 -5
- package/bundled-skills/expo-ui/scripts/list-components.js +5 -1
- package/bundled-skills/fable-safe-prompt/SKILL.md +79 -0
- package/bundled-skills/folder-specific-claude-and-agents-md/SKILL.md +96 -0
- package/bundled-skills/frontend-slides/scripts/extract-pptx.py +18 -4
- package/bundled-skills/gcp-cloud-run/SKILL.md +2 -1
- package/bundled-skills/gemini-api-integration/SKILL.md +3 -1
- package/bundled-skills/gemini-live-api-dev/SKILL.md +2 -1
- package/bundled-skills/gemini-omni-flash-api/scripts/video/generate_video.py +49 -14
- package/bundled-skills/goal-loop/SKILL.md +175 -0
- package/bundled-skills/hugging-face-evaluation/SKILL.md +1 -1
- package/bundled-skills/hugging-face-jobs/SKILL.md +1 -1
- package/bundled-skills/hugging-face-jobs/scripts/finepdfs-stats.py +14 -1
- package/bundled-skills/hugging-face-model-trainer/scripts/convert_to_gguf.py +10 -1
- package/bundled-skills/hugo-to-markdown/scripts/inventory_hugo_rules.py +14 -1
- package/bundled-skills/image-generator/SKILL.md +3 -1
- package/bundled-skills/instagram/scripts/export.py +18 -7
- package/bundled-skills/interview-style-doc-building/SKILL.md +86 -0
- package/bundled-skills/junta-leiloeiros/scripts/export.py +19 -10
- package/bundled-skills/landing-page-generator/scripts/landing_page_scaffolder.py +15 -1
- package/bundled-skills/linear-claude-skill/SKILL.md +4 -2
- package/bundled-skills/linkedin-post-writer/SKILL.md +159 -0
- package/bundled-skills/linkedin-post-writer/references/hook-formulas.md +482 -0
- package/bundled-skills/llm-council/SKILL.md +4 -2
- package/bundled-skills/loki-mode/examples/todo-app-generated/backend/package-lock.json +5 -6
- package/bundled-skills/loki-mode/examples/todo-app-generated/backend/package.json +2 -3
- package/bundled-skills/markdown-rendering/SKILL.md +72 -0
- package/bundled-skills/matematico-tao/scripts/complexity_analyzer.py +14 -1
- package/bundled-skills/matematico-tao/scripts/dependency_graph.py +15 -2
- package/bundled-skills/mobile-design/scripts/mobile_audit.py +20 -6
- package/bundled-skills/monte-carlo-validation-notebook/scripts/resolve_dbt_schema.py +15 -2
- package/bundled-skills/multi-agent-architect/SKILL.md +1 -1
- package/bundled-skills/odoo-rpc-api/SKILL.md +2 -1
- package/bundled-skills/pci-compliance/SKILL.md +3 -1
- package/bundled-skills/pdf-official/scripts/create_validation_image.py +17 -3
- package/bundled-skills/pdf-official/scripts/extract_form_field_info.py +1 -1
- package/bundled-skills/personal-tool-builder/SKILL.md +1 -1
- package/bundled-skills/pi-custom-model/SKILL.md +68 -0
- package/bundled-skills/pi-web-search/SKILL.md +74 -0
- package/bundled-skills/playwright-skill/run.js +19 -1
- package/bundled-skills/pptx-official/ooxml/scripts/pack.py +30 -3
- package/bundled-skills/pptx-official/ooxml/scripts/unpack.py +16 -3
- package/bundled-skills/pptx-official/scripts/inventory.py +17 -4
- package/bundled-skills/pptx-official/scripts/rearrange.py +15 -2
- package/bundled-skills/pptx-official/scripts/replace.py +16 -3
- package/bundled-skills/product-manager-toolkit/scripts/customer_interview_analyzer.py +15 -1
- package/bundled-skills/production-code-audit/SKILL.md +1 -1
- package/bundled-skills/push-skill-to-github/SKILL.md +61 -0
- package/bundled-skills/rclone-cli/references/commands/rclone_completion_powershell.md +3 -2
- package/bundled-skills/read-all-adrs/SKILL.md +35 -0
- package/bundled-skills/remote-gpu-trainer/scripts/verify_local.py +14 -1
- package/bundled-skills/research-prompt/SKILL.md +63 -0
- package/bundled-skills/run-deep-swe/SKILL.md +120 -0
- package/bundled-skills/senior-architect/scripts/architecture_diagram_generator.py +15 -2
- package/bundled-skills/senior-architect/scripts/dependency_analyzer.py +15 -2
- package/bundled-skills/senior-architect/scripts/project_architect.py +15 -2
- package/bundled-skills/senior-frontend/scripts/bundle_analyzer.py +14 -1
- package/bundled-skills/senior-frontend/scripts/frontend_scaffolder.py +14 -1
- package/bundled-skills/senior-fullstack/scripts/code_quality_analyzer.py +15 -2
- package/bundled-skills/senior-fullstack/scripts/fullstack_scaffolder.py +15 -2
- package/bundled-skills/senior-fullstack/scripts/project_scaffolder.py +15 -2
- package/bundled-skills/setup-help/SKILL.md +50 -0
- package/bundled-skills/shodan-reconnaissance/SKILL.md +2 -1
- package/bundled-skills/short/SKILL.md +28 -0
- package/bundled-skills/skill-creator/scripts/init_skill.py +15 -2
- package/bundled-skills/skill-creator/scripts/package_skill.py +29 -12
- package/bundled-skills/skill-creator/scripts/quick_validate.py +14 -2
- package/bundled-skills/skill-creator-ms/SKILL.md +1 -1
- package/bundled-skills/skill-installer/scripts/install_skill.py +42 -8
- package/bundled-skills/skill-installer/scripts/package_skill.py +29 -17
- package/bundled-skills/skill-installer/scripts/validate_skill.py +37 -22
- package/bundled-skills/stripe-integration/SKILL.md +7 -3
- package/bundled-skills/swiftui-expert-skill/scripts/instruments_parser/xctrace.py +7 -1
- package/bundled-skills/swiftui-expert-skill/scripts/instruments_parser/xml_utils.py +7 -1
- package/bundled-skills/taisly-social-media-posting/SKILL.md +79 -0
- package/bundled-skills/technical-tutorials/SKILL.md +1 -1
- package/bundled-skills/telegram/scripts/setup_project.py +17 -2
- package/bundled-skills/time-ledger/SKILL.md +118 -0
- package/bundled-skills/trading-ledger/SKILL.md +121 -0
- package/bundled-skills/videodb/scripts/ws_listener.py +17 -4
- package/bundled-skills/voice-ai-development/SKILL.md +2 -1
- package/bundled-skills/vps-server-management/SKILL.md +72 -0
- package/bundled-skills/weaviate/scripts/weaviate_conn.py +20 -18
- package/bundled-skills/wgm/SKILL.md +137 -0
- package/bundled-skills/whatsapp-cloud-api/scripts/setup_project.py +16 -1
- package/bundled-skills/workorai/SKILL.md +137 -0
- package/bundled-skills/wp-site-health-auditor/SKILL.md +341 -0
- package/bundled-skills/wp-site-health-auditor/references/catalog.md +135 -0
- package/bundled-skills/writing-skills/render-graphs.js +13 -2
- package/bundled-skills/x-twitter-scraper/SKILL.md +3 -1
- package/bundled-skills/youtube-notetaker/scripts/serve.py +41 -31
- package/bundled-skills/youtube-notetaker/scripts/vtt_to_transcript.py +16 -2
- package/bundled-skills/youtube-notetaker/scripts/write_library_item.py +15 -1
- package/bundled-skills/youtube-transcript/SKILL.md +120 -0
- package/package.json +5 -1
- package/skills_index.json +786 -6
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: folder-specific-claude-and-agents-md
|
|
3
|
+
description: "Create folder-scoped CLAUDE.md and AGENTS.md guidance for future agents working in that area."
|
|
4
|
+
category: development
|
|
5
|
+
risk: critical
|
|
6
|
+
source: community
|
|
7
|
+
source_repo: davidondrej/skills
|
|
8
|
+
source_type: community
|
|
9
|
+
date_added: "2026-07-07"
|
|
10
|
+
author: davidondrej
|
|
11
|
+
tags: [agents-md, claude-md, documentation]
|
|
12
|
+
tools: [claude, codex]
|
|
13
|
+
license: "MIT"
|
|
14
|
+
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
|
|
15
|
+
user-invocable: true
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Folder CLAUDE.md Creation
|
|
19
|
+
|
|
20
|
+
## When to Use
|
|
21
|
+
|
|
22
|
+
- Use when the user asks for folder-specific agent instructions or local context files.
|
|
23
|
+
- Use when a subdirectory needs a CLAUDE.md and AGENTS.md handoff for future agents.
|
|
24
|
+
|
|
25
|
+
Generate a focused `CLAUDE.md` inside a target folder, plus an `AGENTS.md` symlink pointing at it. The file gives any future agent (Claude Code, Codex, etc.) the folder-specific context the global `CLAUDE.md` doesn't cover.
|
|
26
|
+
|
|
27
|
+
Background reference: `library/claude-code/claude-and-agents-md.md`.
|
|
28
|
+
|
|
29
|
+
## Process
|
|
30
|
+
|
|
31
|
+
### Step 1: Confirm the target folder + sanity-check it deserves a file
|
|
32
|
+
Ask the user which folder. Use absolute path under `~/Documents/code/workspace/`.
|
|
33
|
+
|
|
34
|
+
**Only create a file if the folder has context needed across multiple sessions** — active evolving work, specific conventions, ongoing decisions. A folder of static reference files does NOT need one (agents can read on demand). If unsure, ask the user.
|
|
35
|
+
|
|
36
|
+
### Step 2: Read every file in the folder IN FULL
|
|
37
|
+
- Use `ls -la` first to enumerate files and subfolders.
|
|
38
|
+
- Read every markdown, config, and key source file.
|
|
39
|
+
- For large tldraw/Vite subprojects: read `package.json`, `src/App.tsx`, one representative module file, and the folder's own `module-details.md`-style files.
|
|
40
|
+
- Do NOT skim. Do NOT skip. The user's later edits depend on you having full context.
|
|
41
|
+
|
|
42
|
+
### Step 3: Draft a bullet list of candidate content
|
|
43
|
+
Before writing the file, give the user a bullet list grouped by section — let them react first. Candidate sections (skip any that don't apply):
|
|
44
|
+
|
|
45
|
+
- **Product / Purpose** — what this folder/project is, current state, key metrics
|
|
46
|
+
- **Avatar / Audience** — who it's for (if applicable)
|
|
47
|
+
- **Essential Files** — one-line role for each important file, including cross-folder references (use `@path/file.md` import syntax)
|
|
48
|
+
- **Constraints (MUST NOT)** — explicit hard negatives. Highest-ROI content in the file.
|
|
49
|
+
- **Conventions** — the user's lingo, status emojis (✅ 🟡), naming patterns, "usually do" patterns
|
|
50
|
+
- **Locked Decisions** — things agreed + dated, must not re-litigate
|
|
51
|
+
- **Context** — history, authority, credibility that frames the work
|
|
52
|
+
- **How to work with the user** — collaboration style for this specific folder
|
|
53
|
+
- **Marketing Angles / Positioning** — if public-facing
|
|
54
|
+
- **Top Insights** — 3-5 most glaring signals from research (if research exists)
|
|
55
|
+
|
|
56
|
+
### Step 4: Iterate with the user
|
|
57
|
+
- Keep answers short. The user will edit directly in the IDE.
|
|
58
|
+
- When they edit the file, RE-READ it and flag: contradictions, typos, missing rules, wrong categorization.
|
|
59
|
+
- Do not revert their edits unless asked.
|
|
60
|
+
|
|
61
|
+
### Step 5: Write the file
|
|
62
|
+
- Path: `<folder>/CLAUDE.md`
|
|
63
|
+
- Start with a one-line header explaining the file's purpose.
|
|
64
|
+
- **Subdir file marker:** if this is a subdirectory file (parent folder already has its own CLAUDE.md), open with `Apply root CLAUDE.md first, then this file.`
|
|
65
|
+
- Use `##` section headers matching the sections the user approved.
|
|
66
|
+
- Bullets over prose. Short bullets.
|
|
67
|
+
- **Cross-folder references:** use `@relative/path/file.md` import syntax, not prose mentions.
|
|
68
|
+
- **Heavy reference docs:** annotate with `**Read when:**` triggers (e.g. "Read when: writing offer copy"). Prevents loading every session.
|
|
69
|
+
|
|
70
|
+
### Step 6: Create the AGENTS.md symlink
|
|
71
|
+
```
|
|
72
|
+
cd <folder> && ln -s CLAUDE.md AGENTS.md
|
|
73
|
+
```
|
|
74
|
+
Verify with `ls -la CLAUDE.md AGENTS.md`.
|
|
75
|
+
|
|
76
|
+
### Step 7: Commit only when asked
|
|
77
|
+
Do NOT stage or push unless the user says to. When they do: `git add -A`, commit with a `Day N:` style message, push.
|
|
78
|
+
|
|
79
|
+
## Rules
|
|
80
|
+
|
|
81
|
+
- **Never invent content.** Every bullet must trace back to something you read in the folder or something the user said. No generic boilerplate.
|
|
82
|
+
- **Brevity wins.** The user edits aggressively to make things shorter. Start tight.
|
|
83
|
+
- **Folder-scoped only.** Don't duplicate the global `CLAUDE.md` (personality, dates, ports, etc.). Only include what's specific to this folder.
|
|
84
|
+
- **No file trees, no directory dumps, no stack details the code already shows.** Anything an agent can derive from `ls` or `grep` rots fast and wastes tokens. Pin decisions, rules, and context — not structure.
|
|
85
|
+
- **Constraints vs Conventions.** Hard "MUST NOT" rules go in Constraints (explicit negatives). "Usually do X" patterns go in Conventions. Splitting these improves adherence.
|
|
86
|
+
- **No absolute ALWAYS/NEVER without explicit exceptions.** Edge cases make absolute rules get ignored. "Never commit secrets EXCEPT `.env.example`" beats "never commit secrets."
|
|
87
|
+
- **Never summarize or auto-shorten the file.** Context collapse degrades it. Grow deliberately, prune manually. If the user asks to trim, do it by hand.
|
|
88
|
+
- **Maintenance loop.** When the user corrects the agent on something this file should have prevented, add the rule to the file immediately. Don't wait.
|
|
89
|
+
- **No emojis unless the user uses them** (status markers ✅ 🟡 are the exception — they're already conventions).
|
|
90
|
+
- **Symlink, not copy.** `AGENTS.md` must be a symlink so edits stay in sync.
|
|
91
|
+
- **Flag gaps honestly.** If the user's edits introduce contradictions (e.g. "sell X" in one section and "never sell X" in another), call it out before they ask.
|
|
92
|
+
|
|
93
|
+
## Limitations
|
|
94
|
+
|
|
95
|
+
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
|
|
96
|
+
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
|
|
@@ -13,6 +13,20 @@ import json
|
|
|
13
13
|
import os
|
|
14
14
|
import sys
|
|
15
15
|
from pptx import Presentation
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def safe_user_path(path_value, base_dir="."):
|
|
20
|
+
"""Resolve a CLI path under the current workspace."""
|
|
21
|
+
if base_dir != ".":
|
|
22
|
+
raise ValueError("Custom base directories are not supported for CLI paths")
|
|
23
|
+
base_path = Path.cwd().resolve()
|
|
24
|
+
resolved_path = Path(path_value).expanduser().resolve()
|
|
25
|
+
try:
|
|
26
|
+
resolved_path.relative_to(base_path)
|
|
27
|
+
except ValueError as exc:
|
|
28
|
+
raise ValueError(f"Path escapes allowed directory: {path_value}") from exc
|
|
29
|
+
return resolved_path
|
|
16
30
|
|
|
17
31
|
|
|
18
32
|
def extract_pptx(file_path, output_dir="."):
|
|
@@ -54,7 +68,7 @@ def extract_pptx(file_path, output_dir="."):
|
|
|
54
68
|
image_name = f"slide{slide_num + 1}_img{len(slide_data['images']) + 1}.{image_ext}"
|
|
55
69
|
image_path = os.path.join(assets_dir, image_name)
|
|
56
70
|
|
|
57
|
-
with open(
|
|
71
|
+
with safe_user_path(image_path).open("wb") as f:
|
|
58
72
|
f.write(image_bytes)
|
|
59
73
|
|
|
60
74
|
slide_data["images"].append(
|
|
@@ -81,14 +95,14 @@ if __name__ == "__main__":
|
|
|
81
95
|
sys.exit(1)
|
|
82
96
|
|
|
83
97
|
input_file = sys.argv[1]
|
|
84
|
-
output_dir = sys.argv[2] if len(sys.argv) > 2 else "."
|
|
98
|
+
output_dir = safe_user_path(sys.argv[2]) if len(sys.argv) > 2 else "."
|
|
85
99
|
|
|
86
100
|
slides = extract_pptx(input_file, output_dir)
|
|
87
101
|
|
|
88
102
|
# Write extracted data as JSON
|
|
89
103
|
output_path = os.path.join(output_dir, "extracted-slides.json")
|
|
90
|
-
with open(
|
|
91
|
-
json.
|
|
104
|
+
with safe_user_path(output_path).open("w") as f:
|
|
105
|
+
f.write(json.dumps(slides, indent=2))
|
|
92
106
|
|
|
93
107
|
print(f"Extracted {len(slides)} slides to {output_path}")
|
|
94
108
|
for s in slides:
|
|
@@ -948,6 +948,7 @@ cloud-sql-python-connector[pg8000]
|
|
|
948
948
|
```
|
|
949
949
|
|
|
950
950
|
```python
|
|
951
|
+
import os
|
|
951
952
|
from google.cloud.sql.connector import Connector
|
|
952
953
|
import sqlalchemy
|
|
953
954
|
|
|
@@ -958,7 +959,7 @@ def getconn():
|
|
|
958
959
|
"project:region:instance",
|
|
959
960
|
"pg8000",
|
|
960
961
|
user="user",
|
|
961
|
-
password="
|
|
962
|
+
password=os.environ["DB_PASSWORD"],
|
|
962
963
|
db="database"
|
|
963
964
|
)
|
|
964
965
|
|
|
@@ -85,9 +85,10 @@ To streamline real-time audio/video app development, use a third-party integrati
|
|
|
85
85
|
#### Python
|
|
86
86
|
|
|
87
87
|
```python
|
|
88
|
+
import os
|
|
88
89
|
from google import genai
|
|
89
90
|
|
|
90
|
-
client = genai.Client(api_key="
|
|
91
|
+
client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])
|
|
91
92
|
```
|
|
92
93
|
|
|
93
94
|
#### JavaScript
|
|
@@ -15,12 +15,27 @@ import sys
|
|
|
15
15
|
import time
|
|
16
16
|
import urllib.request
|
|
17
17
|
import urllib.error
|
|
18
|
+
import urllib.parse
|
|
18
19
|
import uuid
|
|
19
20
|
from google import genai
|
|
20
21
|
|
|
21
22
|
# Load local upload helper logic inline to prevent dependency issues
|
|
22
23
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
23
24
|
from upload_file import upload_file, wait_for_active
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def safe_user_path(path_value, base_dir="."):
|
|
29
|
+
"""Resolve a CLI path under the current workspace."""
|
|
30
|
+
if base_dir != ".":
|
|
31
|
+
raise ValueError("Custom base directories are not supported for CLI paths")
|
|
32
|
+
base_path = Path.cwd().resolve()
|
|
33
|
+
resolved_path = Path(path_value).expanduser().resolve()
|
|
34
|
+
try:
|
|
35
|
+
resolved_path.relative_to(base_path)
|
|
36
|
+
except ValueError as exc:
|
|
37
|
+
raise ValueError(f"Path escapes allowed directory: {path_value}") from exc
|
|
38
|
+
return resolved_path
|
|
24
39
|
|
|
25
40
|
def get_api_key(args):
|
|
26
41
|
"""Retrieves API key from command args or environment."""
|
|
@@ -28,22 +43,43 @@ def get_api_key(args):
|
|
|
28
43
|
return args.api_key
|
|
29
44
|
return os.environ.get("GEMINI_API_KEY")
|
|
30
45
|
|
|
46
|
+
FILE_ID_RE = re.compile(r'^[A-Za-z0-9_-]+$')
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def extract_file_id(uri):
|
|
50
|
+
"""Returns a Gemini File API id from a local reference or trusted API URL."""
|
|
51
|
+
if not uri:
|
|
52
|
+
return None
|
|
53
|
+
if uri.startswith("files/"):
|
|
54
|
+
file_id = uri.removeprefix("files/")
|
|
55
|
+
return file_id if FILE_ID_RE.fullmatch(file_id) else None
|
|
56
|
+
|
|
57
|
+
parsed = urllib.parse.urlparse(uri)
|
|
58
|
+
if parsed.scheme != "https" or parsed.netloc != "generativelanguage.googleapis.com":
|
|
59
|
+
return None
|
|
60
|
+
path_match = re.fullmatch(r'/files/([A-Za-z0-9_-]+)', parsed.path)
|
|
61
|
+
return path_match.group(1) if path_match else None
|
|
62
|
+
|
|
63
|
+
|
|
31
64
|
def is_file_uri(uri):
|
|
32
65
|
"""Returns True if the string is a standard Gemini File URI."""
|
|
33
|
-
|
|
34
|
-
return False
|
|
35
|
-
return "files/" in uri and ("generativelanguage.googleapis.com" in uri or uri.startswith("files/"))
|
|
66
|
+
return extract_file_id(uri) is not None
|
|
36
67
|
|
|
37
68
|
def normalize_file_uri(uri):
|
|
38
69
|
"""Normalizes any File API URI/reference to the standard https://generativelanguage.googleapis.com/files/{id} format."""
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
match = re.search(r'files/([a-zA-Z0-9]+)', uri)
|
|
42
|
-
if match:
|
|
43
|
-
file_id = match.group(1)
|
|
70
|
+
file_id = extract_file_id(uri)
|
|
71
|
+
if file_id:
|
|
44
72
|
return f"https://generativelanguage.googleapis.com/files/{file_id}"
|
|
45
73
|
return uri
|
|
46
74
|
|
|
75
|
+
|
|
76
|
+
def media_download_url(file_uri):
|
|
77
|
+
"""Build a media URL only for validated Gemini File API references."""
|
|
78
|
+
file_id = extract_file_id(file_uri)
|
|
79
|
+
if not file_id:
|
|
80
|
+
raise ValueError("Generated video URI must be a Gemini File API reference.")
|
|
81
|
+
return f"https://generativelanguage.googleapis.com/files/{file_id}?alt=media"
|
|
82
|
+
|
|
47
83
|
def slugify(text):
|
|
48
84
|
"""Converts a text prompt into a safe, descriptive filename slug."""
|
|
49
85
|
text = text.lower()
|
|
@@ -144,7 +180,7 @@ def resolve_or_upload_asset(asset_path, mime_type, api_key, strip_audio=False):
|
|
|
144
180
|
# Clean up temporary stripped file if we created one
|
|
145
181
|
if temp_stripped_path and os.path.exists(temp_stripped_path):
|
|
146
182
|
try:
|
|
147
|
-
|
|
183
|
+
safe_user_path(temp_stripped_path).unlink()
|
|
148
184
|
print(f"Cleaned up temporary video file: {temp_stripped_path}")
|
|
149
185
|
except Exception as e:
|
|
150
186
|
print(f"Warning: Failed to remove temporary file {temp_stripped_path}: {e}", file=sys.stderr)
|
|
@@ -157,8 +193,7 @@ def resolve_or_upload_asset(asset_path, mime_type, api_key, strip_audio=False):
|
|
|
157
193
|
|
|
158
194
|
def download_video_file(file_uri, output_path, api_key):
|
|
159
195
|
"""Downloads generated video file from URI using alt=media standard in a memory-safe, chunked manner."""
|
|
160
|
-
|
|
161
|
-
download_url = f"{file_uri}{separator}alt=media"
|
|
196
|
+
download_url = media_download_url(file_uri)
|
|
162
197
|
|
|
163
198
|
print(f"Downloading video from {file_uri} to {output_path} in chunked mode...")
|
|
164
199
|
req = urllib.request.Request(download_url)
|
|
@@ -170,7 +205,7 @@ def download_video_file(file_uri, output_path, api_key):
|
|
|
170
205
|
if parent_dir:
|
|
171
206
|
os.makedirs(parent_dir, exist_ok=True)
|
|
172
207
|
|
|
173
|
-
with open(
|
|
208
|
+
with safe_user_path(output_path).open("wb") as f:
|
|
174
209
|
while True:
|
|
175
210
|
chunk = resp.read(8192)
|
|
176
211
|
if not chunk:
|
|
@@ -343,7 +378,7 @@ def main():
|
|
|
343
378
|
print(f"Error: Batch JSON file '{args.batch}' not found.", file=sys.stderr)
|
|
344
379
|
sys.exit(1)
|
|
345
380
|
try:
|
|
346
|
-
with
|
|
381
|
+
with safe_user_path(args.batch).open("r", encoding="utf-8") as f:
|
|
347
382
|
jobs = json.load(f)
|
|
348
383
|
if not isinstance(jobs, list):
|
|
349
384
|
print("Error: Batch JSON file must contain a list/array of job objects.", file=sys.stderr)
|
|
@@ -361,7 +396,7 @@ def main():
|
|
|
361
396
|
sys.exit(1)
|
|
362
397
|
|
|
363
398
|
jobs = []
|
|
364
|
-
with
|
|
399
|
+
with safe_user_path(args.prompts_file).open("r", encoding="utf-8") as f:
|
|
365
400
|
for line in f:
|
|
366
401
|
line = line.strip()
|
|
367
402
|
if line and not line.startswith("#"):
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: goal-loop
|
|
3
|
+
description: "Draft and explain persistent goal-loop prompts for long-running agent work with clear stop conditions."
|
|
4
|
+
category: agent-orchestration
|
|
5
|
+
risk: safe
|
|
6
|
+
source: community
|
|
7
|
+
source_repo: davidondrej/skills
|
|
8
|
+
source_type: community
|
|
9
|
+
date_added: "2026-07-07"
|
|
10
|
+
author: davidondrej
|
|
11
|
+
tags: [goals, autonomy, planning]
|
|
12
|
+
tools: [claude, codex]
|
|
13
|
+
license: "MIT"
|
|
14
|
+
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Agent `/goal` Loop
|
|
18
|
+
|
|
19
|
+
## What `/goal` is
|
|
20
|
+
|
|
21
|
+
`/goal` is a slash command that turns an agent prompt into a **persistent agent** looping `plan → act → test → review → iterate` until a stop condition is met, the user pauses, or the token budget runs out. Internally called the "Ralph loop."
|
|
22
|
+
|
|
23
|
+
Agents with the `/goal` feature right now: **Codex, Claude Code, and Hermes Agent**.
|
|
24
|
+
|
|
25
|
+
Key difference from a normal prompt: when a turn ends but the goal isn't met, the agent **auto-continues** instead of waiting for input.
|
|
26
|
+
|
|
27
|
+
**Lifecycle states:** `pursuing`, `paused`, `achieved`, `unmet`, `budget-limited`.
|
|
28
|
+
|
|
29
|
+
When monitoring a running `/goal`, every check should include a one-line update to the user: what the agent is doing and whether it is on track. Keep it extremely concise.
|
|
30
|
+
|
|
31
|
+
**Not:** a budget command, a safety boundary, "run forever", or a replacement for `/plan`. It's a contract enforcer with a verification loop.
|
|
32
|
+
|
|
33
|
+
## Requirements
|
|
34
|
+
|
|
35
|
+
- An agent with the `/goal` feature — right now: Codex, Claude Code, or Hermes Agent
|
|
36
|
+
- The goals feature enabled in the agent's config
|
|
37
|
+
- **Subscription auth** — API-key auth does **not** work. A pro-tier plan is the realistic minimum for long runs.
|
|
38
|
+
|
|
39
|
+
## When to Use it
|
|
40
|
+
|
|
41
|
+
Use only when **all three** are true:
|
|
42
|
+
1. Task is >30 min of mechanical work.
|
|
43
|
+
2. There's a **verifiable stop condition** (tests pass, coverage hit, eval ≥ X, build green).
|
|
44
|
+
3. Repo is agent-ready (working build, decent tests, `AGENTS.md` present).
|
|
45
|
+
|
|
46
|
+
Fits: migrations, coverage lifts, TDD feature builds, refactors with contract tests, prompt/eval optimization, deploy retry loops, bug-repro-then-fix.
|
|
47
|
+
|
|
48
|
+
Bad fits: exploratory work, vague "improve this", anything without a "done" definition, prod credentials, destructive shared-infra ops.
|
|
49
|
+
|
|
50
|
+
## The 5-part contract (every goal needs this)
|
|
51
|
+
|
|
52
|
+
1. **Objective** — one sentence, one concrete outcome.
|
|
53
|
+
2. **Constraints** — what must NOT change (public API, files, libs, conventions).
|
|
54
|
+
3. **Validation command** — the exact shell command that proves progress (`pytest -q`, `pnpm test`, etc.).
|
|
55
|
+
4. **Stop condition** — verifiable: "Stop when X passes" OR "when further changes need human/product input."
|
|
56
|
+
5. **Documentation** — one sentence instructing the agent to write concise, targeted docs for every change, either creating new `.md` files or updating existing ones.
|
|
57
|
+
|
|
58
|
+
Plus: tell the agent what to read first, ask it to work in checkpoints with a short progress log.
|
|
59
|
+
|
|
60
|
+
## Writing a goal (the core deliverable)
|
|
61
|
+
|
|
62
|
+
When the user wants a quick `/goal` instruction, produce a structured markdown block with one line per contract item (proper newlines, not flowing prose). **Do not prefix the output with `/goal`** — the user adds the slash command themselves in the composer. Emit only the contract body. Template:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
**Objective:** <one-sentence objective>
|
|
66
|
+
**Read first:** <files/PLAN.md/issue>
|
|
67
|
+
**Constraints:** <what not to change, libs, conventions>
|
|
68
|
+
**Validate:** `<exact command>` after each change
|
|
69
|
+
**Document:** Write concise, targeted documentation for all changes — create new `.md` files or update existing docs as needed.
|
|
70
|
+
**Checkpoints:** work in checkpoints and log progress briefly
|
|
71
|
+
**Stop when:** <verifiable condition>, OR when further changes require human/product input
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Example (migration)
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
**Objective:** Migrate this project from Pydantic v1 to v2.
|
|
78
|
+
**Read first:** pyproject.toml, src/, tests/
|
|
79
|
+
**Constraints:** no public API changes; keep imports backwards-compatible via shims if needed; no new dependencies
|
|
80
|
+
**Validate:** `pytest -q` after each change
|
|
81
|
+
**Checkpoints:** work in checkpoints; log progress briefly
|
|
82
|
+
**Stop when:** full suite passes with zero deprecation warnings, OR when a change requires architecture decisions
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Example (coverage lift)
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
**Objective:** Raise coverage in src/auth/ from ~38% to ≥75%.
|
|
89
|
+
**Read first:** src/auth/, tests/auth/, AGENTS.md
|
|
90
|
+
**Constraints:** no new deps; mirror existing test style; do not modify production code unless strictly required for testability
|
|
91
|
+
**Validate:** `pytest --cov=src/auth --cov-report=term-missing`
|
|
92
|
+
**Checkpoints:** work in checkpoints; log coverage delta each one
|
|
93
|
+
**Stop when:** coverage ≥75% AND all tests pass, OR when uncovered code needs design changes
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Writing rules
|
|
97
|
+
- **One objective, one stop condition.** Not a backlog.
|
|
98
|
+
- **Documentation is mandatory.** Every `/goal` prompt must include a single sentence committing the agent to concise, targeted docs — new `.md` files or focused updates to existing docs.
|
|
99
|
+
- **Never instruct the agent to create new ADRs** — ADRs require the user's explicit approval, so goal prompts must not pre-approve or encourage them.
|
|
100
|
+
- **Forbid reward-hacking explicitly:** "Do not delete, skip, weaken, or narrow tests to make the goal pass." Otherwise the agent may game the stop condition.
|
|
101
|
+
- **4,000-char limit** on the objective. If longer, put detail in a file (`PLAN.md`/`GOAL_BRIEF.md`) and make the goal point to it — keep the goal itself compact.
|
|
102
|
+
- Use **literal strings** for paths, commands, issue numbers — exact.
|
|
103
|
+
- Forbid scope creep explicitly: "Do not refactor unrelated code. Do not add dependencies."
|
|
104
|
+
- Tell the agent when to pause: "If <condition>, pause and ask before proceeding."
|
|
105
|
+
- Short, vague goals burn tokens for no extra value vs. a normal prompt.
|
|
106
|
+
|
|
107
|
+
### Meta-prompting trick (highest-leverage)
|
|
108
|
+
|
|
109
|
+
Hand-written goals under-specify. Ask a second AI session (Claude with the codebase loaded, ChatGPT with project connected, or a separate agent thread in the same dir) to: (1) inspect the codebase, (2) surface hidden assumptions/constraints/edge cases, (3) emit a structured `/goal` markdown block using the 4-part contract. Paste that into the agent. Order-of-magnitude better runs.
|
|
110
|
+
|
|
111
|
+
Claude Code cmux note: after Claude finishes, it may prefill a predicted next user message; that draft is Claude, not the user speaking.
|
|
112
|
+
|
|
113
|
+
### Self-goal setting
|
|
114
|
+
|
|
115
|
+
The agent can now write and set its own goal natively (the `create_goal` tool). Instead of crafting the contract yourself, give it your high-level intent and tell it to set the goal: "Inspect this repo, then write yourself a `/goal` with a verifiable stop condition and pursue it." It's the meta-prompting trick done inline — the agent turns your intent into the contract. Still give it the same raw materials (files to read, constraints, the validation command) so the goal it writes is grounded. Add: "ask clarifying questions before committing if the intent is underspecified" — catches ambiguity up front and prevents the self-set goal from drifting.
|
|
116
|
+
|
|
117
|
+
## Launching
|
|
118
|
+
|
|
119
|
+
1. `cd <repo>` (goals run scoped to the working directory).
|
|
120
|
+
2. Launch the agent bare (opens the TUI). **Not** exec/headless mode — `/goal` is a TUI slash command only.
|
|
121
|
+
3. Sign in with subscription auth (not an API key).
|
|
122
|
+
4. Type `/goal <your contract>` in the composer, Enter.
|
|
123
|
+
5. Walk away.
|
|
124
|
+
|
|
125
|
+
## Controlling a running goal
|
|
126
|
+
|
|
127
|
+
| Command | Effect |
|
|
128
|
+
|---|---|
|
|
129
|
+
| `/goal` (alone) | Status: current checkpoint, what's verified, what remains, blockers |
|
|
130
|
+
| `/goal pause` | Freeze |
|
|
131
|
+
| `/goal resume` | Unfreeze (paused goals never auto-resume) |
|
|
132
|
+
| `/goal clear` | Kill the goal |
|
|
133
|
+
| `/goal <new>` | Replace the current goal |
|
|
134
|
+
| Ctrl+C / any typed message | Auto-pauses; user input always wins priority |
|
|
135
|
+
|
|
136
|
+
Resuming across sessions: goal state is persisted server-side. `cd` back into the repo, launch the agent, `/goal` for status, `/goal resume`.
|
|
137
|
+
|
|
138
|
+
Budget-limited state: the agent doesn't stop abruptly — it summarizes, notes what's left, saves state. `/goal resume` works after budget refresh or upgrade.
|
|
139
|
+
|
|
140
|
+
## When a goal drifts
|
|
141
|
+
|
|
142
|
+
- **Minor drift:** just type a correction in the composer (auto-pauses, folds it in, resumes).
|
|
143
|
+
- **Loose objective:** `/goal pause`, read status, then `/goal <tighter version>` — replaces the contract. Don't pile instructions on a vague goal.
|
|
144
|
+
- **Bad mess:** `/goal clear`, `git status` or `git stash`, rewrite with the meta-prompting trick, restart.
|
|
145
|
+
|
|
146
|
+
Don't let a drifting goal keep running "to see where it goes." Tokens burn, diffs compound.
|
|
147
|
+
|
|
148
|
+
## Operational tips
|
|
149
|
+
|
|
150
|
+
- Inspect status periodically with bare `/goal`.
|
|
151
|
+
- **Always review the diff** before merging — long autonomy means more code to validate, not less. Human oversight becomes more critical, not optional.
|
|
152
|
+
- Keep approvals/sandboxing tight; default permissions are correct.
|
|
153
|
+
- First run: pick a 30-min scoped task so you learn how `/goal` actually stops before trusting it overnight.
|
|
154
|
+
- Bake recurring policy into `AGENTS.md` so every goal inherits it without restating: adversarial self-review before declaring done, an extra QA pass even when tests pass, and the standard validation command. Saves repeating it in each goal paragraph.
|
|
155
|
+
|
|
156
|
+
## Troubleshooting
|
|
157
|
+
|
|
158
|
+
| Symptom | Fix |
|
|
159
|
+
|---|---|
|
|
160
|
+
| `/goal` missing from slash popup | Update the agent to a version that supports `/goal` |
|
|
161
|
+
| Feature flag on but command missing | Quit and restart the agent fully |
|
|
162
|
+
| Typed `/goals` | It's singular: `/goal` |
|
|
163
|
+
| Doesn't activate | Sign out, sign back in with subscription auth (not API key) |
|
|
164
|
+
| Stopped with progress summary | Budget-limited — `/goal resume` after refresh, or tighten scope |
|
|
165
|
+
| `/goal resume` says no active goal | Terminal state or cleared — start fresh with `/goal <new>` |
|
|
166
|
+
| Goal looks active but won't auto-continue | Stuck in Plan mode — plan-only work doesn't trigger continuation. Draft the plan, then switch to Goal execution |
|
|
167
|
+
|
|
168
|
+
## Mental model
|
|
169
|
+
|
|
170
|
+
`/goal` is a **contract enforcer with a verification loop**, not a "run forever" button. The shift: stop writing prompts, start writing **specifications with stop conditions**. Spend the time upfront defining "done"; the run takes care of itself.
|
|
171
|
+
|
|
172
|
+
## Limitations
|
|
173
|
+
|
|
174
|
+
- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
|
|
175
|
+
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.
|
|
@@ -192,7 +192,7 @@ Fetch benchmark scores from Artificial Analysis API and add them to a model card
|
|
|
192
192
|
|
|
193
193
|
**Basic Usage:**
|
|
194
194
|
```bash
|
|
195
|
-
AA_API_KEY
|
|
195
|
+
env "AA_API_KEY=${AA_API_KEY:?set AA_API_KEY first}" uv run scripts/evaluation_manager.py import-aa \
|
|
196
196
|
--creator-slug "anthropic" \
|
|
197
197
|
--model-name "claude-sonnet-4" \
|
|
198
198
|
--repo-id "username/model-name"
|
|
@@ -42,6 +42,19 @@ import sys
|
|
|
42
42
|
import time
|
|
43
43
|
from pathlib import Path
|
|
44
44
|
|
|
45
|
+
|
|
46
|
+
def safe_user_path(path_value, base_dir="."):
|
|
47
|
+
"""Resolve a CLI path under the current workspace."""
|
|
48
|
+
if base_dir != ".":
|
|
49
|
+
raise ValueError("Custom base directories are not supported for CLI paths")
|
|
50
|
+
base_path = Path.cwd().resolve()
|
|
51
|
+
resolved_path = Path(path_value).expanduser().resolve()
|
|
52
|
+
try:
|
|
53
|
+
resolved_path.relative_to(base_path)
|
|
54
|
+
except ValueError as exc:
|
|
55
|
+
raise ValueError(f"Path escapes allowed directory: {path_value}") from exc
|
|
56
|
+
return resolved_path
|
|
57
|
+
|
|
45
58
|
import polars as pl
|
|
46
59
|
from ascii_graph import Pyasciigraph
|
|
47
60
|
from datasets import Dataset
|
|
@@ -401,7 +414,7 @@ def main():
|
|
|
401
414
|
print("The 'text' column is never loaded, making this very fast.\n")
|
|
402
415
|
|
|
403
416
|
# Create output directory
|
|
404
|
-
output_dir =
|
|
417
|
+
output_dir = safe_user_path(args.output_dir)
|
|
405
418
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
406
419
|
|
|
407
420
|
# Single scan: compute temporal stats
|
|
@@ -84,6 +84,7 @@ def run_command(cmd, description):
|
|
|
84
84
|
cmd,
|
|
85
85
|
check=True,
|
|
86
86
|
capture_output=True,
|
|
87
|
+
shell=False,
|
|
87
88
|
text=True
|
|
88
89
|
)
|
|
89
90
|
if result.stdout:
|
|
@@ -114,6 +115,14 @@ def require_hf_repo_id(value, name):
|
|
|
114
115
|
sys.exit(1)
|
|
115
116
|
|
|
116
117
|
|
|
118
|
+
def safe_filename_component(value, name):
|
|
119
|
+
"""Allow repo-name text only where it becomes a local filename component."""
|
|
120
|
+
if not re.fullmatch(r"[A-Za-z0-9._-]{1,96}", value):
|
|
121
|
+
print(f" Invalid {name}: {value!r}. Use letters, numbers, dots, dashes, or underscores.", file=sys.stderr)
|
|
122
|
+
sys.exit(1)
|
|
123
|
+
return value
|
|
124
|
+
|
|
125
|
+
|
|
117
126
|
def env_flag(name):
|
|
118
127
|
return os.environ.get(name, "").strip().lower() in {"1", "true", "yes", "on"}
|
|
119
128
|
|
|
@@ -230,7 +239,7 @@ gguf_output_dir = "/tmp/gguf_output"
|
|
|
230
239
|
os.makedirs(gguf_output_dir, exist_ok=True)
|
|
231
240
|
|
|
232
241
|
convert_script = "/tmp/llama.cpp/convert_hf_to_gguf.py"
|
|
233
|
-
model_name = ADAPTER_MODEL.split('/')[-1]
|
|
242
|
+
model_name = safe_filename_component(ADAPTER_MODEL.split('/')[-1], "ADAPTER_MODEL repo name")
|
|
234
243
|
gguf_file = f"{gguf_output_dir}/{model_name}-f16.gguf"
|
|
235
244
|
|
|
236
245
|
print(f" Running conversion...")
|
|
@@ -6,6 +6,19 @@ import re
|
|
|
6
6
|
from collections import Counter, defaultdict
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
|
+
|
|
10
|
+
def safe_user_path(path_value, base_dir="."):
|
|
11
|
+
"""Resolve a CLI path under the current workspace."""
|
|
12
|
+
if base_dir != ".":
|
|
13
|
+
raise ValueError("Custom base directories are not supported for CLI paths")
|
|
14
|
+
base_path = Path.cwd().resolve()
|
|
15
|
+
resolved_path = Path(path_value).expanduser().resolve()
|
|
16
|
+
try:
|
|
17
|
+
resolved_path.relative_to(base_path)
|
|
18
|
+
except ValueError as exc:
|
|
19
|
+
raise ValueError(f"Path escapes allowed directory: {path_value}") from exc
|
|
20
|
+
return resolved_path
|
|
21
|
+
|
|
9
22
|
try:
|
|
10
23
|
import tomllib
|
|
11
24
|
except ModuleNotFoundError: # pragma: no cover
|
|
@@ -177,7 +190,7 @@ def main():
|
|
|
177
190
|
|
|
178
191
|
payload = json.dumps(result, indent=2, sort_keys=True)
|
|
179
192
|
if args.output:
|
|
180
|
-
output =
|
|
193
|
+
output = safe_user_path(args.output)
|
|
181
194
|
output.parent.mkdir(parents=True, exist_ok=True)
|
|
182
195
|
output.write_text(payload + "\n", encoding="utf-8")
|
|
183
196
|
else:
|
|
@@ -39,7 +39,9 @@ Before using this skill, the user must set the `GEMINI_API_KEY` environment vari
|
|
|
39
39
|
1. Get a free API key from [Google AI Studio](https://aistudio.google.com/)
|
|
40
40
|
2. Export the key in your shell profile (`~/.zshrc`, `~/.bashrc`, etc.):
|
|
41
41
|
```bash
|
|
42
|
-
|
|
42
|
+
read -rsp "Gemini API key: " GEMINI_API_KEY
|
|
43
|
+
echo
|
|
44
|
+
export GEMINI_API_KEY
|
|
43
45
|
```
|
|
44
46
|
3. Restart your terminal or run `source ~/.zshrc` (or `~/.bashrc`)
|
|
45
47
|
|