pi-interactive-shell 0.5.1 → 0.5.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/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  All notable changes to the `pi-interactive-shell` extension will be documented in this file.
4
4
 
5
+ ## [0.5.2] - 2026-01-23
6
+
7
+ ### Fixed
8
+ - **npx installation missing files** - The install script had a hardcoded file list that was missing 4 critical files (`key-encoding.ts`, `types.ts`, `tool-schema.ts`, `reattach-overlay.ts`). Now reads from `package.json`'s `files` array as the single source of truth, ensuring all files are always copied.
9
+ - **Broken symlink handling** - Fixed skill symlink creation failing when a broken symlink already existed at the target path. `existsSync()` returns `false` for broken symlinks, causing the old code to skip removal. Now unconditionally attempts removal, correctly handling broken symlinks.
10
+
5
11
  ## [0.5.1] - 2026-01-22
6
12
 
7
13
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-interactive-shell",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "Run AI coding agents as foreground subagents in pi TUI overlays with hands-free monitoring",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { existsSync, mkdirSync, cpSync, symlinkSync, unlinkSync, readFileSync } from "node:fs";
3
+ import { existsSync, mkdirSync, cpSync, symlinkSync, unlinkSync, readFileSync, statSync } from "node:fs";
4
4
  import { join, dirname } from "node:path";
5
5
  import { homedir } from "node:os";
6
6
  import { execSync } from "node:child_process";
@@ -24,36 +24,34 @@ function main() {
24
24
  log(`Creating ${EXTENSION_DIR}`);
25
25
  mkdirSync(EXTENSION_DIR, { recursive: true });
26
26
 
27
- // Files to copy
28
- const files = [
29
- "package.json",
30
- "index.ts",
31
- "config.ts",
32
- "overlay-component.ts",
33
- "pty-session.ts",
34
- "session-manager.ts",
35
- "README.md",
36
- "SKILL.md",
37
- "CHANGELOG.md",
38
- ];
27
+ // Read files list from package.json (single source of truth)
28
+ // Include package.json itself (npm auto-includes it but it's not in the files array)
29
+ const files = ["package.json", ...(pkg.files || [])];
39
30
 
40
- // Copy files
41
- for (const file of files) {
42
- const src = join(packageRoot, file);
43
- const dest = join(EXTENSION_DIR, file);
44
- if (existsSync(src)) {
45
- cpSync(src, dest);
46
- log(`Copied ${file}`);
31
+ // Copy files and directories
32
+ for (const rawEntry of files) {
33
+ // Normalize: remove trailing slashes for consistent handling
34
+ const entry = rawEntry.replace(/\/+$/, "");
35
+ const src = join(packageRoot, entry);
36
+ const dest = join(EXTENSION_DIR, entry);
37
+
38
+ if (!existsSync(src)) {
39
+ continue;
47
40
  }
48
- }
49
41
 
50
- // Copy scripts directory
51
- const scriptsDir = join(packageRoot, "scripts");
52
- const destScriptsDir = join(EXTENSION_DIR, "scripts");
53
- if (existsSync(scriptsDir)) {
54
- mkdirSync(destScriptsDir, { recursive: true });
55
- cpSync(scriptsDir, destScriptsDir, { recursive: true });
56
- log("Copied scripts/");
42
+ try {
43
+ const stat = statSync(src);
44
+ if (stat.isDirectory()) {
45
+ mkdirSync(dest, { recursive: true });
46
+ cpSync(src, dest, { recursive: true });
47
+ log(`Copied ${entry}/`);
48
+ } else {
49
+ cpSync(src, dest);
50
+ log(`Copied ${entry}`);
51
+ }
52
+ } catch (error) {
53
+ log(`Warning: Could not copy ${entry}: ${error.message}`);
54
+ }
57
55
  }
58
56
 
59
57
  // Run npm install in extension directory
@@ -72,8 +70,12 @@ function main() {
72
70
  const skillTarget = join(EXTENSION_DIR, "SKILL.md");
73
71
 
74
72
  try {
75
- if (existsSync(skillLink)) {
73
+ // Remove existing entry if present (handles regular files, symlinks, and broken symlinks)
74
+ // Note: existsSync returns false for broken symlinks, so we unconditionally try unlink
75
+ try {
76
76
  unlinkSync(skillLink);
77
+ } catch (e) {
78
+ if (e.code !== "ENOENT") throw e;
77
79
  }
78
80
  symlinkSync(skillTarget, skillLink);
79
81
  log("Skill symlink created");