646c82be4e02abaf02d8ad303636239bc3d18ea6

Author
TheEdgeOfRage <git@theedgeofrage.com>
Committer
TheEdgeOfRage <git@theedgeofrage.com>
Date

Message

Update opencode skills

Diff

This diff is truncated to protect this page.

  1diff --git a/dot_config/opencode/opencode.json.tmpl b/dot_config/opencode/opencode.json.tmpl
  2index 7223d882295f852de3d1b9c81329246d02d39841..3cd9e2a45282844b8353448c9ce3c9af31a1eb19 100644
  3--- a/dot_config/opencode/opencode.json.tmpl
  4+++ b/dot_config/opencode/opencode.json.tmpl
  5@@ -30,7 +30,7 @@
  6     "doom_loop": "ask"
  7   },
  8   "plugin": [
  9-    "@tarquinen/opencode-dcp@v3.1.13",
 10+    "@tarquinen/opencode-dcp@v3.1.15",
 11     "/home/pavle/dev/opencode/policy-engine/src/index.ts",
 12     "file:///home/pavle/.local/lib/node_modules/@rynfar/meridian/plugin/meridian.ts"
 13   ],
 14diff --git a/dot_config/opencode/skills/comms-polish/SKILL.md b/dot_config/opencode/skills/comms-polish/SKILL.md
 15new file mode 100644
 16index 0000000000000000000000000000000000000000..6fc217b039754c41f658fba9fd141656c90f33f6
 17--- /dev/null
 18+++ b/dot_config/opencode/skills/comms-polish/SKILL.md
 19@@ -0,0 +1,91 @@
 20+---
 21+name: comms-polish
 22diff --git a/dot_config/opencode/skills/go-code/SKILL.md b/dot_config/opencode/skills/go-code/SKILL.md
 23new file mode 100644
 24index 0000000000000000000000000000000000000000..415c1463e65eb9bac543636c65f918e5ae3f8ab4
 25--- /dev/null
 26+++ b/dot_config/opencode/skills/go-code/SKILL.md
 27@@ -0,0 +1,8 @@
 28+---
 29+name: go-code
 30+description: Rules for writing go code
 31+---
 32+
 33+## Go development
 34+
 35+- Always use `make lint` if available, if not, prefer `go vet` over `go build`
 36diff --git a/dot_config/opencode/skills/linear-update/SKILL.md b/dot_config/opencode/skills/linear-update/SKILL.md
 37new file mode 100644
 38index 0000000000000000000000000000000000000000..9df76bc9292aa469c6cb59003bedf4cf4be86ca5
 39--- /dev/null
 40+++ b/dot_config/opencode/skills/linear-update/SKILL.md
 41@@ -0,0 +1,122 @@
 42+---
 43+name: linear-update
 44+version: 2.0.0
 45+description: "Draft and post a weekly status update to Linear for a project OR initiative. Auto-detects which the name refers to, synthesizes Past week / Next week / Asks from Linear + Slack, and posts on approval."
 46+metadata:
 47+  openclaw:
 48+    category: "productivity"
 49+    requires:
 50+      mcpServers: ["linear", "slack"]
 51+---
 52+
 53+# /linear-update
 54+
 55+Draft and post a weekly status update to Linear. Takes a **name**, figures out whether it
 56+is a Linear **project** or **initiative**, then writes the update in the **Past week /
 57+Next week / Asks** format and posts it on your approval.
 58+
 59+## Parameters
 60+
 61+| Parameter | Required | Default | Description |
 62+|-----------|----------|---------|-------------|
 63+| `name` | No | — | Name of the Linear project or initiative to update (passed as the argument). The skill auto-detects which it is. If omitted, ask the user. |
 64+| `channels` | No | auto | Optional Slack channel name(s) to pull context from. If omitted, auto-discover and confirm. |
 65+
 66+## Step 1 — Resolve the name (project vs. initiative)
 67+
 68+This is the first thing the skill does and it determines everything downstream.
 69+
 70+1. If no `name` was provided, ask the user which project or initiative to update.
 71+2. Search both in parallel:
 72+   - `list_initiatives` with `query: <name>`
 73+   - `list_projects` with `query: <name>`
 74+3. Match case-insensitively against the returned names:
 75+   - **Exactly one type matches** → use that type (`project` or `initiative`).
 76+   - **Both an initiative and a project match** (or near-match) → ask the user which one they mean before continuing. Do not guess.
 77+   - **Nothing matches** → show the closest candidates from both lists and ask the user to pick or rename.
 78+4. Hold onto the resolved `type` (`project` | `initiative`) and the canonical name/ID — every later tool call branches on it.
 79+
 80+## Step 2 — Gather context (parallel where possible)
 81+
 82diff --git a/dot_config/opencode/skills/share-tables/SKILL.md b/dot_config/opencode/skills/share-tables/SKILL.md
 83new file mode 100644
 84index 0000000000000000000000000000000000000000..5593174147de2d9bdb2075ed36b85437d0582582
 85--- /dev/null
 86+++ b/dot_config/opencode/skills/share-tables/SKILL.md
 87@@ -0,0 +1,104 @@
 88+---
 89+name: share-tables
 90diff --git a/dot_config/opencode/skills/share-tables/mappings_prod b/dot_config/opencode/skills/share-tables/mappings_prod
 91new file mode 100644
 92index 0000000000000000000000000000000000000000..327c8d2f9add112b8464aa3f77e6d8e3e6ba8074
 93--- /dev/null
 94+++ b/dot_config/opencode/skills/share-tables/mappings_prod
 95@@ -0,0 +1,3 @@
 96+stablecore:29946
 97+dune_curated_data:35887
 98+dune:12
 99diff --git a/dot_config/opencode/skills/share-tables/scripts/executable_get-table.sh b/dot_config/opencode/skills/share-tables/scripts/executable_get-table.sh
