0xkobold 0.0.1
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/.agents/skills/nextjs-best-practices/SKILL.md +208 -0
- package/.agents/skills/sql-optimization-patterns/SKILL.md +509 -0
- package/HEARTBEAT.md +45 -0
- package/README.md +197 -0
- package/USAGE.md +191 -0
- package/dist/package.json +77 -0
- package/dist/src/agent/pi-adapter.js +307 -0
- package/dist/src/agent/pi-adapter.js.map +1 -0
- package/dist/src/agent/tool-adapter.js +86 -0
- package/dist/src/agent/tool-adapter.js.map +1 -0
- package/dist/src/approval/queue.js +114 -0
- package/dist/src/approval/queue.js.map +1 -0
- package/dist/src/ascii-kobold.js +76 -0
- package/dist/src/ascii-kobold.js.map +1 -0
- package/dist/src/cli/client.js +217 -0
- package/dist/src/cli/client.js.map +1 -0
- package/dist/src/cli/commands/agent.js +272 -0
- package/dist/src/cli/commands/agent.js.map +1 -0
- package/dist/src/cli/commands/chat.js +234 -0
- package/dist/src/cli/commands/chat.js.map +1 -0
- package/dist/src/cli/commands/config.js +202 -0
- package/dist/src/cli/commands/config.js.map +1 -0
- package/dist/src/cli/commands/daemon.js +203 -0
- package/dist/src/cli/commands/daemon.js.map +1 -0
- package/dist/src/cli/commands/gateway.js +184 -0
- package/dist/src/cli/commands/gateway.js.map +1 -0
- package/dist/src/cli/commands/init.js +175 -0
- package/dist/src/cli/commands/init.js.map +1 -0
- package/dist/src/cli/commands/kobold.js +21 -0
- package/dist/src/cli/commands/kobold.js.map +1 -0
- package/dist/src/cli/commands/logs.js +27 -0
- package/dist/src/cli/commands/logs.js.map +1 -0
- package/dist/src/cli/commands/mode.js +121 -0
- package/dist/src/cli/commands/mode.js.map +1 -0
- package/dist/src/cli/commands/persona.js +261 -0
- package/dist/src/cli/commands/persona.js.map +1 -0
- package/dist/src/cli/commands/start.js +66 -0
- package/dist/src/cli/commands/start.js.map +1 -0
- package/dist/src/cli/commands/status.js +117 -0
- package/dist/src/cli/commands/status.js.map +1 -0
- package/dist/src/cli/commands/stop.js +27 -0
- package/dist/src/cli/commands/stop.js.map +1 -0
- package/dist/src/cli/commands/system.js +128 -0
- package/dist/src/cli/commands/system.js.map +1 -0
- package/dist/src/cli/commands/tui.js +103 -0
- package/dist/src/cli/commands/tui.js.map +1 -0
- package/dist/src/cli/commands/update.js +133 -0
- package/dist/src/cli/commands/update.js.map +1 -0
- package/dist/src/cli/extensions/discord.js +113 -0
- package/dist/src/cli/extensions/discord.js.map +1 -0
- package/dist/src/cli/extensions/env.js +91 -0
- package/dist/src/cli/extensions/env.js.map +1 -0
- package/dist/src/cli/extensions/heartbeat.js +78 -0
- package/dist/src/cli/extensions/heartbeat.js.map +1 -0
- package/dist/src/cli/index.js +24 -0
- package/dist/src/cli/index.js.map +1 -0
- package/dist/src/cli/program.js +70 -0
- package/dist/src/cli/program.js.map +1 -0
- package/dist/src/cli/repl.js +184 -0
- package/dist/src/cli/repl.js.map +1 -0
- package/dist/src/cli/shared/discord-service.js +102 -0
- package/dist/src/cli/shared/discord-service.js.map +1 -0
- package/dist/src/config/index.js +10 -0
- package/dist/src/config/index.js.map +1 -0
- package/dist/src/config/loader.js +401 -0
- package/dist/src/config/loader.js.map +1 -0
- package/dist/src/config/paths.js +84 -0
- package/dist/src/config/paths.js.map +1 -0
- package/dist/src/config/types.js +8 -0
- package/dist/src/config/types.js.map +1 -0
- package/dist/src/context-detector.js +60 -0
- package/dist/src/context-detector.js.map +1 -0
- package/dist/src/discord/index.js +376 -0
- package/dist/src/discord/index.js.map +1 -0
- package/dist/src/event-bus/index.js +97 -0
- package/dist/src/event-bus/index.js.map +1 -0
- package/dist/src/extensions/command-args.js +68 -0
- package/dist/src/extensions/command-args.js.map +1 -0
- package/dist/src/extensions/core/agent-registry-extension.js +541 -0
- package/dist/src/extensions/core/agent-registry-extension.js.map +1 -0
- package/dist/src/extensions/core/agent-worker.js +148 -0
- package/dist/src/extensions/core/agent-worker.js.map +1 -0
- package/dist/src/extensions/core/compaction-safeguard.js +154 -0
- package/dist/src/extensions/core/compaction-safeguard.js.map +1 -0
- package/dist/src/extensions/core/confirm-destructive.js +43 -0
- package/dist/src/extensions/core/confirm-destructive.js.map +1 -0
- package/dist/src/extensions/core/context-aware-extension.js +124 -0
- package/dist/src/extensions/core/context-aware-extension.js.map +1 -0
- package/dist/src/extensions/core/context-pruning/extension.js +124 -0
- package/dist/src/extensions/core/context-pruning/extension.js.map +1 -0
- package/dist/src/extensions/core/context-pruning/pruner.js +312 -0
- package/dist/src/extensions/core/context-pruning/pruner.js.map +1 -0
- package/dist/src/extensions/core/context-pruning/runtime.js +48 -0
- package/dist/src/extensions/core/context-pruning/runtime.js.map +1 -0
- package/dist/src/extensions/core/context-pruning/settings.js +105 -0
- package/dist/src/extensions/core/context-pruning/settings.js.map +1 -0
- package/dist/src/extensions/core/dirty-repo-guard.js +42 -0
- package/dist/src/extensions/core/dirty-repo-guard.js.map +1 -0
- package/dist/src/extensions/core/discord-channel-extension.js +205 -0
- package/dist/src/extensions/core/discord-channel-extension.js.map +1 -0
- package/dist/src/extensions/core/discord-extension.js +142 -0
- package/dist/src/extensions/core/discord-extension.js.map +1 -0
- package/dist/src/extensions/core/env-loader-extension.js +157 -0
- package/dist/src/extensions/core/env-loader-extension.js.map +1 -0
- package/dist/src/extensions/core/fileops-extension.js +699 -0
- package/dist/src/extensions/core/fileops-extension.js.map +1 -0
- package/dist/src/extensions/core/gateway-extension.js +730 -0
- package/dist/src/extensions/core/gateway-extension.js.map +1 -0
- package/dist/src/extensions/core/git-checkpoint.js +46 -0
- package/dist/src/extensions/core/git-checkpoint.js.map +1 -0
- package/dist/src/extensions/core/handoff-extension.js +206 -0
- package/dist/src/extensions/core/handoff-extension.js.map +1 -0
- package/dist/src/extensions/core/heartbeat-extension.js +373 -0
- package/dist/src/extensions/core/heartbeat-extension.js.map +1 -0
- package/dist/src/extensions/core/mcp-extension.js +413 -0
- package/dist/src/extensions/core/mcp-extension.js.map +1 -0
- package/dist/src/extensions/core/mode-manager-extension.js +562 -0
- package/dist/src/extensions/core/mode-manager-extension.js.map +1 -0
- package/dist/src/extensions/core/multi-channel-extension.js +435 -0
- package/dist/src/extensions/core/multi-channel-extension.js.map +1 -0
- package/dist/src/extensions/core/ollama-provider-extension.js +66 -0
- package/dist/src/extensions/core/ollama-provider-extension.js.map +1 -0
- package/dist/src/extensions/core/onboarding-extension.js +122 -0
- package/dist/src/extensions/core/onboarding-extension.js.map +1 -0
- package/dist/src/extensions/core/persona-loader-extension.js +139 -0
- package/dist/src/extensions/core/persona-loader-extension.js.map +1 -0
- package/dist/src/extensions/core/pi-notify-extension.js +70 -0
- package/dist/src/extensions/core/pi-notify-extension.js.map +1 -0
- package/dist/src/extensions/core/protected-paths.js +24 -0
- package/dist/src/extensions/core/protected-paths.js.map +1 -0
- package/dist/src/extensions/core/questionnaire-extension.js +242 -0
- package/dist/src/extensions/core/questionnaire-extension.js.map +1 -0
- package/dist/src/extensions/core/self-update-extension.js +181 -0
- package/dist/src/extensions/core/self-update-extension.js.map +1 -0
- package/dist/src/extensions/core/session-bridge-extension.js +78 -0
- package/dist/src/extensions/core/session-bridge-extension.js.map +1 -0
- package/dist/src/extensions/core/session-manager-extension.js +319 -0
- package/dist/src/extensions/core/session-manager-extension.js.map +1 -0
- package/dist/src/extensions/core/session-name-extension.js +88 -0
- package/dist/src/extensions/core/session-name-extension.js.map +1 -0
- package/dist/src/extensions/core/session-pruning-extension.js +480 -0
- package/dist/src/extensions/core/session-pruning-extension.js.map +1 -0
- package/dist/src/extensions/core/task-manager-extension.js +661 -0
- package/dist/src/extensions/core/task-manager-extension.js.map +1 -0
- package/dist/src/extensions/core/update-extension.js +438 -0
- package/dist/src/extensions/core/update-extension.js.map +1 -0
- package/dist/src/extensions/core/websearch-extension.js +463 -0
- package/dist/src/extensions/core/websearch-extension.js.map +1 -0
- package/dist/src/extensions/index.js +5 -0
- package/dist/src/extensions/index.js.map +1 -0
- package/dist/src/extensions/loader.js +80 -0
- package/dist/src/extensions/loader.js.map +1 -0
- package/dist/src/gateway/index.js +353 -0
- package/dist/src/gateway/index.js.map +1 -0
- package/dist/src/index.js +150 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/llm/anthropic.js +86 -0
- package/dist/src/llm/anthropic.js.map +1 -0
- package/dist/src/llm/index.js +9 -0
- package/dist/src/llm/index.js.map +1 -0
- package/dist/src/llm/ollama.js +113 -0
- package/dist/src/llm/ollama.js.map +1 -0
- package/dist/src/llm/router.js +145 -0
- package/dist/src/llm/router.js.map +1 -0
- package/dist/src/llm/types.js +7 -0
- package/dist/src/llm/types.js.map +1 -0
- package/dist/src/memory/index.js +5 -0
- package/dist/src/memory/index.js.map +1 -0
- package/dist/src/memory/store.js +91 -0
- package/dist/src/memory/store.js.map +1 -0
- package/dist/src/pi-config.js +80 -0
- package/dist/src/pi-config.js.map +1 -0
- package/dist/src/skills/builtin/file.js +184 -0
- package/dist/src/skills/builtin/file.js.map +1 -0
- package/dist/src/skills/builtin/shell.js +100 -0
- package/dist/src/skills/builtin/shell.js.map +1 -0
- package/dist/src/skills/builtin/subagent.js +62 -0
- package/dist/src/skills/builtin/subagent.js.map +1 -0
- package/dist/src/skills/hello.js +42 -0
- package/dist/src/skills/hello.js.map +1 -0
- package/dist/src/skills/index.js +11 -0
- package/dist/src/skills/index.js.map +1 -0
- package/dist/src/skills/loader.js +382 -0
- package/dist/src/skills/loader.js.map +1 -0
- package/dist/src/skills/types.js +8 -0
- package/dist/src/skills/types.js.map +1 -0
- package/dist/src/utils/working-dir.js +71 -0
- package/dist/src/utils/working-dir.js.map +1 -0
- package/package.json +77 -0
- package/skills/1password/SKILL.md +70 -0
- package/skills/1password/references/cli-examples.md +29 -0
- package/skills/1password/references/get-started.md +17 -0
- package/skills/apple-notes/SKILL.md +77 -0
- package/skills/apple-reminders/SKILL.md +118 -0
- package/skills/bear-notes/SKILL.md +107 -0
- package/skills/blogwatcher/SKILL.md +69 -0
- package/skills/blucli/SKILL.md +47 -0
- package/skills/bluebubbles/SKILL.md +131 -0
- package/skills/camsnap/SKILL.md +45 -0
- package/skills/canvas/SKILL.md +198 -0
- package/skills/clawhub/SKILL.md +77 -0
- package/skills/coding-agent/SKILL.md +284 -0
- package/skills/discord/SKILL.md +197 -0
- package/skills/eightctl/SKILL.md +50 -0
- package/skills/food-order/SKILL.md +48 -0
- package/skills/gemini/SKILL.md +43 -0
- package/skills/gh-issues/SKILL.md +865 -0
- package/skills/gifgrep/SKILL.md +79 -0
- package/skills/github/SKILL.md +163 -0
- package/skills/gog/SKILL.md +116 -0
- package/skills/goplaces/SKILL.md +52 -0
- package/skills/healthcheck/SKILL.md +245 -0
- package/skills/himalaya/SKILL.md +257 -0
- package/skills/himalaya/references/configuration.md +184 -0
- package/skills/himalaya/references/message-composition.md +199 -0
- package/skills/imsg/SKILL.md +122 -0
- package/skills/mcporter/SKILL.md +61 -0
- package/skills/model-usage/SKILL.md +69 -0
- package/skills/model-usage/references/codexbar-cli.md +33 -0
- package/skills/model-usage/scripts/model_usage.py +310 -0
- package/skills/nano-banana-pro/SKILL.md +58 -0
- package/skills/nano-banana-pro/scripts/generate_image.py +184 -0
- package/skills/nano-pdf/SKILL.md +38 -0
- package/skills/notion/SKILL.md +172 -0
- package/skills/obsidian/SKILL.md +81 -0
- package/skills/openai-image-gen/SKILL.md +89 -0
- package/skills/openai-image-gen/scripts/gen.py +240 -0
- package/skills/openai-whisper/SKILL.md +38 -0
- package/skills/openai-whisper-api/SKILL.md +52 -0
- package/skills/openai-whisper-api/scripts/transcribe.sh +85 -0
- package/skills/openhue/SKILL.md +112 -0
- package/skills/oracle/SKILL.md +125 -0
- package/skills/ordercli/SKILL.md +78 -0
- package/skills/peekaboo/SKILL.md +190 -0
- package/skills/sag/SKILL.md +87 -0
- package/skills/session-logs/SKILL.md +115 -0
- package/skills/sherpa-onnx-tts/SKILL.md +103 -0
- package/skills/sherpa-onnx-tts/bin/sherpa-onnx-tts +178 -0
- package/skills/skill-creator/SKILL.md +370 -0
- package/skills/skill-creator/license.txt +202 -0
- package/skills/skill-creator/scripts/init_skill.py +378 -0
- package/skills/skill-creator/scripts/package_skill.py +111 -0
- package/skills/skill-creator/scripts/quick_validate.py +101 -0
- package/skills/slack/SKILL.md +144 -0
- package/skills/songsee/SKILL.md +49 -0
- package/skills/sonoscli/SKILL.md +46 -0
- package/skills/spotify-player/SKILL.md +64 -0
- package/skills/summarize/SKILL.md +87 -0
- package/skills/things-mac/SKILL.md +86 -0
- package/skills/tmux/SKILL.md +153 -0
- package/skills/tmux/scripts/find-sessions.sh +112 -0
- package/skills/tmux/scripts/wait-for-text.sh +83 -0
- package/skills/trello/SKILL.md +95 -0
- package/skills/video-frames/SKILL.md +46 -0
- package/skills/video-frames/scripts/frame.sh +81 -0
- package/skills/voice-call/SKILL.md +45 -0
- package/skills/wacli/SKILL.md +72 -0
- package/skills/weather/SKILL.md +112 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# /// script
|
|
3
|
+
# requires-python = ">=3.10"
|
|
4
|
+
# dependencies = [
|
|
5
|
+
# "google-genai>=1.0.0",
|
|
6
|
+
# "pillow>=10.0.0",
|
|
7
|
+
# ]
|
|
8
|
+
# ///
|
|
9
|
+
"""
|
|
10
|
+
Generate images using Google's Nano Banana Pro (Gemini 3 Pro Image) API.
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
uv run generate_image.py --prompt "your image description" --filename "output.png" [--resolution 1K|2K|4K] [--api-key KEY]
|
|
14
|
+
|
|
15
|
+
Multi-image editing (up to 14 images):
|
|
16
|
+
uv run generate_image.py --prompt "combine these images" --filename "output.png" -i img1.png -i img2.png -i img3.png
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import argparse
|
|
20
|
+
import os
|
|
21
|
+
import sys
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def get_api_key(provided_key: str | None) -> str | None:
|
|
26
|
+
"""Get API key from argument first, then environment."""
|
|
27
|
+
if provided_key:
|
|
28
|
+
return provided_key
|
|
29
|
+
return os.environ.get("GEMINI_API_KEY")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def main():
|
|
33
|
+
parser = argparse.ArgumentParser(
|
|
34
|
+
description="Generate images using Nano Banana Pro (Gemini 3 Pro Image)"
|
|
35
|
+
)
|
|
36
|
+
parser.add_argument(
|
|
37
|
+
"--prompt", "-p",
|
|
38
|
+
required=True,
|
|
39
|
+
help="Image description/prompt"
|
|
40
|
+
)
|
|
41
|
+
parser.add_argument(
|
|
42
|
+
"--filename", "-f",
|
|
43
|
+
required=True,
|
|
44
|
+
help="Output filename (e.g., sunset-mountains.png)"
|
|
45
|
+
)
|
|
46
|
+
parser.add_argument(
|
|
47
|
+
"--input-image", "-i",
|
|
48
|
+
action="append",
|
|
49
|
+
dest="input_images",
|
|
50
|
+
metavar="IMAGE",
|
|
51
|
+
help="Input image path(s) for editing/composition. Can be specified multiple times (up to 14 images)."
|
|
52
|
+
)
|
|
53
|
+
parser.add_argument(
|
|
54
|
+
"--resolution", "-r",
|
|
55
|
+
choices=["1K", "2K", "4K"],
|
|
56
|
+
default="1K",
|
|
57
|
+
help="Output resolution: 1K (default), 2K, or 4K"
|
|
58
|
+
)
|
|
59
|
+
parser.add_argument(
|
|
60
|
+
"--api-key", "-k",
|
|
61
|
+
help="Gemini API key (overrides GEMINI_API_KEY env var)"
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
args = parser.parse_args()
|
|
65
|
+
|
|
66
|
+
# Get API key
|
|
67
|
+
api_key = get_api_key(args.api_key)
|
|
68
|
+
if not api_key:
|
|
69
|
+
print("Error: No API key provided.", file=sys.stderr)
|
|
70
|
+
print("Please either:", file=sys.stderr)
|
|
71
|
+
print(" 1. Provide --api-key argument", file=sys.stderr)
|
|
72
|
+
print(" 2. Set GEMINI_API_KEY environment variable", file=sys.stderr)
|
|
73
|
+
sys.exit(1)
|
|
74
|
+
|
|
75
|
+
# Import here after checking API key to avoid slow import on error
|
|
76
|
+
from google import genai
|
|
77
|
+
from google.genai import types
|
|
78
|
+
from PIL import Image as PILImage
|
|
79
|
+
|
|
80
|
+
# Initialise client
|
|
81
|
+
client = genai.Client(api_key=api_key)
|
|
82
|
+
|
|
83
|
+
# Set up output path
|
|
84
|
+
output_path = Path(args.filename)
|
|
85
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
86
|
+
|
|
87
|
+
# Load input images if provided (up to 14 supported by Nano Banana Pro)
|
|
88
|
+
input_images = []
|
|
89
|
+
output_resolution = args.resolution
|
|
90
|
+
if args.input_images:
|
|
91
|
+
if len(args.input_images) > 14:
|
|
92
|
+
print(f"Error: Too many input images ({len(args.input_images)}). Maximum is 14.", file=sys.stderr)
|
|
93
|
+
sys.exit(1)
|
|
94
|
+
|
|
95
|
+
max_input_dim = 0
|
|
96
|
+
for img_path in args.input_images:
|
|
97
|
+
try:
|
|
98
|
+
img = PILImage.open(img_path)
|
|
99
|
+
input_images.append(img)
|
|
100
|
+
print(f"Loaded input image: {img_path}")
|
|
101
|
+
|
|
102
|
+
# Track largest dimension for auto-resolution
|
|
103
|
+
width, height = img.size
|
|
104
|
+
max_input_dim = max(max_input_dim, width, height)
|
|
105
|
+
except Exception as e:
|
|
106
|
+
print(f"Error loading input image '{img_path}': {e}", file=sys.stderr)
|
|
107
|
+
sys.exit(1)
|
|
108
|
+
|
|
109
|
+
# Auto-detect resolution from largest input if not explicitly set
|
|
110
|
+
if args.resolution == "1K" and max_input_dim > 0: # Default value
|
|
111
|
+
if max_input_dim >= 3000:
|
|
112
|
+
output_resolution = "4K"
|
|
113
|
+
elif max_input_dim >= 1500:
|
|
114
|
+
output_resolution = "2K"
|
|
115
|
+
else:
|
|
116
|
+
output_resolution = "1K"
|
|
117
|
+
print(f"Auto-detected resolution: {output_resolution} (from max input dimension {max_input_dim})")
|
|
118
|
+
|
|
119
|
+
# Build contents (images first if editing, prompt only if generating)
|
|
120
|
+
if input_images:
|
|
121
|
+
contents = [*input_images, args.prompt]
|
|
122
|
+
img_count = len(input_images)
|
|
123
|
+
print(f"Processing {img_count} image{'s' if img_count > 1 else ''} with resolution {output_resolution}...")
|
|
124
|
+
else:
|
|
125
|
+
contents = args.prompt
|
|
126
|
+
print(f"Generating image with resolution {output_resolution}...")
|
|
127
|
+
|
|
128
|
+
try:
|
|
129
|
+
response = client.models.generate_content(
|
|
130
|
+
model="gemini-3-pro-image-preview",
|
|
131
|
+
contents=contents,
|
|
132
|
+
config=types.GenerateContentConfig(
|
|
133
|
+
response_modalities=["TEXT", "IMAGE"],
|
|
134
|
+
image_config=types.ImageConfig(
|
|
135
|
+
image_size=output_resolution
|
|
136
|
+
)
|
|
137
|
+
)
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# Process response and convert to PNG
|
|
141
|
+
image_saved = False
|
|
142
|
+
for part in response.parts:
|
|
143
|
+
if part.text is not None:
|
|
144
|
+
print(f"Model response: {part.text}")
|
|
145
|
+
elif part.inline_data is not None:
|
|
146
|
+
# Convert inline data to PIL Image and save as PNG
|
|
147
|
+
from io import BytesIO
|
|
148
|
+
|
|
149
|
+
# inline_data.data is already bytes, not base64
|
|
150
|
+
image_data = part.inline_data.data
|
|
151
|
+
if isinstance(image_data, str):
|
|
152
|
+
# If it's a string, it might be base64
|
|
153
|
+
import base64
|
|
154
|
+
image_data = base64.b64decode(image_data)
|
|
155
|
+
|
|
156
|
+
image = PILImage.open(BytesIO(image_data))
|
|
157
|
+
|
|
158
|
+
# Ensure RGB mode for PNG (convert RGBA to RGB with white background if needed)
|
|
159
|
+
if image.mode == 'RGBA':
|
|
160
|
+
rgb_image = PILImage.new('RGB', image.size, (255, 255, 255))
|
|
161
|
+
rgb_image.paste(image, mask=image.split()[3])
|
|
162
|
+
rgb_image.save(str(output_path), 'PNG')
|
|
163
|
+
elif image.mode == 'RGB':
|
|
164
|
+
image.save(str(output_path), 'PNG')
|
|
165
|
+
else:
|
|
166
|
+
image.convert('RGB').save(str(output_path), 'PNG')
|
|
167
|
+
image_saved = True
|
|
168
|
+
|
|
169
|
+
if image_saved:
|
|
170
|
+
full_path = output_path.resolve()
|
|
171
|
+
print(f"\nImage saved: {full_path}")
|
|
172
|
+
# Kobold parses MEDIA tokens and will attach the file on supported providers.
|
|
173
|
+
print(f"MEDIA: {full_path}")
|
|
174
|
+
else:
|
|
175
|
+
print("Error: No image was generated in the response.", file=sys.stderr)
|
|
176
|
+
sys.exit(1)
|
|
177
|
+
|
|
178
|
+
except Exception as e:
|
|
179
|
+
print(f"Error generating image: {e}", file=sys.stderr)
|
|
180
|
+
sys.exit(1)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
if __name__ == "__main__":
|
|
184
|
+
main()
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nano-pdf
|
|
3
|
+
description: Edit PDFs with natural-language instructions using the nano-pdf CLI.
|
|
4
|
+
homepage: https://pypi.org/project/nano-pdf/
|
|
5
|
+
metadata:
|
|
6
|
+
{
|
|
7
|
+
"kobold":
|
|
8
|
+
{
|
|
9
|
+
"emoji": "📄",
|
|
10
|
+
"requires": { "bins": ["nano-pdf"] },
|
|
11
|
+
"install":
|
|
12
|
+
[
|
|
13
|
+
{
|
|
14
|
+
"id": "uv",
|
|
15
|
+
"kind": "uv",
|
|
16
|
+
"package": "nano-pdf",
|
|
17
|
+
"bins": ["nano-pdf"],
|
|
18
|
+
"label": "Install nano-pdf (uv)",
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# nano-pdf
|
|
26
|
+
|
|
27
|
+
Use `nano-pdf` to apply edits to a specific page in a PDF using a natural-language instruction.
|
|
28
|
+
|
|
29
|
+
## Quick start
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
nano-pdf edit deck.pdf 1 "Change the title to 'Q3 Results' and fix the typo in the subtitle"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Notes:
|
|
36
|
+
|
|
37
|
+
- Page numbers are 0-based or 1-based depending on the tool’s version/config; if the result looks off by one, retry with the other.
|
|
38
|
+
- Always sanity-check the output PDF before sending it out.
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: notion
|
|
3
|
+
description: Notion API for creating and managing pages, databases, and blocks.
|
|
4
|
+
homepage: https://developers.notion.com
|
|
5
|
+
metadata:
|
|
6
|
+
{
|
|
7
|
+
"kobold":
|
|
8
|
+
{ "emoji": "📝", "requires": { "env": ["NOTION_API_KEY"] }, "primaryEnv": "NOTION_API_KEY" },
|
|
9
|
+
}
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# notion
|
|
13
|
+
|
|
14
|
+
Use the Notion API to create/read/update pages, data sources (databases), and blocks.
|
|
15
|
+
|
|
16
|
+
## Setup
|
|
17
|
+
|
|
18
|
+
1. Create an integration at https://notion.so/my-integrations
|
|
19
|
+
2. Copy the API key (starts with `ntn_` or `secret_`)
|
|
20
|
+
3. Store it:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
mkdir -p ~/.config/notion
|
|
24
|
+
echo "ntn_your_key_here" > ~/.config/notion/api_key
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
4. Share target pages/databases with your integration (click "..." → "Connect to" → your integration name)
|
|
28
|
+
|
|
29
|
+
## API Basics
|
|
30
|
+
|
|
31
|
+
All requests need:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
NOTION_KEY=$(cat ~/.config/notion/api_key)
|
|
35
|
+
curl -X GET "https://api.notion.com/v1/..." \
|
|
36
|
+
-H "Authorization: Bearer $NOTION_KEY" \
|
|
37
|
+
-H "Notion-Version: 2025-09-03" \
|
|
38
|
+
-H "Content-Type: application/json"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
> **Note:** The `Notion-Version` header is required. This skill uses `2025-09-03` (latest). In this version, databases are called "data sources" in the API.
|
|
42
|
+
|
|
43
|
+
## Common Operations
|
|
44
|
+
|
|
45
|
+
**Search for pages and data sources:**
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
curl -X POST "https://api.notion.com/v1/search" \
|
|
49
|
+
-H "Authorization: Bearer $NOTION_KEY" \
|
|
50
|
+
-H "Notion-Version: 2025-09-03" \
|
|
51
|
+
-H "Content-Type: application/json" \
|
|
52
|
+
-d '{"query": "page title"}'
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Get page:**
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
curl "https://api.notion.com/v1/pages/{page_id}" \
|
|
59
|
+
-H "Authorization: Bearer $NOTION_KEY" \
|
|
60
|
+
-H "Notion-Version: 2025-09-03"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Get page content (blocks):**
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
curl "https://api.notion.com/v1/blocks/{page_id}/children" \
|
|
67
|
+
-H "Authorization: Bearer $NOTION_KEY" \
|
|
68
|
+
-H "Notion-Version: 2025-09-03"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Create page in a data source:**
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
curl -X POST "https://api.notion.com/v1/pages" \
|
|
75
|
+
-H "Authorization: Bearer $NOTION_KEY" \
|
|
76
|
+
-H "Notion-Version: 2025-09-03" \
|
|
77
|
+
-H "Content-Type: application/json" \
|
|
78
|
+
-d '{
|
|
79
|
+
"parent": {"database_id": "xxx"},
|
|
80
|
+
"properties": {
|
|
81
|
+
"Name": {"title": [{"text": {"content": "New Item"}}]},
|
|
82
|
+
"Status": {"select": {"name": "Todo"}}
|
|
83
|
+
}
|
|
84
|
+
}'
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Query a data source (database):**
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
curl -X POST "https://api.notion.com/v1/data_sources/{data_source_id}/query" \
|
|
91
|
+
-H "Authorization: Bearer $NOTION_KEY" \
|
|
92
|
+
-H "Notion-Version: 2025-09-03" \
|
|
93
|
+
-H "Content-Type: application/json" \
|
|
94
|
+
-d '{
|
|
95
|
+
"filter": {"property": "Status", "select": {"equals": "Active"}},
|
|
96
|
+
"sorts": [{"property": "Date", "direction": "descending"}]
|
|
97
|
+
}'
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Create a data source (database):**
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
curl -X POST "https://api.notion.com/v1/data_sources" \
|
|
104
|
+
-H "Authorization: Bearer $NOTION_KEY" \
|
|
105
|
+
-H "Notion-Version: 2025-09-03" \
|
|
106
|
+
-H "Content-Type: application/json" \
|
|
107
|
+
-d '{
|
|
108
|
+
"parent": {"page_id": "xxx"},
|
|
109
|
+
"title": [{"text": {"content": "My Database"}}],
|
|
110
|
+
"properties": {
|
|
111
|
+
"Name": {"title": {}},
|
|
112
|
+
"Status": {"select": {"options": [{"name": "Todo"}, {"name": "Done"}]}},
|
|
113
|
+
"Date": {"date": {}}
|
|
114
|
+
}
|
|
115
|
+
}'
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Update page properties:**
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
curl -X PATCH "https://api.notion.com/v1/pages/{page_id}" \
|
|
122
|
+
-H "Authorization: Bearer $NOTION_KEY" \
|
|
123
|
+
-H "Notion-Version: 2025-09-03" \
|
|
124
|
+
-H "Content-Type: application/json" \
|
|
125
|
+
-d '{"properties": {"Status": {"select": {"name": "Done"}}}}'
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**Add blocks to page:**
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
curl -X PATCH "https://api.notion.com/v1/blocks/{page_id}/children" \
|
|
132
|
+
-H "Authorization: Bearer $NOTION_KEY" \
|
|
133
|
+
-H "Notion-Version: 2025-09-03" \
|
|
134
|
+
-H "Content-Type: application/json" \
|
|
135
|
+
-d '{
|
|
136
|
+
"children": [
|
|
137
|
+
{"object": "block", "type": "paragraph", "paragraph": {"rich_text": [{"text": {"content": "Hello"}}]}}
|
|
138
|
+
]
|
|
139
|
+
}'
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Property Types
|
|
143
|
+
|
|
144
|
+
Common property formats for database items:
|
|
145
|
+
|
|
146
|
+
- **Title:** `{"title": [{"text": {"content": "..."}}]}`
|
|
147
|
+
- **Rich text:** `{"rich_text": [{"text": {"content": "..."}}]}`
|
|
148
|
+
- **Select:** `{"select": {"name": "Option"}}`
|
|
149
|
+
- **Multi-select:** `{"multi_select": [{"name": "A"}, {"name": "B"}]}`
|
|
150
|
+
- **Date:** `{"date": {"start": "2024-01-15", "end": "2024-01-16"}}`
|
|
151
|
+
- **Checkbox:** `{"checkbox": true}`
|
|
152
|
+
- **Number:** `{"number": 42}`
|
|
153
|
+
- **URL:** `{"url": "https://..."}`
|
|
154
|
+
- **Email:** `{"email": "a@b.com"}`
|
|
155
|
+
- **Relation:** `{"relation": [{"id": "page_id"}]}`
|
|
156
|
+
|
|
157
|
+
## Key Differences in 2025-09-03
|
|
158
|
+
|
|
159
|
+
- **Databases → Data Sources:** Use `/data_sources/` endpoints for queries and retrieval
|
|
160
|
+
- **Two IDs:** Each database now has both a `database_id` and a `data_source_id`
|
|
161
|
+
- Use `database_id` when creating pages (`parent: {"database_id": "..."}`)
|
|
162
|
+
- Use `data_source_id` when querying (`POST /v1/data_sources/{id}/query`)
|
|
163
|
+
- **Search results:** Databases return as `"object": "data_source"` with their `data_source_id`
|
|
164
|
+
- **Parent in responses:** Pages show `parent.data_source_id` alongside `parent.database_id`
|
|
165
|
+
- **Finding the data_source_id:** Search for the database, or call `GET /v1/data_sources/{data_source_id}`
|
|
166
|
+
|
|
167
|
+
## Notes
|
|
168
|
+
|
|
169
|
+
- Page/database IDs are UUIDs (with or without dashes)
|
|
170
|
+
- The API cannot set database view filters — that's UI-only
|
|
171
|
+
- Rate limit: ~3 requests/second average
|
|
172
|
+
- Use `is_inline: true` when creating data sources to embed them in pages
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: obsidian
|
|
3
|
+
description: Work with Obsidian vaults (plain Markdown notes) and automate via obsidian-cli.
|
|
4
|
+
homepage: https://help.obsidian.md
|
|
5
|
+
metadata:
|
|
6
|
+
{
|
|
7
|
+
"kobold":
|
|
8
|
+
{
|
|
9
|
+
"emoji": "💎",
|
|
10
|
+
"requires": { "bins": ["obsidian-cli"] },
|
|
11
|
+
"install":
|
|
12
|
+
[
|
|
13
|
+
{
|
|
14
|
+
"id": "brew",
|
|
15
|
+
"kind": "brew",
|
|
16
|
+
"formula": "yakitrak/yakitrak/obsidian-cli",
|
|
17
|
+
"bins": ["obsidian-cli"],
|
|
18
|
+
"label": "Install obsidian-cli (brew)",
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# Obsidian
|
|
26
|
+
|
|
27
|
+
Obsidian vault = a normal folder on disk.
|
|
28
|
+
|
|
29
|
+
Vault structure (typical)
|
|
30
|
+
|
|
31
|
+
- Notes: `*.md` (plain text Markdown; edit with any editor)
|
|
32
|
+
- Config: `.obsidian/` (workspace + plugin settings; usually don’t touch from scripts)
|
|
33
|
+
- Canvases: `*.canvas` (JSON)
|
|
34
|
+
- Attachments: whatever folder you chose in Obsidian settings (images/PDFs/etc.)
|
|
35
|
+
|
|
36
|
+
## Find the active vault(s)
|
|
37
|
+
|
|
38
|
+
Obsidian desktop tracks vaults here (source of truth):
|
|
39
|
+
|
|
40
|
+
- `~/Library/Application Support/obsidian/obsidian.json`
|
|
41
|
+
|
|
42
|
+
`obsidian-cli` resolves vaults from that file; vault name is typically the **folder name** (path suffix).
|
|
43
|
+
|
|
44
|
+
Fast “what vault is active / where are the notes?”
|
|
45
|
+
|
|
46
|
+
- If you’ve already set a default: `obsidian-cli print-default --path-only`
|
|
47
|
+
- Otherwise, read `~/Library/Application Support/obsidian/obsidian.json` and use the vault entry with `"open": true`.
|
|
48
|
+
|
|
49
|
+
Notes
|
|
50
|
+
|
|
51
|
+
- Multiple vaults common (iCloud vs `~/Documents`, work/personal, etc.). Don’t guess; read config.
|
|
52
|
+
- Avoid writing hardcoded vault paths into scripts; prefer reading the config or using `print-default`.
|
|
53
|
+
|
|
54
|
+
## obsidian-cli quick start
|
|
55
|
+
|
|
56
|
+
Pick a default vault (once):
|
|
57
|
+
|
|
58
|
+
- `obsidian-cli set-default "<vault-folder-name>"`
|
|
59
|
+
- `obsidian-cli print-default` / `obsidian-cli print-default --path-only`
|
|
60
|
+
|
|
61
|
+
Search
|
|
62
|
+
|
|
63
|
+
- `obsidian-cli search "query"` (note names)
|
|
64
|
+
- `obsidian-cli search-content "query"` (inside notes; shows snippets + lines)
|
|
65
|
+
|
|
66
|
+
Create
|
|
67
|
+
|
|
68
|
+
- `obsidian-cli create "Folder/New note" --content "..." --open`
|
|
69
|
+
- Requires Obsidian URI handler (`obsidian://…`) working (Obsidian installed).
|
|
70
|
+
- Avoid creating notes under “hidden” dot-folders (e.g. `.something/...`) via URI; Obsidian may refuse.
|
|
71
|
+
|
|
72
|
+
Move/rename (safe refactor)
|
|
73
|
+
|
|
74
|
+
- `obsidian-cli move "old/path/note" "new/path/note"`
|
|
75
|
+
- Updates `[[wikilinks]]` and common Markdown links across the vault (this is the main win vs `mv`).
|
|
76
|
+
|
|
77
|
+
Delete
|
|
78
|
+
|
|
79
|
+
- `obsidian-cli delete "path/note"`
|
|
80
|
+
|
|
81
|
+
Prefer direct edits when appropriate: open the `.md` file and change it; Obsidian will pick it up.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: openai-image-gen
|
|
3
|
+
description: Batch-generate images via OpenAI Images API. Random prompt sampler + `index.html` gallery.
|
|
4
|
+
homepage: https://platform.openai.com/docs/api-reference/images
|
|
5
|
+
metadata:
|
|
6
|
+
{
|
|
7
|
+
"kobold":
|
|
8
|
+
{
|
|
9
|
+
"emoji": "🖼️",
|
|
10
|
+
"requires": { "bins": ["python3"], "env": ["OPENAI_API_KEY"] },
|
|
11
|
+
"primaryEnv": "OPENAI_API_KEY",
|
|
12
|
+
"install":
|
|
13
|
+
[
|
|
14
|
+
{
|
|
15
|
+
"id": "python-brew",
|
|
16
|
+
"kind": "brew",
|
|
17
|
+
"formula": "python",
|
|
18
|
+
"bins": ["python3"],
|
|
19
|
+
"label": "Install Python (brew)",
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
}
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# OpenAI Image Gen
|
|
27
|
+
|
|
28
|
+
Generate a handful of “random but structured” prompts and render them via the OpenAI Images API.
|
|
29
|
+
|
|
30
|
+
## Run
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
python3 {baseDir}/scripts/gen.py
|
|
34
|
+
open ~/Projects/tmp/openai-image-gen-*/index.html # if ~/Projects/tmp exists; else ./tmp/...
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Useful flags:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# GPT image models with various options
|
|
41
|
+
python3 {baseDir}/scripts/gen.py --count 16 --model gpt-image-1
|
|
42
|
+
python3 {baseDir}/scripts/gen.py --prompt "ultra-detailed studio photo of a lobster astronaut" --count 4
|
|
43
|
+
python3 {baseDir}/scripts/gen.py --size 1536x1024 --quality high --out-dir ./out/images
|
|
44
|
+
python3 {baseDir}/scripts/gen.py --model gpt-image-1.5 --background transparent --output-format webp
|
|
45
|
+
|
|
46
|
+
# DALL-E 3 (note: count is automatically limited to 1)
|
|
47
|
+
python3 {baseDir}/scripts/gen.py --model dall-e-3 --quality hd --size 1792x1024 --style vivid
|
|
48
|
+
python3 {baseDir}/scripts/gen.py --model dall-e-3 --style natural --prompt "serene mountain landscape"
|
|
49
|
+
|
|
50
|
+
# DALL-E 2
|
|
51
|
+
python3 {baseDir}/scripts/gen.py --model dall-e-2 --size 512x512 --count 4
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Model-Specific Parameters
|
|
55
|
+
|
|
56
|
+
Different models support different parameter values. The script automatically selects appropriate defaults based on the model.
|
|
57
|
+
|
|
58
|
+
### Size
|
|
59
|
+
|
|
60
|
+
- **GPT image models** (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`): `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or `auto`
|
|
61
|
+
- Default: `1024x1024`
|
|
62
|
+
- **dall-e-3**: `1024x1024`, `1792x1024`, or `1024x1792`
|
|
63
|
+
- Default: `1024x1024`
|
|
64
|
+
- **dall-e-2**: `256x256`, `512x512`, or `1024x1024`
|
|
65
|
+
- Default: `1024x1024`
|
|
66
|
+
|
|
67
|
+
### Quality
|
|
68
|
+
|
|
69
|
+
- **GPT image models**: `auto`, `high`, `medium`, or `low`
|
|
70
|
+
- Default: `high`
|
|
71
|
+
- **dall-e-3**: `hd` or `standard`
|
|
72
|
+
- Default: `standard`
|
|
73
|
+
- **dall-e-2**: `standard` only
|
|
74
|
+
- Default: `standard`
|
|
75
|
+
|
|
76
|
+
### Other Notable Differences
|
|
77
|
+
|
|
78
|
+
- **dall-e-3** only supports generating 1 image at a time (`n=1`). The script automatically limits count to 1 when using this model.
|
|
79
|
+
- **GPT image models** support additional parameters:
|
|
80
|
+
- `--background`: `transparent`, `opaque`, or `auto` (default)
|
|
81
|
+
- `--output-format`: `png` (default), `jpeg`, or `webp`
|
|
82
|
+
- Note: `stream` and `moderation` are available via API but not yet implemented in this script
|
|
83
|
+
- **dall-e-3** has a `--style` parameter: `vivid` (hyper-real, dramatic) or `natural` (more natural looking)
|
|
84
|
+
|
|
85
|
+
## Output
|
|
86
|
+
|
|
87
|
+
- `*.png`, `*.jpeg`, or `*.webp` images (output format depends on model + `--output-format`)
|
|
88
|
+
- `prompts.json` (prompt → file mapping)
|
|
89
|
+
- `index.html` (thumbnail gallery)
|