@callmeradical/augy 0.5.0 → 0.6.0

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.
@@ -1,3 +1,6 @@
1
+ import {
2
+ filterableMultiselect
3
+ } from "./chunk-A3USXURD.js";
1
4
  import {
2
5
  AGENTS,
3
6
  agentSkillPath,
@@ -14,7 +17,7 @@ import {
14
17
  } from "./chunk-JM4VVAHN.js";
15
18
 
16
19
  // src/commands/home.ts
17
- import { intro, outro, spinner } from "@clack/prompts";
20
+ import { intro, isCancel, multiselect, outro, spinner } from "@clack/prompts";
18
21
  import chalk from "chalk";
19
22
  import { cp, mkdir, readdir, writeFile } from "fs/promises";
20
23
  import { existsSync } from "fs";
@@ -98,21 +101,20 @@ async function homePushCommand() {
98
101
  s.start(`Cloning ${chalk.cyan(home.repo)}\u2026`);
99
102
  await cloneRepo(repoToUrl(home.repo), cloneDir);
100
103
  s.stop(`${chalk.green("\u2713")} Cloned`);
101
- const homeRepo = home.repo;
102
104
  for (const skill of authored) {
103
105
  const sourcePath = Object.values(skill.agents).find((a) => a.active && existsSync(a.path))?.path;
104
106
  if (!sourcePath) continue;
105
107
  const destPath = home.skillsPath ? join(cloneDir, home.skillsPath, skill.name) : join(cloneDir, skill.name);
106
108
  await mkdir(destPath, { recursive: true });
107
109
  await cp(sourcePath, destPath, { recursive: true, force: true });
108
- const newSource = `https://github.com/${homeRepo}/tree/main/${home.skillsPath ? home.skillsPath + "/" : ""}${skill.name}`;
109
- skill.source = newSource;
110
- upsertSkill(registry, skill);
111
110
  }
112
111
  const bundle = { version: 1, skills: {} };
113
- for (const skill of allSkills) {
112
+ for (const skill of external) {
114
113
  bundle.skills[skill.name] = skill.source;
115
114
  }
115
+ for (const skill of authored) {
116
+ bundle.skills[skill.name] = "";
117
+ }
116
118
  await writeFile(
117
119
  join(cloneDir, home.path),
118
120
  JSON.stringify(bundle, null, 2) + "\n",
@@ -125,8 +127,6 @@ async function homePushCommand() {
125
127
  const authoredNote = authored.length ? ` (${authored.length} authored)` : "";
126
128
  await gitCommit(cloneDir, `chore: update skills via augy \u2014 ${skillCount} skill(s)${authoredNote}`);
127
129
  await gitPush(cloneDir);
128
- s2.stop(`${chalk.green("\u2713")} Pushed`);
129
- if (authored.length) await writeRegistry(registry);
130
130
  outro(
131
131
  `${chalk.bold(String(skillCount))} skill(s) saved to ${chalk.cyan(home.repo)}
132
132
  ` + (authored.length ? chalk.dim(` ${authored.length} authored skill(s) committed + source registered
@@ -138,9 +138,7 @@ async function homePullCommand(opts = {}) {
138
138
  const registry = await readRegistry();
139
139
  const home = getHomeConfig(registry);
140
140
  if (!home) {
141
- console.error(
142
- chalk.red("No home repo configured.") + "\nRun `augy home set <owner/repo>` first."
143
- );
141
+ console.error(chalk.red("No home repo configured.") + "\nRun `augy home set <owner/repo>` first.");
144
142
  process.exit(1);
145
143
  }
146
144
  const cloneDir = join(tmpdir(), `augy-home-pull-${Date.now()}`);
@@ -148,53 +146,97 @@ async function homePullCommand(opts = {}) {
148
146
  s.start(`Cloning ${chalk.cyan(home.repo)}\u2026`);
149
147
  await cloneRepo(repoToUrl(home.repo), cloneDir);
150
148
  s.stop(`${chalk.green("\u2713")} Cloned`);
151
- const targetAgents = opts.agent?.length ? AGENTS.filter((a) => opts.agent.includes(a.id)) : detectInstalledAgents();
152
- if (!targetAgents.length) {
153
- console.error(chalk.red("No agents detected. Install an agent or use --agent to specify one."));
154
- process.exit(1);
155
- }
149
+ const available = [];
156
150
  const skillsDir = home.skillsPath ? join(cloneDir, home.skillsPath) : cloneDir;
157
- const authoredInstalled = [];
158
151
  if (existsSync(skillsDir)) {
159
152
  const entries = await readdir(skillsDir, { withFileTypes: true });
160
- const skillDirs = entries.filter((e) => e.isDirectory());
161
- for (const dir of skillDirs) {
162
- const skillName = dir.name;
163
- const srcPath = join(skillsDir, skillName);
164
- const source = `https://github.com/${home.repo}/tree/main/${home.skillsPath ? home.skillsPath + "/" : ""}${skillName}`;
165
- if (opts.dryRun) {
166
- console.log(` ${chalk.cyan("+")} ${skillName} ${chalk.dim("(authored)")}`);
167
- continue;
168
- }
169
- const agentPaths = {};
170
- for (const agent of targetAgents) {
171
- const dest = agentSkillPath(agent, skillName);
172
- await mkdir(dest, { recursive: true });
173
- await cp(srcPath, dest, { recursive: true, force: true });
174
- agentPaths[agent.id] = dest;
175
- }
176
- const record = createSkillRecord({
177
- name: skillName,
178
- source,
179
- gigetSource: "",
180
- sha: "home",
181
- agentIds: targetAgents.map((a) => a.id),
182
- agentPaths
183
- });
184
- upsertSkill(registry, record);
185
- authoredInstalled.push(skillName);
153
+ for (const e of entries) {
154
+ if (e.isDirectory()) available.push({ name: e.name, source: "", isAuthored: true });
186
155
  }
187
156
  }
188
157
  const manifestPath = join(cloneDir, home.path);
189
158
  if (existsSync(manifestPath)) {
190
- const { syncCommand } = await import("./sync-QQFXUXCN.js");
191
- await syncCommand(manifestPath, opts);
159
+ const { readFile } = await import("fs/promises");
160
+ const bundle = JSON.parse(await readFile(manifestPath, "utf8"));
161
+ for (const [name, source] of Object.entries(bundle.skills)) {
162
+ if (source && !available.find((s2) => s2.name === name)) {
163
+ available.push({ name, source, isAuthored: false });
164
+ }
165
+ }
166
+ }
167
+ if (!available.length) {
168
+ outro(chalk.dim("No skills found in home repo."));
169
+ return;
170
+ }
171
+ const selected = await filterableMultiselect({
172
+ message: `Select skills to install ${chalk.dim(`(${available.length} available)`)}`,
173
+ options: available.map((sk) => ({
174
+ value: sk,
175
+ label: sk.name,
176
+ hint: sk.isAuthored ? chalk.dim("authored") : chalk.dim(sk.source),
177
+ selected: true
178
+ }))
179
+ });
180
+ if (isCancel(selected) || !selected.length) {
181
+ console.log(chalk.dim("Cancelled."));
182
+ process.exit(0);
183
+ }
184
+ const toInstall = selected;
185
+ let targetAgents = opts.agent?.length ? AGENTS.filter((a) => opts.agent.includes(a.id)) : detectInstalledAgents();
186
+ if (!opts.agent?.length) {
187
+ const agentResult = await multiselect({
188
+ message: "Install to which agents?",
189
+ options: targetAgents.map((a) => ({ value: a.id, label: a.name })),
190
+ initialValues: targetAgents.map((a) => a.id)
191
+ });
192
+ if (isCancel(agentResult)) {
193
+ console.log(chalk.dim("Cancelled."));
194
+ process.exit(0);
195
+ }
196
+ targetAgents = AGENTS.filter((a) => agentResult.includes(a.id));
192
197
  }
193
- if (!opts.dryRun && authoredInstalled.length) {
194
- await writeRegistry(registry);
198
+ if (!targetAgents.length) {
199
+ console.error(chalk.red("No agents selected."));
200
+ process.exit(1);
195
201
  }
196
202
  if (opts.dryRun) {
203
+ for (const sk of toInstall) {
204
+ console.log(` ${chalk.cyan("+")} ${sk.name} ${chalk.dim(sk.isAuthored ? "authored" : sk.source)}`);
205
+ }
197
206
  outro(chalk.dim("Dry run \u2014 no changes made."));
207
+ return;
208
+ }
209
+ const authoredToInstall = toInstall.filter((sk) => sk.isAuthored);
210
+ for (const sk of authoredToInstall) {
211
+ const srcPath = join(skillsDir, sk.name);
212
+ const agentPaths = {};
213
+ for (const agent of targetAgents) {
214
+ const dest = agentSkillPath(agent, sk.name);
215
+ await mkdir(dest, { recursive: true });
216
+ await cp(srcPath, dest, { recursive: true, force: true });
217
+ agentPaths[agent.id] = dest;
218
+ }
219
+ const record = createSkillRecord({
220
+ name: sk.name,
221
+ source: "",
222
+ gigetSource: "",
223
+ sha: "home",
224
+ agentIds: targetAgents.map((a) => a.id),
225
+ agentPaths
226
+ });
227
+ upsertSkill(registry, record);
228
+ }
229
+ if (authoredToInstall.length) await writeRegistry(registry);
230
+ const externalToInstall = toInstall.filter((sk) => !sk.isAuthored);
231
+ if (externalToInstall.length) {
232
+ const { tmpdir: td } = await import("os");
233
+ const { writeFile: wf } = await import("fs/promises");
234
+ const filteredBundle = { version: 1, skills: {} };
235
+ for (const sk of externalToInstall) filteredBundle.skills[sk.name] = sk.source;
236
+ const tmpManifest = join(td(), `augy-home-pull-manifest-${Date.now()}.json`);
237
+ await wf(tmpManifest, JSON.stringify(filteredBundle, null, 2) + "\n", "utf8");
238
+ const { syncCommand } = await import("./sync-QQFXUXCN.js");
239
+ await syncCommand(tmpManifest, { ...opts, agent: targetAgents.map((a) => a.id) });
198
240
  }
199
241
  }
200
242
  export {
package/dist/index.js CHANGED
@@ -89,19 +89,19 @@ author.command("edit <name>").description("Open an existing skill in $EDITOR").a
89
89
  });
90
90
  var home = program.command("home").description("Manage a personal GitHub repo for backing up your skills manifest");
91
91
  home.command("set <repo>").description("Set the home repo e.g. augy home set alice/my-skills").option("--path <file>", "Manifest path within the repo (default: augy.json)").option("--skills-path <dir>", "Dir for authored skills in the repo (default: skills)").action(async (repo, opts) => {
92
- const { homeSetCommand } = await import("./home-TWK3PMCL.js");
92
+ const { homeSetCommand } = await import("./home-AEZ5IVC3.js");
93
93
  await homeSetCommand(repo, opts);
94
94
  });
95
95
  home.command("push").description("Push your installed skills manifest to the home repo").action(async () => {
96
- const { homePushCommand } = await import("./home-TWK3PMCL.js");
96
+ const { homePushCommand } = await import("./home-AEZ5IVC3.js");
97
97
  await homePushCommand();
98
98
  });
99
99
  home.command("pull").description("Fetch the manifest from the home repo and sync skills").option("--dry-run", "Preview changes without applying them").option("-a, --agent <agents...>", "Target agent(s) (default: all detected)").action(async (opts) => {
100
- const { homePullCommand } = await import("./home-TWK3PMCL.js");
100
+ const { homePullCommand } = await import("./home-AEZ5IVC3.js");
101
101
  await homePullCommand(opts);
102
102
  });
103
103
  home.command("show").description("Show the current home repo configuration").action(async () => {
104
- const { homeShowCommand } = await import("./home-TWK3PMCL.js");
104
+ const { homeShowCommand } = await import("./home-AEZ5IVC3.js");
105
105
  await homeShowCommand();
106
106
  });
107
107
  program.action(async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@callmeradical/augy",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Homebrew for AI agent skills — install, version, update, rollback",
5
5
  "type": "module",
6
6
  "license": "MIT",