garc-gws-agent-runtime/lib/approve.sh
林 駿甫 (Shunsuke Hayashi) a69b9d9160 feat: initial release — GARC v0.1.0
Permission-first AI agent runtime for Google Workspace.
Ports the LARC/OpenClaw governance model (disclosure chain,
execution gates, queue/ingress) to Gmail, Calendar, Drive,
Sheets, Tasks, and People APIs with Claude Code as the
execution engine.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 08:59:12 +09:00

156 lines
4.4 KiB
Bash

#!/usr/bin/env bash
# GARC approve.sh — Execution gate and approval flow
# Uses Google Sheets as the approval tracking backend
GATE_POLICY="${GARC_DIR}/config/gate-policy.json"
garc_approve() {
local subcommand="${1:-help}"
shift || true
case "${subcommand}" in
gate) garc_approve_gate "$@" ;;
list) garc_approve_list "$@" ;;
create) garc_approve_create "$@" ;;
act) garc_approve_act "$@" ;;
*)
echo "Usage: garc approve <gate|list|create|act>"
return 1
;;
esac
}
# garc approve gate <task_type>
# Check the execution gate policy for a task type
garc_approve_gate() {
local task_type="${1:-}"
if [[ -z "${task_type}" ]]; then
echo "Usage: garc approve gate <task_type>"
echo ""
echo "Available task types:"
python3 -c "
import json, sys
with open('${GATE_POLICY}') as f:
policy = json.load(f)
for gate, data in policy['gates'].items():
print(f' [{gate.upper()}] {data[\"description\"]}')
for t in data['tasks']:
print(f' - {t}')
"
return 0
fi
python3 -c "
import json, sys
with open('${GATE_POLICY}') as f:
policy = json.load(f)
task = '${task_type}'
for gate_name, gate_data in policy['gates'].items():
if task in gate_data['tasks']:
icons = {'none': '✅', 'preview': '⚠️', 'approval': '🔒'}
icon = icons.get(gate_name, '❓')
print(f'{icon} Gate: {gate_name.upper()}')
print(f' {gate_data[\"description\"]}')
if gate_name == 'none':
print(f' Action: Execute immediately')
elif gate_name == 'preview':
print(f' Action: Add --confirm flag or get user acknowledgment')
else:
print(f' Action: Create approval request with: garc approve create \"{task}\"')
sys.exit(0)
print(f'Task type \"{task}\" not found in gate policy')
sys.exit(1)
"
}
# garc approve list
# List pending approval items from Google Sheets
garc_approve_list() {
local sheets_id="${GARC_SHEETS_ID:-}"
if [[ -z "${sheets_id}" ]]; then
echo "Error: GARC_SHEETS_ID not set" >&2
return 1
fi
python3 "${GARC_DIR}/scripts/garc-sheets-helper.py" approval-list \
--sheets-id "${sheets_id}"
}
# garc approve create "<task>"
# Create an approval request in Google Sheets (and optionally send Gmail)
garc_approve_create() {
local task_description="$*"
if [[ -z "${task_description}" ]]; then
echo "Usage: garc approve create \"<task description>\""
return 1
fi
local sheets_id="${GARC_SHEETS_ID:-}"
if [[ -z "${sheets_id}" ]]; then
echo "Error: GARC_SHEETS_ID not set" >&2
return 1
fi
local approval_id
approval_id="approval-$(date +%Y%m%d%H%M%S)-$$"
echo "Creating approval request..."
echo " ID: ${approval_id}"
echo " Task: ${task_description}"
python3 "${GARC_DIR}/scripts/garc-sheets-helper.py" approval-create \
--sheets-id "${sheets_id}" \
--approval-id "${approval_id}" \
--task "${task_description}" \
--agent-id "${GARC_DEFAULT_AGENT:-main}" \
--timestamp "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
# Optionally notify via Gmail
if [[ -n "${GARC_GMAIL_DEFAULT_TO:-}" ]]; then
python3 "${GARC_DIR}/scripts/garc-gmail-helper.py" send \
--to "${GARC_GMAIL_DEFAULT_TO}" \
--subject "[GARC Approval Required] ${task_description}" \
--body "Approval Request ID: ${approval_id}
Task: ${task_description}
Agent: ${GARC_DEFAULT_AGENT:-main}
Time: $(date -u +"%Y-%m-%dT%H:%M:%SZ")
To approve: garc approve act ${approval_id} --action approve
To reject: garc approve act ${approval_id} --action reject" 2>/dev/null || true
fi
echo "✅ Approval request created: ${approval_id}"
echo " Waiting for human approval..."
}
# garc approve act <id> --action <approve|reject>
garc_approve_act() {
local approval_id="${1:-}"
local action=""
shift || true
while [[ $# -gt 0 ]]; do
case "$1" in
--action) action="$2"; shift 2 ;;
approve|reject) action="$1"; shift ;;
*) shift ;;
esac
done
if [[ -z "${approval_id}" ]] || [[ -z "${action}" ]]; then
echo "Usage: garc approve act <id> --action <approve|reject>"
return 1
fi
python3 "${GARC_DIR}/scripts/garc-sheets-helper.py" approval-act \
--sheets-id "${GARC_SHEETS_ID:-}" \
--approval-id "${approval_id}" \
--action "${action}" \
--timestamp "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
echo "✅ Approval ${approval_id} marked as: ${action}"
}