heyio 1.2.2 → 1.2.3

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,7 +1,9 @@
1
1
  import { existsSync, readdirSync, readFileSync, rmSync } from "node:fs";
2
2
  import { join, basename } from "node:path";
3
- import { execSync } from "node:child_process";
3
+ import { exec } from "node:child_process";
4
+ import { promisify } from "node:util";
4
5
  import { PATHS } from "../paths.js";
6
+ const execAsync = promisify(exec);
5
7
  export async function listSkills() {
6
8
  if (!existsSync(PATHS.skills))
7
9
  return [];
@@ -35,7 +37,7 @@ export async function addSkill(url) {
35
37
  if (existsSync(dest)) {
36
38
  throw new Error(`Skill "${slug}" is already installed.`);
37
39
  }
38
- execSync(`git clone --depth 1 ${url} ${dest}`, { stdio: "pipe" });
40
+ await execAsync(`git clone --depth 1 ${url} ${dest}`);
39
41
  // Verify SKILL.md exists
40
42
  if (!existsSync(join(dest, "SKILL.md"))) {
41
43
  rmSync(dest, { recursive: true, force: true });
@@ -69,10 +69,12 @@ export function createTools() {
69
69
  const squad = createSquad(name, universe, repo_url);
70
70
  let cloneMsg = "";
71
71
  if (repo_url) {
72
- const { execSync } = await import("node:child_process");
72
+ const { exec } = await import("node:child_process");
73
+ const { promisify } = await import("node:util");
73
74
  const { existsSync, mkdirSync } = await import("node:fs");
74
75
  const { join } = await import("node:path");
75
76
  const { PATHS } = await import("../paths.js");
77
+ const execAsync = promisify(exec);
76
78
  // Extract owner/repo from URL (supports https and git@ formats)
77
79
  const match = repo_url.match(/[/:]([^/]+)\/([^/.]+?)(?:\.git)?$/);
78
80
  if (match) {
@@ -83,8 +85,7 @@ export function createTools() {
83
85
  if (!existsSync(parentDir))
84
86
  mkdirSync(parentDir, { recursive: true });
85
87
  try {
86
- execSync(`git clone ${repo_url} ${sourceDir}`, {
87
- encoding: "utf-8",
88
+ await execAsync(`git clone ${repo_url} ${sourceDir}`, {
88
89
  timeout: 120_000,
89
90
  });
90
91
  cloneMsg = ` Repo cloned to ~/.io/source/${owner}/${repo}.`;
@@ -313,22 +314,23 @@ export function createTools() {
313
314
  cwd: z.string().optional().describe("Working directory (defaults to home directory)"),
314
315
  }),
315
316
  handler: async ({ command, cwd }) => {
316
- const { execSync } = await import("node:child_process");
317
+ const { exec } = await import("node:child_process");
318
+ const { promisify } = await import("node:util");
317
319
  const { homedir } = await import("node:os");
320
+ const execAsync = promisify(exec);
318
321
  try {
319
- const output = execSync(command, {
322
+ const { stdout } = await execAsync(command, {
320
323
  cwd: cwd ?? homedir(),
321
- encoding: "utf-8",
322
324
  timeout: 60_000,
323
325
  maxBuffer: 1024 * 1024,
324
326
  env: { ...process.env, GH_PROMPT_DISABLED: "1" },
325
327
  });
326
- return output.trim() || "(no output)";
328
+ return stdout.trim() || "(no output)";
327
329
  }
328
330
  catch (err) {
329
331
  const stderr = err.stderr?.toString().trim() ?? "";
330
332
  const stdout = err.stdout?.toString().trim() ?? "";
331
- return `Error (exit ${err.status}): ${stderr || stdout || err.message}`;
333
+ return `Error (exit ${err.code}): ${stderr || stdout || err.message}`;
332
334
  }
333
335
  },
334
336
  }),
@@ -1,6 +1,8 @@
1
1
  import { randomUUID } from "node:crypto";
2
- import { execSync } from "node:child_process";
2
+ import { exec } from "node:child_process";
3
+ import { promisify } from "node:util";
3
4
  import { getDb } from "./db.js";
5
+ const execAsync = promisify(exec);
4
6
  const MAX_INSTANCES_PER_SQUAD = 3;
5
7
  export async function createInstance(squadId, branch) {
6
8
  const db = getDb();
@@ -19,18 +21,13 @@ export async function createInstance(squadId, branch) {
19
21
  const id = randomUUID();
20
22
  const worktreePath = `/tmp/io-worktrees/${squadId}/${branch}`;
21
23
  // Create git worktree
24
+ const repoCwd = squad.repo_url.startsWith("/") ? squad.repo_url : process.cwd();
22
25
  try {
23
- execSync(`git worktree add ${worktreePath} -b ${branch}`, {
24
- cwd: squad.repo_url.startsWith("/") ? squad.repo_url : process.cwd(),
25
- stdio: "pipe",
26
- });
26
+ await execAsync(`git worktree add ${worktreePath} -b ${branch}`, { cwd: repoCwd });
27
27
  }
28
- catch (err) {
28
+ catch {
29
29
  // Branch may already exist
30
- execSync(`git worktree add ${worktreePath} ${branch}`, {
31
- cwd: squad.repo_url.startsWith("/") ? squad.repo_url : process.cwd(),
32
- stdio: "pipe",
33
- });
30
+ await execAsync(`git worktree add ${worktreePath} ${branch}`, { cwd: repoCwd });
34
31
  }
35
32
  db.prepare(`INSERT INTO instances (id, squad_id, branch, worktree_path, status)
36
33
  VALUES (?, ?, ?, ?, 'active')`).run(id, squadId, branch, worktreePath);
@@ -45,9 +42,7 @@ export async function destroyInstance(instanceId) {
45
42
  throw new Error(`Instance ${instanceId} not found.`);
46
43
  // Remove worktree
47
44
  try {
48
- execSync(`git worktree remove ${instance.worktree_path} --force`, {
49
- stdio: "pipe",
50
- });
45
+ await execAsync(`git worktree remove ${instance.worktree_path} --force`);
51
46
  }
52
47
  catch {
53
48
  // Already removed or doesn't exist
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "heyio",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "description": "IO — a personal AI assistant daemon built on the GitHub Copilot SDK",
5
5
  "bin": {
6
6
  "io": "dist/index.js"