100new file mode 100644
101index 0000000000000000000000000000000000000000..2e22403e4f012848ec2614bd146fa3aadca98a83
102--- /dev/null
103+++ b/dot_config/opencode/skills/share-tables/scripts/executable_get-table.sh
104@@ -0,0 +1,53 @@
105+#!/usr/bin/env bash
106+# Look up the type (and view SQL, if applicable) of one or more tables via
107+# the Catalog gRPC service, authenticating as a given source team.
108+#
109+# One request per table. No recursion — view-dependency traversal is the
110+# LLM's responsibility.
111+#
112+# Usage:
113+#   get-table.sh <dev|prod> <from_handle:from_id> <catalog.schema.table>...
114+#
115+# Example:
116+#   get-table.sh prod stablecore:29946 dune.stablecore.stablecoins_evm_balances_enriched_v2
117+#
118+# Requires: grpcurl, jq, tailscale network access to the catalog service.
119+set -euo pipefail
120+
121+if (( $# < 3 )); then
122+  echo "usage: $0 <dev|prod> <from_handle:from_id> <catalog.schema.table>..." >&2
123+  exit 2
124+fi
125+
126+env=$1 from=$2
127+shift 2
128+
129+case $env in
130+  dev)  host=dev-catalog-svc-trino.ayu-decibel.ts.net:4040 ;;
131+  prod) host=prod-catalog-service-trino.ayu-decibel.ts.net:4040 ;;
132+  *) echo "error: env must be dev or prod (got: $env)" >&2; exit 2 ;;
133+esac
134+
135+if [[ $from != *:* ]]; then
136+  echo "error: from must be in the form handle:id (got: $from)" >&2
137+  exit 2
138+fi
139+from_id=${from##*:}
140+[[ $from_id =~ ^[0-9]+$ ]] || { echo "error: from id must be numeric (got: $from_id)" >&2; exit 2; }
141+
142+creds=$(printf '{"customerID": "team_%s"}' "$from_id" | base64 -w0 | tr -d '=')
143+
144+for fqn in "$@"; do
145+  IFS='.' read -ra parts <<<"$fqn"
146+  if (( ${#parts[@]} != 3 )) || [[ -z ${parts[0]} || -z ${parts[1]} || -z ${parts[2]} ]]; then
147+    echo "error: table must be in the form catalog.schema.name (got: $fqn)" >&2
148+    exit 2
149+  fi
150+  catalog=${parts[0]} schema=${parts[1]} name=${parts[2]}
151+  echo "=== $catalog.$schema.$name ==="
152+  grpcurl -plaintext \
153+    -d "{\"sql_id\":{\"catalog\":\"$catalog\",\"schema\":\"$schema\",\"name\":\"$name\"},\"credentials\":\"$creds\"}" \
154+    "$host" \
155+    core.catalog.apis.v1.CatalogService/GetTrinoTable \
156+    | jq -r '"type: " + .table.type, (if .table.viewMetadata then "viewSql:\n" + .table.viewMetadata.viewSql else empty end)'
157+done
158diff --git a/dot_config/opencode/skills/share-tables/scripts/executable_share.sh b/dot_config/opencode/skills/share-tables/scripts/executable_share.sh
159new file mode 100644
160index 0000000000000000000000000000000000000000..57622f96203367085573ab6e7dd50a94dbeacf69
161--- /dev/null
162+++ b/dot_config/opencode/skills/share-tables/scripts/executable_share.sh
163@@ -0,0 +1,66 @@
164+#!/usr/bin/env bash
165+# Grant or revoke a team's access to another team's private catalog tables
166+# via the Catalog gRPC service.
167+#
168+# Usage:
169+#   share.sh <dev|prod> <add|remove> <from_handle:from_id> <dest_handle> <catalog.schema.table>...
170+#
171+# Example:
172+#   share.sh prod add stablecore:29946 gfdionis_team dune.stablecore.stablecoins_evm_activity_enriched
173+#
174+# Requires: grpcurl, tailscale network access to the catalog service.
175+set -euo pipefail
176+
177+if (( $# < 5 )); then
178+  echo "usage: $0 <dev|prod> <add|remove> <from_handle:from_id> <dest_handle> <catalog.schema.table>..." >&2
179+  exit 2
180+fi
181+
182+env=$1 action=$2 from=$3 dest=$4
183+shift 4
184+
185+case $env in
186+  dev)  host=dev-catalog-svc-trino.ayu-decibel.ts.net:4040 ;;
187+  prod) host=prod-catalog-service-trino.ayu-decibel.ts.net:4040 ;;
188+  *) echo "error: env must be dev or prod (got: $env)" >&2; exit 2 ;;
189+esac
190+
191+case $action in
192+  add)    method=AddTableTeamAccess ;;
193+  remove) method=RemoveTableTeamAccess ;;
194+  *) echo "error: action must be add or remove (got: $action)" >&2; exit 2 ;;
195+esac
196+
197+if [[ $from != *:* ]]; then
198+  echo "error: from must be in the form handle:id (got: $from)" >&2
199+  exit 2
200+fi
201+from_id=${from##*:}
202+[[ $from_id =~ ^[0-9]+$ ]] || { echo "error: from id must be numeric (got: $from_id)" >&2; exit 2; }
203+
204+creds=$(printf '{"customerID":"team_%s","duneAdminKey":"duneDatashare"}' "$from_id" | base64 -w0 | tr -d '=')
205+
206+for fqn in "$@"; do
207+  IFS='.' read -ra parts <<<"$fqn"
208+  if (( ${#parts[@]} != 3 )) || [[ -z ${parts[0]} || -z ${parts[1]} || -z ${parts[2]} ]]; then
209+    echo "error: table must be in the form catalog.schema.name (got: $fqn)" >&2
210+    exit 2
211+  fi
212+  catalog=${parts[0]} schema=${parts[1]} name=${parts[2]}
213+  echo ">>> $action $catalog.$schema.$name -> $dest"
214+  set +e
215+  out=$(grpcurl -plaintext \
216+    -d "{\"sql_id\":{\"catalog\":\"$catalog\",\"schema\":\"$schema\",\"name\":\"$name\"},\"team_handle\":\"$dest\",\"credentials\":\"$creds\"}" \
217+    "$host" \
218+    "core.catalog.apis.v1.CatalogService/$method" 2>&1)
219+  status=$?
220+  set -e
221+  printf '%s\n' "$out"
222+  if (( status != 0 )); then
223+    if [[ $out == *"can only share private tables"* ]]; then
224+      echo "    (already public, skipping)"
225+      continue
226+    fi
227+    exit "$status"
228+  fi
229+done
230diff --git a/dot_config/opencode/skills/websearch/SKILL.md b/dot_config/opencode/skills/websearch/SKILL.md
231deleted file mode 100644
232index 0a3b39ffc7af4b21caf9a0a60d9b27dfd9c0b09c..0000000000000000000000000000000000000000
233--- a/dot_config/opencode/skills/websearch/SKILL.md
234+++ /dev/null
235@@ -1,56 +0,0 @@
236----
237-name: websearch
238-description: >
239-  Perform web searches using ddgs (web search service client). Use this skill
240-  whenever you are uncertain about a fact, need current information, need to
241-  look up a library/API/version, or the user explicitly asks to search the web
242-  for something. Trigger proactively when you'd otherwise guess or hallucinate
243-  an answer — search instead. Also triggers on: "look this up", "what is the
244-  latest", "search for", "I'm not sure about", or any question about package
245-  versions, documentation, or third-party tools.
246----
247-
248-## When to use
249-
250-Search the web when:
251-- You're uncertain about a fact and could reasonably be wrong
252-- The user asks for current/recent information (versions, docs)
253-- The user explicitly asks for a web search
254-- You need to verify something before giving a definitive answer
255-
256-Don't search for things you know with high confidence, or for purely
257-implementation tasks where no external lookup is needed.
258-
259-## How to search
260-
261-Run the bundled script from this skill's `scripts/` directory:
262-
263-```bash
264-uv run -w ddgs python <skill_dir>/scripts/search.py "<query>" [max_results]
265-```
266-
267-`max_results` defaults to 5. Increase it (up to ~10) for broader topics.
268-
269-The script prints results in this format:
270-
271-```
272-{i}. {title}"
273-   {href}"
274-   {body}"
275-```
276-
277-## Crafting good queries
278-
279-- Be specific: `"python requests library timeout default"` beats `"python timeout"`
280-- For versioning: `"ddgs latest version pypi"` or `"package changelog site:github.com"`
281-- For docs: append `site:docs.example.com` or `filetype:html` when helpful
282-- For recent info: the library uses `timelimit` but the script defaults to no
283-  limit; if you need recent results, modify the query with a year or "2025"
284-
285-## Presenting results
286-
287-After searching:
288-1. Summarize what you found — don't dump raw results on the user
289-2. Cite the source URL for any specific claim
290-3. If results are thin or irrelevant, try a rephrased query before giving up
291-4. If nothing useful turns up after 2 attempts, say so honestly
292diff --git a/dot_config/opencode/skills/websearch/scripts/search.py b/dot_config/opencode/skills/websearch/scripts/search.py
293deleted file mode 100644
294index 4cc412ec1e600a87e6a20b275c97ebd22f974a0b..0000000000000000000000000000000000000000
295--- a/dot_config/opencode/skills/websearch/scripts/search.py
296+++ /dev/null
297@@ -1,25 +0,0 @@
298-#!/usr/bin/env python3
299-"""Web search using ddgs. Usage: uv run -w ddgs python search.py <query> [max_results]"""
300-
301-import sys
302-from ddgs import DDGS
303-
304-
305-def main():
306-    if len(sys.argv) < 2:
307-        print("Usage: search.py <query> [max_results]", file=sys.stderr)
308-        sys.exit(1)
309-
310-    query = sys.argv[1]
311-    max_results = int(sys.argv[2]) if len(sys.argv) > 2 else 5
312-
313-    results = DDGS().text(query, max_results=max_results)
314-    for i, r in enumerate(results, 1):
315-        print(f"{i}. {r['title']}")
316-        print(f"   {r['href']}")
317-        print(f"   {r['body']}")
318-        print()
319-
320-
321-if __name__ == "__main__":
322-    main()