feat(n8n-webhook): expand action bus starter workflow
This commit is contained in:
@@ -4,7 +4,13 @@ set -euo pipefail
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
scripts/call-action.sh <action> [--args '{"k":"v"}'] [--args-file args.json] [--request-id <id|auto>] [--path openclaw-action] [--test] [--pretty] [--dry-run]
|
||||
scripts/call-action.sh [action] [--args '{"k":"v"}'] [--args-file args.json] [--request-id <id|auto>] [--path openclaw-action] [--test] [--pretty] [--dry-run]
|
||||
|
||||
Notes:
|
||||
- `action` is optional when --args/--args-file contains a full payload with top-level `action` + `args`.
|
||||
- `--args` / `--args-file` may contain either:
|
||||
1) a plain args object, or
|
||||
2) a full payload object: {"action":"...","args":{...},"request_id":"..."}
|
||||
|
||||
Environment:
|
||||
N8N_ACTION_PATH Default router webhook path (default: openclaw-action)
|
||||
@@ -14,6 +20,7 @@ Environment:
|
||||
|
||||
Examples:
|
||||
scripts/call-action.sh append_log --args '{"text":"backup complete"}' --request-id auto
|
||||
scripts/call-action.sh --args-file assets/test-send-email-draft.json --pretty
|
||||
scripts/call-action.sh notify --args-file notify.json --test --pretty
|
||||
EOF
|
||||
}
|
||||
@@ -84,11 +91,6 @@ while [[ $# -gt 0 ]]; do
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$ACTION" ]]; then
|
||||
usage >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [[ ${#EXTRA_ARGS[@]} -gt 0 ]]; then
|
||||
echo "Unexpected extra arguments: ${EXTRA_ARGS[*]}" >&2
|
||||
exit 2
|
||||
@@ -110,13 +112,32 @@ PAYLOAD="$({
|
||||
python3 - <<'PY' "$ACTION" "$ARGS" "$REQUEST_ID"
|
||||
import json, sys
|
||||
|
||||
action = sys.argv[1]
|
||||
args = json.loads(sys.argv[2])
|
||||
request_id = sys.argv[3]
|
||||
cli_action = sys.argv[1]
|
||||
raw = json.loads(sys.argv[2])
|
||||
cli_request_id = sys.argv[3]
|
||||
|
||||
if not isinstance(args, dict):
|
||||
if not isinstance(raw, dict):
|
||||
raise SystemExit('Action args must decode to a JSON object.')
|
||||
|
||||
if 'action' in raw and 'args' in raw:
|
||||
file_action = raw.get('action', '')
|
||||
file_args = raw.get('args', {})
|
||||
file_request_id = raw.get('request_id', '')
|
||||
if not isinstance(file_args, dict):
|
||||
raise SystemExit('Full payload args must decode to a JSON object.')
|
||||
if cli_action and file_action and cli_action != file_action:
|
||||
raise SystemExit(f'CLI action {cli_action!r} does not match payload action {file_action!r}.')
|
||||
action = cli_action or file_action
|
||||
args = file_args
|
||||
request_id = cli_request_id or file_request_id
|
||||
else:
|
||||
action = cli_action
|
||||
args = raw
|
||||
request_id = cli_request_id
|
||||
|
||||
if not action:
|
||||
raise SystemExit('Action is required unless provided inside --args/--args-file full payload.')
|
||||
|
||||
payload = {
|
||||
'action': action,
|
||||
'args': args,
|
||||
|
||||
@@ -21,6 +21,38 @@ EXPECTED_TYPES = {
|
||||
'Respond to Webhook': 'n8n-nodes-base.respondToWebhook',
|
||||
}
|
||||
|
||||
SAMPLE_FILES = [
|
||||
'test-append-log.json',
|
||||
'test-notify.json',
|
||||
'test-send-email-draft.json',
|
||||
'test-create-calendar-event.json',
|
||||
'test-fetch-and-normalize-url.json',
|
||||
'test-approval-queue-list.json',
|
||||
'test-inbound-event-filter.json',
|
||||
]
|
||||
|
||||
ROUTER_SNIPPETS = [
|
||||
'append_log',
|
||||
'get_logs',
|
||||
'notify',
|
||||
'send_email_draft',
|
||||
'create_calendar_event',
|
||||
'approval_queue_add',
|
||||
'approval_queue_list',
|
||||
'approval_queue_resolve',
|
||||
'fetch_and_normalize_url',
|
||||
'inbound_event_filter',
|
||||
'unknown_action',
|
||||
'invalid_request',
|
||||
'$getWorkflowStaticData',
|
||||
'approvalQueue',
|
||||
'approvalHistory',
|
||||
'inboundEvents',
|
||||
'eventDedup',
|
||||
'notify_text',
|
||||
'fetch(',
|
||||
]
|
||||
|
||||
|
||||
def fail(msg: str):
|
||||
print(f'ERROR: {msg}', file=sys.stderr)
|
||||
@@ -72,7 +104,7 @@ def main():
|
||||
|
||||
router = by_name['route-action'].get('parameters', {})
|
||||
js_code = router.get('jsCode', '')
|
||||
for snippet in ('append_log', 'get_logs', 'notify', 'unknown_action', 'invalid_request', '$getWorkflowStaticData', 'actionLog', 'retained_entries', 'notify_text', 'entries.length', 'Math.min(50'):
|
||||
for snippet in ROUTER_SNIPPETS:
|
||||
if snippet not in js_code:
|
||||
fail(f'route-action jsCode missing expected snippet: {snippet!r}')
|
||||
|
||||
@@ -94,7 +126,8 @@ def main():
|
||||
if responder.get('respondWith') != 'json':
|
||||
fail('Respond to Webhook must respondWith json')
|
||||
|
||||
for sample in (path.parent / 'test-append-log.json', path.parent / 'test-notify.json'):
|
||||
for sample_name in SAMPLE_FILES:
|
||||
sample = path.parent / sample_name
|
||||
sample_data = load_json(sample)
|
||||
if not isinstance(sample_data, dict) or 'action' not in sample_data or 'args' not in sample_data:
|
||||
fail(f'sample payload missing action/args: {sample}')
|
||||
@@ -102,8 +135,8 @@ def main():
|
||||
print('OK: workflow asset structure looks consistent')
|
||||
print(f'- workflow: {path}')
|
||||
print(f'- nodes: {len(nodes)}')
|
||||
print('- routes: append_log + get_logs via workflow static data, notify via Telegram + Discord, fallback -> JSON error')
|
||||
print('- samples: test-append-log.json, test-notify.json')
|
||||
print('- routes: notify via Telegram + Discord; queue/log/fetch/filter handled in route-action code')
|
||||
print('- samples: ' + ', '.join(SAMPLE_FILES))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
Reference in New Issue
Block a user