Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,21 @@ git clone https://github.com/KalebCole/partiful-cli && cd partiful-cli
npm install && npm link
```

### Install the Partiful agent skill

The package includes one Partiful skill. Install it globally for whichever agent you use:

```bash
partiful skill install hermes
partiful skill install openclaw
partiful skill install copilot
partiful skill install claude
```

Remove an installer-owned copy with `partiful skill uninstall <agent>`. For OpenClaw, uninstall also cleans legacy `partiful-*` links created by older releases; pass `--workspace <path>` when the old workspace was not at `~/.openclaw/workspace`.

Use `--dry-run` to preview filesystem changes. During installation, existing or locally modified skill directories are preserved unless `--force` is supplied. Uninstall never removes an unowned destination; an installer-owned copy with local edits also requires `--force`.

## Features

- 🎉 **Events** — create, list, get, update, cancel
Expand Down
58 changes: 58 additions & 0 deletions docs/plans/2026-07-28-unified-agent-skill-installer-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Unified Agent Skill Installer Design

**Date:** 2026-07-28

## Goal

Replace the removed OpenClaw-only setup command with one agent-neutral interface for installing the bundled Partiful skill:

```bash
partiful skill install <hermes|openclaw|copilot|claude>
partiful skill uninstall <hermes|openclaw|copilot|claude>
```

This change is stacked on `feat/singular-partiful-skill` and must not depend on RSVP questionnaire work.

## Decisions

- Use singular `skill`, because the npm package now ships one `partiful` skill.
- Normalize agent names to lowercase.
- Install at each agent's user-level skill root by default:
- Hermes: `$HERMES_HOME/skills/partiful`, falling back to `~/.hermes/skills/partiful`
- OpenClaw: `~/.openclaw/skills/partiful`
- Copilot: `~/.copilot/skills/partiful`
- Claude Code: `~/.claude/skills/partiful`
- Copy the bundled skill rather than symlink it. This works on Windows without elevated symlink privileges and prevents npm installation paths from becoming runtime dependencies.
- Add a private provenance marker to copied installations. Uninstall refuses to remove an unowned directory.
- Preserve global `--dry-run` and `--force` behavior.
- For OpenClaw uninstall, also clean legacy `partiful-*` symlinks created by `partiful setup openclaw`. Support `--workspace <path>` so custom legacy workspaces can be cleaned.
- Do not add `status`, project-local installation, or auto-detection in this PR.

## Command behavior

### Install

1. Validate agent.
2. Resolve bundled source and agent destination.
3. If destination is absent, recursively copy the skill and marker.
4. If an owned installation already matches, report it as already installed.
5. Refuse to overwrite any existing destination unless `--force` is passed.
6. `--dry-run` returns the intended action without filesystem mutation.

### Uninstall

1. Remove the destination only when it is an installer-owned copy or a symlink to the bundled Partiful skill.
2. Refuse to delete an unowned directory.
3. For OpenClaw, additionally inspect the selected legacy workspace and remove only legacy `partiful-*` symlinks whose targets resolve under this package's `skills/` directory.
4. `--dry-run` reports removals without mutation.

## Output and errors

All responses use the CLI JSON envelope. Unsupported agents, unreadable source directories, unsafe overwrite attempts, and unowned uninstall targets return structured errors with existing exit-code conventions.

## Verification

- Unit tests use temporary homes and never touch real agent directories.
- Test every target's resolved path.
- Test install, idempotence, force overwrite, dry-run, safe uninstall, refusal to delete unowned content, and OpenClaw legacy cleanup.
- Run full tests, typecheck, package dry-run, and CLI smoke tests.
82 changes: 82 additions & 0 deletions docs/plans/2026-07-28-unified-agent-skill-installer-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Unified Agent Skill Installer Implementation Plan

> **For Hermes:** Use subagent-driven-development skill to implement this plan task-by-task.

**Goal:** Add a safe, cross-agent `partiful skill install|uninstall <agent>` interface for the singular bundled Partiful skill.

**Architecture:** A new command module owns target resolution, copy provenance, safe removal, and OpenClaw legacy cleanup. Commander registration remains thin in `src/cli.ts`; filesystem behavior is exercised through temporary-directory integration tests.

**Tech Stack:** TypeScript, Commander.js, Node filesystem APIs, Vitest.

---

### Task 1: Lock command contract with failing tests

**Objective:** Specify supported agents, destination paths, dry-run behavior, and structured output.

**Files:**
- Create: `tests/skill-installer.test.js`
- Modify: `tests/skill-structure.test.js`

**Steps:**
1. Add tests invoking the CLI with isolated `HOME` and `HERMES_HOME` values.
2. Assert `skill install` exists for `hermes`, `openclaw`, `copilot`, and `claude`.
3. Assert `--dry-run` reports target paths and makes no changes.
4. Replace the consolidation test asserting `setup` is absent with assertions for the new command contract.
5. Run `npm test -- --run tests/skill-installer.test.js tests/skill-structure.test.js`; expect failure because `skill` is not registered.

### Task 2: Implement installation

**Objective:** Copy the bundled singular skill safely into each agent's user-level skill root.

**Files:**
- Create: `src/commands/skill.ts`
- Modify: `src/cli.ts`
- Test: `tests/skill-installer.test.js`

**Steps:**
1. Add typed target metadata and path resolution.
2. Register `skill install <agent>`.
3. Recursively copy `skills/partiful/` and write a provenance marker.
4. Implement idempotence, `--force`, and global `--dry-run`.
5. Verify the focused tests pass.

### Task 3: Implement safe uninstall and OpenClaw migration

**Objective:** Remove only installer-owned copies and safely clean legacy OpenClaw links.

**Files:**
- Modify: `src/commands/skill.ts`
- Test: `tests/skill-installer.test.js`

**Steps:**
1. Add failing tests for owned removal, unowned-directory refusal, symlink removal, dry-run, and custom `--workspace` cleanup.
2. Implement `skill uninstall <agent>`.
3. Detect old OpenClaw `partiful-*` links without following dangling symlinks.
4. Restrict migration cleanup to symlinks targeting this package's `skills/` directory.
5. Run focused tests and verify all pass.

### Task 4: Document and verify the public interface

**Objective:** Make installation discoverable and prove package behavior.

**Files:**
- Modify: `README.md`
- Modify: `package.json` only if discoverability metadata requires it.

**Steps:**
1. Document all four install commands and uninstall/migration behavior.
2. Run CLI help smoke tests.
3. Run `npm test`, `npm run typecheck`, and `npm pack --dry-run --json`.
4. Confirm the tarball contains exactly `skills/partiful/SKILL.md` plus its references.
5. Run `git diff --check` and an adversarial review.

### Task 5: Publish stacked PR

**Objective:** Push a PR that depends only on the consolidation branch.

**Steps:**
1. Commit implementation and verification changes.
2. Push `feat/unified-skill-installer`.
3. Open PR with base `feat/singular-partiful-skill`, not `main` and not the RSVP branch.
4. Verify local HEAD equals remote HEAD and inspect PR checks.
2 changes: 2 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { registerDoctorCommands } from './commands/doctor.js';
import { registerTemplateCommands } from './commands/templates.js';
import { registerBulkCommands } from './commands/bulk.js';
import { registerRsvpCommands } from './commands/rsvp.js';
import { registerSkillCommands } from './commands/skill.js';
import { jsonOutput } from './lib/output.js';

// Single source of truth for the version — read from package.json so the
Expand Down Expand Up @@ -52,6 +53,7 @@ export function run(): void {
registerDoctorCommands(program);
registerTemplateCommands(program);
registerBulkCommands(program);
registerSkillCommands(program);
// RSVP / interest verbs, shared across the canonical `events` group and the
// `explore` alias group. Look up the `events` command created above; create
// the `explore` group here.
Expand Down
Loading