pi-rolecast 0.2.0 → 0.2.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-rolecast",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Multi-agent role framework for Pi. Groups of specialist agents (coding, video, etc.) bound to per-role models, dispatched via pi-subagents. Profile-driven, gate-verified, language-agnostic.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -31,11 +31,9 @@ if [[ -n "$DRY_RUN" ]]; then
31
31
  fi
32
32
  mkdir -p "$PREFIX"
33
33
 
34
- # Framework symlink (new pi-rolecast name; keep removing the legacy name).
35
- if [[ ! -e "$PREFIX/pi-rolecast" ]]; then
36
- ln -s "$FRAMEWORK_ROOT" "$PREFIX/pi-rolecast"
37
- echo "linked $PREFIX/pi-rolecast to $FRAMEWORK_ROOT"
38
- fi
34
+ # Remove legacy pi-agent-workflow framework symlink if it exists.
35
+ # v0.2.3: no longer creates ~/.pi/agent/pi-rolecast symlink — npm install
36
+ # path (~/.pi/agent/npm/node_modules/pi-rolecast) is canonical.
39
37
  if [[ -e "$PREFIX/pi-agent-workflow" ]]; then
40
38
  echo "removing legacy $PREFIX/pi-agent-workflow symlink"
41
39
  rm -f "$PREFIX/pi-agent-workflow"
@@ -58,9 +56,19 @@ fi
58
56
  # Global role symlinks for every role-packs/<group>/<role>.md.
59
57
  agents_dir="$PREFIX/agents"
60
58
  mkdir -p "$agents_dir"
59
+ # Clean up ANY pre-existing symlinks pointing at the legacy framework root.
60
+ # Old symlinks would dangle after `pi-agent-workflow` is removed; clean first.
61
+ if [[ -d "$agents_dir" ]]; then
62
+ while IFS= read -r stale; do
63
+ target="$(readlink "$stale" 2>/dev/null || true)"
64
+ if [[ -n "$target" && "$target" == *pi-agent-workflow* ]]; then
65
+ rm -f "$stale"
66
+ fi
67
+ done < <(find "$agents_dir" -maxdepth 1 -type l -name '*.md')
68
+ fi
61
69
  linked=0
62
70
  while IFS= read -r md; do
63
- role=$(basename "$md" .md)
71
+ role=$(basename "$md" .md) # e.g. "coding-architect" (full prefixed name)
64
72
  link_path="$agents_dir/$role.md"
65
73
  if [[ -L "$link_path" ]]; then
66
74
  rm -f "$link_path"
@@ -252,7 +252,8 @@ def _write_agents(agents_dir: Path, framework_root: Path,
252
252
  dry_run: bool, registry) -> int:
