agent-bios 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -102,6 +102,29 @@ deploy_glob() {
102
102
  done
103
103
  }
104
104
 
105
+ # ---- packaged (domain-selected) corpus deploy ----------------------------
106
+ # Active when --domains is passed or a prior selection exists in STATE_DIR.
107
+ # assemble.py owns the corpus surfaces (central tree, entry seeding, codex
108
+ # marker region, settings merge); the entry CLAUDE.md and AGENTS.md are NOT
109
+ # manifested — the entry is user-owned after seeding, AGENTS.md holds a
110
+ # personal region — so uninstall never deletes them.
111
+ packaged_mode() { [ "${DOMAINS_SET:-0}" = 1 ] || [ -f "$STATE_DIR/selection.json" ]; }
112
+
113
+ assemble_packaged() {
114
+ local args=(--claude-dir "$CLAUDE_DIR" --codex-dir "$CODEX_DIR" --state-dir "$STATE_DIR") rc=0
115
+ [ "${DOMAINS_SET:-0}" = 1 ] && args+=(--domains "$DOMAINS_ARG")
116
+ [ "$DRY_RUN" = 1 ] && args+=(--dry-run)
117
+ python3 "$REPO/scripts/assemble.py" "${args[@]}" || rc=$?
118
+ if [ "$rc" = 2 ]; then
119
+ log "packaged: entry file needs user action (import line missing); central content will not load until it is added"
120
+ elif [ "$rc" != 0 ]; then
121
+ return 1
122
+ fi
123
+ if [ "$DRY_RUN" != 1 ]; then
124
+ find "$CLAUDE_DIR/central" "$CODEX_DIR/guides" -type f 2>/dev/null >> "$MANIFEST"
125
+ fi
126
+ }
127
+
105
128
  add_zsh_hook() {
106
129
  if [ -f "$ZSHRC" ] && grep -qF "$HOOK_MARK" "$ZSHRC"; then
107
130
  info "zsh hook present $ZSHRC"
@@ -399,12 +422,17 @@ cmd_install() {
399
422
  : > "$MANIFEST"
400
423
  fi
401
424
  log "Deploying agent-bios from $REPO"
402
- deploy_file "$REPO/claude/CLAUDE.md" "$CLAUDE_DIR/CLAUDE.md"
403
- deploy_glob "$REPO/claude/guides" "*.md" "$CLAUDE_DIR/guides"
404
- deploy_glob "$REPO/claude/agents" "*.md" "$CLAUDE_DIR/agents"
405
- deploy_glob "$REPO/claude/hooks" "*.py" "$CLAUDE_DIR/hooks" "+x"
406
- deploy_file "$REPO/codex/AGENTS.md" "$CODEX_DIR/AGENTS.md"
407
- deploy_glob "$REPO/codex/guides" "*.md" "$CODEX_DIR/guides"
425
+ if packaged_mode; then
426
+ log "packaged mode: assembling selected domains (state: $STATE_DIR/selection.json)"
427
+ assemble_packaged || exit 1
428
+ else
429
+ deploy_file "$REPO/claude/CLAUDE.md" "$CLAUDE_DIR/CLAUDE.md"
430
+ deploy_glob "$REPO/claude/guides" "*.md" "$CLAUDE_DIR/guides"
431
+ deploy_glob "$REPO/claude/agents" "*.md" "$CLAUDE_DIR/agents"
432
+ deploy_glob "$REPO/claude/hooks" "*.py" "$CLAUDE_DIR/hooks" "+x"
433
+ deploy_file "$REPO/codex/AGENTS.md" "$CODEX_DIR/AGENTS.md"
434
+ deploy_glob "$REPO/codex/guides" "*.md" "$CODEX_DIR/guides"
435
+ fi
408
436
  deploy_glob "$REPO/codex/agents" "*.toml" "$CODEX_DIR/agents"
409
437
  codex_config_additions merge || exit 1
410
438
  deploy_file "$REPO/scripts/codex-run.sh" "$CODEX_DIR/bin/codex-run" "+x"
@@ -424,10 +452,10 @@ cmd_install() {
424
452
  || log "warning: venv provisioning failed (numbered-prompt fallback applies)"
425
453
  fi
426
454
  add_zsh_hook
427
- if python3 "$REPO/scripts/session-learning/learning-state.py" project --repo "$REPO" >/dev/null 2>&1; then
428
- info "learning-status projected"
455
+ if python3 "$REPO/scripts/session-distill/corpus-state.py" project --repo "$REPO" >/dev/null 2>&1; then
456
+ info "corpus-status projected"
429
457
  else
430
- log "note: learning-status projection unavailable (versions.json/ledger missing?)"
458
+ log "note: corpus-status projection unavailable (versions.json/ledger missing?)"
431
459
  fi
432
460
  log ""
433
461
  log "Verifying deployment..."
@@ -448,15 +476,32 @@ verify_present() { if [ -f "$1" ]; then return 0; else log "missing $1"; return
448
476
 
449
477
  cmd_verify() {
450
478
  local fail=0 gp
451
- verify_match "$REPO/claude/CLAUDE.md" "$CLAUDE_DIR/CLAUDE.md" || fail=1
452
- verify_match "$REPO/codex/AGENTS.md" "$CODEX_DIR/AGENTS.md" || fail=1
479
+ if packaged_mode; then
480
+ # Packaged: corpus surfaces are selection-derived, not repo-identical.
481
+ # The entry file is user-owned — READ-check the import line, never rewrite.
482
+ python3 "$REPO/scripts/check-domains.py" >/dev/null 2>&1 && info "domains gate OK" || { log "domains gate FAILED"; fail=1; }
483
+ verify_present "$CLAUDE_DIR/central/bundle.md" || fail=1
484
+ if grep -qF '@central/bundle.md' "$CLAUDE_DIR/CLAUDE.md" 2>/dev/null; then
485
+ info "entry import line present"
486
+ else
487
+ log "entry $CLAUDE_DIR/CLAUDE.md lacks '@central/bundle.md' — central corpus is NOT loading"; fail=1
488
+ fi
489
+ if grep -qF 'agent-bios:central:start' "$CODEX_DIR/AGENTS.md" 2>/dev/null; then
490
+ info "codex central region present"
491
+ else
492
+ log "codex AGENTS.md central region missing"; fail=1
493
+ fi
494
+ else
495
+ verify_match "$REPO/claude/CLAUDE.md" "$CLAUDE_DIR/CLAUDE.md" || fail=1
496
+ verify_match "$REPO/codex/AGENTS.md" "$CODEX_DIR/AGENTS.md" || fail=1
497
+ for gp in "$REPO"/claude/guides/*.md; do verify_present "$CLAUDE_DIR/guides/$(basename "$gp")" || fail=1; done
498
+ for gp in "$REPO"/claude/agents/*.md; do verify_present "$CLAUDE_DIR/agents/$(basename "$gp")" || fail=1; done
499
+ for gp in "$REPO"/claude/hooks/*.py; do verify_present "$CLAUDE_DIR/hooks/$(basename "$gp")" || fail=1; done
500
+ for gp in "$REPO"/codex/guides/*.md; do verify_present "$CODEX_DIR/guides/$(basename "$gp")" || fail=1; done
501
+ fi
453
502
  verify_match "$REPO/scripts/agent-launch.py" "$BIN_DIR/agent-launch" || fail=1
454
503
  verify_match "$REPO/config/agent-launch.toml" "$LAUNCH_DIR/profiles.toml" || fail=1
455
504
  verify_match "$REPO/shell/agent-launch.zsh" "$LAUNCH_DIR/shell.zsh" || fail=1
456
- for gp in "$REPO"/claude/guides/*.md; do verify_present "$CLAUDE_DIR/guides/$(basename "$gp")" || fail=1; done
457
- for gp in "$REPO"/claude/agents/*.md; do verify_present "$CLAUDE_DIR/agents/$(basename "$gp")" || fail=1; done
458
- for gp in "$REPO"/claude/hooks/*.py; do verify_present "$CLAUDE_DIR/hooks/$(basename "$gp")" || fail=1; done
459
- for gp in "$REPO"/codex/guides/*.md; do verify_present "$CODEX_DIR/guides/$(basename "$gp")" || fail=1; done
460
505
  python3 - "$CODEX_DIR/agents" <<'PY' && info "agent TOMLs OK" || fail=1
461
506
  import sys, pathlib, tomllib
462
507
  root = pathlib.Path(sys.argv[1])
@@ -526,6 +571,49 @@ cmd_uninstall() {
526
571
  log "Kept: managed venv + backups under $STATE_DIR (rm -rf \"$STATE_DIR\" to purge)."
527
572
  }
528
573
 
574
+ cmd_onboard() {
575
+ log "agent-bios onboarding — pick your domain packages (core + infra always install)"
576
+ local names=() line i=1 choice sel="" n picks
577
+ while IFS= read -r line; do names+=("$line"); done \
578
+ < <(python3 -c "import json;print('\n'.join(sorted(json.load(open('$REPO/config/domains.json'))['domains'])))")
579
+ [ "${#names[@]}" -ge 1 ] || { log "no domains found in config/domains.json"; exit 1; }
580
+ if [ "$DOMAINS_SET" = 1 ]; then
581
+ # Non-interactive path, per this installer's input contract (stdin is
582
+ # detached at the top of the script): selection arrives as domain names.
583
+ [ "$DOMAINS_ARG" = none ] && DOMAINS_ARG=""
584
+ sel="$DOMAINS_ARG"
585
+ elif ( : </dev/tty ) 2>/dev/null; then
586
+ for line in "${names[@]}"; do info "$i) $line"; i=$((i+1)); done
587
+ printf 'Select by number, comma-separated (empty = core+infra only): '
588
+ read -r choice </dev/tty || choice=""
589
+ if [ -n "$choice" ]; then
590
+ # bash 3.2 + set -u: expanding an EMPTY array errors, so split only
591
+ # when there is input; empty input means core+infra only.
592
+ IFS=',' read -ra picks <<<"$choice"
593
+ for n in "${picks[@]}"; do
594
+ n="${n// /}"; [ -n "$n" ] || continue
595
+ case "$n" in (*[!0-9]*) log "invalid selection: $n"; exit 2 ;; esac
596
+ [ "$n" -ge 1 ] && [ "$n" -le "${#names[@]}" ] || { log "selection out of range: $n"; exit 2; }
597
+ sel="$sel${sel:+,}${names[$((n-1))]}"
598
+ done
599
+ fi
600
+ else
601
+ log "onboard needs a terminal or an explicit selection — run:"
602
+ log " agent-bios onboard --domains a,b (or --domains none for core+infra only)"
603
+ exit 2
604
+ fi
605
+ DOMAINS_ARG="$sel"; DOMAINS_SET=1
606
+ log "selection: ${sel:-<core+infra only>}"
607
+ cmd_install
608
+ log ""
609
+ log "Activation canary (proves the bundle loads in a live session)..."
610
+ if [ "$DRY_RUN" = 1 ]; then info "[dry-run] skip canary probe"; return; fi
611
+ bash "$REPO/scripts/canary.sh" || {
612
+ log "ONBOARDING INCOMPLETE: the bundle is installed but not loading — fix the cause above and re-run: agent-bios verify"
613
+ exit 1
614
+ }
615
+ }
616
+
529
617
  cmd_status() {
530
618
  local version p
531
619
  if [ -d "$REPO/.git" ]; then
@@ -561,6 +649,7 @@ usage() {
561
649
  agent-bios — deploy the Claude/Codex instruction SSOT into $HOME (by copy).
562
650
 
563
651
  agent-bios install deploy into this environment (backs up + verifies)
652
+ agent-bios onboard interactive domain selection + packaged install + activation canary
564
653
  agent-bios verify check the deployed state matches the source
565
654
  agent-bios status show what is installed and where
566
655
  agent-bios update git pull + reinstall (clone), or print the npm update line
@@ -568,6 +657,13 @@ agent-bios — deploy the Claude/Codex instruction SSOT into $HOME (by copy).
568
657
  agent-bios help
569
658
 
570
659
  Flags: --dry-run print actions without changing anything
660
+ --domains a,b packaged mode (install/onboard): assemble ONLY the named
661
+ domain packages (plus core+infra) instead of the full
662
+ corpus; with onboard, 'none' means core+infra only. The
663
+ selection persists in the state dir, so later
664
+ installs/updates stay packaged until the selection file
665
+ is removed. Default (no flag, no saved selection) keeps
666
+ today's full-corpus deploy.
571
667
  --with a,b also install the named optional dependencies (install only).
572
668
  Without it, install offers each missing one when the terminal
573
669
  is interactive, and otherwise just prints its install line.
@@ -581,11 +677,15 @@ EOF
581
677
  CMD="${1:-help}"
582
678
  if [ $# -gt 0 ]; then shift; fi
583
679
  WITH=""
680
+ DOMAINS_ARG=""
681
+ DOMAINS_SET=0
584
682
  while [ $# -gt 0 ]; do
585
683
  case "$1" in
586
684
  --dry-run) DRY_RUN=1 ;;
587
685
  --with) shift; WITH="${1:-}"; [ -n "$WITH" ] || { log "--with needs a comma-separated capability list"; exit 2; } ;;
588
686
  --with=*) WITH="${1#--with=}"; [ -n "$WITH" ] || { log "--with needs a comma-separated capability list"; exit 2; } ;;
687
+ --domains) shift; DOMAINS_ARG="${1:-}"; DOMAINS_SET=1; [ -n "$DOMAINS_ARG" ] || { log "--domains needs a comma-separated domain list (use onboard for core-only)"; exit 2; } ;;
688
+ --domains=*) DOMAINS_ARG="${1#--domains=}"; DOMAINS_SET=1; [ -n "$DOMAINS_ARG" ] || { log "--domains needs a comma-separated domain list (use onboard for core-only)"; exit 2; } ;;
589
689
  *) log "unknown flag: $1"; exit 2 ;;
590
690
  esac
591
691
  shift
@@ -593,6 +693,7 @@ done
593
693
 
594
694
  case "$CMD" in
595
695
  install) cmd_install ;;
696
+ onboard) cmd_onboard ;;
596
697
  update) cmd_update ;;
597
698
  uninstall) cmd_uninstall ;;
598
699
  verify) if cmd_verify; then log "VERIFY OK"; else log "VERIFY FAILED"; exit 1; fi ;;