Compare commits
30 Commits
fix/update
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c94e18bc15 | ||
|
|
620dc9666c | ||
|
|
433c7b06af | ||
|
|
de56f637f2 | ||
|
|
3103831ea1 | ||
|
|
1d8fe51b1e | ||
|
|
81cbbedb53 | ||
|
|
26a27195ca | ||
|
|
3584e2b6d2 | ||
|
|
2afbbd55bf | ||
|
|
457023efd4 | ||
|
|
3e8e39bd85 | ||
|
|
9647ce7fcb | ||
|
|
65a58f8367 | ||
|
|
d17f197c47 | ||
|
|
5f677a283d | ||
|
|
cd4c429ff3 | ||
|
|
526067c585 | ||
|
|
9392ba9ac6 | ||
|
|
561592b0b1 | ||
|
|
2b97c49e03 | ||
|
|
50194a9b8e | ||
|
|
eddb00d4c1 | ||
|
|
95ebfa73f4 | ||
|
|
c110209720 | ||
|
|
7cd25c98bb | ||
|
|
d5fc8e2b07 | ||
|
|
b668498d7d | ||
|
|
90516869c1 | ||
|
|
c718196c26 |
68
README.md
68
README.md
@ -16,21 +16,35 @@ These tools are essential for a capable openclaw instance - screen capture, came
|
||||
- **Fresh**: CI keeps tools and skills at latest automatically
|
||||
- **Integrated**: Skills teach your bot how to use each tool
|
||||
|
||||
## Pure Nix and Home Manager design
|
||||
|
||||
This repo is meant to be consumable directly from Nix flakes, Darwin, and Home
|
||||
Manager configs. Packages should stay pinned and reproducible, and optional
|
||||
Home Manager modules should expose normal `programs.<name>` options instead of
|
||||
requiring downstream users to hand-write app bundle or launchd glue.
|
||||
|
||||
For macOS app bundles, prefer a Nix package plus Home Manager integration. Home
|
||||
Manager can expose app bundles from `home.packages` through its Darwin app
|
||||
targets, and modules can opt into `launchd.agents` when Home Manager should own
|
||||
startup. Homebrew casks are still useful, but they belong in a nix-darwin
|
||||
Homebrew configuration, not in these pure Nix package/module definitions.
|
||||
|
||||
## What's included
|
||||
|
||||
| Tool | What it does |
|
||||
|------|--------------|
|
||||
| [**summarize**](https://github.com/steipete/summarize) | Link → clean text → summary |
|
||||
| [**discrawl**](https://github.com/steipete/discrawl) | Mirror Discord into SQLite and search history locally |
|
||||
| [**wacrawl**](https://github.com/steipete/wacrawl) | Read-only local archive and search for WhatsApp Desktop data |
|
||||
| [**gogcli**](https://github.com/steipete/gogcli) | Google CLI for Gmail, Calendar, Drive, and Contacts |
|
||||
| [**goplaces**](https://github.com/steipete/goplaces) | Google Places API (New) CLI |
|
||||
| [**camsnap**](https://github.com/steipete/camsnap) | Capture snapshots/clips from RTSP/ONVIF cameras |
|
||||
| [**sonoscli**](https://github.com/steipete/sonoscli) | Control Sonos speakers |
|
||||
| [**bird**](https://github.com/steipete/bird) | Fast X CLI for tweeting, replying, and reading |
|
||||
| [**peekaboo**](https://github.com/steipete/peekaboo) | Lightning-fast macOS screenshots & AI vision analysis |
|
||||
| [**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 |
|
||||
| [**CodexBar**](https://github.com/steipete/CodexBar) | macOS menu bar app for Codex, Claude, and other provider usage |
|
||||
|
||||
## Usage (as openclaw plugins)
|
||||
|
||||
@ -39,8 +53,10 @@ Each tool is a subflake under `tools/<tool>/` exporting `openclawPlugin`. Point
|
||||
```nix
|
||||
programs.openclaw.plugins = [
|
||||
{ source = "github:openclaw/nix-steipete-tools?dir=tools/camsnap"; }
|
||||
{ source = "github:openclaw/nix-steipete-tools?dir=tools/discrawl"; }
|
||||
{ source = "github:openclaw/nix-steipete-tools?dir=tools/peekaboo"; }
|
||||
{ source = "github:openclaw/nix-steipete-tools?dir=tools/summarize"; }
|
||||
{ source = "github:openclaw/nix-steipete-tools?dir=tools/wacrawl"; }
|
||||
];
|
||||
```
|
||||
|
||||
@ -58,13 +74,53 @@ inputs.nix-steipete-tools.url = "github:openclaw/nix-steipete-tools";
|
||||
|
||||
# Then use:
|
||||
inputs.nix-steipete-tools.packages.aarch64-darwin.camsnap
|
||||
inputs.nix-steipete-tools.packages.aarch64-darwin.discrawl
|
||||
inputs.nix-steipete-tools.packages.aarch64-darwin.peekaboo
|
||||
inputs.nix-steipete-tools.packages.aarch64-darwin.wacrawl
|
||||
inputs.nix-steipete-tools.packages.aarch64-darwin.codexbar-app
|
||||
# etc.
|
||||
|
||||
# Linux examples:
|
||||
inputs.nix-steipete-tools.packages.x86_64-linux.camsnap
|
||||
inputs.nix-steipete-tools.packages.x86_64-linux.discrawl
|
||||
inputs.nix-steipete-tools.packages.aarch64-linux.gogcli
|
||||
inputs.nix-steipete-tools.packages.x86_64-linux.summarize
|
||||
inputs.nix-steipete-tools.packages.x86_64-linux.wacrawl
|
||||
```
|
||||
|
||||
### Home Manager modules
|
||||
|
||||
Some packages also ship Home Manager modules so they can be enabled directly
|
||||
without hand-writing install and launchd wiring. For CodexBar:
|
||||
|
||||
```nix
|
||||
{
|
||||
imports = [ inputs.nix-steipete-tools.homeManagerModules.codexbar ];
|
||||
|
||||
programs.codexbar.enable = true;
|
||||
}
|
||||
```
|
||||
|
||||
That adds the CodexBar app package to `home.packages`. Home Manager can then
|
||||
expose the app bundle through its Darwin app targets. If you want Home Manager
|
||||
to own startup too, enable the launchd agent explicitly:
|
||||
|
||||
```nix
|
||||
{
|
||||
programs.codexbar = {
|
||||
enable = true;
|
||||
launchd.enable = true;
|
||||
launchd.keepAlive = false;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### macOS app bundles
|
||||
|
||||
If you only want the raw app package, use the package output directly:
|
||||
|
||||
```nix
|
||||
inputs.nix-steipete-tools.packages.aarch64-darwin.codexbar-app
|
||||
```
|
||||
|
||||
## Skills syncing
|
||||
@ -85,7 +141,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
|
||||
|
||||
@ -97,6 +153,12 @@ Fetches latest release versions/URLs/hashes and updates the Nix expressions. Ora
|
||||
|
||||
Automated PRs keep everything fresh without manual intervention.
|
||||
|
||||
## Temporarily disabled
|
||||
|
||||
`bird` is not exported right now because the upstream GitHub release assets for
|
||||
v0.8.0 are gone. The npm package still exists, but this flake does not currently
|
||||
build npm dependencies for it.
|
||||
|
||||
## License
|
||||
|
||||
Tools are packaged as-is from upstream. See individual tool repos for their licenses.
|
||||
|
||||
@ -60,14 +60,14 @@ func main() {
|
||||
|
||||
mappings := []Mapping{
|
||||
{"summarize", "skills/summarize"},
|
||||
{"discrawl", "skills/discrawl"},
|
||||
{"wacrawl", "skills/wacrawl"},
|
||||
{"gogcli", "skills/gog"},
|
||||
{"camsnap", "skills/camsnap"},
|
||||
{"sonoscli", "skills/sonoscli"},
|
||||
{"bird", "skills/bird"},
|
||||
{"peekaboo", "skills/peekaboo"},
|
||||
{"sag", "skills/sag"},
|
||||
{"imsg", "skills/imsg"},
|
||||
{"oracle", "skills/oracle"},
|
||||
}
|
||||
|
||||
log.Printf("[sync-skills] cloning clawdbot main")
|
||||
|
||||
@ -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 {
|
||||
@ -226,6 +147,26 @@ func main() {
|
||||
}
|
||||
|
||||
tools := []Tool{
|
||||
{
|
||||
Name: "discrawl",
|
||||
Repo: "steipete/discrawl",
|
||||
Assets: []AssetSpec{
|
||||
{System: "aarch64-darwin", Regex: regexp.MustCompile(`discrawl_[0-9.]+_darwin_arm64\.tar\.gz`)},
|
||||
{System: "x86_64-linux", Regex: regexp.MustCompile(`discrawl_[0-9.]+_linux_amd64\.tar\.gz`)},
|
||||
{System: "aarch64-linux", Regex: regexp.MustCompile(`discrawl_[0-9.]+_linux_arm64\.tar\.gz`)},
|
||||
},
|
||||
NixFile: filepath.Join(repoRoot, "nix", "pkgs", "discrawl.nix"),
|
||||
},
|
||||
{
|
||||
Name: "wacrawl",
|
||||
Repo: "steipete/wacrawl",
|
||||
Assets: []AssetSpec{
|
||||
{System: "aarch64-darwin", Regex: regexp.MustCompile(`wacrawl_[0-9.]+_darwin_arm64\.tar\.gz`)},
|
||||
{System: "x86_64-linux", Regex: regexp.MustCompile(`wacrawl_[0-9.]+_linux_amd64\.tar\.gz`)},
|
||||
{System: "aarch64-linux", Regex: regexp.MustCompile(`wacrawl_[0-9.]+_linux_arm64\.tar\.gz`)},
|
||||
},
|
||||
NixFile: filepath.Join(repoRoot, "nix", "pkgs", "wacrawl.nix"),
|
||||
},
|
||||
{
|
||||
Name: "gogcli",
|
||||
Repo: "steipete/gogcli",
|
||||
@ -236,6 +177,17 @@ func main() {
|
||||
},
|
||||
NixFile: filepath.Join(repoRoot, "nix", "pkgs", "gogcli.nix"),
|
||||
},
|
||||
{
|
||||
Name: "goplaces",
|
||||
Repo: "steipete/goplaces",
|
||||
Assets: []AssetSpec{
|
||||
{System: "aarch64-darwin", Regex: regexp.MustCompile(`goplaces_[0-9.]+_darwin_arm64\.tar\.gz`)},
|
||||
{System: "x86_64-darwin", Regex: regexp.MustCompile(`goplaces_[0-9.]+_darwin_amd64\.tar\.gz`)},
|
||||
{System: "x86_64-linux", Regex: regexp.MustCompile(`goplaces_[0-9.]+_linux_amd64\.tar\.gz`)},
|
||||
{System: "aarch64-linux", Regex: regexp.MustCompile(`goplaces_[0-9.]+_linux_arm64\.tar\.gz`)},
|
||||
},
|
||||
NixFile: filepath.Join(repoRoot, "nix", "pkgs", "goplaces.nix"),
|
||||
},
|
||||
{
|
||||
Name: "camsnap",
|
||||
Repo: "steipete/camsnap",
|
||||
@ -256,20 +208,11 @@ func main() {
|
||||
},
|
||||
NixFile: filepath.Join(repoRoot, "nix", "pkgs", "sonoscli.nix"),
|
||||
},
|
||||
{
|
||||
Name: "bird",
|
||||
Repo: "steipete/bird",
|
||||
Optional: true, // repo got nuked; keep packaging pinned, but don't fail the updater
|
||||
Assets: []AssetSpec{
|
||||
{System: "aarch64-darwin", Regex: regexp.MustCompile(`bird-macos-universal-v[0-9.]+\.tar\.gz`)},
|
||||
},
|
||||
NixFile: filepath.Join(repoRoot, "nix", "pkgs", "bird.nix"),
|
||||
},
|
||||
{
|
||||
Name: "peekaboo",
|
||||
Repo: "steipete/peekaboo",
|
||||
Assets: []AssetSpec{
|
||||
{System: "aarch64-darwin", Regex: regexp.MustCompile(`peekaboo-macos-universal\.tar\.gz`)},
|
||||
{System: "aarch64-darwin", Regex: regexp.MustCompile(`peekaboo-macos-(?:arm64|universal)\.tar\.gz`)},
|
||||
},
|
||||
NixFile: filepath.Join(repoRoot, "nix", "pkgs", "peekaboo.nix"),
|
||||
},
|
||||
@ -313,9 +256,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)
|
||||
}
|
||||
}
|
||||
|
||||
26
flake.nix
26
flake.nix
@ -12,16 +12,17 @@
|
||||
forAllSystems = f: lib.genAttrs systems (system: f system);
|
||||
packageSystems = {
|
||||
summarize = [ "aarch64-darwin" "x86_64-linux" "aarch64-linux" ];
|
||||
discrawl = [ "aarch64-darwin" "x86_64-linux" "aarch64-linux" ];
|
||||
wacrawl = [ "aarch64-darwin" "x86_64-linux" "aarch64-linux" ];
|
||||
gogcli = [ "aarch64-darwin" "x86_64-linux" "aarch64-linux" ];
|
||||
goplaces = [ "aarch64-darwin" "x86_64-linux" "aarch64-linux" ];
|
||||
camsnap = [ "aarch64-darwin" "x86_64-linux" "aarch64-linux" ];
|
||||
sonoscli = [ "aarch64-darwin" "x86_64-linux" "aarch64-linux" ];
|
||||
bird = [ "aarch64-darwin" ];
|
||||
peekaboo = [ "aarch64-darwin" ];
|
||||
poltergeist = [ "aarch64-darwin" ];
|
||||
sag = [ "aarch64-darwin" "x86_64-linux" ];
|
||||
imsg = [ "aarch64-darwin" ];
|
||||
oracle = [ "aarch64-darwin" "x86_64-linux" "aarch64-linux" ];
|
||||
codexbar-app = [ "aarch64-darwin" ];
|
||||
};
|
||||
in {
|
||||
packages = forAllSystems (system:
|
||||
@ -36,6 +37,12 @@
|
||||
nodejs = if pkgs ? nodejs_22 then pkgs.nodejs_22 else pkgs.nodejs;
|
||||
};
|
||||
})
|
||||
// (lib.optionalAttrs (supports "discrawl") {
|
||||
discrawl = pkgs.callPackage ./nix/pkgs/discrawl.nix {};
|
||||
})
|
||||
// (lib.optionalAttrs (supports "wacrawl") {
|
||||
wacrawl = pkgs.callPackage ./nix/pkgs/wacrawl.nix {};
|
||||
})
|
||||
// (lib.optionalAttrs (supports "gogcli") {
|
||||
gogcli = pkgs.callPackage ./nix/pkgs/gogcli.nix {};
|
||||
})
|
||||
@ -48,9 +55,6 @@
|
||||
// (lib.optionalAttrs (supports "sonoscli") {
|
||||
sonoscli = pkgs.callPackage ./nix/pkgs/sonoscli.nix {};
|
||||
})
|
||||
// (lib.optionalAttrs (supports "bird") {
|
||||
bird = pkgs.callPackage ./nix/pkgs/bird.nix {};
|
||||
})
|
||||
// (lib.optionalAttrs (supports "peekaboo") {
|
||||
peekaboo = pkgs.callPackage ./nix/pkgs/peekaboo.nix {};
|
||||
})
|
||||
@ -63,14 +67,16 @@
|
||||
// (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;
|
||||
};
|
||||
// (lib.optionalAttrs (supports "codexbar-app") {
|
||||
codexbar-app = pkgs.callPackage ./nix/pkgs/codexbar-app.nix {};
|
||||
})
|
||||
);
|
||||
|
||||
homeManagerModules = {
|
||||
codexbar = import ./nix/modules/home-manager/codexbar.nix { inherit self; };
|
||||
default = self.homeManagerModules.codexbar;
|
||||
};
|
||||
|
||||
checks = forAllSystems (system: self.packages.${system});
|
||||
};
|
||||
}
|
||||
|
||||
@ -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("")
|
||||
}
|
||||
|
||||
88
nix/modules/home-manager/codexbar.nix
Normal file
88
nix/modules/home-manager/codexbar.nix
Normal file
@ -0,0 +1,88 @@
|
||||
{ self }:
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkEnableOption mkIf mkOption types;
|
||||
cfg = config.programs.codexbar;
|
||||
system = pkgs.stdenv.hostPlatform.system;
|
||||
defaultPackage =
|
||||
if self.packages ? ${system} && self.packages.${system} ? codexbar-app then
|
||||
self.packages.${system}.codexbar-app
|
||||
else
|
||||
null;
|
||||
in
|
||||
{
|
||||
options.programs.codexbar = {
|
||||
enable = mkEnableOption "CodexBar macOS menu bar app";
|
||||
|
||||
package = mkOption {
|
||||
type = types.nullOr types.package;
|
||||
default = defaultPackage;
|
||||
defaultText = lib.literalExpression "inputs.nix-steipete-tools.packages.\${pkgs.system}.codexbar-app";
|
||||
description = "CodexBar app package.";
|
||||
};
|
||||
|
||||
launchd = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Configure a launchd agent to manage the CodexBar process.
|
||||
|
||||
CodexBar can also manage launch-at-login from inside the app. Enable this
|
||||
option when you want Home Manager and launchd to own startup instead.
|
||||
'';
|
||||
};
|
||||
|
||||
keepAlive = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether launchd should restart CodexBar after it exits.";
|
||||
};
|
||||
|
||||
environmentVariables = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = {
|
||||
PATH = "${config.home.profileDirectory}/bin:/usr/bin:/bin:/usr/sbin:/sbin";
|
||||
};
|
||||
defaultText = lib.literalExpression ''
|
||||
{
|
||||
PATH = "\${config.home.profileDirectory}/bin:/usr/bin:/bin:/usr/sbin:/sbin";
|
||||
}
|
||||
'';
|
||||
description = "Environment variables passed to the CodexBar launchd agent.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
(lib.hm.assertions.assertPlatform "programs.codexbar" pkgs lib.platforms.darwin)
|
||||
{
|
||||
assertion = cfg.package != null;
|
||||
message = "programs.codexbar.package must be set on this platform.";
|
||||
}
|
||||
{
|
||||
assertion = !cfg.launchd.enable || config.launchd.enable;
|
||||
message = "programs.codexbar.launchd.enable requires launchd.enable.";
|
||||
}
|
||||
];
|
||||
|
||||
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||
|
||||
launchd.agents.codexbar = mkIf cfg.launchd.enable {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [ "${cfg.package}/Applications/CodexBar.app/Contents/MacOS/CodexBar" ];
|
||||
ProcessType = "Interactive";
|
||||
RunAtLoad = true;
|
||||
KeepAlive = cfg.launchd.keepAlive;
|
||||
EnvironmentVariables = cfg.launchd.environmentVariables;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
37
nix/pkgs/codexbar-app.nix
Normal file
37
nix/pkgs/codexbar-app.nix
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
lib,
|
||||
stdenvNoCC,
|
||||
fetchzip,
|
||||
}:
|
||||
|
||||
stdenvNoCC.mkDerivation {
|
||||
pname = "codexbar-app";
|
||||
version = "0.23";
|
||||
|
||||
src = fetchzip {
|
||||
url = "https://github.com/steipete/CodexBar/releases/download/v0.23/CodexBar-0.23.zip";
|
||||
hash = "sha256-4LtZZzoP9tofNhy8jVkaopE+aivn0PRBEeJBGpDnbE8=";
|
||||
stripRoot = false;
|
||||
};
|
||||
|
||||
dontUnpack = true;
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mkdir -p "$out/Applications"
|
||||
app_path="$(find "$src" -maxdepth 2 -name 'CodexBar.app' -print -quit)"
|
||||
if [ -z "$app_path" ]; then
|
||||
echo "CodexBar.app not found in $src" >&2
|
||||
exit 1
|
||||
fi
|
||||
cp -R "$app_path" "$out/Applications/CodexBar.app"
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "CodexBar macOS menu bar app bundle";
|
||||
homepage = "https://github.com/steipete/CodexBar";
|
||||
license = licenses.mit;
|
||||
platforms = [ "aarch64-darwin" ];
|
||||
};
|
||||
}
|
||||
53
nix/pkgs/discrawl.nix
Normal file
53
nix/pkgs/discrawl.nix
Normal file
@ -0,0 +1,53 @@
|
||||
{ lib, stdenv, fetchurl }:
|
||||
|
||||
let
|
||||
sources = {
|
||||
"aarch64-darwin" = {
|
||||
url = "https://github.com/steipete/discrawl/releases/download/v0.6.5/discrawl_0.6.5_darwin_arm64.tar.gz";
|
||||
hash = "sha256-nxt8Pq0ldbf4QefkBYDMIEzp9dRZUBuK7GBygI+4HDc=";
|
||||
};
|
||||
"x86_64-linux" = {
|
||||
url = "https://github.com/steipete/discrawl/releases/download/v0.6.5/discrawl_0.6.5_linux_amd64.tar.gz";
|
||||
hash = "sha256-0lLlZYWZgvebBNWfZjicdB+o9tJ43N4n3CxAQ9mLfHM=";
|
||||
};
|
||||
"aarch64-linux" = {
|
||||
url = "https://github.com/steipete/discrawl/releases/download/v0.6.5/discrawl_0.6.5_linux_arm64.tar.gz";
|
||||
hash = "sha256-k+ls+9dKvBLaMbThCoNgn6vQxGhviDeXaH6JmbeBrLM=";
|
||||
};
|
||||
};
|
||||
in
|
||||
stdenv.mkDerivation {
|
||||
pname = "discrawl";
|
||||
version = "0.6.5";
|
||||
|
||||
src = fetchurl sources.${stdenv.hostPlatform.system};
|
||||
|
||||
dontConfigure = true;
|
||||
dontBuild = true;
|
||||
|
||||
unpackPhase = ''
|
||||
tar -xzf "$src"
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mkdir -p "$out/bin" "$out/share/doc/discrawl"
|
||||
cp $(find . -type f -name discrawl | head -1) "$out/bin/discrawl"
|
||||
chmod 0755 "$out/bin/discrawl"
|
||||
if [ -f LICENSE ]; then
|
||||
cp LICENSE "$out/share/doc/discrawl/"
|
||||
fi
|
||||
if [ -f README.md ]; then
|
||||
cp README.md "$out/share/doc/discrawl/"
|
||||
fi
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "Mirror Discord into SQLite and search server history locally";
|
||||
homepage = "https://github.com/steipete/discrawl";
|
||||
license = licenses.mit;
|
||||
platforms = builtins.attrNames sources;
|
||||
mainProgram = "discrawl";
|
||||
};
|
||||
}
|
||||
@ -3,22 +3,22 @@
|
||||
let
|
||||
sources = {
|
||||
"aarch64-darwin" = {
|
||||
url = "https://github.com/steipete/gogcli/releases/download/v0.10.0/gogcli_0.10.0_darwin_arm64.tar.gz";
|
||||
hash = "sha256-sNPDBSmr40X1Epzm7ZRzJfcDHU7p70kLHl12/5c4/J8=";
|
||||
url = "https://github.com/steipete/gogcli/releases/download/v0.14.0/gogcli_0.14.0_darwin_arm64.tar.gz";
|
||||
hash = "sha256-qJ+H7dc+oPn7E57kvEIwlAc990nkpiGSqlFCDy9kZjo=";
|
||||
};
|
||||
"x86_64-linux" = {
|
||||
url = "https://github.com/steipete/gogcli/releases/download/v0.10.0/gogcli_0.10.0_linux_amd64.tar.gz";
|
||||
hash = "sha256-f8DVB7LQprzprE6IyGu3jZo2ckRXEu9FiomMM7KqIV0=";
|
||||
url = "https://github.com/steipete/gogcli/releases/download/v0.14.0/gogcli_0.14.0_linux_amd64.tar.gz";
|
||||
hash = "sha256-sq2qUDYnqlbZGGzxBHp5CqFfjdGFIkgN1P8UBgyd0hs=";
|
||||
};
|
||||
"aarch64-linux" = {
|
||||
url = "https://github.com/steipete/gogcli/releases/download/v0.10.0/gogcli_0.10.0_linux_arm64.tar.gz";
|
||||
hash = "sha256-Q48xgr47bF3Om3kyKm6tnH9nOW9g0Em7i0o5AEhPZRU=";
|
||||
url = "https://github.com/steipete/gogcli/releases/download/v0.14.0/gogcli_0.14.0_linux_arm64.tar.gz";
|
||||
hash = "sha256-KOq4AyYyjUvL6tMq4WtOZu2WYTdtJR1g44uFmJt8oHs=";
|
||||
};
|
||||
};
|
||||
in
|
||||
stdenv.mkDerivation {
|
||||
pname = "gogcli";
|
||||
version = "0.10.0";
|
||||
version = "0.14.0";
|
||||
|
||||
src = fetchurl sources.${stdenv.hostPlatform.system};
|
||||
|
||||
|
||||
@ -1,31 +1,60 @@
|
||||
{ lib, buildGoModule, fetchFromGitHub }:
|
||||
{ lib, stdenv, fetchurl }:
|
||||
|
||||
buildGoModule rec {
|
||||
pname = "goplaces";
|
||||
version = "0.2.2-dev";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "joshp123";
|
||||
repo = "goplaces";
|
||||
rev = "a71fe3de986a78607d923f397113d7eb1babc111";
|
||||
hash = "sha256-Lufp9+fwcoluNZR9iDYoIJ1yu3sM/8Q/EOkAlq5VLdk=";
|
||||
let
|
||||
sources = {
|
||||
"aarch64-darwin" = {
|
||||
url = "https://github.com/steipete/goplaces/releases/download/v0.4.0/goplaces_0.4.0_darwin_arm64.tar.gz";
|
||||
hash = "sha256-FJ8hVqQhp/Ppk17CrDJk4dmu2pvS2xBX5cAzafpaM8g=";
|
||||
};
|
||||
"x86_64-darwin" = {
|
||||
url = "https://github.com/steipete/goplaces/releases/download/v0.4.0/goplaces_0.4.0_darwin_amd64.tar.gz";
|
||||
hash = "sha256-/vVK0hqh1q3tliSy4mRT9X3jRayYhWAfZLS+VsFd+NU=";
|
||||
};
|
||||
"x86_64-linux" = {
|
||||
url = "https://github.com/steipete/goplaces/releases/download/v0.4.0/goplaces_0.4.0_linux_amd64.tar.gz";
|
||||
hash = "sha256-cUHDAZ4Ep50K2ljLn8LyJeWPJlcr/sytP95UsNmSv3w=";
|
||||
};
|
||||
"aarch64-linux" = {
|
||||
url = "https://github.com/steipete/goplaces/releases/download/v0.4.0/goplaces_0.4.0_linux_arm64.tar.gz";
|
||||
hash = "sha256-YjeLRDLwuQbUOYZYnpNkuYDvsm54PB1jmqTHas2T5VY=";
|
||||
};
|
||||
};
|
||||
|
||||
subPackages = [ "cmd/goplaces" ];
|
||||
|
||||
ldflags = [
|
||||
"-s"
|
||||
"-w"
|
||||
"-X github.com/steipete/goplaces/internal/cli.Version=${version}"
|
||||
];
|
||||
|
||||
vendorHash = "sha256-OFTjLtKwYSy4tM+D12mqI28M73YJdG4DyqPkXS7ZKUg=";
|
||||
|
||||
meta = with lib; {
|
||||
description = "Modern Go client + CLI for the Google Places API";
|
||||
homepage = "https://github.com/joshp123/goplaces";
|
||||
description = "Modern Go client + CLI for the Google Places API (New)";
|
||||
homepage = "https://github.com/steipete/goplaces";
|
||||
license = licenses.mit;
|
||||
platforms = platforms.darwin ++ platforms.linux;
|
||||
platforms = builtins.attrNames sources;
|
||||
mainProgram = "goplaces";
|
||||
};
|
||||
|
||||
in
|
||||
stdenv.mkDerivation {
|
||||
pname = "goplaces";
|
||||
version = "0.4.0";
|
||||
|
||||
src = fetchurl sources.${stdenv.hostPlatform.system};
|
||||
|
||||
dontConfigure = true;
|
||||
dontBuild = true;
|
||||
|
||||
unpackPhase = ''
|
||||
tar -xzf "$src"
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mkdir -p "$out/bin" "$out/share/doc/goplaces"
|
||||
cp $(find . -type f -name goplaces | head -1) "$out/bin/goplaces"
|
||||
chmod 0755 "$out/bin/goplaces"
|
||||
if [ -f LICENSE ]; then
|
||||
cp LICENSE "$out/share/doc/goplaces/"
|
||||
fi
|
||||
if [ -f README.md ]; then
|
||||
cp README.md "$out/share/doc/goplaces/"
|
||||
fi
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
inherit meta;
|
||||
}
|
||||
|
||||
@ -3,14 +3,14 @@
|
||||
let
|
||||
sources = {
|
||||
"aarch64-darwin" = {
|
||||
url = "https://github.com/steipete/imsg/releases/download/v0.4.0/imsg-macos.zip";
|
||||
hash = "sha256-0OXjM+6IGS1ZW/7Z7s5g417K0DABRZZtWtJ0WMM+QHs=";
|
||||
url = "https://github.com/steipete/imsg/releases/download/v0.5.0/imsg-macos.zip";
|
||||
hash = "sha256-rirJZ+8eQf0Ea3RXD4bHrWljSpGEb+wtbMdrsEtHPAo=";
|
||||
};
|
||||
};
|
||||
in
|
||||
stdenv.mkDerivation {
|
||||
pname = "imsg";
|
||||
version = "0.4.0";
|
||||
version = "0.5.0";
|
||||
|
||||
src = fetchurl sources.${stdenv.hostPlatform.system};
|
||||
|
||||
|
||||
@ -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";
|
||||
};
|
||||
})
|
||||
@ -3,14 +3,14 @@
|
||||
let
|
||||
sources = {
|
||||
"aarch64-darwin" = {
|
||||
url = "https://github.com/steipete/Peekaboo/releases/download/v3.0.0-beta3/peekaboo-macos-universal.tar.gz";
|
||||
hash = "sha256-d+rfb9XFTqxktIRNXMiHiQttb0XUmvYbBcbinqLL0kU=";
|
||||
url = "https://github.com/steipete/Peekaboo/releases/download/v3.0.0-beta4/peekaboo-macos-arm64.tar.gz";
|
||||
hash = "sha256-74eXVHpRAmcs0mzK3GLh/3So78AEMZzXBvx1Zg7uOkc=";
|
||||
};
|
||||
};
|
||||
in
|
||||
stdenv.mkDerivation {
|
||||
pname = "peekaboo";
|
||||
version = "3.0.0-beta3";
|
||||
version = "3.0.0-beta4";
|
||||
|
||||
src = fetchurl sources.${stdenv.hostPlatform.system};
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
{ lib, stdenv, fetchurl, watchman }:
|
||||
{ lib, stdenv, fetchurl }:
|
||||
|
||||
let
|
||||
sources = {
|
||||
@ -30,8 +30,6 @@ stdenv.mkDerivation {
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
propagatedBuildInputs = [ watchman ];
|
||||
|
||||
meta = with lib; {
|
||||
description = "Universal file watcher with auto-rebuild for any language or build system";
|
||||
homepage = "https://github.com/steipete/poltergeist";
|
||||
|
||||
@ -15,17 +15,17 @@
|
||||
|
||||
let
|
||||
pname = "summarize";
|
||||
version = "0.11.1";
|
||||
version = "0.14.1";
|
||||
binSources = {
|
||||
"aarch64-darwin" = {
|
||||
url = "https://github.com/steipete/summarize/releases/download/v0.11.1/summarize-macos-arm64-v0.11.1.tar.gz";
|
||||
hash = "sha256-RJNeCxWfbMCOrD6ABR4wSALdtl1sImS4Wkjz1TdPmTE=";
|
||||
url = "https://github.com/steipete/summarize/releases/download/v0.14.1/summarize-macos-arm64-v0.14.1.tar.gz";
|
||||
hash = "sha256-X3aBGiAjoOSIINxHyGOzg/b88fpCZQcv0cM2L0KqS8c=";
|
||||
};
|
||||
};
|
||||
|
||||
src = fetchurl {
|
||||
url = "https://github.com/steipete/summarize/archive/refs/tags/v${version}.tar.gz";
|
||||
hash = "sha256-2s3XAy9evHRZQthTWRhIjkv7Z40K5PiUFHEIGo6XxBs=";
|
||||
hash = "sha256-UAf7IXerk5VM3DyLyMD259Dh55ZjcZPK/3T2kPj9RO4=";
|
||||
};
|
||||
|
||||
pnpmFetchDepsPkg = pkgs.callPackage "${pkgs.path}/pkgs/build-support/node/fetch-pnpm-deps" {
|
||||
@ -36,7 +36,7 @@ let
|
||||
pname = pname;
|
||||
version = version;
|
||||
src = src;
|
||||
hash = "sha256-vqTXJ64DpanUwdUlSS3Fa+zy70qIGgsNtKzYF82J1RU=";
|
||||
hash = "sha256-s1I3TTX3uw/iJpbWvoNE5kg9XQVjw0mnA5pRTVs7ypY=";
|
||||
fetcherVersion = 3;
|
||||
});
|
||||
|
||||
@ -72,7 +72,7 @@ if stdenv.isLinux then
|
||||
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_nodedir = "${lib.getDev nodejs}";
|
||||
npm_config_build_from_source = "1";
|
||||
PNPM_CONFIG_IGNORE_SCRIPTS = "1";
|
||||
PNPM_CONFIG_MANAGE_PACKAGE_MANAGER_VERSIONS = "false";
|
||||
@ -120,6 +120,7 @@ if stdenv.isLinux then
|
||||
runHook preInstall
|
||||
mkdir -p "$out/libexec" "$out/libexec/packages" "$out/libexec/apps" "$out/bin"
|
||||
cp -r dist node_modules "$out/libexec/"
|
||||
find "$out/libexec/node_modules" -name ".pnpm-workspace-state-v1.json" -delete
|
||||
cp -r packages/core "$out/libexec/packages/"
|
||||
cp -r apps/chrome-extension "$out/libexec/apps/"
|
||||
chmod 0755 "$out/libexec/dist/cli.js"
|
||||
|
||||
53
nix/pkgs/wacrawl.nix
Normal file
53
nix/pkgs/wacrawl.nix
Normal file
@ -0,0 +1,53 @@
|
||||
{ lib, stdenv, fetchurl }:
|
||||
|
||||
let
|
||||
sources = {
|
||||
"aarch64-darwin" = {
|
||||
url = "https://github.com/steipete/wacrawl/releases/download/v0.2.0/wacrawl_0.2.0_darwin_arm64.tar.gz";
|
||||
hash = "sha256-Pk3G8ZBsZOSU9PNgtuJPzQC2XDe71yUSkPHXxqGL+vQ=";
|
||||
};
|
||||
"x86_64-linux" = {
|
||||
url = "https://github.com/steipete/wacrawl/releases/download/v0.2.0/wacrawl_0.2.0_linux_amd64.tar.gz";
|
||||
hash = "sha256-xZBLpgzLG+3NClMwanZ2V79Qqw36acpT2MI5z3gfHoo=";
|
||||
};
|
||||
"aarch64-linux" = {
|
||||
url = "https://github.com/steipete/wacrawl/releases/download/v0.2.0/wacrawl_0.2.0_linux_arm64.tar.gz";
|
||||
hash = "sha256-oiPgR7yWd5aYTYqlIZST89ELSdetW6nvTaE8rl78ZTc=";
|
||||
};
|
||||
};
|
||||
in
|
||||
stdenv.mkDerivation {
|
||||
pname = "wacrawl";
|
||||
version = "0.2.0";
|
||||
|
||||
src = fetchurl sources.${stdenv.hostPlatform.system};
|
||||
|
||||
dontConfigure = true;
|
||||
dontBuild = true;
|
||||
|
||||
unpackPhase = ''
|
||||
tar -xzf "$src"
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mkdir -p "$out/bin" "$out/share/doc/wacrawl"
|
||||
cp $(find . -type f -name wacrawl | head -1) "$out/bin/wacrawl"
|
||||
chmod 0755 "$out/bin/wacrawl"
|
||||
if [ -f LICENSE ]; then
|
||||
cp LICENSE "$out/share/doc/wacrawl/"
|
||||
fi
|
||||
if [ -f README.md ]; then
|
||||
cp README.md "$out/share/doc/wacrawl/"
|
||||
fi
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "Read-only local archive and search for WhatsApp Desktop data";
|
||||
homepage = "https://github.com/steipete/wacrawl";
|
||||
license = licenses.mit;
|
||||
platforms = builtins.attrNames sources;
|
||||
mainProgram = "wacrawl";
|
||||
};
|
||||
}
|
||||
38
tools/discrawl/flake.nix
Normal file
38
tools/discrawl/flake.nix
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
description = "openclaw plugin: discrawl";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs?rev=16c7794d0a28b5a37904d55bcca36003b9109aaa&narHash=sha256-fFUnEYMla8b7UKjijLnMe%2BoVFOz6HjijGGNS1l7dYaQ%3D";
|
||||
root.url = "path:../..";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, root }:
|
||||
let
|
||||
lib = nixpkgs.lib;
|
||||
systems = builtins.attrNames root.packages;
|
||||
pluginFor = system:
|
||||
let
|
||||
packagesForSystem = root.packages.${system} or {};
|
||||
discrawl = packagesForSystem.discrawl or null;
|
||||
in
|
||||
if discrawl == null then null else {
|
||||
name = "discrawl";
|
||||
skills = [ ./skills/discrawl ];
|
||||
packages = [ discrawl ];
|
||||
needs = {
|
||||
stateDirs = [ ".discrawl" ];
|
||||
requiredEnv = [ ];
|
||||
};
|
||||
};
|
||||
in {
|
||||
packages = lib.genAttrs systems (system:
|
||||
let
|
||||
discrawl = (root.packages.${system} or {}).discrawl or null;
|
||||
in
|
||||
if discrawl == null then {}
|
||||
else { discrawl = discrawl; }
|
||||
);
|
||||
|
||||
openclawPlugin = pluginFor;
|
||||
};
|
||||
}
|
||||
74
tools/discrawl/skills/discrawl/SKILL.md
Normal file
74
tools/discrawl/skills/discrawl/SKILL.md
Normal file
@ -0,0 +1,74 @@
|
||||
---
|
||||
name: discrawl
|
||||
description: Mirror Discord guild history into local SQLite and query it offline with search, messages, mentions, reports, and DM wiretap import.
|
||||
homepage: https://github.com/steipete/discrawl
|
||||
metadata:
|
||||
{
|
||||
"openclaw":
|
||||
{
|
||||
"emoji": "🛰️",
|
||||
"requires": { "bins": ["discrawl"] },
|
||||
"install":
|
||||
[
|
||||
{
|
||||
"id": "brew",
|
||||
"kind": "brew",
|
||||
"formula": "steipete/tap/discrawl",
|
||||
"bins": ["discrawl"],
|
||||
"label": "Install discrawl (brew)",
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
---
|
||||
|
||||
# discrawl
|
||||
|
||||
Use `discrawl` to mirror Discord guild data into local SQLite, then query it offline.
|
||||
|
||||
## When to Use
|
||||
|
||||
Use this skill when the user wants to:
|
||||
|
||||
- search Discord history locally without relying on Discord search
|
||||
- archive a guild into SQLite for later queries
|
||||
- inspect recent messages, mentions, channels, or members from a local archive
|
||||
- import local Discord Desktop cache data for DM recovery/search
|
||||
- publish or subscribe to a Git-backed Discord archive snapshot
|
||||
|
||||
## Requirements
|
||||
|
||||
- Discord bot token for guild sync, or an existing OpenClaw Discord config
|
||||
- local Discord Desktop cache files only if using `wiretap`
|
||||
- enough local disk for SQLite archive growth
|
||||
|
||||
## Setup
|
||||
|
||||
- Default config: `~/.discrawl/config.toml`
|
||||
- Default database: `~/.discrawl/discrawl.db`
|
||||
- Fastest setup when OpenClaw already has Discord configured:
|
||||
- `discrawl init --from-openclaw ~/.openclaw/openclaw.json`
|
||||
- Env-only setup:
|
||||
- `export DISCORD_BOT_TOKEN="..."`
|
||||
- `discrawl init`
|
||||
|
||||
## Common Commands
|
||||
|
||||
- Doctor: `discrawl doctor`
|
||||
- Initial history: `discrawl sync --full`
|
||||
- Incremental refresh: `discrawl sync`
|
||||
- Live tail: `discrawl tail`
|
||||
- Search: `discrawl search "panic nil pointer"`
|
||||
- Recent channel messages: `discrawl messages --channel general --hours 24`
|
||||
- Mentions: `discrawl mentions --user <user-id>`
|
||||
- DM cache import: `discrawl wiretap`
|
||||
- Local DM search: `discrawl dms --search "launch checklist"`
|
||||
- Read-only SQL: `discrawl sql "select count(*) from messages"`
|
||||
- Git-backed reader mode: `discrawl subscribe <private-repo-url>`
|
||||
|
||||
## Notes
|
||||
|
||||
- Bot-token sync reads only guilds/channels the bot can access.
|
||||
- `wiretap` uses local Discord Desktop cache files only; it does not use a user token.
|
||||
- Prefer `discrawl doctor` before a first sync.
|
||||
- Use `sync --full` once for backfill, then plain `sync` for routine refreshes.
|
||||
65
tools/gogcli/flake.lock
generated
Normal file
65
tools/gogcli/flake.lock
generated
Normal file
@ -0,0 +1,65 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1767364772,
|
||||
"narHash": "sha256-fFUnEYMla8b7UKjijLnMe+oVFOz6HjijGGNS1l7dYaQ=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "16c7794d0a28b5a37904d55bcca36003b9109aaa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"narHash": "sha256-fFUnEYMla8b7UKjijLnMe+oVFOz6HjijGGNS1l7dYaQ=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "16c7794d0a28b5a37904d55bcca36003b9109aaa",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1767364772,
|
||||
"narHash": "sha256-fFUnEYMla8b7UKjijLnMe+oVFOz6HjijGGNS1l7dYaQ=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "16c7794d0a28b5a37904d55bcca36003b9109aaa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs",
|
||||
"root": "root_2"
|
||||
}
|
||||
},
|
||||
"root_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1772109602,
|
||||
"narHash": "sha256-Lzs6tzCkOOtDaZIRSGvS6ykJOtu0hZrdI95kxhkSIuw=",
|
||||
"owner": "openclaw",
|
||||
"repo": "nix-steipete-tools",
|
||||
"rev": "eddb00d4c1037a983913fccf32880aece050cd32",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"narHash": "sha256-Lzs6tzCkOOtDaZIRSGvS6ykJOtu0hZrdI95kxhkSIuw=",
|
||||
"owner": "openclaw",
|
||||
"repo": "nix-steipete-tools",
|
||||
"rev": "eddb00d4c1037a983913fccf32880aece050cd32",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
@ -3,7 +3,7 @@
|
||||
|
||||
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=";
|
||||
root.url = "github:openclaw/nix-steipete-tools?rev=eddb00d4c1037a983913fccf32880aece050cd32&narHash=sha256-Lzs6tzCkOOtDaZIRSGvS6ykJOtu0hZrdI95kxhkSIuw=";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, root }:
|
||||
|
||||
65
tools/goplaces/flake.lock
generated
Normal file
65
tools/goplaces/flake.lock
generated
Normal file
@ -0,0 +1,65 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1767364772,
|
||||
"narHash": "sha256-fFUnEYMla8b7UKjijLnMe+oVFOz6HjijGGNS1l7dYaQ=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "16c7794d0a28b5a37904d55bcca36003b9109aaa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"narHash": "sha256-fFUnEYMla8b7UKjijLnMe+oVFOz6HjijGGNS1l7dYaQ=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "16c7794d0a28b5a37904d55bcca36003b9109aaa",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1767364772,
|
||||
"narHash": "sha256-fFUnEYMla8b7UKjijLnMe+oVFOz6HjijGGNS1l7dYaQ=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "16c7794d0a28b5a37904d55bcca36003b9109aaa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs",
|
||||
"root": "root_2"
|
||||
}
|
||||
},
|
||||
"root_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1770237944,
|
||||
"narHash": "sha256-nfCSSyNU97XpKVPgo6mODBwrVeTOuMCl3i18QuGjpN0=",
|
||||
"owner": "openclaw",
|
||||
"repo": "nix-steipete-tools",
|
||||
"rev": "6352c8247b3b889d7f17bce1f09d6c58fd34932c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"narHash": "sha256-nfCSSyNU97XpKVPgo6mODBwrVeTOuMCl3i18QuGjpN0=",
|
||||
"owner": "openclaw",
|
||||
"repo": "nix-steipete-tools",
|
||||
"rev": "6352c8247b3b889d7f17bce1f09d6c58fd34932c",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: imsg
|
||||
description: iMessage/SMS CLI for listing chats, history, watch, and sending.
|
||||
description: iMessage/SMS CLI for listing chats, history, and sending messages via Messages.app.
|
||||
homepage: https://imsg.to
|
||||
metadata:
|
||||
{
|
||||
@ -23,52 +23,100 @@ metadata:
|
||||
}
|
||||
---
|
||||
|
||||
# imsg Actions
|
||||
# imsg
|
||||
|
||||
## Overview
|
||||
Use `imsg` to read and send iMessage/SMS via macOS Messages.app.
|
||||
|
||||
Use `imsg` to read and send Messages.app iMessage/SMS on macOS.
|
||||
## When to Use
|
||||
|
||||
Requirements: Messages.app signed in, Full Disk Access for your terminal, and Automation permission to control Messages.app for sending.
|
||||
✅ **USE this skill when:**
|
||||
|
||||
## Inputs to collect
|
||||
- User explicitly asks to send iMessage or SMS
|
||||
- Reading iMessage conversation history
|
||||
- Checking recent Messages.app chats
|
||||
- Sending to phone numbers or Apple IDs
|
||||
|
||||
- Recipient handle (phone/email) for `send`
|
||||
- `chatId` for history/watch (from `imsg chats --limit 10 --json`)
|
||||
- `text` and optional `file` path for sends
|
||||
## When NOT to Use
|
||||
|
||||
## Actions
|
||||
❌ **DON'T use this skill when:**
|
||||
|
||||
### List chats
|
||||
- Telegram messages → use `message` tool with `channel:telegram`
|
||||
- Signal messages → use Signal channel if configured
|
||||
- WhatsApp messages → use WhatsApp channel if configured
|
||||
- Discord messages → use `message` tool with `channel:discord`
|
||||
- Slack messages → use `slack` skill
|
||||
- Group chat management (adding/removing members) → not supported
|
||||
- Bulk/mass messaging → always confirm with user first
|
||||
- Replying in current conversation → just reply normally (OpenClaw routes automatically)
|
||||
|
||||
## Requirements
|
||||
|
||||
- macOS with Messages.app signed in
|
||||
- Full Disk Access for terminal
|
||||
- Automation permission for Messages.app (for sending)
|
||||
|
||||
## Common Commands
|
||||
|
||||
### List Chats
|
||||
|
||||
```bash
|
||||
imsg chats --limit 10 --json
|
||||
```
|
||||
|
||||
### Fetch chat history
|
||||
### View History
|
||||
|
||||
```bash
|
||||
# By chat ID
|
||||
imsg history --chat-id 1 --limit 20 --json
|
||||
|
||||
# With attachments info
|
||||
imsg history --chat-id 1 --limit 20 --attachments --json
|
||||
```
|
||||
|
||||
### Watch a chat
|
||||
### Watch for New Messages
|
||||
|
||||
```bash
|
||||
imsg watch --chat-id 1 --attachments
|
||||
```
|
||||
|
||||
### Send a message
|
||||
### Send Messages
|
||||
|
||||
```bash
|
||||
imsg send --to "+14155551212" --text "hi" --file /path/pic.jpg
|
||||
# Text only
|
||||
imsg send --to "+14155551212" --text "Hello!"
|
||||
|
||||
# With attachment
|
||||
imsg send --to "+14155551212" --text "Check this out" --file /path/to/image.jpg
|
||||
|
||||
# Specify service
|
||||
imsg send --to "+14155551212" --text "Hi" --service imessage
|
||||
imsg send --to "+14155551212" --text "Hi" --service sms
|
||||
```
|
||||
|
||||
## Notes
|
||||
## Service Options
|
||||
|
||||
- `--service imessage|sms|auto` controls delivery.
|
||||
- Confirm recipient + message before sending.
|
||||
- `--service imessage` — Force iMessage (requires recipient has iMessage)
|
||||
- `--service sms` — Force SMS (green bubble)
|
||||
- `--service auto` — Let Messages.app decide (default)
|
||||
|
||||
## Ideas to try
|
||||
## Safety Rules
|
||||
|
||||
- Use `imsg chats --limit 10 --json` to discover chat ids.
|
||||
- Watch a high-signal chat to stream incoming messages.
|
||||
1. **Always confirm recipient and message content** before sending
|
||||
2. **Never send to unknown numbers** without explicit user approval
|
||||
3. **Be careful with attachments** — confirm file path exists
|
||||
4. **Rate limit yourself** — don't spam
|
||||
|
||||
## Example Workflow
|
||||
|
||||
User: "Text mom that I'll be late"
|
||||
|
||||
```bash
|
||||
# 1. Find mom's chat
|
||||
imsg chats --limit 20 --json | jq '.[] | select(.displayName | contains("Mom"))'
|
||||
|
||||
# 2. Confirm with user
|
||||
# "Found Mom at +1555123456. Send 'I'll be late' via iMessage?"
|
||||
|
||||
# 3. Send after confirmation
|
||||
imsg send --to "+1555123456" --text "I'll be late"
|
||||
```
|
||||
|
||||
@ -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;
|
||||
};
|
||||
}
|
||||
@ -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 "<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 + GPT‑5.2 Pro often does). If the CLI times out: don’t 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 (“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).
|
||||
@ -6,7 +6,7 @@ metadata:
|
||||
{
|
||||
"openclaw":
|
||||
{
|
||||
"emoji": "🗣️",
|
||||
"emoji": "🔊",
|
||||
"requires": { "bins": ["sag"], "env": ["ELEVENLABS_API_KEY"] },
|
||||
"primaryEnv": "ELEVENLABS_API_KEY",
|
||||
"install":
|
||||
@ -68,7 +68,7 @@ Confirm voice + speaker before long output.
|
||||
|
||||
## Chat voice responses
|
||||
|
||||
When Peter asks for a "voice" reply (e.g., "crazy scientist voice", "explain in voice"), generate audio and send it:
|
||||
When the user asks for a "voice" reply (e.g., "crazy scientist voice", "explain in voice"), generate audio and send it:
|
||||
|
||||
```bash
|
||||
# Generate audio file
|
||||
|
||||
@ -26,21 +26,40 @@ metadata:
|
||||
|
||||
Use `sonos` to control Sonos speakers on the local network.
|
||||
|
||||
Quick start
|
||||
## Quick start
|
||||
|
||||
- `sonos discover`
|
||||
- `sonos status --name "Kitchen"`
|
||||
- `sonos play|pause|stop --name "Kitchen"`
|
||||
- `sonos volume set 15 --name "Kitchen"`
|
||||
|
||||
Common tasks
|
||||
## Common tasks
|
||||
|
||||
- Grouping: `sonos group status|join|unjoin|party|solo`
|
||||
- Favorites: `sonos favorites list|open`
|
||||
- Queue: `sonos queue list|play|clear`
|
||||
- Spotify search (via SMAPI): `sonos smapi search --service "Spotify" --category tracks "query"`
|
||||
|
||||
Notes
|
||||
## Notes
|
||||
|
||||
- If SSDP fails, specify `--ip <speaker-ip>`.
|
||||
- Spotify Web API search is optional and requires `SPOTIFY_CLIENT_ID/SECRET`.
|
||||
- If there is an error, check the troubleshooting section and offer advice if there is a decent match.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### `sonos discover` - `no route to host`
|
||||
|
||||
- On error `Error: write udp4 0.0.0.0:64326->239.255.255.250:1900: sendto: no route to host (Command exited with code 1)`
|
||||
- Note that the port number after `0.0.0.0:` is ephemeral and will change and the netmask may not match exactly either
|
||||
- The `sendto: no route to host` should stay consistent
|
||||
- Advise the user that in `direct` (no Docker sandbox) mode on Mac OS that Settings -> Privacy & Security -> Local Network will need to be enabled for the top-level host parent process of the Gateway
|
||||
- `node` if running via `launchd`
|
||||
- `Terminal` if running the gateway directly in the terminal
|
||||
- `Visual Studio Code` if running via terminal in VS Code
|
||||
- An alternative option is to use `sandbox` (docker container) with network access allowed for that sandbox
|
||||
|
||||
### `sonos discover` - `bind: operation not permitted`
|
||||
|
||||
- On error `Error: listen udp4 0.0.0.0:0: bind: operation not permitted`
|
||||
- Advise the user that they may be running via a Codex or other sandbox that does not permit network access (this can be replicated by running `sonos discover` within a Codex CLI session with sandbox enabled and not approving the escalation request)
|
||||
|
||||
65
tools/summarize/flake.lock
generated
Normal file
65
tools/summarize/flake.lock
generated
Normal file
@ -0,0 +1,65 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1767364772,
|
||||
"narHash": "sha256-fFUnEYMla8b7UKjijLnMe+oVFOz6HjijGGNS1l7dYaQ=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "16c7794d0a28b5a37904d55bcca36003b9109aaa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"narHash": "sha256-fFUnEYMla8b7UKjijLnMe+oVFOz6HjijGGNS1l7dYaQ=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "16c7794d0a28b5a37904d55bcca36003b9109aaa",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1767364772,
|
||||
"narHash": "sha256-fFUnEYMla8b7UKjijLnMe+oVFOz6HjijGGNS1l7dYaQ=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "16c7794d0a28b5a37904d55bcca36003b9109aaa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs",
|
||||
"root": "root_2"
|
||||
}
|
||||
},
|
||||
"root_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1769797395,
|
||||
"narHash": "sha256-QkPl/Rgk9DXgaVNhjvHHHjy5e81j+MzcVOouZRdUTLA=",
|
||||
"owner": "openclaw",
|
||||
"repo": "nix-steipete-tools",
|
||||
"rev": "dbf0a31a57407d9140e32357ea8d0215bd9feed9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"narHash": "sha256-QkPl/Rgk9DXgaVNhjvHHHjy5e81j+MzcVOouZRdUTLA=",
|
||||
"owner": "openclaw",
|
||||
"repo": "nix-steipete-tools",
|
||||
"rev": "dbf0a31a57407d9140e32357ea8d0215bd9feed9",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: summarize
|
||||
description: Summarize or extract text/transcripts from URLs, podcasts, and local files (great fallback for “transcribe this YouTube/video”).
|
||||
description: Summarize or transcribe URLs, YouTube/videos, podcasts, articles, transcripts, PDFs, and local files.
|
||||
homepage: https://summarize.sh
|
||||
metadata:
|
||||
{
|
||||
|
||||
38
tools/wacrawl/flake.nix
Normal file
38
tools/wacrawl/flake.nix
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
description = "openclaw plugin: wacrawl";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs?rev=16c7794d0a28b5a37904d55bcca36003b9109aaa&narHash=sha256-fFUnEYMla8b7UKjijLnMe%2BoVFOz6HjijGGNS1l7dYaQ%3D";
|
||||
root.url = "path:../..";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, root }:
|
||||
let
|
||||
lib = nixpkgs.lib;
|
||||
systems = builtins.attrNames root.packages;
|
||||
pluginFor = system:
|
||||
let
|
||||
packagesForSystem = root.packages.${system} or {};
|
||||
wacrawl = packagesForSystem.wacrawl or null;
|
||||
in
|
||||
if wacrawl == null then null else {
|
||||
name = "wacrawl";
|
||||
skills = [ ./skills/wacrawl ];
|
||||
packages = [ wacrawl ];
|
||||
needs = {
|
||||
stateDirs = [ ".wacrawl" ];
|
||||
requiredEnv = [ ];
|
||||
};
|
||||
};
|
||||
in {
|
||||
packages = lib.genAttrs systems (system:
|
||||
let
|
||||
wacrawl = (root.packages.${system} or {}).wacrawl or null;
|
||||
in
|
||||
if wacrawl == null then {}
|
||||
else { wacrawl = wacrawl; }
|
||||
);
|
||||
|
||||
openclawPlugin = pluginFor;
|
||||
};
|
||||
}
|
||||
69
tools/wacrawl/skills/wacrawl/SKILL.md
Normal file
69
tools/wacrawl/skills/wacrawl/SKILL.md
Normal file
@ -0,0 +1,69 @@
|
||||
---
|
||||
name: wacrawl
|
||||
description: Read-only local archive and search for WhatsApp Desktop chats, messages, and media metadata.
|
||||
homepage: https://github.com/steipete/wacrawl
|
||||
metadata:
|
||||
{
|
||||
"openclaw":
|
||||
{
|
||||
"emoji": "💬",
|
||||
"requires": { "bins": ["wacrawl"] },
|
||||
"install":
|
||||
[
|
||||
{
|
||||
"id": "brew",
|
||||
"kind": "brew",
|
||||
"formula": "steipete/tap/wacrawl",
|
||||
"bins": ["wacrawl"],
|
||||
"label": "Install wacrawl (brew)",
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
---
|
||||
|
||||
# wacrawl
|
||||
|
||||
Use `wacrawl` to snapshot local WhatsApp Desktop data into a separate SQLite archive and search it offline.
|
||||
|
||||
## When to Use
|
||||
|
||||
Use this skill when the user wants to:
|
||||
|
||||
- inspect local WhatsApp Desktop history without opening the app
|
||||
- archive chats into a local SQLite database for repeat queries
|
||||
- search WhatsApp messages locally with filters
|
||||
- list chats, recent messages, or archive status from a read-only import
|
||||
|
||||
## Requirements
|
||||
|
||||
- local WhatsApp Desktop data on the same machine
|
||||
- enough local disk for `~/.wacrawl/wacrawl.db`
|
||||
- understand that this is read-only inspection, not message sending
|
||||
|
||||
## Setup
|
||||
|
||||
- Default source: `~/Library/Group Containers/group.net.whatsapp.WhatsApp.shared`
|
||||
- Default archive DB: `~/.wacrawl/wacrawl.db`
|
||||
- First sanity check:
|
||||
- `wacrawl doctor`
|
||||
- First import:
|
||||
- `wacrawl import`
|
||||
|
||||
## Common Commands
|
||||
|
||||
- Doctor: `wacrawl doctor`
|
||||
- Import fresh snapshot: `wacrawl import`
|
||||
- Archive status: `wacrawl status`
|
||||
- List chats: `wacrawl chats --limit 20`
|
||||
- Recent messages: `wacrawl messages --limit 20`
|
||||
- One chat: `wacrawl messages --chat 1234567890@s.whatsapp.net --limit 50`
|
||||
- Search: `wacrawl search "release notes"`
|
||||
- Filtered search: `wacrawl --json search "invoice" --from-them --after 2026-01-01`
|
||||
|
||||
## Notes
|
||||
|
||||
- `wacrawl` is read-only and does not send messages.
|
||||
- It copies WhatsApp SQLite files into a temp snapshot before import.
|
||||
- Use `--source` to override the WhatsApp Desktop container path.
|
||||
- Use `--db` to archive somewhere other than `~/.wacrawl/wacrawl.db`.
|
||||
Loading…
Reference in New Issue
Block a user