253
253
  """Write project-local copies of role-packs/<group>/<role>.md for every
254
254
  bound role. Uses full role name (`<group>-<role>`) as the filename so
255
- pi-subagents can find it via @<full-name> mention syntax."""
255
+ pi-subagents can find it via @<full-name> mention syntax.
256
+ """
256
257
  roles = available_roles(framework_root, groups=enabled_groups or None)
257
258
  if dry_run:
258
259
  for role_full_name, rd in sorted(roles.items()):
@@ -274,12 +275,13 @@ def _write_agents(agents_dir: Path, framework_root: Path,
274
275
  print("warning: role-packs file not found: " + str(rd.file_path),
275
276
  file=sys.stderr)
276
277
  continue
277
- dst = agents_dir / (role_full_name + ".md")
278
278
  body = src.read_text()
279
279
  model_id = new_overrides[role_full_name]["model"]
280
280
  provider = _provider_for_model(model_id, registry)
281
281
  full = (provider + "/" + model_id) if provider else model_id
282
282
  updated = _set_frontmatter_field(body, "model", full)
283
+ # v0.2.0+ canonical filename
284
+ dst = agents_dir / (role_full_name + ".md")
283
285
  dst.write_text(updated)
284
286
  written += 1
285
287
  print("wrote " + str(written) + " project-local agent files to " + str(agents_dir))
@@ -0,0 +1,150 @@
1
+ #!/usr/bin/env bash
2
+ # pi-rolecast uninstaller. Removes all framework artifacts created by
3
+ # install.sh and sync_settings.py. Safe to run multiple times (idempotent).
4
+ #
5
+ # Removes:
6
+ # - ~/.pi/agent/pi-rolecast framework symlink
7
+ # - ~/.pi/agent/agents/*.md symlinks whose target is inside a pi-rolecast
8
+ # framework
9
+ # - .pi/agents/<framework-role>.md files matching framework role names
10
+ # (in cwd)
11
+ # - subagents.agentOverrides entries for framework roles in settings.json
12
+ # - empty agent directories if nothing else remains
13
+ #
14
+ # Does NOT remove:
15
+ # - ~/.pi/agent/npm/node_modules/pi-rolecast/ (run `pi uninstall npm:pi-rolecast` first)
16
+ # - user-created agent files in .pi/agents/ (e.g. custom-role.md)
17
+ # - user-created symlinks in ~/.pi/agent/agents/ (e.g. targeting other frameworks)
18
+ # - settings.json entries for non-framework roles
19
+ set -euo pipefail
20
+
21
+ PREFIX="${HOME}/.pi/agent"
22
+ DRY_RUN=""
23
+ KEEP_PROJECT_AGENTS=""
24
+ SETTINGS_JSON=""
25
+ GLOBAL_AGENTS_DIR=""
26
+ PROJECT_AGENTS_DIR=""
27
+ FRAMEWORK_ROOT=""
28
+
29
+ while [[ $# -gt 0 ]]; do
30
+ case "$1" in
31
+ --prefix) PREFIX="$2"; shift 2 ;;
32
+ --framework-root) FRAMEWORK_ROOT="$2"; shift 2 ;;
33
+ --dry-run) DRY_RUN="1"; shift ;;
34
+ --settings) SETTINGS_JSON="$2"; shift 2 ;;
35
+ --global-agents-dir) GLOBAL_AGENTS_DIR="$2"; shift 2 ;;
36
+ --project-agents-dir) PROJECT_AGENTS_DIR="$2"; shift 2 ;;
37
+ --keep-project-agents) KEEP_PROJECT_AGENTS="1"; shift ;;
38
+ *) echo "unknown argument: $1" >&2; exit 1 ;;
39
+ esac
40
+ done
41
+
42
+ [[ -z "$SETTINGS_JSON" ]] && SETTINGS_JSON="$PREFIX/settings.json"
43
+ [[ -z "$GLOBAL_AGENTS_DIR" ]] && GLOBAL_AGENTS_DIR="$PREFIX/agents"
44
+ [[ -z "$PROJECT_AGENTS_DIR" ]] && PROJECT_AGENTS_DIR="$(pwd)/.pi/agents"
45
+
46
+ # Find framework root to enumerate framework role names. Without this we
47
+ # cannot tell framework-written project-local files from user customizations.
48
+ if [[ -z "$FRAMEWORK_ROOT" ]]; then
49
+ if [[ -d "./role-packs" ]]; then
50
+ FRAMEWORK_ROOT="$(cd . && pwd)"
51
+ elif [[ -d "$PREFIX/npm/node_modules/pi-rolecast/role-packs" ]]; then
52
+ FRAMEWORK_ROOT="$PREFIX/npm/node_modules/pi-rolecast"
53
+ fi
54
+ fi
55
+
56
+ framework_roles=()
57
+ if [[ -n "$FRAMEWORK_ROOT" ]]; then
58
+ while IFS= read -r role; do
59
+ framework_roles+=("$role")
60
+ done < <(find "$FRAMEWORK_ROOT/role-packs" -type f -name '*.md' \
61
+ -exec basename {} .md \; 2>/dev/null | sort -u)
62
+ fi
63
+
64
+ removed=0
65
+ _action() {
66
+ # $1 = action (rm), $2 = path, $3 = reason
67
+ if [[ -n "$DRY_RUN" ]]; then
68
+ echo "would $1 $2 ($3)"
69
+ else
70
+ if "$1" "$2" 2>/dev/null; then
71
+ echo "$1 $2 ($3)"
72
+ removed=$((removed + 1))
73
+ fi
74
+ fi
75
+ }
76
+
77
+ # 1. Framework symlink ~/.pi/agent/pi-rolecast
78
+ link="$PREFIX/pi-rolecast"
79
+ if [[ -L "$link" ]]; then
80
+ target="$(readlink "$link")"
81
+ case "$target" in
82
+ *pi-rolecast*) _action rm "$link" "framework symlink" ;;
83
+ esac
84
+ fi
85
+
86
+ # 2. Global agent symlinks ~/.pi/agent/agents/*.md
87
+ # Only remove symlinks whose target is inside a pi-rolecast framework.
88
+ if [[ -d "$GLOBAL_AGENTS_DIR" ]]; then
89
+ while IFS= read -r l; do
90
+ target="$(readlink "$l")"
91
+ case "$target" in
92
+ *pi-rolecast*) _action rm "$l" "global agent symlink" ;;
93
+ esac
94
+ done < <(find "$GLOBAL_AGENTS_DIR" -maxdepth 1 -type l -name '*.md' 2>/dev/null)
95
+ fi
96
+
97
+ # 3. Project-local agent files .pi/agents/<role>.md
98
+ # Only remove files matching framework role names. Skip symlinks (user-created).
99
+ if [[ -z "$KEEP_PROJECT_AGENTS" && -d "$PROJECT_AGENTS_DIR" && ${#framework_roles[@]} -gt 0 ]]; then
100
+ for role in "${framework_roles[@]}"; do
101
+ f="$PROJECT_AGENTS_DIR/$role.md"
102
+ [[ -e "$f" || -L "$f" ]] || continue
103
+ [[ -L "$f" ]] && continue
104
+ _action rm "$f" "project-local agent file"
105
+ done
106
+ elif [[ -z "$KEEP_PROJECT_AGENTS" && -d "$PROJECT_AGENTS_DIR" ]]; then
107
+ echo "warning: framework root not found, skipping project-local agent cleanup" >&2
108
+ echo " hint: cd into a project with .pi/rolecast.yaml, or run from pi-rolecast repo" >&2
109
+ fi
110
+
111
+ # 4. Clean settings.json subagents.agentOverrides for framework roles
112
+ if [[ -f "$SETTINGS_JSON" && ${#framework_roles[@]} -gt 0 ]]; then
113
+ python3 - "$SETTINGS_JSON" "${framework_roles[@]}" <<'PYEOF'
114
+ import json, sys
115
+ path = sys.argv[1]
116
+ roles = set(sys.argv[2:])
117
+ try:
118
+ with open(path) as f:
119
+ s = json.load(f)
120
+ except (FileNotFoundError, json.JSONDecodeError):
121
+ sys.exit(0)
122
+ sub = s.setdefault("subagents", {})
123
+ ov = sub.get("agentOverrides", {}) or {}
124
+ cleared = [k for k in list(ov) if k in roles]
125
+ for k in cleared:
126
+ del ov[k]
127
+ sub["agentOverrides"] = ov
128
+ s["subagents"] = sub
129
+ with open(path, "w") as f:
130
+ json.dump(s, f, indent=2, sort_keys=True)
131
+ f.write("\n")
132
+ print(f"removed {len(cleared)} framework overrides from {path}")
133
+ PYEOF
134
+ fi
135
+
136
+ # 5. Remove empty agent directories (after all cleanup)
137
+ for d in "$GLOBAL_AGENTS_DIR" "$PROJECT_AGENTS_DIR"; do
138
+ if [[ -d "$d" && -z "$(ls -A "$d" 2>/dev/null)" ]]; then
139
+ if [[ -n "$DRY_RUN" ]]; then
140
+ echo "would remove empty dir $d"
141
+ else
142
+ if rmdir "$d" 2>/dev/null; then
143
+ echo "rmdir $d (empty dir)"
144
+ removed=$((removed + 1))
145
+ fi
146
+ fi
147
+ fi
148
+ done
149
+
150
+ echo "uninstall complete: removed $removed items"