Files
arnes/scripts/start.sh
2026-05-18 00:30:39 +02:00

216 lines
6.2 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"
ask() {
local prompt="$1"; local def="${2:-}"; local val
if [ -n "$def" ]; then
read -r -p "$prompt [$def]: " val || true
echo "${val:-$def}"
else
read -r -p "$prompt: " val || true
echo "$val"
fi
}
echo "=== ARNES start wizard ==="
echo "Mode: use this template in a new repo or copy core ARNES into an existing repo."
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
echo "No git repo detected. Initializing local git repository..."
git init >/dev/null
fi
PROJECT_NAME="$(ask 'Project name' 'my-project')"
PROJECT_DESC="$(ask 'Project description' 'Project using ARNES template')"
APP_DIR="$(ask 'App directory (relative)' 'project')"
STACK_CHOICE="$(ask 'Stack preset (1=default Flask+MariaDB+Skeleton, 2=custom)' '1')"
if [ "$STACK_CHOICE" = "2" ]; then
BACKEND="$(ask 'Backend stack' 'python/flask')"
DB="$(ask 'Database' 'mariadb')"
CSSFW="$(ask 'CSS framework' 'skeleton')"
else
BACKEND="python/flask"
DB="mariadb"
CSSFW="skeleton"
fi
DEFAULT_TEST_CMD="echo TODO-set-test-command"
if [ "$BACKEND" = "python/flask" ]; then
DEFAULT_TEST_CMD="python3 -m unittest discover -s $APP_DIR/tests -v"
fi
TEST_CMD="$(ask 'Test command' "$DEFAULT_TEST_CMD")"
LINT_CMD="$(ask 'Lint command (optional)' '')"
MODEL_MODE="$(ask 'Model mode (lean/balanced/power)' 'lean')"
ADD_BOOTSTRAP="$(ask 'Create bootstrap ticket F-001 now? (y/n)' 'y')"
mkdir -p "$APP_DIR"
[ -f "$APP_DIR/README.md" ] || cat > "$APP_DIR/README.md" <<EOF
# Project code
This directory holds the real project code.
Configured by ARNES start wizard.
EOF
if [ "$BACKEND" = "python/flask" ]; then
mkdir -p "$APP_DIR/templates" "$APP_DIR/static/js" "$APP_DIR/static/css" "$APP_DIR/static/images" "$APP_DIR/tests"
[ -f "$APP_DIR/tests/test_bootstrap.py" ] || cat > "$APP_DIR/tests/test_bootstrap.py" <<'PY'
import unittest
class BootstrapSmokeTest(unittest.TestCase):
def test_bootstrap(self):
self.assertTrue(True)
if __name__ == '__main__':
unittest.main()
PY
fi
if [ "$CSSFW" = "skeleton" ]; then
mkdir -p "$APP_DIR/static/css" "$APP_DIR/static/images"
[ -f "$APP_DIR/static/css/normalize.css" ] || cp defaults/flask-skeleton/static/css/normalize.css "$APP_DIR/static/css/normalize.css"
[ -f "$APP_DIR/static/css/skeleton.css" ] || cp defaults/flask-skeleton/static/css/skeleton.css "$APP_DIR/static/css/skeleton.css"
[ -f "$APP_DIR/static/images/favicon.png" ] || cp defaults/flask-skeleton/static/images/favicon.png "$APP_DIR/static/images/favicon.png"
fi
cat > harness/project.config.json <<JSON
{
"project_name": "$PROJECT_NAME",
"project_description": "$PROJECT_DESC",
"app_dir": "$APP_DIR",
"stack": {
"backend": "$BACKEND",
"database": "$DB",
"css": "$CSSFW"
},
"commands": {
"test": "$TEST_CMD",
"lint": "$LINT_CMD"
},
"model_mode": "$MODEL_MODE"
}
JSON
cat > scripts/verify.local.sh <<'SH'
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"
if [ ! -f "harness/project.config.json" ]; then
echo "[LOCAL] missing harness/project.config.json"
exit 1
fi
APP_DIR=$(python3 - <<'PY'
import json
from pathlib import Path
cfg=json.loads(Path('harness/project.config.json').read_text())
print(cfg.get('app_dir','project'))
PY
)
TEST_CMD=$(python3 - <<'PY'
import json
from pathlib import Path
cfg=json.loads(Path('harness/project.config.json').read_text())
print(cfg.get('commands',{}).get('test',''))
PY
)
LINT_CMD=$(python3 - <<'PY'
import json
from pathlib import Path
cfg=json.loads(Path('harness/project.config.json').read_text())
print(cfg.get('commands',{}).get('lint',''))
PY
)
if [ ! -d "$APP_DIR" ]; then
echo "[LOCAL] app dir not found: $APP_DIR"
exit 1
fi
echo "[LOCAL] app dir OK: $APP_DIR"
if [ -n "$LINT_CMD" ]; then
echo "[LOCAL] lint: $LINT_CMD"
bash -lc "$LINT_CMD"
fi
if [ -n "$TEST_CMD" ]; then
echo "[LOCAL] test: $TEST_CMD"
bash -lc "$TEST_CMD"
fi
echo "[LOCAL] OK"
SH
chmod +x scripts/verify.local.sh
python3 - <<PY
import json
from pathlib import Path
from datetime import date
b = Path('backlog/features.json')
data = json.loads(b.read_text(encoding='utf-8'))
data['project'] = '$PROJECT_NAME'
data['description'] = '$PROJECT_DESC'
rules = data.setdefault('rules', {})
rules.setdefault('valid_types', ['feature', 'fix', 'bug', 'chore'])
features = data.get('features', [])
if '$ADD_BOOTSTRAP'.lower().startswith('y') and not features:
features.append({
'id': 'F-001',
'type': 'chore',
'title': 'Bootstrap ARNES on project',
'problem': 'Need base workflow and control',
'goal': 'Make ARNES ready on this repo',
'scope_in': ['Harness setup', 'Runtime status', 'First verify cycle'],
'scope_out': ['Business feature work', 'Product redesign'],
'priority': 'med',
'risk': 'low',
'description': 'Problem: Need base workflow and control. Goal: Make ARNES ready on this repo. Scope IN: Harness setup, Runtime status, First verify cycle. Scope OUT: Business feature work, Product redesign. Type: chore. Priority: med. Risk: low.',
'acceptance': ['verify.sh is green', 'runtime status works', 'first feature closes with gates'],
'status': 'pending',
'created_at': str(date.today()),
'gates': {'review': False, 'security': False, 'qa': False}
})
data['features'] = features
b.write_text(json.dumps(data, indent=2, ensure_ascii=False) + '\n', encoding='utf-8')
PY
cat > work/current.md <<EOF
# Current session
- Feature in progress: _none_
- Orchestrator: _leader_
## Plan
- Pick one pending feature.
- Run ./scripts/verify.sh
- Set runtime status.
## Next step
- Use python3 scripts/new_ticket.py to create first real ticket.
EOF
python3 scripts/agent_status.py reset >/dev/null || true
echo ""
echo "Done. Project configured."
echo "- Config: harness/project.config.json"
echo "- Local checks: scripts/verify.local.sh"
echo "- Ticket tool: python3 scripts/new_ticket.py"
echo "- Publish tool: python3 scripts/publish_ticket.py --feature-id F-001"
echo "- Verify: ./scripts/verify.sh"
echo "- Runtime: python3 scripts/agent_status.py show"
echo "- Reminder: configure git remote before final publish if missing"