@outsidestudio/agent-kit 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/README.md CHANGED
@@ -20,15 +20,16 @@ That command:
20
20
  2. Asks once for any secrets the profile needs (API keys, model endpoint) and stores them in `~/.config/outside-agent-kit/env` (chmod 600), loaded from `~/.zshrc` / `~/.bashrc`.
21
21
  3. Fetches the **latest** version of every skill and plugin. Nothing is pinned.
22
22
  4. Writes each tool's config, keeping anything the developer added themselves.
23
- 5. Installing **only registry items** (no profile) is additive: it adds/replaces those items and keeps the rest of your install. Installing a profile reconciles the full set.
23
+ 5. **Installs are additive**: `agent-kit <target>` writes the named profiles/items and never removes anything else you already have — so `agent-kit product-backend` after `agent-kit product-backend web-frontend` just refreshes backend and leaves the web skills in place. To drop something, use `agent-kit remove <target>`; to rebuild configs to exactly your saved set, use `agent-kit update`.
24
24
 
25
25
  ## Commands
26
26
 
27
27
  | Command | What it does |
28
28
  |---|---|
29
- | `agent-kit <profile...>` | Install one or more profiles |
30
- | `agent-kit outside/llm` | Add/refresh a single registry item without touching the rest of the install (see `agent-kit list`) |
31
- | `agent-kit update` | Re-install the current targets with the latest of everything |
29
+ | `agent-kit add <profile...>` | Add/refresh one or more profiles (additive — keeps the rest). Bare `agent-kit <profile...>` and `install` are shorthands |
30
+ | `agent-kit add outside/llm` | Add/refresh a single registry item on top of what you have (see `agent-kit list`) |
31
+ | `agent-kit remove <target...>` | Remove installed profiles/items; everything else is reconciled to stay |
32
+ | `agent-kit update` | Re-fetch your saved targets and reconcile configs to exactly them (prunes leftovers) |
32
33
  | `agent-kit doctor` | Check tools, secrets, model endpoint, MCP servers, skills |
33
34
  | `agent-kit secrets` | Enter missing secrets |
34
35
  | `agent-kit list` | Show profiles and registry items |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@outsidestudio/agent-kit",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "One-command setup of skills, MCP servers and model providers for OpenCode and OMP",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env bun
2
2
  import { doctor } from "./commands/doctor";
3
- import { install, secrets, update } from "./commands/install";
3
+ import { install, remove, secrets, update } from "./commands/install";
4
4
  import { list } from "./commands/list";
5
5
  import { newMcp, newSkill } from "./commands/new";
6
6
  import { color, log } from "./log";
@@ -8,8 +8,9 @@ import { color, log } from "./log";
8
8
  const HELP = `${color.bold("agent-kit")}: set up skills, MCP servers and models for OpenCode and OMP
9
9
 
10
10
  ${color.bold("Usage")}
11
- agent-kit <target...> Install profiles and/or single registry items (same as: agent-kit install <target...>)
12
- agent-kit update Re-install the current targets with the latest of everything
11
+ agent-kit add <target...> Add/refresh profiles and/or single registry items; leaves everything else installed untouched (shorthand: agent-kit <target...>, also: agent-kit install)
12
+ agent-kit remove <target...> Remove installed profiles/items; the rest is kept and reconciled
13
+ agent-kit update Re-fetch the saved targets and reconcile configs to exactly them
13
14
  agent-kit doctor Check tools, secrets, model endpoint and MCP servers
14
15
  agent-kit secrets Enter any missing secrets
15
16
  agent-kit list Show profiles and registry items
@@ -23,9 +24,10 @@ ${color.bold("Options")}
23
24
  --no-shell Don't add the secrets loader to ~/.zshrc / ~/.bashrc
24
25
 
25
26
  ${color.bold("Examples")}
26
- bunx @outsidestudio/agent-kit product-backend
27
+ bunx @outsidestudio/agent-kit add product-backend # bare form works too: bunx @outsidestudio/agent-kit product-backend
27
28
  bunx @outsidestudio/agent-kit product-backend web-frontend
28
- bunx @outsidestudio/agent-kit outside/llm # just the model provider (see: agent-kit list)
29
+ bunx @outsidestudio/agent-kit outside/llm # just the model provider, on top of what's installed (see: agent-kit list)
30
+ bunx @outsidestudio/agent-kit remove web-frontend # drop web skills, keep backend + shared
29
31
  bunx @outsidestudio/agent-kit update
30
32
  `;
31
33
 
