@supercode-sh/claude-install-mac 0.1.2 → 0.1.3

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.
@@ -0,0 +1,62 @@
1
+ #!/bin/zsh -f
2
+
3
+ # Installs the recovery trigger into Claude's own local-extension profile. Claude
4
+ # runs the bundled JS patcher in its signed Plugin helper; zsh only coordinates relaunch.
5
+
6
+ sc_configure_recovery_extension() {
7
+ local user_data=${1:A} coordinator_hook=${2:A} extension_source=${3:A} storage_root=${4:A}
8
+ local runtime_version=$5 bootstrap_namespace=$6
9
+ local extension_id=local.supercode-recovery extension_root settings_root target settings_target
10
+ local coordinator_json storage_json runtime_json namespace_json
11
+ local -a existing_names=()
12
+ sc_assert_path "$user_data"
13
+ sc_assert_path "$coordinator_hook"
14
+ sc_assert_path "$extension_source"
15
+ sc_assert_path "$storage_root"
16
+ [[ "$bootstrap_namespace" == .s || "$bootstrap_namespace" == .d || "$bootstrap_namespace" == .e ]] ||
17
+ sc_fail 'Unsupported Claude bootstrap namespace.'
18
+ [[ -n "$runtime_version" ]] || sc_fail 'Claude recovery runtime version is unavailable.'
19
+ [[ -f "$coordinator_hook" && ! -L "$coordinator_hook" ]] || sc_fail 'Claude recovery coordinator is unavailable.'
20
+ [[ -f "$extension_source/manifest.json" && ! -L "$extension_source/manifest.json" ]] ||
21
+ sc_fail 'Claude recovery extension manifest is unavailable.'
22
+ [[ -f "$extension_source/server.cjs" && ! -L "$extension_source/server.cjs" ]] ||
23
+ sc_fail 'Claude recovery extension server is unavailable.'
24
+
25
+ /bin/mkdir -p "$user_data"
26
+ [[ -d "$user_data" && ! -L "$user_data" ]] || sc_fail 'Claude user data directory is invalid.'
27
+ extension_root="$user_data/Claude Extensions"
28
+ settings_root="$user_data/Claude Extensions Settings"
29
+ target="$extension_root/$extension_id"
30
+ settings_target="$settings_root/$extension_id.json"
31
+ /bin/mkdir -p "$extension_root" "$settings_root"
32
+ [[ -d "$extension_root" && ! -L "$extension_root" && -d "$settings_root" && ! -L "$settings_root" ]] ||
33
+ sc_fail 'Claude recovery extension directories are invalid.'
34
+
35
+ if [[ -e "$target" || -L "$target" ]]; then
36
+ [[ -d "$target" && ! -L "$target" ]] || sc_fail 'Claude recovery extension location is occupied.'
37
+ existing_names=("$target"/*(DN:t))
38
+ [[ ${(j:,:)${(on)existing_names}} == manifest.json,recovery.json,server.cjs,supercode-owned ]] ||
39
+ sc_fail 'Claude recovery extension location is not owned by Supercode.'
40
+ [[ "$(<"$target/supercode-owned")" == 'supercode-claude-recovery-v1' ]] ||
41
+ sc_fail 'Claude recovery extension ownership marker is invalid.'
42
+ else
43
+ /bin/mkdir -m 700 "$target"
44
+ fi
45
+
46
+ /bin/cp -p "$extension_source/manifest.json" "$sc_stage/recovery-extension-manifest.json"
47
+ /bin/cp -p "$extension_source/server.cjs" "$sc_stage/recovery-extension-server.cjs"
48
+ print -rn -- 'supercode-claude-recovery-v1' >"$sc_stage/recovery-extension-owned"
49
+ sc_json_string "$coordinator_hook"; coordinator_json=$REPLY
50
+ sc_json_string "$storage_root"; storage_json=$REPLY
51
+ sc_json_string "$runtime_version"; runtime_json=$REPLY
52
+ sc_json_string "$bootstrap_namespace"; namespace_json=$REPLY
53
+ print -r -- "{\"schemaVersion\":1,\"coordinatorHook\":$coordinator_json,\"storageRoot\":$storage_json,\"runtimeVersion\":$runtime_json,\"bootstrapNamespace\":$namespace_json}" \
54
+ >"$sc_stage/recovery-extension-config.json"
55
+ print -r -- '{"isEnabled":true}' >"$sc_stage/recovery-extension-settings.json"
56
+
57
+ sc_copy_atomic "$sc_stage/recovery-extension-manifest.json" "$target/manifest.json"
58
+ sc_copy_atomic "$sc_stage/recovery-extension-server.cjs" "$target/server.cjs"
59
+ sc_copy_atomic "$sc_stage/recovery-extension-config.json" "$target/recovery.json"
60
+ sc_copy_atomic "$sc_stage/recovery-extension-owned" "$target/supercode-owned"
61
+ sc_copy_atomic "$sc_stage/recovery-extension-settings.json" "$settings_target"
62
+ }
@@ -0,0 +1,97 @@
1
+ # Shared primitives; sourced only by the reviewed install/recovery entrypoints.
2
+ export PATH=/usr/bin:/bin:/usr/sbin:/sbin
3
+ export LC_ALL=C
4
+ umask 077
5
+
6
+ sc_fail() {
7
+ print -ru2 -- "Supercode: $*"
8
+ return 1
9
+ }
10
+
11
+ sc_sha256_file() {
12
+ [[ -f "$1" ]] || sc_fail "Cannot hash a missing file: $1"
13
+ /usr/bin/openssl dgst -sha256 "$1" | /usr/bin/awk '{print $NF}'
14
+ }
15
+
16
+ sc_assert_path() {
17
+ [[ "$1" == /* && "$1" != *[[:cntrl:]]* ]] || sc_fail 'An absolute path without control characters is required.'
18
+ }
19
+
20
+ sc_json_string() {
21
+ local value=$1
22
+ value=${value//\\/\\\\}
23
+ value=${value//\"/\\\"}
24
+ value=${value//$'\n'/\\n}
25
+ value=${value//$'\r'/\\r}
26
+ value=${value//$'\t'/\\t}
27
+ REPLY="\"$value\""
28
+ }
29
+
30
+ sc_process() {
31
+ sc_verify_process "$sc_app" "$sc_pid"
32
+ }
33
+
34
+ sc_acquire_lock() {
35
+ local owner previous owner_pid
36
+ sc_lock="$sc_root/lifecycle.lock"
37
+ owner="$$:$(/usr/bin/uuidgen)"
38
+ if ! /bin/ln -s "$owner" "$sc_lock" 2>/dev/null; then
39
+ [[ -L "$sc_lock" ]] || sc_fail 'Lifecycle lock is occupied.'
40
+ previous=$(/usr/bin/readlink "$sc_lock")
41
+ owner_pid=${previous%%:*}
42
+ [[ "$owner_pid" == <1-> ]] || sc_fail 'Lifecycle lock has invalid ownership.'
43
+ if kill -0 "$owner_pid" 2>/dev/null; then
44
+ sc_fail 'Another install or recovery is running.'
45
+ return 1
46
+ fi
47
+ [[ "$(/usr/bin/readlink "$sc_lock")" == "$previous" ]] || return 1
48
+ /bin/rm "$sc_lock"
49
+ /bin/ln -s "$owner" "$sc_lock" || return 1
50
+ fi
51
+ sc_lock_owner=$owner
52
+ }
53
+
54
+ sc_cleanup() {
55
+ if [[ -n ${sc_lock_owner:-} && -L ${sc_lock:-} && "$(/usr/bin/readlink "$sc_lock")" == "$sc_lock_owner" ]]; then
56
+ /bin/rm "$sc_lock"
57
+ fi
58
+ if [[ -n ${sc_stage:-} && "$sc_stage" == "$sc_root"/install-stage.* && -d "$sc_stage" && ! -L "$sc_stage" ]]; then
59
+ /bin/rm -r -- "$sc_stage"
60
+ fi
61
+ }
62
+
63
+ sc_copy_atomic() {
64
+ local temporary
65
+ [[ -f "$1" && ! -L "$1" ]] || sc_fail 'Distribution asset is missing or is a symlink.'
66
+ [[ ! -L "$2" ]] || sc_fail 'Refusing to replace a symlinked state file.'
67
+ temporary=$(/usr/bin/mktemp "${2}.XXXXXXXX") || return 1
68
+ /bin/cp "$1" "$temporary" || { /bin/rm -f "$temporary"; return 1; }
69
+ /bin/chmod "${3:-600}" "$temporary" || { /bin/rm -f "$temporary"; return 1; }
70
+ /bin/mv -f "$temporary" "$2" || { /bin/rm -f "$temporary"; return 1; }
71
+ }
72
+
73
+ sc_select_app() {
74
+ local row candidate pid
75
+ local -a matches=()
76
+ if [[ -n "$sc_app" ]]; then
77
+ sc_assert_path "$sc_app"
78
+ sc_app=${sc_app:A}
79
+ fi
80
+ if [[ -z "$sc_app" || -z "$sc_pid" ]]; then
81
+ while IFS= read -r row; do
82
+ row=${row##[[:space:]]#}
83
+ pid=${row%%[[:space:]]*}
84
+ candidate=${row#${pid}}
85
+ candidate=${candidate##[[:space:]]#}
86
+ [[ "$candidate" == */Claude.app/Contents/MacOS/Claude ]] || continue
87
+ [[ -z "$sc_app" || "$candidate" == "$sc_app/Contents/MacOS/Claude" ]] || continue
88
+ [[ -z "$sc_pid" || "$pid" == "$sc_pid" ]] || continue
89
+ matches+=("$pid" "${candidate%/Contents/MacOS/Claude}")
90
+ done < <(/bin/ps -axo pid=,comm=)
91
+ (( ${#matches} == 2 )) || sc_fail 'Open one Claude Desktop, or select its exact --app and --pid.'
92
+ sc_pid=$matches[1]
93
+ sc_app=${matches[2]:A}
94
+ fi
95
+ [[ -d "$sc_app" && "${sc_app:t}" == Claude.app ]] || sc_fail 'Invalid Claude application directory.'
96
+ sc_process
97
+ }
@@ -0,0 +1,122 @@
1
+ #!/bin/zsh -f
2
+ emulate -LR zsh
3
+ setopt ERR_EXIT NO_UNSET PIPE_FAIL EXTENDED_GLOB
4
+ sc_distribution=${0:A:h:h}
5
+ source "$sc_distribution/macos/common.zsh"
6
+ source "$sc_distribution/macos/claude-asar-bootstrap.zsh"
7
+ source "$sc_distribution/macos/claude-installation-state.zsh"
8
+ source "$sc_distribution/macos/claude-process.zsh"
9
+ source "$sc_distribution/macos/claude-recovery-extension.zsh"
10
+
11
+ sc_app='' sc_pid='' sc_user_data='' sc_channel=stable
12
+ sc_root=${SUPERCODE_CLAUDE_STORAGE_ROOT:-$HOME/.supercode/claude}
13
+ sc_bootstrap_namespace=${SUPERCODE_CLAUDE_BOOTSTRAP_NAMESPACE:-.s}
14
+
15
+ sc_publish_external_runtime() {
16
+ local sc_shim="$HOME/$sc_bootstrap_namespace" sc_release="$sc_root/extension/seed/$sc_version"
17
+ local sc_file sc_main_json
18
+ local -a sc_names=()
19
+ if [[ -e "$sc_shim" || -L "$sc_shim" ]]; then
20
+ [[ -d "$sc_shim" && ! -L "$sc_shim" ]] || sc_fail 'The bootstrap location is occupied.'
21
+ sc_names=("$sc_shim"/*(DN:t))
22
+ [[ ${(j:,:)${(on)sc_names}} == index.cjs,package.json ]] || sc_fail 'The bootstrap location is not owned by Supercode.'
23
+ [[ -f "$sc_shim/index.cjs" && ! -L "$sc_shim/index.cjs" && -f "$sc_shim/package.json" && ! -L "$sc_shim/package.json" ]] ||
24
+ sc_fail 'Invalid bootstrap file.'
25
+ /usr/bin/cmp -s "$sc_shim/package.json" "$sc_distribution/assets/bootstrap/package.json" ||
26
+ sc_fail 'Unrelated bootstrap files; refusing to overwrite.'
27
+ if ! /usr/bin/cmp -s "$sc_shim/index.cjs" "$sc_distribution/assets/bootstrap/index.cjs"; then
28
+ /usr/bin/cmp -s "$sc_shim/index.cjs" "$sc_distribution/assets/bootstrap/index-legacy.cjs" ||
29
+ sc_fail 'Unrelated bootstrap files; refusing to overwrite.'
30
+ sc_copy_atomic "$sc_distribution/assets/bootstrap/index.cjs" "$sc_shim/index.cjs"
31
+ fi
32
+ else
33
+ /bin/mkdir -m 700 "$sc_shim"
34
+ for sc_file in index.cjs package.json; do
35
+ sc_copy_atomic "$sc_distribution/assets/bootstrap/$sc_file" "$sc_shim/$sc_file"
36
+ done
37
+ fi
38
+
39
+ /bin/mkdir -p "$sc_root/extension/seed" "$sc_root/runtime" "$sc_root/logs"
40
+ if [[ ! -e "$sc_release" ]]; then
41
+ /bin/cp -R "$sc_distribution/assets/runtime" "$sc_stage/release"
42
+ /bin/mv "$sc_stage/release" "$sc_release"
43
+ else
44
+ /usr/bin/diff -rq "$sc_distribution/assets/runtime" "$sc_release" >/dev/null ||
45
+ sc_fail 'The installed Claude seed release does not match this installer.'
46
+ fi
47
+ sc_json_string "$sc_release/main.cjs"; sc_main_json=$REPLY
48
+ print -r -- "module.exports=require($sc_main_json);" >"$sc_stage/active.cjs"
49
+ sc_copy_atomic "$sc_stage/active.cjs" "$sc_root/runtime/main.cjs"
50
+ print -r -- "$sc_channel" >"$sc_stage/channel-v1"
51
+ sc_copy_atomic "$sc_stage/channel-v1" "$sc_root/extension/channel-v1"
52
+ print -r -- '#!/bin/zsh -f' >"$sc_stage/recover-v1"
53
+ print -r -- "exec /bin/zsh -f ${(q)sc_release}/recovery/macos/recover.zsh \"\$@\"" >>"$sc_stage/recover-v1"
54
+ sc_copy_atomic "$sc_stage/recover-v1" "$sc_root/recover-v1" 700
55
+ sc_configure_recovery_extension "$sc_user_data" "$sc_root/recover-v1" "$sc_release/recovery/macos" "$sc_root" "$sc_version" \
56
+ "$sc_bootstrap_namespace"
57
+ print -rn -- '' >"$sc_stage/enabled"
58
+ sc_copy_atomic "$sc_stage/enabled" "$sc_root/recovery-enabled-v1"
59
+ # The active selector is the final atomic publication boundary.
60
+ sc_copy_atomic "$sc_stage/active.cjs" "$sc_root/extension/active.cjs"
61
+ }
62
+
63
+ [[ "$sc_bootstrap_namespace" == .s || "$sc_bootstrap_namespace" == .d || "$sc_bootstrap_namespace" == .e ]] ||
64
+ sc_fail 'Unsupported Claude bootstrap namespace.'
65
+ while (( $# )); do
66
+ case "$1" in
67
+ --help)
68
+ print -r -- 'Open Claude Desktop, then run claude-install-mac [--app /path/to/Claude.app] [--pid PID] [--channel stable|staging].'
69
+ print -r -- 'The installer and recovery lifecycle use only built-in macOS system tools.'
70
+ exit 0 ;;
71
+ --app|--pid|--storage-root|--user-data-dir|--channel)
72
+ (( $# >= 2 )) || sc_fail "Missing value for $1"
73
+ case "$1" in
74
+ --app) sc_app=$2 ;;
75
+ --pid) sc_pid=$2 ;;
76
+ --storage-root) sc_root=$2 ;;
77
+ --user-data-dir) sc_user_data=$2 ;;
78
+ --channel) sc_channel=$2 ;;
79
+ esac
80
+ shift 2 ;;
81
+ *) sc_fail "Unknown Claude installer argument: $1" ;;
82
+ esac
83
+ done
84
+ [[ "$sc_channel" == stable || "$sc_channel" == staging ]] || sc_fail 'Claude extension channel must be stable or staging.'
85
+ [[ "$OSTYPE" == darwin* && "$EUID" != 0 ]] || sc_fail 'Run this installer as your normal macOS user, not sudo.'
86
+ sc_assert_path "$sc_root"
87
+ sc_root=${sc_root:A}
88
+ sc_select_app
89
+ /bin/mkdir -p "$sc_root"
90
+ sc_acquire_lock
91
+ trap sc_cleanup EXIT
92
+ trap 'exit 130' INT
93
+ trap 'exit 143' TERM HUP
94
+ sc_identity=$(print -rn -- "$sc_app" | /usr/bin/openssl dgst -sha256 | /usr/bin/awk '{print $NF}')
95
+ sc_installation="$sc_root/installations/$sc_identity"
96
+ if [[ -z "$sc_user_data" ]]; then
97
+ sc_user_data="$HOME/Library/Application Support/Claude"
98
+ fi
99
+ sc_assert_path "$sc_user_data"
100
+ sc_user_data=${sc_user_data:A}
101
+ sc_stage=$(/usr/bin/mktemp -d "$sc_root/install-stage.XXXXXXXX")
102
+ sc_version=$(<"$sc_distribution/version")
103
+ sc_installation_state "$sc_app" "$sc_installation" "$sc_pid"
104
+ sc_state=$REPLY
105
+ if [[ "$sc_state" == admission-active || "$sc_state" == already-patched ]]; then
106
+ sc_publish_external_runtime
107
+ print -r -- "$sc_state"
108
+ exit 0
109
+ fi
110
+ /usr/bin/codesign --verify --deep --strict "$sc_app"
111
+ sc_asar_plan "$sc_app" "$sc_stage" "$sc_version" "$sc_bootstrap_namespace"
112
+
113
+ # Publish every prerequisite before modifying either sealed resource.
114
+ sc_publish_external_runtime
115
+ sc_pristine="$sc_installation/pristine/Claude.app/Contents"
116
+ /bin/mkdir -p "$sc_pristine/Resources"
117
+ sc_copy_atomic "$sc_app/Contents/Resources/app.asar" "$sc_pristine/Resources/app.asar"
118
+ sc_copy_atomic "$sc_app/Contents/Info.plist" "$sc_pristine/Info.plist"
119
+ sc_process
120
+ sc_asar_apply "$sc_app" "$sc_stage" "$sc_installation/installed.json"
121
+ print -r -- 'patched'
122
+ print -r -- 'Supercode installed. Quit Claude completely and reopen it.'
@@ -0,0 +1,71 @@
1
+ #!/bin/zsh -f
2
+ emulate -LR zsh
3
+ setopt ERR_EXIT NO_UNSET PIPE_FAIL EXTENDED_GLOB
4
+ sc_distribution=${0:A:h:h}
5
+ source "$sc_distribution/macos/common.zsh"
6
+ source "$sc_distribution/macos/claude-process.zsh"
7
+
8
+ zmodload zsh/datetime
9
+
10
+ sc_recovery_log() {
11
+ printf '%.6f %s\n' "$EPOCHREALTIME" "$*"
12
+ }
13
+
14
+ sc_wait_for_source_exit() {
15
+ local tick
16
+ for tick in {1..100}; do
17
+ kill -0 "$sc_pid" 2>/dev/null || return 0
18
+ /bin/sleep 0.1
19
+ done
20
+ ! kill -0 "$sc_pid" 2>/dev/null
21
+ }
22
+
23
+ sc_app='' sc_pid='' sc_root='' sc_user_data='' sc_bootstrap_namespace=''
24
+ while (( $# )); do
25
+ (( $# >= 2 )) || exit 0
26
+ case "$1" in
27
+ --app) sc_app=$2 ;;
28
+ --pid) sc_pid=$2 ;;
29
+ --storage-root) sc_root=$2 ;;
30
+ --bootstrap-namespace) sc_bootstrap_namespace=$2 ;;
31
+ --user-data-dir) sc_user_data=$2 ;;
32
+ *) exit 0 ;;
33
+ esac
34
+ shift 2
35
+ done
36
+ [[ -n "$sc_app" && -n "$sc_pid" && -n "$sc_root" && -n "$sc_user_data" ]] || exit 0
37
+ [[ "$sc_bootstrap_namespace" == .s || "$sc_bootstrap_namespace" == .d || "$sc_bootstrap_namespace" == .e ]] || exit 0
38
+ sc_assert_path "$sc_app"
39
+ sc_assert_path "$sc_root"
40
+ sc_assert_path "$sc_user_data"
41
+ sc_app=${sc_app:A}
42
+ sc_root=${sc_root:A}
43
+ sc_user_data=${sc_user_data:A}
44
+ /bin/mkdir -p "$sc_root/logs"
45
+ exec </dev/null >>"$sc_root/logs/recovery.log" 2>&1
46
+ sc_verify_process "$sc_app" "$sc_pid" || { print -r -- 'relaunch-rejected unexpected-main'; exit 0; }
47
+ sc_identity=$(print -rn -- "$sc_app" | /usr/bin/openssl dgst -sha256 | /usr/bin/awk '{print $NF}')
48
+ sc_installation="$sc_root/installations/$sc_identity"
49
+ [[ -f "$sc_root/recovery-enabled-v1" && -f "$sc_installation/installed.json" ]] || exit 0
50
+ sc_recovery_log "relaunch-start sourcePid=$sc_pid"
51
+ kill -TERM "$sc_pid"
52
+ sc_recovery_log "relaunch-signal-sent sourcePid=$sc_pid"
53
+
54
+ # Claude can receive the first signal while Electron is still installing its
55
+ # lifecycle handlers. Retry the same graceful signal once; never escalate to
56
+ # SIGKILL while the application may be persisting native state.
57
+ if ! sc_wait_for_source_exit; then
58
+ kill -TERM "$sc_pid"
59
+ sc_recovery_log "relaunch-signal-retried sourcePid=$sc_pid"
60
+ fi
61
+ if ! sc_wait_for_source_exit; then
62
+ sc_recovery_log 'relaunch-failed reason=source-still-running'
63
+ exit 0
64
+ fi
65
+ sc_recovery_log "relaunch-source-exited sourcePid=$sc_pid"
66
+ export SUPERCODE_CLAUDE_STORAGE_ROOT="$sc_root"
67
+ export SUPERCODE_CLAUDE_BOOTSTRAP_NAMESPACE="$sc_bootstrap_namespace"
68
+ "$sc_app/Contents/MacOS/Claude" "--user-data-dir=$sc_user_data" </dev/null >/dev/null 2>&1 &
69
+ sc_relaunched_pid=$!
70
+ disown "$sc_relaunched_pid" 2>/dev/null || true
71
+ sc_recovery_log "relaunch-launched sourcePid=$sc_pid pid=$sc_relaunched_pid"
@@ -0,0 +1,21 @@
1
+ {
2
+ "manifest_version": "0.4",
3
+ "name": "supercode-recovery",
4
+ "display_name": "Supercode Recovery",
5
+ "version": "0.1.0",
6
+ "description": "Restores Supercode after Claude Desktop updates.",
7
+ "author": {
8
+ "name": "Supercode"
9
+ },
10
+ "server": {
11
+ "type": "node",
12
+ "entry_point": "server.cjs",
13
+ "mcp_config": {
14
+ "command": "node",
15
+ "args": [
16
+ "${__dirname}/server.cjs"
17
+ ]
18
+ }
19
+ },
20
+ "tools": []
21
+ }
@@ -0,0 +1,8 @@
1
+ "use strict";var Ce=Object.create;var Z=Object.defineProperty;var Ie=Object.getOwnPropertyDescriptor;var Ee=Object.getOwnPropertyNames;var xe=Object.getPrototypeOf,ke=Object.prototype.hasOwnProperty;var Oe=(a,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of Ee(e))!ke.call(a,n)&&n!==t&&Z(a,n,{get:()=>e[n],enumerable:!(r=Ie(e,n))||r.enumerable});return a};var h=(a,e,t)=>(t=a!=null?Ce(xe(a)):{},Oe(e||!a||!a.__esModule?Z(t,"default",{value:a,enumerable:!0}):t,a));var Re=require("node:module"),B=h(require("node:fs"),1),G=h(require("node:path"),1);var Q=h(require("node:crypto"),1),R=h(require("node:fs"),1),ee=h(require("node:path"),1),F=Symbol.for("supercode.claude.extension-lifecycle-lock.v1"),M=class{constructor(e){this.lockPath=e}lockPath;async run(e){let t=globalThis;if(t[F])throw new Error("Another Supercode Claude lifecycle operation is already in progress");let r={};t[F]=r;let n=null;try{return n=this.acquireFileLock(),await e()}finally{this.releaseFileLock(n),t[F]===r&&delete t[F]}}acquireFileLock(){if(!this.lockPath)return null;R.default.mkdirSync(ee.default.dirname(this.lockPath),{recursive:!0});let e=`${process.pid}:${Q.default.randomUUID()}`;for(let t=0;t<2;t+=1)try{return R.default.symlinkSync(e,this.lockPath),e}catch(r){if(r.code!=="EEXIST"||this.hasLiveOwner())throw new Error("Another Supercode Claude lifecycle operation is already in progress");R.default.rmSync(this.lockPath,{force:!0,recursive:!0})}throw new Error("Another Supercode Claude lifecycle operation is already in progress")}hasLiveOwner(){if(!this.lockPath)return!1;try{let e=Number(R.default.readlinkSync(this.lockPath).split(":",1)[0]);return!Number.isSafeInteger(e)||e<=0?!1:(process.kill(e,0),!0)}catch(e){return e.code==="EPERM"}}releaseFileLock(e){if(!(!this.lockPath||!e))try{R.default.readlinkSync(this.lockPath)===e&&R.default.unlinkSync(this.lockPath)}catch{}}};var Y=require("node:crypto"),re=h(require("node:os"),1),o=h(require("node:path"),1),E="SUPERCODE_CLAUDE_STORAGE_ROOT",te="SUPERCODE_CLAUDE_BOOTSTRAP_NAMESPACE",v=class{root;bootstrapDirectory;constructor(e=process.env,t=re.default.homedir()){this.root=o.default.resolve(e[E]??o.default.join(t,".supercode","claude"));let r=e[te]??".s";if(r!==".s"&&r!==".d"&&r!==".e")throw new Error(`${te} is invalid`);this.bootstrapDirectory=o.default.join(t,r)}get enabledMarker(){return o.default.join(this.root,"recovery-enabled-v1")}get recoveryHook(){return o.default.join(this.root,"recover-v1")}get recoveryLog(){return o.default.join(this.root,"logs","recovery.log")}get recoveryAttemptStateRoot(){return o.default.join(this.root,"recovery-attempt-v1")}get lifecycleLock(){return o.default.join(this.root,"lifecycle.lock")}get extensionChannel(){return o.default.join(this.extensionRoot,"channel-v1")}get extensionDownloadsRoot(){return o.default.join(this.extensionRoot,"downloads")}get extensionRoot(){return o.default.join(this.root,"extension")}get installationsRoot(){return o.default.join(this.root,"installations")}get logsRoot(){return o.default.join(this.root,"logs")}get managedBinariesRoot(){return o.default.join(this.root,"managed-binaries")}get productRoot(){return o.default.join(this.root,"product")}get runtimeRoot(){return o.default.join(this.root,"runtime")}get extensionActiveBootstrap(){return o.default.join(this.extensionRoot,"active.cjs")}get extensionUpdateRetryState(){return o.default.join(this.extensionRoot,"update-retry-v1.json")}get extensionUpdateNotificationState(){return o.default.join(this.extensionRoot,"update-notification-v1.json")}get extensionUnpackingRoot(){return o.default.join(this.extensionRoot,"unpacking")}get extensionReleasesRoot(){return o.default.join(this.extensionRoot,"releases")}get runtimeMain(){return o.default.join(this.root,"runtime","main.cjs")}get runtimeMcpStdio(){return o.default.join(this.root,"runtime","mcp-stdio.zsh")}get runtimePreload(){return o.default.join(this.root,"runtime","preload.cjs")}get runtimeRenderer(){return o.default.join(this.root,"runtime","renderer.js")}get runtimeLog(){return o.default.join(this.root,"logs","runtime.jsonl")}installationRoot(e){let t=(0,Y.createHash)("sha256").update(o.default.resolve(e)).digest("hex");return o.default.join(this.installationsRoot,t)}installationManifest(e){return o.default.join(this.installationRoot(e),"installed.json")}admissionMarker(e){return o.default.join(this.installationRoot(e),"admission-in-progress.json")}pristineApp(e){return o.default.join(this.installationRoot(e),"pristine","Claude.app")}recoveryAttemptState(e){let t=(0,Y.createHash)("sha256").update(e).digest("hex");return o.default.join(this.recoveryAttemptStateRoot,t)}extensionArchive(e){return this.assertReleaseVersion(e),o.default.join(this.extensionDownloadsRoot,`${e}.zip`)}extensionArchivePart(e){return`${this.extensionArchive(e)}.part`}extensionRelease(e){return this.assertReleaseVersion(e),o.default.join(this.extensionReleasesRoot,e)}extensionUnpacking(e){return this.assertReleaseVersion(e),o.default.join(this.extensionUnpackingRoot,e)}assertReleaseVersion(e){if(!/^[A-Za-z0-9][A-Za-z0-9._+-]*$/.test(e))throw new Error("Supercode Claude extension version is invalid")}};var J=h(require("node:crypto"),1),w=h(require("node:path"),1);var ne=h(require("node:crypto"),1),se=h(require("node:fs"),1);var H=class{constructor(e,t,r){this.runtime=e;this.archivePath=t;this.infoPlistPath=r}runtime;archivePath;infoPlistPath;patch(e,t){let r=this.runtime.fs.statSync(this.archivePath).size,n=this.runtime.fs.openSync(this.archivePath,this.openFlags());try{let s=this.read(n,16,0);if(s.readUInt32LE(0)!==4)throw new Error("Unsupported ASAR header");let i=s.readUInt32LE(4),c=s.readUInt32LE(12),l=this.read(n,c,16),y=JSON.parse(l.toString("utf8")),m=8+i,p=this.requirePackedFile(y,e),d=m+this.requireOffset(p,e),u=this.read(n,p.size,d),A=this.requireIntegrity(p,u.length,e),g=t.patch(e,u);if(g.content.length!==u.length)throw new Error("Claude main-entry patch changed the entry size");let f=this.planHeaderPatch(l,p,A,g.content),C=this.digest(l),I=this.digest(f.patchedHeader),S=this.planInfoPlistPatch(C,I);if(g.didPatch)try{this.write(n,g.content,d),this.write(n,f.patchedIntegrity,f.integrityOffset),this.runtime.fs.fsyncSync(n),S&&this.writeFileSegmentInPlace(this.infoPlistPath,S.offset,S.patchedHash),this.verify(d,g.content,f,S)}catch(W){throw this.write(n,u,d),this.write(n,f.integrity,f.integrityOffset),this.runtime.fs.fsyncSync(n),S&&this.writeFileSegmentInPlace(this.infoPlistPath,S.offset,S.hash),W}return{archiveBytes:r,didPatch:g.didPatch,entry:this.segment(d,u,g.content,void 0,f.patchedEntrySha256),entryPath:e,header:this.segment(16,f.header,f.patchedHeader,C,I),headerIntegrity:this.segment(f.integrityOffset,f.integrity,f.patchedIntegrity),...S?{infoPlistAsarIntegrity:this.segment(S.offset,S.hash,S.patchedHash)}:{}}}finally{this.runtime.fs.closeSync(n)}}planHeaderPatch(e,t,r,n){let s=Buffer.from(JSON.stringify(t)),i=this.uniqueOffset(e,s,"ASAR entry metadata"),c=Buffer.from(JSON.stringify(r)),l=this.uniqueOffset(s,c,"ASAR entry integrity metadata"),y=this.digest(n),m={...r,blocks:n.length>0&&n.length<=r.blockSize?[y]:this.blockHashes(n,r.blockSize),hash:y},p=Buffer.from(JSON.stringify(m));if(p.length!==c.length)throw new Error("Patched ASAR entry integrity metadata changed size");let d=Buffer.from(e),u=i+l;return p.copy(d,u),{header:e,integrity:c,integrityOffset:16+u,patchedHeader:d,patchedIntegrity:p,patchedEntrySha256:y}}planInfoPlistPatch(e,t){if(!this.infoPlistPath)return null;let r=this.runtime.fs.readFileSync(this.infoPlistPath),n=r.toString("utf8"),s=n.indexOf("<key>ElectronAsarIntegrity</key>"),i=/<key>hash<\/key>\s*<string>([a-f0-9]{64})<\/string>/.exec(n.slice(s));if(s<0||!i?.[1])throw new Error("ElectronAsarIntegrity hash is unavailable");if(i[1]!==e)throw new Error("ElectronAsarIntegrity mismatch before patch");let c=Buffer.from(e),l=this.uniqueOffset(r,c,"ElectronAsarIntegrity hash");return{hash:c,offset:l,patchedHash:Buffer.from(t)}}verify(e,t,r,n){let s=this.runtime.fs.openSync(this.archivePath,"r");try{if(!this.read(s,r.patchedHeader.length,16).equals(r.patchedHeader))throw new Error("Installed ASAR header does not match the planned bootstrap");if(!this.read(s,t.length,e).equals(t))throw new Error("Installed Claude main entry does not match the planned bootstrap")}finally{this.runtime.fs.closeSync(s)}if(n&&!this.readFileSegment(this.infoPlistPath,n.offset,64).equals(n.patchedHash))throw new Error("Installed ElectronAsarIntegrity hash does not match the ASAR header")}requirePackedFile(e,t){let r=e;for(let n of t.replace(/^\.\//,"").split("/"))r=r?.files?.[n];if(r?.size===void 0||r.offset===void 0||r.unpacked)throw new Error(`ASAR file is unavailable: ${t}`);return r}requireOffset(e,t){let r=Number(e.offset);if(!Number.isSafeInteger(r)||r<0||!Number.isSafeInteger(e.size)||e.size<0)throw new Error(`ASAR file metadata is invalid: ${t}`);return r}requireIntegrity(e,t,r){let n=e.integrity;if(!n||n.algorithm!=="SHA256"||!Number.isSafeInteger(n.blockSize)||n.blockSize<=0||!this.isSha256(n.hash)||!Array.isArray(n.blocks)||n.blocks.length!==Math.ceil(t/n.blockSize)||n.blocks.some(s=>!this.isSha256(s)))throw new Error(`ASAR file has invalid integrity metadata: ${r}`);return n}blockHashes(e,t){let r=[];for(let n=0;n<e.length;n+=t)r.push(this.digest(e.subarray(n,Math.min(n+t,e.length))));return r}segment(e,t,r,n=this.digest(t),s=this.digest(r)){return{bytes:t.length,offset:e,originalSha256:n,patchedSha256:s}}uniqueOffset(e,t,r){let n=e.indexOf(t);if(n<0||e.indexOf(t,n+1)>=0)throw new Error(`${r} must occur exactly once`);return n}isSha256(e){return typeof e=="string"&&/^[a-f0-9]{64}$/.test(e)}digest(e){return this.runtime.crypto.createHash("sha256").update(e).digest("hex")}openFlags(){return this.runtime.fs.constants.O_RDWR|this.runtime.fs.constants.O_NOFOLLOW}read(e,t,r){let n=Buffer.alloc(t),s=0;for(;s<t;){let i=this.runtime.fs.readSync(e,n,s,t-s,r+s);if(i<=0)throw new Error("Unexpected file end");s+=i}return n}readFileSegment(e,t,r){let n=this.runtime.fs.openSync(e,"r");try{return this.read(n,r,t)}finally{this.runtime.fs.closeSync(n)}}write(e,t,r){let n=0;for(;n<t.length;){let s=this.runtime.fs.writeSync(e,t,n,t.length-n,r+n);if(s<=0)throw new Error("In-place write stopped before completion");n+=s}}writeFileSegmentInPlace(e,t,r){let n=this.runtime.fs.openSync(e,this.openFlags());try{this.write(n,r,t),this.runtime.fs.fsyncSync(n)}finally{this.runtime.fs.closeSync(n)}}};var Ne='"use strict";',Be=/(?:\r?\n)?\/\/# sourceMappingURL=[^\r\n]+\s*$/,Fe=/\blet ([\w$]+)=require\("node:os"\);/g,j=class{constructor(e=".s"){this.bootstrapNamespace=e}bootstrapNamespace;reportValue=null;patch(e,t){this.reportValue=null;let r=t.toString("utf8");if(!Buffer.from(r).equals(t))throw new Error("Claude main entry is not canonical UTF-8");if(!r.startsWith(Ne))throw new Error("Claude main entry strict-mode prefix was not found");let n=[...r.matchAll(Fe)];if(n.length!==1)throw new Error("Claude native os-module declaration must occur exactly once");let s=n[0],i=s.index+s[0].length,c=`try{require(${s[1]}.homedir()+"/${this.bootstrapNamespace}")}catch{}`,l=Buffer.byteLength(c);if(r.startsWith(c,i))return this.reportValue={bootstrapBytes:l,windowBytes:l+Buffer.byteLength(/\s*$/.exec(r)[0])},{content:t,didPatch:!1};let y=Be.exec(r);if(!y||i>y.index)throw new Error("Claude bootstrap source-map boundary is unavailable");let m=Buffer.byteLength(y[0]);if(l+1>m)throw new Error("Claude bootstrap does not fit the source-map suffix");let p=r.slice(0,y.index),d=p.slice(0,i)+c+p.slice(i),u=Buffer.alloc(t.length,32);return u.write(d,0,"utf8"),u[u.length-1]=10,this.reportValue={bootstrapBytes:l,windowBytes:m},{content:u,didPatch:!0}}report(){if(!this.reportValue)throw new Error("Claude bootstrap patch has not been planned");return this.reportValue}};var V=class{constructor(e={crypto:ne.default,fs:se.default}){this.runtime=e}runtime;install(e){let t=new H(this.runtime,e.asarPath,e.infoPlistPath),r=new j(e.bootstrapNamespace),n=t.patch(e.entryPath,r),s=r.report();return{...n,bootstrapBytes:s.bootstrapBytes,patchWindowBytes:s.windowBytes}}};var oe=h(require("node:fs"),1),$=h(require("node:path"),1);var ie=require("node:crypto"),ae=h(require("node:fs"),1),x=h(require("node:path"),1),b=class{constructor(e=ae.default){this.filesystem=e}filesystem;write(e,t,r){this.filesystem.mkdirSync(x.default.dirname(e),{recursive:!0,mode:448});let n=x.default.join(x.default.dirname(e),`.${x.default.basename(e)}.${(0,ie.randomUUID)()}.tmp`),s=null;try{s=this.filesystem.openSync(n,"wx",r),this.filesystem.writeFileSync(s,t),this.filesystem.fsyncSync(s),this.filesystem.closeSync(s),s=null,this.filesystem.renameSync(n,e),this.filesystem.chmodSync(e,r),this.syncDirectory(x.default.dirname(e))}catch(i){throw s!==null&&this.filesystem.closeSync(s),this.filesystem.rmSync(n,{force:!0}),i}}writeIfChanged(e,t,r){let n=Buffer.isBuffer(t)?t:Buffer.from(t);return this.filesystem.existsSync(e)&&this.filesystem.readFileSync(e).equals(n)?!1:(this.write(e,n,r),!0)}syncDirectory(e){let t=this.filesystem.openSync(e,"r");try{this.filesystem.fsyncSync(t)}finally{this.filesystem.closeSync(t)}}};var _=class{constructor(e,t=oe.default){this.paths=e;this.filesystem=t;this.writer=new b(t)}paths;filesystem;writer;begin(e,t){let r={schemaVersion:1,appPath:$.default.resolve(e),createdAt:new Date().toISOString(),pid:t.pid,processStartedAt:t.startedAt};this.writer.write(this.paths.admissionMarker(e),`${JSON.stringify(r,null,2)}
2
+ `,384)}isActive(e,t){let r=this.paths.admissionMarker(e);if(!this.filesystem.existsSync(r))return!1;let n;try{n=JSON.parse(this.filesystem.readFileSync(r,"utf8"))}catch{return!1}if(!this.isMarker(n,$.default.resolve(e))||n.pid!==t.pid||n.processStartedAt!==t.startedAt)return!1;try{return process.kill(n.pid,0),!0}catch{return!1}}clear(e,t=process.pid){let r=this.paths.admissionMarker(e);if(!this.filesystem.existsSync(r))return;let n;try{n=JSON.parse(this.filesystem.readFileSync(r,"utf8"))}catch{return}this.isMarker(n,$.default.resolve(e))&&n.pid===t&&this.filesystem.rmSync(r)}isMarker(e,t){if(!e||typeof e!="object")return!1;let r=e;return r.schemaVersion===1&&r.appPath===t&&typeof r.createdAt=="string"&&!Number.isNaN(Date.parse(r.createdAt))&&Number.isSafeInteger(r.pid)&&(r.pid??0)>0&&typeof r.processStartedAt=="string"&&!Number.isNaN(Date.parse(r.processStartedAt))}};var le=require("node:crypto"),ce=h(require("node:fs"),1),de=h(require("node:path"),1);var T=class{constructor(e,t=ce.default){this.paths=e;this.filesystem=t;this.writer=new b(t)}paths;filesystem;writer;read(e){let t=this.filesystem.realpathSync.native(e),r=this.paths.installationManifest(t);if(!this.filesystem.existsSync(r))return null;let n;try{n=JSON.parse(this.filesystem.readFileSync(r,"utf8"))}catch(s){throw new Error(`Claude installation marker cannot be read: ${r}`,{cause:s})}return this.assertManifest(n,t),n}publish(e){this.assertManifest(e,de.default.resolve(e.appPath)),this.writer.write(this.paths.installationManifest(e.appPath),`${JSON.stringify(e,null,2)}
3
+ `,384)}assertManifest(e,t){if(!e||typeof e!="object")throw new Error("Claude installation marker must be an object");let r=e;if(r.schemaVersion!==1||r.appPath!==t||r.bundleIdentifier!=="com.anthropic.claudefordesktop"||typeof r.desktopVersion!="string"||typeof r.bundleVersion!="string"||r.entryPath!==".vite/build/index.pre.js"||typeof r.installedAt!="string"||Number.isNaN(Date.parse(r.installedAt))||typeof r.runtimeVersion!="string"||!this.isResource(r.resources?.asar)||!this.isResource(r.resources.infoPlist))throw new Error("Claude installation marker is invalid");if(r.sealedResourcePatch!==void 0&&!this.isPatch(r.sealedResourcePatch,r.resources.asar.bytes,r.resources.infoPlist.bytes))throw new Error("Claude installation marker has an invalid sealed-resource patch identity")}isPatch(e,t,r){if(!e||typeof e!="object")return!1;let n=e;return this.isSegment(n.asarEntry,t)&&this.isSegment(n.asarEntryIntegrity,t)&&this.isSegment(n.asarHeader,t)&&this.isSegment(n.infoPlistAsarIntegrity,r)}isSegment(e,t){if(!this.isResource(e))return!1;let r=e;return Number.isSafeInteger(r.offset)&&r.offset>=0&&r.offset+r.bytes<=t}isResource(e){if(!e||typeof e!="object")return!1;let t=e;return Number.isSafeInteger(t.bytes)&&(t.bytes??0)>0&&this.isSha256(t.pristineSha256)&&this.isSha256(t.patchedSha256)&&t.pristineSha256!==t.patchedSha256}isSha256(e){return typeof e=="string"&&/^[a-f0-9]{64}$/.test(e)}static sha256(e){return(0,le.createHash)("sha256").update(e).digest("hex")}};var ue=h(require("node:fs"),1),k=h(require("node:path"),1);var D=class{constructor(e,t=ue.default){this.paths=e;this.filesystem=t;this.writer=new b(t)}paths;filesystem;writer;retain(e,t,r){let n=this.paths.pristineApp(e),s=k.default.join(n,"Contents","Resources","app.asar"),i=k.default.join(n,"Contents","Info.plist");if(this.writer.writeIfChanged(s,t,384),this.writer.writeIfChanged(i,r,384),!this.filesystem.readFileSync(s).equals(t)||!this.filesystem.readFileSync(i).equals(r))throw new Error("Claude pristine sealed resources were not retained exactly")}hasFixedSizeResources(e,t,r){let n=this.paths.pristineApp(e);return this.isRealFile(k.default.join(n,"Contents","Resources","app.asar"),t)&&this.isRealFile(k.default.join(n,"Contents","Info.plist"),r)}isRealFile(e,t){try{let r=this.filesystem.lstatSync(e);return r.isFile()&&!r.isSymbolicLink()&&r.size===t}catch(r){if(r.code==="ENOENT")return!1;throw r}}};var he=require("node:crypto"),pe=h(require("node:fs"),1),L=class{constructor(e=pe.default){this.filesystem=e}filesystem;restore(e){this.assertFile(e.sourceAsarPath,e.resourceBytes.asar,"Pristine Claude ASAR"),this.assertFile(e.sourceInfoPlistPath,e.resourceBytes.infoPlist,"Pristine Claude Info.plist"),this.assertFile(e.targetAsarPath,e.resourceBytes.asar,"Patched Claude ASAR"),this.assertFile(e.targetInfoPlistPath,e.resourceBytes.infoPlist,"Patched Claude Info.plist");let t=[{identity:e.patch.asarEntry,sourcePath:e.sourceAsarPath,targetPath:e.targetAsarPath},{identity:e.patch.asarEntryIntegrity,sourcePath:e.sourceAsarPath,targetPath:e.targetAsarPath},{identity:e.patch.infoPlistAsarIntegrity,sourcePath:e.sourceInfoPlistPath,targetPath:e.targetInfoPlistPath}].map(i=>this.prepareTransition(i)),r=this.readFileSegment(e.sourceAsarPath,e.patch.asarHeader.offset,e.patch.asarHeader.bytes),n=this.readFileSegment(e.targetAsarPath,e.patch.asarHeader.offset,e.patch.asarHeader.bytes);this.assertHash(r,e.patch.asarHeader.pristineSha256,"pristine ASAR header"),this.assertHash(n,e.patch.asarHeader.patchedSha256,"patched ASAR header"),this.restoreFile(e.targetAsarPath,t.filter(i=>i.targetPath===e.targetAsarPath)),this.restoreFile(e.targetInfoPlistPath,t.filter(i=>i.targetPath===e.targetInfoPlistPath));for(let i of t){let c=this.readFileSegment(i.targetPath,i.identity.offset,i.identity.bytes);this.assertHash(c,i.identity.pristineSha256,"restored sealed-resource segment")}let s=this.readFileSegment(e.targetAsarPath,e.patch.asarHeader.offset,e.patch.asarHeader.bytes);return this.assertHash(s,e.patch.asarHeader.pristineSha256,"restored ASAR header"),{entryBytes:e.patch.asarEntry.bytes,entrySha256:e.patch.asarEntry.pristineSha256,headerBytes:e.patch.asarHeader.bytes,headerSha256:e.patch.asarHeader.pristineSha256,infoPlistAsarIntegritySha256:e.patch.infoPlistAsarIntegrity.pristineSha256}}prepareTransition(e){let t=this.readFileSegment(e.sourcePath,e.identity.offset,e.identity.bytes),r=this.readFileSegment(e.targetPath,e.identity.offset,e.identity.bytes);return this.assertHash(t,e.identity.pristineSha256,"pristine sealed-resource segment"),this.assertHash(r,e.identity.patchedSha256,"patched sealed-resource segment"),{...e,pristine:t}}restoreFile(e,t){let r=this.filesystem.openSync(e,this.filesystem.constants.O_RDWR|this.filesystem.constants.O_NOFOLLOW);try{for(let n of t)this.write(r,n.pristine,n.identity.offset);this.filesystem.fsyncSync(r)}finally{this.filesystem.closeSync(r)}}assertFile(e,t,r){let n=this.filesystem.lstatSync(e);if(!n.isFile()||n.isSymbolicLink()||n.size!==t)throw new Error(`${r} must be the expected fixed-size real file`)}assertHash(e,t,r){if(this.sha256(e)!==t)throw new Error(`Claude ${r} does not match its installation manifest`)}readFileSegment(e,t,r){let n=this.filesystem.openSync(e,this.filesystem.constants.O_RDONLY|this.filesystem.constants.O_NOFOLLOW);try{let s=Buffer.alloc(r),i=0;for(;i<r;){let c=this.filesystem.readSync(n,s,i,r-i,t+i);if(c<=0)throw new Error(`Unexpected file end while reading sealed-resource segment from ${e}`);i+=c}return s}finally{this.filesystem.closeSync(n)}}write(e,t,r){let n=0;for(;n<t.length;){let s=this.filesystem.writeSync(e,t,n,t.length-n,r+n);if(s<=0)throw new Error("Claude sealed-resource restore stopped before completion");n+=s}}sha256(e){return(0,he.createHash)("sha256").update(e).digest("hex")}};var ye=h(require("node:fs"),1);var Me=3,He=1440*60*1e3,U=class{constructor(e,t=ye.default){this.paths=e;this.filesystem=t;this.writer=new b(t)}paths;filesystem;writer;register(e){let t=this.bundleIdentity(e),r=`${e.mainPid}:${e.mainStartedAt}`,n=this.paths.recoveryAttemptState(t),s=this.read(n,t);if(s?.processIdentity===r)return{attempts:s.attemptCount,bundleIdentity:t,kind:"duplicate"};let i=Date.now(),c=s!==null&&i-s.attemptedAt<He;if(c&&s.attemptCount>=Me)return{attempts:s.attemptCount,bundleIdentity:t,kind:"circuit-open"};let l=c?s.attemptCount+1:1,y={attemptCount:l,attemptedAt:i,bundleIdentity:t,processIdentity:r,schemaVersion:1};return this.writer.write(n,`${JSON.stringify(y)}
4
+ `,384),{attempt:l,bundleIdentity:t,kind:"attempt"}}clear(e){this.filesystem.rmSync(this.paths.recoveryAttemptState(e.bundleIdentity),{force:!0});try{this.filesystem.rmdirSync(this.paths.recoveryAttemptStateRoot)}catch(t){if(!["ENOENT","ENOTEMPTY"].includes(t.code??""))throw t}}bundleIdentity(e){let t=this.filesystem.statSync(e.appPath,{bigint:!0});if(!t.isDirectory())throw new Error("Claude recovery target must be an application directory");return`${t.dev}:${t.ino}:${e.desktopVersion}:${e.bundleVersion}`}read(e,t){if(!this.filesystem.existsSync(e))return null;try{let r=JSON.parse(this.filesystem.readFileSync(e,"utf8"));if(r.schemaVersion===1&&r.bundleIdentity===t&&typeof r.processIdentity=="string"&&r.processIdentity.length>0&&Number.isSafeInteger(r.attemptCount)&&(r.attemptCount??0)>0&&Number.isSafeInteger(r.attemptedAt)&&(r.attemptedAt??0)>0)return r}catch{}return null}};var O=class extends Error{constructor(t,r,n){super(n instanceof Error?n.message:String(n),{cause:n});this.attempt=t;this.bundleIdentity=r;this.name="ClaudeRecoveryAttemptError"}attempt;bundleIdentity},fe=".vite/build/index.pre.js",me="com.anthropic.claudefordesktop",z=class{constructor(e){this.filesystem=e}filesystem;install(e){let t=performance.now(),r=this.filesystem.realpathSync.native(e.appPath),n=new v({[E]:e.storageRoot});if(!this.isRealFile(n.enabledMarker))return this.report("uninstalled",t);let s=new T(n,this.filesystem),i=s.read(r);if(!i)return this.report("uninstalled",t);if(new _(n,this.filesystem).isActive(r,{pid:e.mainPid,startedAt:e.mainStartedAt}))return this.report("admission-active",t);let l=w.default.join(r,"Contents","Resources","app.asar"),y=w.default.join(r,"Contents","Info.plist"),m=this.readRealFile(y,"Claude Info.plist"),p=this.readBundleMetadata(m),d=new U(n,this.filesystem),u=d.register({appPath:r,bundleVersion:p.bundleVersion,desktopVersion:p.desktopVersion,mainPid:e.mainPid,mainStartedAt:e.mainStartedAt});if(u.kind==="circuit-open")return this.report("circuit-open",t,void 0,u);if(u.kind==="duplicate")return this.report("duplicate-attempt",t,void 0,u);let A=null,g=null,f;try{g=this.realFileBytes(l,"Claude ASAR");let C=i.bundleVersion===p.bundleVersion&&i.desktopVersion===p.desktopVersion&&i.resources.asar.bytes===g&&i.resources.infoPlist.bytes===m.length,I=new D(n,this.filesystem);(!C||!I.hasFixedSizeResources(r,g,m.length))&&I.retain(r,this.readRealFile(l,"Claude ASAR"),m);let S=new V({crypto:J.default,fs:this.filesystem}),W=performance.now();if(A=S.install({asarPath:l,bootstrapNamespace:e.bootstrapNamespace,entryPath:fe,infoPlistPath:y}),f=performance.now()-W,!A.didPatch)return d.clear(u),this.report("already-patched",t,f,u);if(!A.infoPlistAsarIntegrity)throw new Error("Claude bootstrap patch did not expose its Info.plist integrity segment");let X=this.patchIdentity(A),ve=this.reuseResourceIdentities(i,p,X)?i.resources:this.resourceIdentities(n,r,l,y,g,m.length),we={schemaVersion:1,appPath:r,bundleIdentifier:me,bundleVersion:p.bundleVersion,desktopVersion:p.desktopVersion,entryPath:fe,installedAt:new Date().toISOString(),resources:ve,runtimeVersion:e.runtimeVersion,sealedResourcePatch:X};return s.publish(we),d.clear(u),this.report("patched",t,f,u)}catch(C){throw A?.didPatch&&A.infoPlistAsarIntegrity&&g!==null&&new L(this.filesystem).restore({patch:this.patchIdentity(A),resourceBytes:{asar:g,infoPlist:m.length},sourceAsarPath:w.default.join(n.pristineApp(r),"Contents","Resources","app.asar"),sourceInfoPlistPath:w.default.join(n.pristineApp(r),"Contents","Info.plist"),targetAsarPath:l,targetInfoPlistPath:y}),new O(u.attempt,u.bundleIdentity,C)}}report(e,t,r,n){return{...n===void 0?{}:{attempts:n.kind==="attempt"?n.attempt:n.attempts,bundleIdentity:n.bundleIdentity},...r===void 0?{}:{patchMs:r},result:e,totalMs:performance.now()-t}}patchIdentity(e){return{asarEntry:this.segmentIdentity(e.entry),asarEntryIntegrity:this.segmentIdentity(e.headerIntegrity),asarHeader:this.segmentIdentity(e.header),infoPlistAsarIntegrity:this.segmentIdentity(e.infoPlistAsarIntegrity)}}segmentIdentity(e){return{bytes:e.bytes,offset:e.offset,patchedSha256:e.patchedSha256,pristineSha256:e.originalSha256}}reuseResourceIdentities(e,t,r){return e.bundleVersion===t.bundleVersion&&e.desktopVersion===t.desktopVersion&&e.sealedResourcePatch!==void 0&&JSON.stringify(e.sealedResourcePatch)===JSON.stringify(r)}resourceIdentities(e,t,r,n,s,i){let c=e.pristineApp(t);return{asar:this.resourceIdentity(s,w.default.join(c,"Contents","Resources","app.asar"),r),infoPlist:this.resourceIdentity(i,w.default.join(c,"Contents","Info.plist"),n)}}resourceIdentity(e,t,r){return{bytes:e,patchedSha256:this.sha256File(r),pristineSha256:this.sha256File(t)}}readBundleMetadata(e){let t=e.toString("utf8");if(this.readPlistString(t,"CFBundleIdentifier")!==me)throw new Error("Recovery target is not Claude Desktop");return{bundleVersion:this.readPlistString(t,"CFBundleVersion"),desktopVersion:this.readPlistString(t,"CFBundleShortVersionString")}}readPlistString(e,t){let r=[...e.matchAll(new RegExp(`<key>${t}</key>\\s*<string>([^<]+)</string>`,"g"))];if(r.length!==1||!r[0]?.[1])throw new Error(`Claude Info.plist ${t} must occur exactly once`);return r[0][1]}realFileBytes(e,t){let r=this.filesystem.lstatSync(e);if(!r.isFile()||r.isSymbolicLink())throw new Error(`${t} must be a real file`);return r.size}readRealFile(e,t){return this.realFileBytes(e,t),this.filesystem.readFileSync(e)}isRealFile(e){try{let t=this.filesystem.lstatSync(e);return t.isFile()&&!t.isSymbolicLink()}catch(t){if(t.code==="ENOENT")return!1;throw t}}sha256File(e){let t=this.filesystem.openSync(e,"r"),r=(0,J.createHash)("sha256"),n=Buffer.allocUnsafe(1024*1024);try{let s=0;do s=this.filesystem.readSync(t,n,0,n.length,null),r.update(n.subarray(0,s));while(s>0)}finally{this.filesystem.closeSync(t)}return r.digest("hex")}};var Se=h(require("node:path"),1);function Pe(a){if(!a||typeof a!="object")throw new Error("Claude recovery configuration must be an object");let e=a;if(e.schemaVersion!==1||!ge(e.coordinatorHook)||!ge(e.storageRoot)||typeof e.runtimeVersion!="string"||e.runtimeVersion.length===0||!je(e.bootstrapNamespace))throw new Error("Claude recovery configuration is invalid");return e}function ge(a){return typeof a=="string"&&Se.default.isAbsolute(a)&&![...a].some(e=>{let t=e.codePointAt(0);return t<=31||t===127})}function je(a){return a===".s"||a===".d"||a===".e"}var N=require("node:child_process"),P=h(require("node:path"),1);var be=require("node:child_process");function Ae(a){if(!Number.isSafeInteger(a)||a<=1)throw new Error("Claude process ID is invalid");let e=(0,be.execFileSync)("/bin/ps",["-p",String(a),"-o","lstart="],{encoding:"utf8",env:{...process.env,LC_ALL:"C"}}).trim().replace(/\s+/g," ");if(!e||Number.isNaN(Date.parse(e)))throw new Error("Claude process start time is unavailable");return{pid:a,startedAt:e}}var Ve=`${P.default.sep}Contents${P.default.sep}Frameworks${P.default.sep}`,q=class{constructor(e,t){this.extensionDirectory=e;this.filesystem=t}extensionDirectory;filesystem;discover(){let e=this.filesystem.realpathSync.native(this.extensionDirectory);if(P.default.basename(e)!=="local.supercode-recovery"||P.default.basename(P.default.dirname(e))!=="Claude Extensions")throw new Error("Recovery server is not installed in the expected Claude extension directory");let t=this.filesystem.realpathSync.native(process.execPath),r=t.indexOf(Ve);if(r<=0||!t.includes(`${P.default.sep}Claude Helper (Plugin).app${P.default.sep}`))throw new Error("Recovery did not start in Claude Helper (Plugin)");let n=this.filesystem.realpathSync.native(t.slice(0,r));if(P.default.basename(n)!=="Claude.app")throw new Error("Recovery helper does not belong to Claude.app");let s=process.ppid;if(!Number.isSafeInteger(s)||s<=1)throw new Error("Claude recovery parent PID is invalid");let i=P.default.join(n,"Contents","MacOS","Claude"),c=(0,N.execFileSync)("/bin/ps",["-p",String(s),"-o","comm="],{encoding:"utf8"}).trim(),l=Number((0,N.execFileSync)("/bin/ps",["-p",String(s),"-o","uid="],{encoding:"utf8"}).trim());if(this.filesystem.realpathSync.native(c)!==this.filesystem.realpathSync.native(i))throw new Error("Recovery helper parent is not the exact Claude main executable");if(l!==process.getuid?.())throw new Error("Recovery helper parent belongs to another user");return{appPath:n,mainPid:s,mainStartedAt:Ae(s).startedAt,userDataPath:P.default.resolve(e,"..","..")}}coordinateRelaunch(e,t){(0,N.spawn)("/bin/zsh",["-f",t.coordinatorHook,"--app",e.appPath,"--pid",String(e.mainPid),"--storage-root",t.storageRoot,"--bootstrap-namespace",t.bootstrapNamespace,"--user-data-dir",e.userDataPath],{detached:!0,env:process.env,stdio:"ignore"}).unref()}};var K=class{input="";start(){process.stdin.setEncoding("utf8"),process.stdin.on("data",e=>this.receive(e)),setImmediate(()=>{this.recover()})}async recover(){let e=performance.now(),t=G.default.join(__dirname,"recovery.json");if(!B.default.existsSync(t))return;let r=null;try{r=Pe(JSON.parse(B.default.readFileSync(t,"utf8")));let n=r;this.write(n,"recovery-started");let i=(0,Re.createRequire)(__filename)("original-fs"),c=new q(__dirname,i),l=c.discover(),y=new v({[E]:r.storageRoot});await new M(y.lifecycleLock).run(()=>{let p=new z(i);this.write(n,`recovery-patch-started pid=${l.mainPid}`);let d=p.install({appPath:l.appPath,bootstrapNamespace:n.bootstrapNamespace,mainPid:l.mainPid,mainStartedAt:l.mainStartedAt,runtimeVersion:n.runtimeVersion,storageRoot:n.storageRoot});if(d.result==="circuit-open"){this.write(n,`circuit-open identity=${d.bundleIdentity} attempts=${d.attempts??0} pid=${l.mainPid}`);return}if(d.result==="duplicate-attempt"){this.write(n,`recovery-skipped reason=duplicate identity=${d.bundleIdentity} attempts=${d.attempts??0} pid=${l.mainPid}`);return}this.write(n,`recovery-result result=${d.result} pid=${l.mainPid} patchMs=${d.patchMs?.toFixed(3)??"0"} installationMs=${d.totalMs.toFixed(3)} totalMs=${this.millisecondsSince(e)}`),d.result==="patched"&&c.coordinateRelaunch(l,n)})}catch(n){let s=n instanceof O?` identity=${n.bundleIdentity} attempt=${n.attempt}`:"";this.write(r,`recovery-failed${s} error=${this.formatError(n)}`)}}millisecondsSince(e){return(performance.now()-e).toFixed(3)}receive(e){for(this.input+=e;this.input.includes(`
5
+ `);){let t=this.input.indexOf(`
6
+ `),r=this.input.slice(0,t);if(this.input=this.input.slice(t+1),!!r)try{this.respond(JSON.parse(r))}catch{}}}respond(e){if(e.id===void 0)return;let t={};e.method==="initialize"?t={capabilities:{},protocolVersion:typeof e.params?.protocolVersion=="string"?e.params.protocolVersion:"2025-06-18",serverInfo:{name:"supercode-recovery",version:"0.1.0"}}:e.method==="tools/list"?t={tools:[]}:e.method==="resources/list"?t={resources:[]}:e.method==="prompts/list"&&(t={prompts:[]}),process.stdout.write(`${JSON.stringify({id:e.id,jsonrpc:"2.0",result:t})}
7
+ `)}write(e,t){try{if(!e)return;let r=new v({[E]:e.storageRoot});B.default.mkdirSync(G.default.dirname(r.recoveryLog),{mode:448,recursive:!0}),B.default.appendFileSync(r.recoveryLog,`${new Date().toISOString()} ${t}
8
+ `,{mode:384})}catch{}}formatError(e){return e instanceof Error?e.message.replace(/[\r\n]+/g," "):String(e).replace(/[\r\n]+/g," ")}},$e=new K;$e.start();
package/dist/version ADDED
@@ -0,0 +1 @@
1
+ 0.1.1
package/package.json CHANGED
@@ -1,22 +1,26 @@
1
1
  {
2
2
  "name": "@supercode-sh/claude-install-mac",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Installer for the Supercode Claude Desktop integration on macOS.",
5
5
  "type": "module",
6
6
  "bin": {
7
- "claude-install-mac": "bin/noop.mjs"
7
+ "claude-install-mac": "dist/claude-install-mac"
8
8
  },
9
9
  "files": [
10
- "bin/noop.mjs",
10
+ "dist/",
11
11
  "README.md"
12
12
  ],
13
+ "os": [
14
+ "darwin"
15
+ ],
13
16
  "engines": {
14
17
  "node": ">=18"
15
18
  },
16
19
  "scripts": {
17
- "build": "node --check bin/noop.mjs",
18
- "check:build": "node --check bin/noop.mjs",
19
- "verify:dist": "node --check bin/noop.mjs",
20
+ "prebuild": "npm --prefix ../extension run build:production",
21
+ "build": "node scripts/build.cjs",
22
+ "check:build": "node --check scripts/build.cjs && node --check scripts/ShellDistribution.cjs && /bin/zsh -n bin/claude-install-mac && /bin/zsh -n macos/common.zsh && /bin/zsh -n macos/claude-asar-bootstrap.zsh && /bin/zsh -n macos/claude-installation-state.zsh && /bin/zsh -n macos/claude-process.zsh && /bin/zsh -n macos/claude-recovery-extension.zsh && /bin/zsh -n macos/install.zsh && /bin/zsh -n macos/recover.zsh && /bin/zsh -n macos/mcp-stdio.zsh",
23
+ "verify:dist": "node scripts/build.cjs --verify-only",
20
24
  "prepack": "npm --prefix .. run check && npm run verify:dist"
21
25
  },
22
26
  "publishConfig": {
package/bin/noop.mjs DELETED
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- process.stdout.write('Supercode for Claude Desktop on macOS is not available in this preview package. No changes were made.\n');