@quolu/aishell 0.4.3 → 0.4.4

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.ja.md CHANGED
@@ -90,7 +90,12 @@ flowchart LR
90
90
 
91
91
  ## npmからinstall
92
92
 
93
- global packageは`aishell-mcp`と`aishell-open`を`PATH`へ追加する。`aishell-open`は同梱された管理アプリをLaunchServicesで開く。install scriptは実行しない。
93
+ global packageは`aishell-mcp`と`aishell-open`を`PATH`へ追加する。`aishell-open`は同梱された管理アプリをLaunchServicesで開く。
94
+
95
+ install scriptは助言専用の`postinstall`検査だけである。今回のinstallで置き換えられるinstallから
96
+ 管理アプリの窓がまだ動いている場合に警告する。その窓は削除済みbundleを掴み続け、ファイル選択を
97
+ 伴う操作を無言で失うためである。検査はprocess一覧を読んで該当pidを表示するだけで、何も書き込まず、
98
+ installを失敗させない。窓を開き直せば新版に移る。窓自身も置換を検知して表示する。
94
99
 
95
100
  ```sh
96
101
  npm install -g @quolu/aishell
package/README.md CHANGED
@@ -88,7 +88,13 @@ flowchart LR
88
88
 
89
89
  ## Install from npm
90
90
 
91
- The global package adds `aishell-mcp` and `aishell-open` to `PATH`. `aishell-open` opens the bundled manager app through LaunchServices. The package runs no install script.
91
+ The global package adds `aishell-mcp` and `aishell-open` to `PATH`. `aishell-open` opens the bundled manager app through LaunchServices.
92
+
93
+ The only install script is an advisory `postinstall` check. It warns when a manager window is still
94
+ running from the install this one replaces, because such a window keeps holding a deleted bundle and
95
+ silently loses every operation that opens a file panel. The check reads the process list, prints the
96
+ affected pids, writes nothing, and never fails the install. Reopen the window to pick up the new
97
+ version; the window itself also detects the replacement and says so.
92
98
 
93
99
  ```sh
94
100
  npm install -g @quolu/aishell
@@ -17,9 +17,9 @@
17
17
  <key>CFBundlePackageType</key>
18
18
  <string>APPL</string>
19
19
  <key>CFBundleShortVersionString</key>
20
- <string>0.4.3</string>
20
+ <string>0.4.4</string>
21
21
  <key>CFBundleVersion</key>
22
- <string>14</string>
22
+ <string>15</string>
23
23
  <key>LSApplicationCategoryType</key>
24
24
  <string>public.app-category.utilities</string>
25
25
  <key>LSMinimumSystemVersion</key>
@@ -10,19 +10,19 @@
10
10
  <dict>
11
11
  <key>cdhash</key>
12
12
  <data>
13
- oFfflOEgv+pXYnE8/ZukkT/b4RY=
13
+ 62lLj6uPM5cPENNgG2IlBMPjEiQ=
14
14
  </data>
15
15
  <key>requirement</key>
16
- <string>cdhash H"a057df94e120bfea5762713cfd9ba4913fdbe116"</string>
16
+ <string>cdhash H"eb694b8fab8f33970f10d3601b622504c3e31224"</string>
17
17
  </dict>
18
18
  <key>Helpers/aishell-run-supervisor</key>
19
19
  <dict>
20
20
  <key>cdhash</key>
21
21
  <data>
22
- pjz+O5pncMYZJTTY0tVWp3i0hck=
22
+ 08JZvJ0KKUPCwBJJHo5i6fR6r68=
23
23
  </data>
24
24
  <key>requirement</key>
25
- <string>cdhash H"a63cfe3b9a6770c6192534d8d2d556a778b485c9"</string>
25
+ <string>cdhash H"d3c259bc9d0a2943c2c012491e8e62e9f47aafaf"</string>
26
26
  </dict>
27
27
  </dict>
28
28
  <key>rules</key>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quolu/aishell",
3
- "version": "0.4.3",
3
+ "version": "0.4.4",
4
4
  "description": "A native macOS state runtime with high-density MCP tools for AI development",
