@quolu/aishell 0.1.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.
- package/README.md +71 -0
- package/dist/AIShell.app/Contents/Helpers/aishell-mcp +0 -0
- package/dist/AIShell.app/Contents/Info.plist +32 -0
- package/dist/AIShell.app/Contents/MacOS/AIShell +0 -0
- package/dist/AIShell.app/Contents/_CodeSignature/CodeResources +125 -0
- package/package.json +49 -0
- package/scripts/install-npm-app.mjs +63 -0
package/README.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# AIShell
|
|
2
|
+
|
|
3
|
+
AIがshell、Terminal、AppleScript、JXAを介さず、SwiftのmacOS APIを通してOSを直接操作する実験プロジェクト。
|
|
4
|
+
|
|
5
|
+
## 現在できること
|
|
6
|
+
|
|
7
|
+
- 許可フォルダ内の一覧、検索、UTF-8テキスト読取
|
|
8
|
+
- フォルダ/テキスト作成、copy、move、rename、Trash
|
|
9
|
+
- stat、SHA-256、再帰tree
|
|
10
|
+
- SHA-256競合検出付き原子的更新、旧テキストを事前条件にした部分置換
|
|
11
|
+
- executable URLと引数配列による開発プログラムの直接実行
|
|
12
|
+
- working directory、環境変数、timeout、stdout、stderr、終了コードの取得
|
|
13
|
+
- 実行中/インストール済みアプリの一覧
|
|
14
|
+
- bundle identifierによるアプリ起動・前面化
|
|
15
|
+
- 管理アプリから許可フォルダ選択、全停止、操作履歴確認
|
|
16
|
+
- MCP 2025-11-25 stdio接続
|
|
17
|
+
|
|
18
|
+
## 起動
|
|
19
|
+
|
|
20
|
+
### npmからインストール
|
|
21
|
+
|
|
22
|
+
対応環境はApple Silicon Mac、macOS 15以降。
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
npm install -g @quolu/aishell
|
|
26
|
+
open ~/Applications/AIShell.app
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
global installは `AIShell.app` を `~/Applications` へ配置し、`aishell-mcp` コマンドをPATHへ追加する。現在はDeveloper ID署名・notarization前の実験版である。
|
|
30
|
+
|
|
31
|
+
### ソースから起動
|
|
32
|
+
|
|
33
|
+
ローカル成果物は `build/AIShell.app`。Finderから通常のMacアプリとして起動できる。
|
|
34
|
+
|
|
35
|
+
最初に「フォルダを選択」でAIに操作させる範囲を選ぶ。停止中はMCPからのファイル操作とアプリ操作をどちらも拒否する。
|
|
36
|
+
|
|
37
|
+
MCP実行ファイルはアプリ内に同梱される。
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
/Users/kite/Developer/aishell/build/AIShell.app/Contents/Helpers/aishell-mcp
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## 別のCodexタスクから使う
|
|
44
|
+
|
|
45
|
+
個人用のグローバルMCPとして登録する。npm版ではPATH上の絶対パスを指定する。
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
codex mcp add aishell -- /opt/homebrew/bin/aishell-mcp
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
このMacでは登録済み。新しく開始したCodexタスクから `aishell` の19ツールを利用できる。操作を許可するときは `AIShell.app` を開いて対象フォルダを確認し、「AI操作を再開」を押す。停止中も `runtime_status` は使えるが、ファイル、アプリ、process操作は拒否される。
|
|
52
|
+
|
|
53
|
+
登録確認と解除は次のとおり。
|
|
54
|
+
|
|
55
|
+
```text
|
|
56
|
+
codex mcp get aishell
|
|
57
|
+
codex mcp remove aishell
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## 開発検証
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
swift test
|
|
64
|
+
scripts/package-app.sh release
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`xcodegen generate` で `AIShell.xcodeproj` を再生成できる。現在の検証機ではXcode 26.6とCoreSimulatorのbuild versionが一致せず、`xcodebuild` はXCBuild開始待ちで停止するため、同じSwift 6.3.3 toolchainを使うSwiftPMでビルド・テストした。この環境問題はソースの成功扱いへ混ぜていない。
|
|
68
|
+
|
|
69
|
+
## 実装上の禁止事項
|
|
70
|
+
|
|
71
|
+
`AIShellCore` と `AIShellMCP` は、shell、AppleScript、JXA、コマンド文字列を実行しない。開発プログラムは実行ファイルの絶対パスと引数配列を分離したままmacOSのprocess APIへ渡し、shell本体の起動、パイプ、リダイレクト、shell展開を拒否する。MCPは型付き要求をmacOSネイティブAPIへ渡すアダプターである。
|
|
Binary file
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>CFBundleDevelopmentRegion</key>
|
|
6
|
+
<string>ja</string>
|
|
7
|
+
<key>CFBundleDisplayName</key>
|
|
8
|
+
<string>AIShell</string>
|
|
9
|
+
<key>CFBundleExecutable</key>
|
|
10
|
+
<string>AIShell</string>
|
|
11
|
+
<key>CFBundleIdentifier</key>
|
|
12
|
+
<string>dev.kite.aishell</string>
|
|
13
|
+
<key>CFBundleInfoDictionaryVersion</key>
|
|
14
|
+
<string>6.0</string>
|
|
15
|
+
<key>CFBundleName</key>
|
|
16
|
+
<string>AIShell</string>
|
|
17
|
+
<key>CFBundlePackageType</key>
|
|
18
|
+
<string>APPL</string>
|
|
19
|
+
<key>CFBundleShortVersionString</key>
|
|
20
|
+
<string>0.1.0</string>
|
|
21
|
+
<key>CFBundleVersion</key>
|
|
22
|
+
<string>1</string>
|
|
23
|
+
<key>LSApplicationCategoryType</key>
|
|
24
|
+
<string>public.app-category.utilities</string>
|
|
25
|
+
<key>LSMinimumSystemVersion</key>
|
|
26
|
+
<string>15.0</string>
|
|
27
|
+
<key>NSHighResolutionCapable</key>
|
|
28
|
+
<true/>
|
|
29
|
+
<key>NSPrincipalClass</key>
|
|
30
|
+
<string>NSApplication</string>
|
|
31
|
+
</dict>
|
|
32
|
+
</plist>
|
|
Binary file
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>files</key>
|
|
6
|
+
<dict/>
|
|
7
|
+
<key>files2</key>
|
|
8
|
+
<dict>
|
|
9
|
+
<key>Helpers/aishell-mcp</key>
|
|
10
|
+
<dict>
|
|
11
|
+
<key>cdhash</key>
|
|
12
|
+
<data>
|
|
13
|
+
koF5aqCXOuiIDbAFGjF42v8yWDo=
|
|
14
|
+
</data>
|
|
15
|
+
<key>requirement</key>
|
|
16
|
+
<string>cdhash H"9281796aa0973ae8880db0051a3178daff32583a"</string>
|
|
17
|
+
</dict>
|
|
18
|
+
</dict>
|
|
19
|
+
<key>rules</key>
|
|
20
|
+
<dict>
|
|
21
|
+
<key>^Resources/</key>
|
|
22
|
+
<true/>
|
|
23
|
+
<key>^Resources/.*\.lproj/</key>
|
|
24
|
+
<dict>
|
|
25
|
+
<key>optional</key>
|
|
26
|
+
<true/>
|
|
27
|
+
<key>weight</key>
|
|
28
|
+
<real>1000</real>
|
|
29
|
+
</dict>
|
|
30
|
+
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
|
31
|
+
<dict>
|
|
32
|
+
<key>omit</key>
|
|
33
|
+
<true/>
|
|
34
|
+
<key>weight</key>
|
|
35
|
+
<real>1100</real>
|
|
36
|
+
</dict>
|
|
37
|
+
<key>^Resources/Base\.lproj/</key>
|
|
38
|
+
<dict>
|
|
39
|
+
<key>weight</key>
|
|
40
|
+
<real>1010</real>
|
|
41
|
+
</dict>
|
|
42
|
+
<key>^version.plist$</key>
|
|
43
|
+
<true/>
|
|
44
|
+
</dict>
|
|
45
|
+
<key>rules2</key>
|
|
46
|
+
<dict>
|
|
47
|
+
<key>.*\.dSYM($|/)</key>
|
|
48
|
+
<dict>
|
|
49
|
+
<key>weight</key>
|
|
50
|
+
<real>11</real>
|
|
51
|
+
</dict>
|
|
52
|
+
<key>^(.*/)?\.DS_Store$</key>
|
|
53
|
+
<dict>
|
|
54
|
+
<key>omit</key>
|
|
55
|
+
<true/>
|
|
56
|
+
<key>weight</key>
|
|
57
|
+
<real>2000</real>
|
|
58
|
+
</dict>
|
|
59
|
+
<key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
|
|
60
|
+
<dict>
|
|
61
|
+
<key>nested</key>
|
|
62
|
+
<true/>
|
|
63
|
+
<key>weight</key>
|
|
64
|
+
<real>10</real>
|
|
65
|
+
</dict>
|
|
66
|
+
<key>^.*</key>
|
|
67
|
+
<true/>
|
|
68
|
+
<key>^Info\.plist$</key>
|
|
69
|
+
<dict>
|
|
70
|
+
<key>omit</key>
|
|
71
|
+
<true/>
|
|
72
|
+
<key>weight</key>
|
|
73
|
+
<real>20</real>
|
|
74
|
+
</dict>
|
|
75
|
+
<key>^PkgInfo$</key>
|
|
76
|
+
<dict>
|
|
77
|
+
<key>omit</key>
|
|
78
|
+
<true/>
|
|
79
|
+
<key>weight</key>
|
|
80
|
+
<real>20</real>
|
|
81
|
+
</dict>
|
|
82
|
+
<key>^Resources/</key>
|
|
83
|
+
<dict>
|
|
84
|
+
<key>weight</key>
|
|
85
|
+
<real>20</real>
|
|
86
|
+
</dict>
|
|
87
|
+
<key>^Resources/.*\.lproj/</key>
|
|
88
|
+
<dict>
|
|
89
|
+
<key>optional</key>
|
|
90
|
+
<true/>
|
|
91
|
+
<key>weight</key>
|
|
92
|
+
<real>1000</real>
|
|
93
|
+
</dict>
|
|
94
|
+
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
|
95
|
+
<dict>
|
|
96
|
+
<key>omit</key>
|
|
97
|
+
<true/>
|
|
98
|
+
<key>weight</key>
|
|
99
|
+
<real>1100</real>
|
|
100
|
+
</dict>
|
|
101
|
+
<key>^Resources/Base\.lproj/</key>
|
|
102
|
+
<dict>
|
|
103
|
+
<key>weight</key>
|
|
104
|
+
<real>1010</real>
|
|
105
|
+
</dict>
|
|
106
|
+
<key>^[^/]+$</key>
|
|
107
|
+
<dict>
|
|
108
|
+
<key>nested</key>
|
|
109
|
+
<true/>
|
|
110
|
+
<key>weight</key>
|
|
111
|
+
<real>10</real>
|
|
112
|
+
</dict>
|
|
113
|
+
<key>^embedded\.provisionprofile$</key>
|
|
114
|
+
<dict>
|
|
115
|
+
<key>weight</key>
|
|
116
|
+
<real>20</real>
|
|
117
|
+
</dict>
|
|
118
|
+
<key>^version\.plist$</key>
|
|
119
|
+
<dict>
|
|
120
|
+
<key>weight</key>
|
|
121
|
+
<real>20</real>
|
|
122
|
+
</dict>
|
|
123
|
+
</dict>
|
|
124
|
+
</dict>
|
|
125
|
+
</plist>
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@quolu/aishell",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A native macOS MCP server for direct file, app, and development tool operations without a shell",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"author": "quolu",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/kitepon-rgb/aishell.git"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/kitepon-rgb/aishell/issues"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/kitepon-rgb/aishell#readme",
|
|
15
|
+
"keywords": [
|
|
16
|
+
"mcp",
|
|
17
|
+
"macos",
|
|
18
|
+
"swift",
|
|
19
|
+
"ai",
|
|
20
|
+
"automation"
|
|
21
|
+
],
|
|
22
|
+
"os": [
|
|
23
|
+
"darwin"
|
|
24
|
+
],
|
|
25
|
+
"cpu": [
|
|
26
|
+
"arm64"
|
|
27
|
+
],
|
|
28
|
+
"bin": {
|
|
29
|
+
"aishell-mcp": "dist/AIShell.app/Contents/Helpers/aishell-mcp"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist/AIShell.app",
|
|
33
|
+
"scripts/install-npm-app.mjs",
|
|
34
|
+
"README.md"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build:npm": "node scripts/prepare-npm-release.mjs",
|
|
38
|
+
"prepack": "npm run build:npm",
|
|
39
|
+
"postinstall": "node scripts/install-npm-app.mjs",
|
|
40
|
+
"test": "swift test",
|
|
41
|
+
"test:package": "npm run build:npm && node scripts/verify-npm-package.mjs"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18"
|
|
45
|
+
},
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { access, mkdir, rename, rm } from "node:fs/promises";
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
import os from "node:os";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
|
|
9
|
+
if (process.env.npm_config_global !== "true") {
|
|
10
|
+
console.log("AIShell.app installation skipped because this is not a global npm install.");
|
|
11
|
+
process.exit(0);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const scriptDirectory = path.dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const packageDirectory = path.dirname(scriptDirectory);
|
|
16
|
+
const sourceApp = path.join(packageDirectory, "dist", "AIShell.app");
|
|
17
|
+
const applicationsDirectory = process.env.AISHELL_APPLICATIONS_DIR
|
|
18
|
+
? path.resolve(process.env.AISHELL_APPLICATIONS_DIR)
|
|
19
|
+
: path.join(os.homedir(), "Applications");
|
|
20
|
+
const targetApp = path.join(applicationsDirectory, "AIShell.app");
|
|
21
|
+
const temporaryApp = path.join(applicationsDirectory, `.AIShell.installing-${process.pid}.app`);
|
|
22
|
+
const previousApp = path.join(applicationsDirectory, "AIShell.previous.app");
|
|
23
|
+
|
|
24
|
+
await access(sourceApp);
|
|
25
|
+
await mkdir(applicationsDirectory, { recursive: true });
|
|
26
|
+
await rm(temporaryApp, { recursive: true, force: true });
|
|
27
|
+
|
|
28
|
+
const copy = spawnSync("/usr/bin/ditto", [sourceApp, temporaryApp], {
|
|
29
|
+
stdio: "inherit"
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
if (copy.error) {
|
|
33
|
+
throw copy.error;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (copy.status !== 0) {
|
|
37
|
+
throw new Error(`AIShell.app copy failed with status ${copy.status}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let hadPreviousInstallation = false;
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
await access(targetApp);
|
|
44
|
+
hadPreviousInstallation = true;
|
|
45
|
+
} catch {
|
|
46
|
+
hadPreviousInstallation = false;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (hadPreviousInstallation) {
|
|
50
|
+
await rm(previousApp, { recursive: true, force: true });
|
|
51
|
+
await rename(targetApp, previousApp);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
await rename(temporaryApp, targetApp);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
if (hadPreviousInstallation) {
|
|
58
|
+
await rename(previousApp, targetApp);
|
|
59
|
+
}
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
console.log(`Installed AIShell.app at ${targetApp}`);
|