nextclaw-core 0.4.0 โ†’ 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ usage() {
5
+ cat <<'USAGE'
6
+ Usage: find-sessions.sh [-L socket-name|-S socket-path|-A] [-q pattern]
7
+
8
+ List tmux sessions on a socket (default tmux socket if none provided).
9
+
10
+ Options:
11
+ -L, --socket tmux socket name (passed to tmux -L)
12
+ -S, --socket-path tmux socket path (passed to tmux -S)
13
+ -A, --all scan all sockets under NEXTCLAW_TMUX_SOCKET_DIR
14
+ -q, --query case-insensitive substring to filter session names
15
+ -h, --help show this help
16
+ USAGE
17
+ }
18
+
19
+ socket_name=""
20
+ socket_path=""
21
+ query=""
22
+ scan_all=false
23
+ socket_dir="${NEXTCLAW_TMUX_SOCKET_DIR:-${TMPDIR:-/tmp}/nextclaw-tmux-sockets}"
24
+
25
+ while [[ $# -gt 0 ]]; do
26
+ case "$1" in
27
+ -L|--socket) socket_name="${2-}"; shift 2 ;;
28
+ -S|--socket-path) socket_path="${2-}"; shift 2 ;;
29
+ -A|--all) scan_all=true; shift ;;
30
+ -q|--query) query="${2-}"; shift 2 ;;
31
+ -h|--help) usage; exit 0 ;;
32
+ *) echo "Unknown option: $1" >&2; usage; exit 1 ;;
33
+ esac
34
+ done
35
+
36
+ if [[ "$scan_all" == true && ( -n "$socket_name" || -n "$socket_path" ) ]]; then
37
+ echo "Cannot combine --all with -L or -S" >&2
38
+ exit 1
39
+ fi
40
+
41
+ if [[ -n "$socket_name" && -n "$socket_path" ]]; then
42
+ echo "Use either -L or -S, not both" >&2
43
+ exit 1
44
+ fi
45
+
46
+ if ! command -v tmux >/dev/null 2>&1; then
47
+ echo "tmux not found in PATH" >&2
48
+ exit 1
49
+ fi
50
+
51
+ list_sessions() {
52
+ local label="$1"; shift
53
+ local tmux_cmd=(tmux "$@")
54
+
55
+ if ! sessions="$("${tmux_cmd[@]}" list-sessions -F '#{session_name}\t#{session_attached}\t#{session_created_string}' 2>/dev/null)"; then
56
+ echo "No tmux server found on $label" >&2
57
+ return 1
58
+ fi
59
+
60
+ if [[ -n "$query" ]]; then
61
+ sessions="$(printf '%s\n' "$sessions" | grep -i -- "$query" || true)"
62
+ fi
63
+
64
+ if [[ -z "$sessions" ]]; then
65
+ echo "No sessions found on $label"
66
+ return 0
67
+ fi
68
+
69
+ echo "Sessions on $label:"
70
+ printf '%s\n' "$sessions" | while IFS=$'\t' read -r name attached created; do
71
+ attached_label=$([[ "$attached" == "1" ]] && echo "attached" || echo "detached")
72
+ printf ' - %s (%s, started %s)\n' "$name" "$attached_label" "$created"
73
+ done
74
+ }
75
+
76
+ if [[ "$scan_all" == true ]]; then
77
+ if [[ ! -d "$socket_dir" ]]; then
78
+ echo "Socket directory not found: $socket_dir" >&2
79
+ exit 1
80
+ fi
81
+
82
+ shopt -s nullglob
83
+ sockets=("$socket_dir"/*)
84
+ shopt -u nullglob
85
+
86
+ if [[ "${#sockets[@]}" -eq 0 ]]; then
87
+ echo "No sockets found under $socket_dir" >&2
88
+ exit 1
89
+ fi
90
+
91
+ exit_code=0
92
+ for sock in "${sockets[@]}"; do
93
+ if [[ ! -S "$sock" ]]; then
94
+ continue
95
+ fi
96
+ list_sessions "socket path '$sock'" -S "$sock" || exit_code=$?
97
+ done
98
+ exit "$exit_code"
99
+ fi
100
+
101
+ tmux_cmd=(tmux)
102
+ socket_label="default socket"
103
+
104
+ if [[ -n "$socket_name" ]]; then
105
+ tmux_cmd+=(-L "$socket_name")
106
+ socket_label="socket name '$socket_name'"
107
+ elif [[ -n "$socket_path" ]]; then
108
+ tmux_cmd+=(-S "$socket_path")
109
+ socket_label="socket path '$socket_path'"
110
+ fi
111
+
112
+ list_sessions "$socket_label" "${tmux_cmd[@]:1}"
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ usage() {
5
+ cat <<'USAGE'
6
+ Usage: wait-for-text.sh -t target -p pattern [options]
7
+
8
+ Poll a tmux pane for text and exit when found.
9
+
10
+ Options:
11
+ -t, --target tmux target (session:window.pane), required
12
+ -p, --pattern regex pattern to look for, required
13
+ -F, --fixed treat pattern as a fixed string (grep -F)
14
+ -T, --timeout seconds to wait (integer, default: 15)
15
+ -i, --interval poll interval in seconds (default: 0.5)
16
+ -l, --lines number of history lines to inspect (integer, default: 1000)
17
+ -h, --help show this help
18
+ USAGE
19
+ }
20
+
21
+ target=""
22
+ pattern=""
23
+ grep_flag="-E"
24
+ timeout=15
25
+ interval=0.5
26
+ lines=1000
27
+
28
+ while [[ $# -gt 0 ]]; do
29
+ case "$1" in
30
+ -t|--target) target="${2-}"; shift 2 ;;
31
+ -p|--pattern) pattern="${2-}"; shift 2 ;;
32
+ -F|--fixed) grep_flag="-F"; shift ;;
33
+ -T|--timeout) timeout="${2-}"; shift 2 ;;
34
+ -i|--interval) interval="${2-}"; shift 2 ;;
35
+ -l|--lines) lines="${2-}"; shift 2 ;;
36
+ -h|--help) usage; exit 0 ;;
37
+ *) echo "Unknown option: $1" >&2; usage; exit 1 ;;
38
+ esac
39
+ done
40
+
41
+ if [[ -z "$target" || -z "$pattern" ]]; then
42
+ echo "target and pattern are required" >&2
43
+ usage
44
+ exit 1
45
+ fi
46
+
47
+ if ! [[ "$timeout" =~ ^[0-9]+$ ]]; then
48
+ echo "timeout must be an integer number of seconds" >&2
49
+ exit 1
50
+ fi
51
+
52
+ if ! [[ "$lines" =~ ^[0-9]+$ ]]; then
53
+ echo "lines must be an integer" >&2
54
+ exit 1
55
+ fi
56
+
57
+ if ! command -v tmux >/dev/null 2>&1; then
58
+ echo "tmux not found in PATH" >&2
59
+ exit 1
60
+ fi
61
+
62
+ # End time in epoch seconds (integer, good enough for polling)
63
+ start_epoch=$(date +%s)
64
+ deadline=$((start_epoch + timeout))
65
+
66
+ while true; do
67
+ # -J joins wrapped lines, -S uses negative index to read last N lines
68
+ pane_text="$(tmux capture-pane -p -J -t "$target" -S "-${lines}" 2>/dev/null || true)"
69
+
70
+ if printf '%s\n' "$pane_text" | grep $grep_flag -- "$pattern" >/dev/null 2>&1; then
71
+ exit 0
72
+ fi
73
+
74
+ now=$(date +%s)
75
+ if (( now >= deadline )); then
76
+ echo "Timed out after ${timeout}s waiting for pattern: $pattern" >&2
77
+ echo "Last ${lines} lines from $target:" >&2
78
+ printf '%s\n' "$pane_text" >&2
79
+ exit 1
80
+ fi
81
+
82
+ sleep "$interval"
83
+ done
@@ -0,0 +1,49 @@
1
+ ---
2
+ name: weather
3
+ description: Get current weather and forecasts (no API key required).
4
+ homepage: https://wttr.in/:help
5
+ metadata: {"nextclaw":{"emoji":"๐ŸŒค๏ธ","requires":{"bins":["curl"]}}}
6
+ ---
7
+
8
+ # Weather
9
+
10
+ Two free services, no API keys needed.
11
+
12
+ ## wttr.in (primary)
13
+
14
+ Quick one-liner:
15
+ ```bash
16
+ curl -s "wttr.in/London?format=3"
17
+ # Output: London: โ›…๏ธ +8ยฐC
18
+ ```
19
+
20
+ Compact format:
21
+ ```bash
22
+ curl -s "wttr.in/London?format=%l:+%c+%t+%h+%w"
23
+ # Output: London: โ›…๏ธ +8ยฐC 71% โ†™5km/h
24
+ ```
25
+
26
+ Full forecast:
27
+ ```bash
28
+ curl -s "wttr.in/London?T"
29
+ ```
30
+
31
+ Format codes: `%c` condition ยท `%t` temp ยท `%h` humidity ยท `%w` wind ยท `%l` location ยท `%m` moon
32
+
33
+ Tips:
34
+ - URL-encode spaces: `wttr.in/New+York`
35
+ - Airport codes: `wttr.in/JFK`
36
+ - Units: `?m` (metric) `?u` (USCS)
37
+ - Today only: `?1` ยท Current only: `?0`
38
+ - PNG: `curl -s "wttr.in/Berlin.png" -o /tmp/weather.png`
39
+
40
+ ## Open-Meteo (fallback, JSON)
41
+
42
+ Free, no key, good for programmatic use:
43
+ ```bash
44
+ curl -s "https://api.open-meteo.com/v1/forecast?latitude=51.5&longitude=-0.12&current_weather=true"
45
+ ```
46
+
47
+ Find coordinates for a city, then query. Returns JSON with temp, windspeed, weathercode.
48
+
49
+ Docs: https://open-meteo.com/en/docs
package/dist/index.js CHANGED
@@ -1,7 +1,6 @@
1
1
  // src/agent/context.ts
2
2
  import { readFileSync as readFileSync3, existsSync as existsSync4 } from "fs";
3
3
  import { join as join3, extname } from "path";
4
- import { fileURLToPath as fileURLToPath2 } from "url";
5
4
 
6
5
  // src/agent/memory.ts
7
6
  import { readFileSync, writeFileSync, existsSync as existsSync2, readdirSync } from "fs";
@@ -402,7 +401,7 @@ var ContextBuilder = class {
402
401
  constructor(workspace, contextConfig) {
403
402
  this.workspace = workspace;
404
403
  this.memory = new MemoryStore(workspace);
405
- this.skills = new SkillsLoader(workspace, join3(fileURLToPath2(new URL("..", import.meta.url)), "skills"));
404
+ this.skills = new SkillsLoader(workspace);
406
405
  this.contextConfig = {
407
406
  bootstrap: {
408
407
  ...DEFAULT_CONTEXT_CONFIG.bootstrap,
@@ -0,0 +1,24 @@
1
+ # nextclaw Skills
2
+
3
+ This directory contains built-in skills that extend nextclaw's capabilities.
4
+
5
+ ## Skill Format
6
+
7
+ Each skill is a directory containing a `SKILL.md` file with:
8
+ - YAML frontmatter (name, description, metadata)
9
+ - Markdown instructions for the agent
10
+
11
+ ## Attribution
12
+
13
+ These skills are adapted from [OpenClaw](https://github.com/openclaw/openclaw)'s skill system.
14
+ The skill format and metadata structure follow OpenClaw's conventions to maintain compatibility.
15
+
16
+ ## Available Skills
17
+
18
+ | Skill | Description |
19
+ |-------|-------------|
20
+ | `github` | Interact with GitHub using the `gh` CLI |
21
+ | `weather` | Get weather info using wttr.in and Open-Meteo |
22
+ | `summarize` | Summarize URLs, files, and YouTube videos |
23
+ | `tmux` | Remote-control tmux sessions |
24
+ | `skill-creator` | Create new skills |
@@ -0,0 +1,40 @@
1
+ ---
2
+ name: cron
3
+ description: Schedule reminders and recurring tasks.
4
+ ---
5
+
6
+ # Cron
7
+
8
+ Use the `cron` tool to schedule reminders or recurring tasks.
9
+
10
+ ## Two Modes
11
+
12
+ 1. **Reminder** - message is sent directly to user
13
+ 2. **Task** - message is a task description, agent executes and sends result
14
+
15
+ ## Examples
16
+
17
+ Fixed reminder:
18
+ ```
19
+ cron(action="add", message="Time to take a break!", every_seconds=1200)
20
+ ```
21
+
22
+ Dynamic task (agent executes each time):
23
+ ```
24
+ cron(action="add", message="Check Peiiii/nextclaw GitHub stars and report", every_seconds=600)
25
+ ```
26
+
27
+ List/remove:
28
+ ```
29
+ cron(action="list")
30
+ cron(action="remove", job_id="abc123")
31
+ ```
32
+
33
+ ## Time Expressions
34
+
35
+ | User says | Parameters |
36
+ |-----------|------------|
37
+ | every 20 minutes | every_seconds: 1200 |
38
+ | every hour | every_seconds: 3600 |
39
+ | every day at 8am | cron_expr: "0 8 * * *" |
40
+ | weekdays at 5pm | cron_expr: "0 17 * * 1-5" |
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: github
3
+ description: "Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries."
4
+ metadata: {"nextclaw":{"emoji":"๐Ÿ™","requires":{"bins":["gh"]},"install":[{"id":"brew","kind":"brew","formula":"gh","bins":["gh"],"label":"Install GitHub CLI (brew)"},{"id":"apt","kind":"apt","package":"gh","bins":["gh"],"label":"Install GitHub CLI (apt)"}]}}
5
+ ---
6
+
7
+ # GitHub Skill
8
+
9
+ Use the `gh` CLI to interact with GitHub. Always specify `--repo owner/repo` when not in a git directory, or use URLs directly.
10
+
11
+ ## Pull Requests
12
+
13
+ Check CI status on a PR:
14
+ ```bash
15
+ gh pr checks 55 --repo owner/repo
16
+ ```
17
+
18
+ List recent workflow runs:
19
+ ```bash
20
+ gh run list --repo owner/repo --limit 10
21
+ ```
22
+
23
+ View a run and see which steps failed:
24
+ ```bash
25
+ gh run view <run-id> --repo owner/repo
26
+ ```
27
+
28
+ View logs for failed steps only:
29
+ ```bash
30
+ gh run view <run-id> --repo owner/repo --log-failed
31
+ ```
32
+
33
+ ## API for Advanced Queries
34
+
35
+ The `gh api` command is useful for accessing data not available through other subcommands.
36
+
37
+ Get PR with specific fields:
38
+ ```bash
39
+ gh api repos/owner/repo/pulls/55 --jq '.title, .state, .user.login'
40
+ ```
41
+
42
+ ## JSON Output
43
+
44
+ Most commands support `--json` for structured output. You can use `--jq` to filter:
45
+
46
+ ```bash
47
+ gh issue list --repo owner/repo --json number,title --jq '.[] | "\(.number): \(.title)"'
48
+ ```