Merge pull request #656 from AIOSAI/dev
setup.sh chains into aipass init run — clone-first one-command install (DPLAN-0234 Strand A). git clone && ./setup.sh now takes a new user from cold clone to an initialized first project in one command. --no-init/--with-init/--project mirror aipass install's handoff rules; CI + piped shells skip automatically (windows/macos-test workflows untouched, proven in clean-room Docker run 1). install.py passes --no-init so the pip path doesn't double-init. Clean-room Docker: both runs exit 0.
This commit is contained in:
@@ -13,6 +13,24 @@ PyPI version — not the changelog header.
|
||||
|
||||
### Added
|
||||
|
||||
- **`./setup.sh` chains into `aipass init run` — clone-first one-command install
|
||||
(DPLAN-0234 Strand A).** Distribution is git-clone, not pip: the framework
|
||||
changes constantly, so a PyPI snapshot goes stale while a clone is always
|
||||
current HEAD. Now `git clone && cd AIPass && ./setup.sh` takes you from cold
|
||||
clone to a working first project in one command: on interactive terminals,
|
||||
setup ends by launching the guided `aipass init run` in a sibling directory
|
||||
(default `~/aipass-project`, prompt to choose — init refuses to run inside the
|
||||
engine tree). New flags mirror `aipass install`'s handoff rules: `--no-init`
|
||||
skips, `--with-init` forces even headless (init chains `--non-interactive`),
|
||||
`--project <dir>` picks the target. CI and piped shells skip automatically
|
||||
(`CI` env or no tty), so the windows/macos-test workflows that run bare
|
||||
`bash setup.sh` are untouched. `install.py` now calls `setup.sh --no-init`
|
||||
since install owns its own init handoff — no double-scaffold. Proven in
|
||||
clean-room Docker, both runs exit 0: bare headless run skips init with a
|
||||
hint; `--with-init` run chains init to `✓ Project initialized.` with the
|
||||
project dir scaffolded. 39/39 install tests, seedgo 30/30. README Quick
|
||||
Start updated to the one-command flow.
|
||||
|
||||
- **`aipass install` — one-command framework bootstrap.** The missing half of
|
||||
`pip install aipass`: a single command resolves the install home (default
|
||||
`~/AIPass`), git-clones the public repo, runs `setup.sh` (venv, editable
|
||||
|
||||
@@ -32,13 +32,10 @@ AIPass is a CLI-native scaffold that adds **persistent memory, identity, and coo
|
||||
|
||||
```bash
|
||||
git clone https://github.com/AIOSAI/AIPass.git
|
||||
cd AIPass && ./setup.sh # installs the `aipass` + `drone` commands on your PATH
|
||||
|
||||
cd ~ && mkdir my-project && cd my-project
|
||||
aipass init run
|
||||
cd AIPass && ./setup.sh # installs everything, then walks you into your first project
|
||||
```
|
||||
|
||||
A guided setup creates your project, your first agent, and opens a terminal where that agent is already running. Say "hi" — it knows who it is. Come back tomorrow — it remembers.
|
||||
Setup builds the environment, puts `aipass` + `drone` on your PATH, then chains straight into a guided init that creates your project, your first agent, and opens a terminal where that agent is already running. Say "hi" — it knows who it is. Come back tomorrow — it remembers.
|
||||
|
||||
This is the base framework. It gives your agents the infrastructure to persist, communicate, and organize — everything else you build on top.
|
||||
|
||||
@@ -87,7 +84,9 @@ git clone https://github.com/AIOSAI/AIPass.git
|
||||
cd AIPass && ./setup.sh # Creates venv, installs, puts `aipass` + `drone` on your PATH, bootstraps 17 agents
|
||||
```
|
||||
|
||||
### 2. Your own project
|
||||
On an interactive terminal, setup ends by chaining into `aipass init run` — one command takes you from clone to a working first project. Pass `--no-init` to skip the chain, `--project <dir>` to pick where the project lands (CI and piped shells skip automatically).
|
||||
|
||||
### 2. Your own project (if you skipped the chain)
|
||||
|
||||
```bash
|
||||
cd ~ && mkdir my-project && cd my-project
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
#
|
||||
# AIPass setup script
|
||||
# Creates a venv, installs the package in editable mode, and verifies CLI entry points.
|
||||
# On interactive terminals it then chains into `aipass init run` to scaffold a first
|
||||
# project (DPLAN-0234: one command does setup + init).
|
||||
#
|
||||
# Usage: ./setup.sh [--no-init] [--with-init] [--project <dir>]
|
||||
# --no-init skip the first-project init chain
|
||||
# --with-init force the init chain even headless (init runs --non-interactive)
|
||||
# --project <dir> first-project directory (default: ~/aipass-project)
|
||||
#
|
||||
|
||||
set -euo pipefail
|
||||
@@ -27,6 +34,27 @@ case "${OSTYPE:-}" in
|
||||
;;
|
||||
esac
|
||||
|
||||
# --- Args ---
|
||||
# Mirrors the `aipass install` handoff rules: --no-init wins, --with-init forces,
|
||||
# default (auto) chains into init on interactive terminals only — CI/headless skip.
|
||||
RUN_INIT="auto"
|
||||
INIT_PROJECT=""
|
||||
PREV_ARG=""
|
||||
for arg in "$@"; do
|
||||
if [ "$PREV_ARG" = "--project" ]; then
|
||||
INIT_PROJECT="$arg"
|
||||
PREV_ARG=""
|
||||
continue
|
||||
fi
|
||||
case "$arg" in
|
||||
--no-init) RUN_INIT="no" ;;
|
||||
--with-init) RUN_INIT="yes" ;;
|
||||
--project=*) INIT_PROJECT="${arg#--project=}" ;;
|
||||
--project) PREV_ARG="--project" ;;
|
||||
*) echo "WARN: unknown argument '$arg' (ignored)" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo "=== AIPass Setup ==="
|
||||
echo "Repo root: $SCRIPT_DIR"
|
||||
echo ""
|
||||
@@ -982,6 +1010,77 @@ if [ "$FAIL" -eq 0 ]; then
|
||||
echo " Claude Code: hooks installed to ~/.claude/settings.json"
|
||||
command -v codex &>/dev/null && echo " Codex CLI: hooks at .codex/hooks.json + config at ~/.codex/config.toml"
|
||||
echo ""
|
||||
|
||||
# --- Chain into first-project init (DPLAN-0234: one command does setup + init) ---
|
||||
# `aipass init` refuses to run inside the engine tree, so it always targets a
|
||||
# sibling directory — never the repo itself. Decision mirrors install.py:
|
||||
# --no-init wins, --with-init forces (headless chains --non-interactive),
|
||||
# default = interactive terminals only (CI and piped shells skip).
|
||||
AIPASS_BIN=""
|
||||
if [ "$IS_WINDOWS" -eq 1 ] && [ -f "$SCRIPT_DIR/.venv/Scripts/aipass.exe" ]; then
|
||||
AIPASS_BIN="$SCRIPT_DIR/.venv/Scripts/aipass.exe"
|
||||
elif [ "$IS_WINDOWS" -eq 1 ] && [ -f "$SCRIPT_DIR/.venv/Scripts/aipass" ]; then
|
||||
AIPASS_BIN="$SCRIPT_DIR/.venv/Scripts/aipass"
|
||||
elif [ -f "$SCRIPT_DIR/.venv/bin/aipass" ]; then
|
||||
AIPASS_BIN="$SCRIPT_DIR/.venv/bin/aipass"
|
||||
elif command -v aipass &>/dev/null; then
|
||||
AIPASS_BIN="$(command -v aipass)"
|
||||
fi
|
||||
|
||||
LAUNCH_INIT=0
|
||||
INIT_HEADLESS=0
|
||||
if [ "$RUN_INIT" = "no" ]; then
|
||||
echo "Skipping first-project init (--no-init). Run 'aipass init run' in a fresh directory when ready."
|
||||
elif [ "$RUN_INIT" = "yes" ]; then
|
||||
LAUNCH_INIT=1
|
||||
if [ ! -t 0 ]; then
|
||||
INIT_HEADLESS=1
|
||||
fi
|
||||
elif [ -t 0 ] && [ -z "${CI:-}" ]; then
|
||||
LAUNCH_INIT=1
|
||||
else
|
||||
echo "Non-interactive shell — skipping first-project init. Run 'aipass init run' in a fresh directory when ready."
|
||||
fi
|
||||
|
||||
if [ "$LAUNCH_INIT" -eq 1 ]; then
|
||||
if [ -z "$AIPASS_BIN" ]; then
|
||||
echo "WARN: aipass binary not found — open a new terminal and run 'aipass init run' in a fresh directory."
|
||||
else
|
||||
DEFAULT_PROJECT_DIR="$HOME/aipass-project"
|
||||
PROJECT_DIR="$INIT_PROJECT"
|
||||
if [ -z "$PROJECT_DIR" ] && [ "$INIT_HEADLESS" -eq 0 ] && [ -t 0 ]; then
|
||||
echo "AIPass projects live in their own directory, never inside the engine repo."
|
||||
read -r -p "Set up your first project now? [Y/n]: " INIT_REPLY
|
||||
case "$INIT_REPLY" in
|
||||
[nN]*)
|
||||
PROJECT_DIR="-"
|
||||
echo " Skipped. Run 'aipass init run' in a fresh directory when ready."
|
||||
;;
|
||||
*)
|
||||
read -r -p " Project directory [$DEFAULT_PROJECT_DIR]: " INIT_INPUT
|
||||
PROJECT_DIR="${INIT_INPUT:-$DEFAULT_PROJECT_DIR}"
|
||||
;;
|
||||
esac
|
||||
elif [ -z "$PROJECT_DIR" ]; then
|
||||
PROJECT_DIR="$DEFAULT_PROJECT_DIR"
|
||||
fi
|
||||
|
||||
if [ "$PROJECT_DIR" != "-" ]; then
|
||||
mkdir -p "$PROJECT_DIR"
|
||||
INIT_CMD=("$AIPASS_BIN" init run)
|
||||
if [ "$INIT_HEADLESS" -eq 1 ]; then
|
||||
INIT_CMD+=(--non-interactive)
|
||||
fi
|
||||
echo ""
|
||||
echo "Launching guided setup in $PROJECT_DIR ..."
|
||||
if (cd "$PROJECT_DIR" && "${INIT_CMD[@]}"); then
|
||||
echo "First project initialized at $PROJECT_DIR"
|
||||
else
|
||||
echo "Init didn't complete — run 'aipass init run' in $PROJECT_DIR when ready."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "=== Setup finished with errors ==="
|
||||
echo "The venv was created and the package was installed, but one or more"
|
||||
|
||||
@@ -131,7 +131,9 @@ def _run_setup(home: Path, dry_run: bool) -> bool:
|
||||
return False
|
||||
console.print("[cyan]Building environment[/cyan] [dim](venv, dependencies, hook wiring)…[/dim]")
|
||||
try:
|
||||
proc = subprocess.run(["bash", str(setup)], cwd=str(home), timeout=_SETUP_TIMEOUT)
|
||||
# --no-init: install owns the init handoff (_handoff_to_init) — without it,
|
||||
# setup.sh's own init chain (DPLAN-0234) would scaffold the project twice.
|
||||
proc = subprocess.run(["bash", str(setup), "--no-init"], cwd=str(home), timeout=_SETUP_TIMEOUT)
|
||||
if proc.returncode == 0:
|
||||
return True
|
||||
logger.warning("[install] setup.sh exited %s", proc.returncode)
|
||||
|
||||
Reference in New Issue
Block a user