@@ -57,9 +59,13 @@ async function main() {
57
59
  if (!cmd || flags.help) return console.log(HELP);
58
60
 
59
61
  switch (cmd) {
62
+ case "add":
60
63
  case "install":
61
64
  if (!rest.length) throw new Error("What to install? Run: agent-kit list");
62
65
  return install(rest, opts);
66
+ case "remove":
67
+ if (!rest.length) throw new Error("What to remove? Run: agent-kit list");
68
+ return remove(rest, opts);
63
69
  case "update":
64
70
  return update(opts);
65
71
  case "doctor":
@@ -11,6 +11,8 @@ export interface InstallOptions {
11
11
  tools?: string[];
12
12
  yes?: boolean;
13
13
  shell?: boolean;
14
+ /** Rebuild configs from exactly these targets, purging managed leftovers. */
15
+ reconcile?: boolean;
14
16
  }
15
17
 
16
18
  function pickTools(requested?: string[]): string[] {
@@ -46,10 +48,14 @@ function mergeToolState(prev: ToolState | undefined, next: ToolState): ToolState
46
48
  export async function install(targets: string[], opts: InstallOptions = {}) {
47
49
  const tools = pickTools(opts.tools);
48
50
  const { profiles, items: direct } = await resolveTargets(targets);
49
- // Targeting only registry items adds/replaces those items; it never purges
50
- // the rest of the install. A profile target still reconciles the full set.
51
- const additive = profiles.length === 0 && direct.length > 0;
52
- log.head(`Setting up ${targets.map((t) => `"${t}"`).join(" + ")} for ${tools.join(" + ")}`);
51
+ // Installs are additive: they add/refresh the named targets and never touch
52
+ // what else is installed. Only --reconcile runs (update, remove) purge.
53
+ const additive = opts.reconcile !== true;
54
+ log.head(
55
+ targets.length
56
+ ? `Setting up ${targets.map((t) => `"${t}"`).join(" + ")} for ${tools.join(" + ")}`
57
+ : `Removing everything the kit manages for ${tools.join(" + ")}`,
58
+ );
53
59
 
54
60
  const ids = [...new Set([...(await resolveProfiles(profiles)), ...direct])];
55
61
  const items = await Promise.all(ids.map(loadItem));
@@ -101,7 +107,10 @@ export async function install(targets: string[], opts: InstallOptions = {}) {
101
107
  managed: { ...(prev?.managed ?? {}) },
102
108
  installed: additive ? { ...(prev?.installed ?? {}), ...plan.fetched } : plan.fetched,
103
109
  };
104
- if (additive && prev) log.step(`Additive: keeping ${prev.profiles.join(", ") || "existing items"}; replacing ${direct.join(", ")}`);
110
+ if (additive && prev)
111
+ log.step(
112
+ `Additive: keeping ${[...prev.profiles, ...prev.items].join(", ") || "nothing"}; refreshing ${targets.join(", ")}`,
113
+ );
105
114
  for (const t of tools) {
106
115
  const next = await adapters[t].apply(plan, prev?.managed[t]);
107
116
  state.managed[t] = additive ? mergeToolState(prev?.managed[t], next) : next;
@@ -124,7 +133,31 @@ export async function install(targets: string[], opts: InstallOptions = {}) {
124
133
  export async function update(opts: InstallOptions = {}) {
125
134
  const prev = await readState();
126
135
  if (!prev) throw new Error("Nothing installed yet. Run: agent-kit <profile>");
127
- await install([...prev.profiles, ...prev.items], { ...opts, tools: opts.tools ?? prev.tools });
136
+ // Reconcile: the saved targets are the whole truth, so leftovers from
137
+ // changed profile definitions get purged.
138
+ await install([...prev.profiles, ...prev.items], {
139
+ ...opts,
140
+ tools: opts.tools ?? prev.tools,
141
+ reconcile: true,
142
+ });
143
+ }
144
+
145
+ /** Drop targets from the saved install; everything else is reconciled to stay. */
146
+ export async function remove(targets: string[], opts: InstallOptions = {}) {
147
+ const prev = await readState();
148
+ if (!prev) throw new Error("Nothing installed yet. Run: agent-kit <profile>");
149
+ await resolveTargets(targets); // reject unknown names
150
+ const saved = [...prev.profiles, ...prev.items];
151
+ const gone = targets.filter((t) => saved.includes(t));
152
+ if (!gone.length)
153
+ throw new Error(
154
+ `None of ${targets.join(", ")} is installed. Installed: ${saved.join(", ") || "nothing"}. ` +
155
+ `Items pulled in by a profile can only be removed by removing that profile.`,
156
+ );
157
+ const rest = saved.filter((t) => !gone.includes(t));
158
+ log.head(`Removing ${gone.join(", ")}`);
159
+ if (rest.length) log.info(`Keeping: ${rest.join(", ")}`);
160
+ await install(rest, { ...opts, tools: opts.tools ?? prev.tools, reconcile: true });
128
161
  }
129
162
 
130
163
  /** Re-prompt for every secret the current install needs. */
package/src/types.ts CHANGED
@@ -95,8 +95,10 @@ export interface Plan {
95
95
  /** What was fetched, for the install log. */
96
96
  fetched: Record<string, string>;
97
97
  /**
98
- * Single registry-item install: replace only the items in this plan and
99
- * keep everything else the kit managed before (no purge of skills/MCP/etc).
98
+ * Additive run (the default for installs): write exactly what this plan
99
+ * names and keep every other entry the kit managed before — no purge of
100
+ * skills/MCP/plugins/providers. Reconcile runs (update, remove) leave this
101
+ * false and rebuild the config from only this plan.
100
102
  */
101
103
  additive?: boolean;
102
104
  }