patchcord 0.3.48 → 0.3.50

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/bin/patchcord.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { existsSync, mkdirSync, cpSync } from "fs";
3
+ import { existsSync, mkdirSync, cpSync, readdirSync } from "fs";
4
4
  import { join, dirname } from "path";
5
5
  import { fileURLToPath } from "url";
6
6
  import { execSync } from "child_process";
@@ -35,6 +35,29 @@ function isSafeId(s) {
35
35
  return /^[A-Za-z0-9_\-]+$/.test(s) && s.length < 100;
36
36
  }
37
37
 
38
+ const PROJECT_MARKERS = [
39
+ ".git", "package.json", "package-lock.json", "Cargo.toml", "go.mod", "go.sum",
40
+ "pyproject.toml", "pom.xml", "build.gradle", "Makefile", "CMakeLists.txt",
41
+ "Gemfile", "composer.json", "mix.exs", "requirements.txt", "setup.py",
42
+ ".claude", ".codex", ".cursor", ".vscode",
43
+ ];
44
+
45
+ function detectFolder(dir) {
46
+ if (dir === HOME || dir === HOME + "/" || dir === "/") return "HOME";
47
+ for (const m of PROJECT_MARKERS) {
48
+ if (existsSync(join(dir, m))) return "PROJECT";
49
+ }
50
+ let entries;
51
+ try {
52
+ entries = readdirSync(dir, { withFileTypes: true });
53
+ } catch { return "UNKNOWN"; }
54
+ if (entries.length === 0) return "EMPTY";
55
+ const files = entries.filter(e => e.isFile());
56
+ const dirs = entries.filter(e => e.isDirectory());
57
+ if (files.length === 0 && dirs.length >= 2) return "CONTAINER";
58
+ return "UNKNOWN";
59
+ }
60
+
38
61
 
39
62
  if (cmd === "help" || cmd === "--help" || cmd === "-h") {
40
63
  console.log(`patchcord — agent messaging for AI coding agents
@@ -258,7 +281,30 @@ if (!cmd || cmd === "install" || cmd === "agent") {
258
281
  const toolLabel = isZed ? "Zed" : isWindsurf ? "Windsurf" : "Gemini CLI";
259
282
  console.log(`\n ${yellow}Note: ${toolLabel} uses global config — applies to all projects.${r}`);
260
283
  } else {
261
- console.log(`\n${dim}Project:${r} ${bold}${cwd}${r}`);
284
+ const folderType = detectFolder(cwd);
285
+ const folderName = cwd.split("/").pop() || cwd.split("\\").pop() || cwd;
286
+
287
+ if (folderType === "HOME") {
288
+ console.log(`\n ${red}✗ You're in your home folder.${r}`);
289
+ console.log(` ${yellow}Patchcord must be installed inside a project folder —${r}`);
290
+ console.log(` ${yellow}the folder where your agent actually runs.${r}`);
291
+ console.log(` ${dim}cd into your project first, then run this again.${r}`);
292
+ rl.close();
293
+ process.exit(0);
294
+ } else if (folderType === "CONTAINER") {
295
+ console.log(`\n ${yellow}⚠ This looks like a projects container, not a project.${r}`);
296
+ console.log(` ${dim}${cwd}${r}`);
297
+ console.log(` ${dim}Patchcord should be installed inside a project, not the folder above it.${r}`);
298
+ const proceed = (await ask(` ${dim}Set up here anyway? (y/N):${r} `)).trim().toLowerCase();
299
+ if (proceed !== "y" && proceed !== "yes") {
300
+ console.log(` ${dim}cd into your project and run this again.${r}`);
301
+ rl.close();
302
+ process.exit(0);
303
+ }
304
+ }
305
+
306
+ console.log(`\n ${dim}Agent identity:${r} ${bold}${folderName}${r}`);
307
+ console.log(` ${dim}Folder:${r} ${cwd}`);
262
308
  }
263
309
 
264
310
 
@@ -732,6 +778,12 @@ if (!cmd || cmd === "install" || cmd === "agent") {
732
778
  }
733
779
 
734
780
  const toolName = isOpenCode ? "OpenCode" : isZed ? "Zed" : isVSCode ? "VS Code" : isGemini ? "Gemini CLI" : isWindsurf ? "Windsurf" : isCursor ? "Cursor" : isCodex ? "Codex" : "Claude Code";
781
+
782
+ if (!isWindsurf && !isGemini && !isZed) {
783
+ console.log(`\n ${dim}To connect a second agent:${r}`);
784
+ console.log(` ${dim}cd into another project and run${r} ${bold}npx patchcord@latest${r} ${dim}there.${r}`);
785
+ }
786
+
735
787
  console.log(`\n${dim}Restart your ${toolName} session, then run:${r} ${bold}inbox()${r}`);
736
788
  process.exit(0);
737
789
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patchcord",
3
- "version": "0.3.48",
3
+ "version": "0.3.50",
4
4
  "description": "Cross-machine agent messaging for Claude Code and Codex",
5
5
  "author": "ppravdin",
6
6
  "license": "MIT",
@@ -13,16 +13,22 @@ for arg in "$@"; do
13
13
  [ "$arg" = "--full" ] && EXTRA_ARGS=" --full"
14
14
  done
15
15
 
16
- # Find the statusline script path
16
+ # Copy statusline.sh to a stable location (npx cache can be cleared)
17
17
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
18
- STATUSLINE="$SCRIPT_DIR/statusline.sh"
18
+ SRC_STATUSLINE="$SCRIPT_DIR/statusline.sh"
19
+ STABLE_DIR="$HOME/.claude/patchcord"
20
+ STABLE_STATUSLINE="$STABLE_DIR/statusline.sh"
19
21
 
20
- if [ ! -f "$STATUSLINE" ]; then
21
- echo "Error: statusline.sh not found at $STATUSLINE" >&2
22
+ if [ ! -f "$SRC_STATUSLINE" ]; then
23
+ echo "Error: statusline.sh not found at $SRC_STATUSLINE" >&2
22
24
  exit 1
23
25
  fi
24
26
 
25
- NEW_CMD="bash \"$STATUSLINE\"${EXTRA_ARGS}"
27
+ mkdir -p "$STABLE_DIR"
28
+ cp "$SRC_STATUSLINE" "$STABLE_STATUSLINE"
29
+ chmod +x "$STABLE_STATUSLINE"
30
+
31
+ NEW_CMD="bash \"$STABLE_STATUSLINE\"${EXTRA_ARGS}"
26
32
 
27
33
  # Decide where to write
28
34
  USER_SETTINGS="$HOME/.claude/settings.json"