@a5c-ai/babysitter-openclaw 0.1.1-staging.45beae68

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.
Files changed (50) hide show
  1. package/README.md +312 -0
  2. package/bin/cli.cjs +80 -0
  3. package/bin/install.cjs +370 -0
  4. package/bin/uninstall.cjs +172 -0
  5. package/commands/assimilate.md +37 -0
  6. package/commands/babysit.md +7 -0
  7. package/commands/call.md +7 -0
  8. package/commands/cleanup.md +20 -0
  9. package/commands/contrib.md +33 -0
  10. package/commands/doctor.md +426 -0
  11. package/commands/forever.md +7 -0
  12. package/commands/help.md +244 -0
  13. package/commands/observe.md +12 -0
  14. package/commands/plan.md +7 -0
  15. package/commands/plugins.md +255 -0
  16. package/commands/project-install.md +17 -0
  17. package/commands/resume.md +8 -0
  18. package/commands/retrospect.md +55 -0
  19. package/commands/user-install.md +17 -0
  20. package/commands/yolo.md +7 -0
  21. package/extensions/hooks/agent-end.ts +127 -0
  22. package/extensions/hooks/before-prompt-build.ts +98 -0
  23. package/extensions/hooks/session-end.ts +80 -0
  24. package/extensions/hooks/session-start.ts +81 -0
  25. package/extensions/index.ts +67 -0
  26. package/hooks/babysitter-session-start.sh +61 -0
  27. package/hooks/babysitter-stop-hook.sh +44 -0
  28. package/hooks.json +26 -0
  29. package/openclaw.plugin.json +17 -0
  30. package/package.json +67 -0
  31. package/plugin.json +25 -0
  32. package/scripts/setup.sh +99 -0
  33. package/scripts/sync-command-docs.cjs +106 -0
  34. package/skills/assimilate/SKILL.md +38 -0
  35. package/skills/babysit/SKILL.md +36 -0
  36. package/skills/call/SKILL.md +8 -0
  37. package/skills/cleanup/SKILL.md +21 -0
  38. package/skills/contrib/SKILL.md +34 -0
  39. package/skills/doctor/SKILL.md +427 -0
  40. package/skills/forever/SKILL.md +8 -0
  41. package/skills/help/SKILL.md +245 -0
  42. package/skills/observe/SKILL.md +13 -0
  43. package/skills/plan/SKILL.md +8 -0
  44. package/skills/plugins/SKILL.md +257 -0
  45. package/skills/project-install/SKILL.md +18 -0
  46. package/skills/resume/SKILL.md +9 -0
  47. package/skills/retrospect/SKILL.md +56 -0
  48. package/skills/user-install/SKILL.md +18 -0
  49. package/skills/yolo/SKILL.md +8 -0
  50. package/versions.json +3 -0
