diff --git a/README.md b/README.md index 9530815..92e63ce 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,6 @@ These tools are essential for a capable openclaw instance - screen capture, came | [**poltergeist**](https://github.com/steipete/poltergeist) | Universal file watcher with auto-rebuild | | [**sag**](https://github.com/steipete/sag) | Command-line ElevenLabs TTS with mac-style flags | | [**imsg**](https://github.com/steipete/imsg) | iMessage/SMS CLI | -| [**oracle**](https://github.com/steipete/oracle) | Bundle prompts + files for AI queries | ## Usage (as openclaw plugins) @@ -85,7 +84,7 @@ Tools track upstream GitHub releases directly (not Homebrew). go run ./cmd/update-tools ``` -Fetches latest release versions/URLs/hashes and updates the Nix expressions. Oracle uses pnpm and auto-derives its hash via build mismatch. +Fetches latest release versions/URLs/hashes and updates the Nix expressions. ## CI diff --git a/cmd/sync-skills/main.go b/cmd/sync-skills/main.go index 1951a44..3ae2860 100644 --- a/cmd/sync-skills/main.go +++ b/cmd/sync-skills/main.go @@ -67,7 +67,6 @@ func main() { {"peekaboo", "skills/peekaboo"}, {"sag", "skills/sag"}, {"imsg", "skills/imsg"}, - {"oracle", "skills/oracle"}, } log.Printf("[sync-skills] cloning clawdbot main") diff --git a/cmd/update-tools/main.go b/cmd/update-tools/main.go index c155c03..85d0d27 100644 --- a/cmd/update-tools/main.go +++ b/cmd/update-tools/main.go @@ -140,85 +140,6 @@ func updateSummarize(repoRoot string) error { return nil } -func updateOracle(repoRoot string) error { - log.Printf("[update-tools] oracle") - oracleFile := filepath.Join(repoRoot, "nix", "pkgs", "oracle.nix") - orig, err := os.ReadFile(oracleFile) - if err != nil { - return err - } - - rel, err := internal.LatestRelease("steipete/oracle") - if err != nil { - return err - } - version := strings.TrimPrefix(rel.TagName, "v") - var assetURL string - for _, a := range rel.Assets { - if matched, _ := regexp.MatchString(`oracle-[0-9.]+\.tgz`, a.Name); matched { - assetURL = a.BrowserDownloadURL - break - } - } - if assetURL == "" { - return fmt.Errorf("no asset matched for oracle") - } - assetHash, err := internal.PrefetchHash(assetURL) - if err != nil { - return err - } - lockHash, err := internal.PrefetchGitHub("steipete", "oracle", rel.TagName) - if err != nil { - return err - } - - if err := internal.ReplaceOnce(oracleFile, regexp.MustCompile(`version = "[^"]+";`), fmt.Sprintf(`version = "%s";`, version)); err != nil { - return err - } - if err := internal.ReplaceOnce(oracleFile, regexp.MustCompile(`url = "[^"]+";`), fmt.Sprintf(`url = "%s";`, assetURL)); err != nil { - return err - } - if err := internal.ReplaceOnce(oracleFile, regexp.MustCompile(`hash = "sha256-[^"]+";`), fmt.Sprintf(`hash = "%s";`, assetHash)); err != nil { - return err - } - lockRe := regexp.MustCompile(`(?s)lockSrc = fetchFromGitHub \{[^}]*hash = "sha256-[^"]+";`) - if err := internal.ReplaceOnceFunc(oracleFile, lockRe, func(s string) string { - out := regexp.MustCompile(`rev = "[^"]+";`).ReplaceAllString(s, fmt.Sprintf(`rev = "%s";`, rel.TagName)) - out = regexp.MustCompile(`hash = "sha256-[^"]+";`).ReplaceAllString(out, fmt.Sprintf(`hash = "%s";`, lockHash)) - return out - }); err != nil { - return err - } - pnpmRe := regexp.MustCompile(`(?s)pnpmDeps.*hash = "sha256-[^"]+";`) - if err := internal.ReplaceOnceFunc(oracleFile, pnpmRe, func(s string) string { - return regexp.MustCompile(`hash = "sha256-[^"]+";`).ReplaceAllString(s, `hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";`) - }); err != nil { - return err - } - - log.Printf("[update-tools] oracle: deriving pnpm hash") - logText, buildErr := internal.NixBuildOracle() - pnpmHash := internal.ExtractGotHash(logText) - if pnpmHash == "" { - // Restore original file so we don't leave a broken placeholder hash behind. - _ = os.WriteFile(oracleFile, orig, 0644) - // Surface some context in CI logs. This is usually a hash-mismatch line we failed to parse. - lines := strings.Split(logText, "\n") - start := 0 - if len(lines) > 200 { - start = len(lines) - 200 - } - log.Printf("[update-tools] oracle build output (last %d lines):\n%s", len(lines)-start, strings.Join(lines[start:], "\n")) - return fmt.Errorf("oracle pnpm hash not found (build err: %v)", buildErr) - } - if err := internal.ReplaceOnceFunc(oracleFile, pnpmRe, func(s string) string { - return regexp.MustCompile(`hash = "sha256-[^"]+";`).ReplaceAllString(s, fmt.Sprintf(`hash = "%s";`, pnpmHash)) - }); err != nil { - return err - } - return nil -} - func main() { repoRoot, err := os.Getwd() if err != nil { @@ -324,9 +245,4 @@ func main() { } } - if err := updateOracle(repoRoot); err != nil { - // Oracle releases occasionally ship with an out-of-date pnpm-lock.yaml. - // In that case, we keep the previously pinned version and still update other tools. - log.Printf("[update-tools] skipping oracle update: %v", err) - } } diff --git a/flake.nix b/flake.nix index 6765d33..b4ae1dc 100644 --- a/flake.nix +++ b/flake.nix @@ -21,7 +21,6 @@ poltergeist = [ "aarch64-darwin" ]; sag = [ "aarch64-darwin" "x86_64-linux" ]; imsg = [ "aarch64-darwin" ]; - oracle = [ "aarch64-darwin" "x86_64-linux" "aarch64-linux" ]; }; in { packages = forAllSystems (system: @@ -63,12 +62,6 @@ // (lib.optionalAttrs (supports "imsg") { imsg = pkgs.callPackage ./nix/pkgs/imsg.nix {}; }) - // (lib.optionalAttrs (supports "oracle") { - oracle = pkgs.callPackage ./nix/pkgs/oracle.nix { - pkgs = pkgs; - pnpm = if pkgs ? pnpm_10 then pkgs.pnpm_10 else pkgs.pnpm; - }; - }) ); checks = forAllSystems (system: self.packages.${system}); diff --git a/internal/nix.go b/internal/nix.go index 915eef6..1744e16 100644 --- a/internal/nix.go +++ b/internal/nix.go @@ -61,15 +61,6 @@ func PrefetchGitHub(owner, repo, rev string) (string, error) { return res.Hash, nil } -func NixBuildOracle() (string, error) { - cmd := exec.Command("nix", "build", ".#oracle") - var out bytes.Buffer - cmd.Stdout = &out - cmd.Stderr = &out - err := cmd.Run() - return out.String(), err -} - func NixBuildSummarize() (string, error) { return NixBuildSummarizeSystem("") } diff --git a/nix/pkgs/oracle.nix b/nix/pkgs/oracle.nix deleted file mode 100644 index 890dcea..0000000 --- a/nix/pkgs/oracle.nix +++ /dev/null @@ -1,128 +0,0 @@ -{ lib -, stdenv -, fetchurl -, fetchFromGitHub -, nodejs -, pnpm -, python3 -, python3Packages -, pkg-config -, makeWrapper -, pkgs -, zstd -}: - -let - pnpmFetchDepsPkg = pkgs.callPackage "${pkgs.path}/pkgs/build-support/node/fetch-pnpm-deps" { - inherit pnpm; - }; -in -stdenv.mkDerivation (finalAttrs: { - pname = "oracle"; - version = "0.8.5"; - - srcTarball = fetchurl { - url = "https://github.com/steipete/oracle/releases/download/v0.8.5/oracle-0.8.5.tgz"; - hash = "sha256-MSb1+5wEHK38iq+yob7Tz7xov0Wh9zHcmXGs/l2KdMA="; - }; - - lockSrc = fetchFromGitHub { - owner = "steipete"; - repo = "oracle"; - rev = "v0.8.5"; - hash = "sha256-q1l3IcVAj7Gb8Lp0JzQakLRg2AlVrJniMBHRwxKQVbM="; - }; - - srcPatched = stdenv.mkDerivation { - name = "oracle-src-patched"; - src = finalAttrs.srcTarball; - nativeBuildInputs = [ python3 ]; - dontConfigure = true; - dontBuild = true; - unpackPhase = '' - tar -xzf "$src" - ''; - installPhase = '' - mkdir -p "$out" - if [ -d package ]; then - shopt -s dotglob - mv package/* "$out"/ - else - cp -R . "$out"/ - fi - cp -f "${finalAttrs.lockSrc}/pnpm-lock.yaml" "$out/pnpm-lock.yaml" - export OUT_DIR="$out" - python3 - <<'PY' -import json -import os -from pathlib import Path - -path = Path(os.environ["OUT_DIR"]) / "package.json" -data = json.loads(path.read_text()) -data.pop("packageManager", None) -path.write_text(json.dumps(data, indent=2) + "\n") -PY - ''; - }; - - src = finalAttrs.srcPatched; - - pnpmDeps = (pnpmFetchDepsPkg.fetchPnpmDeps { - pname = finalAttrs.pname; - version = finalAttrs.version; - src = finalAttrs.srcPatched; - hash = "sha256-Tmwe55l4QMzXsO7F1kUSnGuZjkuMtDORNtqKnWZ/HrA="; - fetcherVersion = 3; - }); - - nativeBuildInputs = [ - nodejs - pnpm - python3 - python3Packages.setuptools - pkg-config - makeWrapper - zstd - ]; - - env = { - PNPM_IGNORE_PACKAGE_MANAGER_CHECK = "1"; - CI = "1"; - HOME = "/tmp"; - PNPM_HOME = "/tmp/pnpm-home"; - PNPM_CONFIG_HOME = "/tmp/pnpm-config"; - XDG_CACHE_HOME = "/tmp/pnpm-cache"; - NPM_CONFIG_USERCONFIG = "/tmp/pnpm-config/.npmrc"; - npm_config_nodedir = "${nodejs.dev}"; - npm_config_build_from_source = "1"; - PNPM_CONFIG_IGNORE_SCRIPTS = "1"; - }; - - buildPhase = '' - runHook preBuild - mkdir -p "$HOME" "$PNPM_HOME" "$PNPM_CONFIG_HOME" "$XDG_CACHE_HOME" - export PNPM_STORE_PATH="$TMPDIR/pnpm-store" - mkdir -p "$PNPM_STORE_PATH" - tar --zstd -xf ${finalAttrs.pnpmDeps}/pnpm-store.tar.zst -C "$PNPM_STORE_PATH" - pnpm install --offline --no-frozen-lockfile --store-dir "$PNPM_STORE_PATH" --ignore-scripts - runHook postBuild - ''; - - installPhase = '' - runHook preInstall - mkdir -p "$out/libexec" "$out/bin" - cp -r dist package.json vendor assets-oracle-icon.png node_modules "$out/libexec/" - chmod 0755 "$out/libexec/dist/bin/oracle-cli.js" "$out/libexec/dist/bin/oracle-mcp.js" - ln -s "$out/libexec/dist/bin/oracle-cli.js" "$out/bin/oracle" - ln -s "$out/libexec/dist/bin/oracle-mcp.js" "$out/bin/oracle-mcp" - runHook postInstall - ''; - - meta = with lib; { - description = "Bundle prompts + files for second-model review"; - homepage = "https://github.com/steipete/oracle"; - license = licenses.mit; - platforms = [ "aarch64-darwin" "x86_64-linux" "aarch64-linux" ]; - mainProgram = "oracle"; - }; -}) diff --git a/tools/oracle/flake.nix b/tools/oracle/flake.nix deleted file mode 100644 index d61a388..0000000 --- a/tools/oracle/flake.nix +++ /dev/null @@ -1,38 +0,0 @@ -{ - description = "openclaw plugin: oracle"; - - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs?rev=16c7794d0a28b5a37904d55bcca36003b9109aaa&narHash=sha256-fFUnEYMla8b7UKjijLnMe%2BoVFOz6HjijGGNS1l7dYaQ%3D"; - root.url = "github:openclaw/nix-steipete-tools?rev=dbf0a31a57407d9140e32357ea8d0215bd9feed9&narHash=sha256-QkPl/Rgk9DXgaVNhjvHHHjy5e81j+MzcVOouZRdUTLA="; - }; - - outputs = { self, nixpkgs, root }: - let - lib = nixpkgs.lib; - systems = builtins.attrNames root.packages; - pluginFor = system: - let - packagesForSystem = root.packages.${system} or {}; - oracle = packagesForSystem.oracle or null; - in - if oracle == null then null else { - name = "oracle"; - skills = [ ./skills/oracle ]; - packages = [ oracle ]; - needs = { - stateDirs = []; - requiredEnv = []; - }; - }; - in { - packages = lib.genAttrs systems (system: - let - oracle = (root.packages.${system} or {}).oracle or null; - in - if oracle == null then {} - else { oracle = oracle; } - ); - - openclawPlugin = pluginFor; - }; -} diff --git a/tools/oracle/skills/oracle/SKILL.md b/tools/oracle/skills/oracle/SKILL.md deleted file mode 100644 index 727ce76..0000000 --- a/tools/oracle/skills/oracle/SKILL.md +++ /dev/null @@ -1,125 +0,0 @@ ---- -name: oracle -description: Best practices for using the oracle CLI (prompt + file bundling, engines, sessions, and file attachment patterns). -homepage: https://askoracle.dev -metadata: - { - "openclaw": - { - "emoji": "🧿", - "requires": { "bins": ["oracle"] }, - "install": - [ - { - "id": "node", - "kind": "node", - "package": "@steipete/oracle", - "bins": ["oracle"], - "label": "Install oracle (node)", - }, - ], - }, - } ---- - -# oracle — best use - -Oracle bundles your prompt + selected files into one “one-shot” request so another model can answer with real repo context (API or browser automation). Treat output as advisory: verify against code + tests. - -## Main use case (browser, GPT‑5.2 Pro) - -Default workflow here: `--engine browser` with GPT‑5.2 Pro in ChatGPT. This is the common “long think” path: ~10 minutes to ~1 hour is normal; expect a stored session you can reattach to. - -Recommended defaults: - -- Engine: browser (`--engine browser`) -- Model: GPT‑5.2 Pro (`--model gpt-5.2-pro` or `--model "5.2 Pro"`) - -## Golden path - -1. Pick a tight file set (fewest files that still contain the truth). -2. Preview payload + token spend (`--dry-run` + `--files-report`). -3. Use browser mode for the usual GPT‑5.2 Pro workflow; use API only when you explicitly want it. -4. If the run detaches/timeouts: reattach to the stored session (don’t re-run). - -## Commands (preferred) - -- Help: - - `oracle --help` - - If the binary isn’t installed: `npx -y @steipete/oracle --help` (avoid `pnpx` here; sqlite bindings). - -- Preview (no tokens): - - `oracle --dry-run summary -p "" --file "src/**" --file "!**/*.test.*"` - - `oracle --dry-run full -p "" --file "src/**"` - -- Token sanity: - - `oracle --dry-run summary --files-report -p "" --file "src/**"` - -- Browser run (main path; long-running is normal): - - `oracle --engine browser --model gpt-5.2-pro -p "" --file "src/**"` - -- Manual paste fallback: - - `oracle --render --copy -p "" --file "src/**"` - - Note: `--copy` is a hidden alias for `--copy-markdown`. - -## Attaching files (`--file`) - -`--file` accepts files, directories, and globs. You can pass it multiple times; entries can be comma-separated. - -- Include: - - `--file "src/**"` - - `--file src/index.ts` - - `--file docs --file README.md` - -- Exclude: - - `--file "src/**" --file "!src/**/*.test.ts" --file "!**/*.snap"` - -- Defaults (implementation behavior): - - Default-ignored dirs: `node_modules`, `dist`, `coverage`, `.git`, `.turbo`, `.next`, `build`, `tmp` (skipped unless explicitly passed as literal dirs/files). - - Honors `.gitignore` when expanding globs. - - Does not follow symlinks. - - Dotfiles filtered unless opted in via pattern (e.g. `--file ".github/**"`). - - Files > 1 MB rejected. - -## Engines (API vs browser) - -- Auto-pick: `api` when `OPENAI_API_KEY` is set; otherwise `browser`. -- Browser supports GPT + Gemini only; use `--engine api` for Claude/Grok/Codex or multi-model runs. -- Browser attachments: - - `--browser-attachments auto|never|always` (auto pastes inline up to ~60k chars then uploads). -- Remote browser host: - - Host: `oracle serve --host 0.0.0.0 --port 9473 --token ` - - Client: `oracle --engine browser --remote-host --remote-token -p "" --file "src/**"` - -## Sessions + slugs - -- Stored under `~/.oracle/sessions` (override with `ORACLE_HOME_DIR`). -- Runs may detach or take a long time (browser + GPT‑5.2 Pro often does). If the CLI times out: don’t re-run; reattach. - - List: `oracle status --hours 72` - - Attach: `oracle session --render` -- Use `--slug "<3-5 words>"` to keep session IDs readable. -- Duplicate prompt guard exists; use `--force` only when you truly want a fresh run. - -## Prompt template (high signal) - -Oracle starts with **zero** project knowledge. Assume the model cannot infer your stack, build tooling, conventions, or “obvious” paths. Include: - -- Project briefing (stack + build/test commands + platform constraints). -- “Where things live” (key directories, entrypoints, config files, boundaries). -- Exact question + what you tried + the error text (verbatim). -- Constraints (“don’t change X”, “must keep public API”, etc). -- Desired output (“return patch plan + tests”, “give 3 options with tradeoffs”). - -## Safety - -- Don’t attach secrets by default (`.env`, key files, auth tokens). Redact aggressively; share only what’s required. - -## “Exhaustive prompt” restoration pattern - -For long investigations, write a standalone prompt + file set so you can rerun days later: - -- 6–30 sentence project briefing + the goal. -- Repro steps + exact errors + what you tried. -- Attach all context files needed (entrypoints, configs, key modules, docs). - -Oracle runs are one-shot; the model doesn’t remember prior runs. “Restoring context” means re-running with the same prompt + `--file …` set (or reattaching a still-running stored session).