feat(build.py): --no-purge flag and opencode-archive install target
Conflict fix: --install opencode wipes ~/.config/opencode/skills/ on every build, which clobbers the work of external managers like opc-skills. New flag --no-purge skips that wipe so opc-skills' enabled set survives a rebuild. New install target opencode-archive: instead of writing to ~/.config/opencode/, it regenerates personas/skills-archive/ + personas/agents-opencode-archive/ (the source-of-truth that opc-skills + opc-agents consume). This lets the build pipeline stay decoupled from runtime install dirs. install_opencode() now accepts agents_dest / skills_dest overrides for the archive target. Live target behavior unchanged.
This commit is contained in:
67
build.py
67
build.py
@@ -1513,6 +1513,9 @@ def install_opencode(
|
||||
output_dir: Path,
|
||||
shared_dir: Path | None = None,
|
||||
topics: set[str] | None = None,
|
||||
purge_skills: bool = True,
|
||||
agents_dest: Path | None = None,
|
||||
skills_dest: Path | None = None,
|
||||
):
|
||||
"""Install personas to OpenCode as agents + skills.
|
||||
|
||||
@@ -1529,11 +1532,26 @@ def install_opencode(
|
||||
Args:
|
||||
topics: set of topics to install (see OPENCODE_TOPICS). Defaults to
|
||||
OPENCODE_DEFAULT_TOPICS which drops marketing/biz skills.
|
||||
purge_skills: when True (default), wipe ~/.config/opencode/skills/
|
||||
before installing. Set False (via --no-purge) when this dir is also
|
||||
managed by an external tool (e.g. opc-skills) — purge would otherwise
|
||||
delete its work on every build.
|
||||
"""
|
||||
if topics is None:
|
||||
topics = OPENCODE_DEFAULT_TOPICS
|
||||
agents_dir = Path.home() / ".config" / "opencode" / "agents"
|
||||
skills_dir = Path.home() / ".config" / "opencode" / "skills"
|
||||
# Archive mode: agents_dest / skills_dest override the live opencode dirs.
|
||||
# Used by --install opencode-archive to regenerate the personas archive
|
||||
# that opc-skills and opc-agents consume as source-of-truth.
|
||||
if agents_dest is not None:
|
||||
agents_dir = agents_dest
|
||||
agents_dir.mkdir(parents=True, exist_ok=True)
|
||||
else:
|
||||
agents_dir = Path.home() / ".config" / "opencode" / "agents"
|
||||
if skills_dest is not None:
|
||||
skills_dir = skills_dest
|
||||
skills_dir.mkdir(parents=True, exist_ok=True)
|
||||
else:
|
||||
skills_dir = Path.home() / ".config" / "opencode" / "skills"
|
||||
agents_dir.mkdir(parents=True, exist_ok=True)
|
||||
skills_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
@@ -1719,12 +1737,16 @@ def install_opencode(
|
||||
skipped_topic = 0
|
||||
|
||||
# Purge existing skills dir so stale filtered-out skills are removed.
|
||||
if skills_dir.exists():
|
||||
# Skipped when --no-purge is passed (so external tools like opc-skills
|
||||
# that manage this directory don't get clobbered on every build).
|
||||
if purge_skills and skills_dir.exists():
|
||||
import shutil as _shutil
|
||||
|
||||
for existing in skills_dir.iterdir():
|
||||
if existing.is_dir():
|
||||
_shutil.rmtree(existing)
|
||||
elif not purge_skills:
|
||||
print(f" OpenCode: --no-purge — preserving existing {skills_dir}/")
|
||||
|
||||
if shared_dir:
|
||||
for skills_subdir in [
|
||||
@@ -2107,12 +2129,16 @@ def main():
|
||||
"gemini",
|
||||
"openclaw",
|
||||
"opencode",
|
||||
"opencode-archive",
|
||||
"paperclip",
|
||||
"all",
|
||||
],
|
||||
help="Install generated personas to a target platform. "
|
||||
"'claude' installs persona agents+commands; 'claude-skills' installs "
|
||||
"shared skills to ~/.claude/skills/ with category filters.",
|
||||
"shared skills to ~/.claude/skills/ with category filters; "
|
||||
"'opencode-archive' writes opencode-format agents+skills to "
|
||||
"personas/agents-opencode-archive/ + personas/skills-archive/ "
|
||||
"(consumed by opc-skills/opc-agents) without touching ~/.config/opencode/.",
|
||||
)
|
||||
# --- claude-skills filters --------------------------------------------
|
||||
parser.add_argument(
|
||||
@@ -2171,6 +2197,13 @@ def main():
|
||||
"business-pm, uncategorized. "
|
||||
"Default drops marketing/biz. Use 'all' for no filter.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-purge",
|
||||
action="store_true",
|
||||
help="For --install opencode: do NOT wipe ~/.config/opencode/skills/ "
|
||||
"before installing. Use when the directory is also managed by an "
|
||||
"external tool (e.g. opc-skills) so its enabled skills are preserved.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--search",
|
||||
type=str,
|
||||
@@ -2325,7 +2358,7 @@ def main():
|
||||
install_gemini(output_dir)
|
||||
elif target == "openclaw":
|
||||
install_openclaw(output_dir)
|
||||
elif target == "opencode":
|
||||
elif target in ("opencode", "opencode-archive"):
|
||||
if args.opencode_topics:
|
||||
if args.opencode_topics.strip().lower() == "all":
|
||||
oc_topics = OPENCODE_TOPICS
|
||||
@@ -2337,7 +2370,29 @@ def main():
|
||||
}
|
||||
else:
|
||||
oc_topics = None # use default
|
||||
install_opencode(output_dir, shared_dir, topics=oc_topics)
|
||||
if target == "opencode-archive":
|
||||
# Source-of-truth layout consumed by opc-skills + opc-agents:
|
||||
# personas/skills-archive/<name>/SKILL.md ← opc-skills reads
|
||||
# personas/agents-opencode-archive/<n>.md ← opc-agents reads
|
||||
install_opencode(
|
||||
output_dir,
|
||||
shared_dir,
|
||||
topics=oc_topics,
|
||||
purge_skills=False,
|
||||
agents_dest=root / "agents-opencode-archive",
|
||||
skills_dest=root / "skills-archive",
|
||||
)
|
||||
print(
|
||||
" opcode-archive: regenerated source-of-truth used by "
|
||||
"opc-skills + opc-agents. Did NOT touch ~/.config/opencode/."
|
||||
)
|
||||
else:
|
||||
install_opencode(
|
||||
output_dir,
|
||||
shared_dir,
|
||||
topics=oc_topics,
|
||||
purge_skills=not args.no_purge,
|
||||
)
|
||||
elif target == "paperclip":
|
||||
install_paperclip(output_dir, personas_dir, shared_dir)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user