@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.
- package/README.md +312 -0
- package/bin/cli.cjs +80 -0
- package/bin/install.cjs +370 -0
- package/bin/uninstall.cjs +172 -0
- package/commands/assimilate.md +37 -0
- package/commands/babysit.md +7 -0
- package/commands/call.md +7 -0
- package/commands/cleanup.md +20 -0
- package/commands/contrib.md +33 -0
- package/commands/doctor.md +426 -0
- package/commands/forever.md +7 -0
- package/commands/help.md +244 -0
- package/commands/observe.md +12 -0
- package/commands/plan.md +7 -0
- package/commands/plugins.md +255 -0
- package/commands/project-install.md +17 -0
- package/commands/resume.md +8 -0
- package/commands/retrospect.md +55 -0
- package/commands/user-install.md +17 -0
- package/commands/yolo.md +7 -0
- package/extensions/hooks/agent-end.ts +127 -0
- package/extensions/hooks/before-prompt-build.ts +98 -0
- package/extensions/hooks/session-end.ts +80 -0
- package/extensions/hooks/session-start.ts +81 -0
- package/extensions/index.ts +67 -0
- package/hooks/babysitter-session-start.sh +61 -0
- package/hooks/babysitter-stop-hook.sh +44 -0
- package/hooks.json +26 -0
- package/openclaw.plugin.json +17 -0
- package/package.json +67 -0
- package/plugin.json +25 -0
- package/scripts/setup.sh +99 -0
- package/scripts/sync-command-docs.cjs +106 -0
- package/skills/assimilate/SKILL.md +38 -0
- package/skills/babysit/SKILL.md +36 -0
- package/skills/call/SKILL.md +8 -0
- package/skills/cleanup/SKILL.md +21 -0
- package/skills/contrib/SKILL.md +34 -0
- package/skills/doctor/SKILL.md +427 -0
- package/skills/forever/SKILL.md +8 -0
- package/skills/help/SKILL.md +245 -0
- package/skills/observe/SKILL.md +13 -0
- package/skills/plan/SKILL.md +8 -0
- package/skills/plugins/SKILL.md +257 -0
- package/skills/project-install/SKILL.md +18 -0
- package/skills/resume/SKILL.md +9 -0
- package/skills/retrospect/SKILL.md +56 -0
- package/skills/user-install/SKILL.md +18 -0
- package/skills/yolo/SKILL.md +8 -0
- 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
|
+
}
|
package/scripts/setup.sh
ADDED
|
@@ -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();
|