🤖 refactor: remove oracle from nix-steipete-tools

What:
- delete oracle package and plugin exports
- remove oracle from tool update and skill sync pipelines
- remove oracle mentions from README

Why:
- oracle is no longer part of the bundled toolchain
- keep package/update surface aligned with active bundled plugins only

Tests:
- go test ./... (pass)
- nix flake check --no-build (pass)
This commit is contained in:
joshp123 2026-02-17 19:42:26 -08:00
parent d5fc8e2b07
commit 7cd25c98bb
8 changed files with 1 additions and 394 deletions

View File

@ -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 | | [**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 | | [**sag**](https://github.com/steipete/sag) | Command-line ElevenLabs TTS with mac-style flags |
| [**imsg**](https://github.com/steipete/imsg) | iMessage/SMS CLI | | [**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) ## Usage (as openclaw plugins)
@ -85,7 +84,7 @@ Tools track upstream GitHub releases directly (not Homebrew).
go run ./cmd/update-tools 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 ## CI

View File

@ -67,7 +67,6 @@ func main() {
{"peekaboo", "skills/peekaboo"}, {"peekaboo", "skills/peekaboo"},
{"sag", "skills/sag"}, {"sag", "skills/sag"},
{"imsg", "skills/imsg"}, {"imsg", "skills/imsg"},
{"oracle", "skills/oracle"},
} }
log.Printf("[sync-skills] cloning clawdbot main") log.Printf("[sync-skills] cloning clawdbot main")

View File

@ -140,85 +140,6 @@ func updateSummarize(repoRoot string) error {
return nil 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() { func main() {
repoRoot, err := os.Getwd() repoRoot, err := os.Getwd()
if err != nil { 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)
}
} }

View File

@ -21,7 +21,6 @@
poltergeist = [ "aarch64-darwin" ]; poltergeist = [ "aarch64-darwin" ];
sag = [ "aarch64-darwin" "x86_64-linux" ]; sag = [ "aarch64-darwin" "x86_64-linux" ];
imsg = [ "aarch64-darwin" ]; imsg = [ "aarch64-darwin" ];
oracle = [ "aarch64-darwin" "x86_64-linux" "aarch64-linux" ];
}; };
in { in {
packages = forAllSystems (system: packages = forAllSystems (system:
@ -63,12 +62,6 @@
// (lib.optionalAttrs (supports "imsg") { // (lib.optionalAttrs (supports "imsg") {
imsg = pkgs.callPackage ./nix/pkgs/imsg.nix {}; 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}); checks = forAllSystems (system: self.packages.${system});

View File

@ -61,15 +61,6 @@ func PrefetchGitHub(owner, repo, rev string) (string, error) {
return res.Hash, nil 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) { func NixBuildSummarize() (string, error) {
return NixBuildSummarizeSystem("") return NixBuildSummarizeSystem("")
} }

View File

@ -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";
};
})

View File

@ -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;
};
}

View File

@ -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, GPT5.2 Pro)
Default workflow here: `--engine browser` with GPT5.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: GPT5.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 GPT5.2 Pro workflow; use API only when you explicitly want it.
4. If the run detaches/timeouts: reattach to the stored session (dont re-run).
## Commands (preferred)
- Help:
- `oracle --help`
- If the binary isnt installed: `npx -y @steipete/oracle --help` (avoid `pnpx` here; sqlite bindings).
- Preview (no tokens):
- `oracle --dry-run summary -p "<task>" --file "src/**" --file "!**/*.test.*"`
- `oracle --dry-run full -p "<task>" --file "src/**"`
- Token sanity:
- `oracle --dry-run summary --files-report -p "<task>" --file "src/**"`
- Browser run (main path; long-running is normal):
- `oracle --engine browser --model gpt-5.2-pro -p "<task>" --file "src/**"`
- Manual paste fallback:
- `oracle --render --copy -p "<task>" --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 <secret>`
- Client: `oracle --engine browser --remote-host <host:port> --remote-token <secret> -p "<task>" --file "src/**"`
## Sessions + slugs
- Stored under `~/.oracle/sessions` (override with `ORACLE_HOME_DIR`).
- Runs may detach or take a long time (browser + GPT5.2 Pro often does). If the CLI times out: dont re-run; reattach.
- List: `oracle status --hours 72`
- Attach: `oracle session <id> --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 (“dont change X”, “must keep public API”, etc).
- Desired output (“return patch plan + tests”, “give 3 options with tradeoffs”).
## Safety
- Dont attach secrets by default (`.env`, key files, auth tokens). Redact aggressively; share only whats required.
## “Exhaustive prompt” restoration pattern
For long investigations, write a standalone prompt + file set so you can rerun days later:
- 630 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 doesnt remember prior runs. “Restoring context” means re-running with the same prompt + `--file …` set (or reattaching a still-running stored session).