Files
training-system/membership/.claude/skills/tgassist/scripts/init_workspace.sh
2026-05-12 12:24:11 +08:00

159 lines
5.3 KiB
Bash

#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'USAGE'
Usage:
init_workspace.sh --name NAME [options]
Required:
--name NAME Project name
Optional:
--alias ALIAS Project alias (default: slugified name)
--desc DESC Project description
--owner OWNER Project owner
--scale small|medium|large Project scale (default: medium)
--risk low|medium|high Risk level (default: medium)
--gate-architecture enabled|disabled Optional gate (default: disabled)
--gate-code-review enabled|disabled Optional gate (default: disabled)
--gate-security enabled|disabled Optional gate (default: disabled)
--gate-privacy enabled|disabled Optional gate (default: disabled)
--git-enabled true|false Git policy enabled (default: false)
--git-commit-format FORMAT Commit format (default: "[role][phase] summary - reason")
--output PATH Output directory (default: ./workspace/specs/{alias}-YYYYMMDD-HHMM)
-h, --help Show help
USAGE
}
die() {
echo "error: $*" >&2
exit 1
}
command -v python3 >/dev/null 2>&1 || die "python3 is required"
project_name=""
project_alias=""
project_desc=""
project_owner=""
scale="medium"
risk="medium"
_gate_arch="disabled"
_gate_code_review="disabled"
_gate_security="disabled"
_gate_privacy="disabled"
git_enabled="false"
git_commit_format="[role][phase] summary - reason"
output=""
while [[ $# -gt 0 ]]; do
case "$1" in
--name) project_name="$2"; shift 2;;
--alias) project_alias="$2"; shift 2;;
--desc) project_desc="$2"; shift 2;;
--owner) project_owner="$2"; shift 2;;
--scale) scale="$2"; shift 2;;
--risk) risk="$2"; shift 2;;
--gate-architecture) _gate_arch="$2"; shift 2;;
--gate-code-review) _gate_code_review="$2"; shift 2;;
--gate-security) _gate_security="$2"; shift 2;;
--gate-privacy) _gate_privacy="$2"; shift 2;;
--git-enabled) git_enabled="$2"; shift 2;;
--git-commit-format) git_commit_format="$2"; shift 2;;
--output) output="$2"; shift 2;;
-h|--help) usage; exit 0;;
*) die "unknown arg: $1";;
esac
done
[[ -z "$project_name" ]] && die "--name is required"
if [[ -z "$project_alias" ]]; then
project_alias=$(echo "$project_name" | tr '[:upper:] ' '[:lower:]-' | tr -cd 'a-z0-9-')
fi
if [[ -z "$output" ]]; then
output="./workspace/specs/${project_alias}-$(date +%Y%m%d-%H%M)"
fi
if [[ -e "$output" ]]; then
die "output already exists: $output"
fi
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
template_dir="${script_dir}/../assets/workspace_template"
mkdir -p "$output"
cp -R "$template_dir"/. "$output"/
date_str="$(date +%Y-%m-%d)"
export TG_PROJECT_NAME="$project_name"
export TG_PROJECT_ALIAS="$project_alias"
export TG_PROJECT_DESC="$project_desc"
export TG_PROJECT_OWNER="$project_owner"
export TG_DATE="$date_str"
export TG_SCALE="$scale"
export TG_RISK="$risk"
export TG_GATE_ARCH="$_gate_arch"
export TG_GATE_CODE_REVIEW="$_gate_code_review"
export TG_GATE_SECURITY="$_gate_security"
export TG_GATE_PRIVACY="$_gate_privacy"
export TG_GIT_ENABLED="$git_enabled"
export TG_GIT_COMMIT_FORMAT="$git_commit_format"
export TG_CURRENT_PHASE="demand"
export TG_CURRENT_ROUND="1"
export TG_P0_COUNT="0"
export TG_LAST_DECISION="-"
export TG_NEXT_ACTION="collect requirements"
replace_file() {
python3 - "$1" <<'PY'
import os
from pathlib import Path
path = Path(os.environ["TARGET_FILE"])
data = path.read_text()
repl = {
"project_name": os.environ.get("TG_PROJECT_NAME", ""),
"project_alias": os.environ.get("TG_PROJECT_ALIAS", ""),
"project_desc": os.environ.get("TG_PROJECT_DESC", ""),
"project_owner": os.environ.get("TG_PROJECT_OWNER", ""),
"date": os.environ.get("TG_DATE", ""),
"current_phase": os.environ.get("TG_CURRENT_PHASE", ""),
"current_round": os.environ.get("TG_CURRENT_ROUND", ""),
"p0_count": os.environ.get("TG_P0_COUNT", ""),
"last_decision": os.environ.get("TG_LAST_DECISION", ""),
"next_action": os.environ.get("TG_NEXT_ACTION", ""),
}
for k, v in repl.items():
data = data.replace("{{" + k + "}}", v)
# project.yaml optional fields
if path.name == "project.yaml":
data = data.replace("small|medium|large", os.environ.get("TG_SCALE", "medium"))
data = data.replace("low|medium|high", os.environ.get("TG_RISK", "medium"))
data = data.replace("enabled|disabled", "enabled" if os.environ.get("TG_GATE_ARCH") == "enabled" else "disabled", 1)
data = data.replace("enabled|disabled", "enabled" if os.environ.get("TG_GATE_CODE_REVIEW") == "enabled" else "disabled", 1)
data = data.replace("enabled|disabled", "enabled" if os.environ.get("TG_GATE_SECURITY") == "enabled" else "disabled", 1)
data = data.replace("enabled|disabled", "enabled" if os.environ.get("TG_GATE_PRIVACY") == "enabled" else "disabled", 1)
data = data.replace("true|false", "true" if os.environ.get("TG_GIT_ENABLED") == "true" else "false", 1)
data = data.replace("[role][phase] summary - reason", os.environ.get("TG_GIT_COMMIT_FORMAT", "[role][phase] summary - reason"))
path.write_text(data)
PY
}
for f in \
"$output/00_meta/project.yaml" \
"$output/00_meta/session.yaml" \
"$output/00_meta/summary.md" \
"$output/00_meta/decision_log.md" \
"$output/00_meta/status.md"; do
export TARGET_FILE="$f"
replace_file "$f"
done
echo "Workspace initialized at: $output"