From 8a1fcc67c8cc5575d6e065d455de202f0aa8dc84 Mon Sep 17 00:00:00 2001 From: Twentyninehairs_bot Date: Sun, 3 May 2026 21:54:06 -0700 Subject: [PATCH] Add git-ops and opencode-setup skills for documentation --- README.md | 2 + git-ops.mjs | 131 ++++++++++++++++++++++++++++++++++ opencode-setup.mjs | 171 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 304 insertions(+) create mode 100644 git-ops.mjs create mode 100644 opencode-setup.mjs diff --git a/README.md b/README.md index 881de44..f839dd5 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,8 @@ This approach: - `opencode-start.sh` — Wrapper script that starts OpenCode with/without omoa - `omoa-post-upgrade.sh` — Removes omoa plugin from `opencode.json` after upstream install - `omoa-toggle.mjs` — OpenCode skill for Telegram bot integration +- `git-ops.mjs` — OpenCode skill for git operations with Hibbhome Gitea server +- `opencode-setup.mjs` — OpenCode skill documenting the full system architecture - `README.md` — This file ## Installation diff --git a/git-ops.mjs b/git-ops.mjs new file mode 100644 index 0000000..6225dca --- /dev/null +++ b/git-ops.mjs @@ -0,0 +1,131 @@ +/** + * git-ops.mjs — OpenCode skill for git operations with Hibbhome Gitea server + * + * PURPOSE: + * Documents the git server setup and provides helper functions for + * common git operations. New sessions can load this skill to immediately + * know how to work with the Hibbhome Gitea server. + * + * SERVER DETAILS: + * - Web UI / API: https://git.hibbhome.com + * - SSH hostname: wwwdb.dmz.home.hibbhome.com + * - SSH clone URL: git@wwwdb.dmz.home.hibbhome.com:/.git + * - API key: fc4332a8a1a87b1f8cbcc01668ed94803dcd3a81 + * - Organization: Hibbhome + * + * SSH KEY: + * - Location: ~/.ssh/id_gitea (ed25519) + * - Added to Gitea server for passwordless push + * + * USAGE: + * Load this skill when you need to: + * - Create a new repo on the Gitea server + * - Push code to the server + * - Clone repos from the server + * - Check repo status + * + * EXAMPLES: + * skill("git-ops") — Load this skill + * Then use the helper functions or follow the documentation + * + * UPSTREAM REPO: + * https://git.hibbhome.com/Hibbhome/opencode-omoa-toggle + * + * CREATED: 2026-05-03 + */ + +import { tool } from "@opencode-ai/plugin/tool"; +import { execSync } from "node:child_process"; + +const GITEA_API = "https://git.hibbhome.com"; +const GITEA_SSH = "git@wwwdb.dmz.home.hibbhome.com"; +const GITEA_TOKEN = "fc4332a8a1a87b1f8cbcc01668ed94803dcd3a81"; +const GITEA_ORG = "Hibbhome"; + +export const GitOpsPlugin = async (_ctx) => { + return { + tool: { + /** + * Create a new repo on the Gitea server + */ + git_create_repo: tool({ + description: "Create a new repo on the Hibbhome Gitea server", + args: { + name: tool.schema.string().describe("Repository name (e.g., my-project)"), + description: tool.schema.string().describe("Repository description"), + private: tool.schema.boolean().describe("Whether the repo should be private").default(false), + }, + async execute(args) { + try { + const result = execSync(`curl -s -X POST "${GITEA_API}/api/v1/orgs/${GITEA_ORG}/repos" \ + -H "Authorization: token ${GITEA_TOKEN}" \ + -H "Content-Type: application/json" \ + -d '{"name":"${args.name}","description":"${args.description}","private":${args.private}}'`, + { encoding: "utf-8" } + ); + const repo = JSON.parse(result); + return `Repo created: ${repo.clone_url}\nSSH: ${GITEA_SSH}:${GITEA_ORG}/${args.name}.git`; + } catch (err) { + return `Error creating repo: ${err.message}`; + } + }, + }), + + /** + * Push a local directory to a Gitea repo + */ + git_push: tool({ + description: "Push a local directory to a Gitea repo", + args: { + local_path: tool.schema.string().describe("Local directory path"), + repo_name: tool.schema.string().describe("Repository name on Gitea"), + branch: tool.schema.string().describe("Branch name").default("master"), + }, + async execute(args) { + try { + const remote_url = `${GITEA_SSH}:${GITEA_ORG}/${args.repo_name}.git`; + + // Check if git repo exists + const is_git = execSync(`cd ${args.local_path} && git rev-parse --is-inside-work-tree 2>/dev/null || echo "false"`, { encoding: "utf-8" }).trim(); + + if (is_git !== "true") { + execSync(`cd ${args.local_path} && git init && git add . && git commit -m "Initial commit"`, { encoding: "utf-8" }); + } + + // Add remote if not exists + try { + execSync(`cd ${args.local_path} && git remote add origin ${remote_url}`, { encoding: "utf-8" }); + } catch (e) { + // Remote already exists + } + + execSync(`cd ${args.local_path} && git push -u origin ${args.branch}`, { encoding: "utf-8" }); + return `Pushed to ${remote_url}`; + } catch (err) { + return `Error pushing: ${err.message}`; + } + }, + }), + + /** + * List repos in the Hibbhome organization + */ + git_list_repos: tool({ + description: "List repos in the Hibbhome organization", + args: {}, + async execute() { + try { + const result = execSync(`curl -s "${GITEA_API}/api/v1/orgs/${GITEA_ORG}/repos" \ + -H "Authorization: token ${GITEA_TOKEN}"`, + { encoding: "utf-8" } + ); + const repos = JSON.parse(result); + return repos.map(r => `- ${r.name}: ${r.description || 'No description'}\n ${r.clone_url}`).join("\n"); + } catch (err) { + return `Error listing repos: ${err.message}`; + } + }, + }), + }, + }; +}; diff --git a/opencode-setup.mjs b/opencode-setup.mjs new file mode 100644 index 0000000..da6b12c --- /dev/null +++ b/opencode-setup.mjs @@ -0,0 +1,171 @@ +/** + * opencode-setup.mjs — OpenCode skill documenting the full system architecture + * + * PURPOSE: + * Documents the complete OpenCode setup including providers, services, + * skills, and configuration. New sessions can load this skill to understand + * the entire system without rediscovering everything. + * + * SYSTEM OVERVIEW: + * Host: memgpt (kenny@memgpt) + * OS: Linux + * OpenCode: v1.14.33 + * + * PROVIDERS: + * 1. OpenCode Zen — https://opencode.ai/zen/v1 + * Models: GPT-5.4, GPT-5.3-codex, GPT-5-nano, GLM-5, Big Pickle, + * MiniMax M2.7, Kimi K2.5 + * + * 2. XiaomiMimo (SGP) — https://token-plan-sgp.xiaomimimo.com/v1 + * Models: Mimo V2.5, Mimo V2.5 Pro, Mimo V2 Omni, Mimo V2 Pro + * + * 3. Claude Code (proxy) — http://localhost:3000/v1 + * Models: Claude Opus 4.7, Claude Sonnet 4.6, Claude Haiku 4.5 + * Proxy script: ~/.config/opencode/claude-proxy.mjs + * Uses: claude -p CLI with --permission-mode bypassPermissions + * + * 4. CanopyWave — https://inference.canopywave.io/v1 + * Models: DeepSeek V4 Flash, DeepSeek V3.2, GLM-5, Kimi K2.6, etc. + * + * 5. DeepInfra — https://api.deepinfra.com/v1 + * Models: DeepSeek, Gemini, Llama, Qwen, GLM, Kimi, MiniMax, etc. + * + * 6. Ollama (remote) — http://llm01:11434/v1 + * Models: Gemma 4 31B, Qwen 3.6 + * + * SERVICES (systemd user services): + * 1. opencode-serve.service — Main OpenCode server (port 4096) + * ExecStart: ~/.config/opencode/opencode-start.sh + * Supports: --omoa flag for oh-my-openagent injection + * + * 2. opencode-telegram-bot.service — Telegram bot client + * Bot: @twentyninehairs_opencode_mem_bot + * Config: ~/.config/opencode-telegram-bot/.env + * Connects to: http://localhost:4096 + * + * 3. claude-proxy.service — Proxy for Claude models + * Port: 3000 + * Script: ~/.config/opencode/claude-proxy.mjs + * Uses: /home/kenny/.local/bin/claude -p + * + * SKILLS: + * 1. nextcloud — File operations with nc.hibbhome.com + * Scripts: ~/.config/opencode/skills/nextcloud.sh, nextcloud.mjs + * + * 2. omoa-toggle — Toggle oh-my-openagent plugin + * Script: ~/.config/opencode/skills/omoa-toggle.mjs + * CLI: ~/.config/opencode/omoa + * + * 3. git-ops — Git operations with Hibbhome Gitea server + * Script: ~/.config/opencode/skills/git-ops.mjs + * + * 4. opencode-setup — This skill (system documentation) + * + * CONFIGURATION: + * Main config: ~/.config/opencode/opencode.json + * Skills dir: ~/.config/opencode/skills/ + * Claude proxy: ~/.config/opencode/claude-proxy.mjs + * Telegram bot config: ~/.config/opencode-telegram-bot/.env + * + * GIT SERVER: + * API: https://git.hibbhome.com + * SSH: git@wwwdb.dmz.home.hibbhome.com + * API key: fc4332a8a1a87b1f8cbcc01668ed94803dcd3a81 + * Organization: Hibbhome + * + * SSH KEYS: + * Gitea: ~/.ssh/id_gitea (ed25519) + * Added to Gitea server for passwordless push + * + * NEXTCLOUD: + * URL: https://nc.hibbhome.com + * User: opencode_memgpt + * Password: ioH2o-QnQJx-8z7Dx-edPyx-pmxLA + * + * OH-MY-OPENAGENT: + * State file: ~/.config/opencode/omoa-enabled + * Toggle: omoa [on|off|status|toggle] + * Post-upgrade: omoa-post-upgrade.sh + * Uses OPENCODE_CONFIG_CONTENT for runtime injection + * + * TELEGRAM BOT: + * Bot username: @twentyninehairs_opencode_mem_bot + * User ID: 5274535598 + * Commands: /commands → omoa_toggle, /commands → nextcloud_*, etc. + * + * REPLICATING TO NEW SYSTEM: + * 1. Install OpenCode: https://opencode.ai + * 2. Clone this repo: git clone git@wwwdb.dmz.home.hibbhome.com:Hibbhome/opencode-omoa-toggle.git + * 3. Copy config files to ~/.config/opencode/ + * 4. Install npm packages: cd ~/.config/opencode && npm install + * 5. Set up systemd services (see systemd service files) + * 6. Configure Telegram bot (see opencode-telegram-bot/.env) + * 7. Add SSH keys to Gitea + * + * CREATED: 2026-05-03 + */ + +import { tool } from "@opencode-ai/plugin/tool"; +import { execSync } from "node:child_process"; +import { readFileSync } from "node:fs"; + +export const OpenCodeSetupPlugin = async (_ctx) => { + return { + tool: { + /** + * Show system status + */ + setup_status: tool({ + description: "Show OpenCode system status (services, providers, skills)", + args: {}, + async execute() { + try { + const services = execSync("systemctl --user status opencode-serve.service opencode-telegram-bot.service claude-proxy.service 2>&1 | grep -E 'Active|Main'", { encoding: "utf-8" }); + return `SERVICES:\n${services}\n\nUse skill("opencode-setup") for full documentation.`; + } catch (err) { + return `Error: ${err.message}`; + } + }, + }), + + /** + * Show provider configuration + */ + setup_providers: tool({ + description: "Show configured providers and models", + args: {}, + async execute() { + try { + const config = JSON.parse(readFileSync("/home/kenny/.config/opencode/opencode.json", "utf-8")); + const providers = Object.entries(config.provider || {}).map(([name, p]) => { + const models = Object.keys(p.models || {}).join(", "); + return `- ${name}: ${p.options?.baseURL || 'N/A'}\n Models: ${models}`; + }).join("\n"); + return `PROVIDERS:\n${providers}`; + } catch (err) { + return `Error: ${err.message}`; + } + }, + }), + + /** + * Show installed skills + */ + setup_skills: tool({ + description: "Show installed skills", + args: {}, + async execute() { + try { + const config = JSON.parse(readFileSync("/home/kenny/.config/opencode/opencode.json", "utf-8")); + const skills = Object.entries(config.skills || {}).map(([name, s]) => { + return `- ${name}: ${s.description}`; + }).join("\n"); + return `SKILLS:\n${skills}`; + } catch (err) { + return `Error: ${err.message}`; + } + }, + }), + }, + }; +};