5
5
  "license": "Apache-2.0",
6
6
  "author": "quolu",
@@ -32,11 +32,13 @@
32
32
  "files": [
33
33
  "dist/AIShell.app",
34
34
  "scripts/aishell-open.mjs",
35
+ "scripts/check-running-instances.mjs",
35
36
  "README.md"
36
37
  ],
37
38
  "scripts": {
38
39
  "build:npm": "node scripts/prepare-npm-release.mjs",
39
40
  "prepack": "npm run build:npm",
41
+ "postinstall": "node scripts/check-running-instances.mjs",
40
42
  "test": "swift test",
41
43
  "test:package": "npm run build:npm && node scripts/verify-npm-package.mjs",
42
44
  "verify:release-commit": "node scripts/verify-release-commit.mjs",
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env node
2
+
3
+ // npm global upgradeは既存packageを`@quolu/.aishell-XXXX`へrenameしてから削除する。窓を開いたまま
4
+ // upgradeすると、そのprocessは消えた実体を掴み続け、UIは動くのにbundle resourceを要求するAPI
5
+ // (NSOpenPanelなど)だけが無反応になる。errorも出ないため「rootを追加できない」と見える。
6
+ // install時点でその窓を見つけて再起動を促す。app側の自己検知(AIShellCore/InstallationIntegrity)
7
+ // と二重の網であり、どちらもinstall自体は止めない。
8
+
9
+ import { spawnSync } from "node:child_process";
10
+ import { existsSync } from "node:fs";
11
+ import path from "node:path";
12
+ import { fileURLToPath } from "node:url";
13
+
14
+ const executablePattern = /^(\d+)\s+(\/.*\/AIShell\.app\/Contents\/MacOS\/AIShell)$/;
15
+ // renameで退避された旧installのpath。実体が残っていてもそのbundleは削除される途中にある。
16
+ const stagingPathPattern = /\/\.aishell-[^/]+\//;
17
+
18
+ /// `ps -axo pid=,comm=`の出力から、置換済みの実体を掴んだ窓だけを選ぶ。
19
+ /// 生きているinstallのpathから動いている窓は対象にしない(localのnpm installで誤警告しないため)。
20
+ export function selectStaleWindows(processListing, { exists = existsSync } = {}) {
21
+ return processListing
22
+ .split("\n")
23
+ .flatMap((line) => {
24
+ const matched = line.trim().match(executablePattern);
25
+ return matched ? [{ pid: Number(matched[1]), executable: matched[2] }] : [];
26
+ })
27
+ .filter(({ executable }) => !exists(executable) || stagingPathPattern.test(executable));
28
+ }
29
+
30
+ export function staleWindowWarning(stale) {
31
+ const pidList = stale.map(({ pid }) => `pid ${pid}`).join(", ");
32
+ return [
33
+ "",
34
+ `[AIShell] 起動中の窓(${pidList})が、このinstallで置き換えられた実体を掴んでいます。`,
35
+ " そのままではrootの追加などファイル選択を伴う操作が無反応になります。",
36
+ " 窓を終了して `aishell-open` で開き直してください。",
37
+ ""
38
+ ].join("\n");
39
+ }
40
+
41
+ function main() {
42
+ const listing = spawnSync("/bin/ps", ["-axo", "pid=,comm="], { encoding: "utf8" });
43
+
44
+ if (listing.error || listing.status !== 0) {
45
+ // 確認できなかったことを「問題なし」へ言い換えない。
46
+ console.warn(
47
+ "[AIShell] 起動中の窓を確認できませんでした(psが利用できません)。" +
48
+ "AIShellを開いたままupgradeした場合は、窓を開き直してください。"
49
+ );
50
+ return;
51
+ }
52
+
53
+ const stale = selectStaleWindows(listing.stdout);
54
+ if (stale.length > 0) {
55
+ console.warn(staleWindowWarning(stale));
56
+ }
57
+ }
58
+
59
+ if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
60
+ main();
61
+ }