Compare commits
11 Commits
4d98d83fbb
...
fc720ac05a
| Author | SHA1 | Date | |
|---|---|---|---|
| fc720ac05a | |||
| 7f2ca44ef6 | |||
| db89b9e88e | |||
| f20bfeea80 | |||
| 87c98b26b8 | |||
| f6b13246d8 | |||
| 2e9be8375c | |||
| 8f3055be62 | |||
| cd88440361 | |||
| f73fd68e49 | |||
| 1d8427422a |
@@ -25,10 +25,10 @@ fi
|
||||
|
||||
REPO_NAME="$1"
|
||||
|
||||
# Validate repo name (alphanumeric, hyphens, underscores only)
|
||||
if ! [[ "$REPO_NAME" =~ ^[a-zA-Z0-9_-]+$ ]]; then
|
||||
# Validate repo name (alphanumeric, hyphens, underscores, dots)
|
||||
if ! [[ "$REPO_NAME" =~ ^[a-zA-Z0-9_.-]+$ ]]; then
|
||||
echo "Error: Invalid repository name '$REPO_NAME'"
|
||||
echo "Only alphanumeric characters, hyphens, and underscores are allowed."
|
||||
echo "Only alphanumeric characters, hyphens, underscores, and dots are allowed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
67
git-hangman-lab/scripts/publish-package
Executable file
67
git-hangman-lab/scripts/publish-package
Executable file
@@ -0,0 +1,67 @@
|
||||
#!/bin/bash
|
||||
# publish-package - Publish packages to various registries
|
||||
# Usage:
|
||||
# publish-package docker <registry> <image> <tag> --proj <repo>
|
||||
# publish-package nuget <source> <package-file> --proj <repo>
|
||||
# publish-package pypi <package-file> --proj <repo>
|
||||
# publish-package npm --proj <repo>
|
||||
|
||||
set -e
|
||||
|
||||
COMMAND=""
|
||||
REGISTRY=""
|
||||
IMAGE=""
|
||||
TAG=""
|
||||
SOURCE=""
|
||||
PACKAGE_FILE=""
|
||||
REPO=""
|
||||
|
||||
usage() {
|
||||
echo "Usage:"
|
||||
echo " publish-package docker <registry> <image> <tag> --proj <repo>"
|
||||
echo " publish-package nuget <source> <package-file> --proj <repo>"
|
||||
echo " publish-package pypi <package-file> --proj <repo>"
|
||||
echo " publish-package npm --proj <repo>"
|
||||
exit 1
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
docker|nuget|pypi|npm)
|
||||
COMMAND="$1"
|
||||
shift
|
||||
;;
|
||||
--proj)
|
||||
REPO="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
if [[ -z "$COMMAND" ]]; then
|
||||
usage
|
||||
fi
|
||||
case $COMMAND in
|
||||
docker)
|
||||
[[ -z "$REGISTRY" ]] && REGISTRY="$1" && shift && continue
|
||||
[[ -z "$IMAGE" ]] && IMAGE="$1" && shift && continue
|
||||
[[ -z "$TAG" ]] && TAG="$1" && shift && continue
|
||||
;;
|
||||
nuget)
|
||||
[[ -z "$SOURCE" ]] && SOURCE="$1" && shift && continue
|
||||
[[ -z "$PACKAGE_FILE" ]] && PACKAGE_FILE="$1" && shift && continue
|
||||
;;
|
||||
pypi)
|
||||
[[ -z "$PACKAGE_FILE" ]] && PACKAGE_FILE="$1" && shift && continue
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$COMMAND" ]] || [[ -z "$REPO" ]]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
# TODO: implement publish logic
|
||||
echo "publish-package: $COMMAND not yet implemented"
|
||||
exit 1
|
||||
72
recruitment/SKILL.md
Normal file
72
recruitment/SKILL.md
Normal file
@@ -0,0 +1,72 @@
|
||||
---
|
||||
name: recruitment
|
||||
description: Onboard new agents into OpenClaw. Use when creating a new agent, adding an agent to the system, or setting up a new agent workspace. Triggers on requests like "new agent", "add agent", "create agent", "recruit agent", "onboard agent".
|
||||
---
|
||||
|
||||
# Recruitment Skill
|
||||
|
||||
Onboard new agents into OpenClaw with binding configuration.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
new-agent --type openclaw --agent-id <agent-id> [--model <primary-model>]
|
||||
|
||||
new-agent --type contractor --contractor-provider <claude|gemini> --agent-id <agent-id>
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
When a request to create a new agent is received, follow this workflow:
|
||||
|
||||
### Step 1 — Gather Requirements
|
||||
|
||||
Communicate with the requester to collect the following:
|
||||
- New agent's `agent-id`
|
||||
- New agent's primary model (`--model`)
|
||||
- New agent's role and position
|
||||
- Whether the agent is a contractor agent (default: not a contractor)
|
||||
|
||||
### Step 2 — Create Agent
|
||||
|
||||
Execute `{baseDir}/scripts/new-agent` with the gathered parameters:
|
||||
```bash
|
||||
# openclaw type
|
||||
new-agent --type openclaw --agent-id <agent-id> --model <primary-model>
|
||||
|
||||
# contractor type
|
||||
new-agent --type contractor --contractor-provider <claude|gemini> --agent-id <agent-id>
|
||||
```
|
||||
|
||||
### Step 3 — Interview
|
||||
|
||||
Use the `create-discussion-channel` tool to start an interview with the new agent:
|
||||
- Participant: `interviewee`
|
||||
- Discussion guide: "<@YOUR_DISCORD_USER_ID> please refer to {baseDir}/workflow/interview.md"
|
||||
|
||||
> Note: Replace `YOUR_DISCORD_USER_ID` with your actual Discord user ID. If unsure, use `ego-mgr get discord-id` (via pcexec) to look it up.
|
||||
|
||||
After receiving the discussion callback, review the discussion summary:
|
||||
- If it contains the agent's **name** and **gender** → proceed to Step 4
|
||||
- If either field is missing → attempt to gather the missing information via another `create-discussion-channel` call
|
||||
- If still unavailable → notify the requester and proceed without it
|
||||
|
||||
### Step 4 — Onboard
|
||||
|
||||
Use `proxy-pcexec` to call `{baseDir}/scripts/onboard`:
|
||||
- `proxy-for`: new agent's `agent-id`
|
||||
- Parameters: `--name`, `--role`, `--position`, `--gender`, `--bot-token`
|
||||
|
||||
### Step 5 — Report
|
||||
|
||||
Notify the requester that onboarding is complete.
|
||||
|
||||
## Scripts
|
||||
|
||||
### new-agent
|
||||
|
||||
Creates and registers the agent, then configures the `interviewee` Discord account binding.
|
||||
|
||||
### onboard
|
||||
|
||||
Sets up ego-mgr identity fields and configures the agent's Discord account using the name/gender collected during interview.
|
||||
122
recruitment/scripts/new-agent
Executable file
122
recruitment/scripts/new-agent
Executable file
@@ -0,0 +1,122 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
TYPE=""
|
||||
AGENT_ID=""
|
||||
MODEL=""
|
||||
CONTRACTOR_PROVIDER=""
|
||||
|
||||
usage() {
|
||||
echo "Usage: new-agent --type <openclaw|contractor> --agent-id <agent-id> [--model <primary-model>] [--contractor-provider <claude|gemini>]"
|
||||
exit 1
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--type)
|
||||
TYPE="$2"
|
||||
shift 2
|
||||
;;
|
||||
--agent-id)
|
||||
AGENT_ID="$2"
|
||||
shift 2
|
||||
;;
|
||||
--model)
|
||||
MODEL="$2"
|
||||
shift 2
|
||||
;;
|
||||
--contractor-provider)
|
||||
CONTRACTOR_PROVIDER="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$TYPE" ]] || [[ -z "$AGENT_ID" ]]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
WORKSPACE_DIR="$HOME/.openclaw/workspace/workspace-$AGENT_ID"
|
||||
STATE_DIR="$HOME/.openclaw/states"
|
||||
BINDINGS_LOCK="$STATE_DIR/bindings.lock"
|
||||
|
||||
# Step 1: Register agent
|
||||
if [[ "$TYPE" == "openclaw" ]]; then
|
||||
MODEL_ARG=""
|
||||
if [[ -n "$MODEL" ]]; then
|
||||
MODEL_ARG="--model $MODEL"
|
||||
fi
|
||||
openclaw agents add "$AGENT_ID" $MODEL_ARG --workspace "$WORKSPACE_DIR" --non-interactive
|
||||
elif [[ "$TYPE" == "contractor" ]]; then
|
||||
# Check contractor-agent plugin
|
||||
if ! openclaw plugins list 2>/dev/null | grep -q "contractor-agent"; then
|
||||
echo "Error: contractor-agent plugin is not installed" >&2
|
||||
exit 1
|
||||
fi
|
||||
openclaw contractor-agents add --agent-id "$AGENT_ID" --workspace "$WORKSPACE_DIR" --contractor "$CONTRACTOR_PROVIDER"
|
||||
else
|
||||
echo "Error: unknown type '$TYPE'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Step 2: Wait for bindings
|
||||
echo "Checking bindings..."
|
||||
|
||||
wait_for_bindings() {
|
||||
local bindings
|
||||
bindings=$(openclaw config get bindings 2>/dev/null || echo "{}")
|
||||
if echo "$bindings" | grep -q '"interviewee"'; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
wait_for_lock() {
|
||||
if [[ -f "$BINDINGS_LOCK" ]]; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
while wait_for_bindings; do
|
||||
echo "another interview is ongoing, waiting..."
|
||||
sleep 10
|
||||
done
|
||||
|
||||
while wait_for_lock; do
|
||||
echo "bindings locked, waiting..."
|
||||
sleep 10
|
||||
done
|
||||
|
||||
# Step 3: Set bindings
|
||||
mkdir -p "$STATE_DIR"
|
||||
touch "$BINDINGS_LOCK"
|
||||
|
||||
CURRENT_BINDINGS=$(openclaw config get bindings 2>/dev/null || echo "{}")
|
||||
|
||||
NEW_ENTRY="{\"agentId\": \"$AGENT_ID\", \"match\": {\"channel\": \"discord\", \"accountId\": \"interviewee\"}}"
|
||||
|
||||
if [[ "$CURRENT_BINDINGS" == "{}" ]] || [[ -z "$CURRENT_BINDINGS" ]]; then
|
||||
NEW_BINDINGS="[$NEW_ENTRY]"
|
||||
else
|
||||
NEW_BINDINGS=$(echo "$CURRENT_BINDINGS" | sed 's/\(\[.*\)\]/\1,/' | sed 's/\]$//' | sed 's/\([{,]\)$/\1/')" $NEW_ENTRY]"
|
||||
fi
|
||||
|
||||
openclaw config set bindings "$NEW_BINDINGS"
|
||||
|
||||
rm -f "$BINDINGS_LOCK"
|
||||
|
||||
# Step 4: Configure interviewee account
|
||||
TOKEN=$(secret-mgr get-secret --key interviewee-discord-token --public 2>/dev/null || echo "")
|
||||
|
||||
if [[ -z "$TOKEN" ]]; then
|
||||
echo "Error: failed to get interviewee-discord-token from secret-mgr" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
openclaw config set channels.discord.accounts.interviewee "{\"enabled\": true, \"token\": \"$TOKEN\", \"groupPolicy\": \"open\", \"streaming\": {\"mode\": \"off\"}}"
|
||||
|
||||
echo "Agent $AGENT_ID recruited successfully."
|
||||
130
recruitment/scripts/onboard
Executable file
130
recruitment/scripts/onboard
Executable file
@@ -0,0 +1,130 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
NAME=""
|
||||
ROLE=""
|
||||
POSITION=""
|
||||
GENDER=""
|
||||
BOT_TOKEN=""
|
||||
|
||||
usage() {
|
||||
echo "Usage: onboard --name <name> --role <role> --position <position> --gender <gender> --bot-token <token>"
|
||||
exit 1
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--name)
|
||||
NAME="$2"
|
||||
shift 2
|
||||
;;
|
||||
--role)
|
||||
ROLE="$2"
|
||||
shift 2
|
||||
;;
|
||||
--position)
|
||||
POSITION="$2"
|
||||
shift 2
|
||||
;;
|
||||
--gender)
|
||||
GENDER="$2"
|
||||
shift 2
|
||||
;;
|
||||
--bot-token)
|
||||
BOT_TOKEN="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$NAME" ]] || [[ -z "$ROLE" ]] || [[ -z "$POSITION" ]] || [[ -z "$GENDER" ]] || [[ -z "$BOT_TOKEN" ]]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
if [[ "$PCEXEC_PROXIED" != "true" ]]; then
|
||||
echo "Error: this script must be executed with tool proxy-pcexec" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TODAY=$(date +%Y-%m-%d)
|
||||
|
||||
# Resolve discord-id from bot token
|
||||
DISCORD_ID=$(curl -s "https://discord.com/api/v10/users/@me" \
|
||||
-H "Authorization: Bot $BOT_TOKEN" \
|
||||
-H "Content-Type: application/json" | \
|
||||
python3 -c "import sys,json; print(json.load(sys.stdin).get('id', ''))" 2>/dev/null)
|
||||
|
||||
if [[ -z "$DISCORD_ID" ]]; then
|
||||
echo "Error: failed to resolve discord-id from bot token" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
AGENT_ID="agent-$NAME"
|
||||
|
||||
ego-mgr set name "$NAME"
|
||||
ego-mgr set default-username "$NAME"
|
||||
ego-mgr set discord-id "$DISCORD_ID"
|
||||
ego-mgr set role "$ROLE"
|
||||
ego-mgr set position "$POSITION"
|
||||
ego-mgr set gender "$GENDER"
|
||||
ego-mgr set email "${NAME}@${ROLE}.hangman-lab.top"
|
||||
ego-mgr set agent-id "$AGENT_ID"
|
||||
ego-mgr set date-of-birth "$TODAY"
|
||||
|
||||
BINDINGS_LOCK="$HOME/.openclaw/states/bindings.lock"
|
||||
STATE_DIR="$HOME/.openclaw/states"
|
||||
|
||||
# Wait for bindings.lock to disappear
|
||||
while [[ -f "$BINDINGS_LOCK" ]]; do
|
||||
echo "bindings locked, waiting..."
|
||||
sleep 10
|
||||
done
|
||||
|
||||
# Create bindings.lock and update bindings
|
||||
mkdir -p "$STATE_DIR"
|
||||
touch "$BINDINGS_LOCK"
|
||||
|
||||
CURRENT_BINDINGS=$(openclaw config get bindings 2>/dev/null || echo "[]")
|
||||
|
||||
# Replace accountId "interviewee" -> "{name}" for this agent
|
||||
UPDATED_BINDINGS=$(echo "$CURRENT_BINDINGS" | python3 -c "
|
||||
import sys, json
|
||||
bindings = json.load(sys.stdin)
|
||||
for b in bindings:
|
||||
if b.get('agentId') == '$AGENT_ID' and b.get('match', {}).get('accountId') == 'interviewee':
|
||||
b['match']['accountId'] = '$NAME'
|
||||
print(json.dumps(bindings))
|
||||
" 2>/dev/null)
|
||||
|
||||
openclaw config set bindings "$UPDATED_BINDINGS"
|
||||
|
||||
rm -f "$BINDINGS_LOCK"
|
||||
|
||||
# Configure discord account for {name}
|
||||
openclaw config set channels.discord.accounts."$NAME".enabled true
|
||||
openclaw config set channels.discord.accounts."$NAME".commands.native true
|
||||
openclaw config set channels.discord.accounts."$NAME".commands.nativeSkills true
|
||||
openclaw config set channels.discord.accounts."$NAME".token "$BOT_TOKEN"
|
||||
openclaw config set channels.discord.accounts."$NAME".allowBots true
|
||||
openclaw config set channels.discord.accounts."$NAME".groupPolicy "open"
|
||||
openclaw config set channels.discord.accounts."$NAME".streaming.mode "off"
|
||||
openclaw config set channels.discord.accounts."$NAME".actions.messages true
|
||||
openclaw config set channels.discord.accounts."$NAME".actions.search true
|
||||
openclaw config set channels.discord.accounts."$NAME".actions.roles true
|
||||
openclaw config set channels.discord.accounts."$NAME".actions.channelInfo true
|
||||
openclaw config set channels.discord.accounts."$NAME".actions.events true
|
||||
openclaw config set channels.discord.accounts."$NAME".actions.channels true
|
||||
openclaw config set channels.discord.accounts."$NAME".dmPolicy "open"
|
||||
openclaw config set channels.discord.accounts."$NAME".allowFrom '["*"]'
|
||||
openclaw config set channels.discord.accounts."$NAME".dm.enabled true
|
||||
openclaw config set channels.discord.accounts."$NAME".execApprovals.enabled false
|
||||
openclaw config set channels.discord.accounts."$NAME".execApprovals.approvers '["*"]'
|
||||
|
||||
~/.openclaw/skills/keycloak-hangman-lab/scripts/create-keycloak-account
|
||||
~/.openclaw/skills/git-hangman-lab/scripts/create-git-account
|
||||
~/.openclaw/skills/git-hangman-lab/scripts/link-keycloak
|
||||
|
||||
echo "Onboarding complete for $NAME."
|
||||
0
recruitment/workflows/interviewer.md
Normal file
0
recruitment/workflows/interviewer.md
Normal file
Reference in New Issue
Block a user