@@ -0,0 +1,80 @@
1
+ /**
2
+ * OpenClaw session_end hook handler.
3
+ * Delegates to: babysitter hook:run --hook-type stop --harness openclaw
4
+ *
5
+ * Runs on session teardown to finalize any active babysitter runs.
6
+ */
7
+
8
+ import { execFileSync } from "node:child_process";
9
+ import { readFileSync, mkdirSync } from "node:fs";
10
+ import { homedir } from "node:os";
11
+ import { resolve, dirname } from "node:path";
12
+ import { fileURLToPath } from "node:url";
13
+
14
+ const __dirname = dirname(fileURLToPath(import.meta.url));
15
+ const PLUGIN_ROOT = resolve(__dirname, "../..");
16
+
17
+ function getLogDir(): string {
18
+ const dir = process.env.BABYSITTER_LOG_DIR ?? resolve(homedir(), ".a5c/logs");
19
+ mkdirSync(dir, { recursive: true });
20
+ return dir;
21
+ }
22
+
23
+ function getSdkVersion(): string {
24
+ try {
25
+ const versionsPath = resolve(PLUGIN_ROOT, "versions.json");
26
+ const data = JSON.parse(readFileSync(versionsPath, "utf8"));
27
+ return data.sdkVersion ?? "latest";
28
+ } catch {
29
+ return "latest";
30
+ }
31
+ }
32
+
33
+ function resolveBabysitterCli(): string {
34
+ try {
35
+ execFileSync("babysitter", ["--version"], { stdio: "ignore" });
36
+ return "babysitter";
37
+ } catch {
38
+ return `npx -y @a5c-ai/babysitter-sdk@${getSdkVersion()}`;
39
+ }
40
+ }
41
+
42
+ export async function sessionEndHandler(context: Record<string, unknown>): Promise<void> {
43
+ const logDir = getLogDir();
44
+ const stateDir = process.env.BABYSITTER_STATE_DIR ?? resolve(process.cwd(), ".a5c");
45
+ const cli = resolveBabysitterCli();
46
+
47
+ try {
48
+ const input = JSON.stringify(context);
49
+ const args = [
50
+ "hook:run",
51
+ "--hook-type", "stop",
52
+ "--harness", "openclaw",
53
+ "--plugin-root", PLUGIN_ROOT,
54
+ "--state-dir", stateDir,
55
+ ];
56
+
57
+ if (cli === "babysitter") {
58
+ execFileSync("babysitter", args, {
59
+ input,
60
+ stdio: ["pipe", "pipe", "pipe"],
61
+ timeout: 30_000,
62
+ });
63
+ } else {
64
+ execFileSync("npx", ["-y", `@a5c-ai/babysitter-sdk@${getSdkVersion()}`, ...args], {
65
+ input,
66
+ stdio: ["pipe", "pipe", "pipe"],
67
+ timeout: 60_000,
68
+ });
69
+ }
70
+ } catch (err) {
71
+ try {
72
+ const ts = new Date().toISOString();
73
+ const msg = `[ERROR] ${ts} session-end hook failed: ${err instanceof Error ? err.message : String(err)}\n`;
74
+ const { appendFileSync } = await import("node:fs");
75
+ appendFileSync(resolve(logDir, "babysitter-session-end-hook.log"), msg);
76
+ } catch {
77
+ // Swallow logging failures
78
+ }
79
+ }
80
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * OpenClaw session_start hook handler.
3
+ * Delegates to: babysitter hook:run --hook-type session-start --harness openclaw
4
+ *
5
+ * Ensures the babysitter CLI is available and triggers session initialization.
6
+ */
7
+
8
+ import { execFileSync } from "node:child_process";
9
+ import { readFileSync, mkdirSync } from "node:fs";
10
+ import { homedir } from "node:os";
11
+ import { resolve, dirname } from "node:path";
12
+ import { fileURLToPath } from "node:url";
13
+
14
+ const __dirname = dirname(fileURLToPath(import.meta.url));
15
+ const PLUGIN_ROOT = resolve(__dirname, "../..");
16
+
17
+ function getLogDir(): string {
18
+ const dir = process.env.BABYSITTER_LOG_DIR ?? resolve(homedir(), ".a5c/logs");
19
+ mkdirSync(dir, { recursive: true });
20
+ return dir;
21
+ }
22
+
23
+ function getSdkVersion(): string {
24
+ try {
25
+ const versionsPath = resolve(PLUGIN_ROOT, "versions.json");
26
+ const data = JSON.parse(readFileSync(versionsPath, "utf8"));
27
+ return data.sdkVersion ?? "latest";
28
+ } catch {
29
+ return "latest";
30
+ }
31
+ }
32
+
33
+ function resolveBabysitterCli(): string {
34
+ try {
35
+ execFileSync("babysitter", ["--version"], { stdio: "ignore" });
36
+ return "babysitter";
37
+ } catch {
38
+ return `npx -y @a5c-ai/babysitter-sdk@${getSdkVersion()}`;
39
+ }
40
+ }
41
+
42
+ export async function sessionStartHandler(context: Record<string, unknown>): Promise<void> {
43
+ const logDir = getLogDir();
44
+ const stateDir = process.env.BABYSITTER_STATE_DIR ?? resolve(process.cwd(), ".a5c");
45
+ const cli = resolveBabysitterCli();
46
+
47
+ try {
48
+ const input = JSON.stringify(context);
49
+ const args = [
50
+ "hook:run",
51
+ "--hook-type", "session-start",
52
+ "--harness", "openclaw",
53
+ "--plugin-root", PLUGIN_ROOT,
54
+ "--state-dir", stateDir,
55
+ ];
56
+
57
+ if (cli === "babysitter") {
58
+ execFileSync("babysitter", args, {
59
+ input,
60
+ stdio: ["pipe", "pipe", "pipe"],
61
+ timeout: 30_000,
62
+ });
63
+ } else {
64
+ execFileSync("npx", ["-y", `@a5c-ai/babysitter-sdk@${getSdkVersion()}`, ...args], {
65
+ input,
66
+ stdio: ["pipe", "pipe", "pipe"],
67
+ timeout: 60_000,
68
+ });
69
+ }
70
+ } catch (err) {
71
+ // Log but do not fail the session — hooks are best-effort
72
+ try {
73
+ const ts = new Date().toISOString();
74
+ const msg = `[ERROR] ${ts} session-start hook failed: ${err instanceof Error ? err.message : String(err)}\n`;
75
+ const { appendFileSync } = await import("node:fs");
76
+ appendFileSync(resolve(logDir, "babysitter-session-start-hook.log"), msg);
77
+ } catch {
78
+ // Swallow logging failures
79
+ }
80
+ }
81
+ }
@@ -0,0 +1,67 @@
1
+ import type { OpenClawPluginAPI } from "openclaw";
2
+ import { sessionStartHandler } from "./hooks/session-start.js";
3
+ import { sessionEndHandler } from "./hooks/session-end.js";
4
+ import { beforePromptBuildHandler } from "./hooks/before-prompt-build.js";
5
+ import { agentEndHandler } from "./hooks/agent-end.js";
6
+
7
+ const COMMANDS = [
8
+ "assimilate",
9
+ "call",
10
+ "cleanup",
11
+ "contrib",
12
+ "doctor",
13
+ "forever",
14
+ "help",
15
+ "observe",
16
+ "plan",
17
+ "plugins",
18
+ "project-install",
19
+ "resume",
20
+ "retrospect",
21
+ "user-install",
22
+ "yolo",
23
+ ] as const;
24
+
25
+ function toSkillPrompt(name: string, args: string): string {
26
+ return `/skill:${name}${args ? ` ${args}` : ""}`;
27
+ }
28
+
29
+ export default function activate(api: OpenClawPluginAPI): void {
30
+ // Register programmatic hooks via the OpenClaw Plugin SDK api.on() method.
31
+ // These delegate to babysitter hook:run — no logic lives here.
32
+ api.on("session_start", sessionStartHandler);
33
+ api.on("session_end", sessionEndHandler);
34
+ api.on("before_prompt_build", beforePromptBuildHandler);
35
+ api.on("agent_end", agentEndHandler);
36
+
37
+ // Register slash commands that forward to babysitter skills
38
+ const forwardBabysit = async (args: unknown) => {
39
+ api.sendUserMessage(toSkillPrompt("babysit", String(args ?? "").trim()));
40
+ };
41
+
42
+ api.registerCommand("babysit", {
43
+ description: "Load the Babysitter orchestration skill",
44
+ handler: forwardBabysit,
45
+ });
46
+
47
+ api.registerCommand("babysitter", {
48
+ description: "Alias for /babysit",
49
+ handler: forwardBabysit,
50
+ });
51
+
52
+ for (const name of COMMANDS) {
53
+ const forward = async (args: unknown) => {
54
+ api.sendUserMessage(toSkillPrompt(name, String(args ?? "").trim()));
55
+ };
56
+
57
+ api.registerCommand(name, {
58
+ description: `Open the Babysitter ${name} skill`,
59
+ handler: forward,
60
+ });
61
+
62
+ api.registerCommand(`babysitter:${name}`, {
63
+ description: `Alias for /${name}`,
64
+ handler: forward,
65
+ });
66
+ }
67
+ }
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ PLUGIN_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
6
+ STATE_DIR="${BABYSITTER_STATE_DIR:-${PWD}/.a5c}"
7
+ LOG_DIR="${BABYSITTER_LOG_DIR:-$HOME/.a5c/logs}"
8
+ LOG_FILE="$LOG_DIR/babysitter-session-start-hook.log"
9
+
10
+ export OPENCLAW_PLUGIN_ROOT="${OPENCLAW_PLUGIN_ROOT:-${PLUGIN_ROOT}}"
11
+ export BABYSITTER_STATE_DIR="${STATE_DIR}"
12
+
13
+ mkdir -p "$LOG_DIR" 2>/dev/null
14
+
15
+ blog() {
16
+ local msg="$1"
17
+ local ts
18
+ ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
19
+ echo "[INFO] $ts $msg" >> "$LOG_FILE" 2>/dev/null
20
+ babysitter log --type hook --label "hook:session-start" --message "$msg" --source shell-hook 2>/dev/null || true
21
+ }
22
+
23
+ blog "Hook script invoked"
24
+ blog "PLUGIN_ROOT=$PLUGIN_ROOT"
25
+ blog "STATE_DIR=$STATE_DIR"
26
+
27
+ # Get required SDK version from versions.json
28
+ SDK_VERSION=$(node -e "try{console.log(JSON.parse(require('fs').readFileSync('${PLUGIN_ROOT}/versions.json','utf8')).sdkVersion||'latest')}catch{console.log('latest')}" 2>/dev/null || echo "latest")
29
+
30
+ # Ensure babysitter CLI is available
31
+ if ! command -v babysitter &>/dev/null; then
32
+ if [ -x "$HOME/.local/bin/babysitter" ]; then
33
+ export PATH="$HOME/.local/bin:$PATH"
34
+ else
35
+ if npm i -g "@a5c-ai/babysitter-sdk@${SDK_VERSION}" --loglevel=error 2>/dev/null; then
36
+ blog "Installed SDK globally (${SDK_VERSION})"
37
+ elif npm i -g "@a5c-ai/babysitter-sdk@${SDK_VERSION}" --prefix "$HOME/.local" --loglevel=error 2>/dev/null; then
38
+ export PATH="$HOME/.local/bin:$PATH"
39
+ blog "Installed SDK to user prefix (${SDK_VERSION})"
40
+ fi
41
+ fi
42
+ fi
43
+
44
+ INPUT_FILE=$(mktemp 2>/dev/null || echo "/tmp/openclaw-session-start-hook-$$.json")
45
+ cat > "$INPUT_FILE"
46
+
47
+ blog "Hook input received ($(wc -c < "$INPUT_FILE") bytes)"
48
+
49
+ RESULT=$(babysitter hook:run \
50
+ --hook-type session-start \
51
+ --harness openclaw \
52
+ --plugin-root "${OPENCLAW_PLUGIN_ROOT}" \
53
+ --state-dir "${BABYSITTER_STATE_DIR}" \
54
+ < "$INPUT_FILE" 2>"$LOG_DIR/babysitter-session-start-hook-stderr.log")
55
+ EXIT_CODE=$?
56
+
57
+ blog "CLI exit code=$EXIT_CODE"
58
+
59
+ rm -f "$INPUT_FILE" 2>/dev/null
60
+ printf '%s\n' "$RESULT"
61
+ exit $EXIT_CODE
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ PLUGIN_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
6
+ STATE_DIR="${BABYSITTER_STATE_DIR:-${PWD}/.a5c}"
7
+ LOG_DIR="${BABYSITTER_LOG_DIR:-$HOME/.a5c/logs}"
8
+ LOG_FILE="$LOG_DIR/babysitter-stop-hook.log"
9
+
10
+ export OPENCLAW_PLUGIN_ROOT="${OPENCLAW_PLUGIN_ROOT:-${PLUGIN_ROOT}}"
11
+ export BABYSITTER_STATE_DIR="${STATE_DIR}"
12
+
13
+ mkdir -p "$LOG_DIR" 2>/dev/null
14
+
15
+ blog() {
16
+ local msg="$1"
17
+ local ts
18
+ ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
19
+ echo "[INFO] $ts $msg" >> "$LOG_FILE" 2>/dev/null
20
+ babysitter log --type hook --label "hook:stop" --message "$msg" --source shell-hook 2>/dev/null || true
21
+ }
22
+
23
+ blog "Hook script invoked"
24
+ blog "PLUGIN_ROOT=$PLUGIN_ROOT"
25
+ blog "STATE_DIR=$STATE_DIR"
26
+
27
+ INPUT_FILE=$(mktemp 2>/dev/null || echo "/tmp/openclaw-stop-hook-$$.json")
28
+ cat > "$INPUT_FILE"
29
+
30
+ blog "Hook input received ($(wc -c < "$INPUT_FILE") bytes)"
31
+
32
+ RESULT=$(babysitter hook:run \
33
+ --hook-type stop \
34
+ --harness openclaw \
35
+ --plugin-root "${OPENCLAW_PLUGIN_ROOT}" \
36
+ --state-dir "${BABYSITTER_STATE_DIR}" \
37
+ < "$INPUT_FILE" 2>"$LOG_DIR/babysitter-stop-hook-stderr.log")
38
+ EXIT_CODE=$?
39
+
40
+ blog "CLI exit code=$EXIT_CODE"
41
+
42
+ rm -f "$INPUT_FILE" 2>/dev/null
43
+ printf '%s\n' "$RESULT"
44
+ exit $EXIT_CODE
package/hooks.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "hooks": {
3
+ "SessionStart": [
4
+ {
5
+ "matcher": "*",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "./hooks/babysitter-session-start.sh"
10
+ }
11
+ ]
12
+ }
13
+ ],
14
+ "Stop": [
15
+ {
16
+ "matcher": "*",
17
+ "hooks": [
18
+ {
19
+ "type": "command",
20
+ "command": "./hooks/babysitter-stop-hook.sh"
21
+ }
22
+ ]
23
+ }
24
+ ]
25
+ }
26
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "babysitter",
3
+ "version": "0.1.0",
4
+ "description": "Babysitter orchestration plugin for OpenClaw — event-sourced workflows, multi-step process management, and human-in-the-loop approval",
5
+ "entrypoint": "extensions/index.ts",
6
+ "hooks": {
7
+ "session_start": "extensions/hooks/session-start.ts",
8
+ "session_end": "extensions/hooks/session-end.ts",
9
+ "before_prompt_build": "extensions/hooks/before-prompt-build.ts",
10
+ "agent_end": "extensions/hooks/agent-end.ts"
11
+ },
12
+ "capabilities": [
13
+ "orchestration",
14
+ "process-management",
15
+ "human-in-the-loop"
16
+ ]
17
+ }
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@a5c-ai/babysitter-openclaw",
3
+ "version": "0.1.1-staging.45beae68",
4
+ "type": "module",
5
+ "description": "Babysitter plugin for OpenClaw AI agent with programmatic hook integration, orchestration skills, and SDK-managed process-library bootstrapping",
6
+ "openclaw": {
7
+ "extensions": [
8
+ "./extensions"
9
+ ],
10
+ "compat": {
11
+ "minVersion": "0.1.0"
12
+ },
13
+ "build": {
14
+ "hooks": "extensions/index.ts"
15
+ }
16
+ },
17
+ "keywords": [
18
+ "babysitter",
19
+ "openclaw",
20
+ "orchestration",
21
+ "ai-agent",
22
+ "sdk-integration"
23
+ ],
24
+ "dependencies": {
25
+ "@a5c-ai/babysitter-sdk": "0.0.187-staging.45beae68"
26
+ },
27
+ "peerDependencies": {
28
+ "openclaw": "*"
29
+ },
30
+ "scripts": {
31
+ "postinstall": "node bin/install.cjs --global",
32
+ "preuninstall": "node bin/uninstall.cjs --global",
33
+ "test": "node --test test/integration.test.js",
34
+ "test:integration": "node --test test/integration.test.js",
35
+ "test:packaged-install": "node test/packaged-install.test.cjs",
36
+ "sync:commands": "node scripts/sync-command-docs.cjs",
37
+ "deploy": "npm publish --access public",
38
+ "deploy:staging": "npm publish --access public --tag staging"
39
+ },
40
+ "bin": {
41
+ "babysitter-openclaw": "bin/cli.cjs"
42
+ },
43
+ "files": [
44
+ "bin/",
45
+ "package.json",
46
+ "versions.json",
47
+ "plugin.json",
48
+ "openclaw.plugin.json",
49
+ "hooks/",
50
+ "hooks.json",
51
+ "extensions/",
52
+ "skills/",
53
+ "commands/",
54
+ "scripts/",
55
+ "README.md"
56
+ ],
57
+ "author": "a5c.ai",
58
+ "license": "MIT",
59
+ "publishConfig": {
60
+ "access": "public"
61
+ },
62
+ "repository": {
63
+ "type": "git",
64
+ "url": "https://github.com/a5c-ai/babysitter"
65
+ },
66
+ "homepage": "https://github.com/a5c-ai/babysitter/tree/main/plugins/babysitter-openclaw#readme"
67
+ }
package/plugin.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "babysitter",
3
+ "version": "4.0.156",
4
+ "description": "Orchestrate complex, multi-step workflows with event-sourced state management, hook-based extensibility, and human-in-the-loop approval",
5
+ "author": "a5c.ai",
6
+ "license": "MIT",
7
+ "hooks": "hooks.json",
8
+ "commands": "commands/",
9
+ "skills": "skills/",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/a5c-ai/babysitter"
13
+ },
14
+ "keywords": [
15
+ "orchestration",
16
+ "workflow",
17
+ "automation",
18
+ "event-sourced",
19
+ "hooks",
20
+ "TDD",
21
+ "quality-convergence",
22
+ "agent",
23
+ "LLM"
24
+ ]
25
+ }
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # setup.sh — Full setup script for babysitter-openclaw plugin
5
+ #
6
+ # Installs npm dependencies, verifies the babysitter SDK,
7
+ # creates necessary directories, and prints usage instructions.
8
+
9
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10
+ PLUGIN_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
11
+
12
+ GREEN='\033[0;32m'
13
+ YELLOW='\033[1;33m'
14
+ RED='\033[0;31m'
15
+ NC='\033[0m' # No Color
16
+
17
+ log() { echo -e "${GREEN}[babysitter]${NC} $1"; }
18
+ warn() { echo -e "${YELLOW}[babysitter] WARNING:${NC} $1"; }
19
+ error() { echo -e "${RED}[babysitter] ERROR:${NC} $1"; }
20
+
21
+ # ── Check Node.js ──────────────────────────────────────────────────────
22
+ log "Checking Node.js version..."
23
+ if ! command -v node &>/dev/null; then
24
+ error "Node.js is not installed. Please install Node.js >= 18."
25
+ exit 1
26
+ fi
27
+
28
+ NODE_MAJOR=$(node -e "console.log(process.versions.node.split('.')[0])")
29
+ if [ "$NODE_MAJOR" -lt 18 ]; then
30
+ error "Node.js v$(node -v) detected. babysitter-openclaw requires Node.js >= 18."
31
+ exit 1
32
+ fi
33
+ log "Node.js v$(node -v | tr -d 'v') — OK"
34
+
35
+ # ── Check OpenClaw ────────────────────────────────────────────────────
36
+ log "Checking for OpenClaw..."
37
+ if command -v openclaw &>/dev/null; then
38
+ OPENCLAW_VERSION=$(openclaw --version 2>/dev/null || echo "unknown")
39
+ log "OpenClaw ${OPENCLAW_VERSION} — OK"
40
+ else
41
+ warn "OpenClaw CLI not found in PATH. Install it or ensure it is on your PATH."
42
+ fi
43
+
44
+ # ── Install npm dependencies ──────────────────────────────────────────
45
+ log "Installing npm dependencies..."
46
+ cd "$PLUGIN_DIR"
47
+ if [ -f "package.json" ]; then
48
+ npm install --no-audit --no-fund 2>&1 || {
49
+ warn "npm install encountered issues, but continuing setup."
50
+ }
51
+ log "Dependencies installed."
52
+ else
53
+ warn "No package.json found in $PLUGIN_DIR — skipping npm install."
54
+ fi
55
+
56
+ # ── Verify babysitter SDK ─────────────────────────────────────────────
57
+ log "Checking for @a5c-ai/babysitter-sdk..."
58
+ SDK_CHECK=$(node -e "try { require('@a5c-ai/babysitter-sdk'); console.log('ok'); } catch(e) { console.log('missing'); }" 2>/dev/null)
59
+ if [ "$SDK_CHECK" = "ok" ]; then
60
+ log "@a5c-ai/babysitter-sdk — OK"
61
+ else
62
+ warn "@a5c-ai/babysitter-sdk not found. Install it with: npm install @a5c-ai/babysitter-sdk"
63
+ fi
64
+
65
+ # ── Ensure hook scripts are executable ───────────────────────────────
66
+ log "Setting hook script permissions..."
67
+ if [ -d "$PLUGIN_DIR/hooks" ]; then
68
+ chmod +x "$PLUGIN_DIR/hooks/"*.sh 2>/dev/null || true
69
+ log "Hook scripts are executable."
70
+ fi
71
+
72
+ # ── Create state directory ───────────────────────────────────────────
73
+ log "Creating state directory..."
74
+ STATE_DIR="${BABYSITTER_GLOBAL_STATE_DIR:-$HOME/.a5c}"
75
+ mkdir -p "$STATE_DIR"
76
+ log "State directory ready: $STATE_DIR"
77
+
78
+ # ── Print usage instructions ─────────────────────────────────────────
79
+ echo ""
80
+ echo "============================================"
81
+ echo " babysitter-openclaw plugin setup complete"
82
+ echo "============================================"
83
+ echo ""
84
+ echo "Install methods:"
85
+ echo ""
86
+ echo " PRIMARY (marketplace):"
87
+ echo " babysitter plugin:install babysitter"
88
+ echo ""
89
+ echo " SECONDARY (npm, for development):"
90
+ echo " npm install -g @a5c-ai/babysitter-openclaw"
91
+ echo " babysitter-openclaw install --global"
92
+ echo ""
93
+ echo " PROJECT-LOCAL:"
94
+ echo " babysitter-openclaw install --workspace ."
95
+ echo ""
96
+ echo "For more information, see: $PLUGIN_DIR/README.md"
97
+ echo ""
98
+
99
+ log "Done."
@@ -0,0 +1,106 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const {
5
+ listMarkdownBasenames,
6
+ reportCheckResult,
7
+ syncCommandMirrors,
8
+ syncSkillsFromCommands,
9
+ writeFileIfChanged,
10
+ } = require('../../../scripts/plugin-command-sync-lib.cjs');
11
+
12
+ const PACKAGE_ROOT = path.resolve(__dirname, '..');
13
+ const REPO_ROOT = path.resolve(PACKAGE_ROOT, '..', '..');
14
+ const ROOT_COMMANDS = path.join(REPO_ROOT, 'plugins', 'babysitter', 'commands');
15
+ const COMMANDS_ROOT = path.join(PACKAGE_ROOT, 'commands');
16
+ const SKILLS_ROOT = path.join(PACKAGE_ROOT, 'skills');
17
+ const LABEL = 'babysitter-openclaw sync';
18
+
19
+ const BABYSIT_SKILL = `---
20
+ name: babysit
21
+ description: Orchestrate via @babysitter. Use this skill when asked to babysit a run, orchestrate a process or whenever it is called explicitly. (babysit, babysitter, orchestrate, orchestrate a run, workflow, etc.)
22
+ ---
23
+
24
+ # babysit
25
+
26
+ Orchestrate \`.a5c/runs/<runId>/\` through iterative execution.
27
+
28
+ ## Dependencies
29
+
30
+ ### Babysitter SDK and CLI
31
+
32
+ Read the SDK version from \`versions.json\` to ensure version compatibility:
33
+
34
+ \`\`\`bash
35
+ PLUGIN_ROOT="\${OPENCLAW_PLUGIN_ROOT:-\$(pwd)}"
36
+ SDK_VERSION=$(node -e "try{const fs=require('fs');const path=require('path');const pluginRoot=process.env.OPENCLAW_PLUGIN_ROOT||process.env.PLUGIN_ROOT||process.cwd();const probes=[path.join(pluginRoot,'versions.json'),path.join(pluginRoot,'plugins','babysitter-openclaw','versions.json'),path.join(pluginRoot,'node_modules','@a5c-ai','babysitter-openclaw','versions.json'),path.join(process.cwd(),'node_modules','@a5c-ai','babysitter-openclaw','versions.json')];for(const probe of probes){if(fs.existsSync(probe)){console.log(JSON.parse(fs.readFileSync(probe,'utf8')).sdkVersion||'latest');process.exit(0)}}console.log('latest')}catch{console.log('latest')}")
37
+ CLI="npx -y @a5c-ai/babysitter-sdk@$SDK_VERSION"
38
+ \`\`\`
39
+
40
+ ## Instructions
41
+
42
+ Run the following command to get full orchestration instructions:
43
+
44
+ \`\`\`bash
45
+ babysitter instructions:babysit-skill --harness openclaw --interactive
46
+ \`\`\`
47
+
48
+ For non-interactive mode:
49
+
50
+ \`\`\`bash
51
+ babysitter instructions:babysit-skill --harness openclaw --no-interactive
52
+ \`\`\`
53
+
54
+ Follow the instructions returned by the command above to orchestrate the run.
55
+ `;
56
+
57
+ function getCommandNames() {
58
+ return listMarkdownBasenames(ROOT_COMMANDS);
59
+ }
60
+
61
+ function main() {
62
+ const check = process.argv.includes('--check');
63
+ const commandNames = getCommandNames();
64
+ const mirrorResult = syncCommandMirrors({
65
+ label: LABEL,
66
+ sourceRoot: ROOT_COMMANDS,
67
+ targetRoot: COMMANDS_ROOT,
68
+ names: commandNames,
69
+ check,
70
+ cwd: PACKAGE_ROOT,
71
+ });
72
+ const skillsResult = syncSkillsFromCommands({
73
+ label: LABEL,
74
+ sourceRoot: COMMANDS_ROOT,
75
+ skillsRoot: SKILLS_ROOT,
76
+ names: commandNames,
77
+ check,
78
+ cwd: PACKAGE_ROOT,
79
+ });
80
+
81
+ const babysitSkillPath = path.join(SKILLS_ROOT, 'babysit', 'SKILL.md');
82
+ if (check) {
83
+ const fs = require('fs');
84
+ const stale = [...mirrorResult.stale, ...skillsResult.stale];
85
+ const current = fs.existsSync(babysitSkillPath)
86
+ ? fs.readFileSync(babysitSkillPath, 'utf8')
87
+ : null;
88
+ if (current !== BABYSIT_SKILL) {
89
+ stale.push(path.relative(PACKAGE_ROOT, babysitSkillPath));
90
+ }
91
+ reportCheckResult(LABEL, stale);
92
+ return;
93
+ }
94
+
95
+ const babysitUpdated = writeFileIfChanged(babysitSkillPath, BABYSIT_SKILL) ? 1 : 0;
96
+ const updated = mirrorResult.updated + skillsResult.updated + babysitUpdated;
97
+
98
+ if (updated === 0) {
99
+ console.log(`[${LABEL}] no openclaw command or skill changes were needed.`);
100
+ return;
101
+ }
102
+
103
+ console.log(`[${LABEL}] updated ${updated} openclaw command/skill file(s).`);
104
+ }
105
+
106
+ main();