pi-rolecast 0.2.1 → 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.1",
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"
@@ -70,26 +68,15 @@ if [[ -d "$agents_dir" ]]; then
70
68
  fi
71
69
  linked=0
72
70
  while IFS= read -r md; do
73
- role=$(basename "$md" .md) # e.g. "coding-architect"
74
- bare="${role#coding-}" # legacy compat name e.g. "architect" (for coding group)
71
+ role=$(basename "$md" .md) # e.g. "coding-architect" (full prefixed name)
75
72
  link_path="$agents_dir/$role.md"
76
73
  if [[ -L "$link_path" ]]; then
77
74
  rm -f "$link_path"
78
75
  fi
79
76
  ln -s "$md" "$link_path"
80
77
  linked=$((linked + 1))
81
- # Legacy shim: create <bare-role>.md symlink for extensions that key
82
- # off filename (e.g. bundled pi-cc-extensions). Removed in v0.3.0.
83
- if [[ "$role" == "$bare" ]]; then
84
- continue # safety: if role had no group prefix, skip
85
- fi
86
- legacy_link="$agents_dir/$bare.md"
87
- if [[ ! -L "$legacy_link" && ! -e "$legacy_link" ]]; then
88
- ln -s "$md" "$legacy_link"
89
- linked=$((linked + 1))
90
- fi
91
78
  done < <(find "$FRAMEWORK_ROOT/role-packs" -type f -name '*.md' 2>/dev/null | sort)
92
- echo "linked $linked role agents from role-packs/ (incl. legacy compat shims)"
79
+ echo "linked $linked role agents from role-packs/"
93
80
 
94
81
  # Warn if pi-subagents is missing — required for actual role dispatch.
95
82
  SETTINGS_JSON="$PREFIX/settings.json"
@@ -253,11 +253,6 @@ def _write_agents(agents_dir: Path, framework_root: Path,
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
255
  pi-subagents can find it via @<full-name> mention syntax.
256
-
257
- Also writes a legacy `<bare-role>.md` shim for extensions that key off
258
- filename (e.g. the bundled pi-cc-extensions subagent reference provider).
259
- Both files contain the same body, just different filenames. The legacy
260
- shim is removed in v0.3.0.
261
256
  """
262
257
  roles = available_roles(framework_root, groups=enabled_groups or None)
263
258
  if dry_run:
@@ -269,10 +264,6 @@ def _write_agents(agents_dir: Path, framework_root: Path,
269
264
  full = (provider + "/" + model_id) if provider else model_id
270
265
  print("would write " + str(agents_dir / (role_full_name + ".md")) +
271
266
  " model=" + full)
272
- legacy = rd.role
273
- if legacy and legacy != role_full_name:
274
- print("would write " + str(agents_dir / (legacy + ".md")) +
275
- " model=" + full + " (legacy shim)")
276
267
  return 0
277
268
  agents_dir.mkdir(parents=True, exist_ok=True)
278
269
  written = 0
@@ -293,17 +284,7 @@ def _write_agents(agents_dir: Path, framework_root: Path,
293
284
  dst = agents_dir / (role_full_name + ".md")
294
285
  dst.write_text(updated)
295
286
  written += 1
296
- # Legacy shim: bare role name for filename-keyed extensions.
297
- # Only created for the coding group; other groups have no legacy.
298
- legacy = rd.role
299
- if legacy and legacy != role_full_name and rd.group == "coding":
300
- legacy_dst = agents_dir / (legacy + ".md")
301
- if legacy_dst.exists() or legacy_dst.is_symlink():
302
- legacy_dst.unlink()
303
- legacy_dst.write_text(updated)
304
- written += 1
305
- print("wrote " + str(written) + " project-local agent files to " + str(agents_dir) +
306
- " (incl. legacy compat shims)")
287
+ print("wrote " + str(written) + " project-local agent files to " + str(agents_dir))
307
288
  return 0
308
289
 
309
290
 
@@ -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"