@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 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へ渡すアダプターである。
@@ -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>
@@ -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}`);