Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Logs
logs
*.log
*.pid
npm-debug.log*
yarn-debug.log*
yarn-error.log*
Expand All @@ -25,3 +26,9 @@ dist-ssr
/release-artifacts
CodexMonitor.zip
.codex-worktrees/
codexmonitorMac.provisionprofile
screen-ipad-size.png
screen-ipad-size-small.png
src-tauri/gen/
ilass-planing/transportAbstraction.md
.run/
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,23 @@
"build:appimage": "NO_STRIP=1 tauri build --bundles appimage",
"typecheck": "tsc --noEmit",
"preview": "vite preview",
"tauri": "tauri"
"macos:build-signed": "bash scripts/macos-build-signed.sh",
"tauri": "PATH=$HOME/.cargo/bin:$PATH tauri"
},
"dependencies": {
"@tauri-apps/api": "^2",
"@tauri-apps/plugin-dialog": "^2",
"@tauri-apps/plugin-dialog": "^2.6.0",
"@tauri-apps/plugin-opener": "^2",
"@tauri-apps/plugin-process": "^2.3.1",
"@tauri-apps/plugin-updater": "^2.9.0",
"@xterm/addon-fit": "^0.10.0",
"@xterm/xterm": "^5.5.0",
"lucide-react": "^0.562.0",
"prismjs": "^1.30.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-markdown": "^10.1.0",
"remark-gfm": "^4.0.1",
"@xterm/xterm": "^5.5.0",
"@xterm/addon-fit": "^0.10.0"
"remark-gfm": "^4.0.1"
},
"devDependencies": {
"@tauri-apps/cli": "^2",
Expand Down
38 changes: 38 additions & 0 deletions scripts/ios-build-device.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env bash
set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"

# Ensure we don't accidentally pick up an older MacPorts cargo (e.g. /opt/local/bin/cargo).
NODE_BIN="$(command -v node)"
NODE_DIR="$(cd "$(dirname "${NODE_BIN}")" && pwd)"

export PATH="${ROOT_DIR}/node_modules/.bin:${HOME}/.cargo/bin:${NODE_DIR}:/usr/bin:/bin:/usr/sbin:/sbin"

cd "${ROOT_DIR}"

echo "[ios] Using cargo: $(command -v cargo)"
cargo -V

rm -rf "${ROOT_DIR}/src-tauri/gen/apple/build"

echo "[ios] Building (device)..."
npm run tauri -- ios build -d -t aarch64 --ci

IPA_PATH="${ROOT_DIR}/src-tauri/gen/apple/build/arm64/CodexMonitor.ipa"
if [[ -f "${IPA_PATH}" ]]; then
echo "[ios] Extracting .app from ${IPA_PATH}..."
TMP_DIR="${ROOT_DIR}/src-tauri/gen/apple/build/arm64/_ipa_extract"
rm -rf "${TMP_DIR}"
mkdir -p "${TMP_DIR}"
unzip -q "${IPA_PATH}" -d "${TMP_DIR}"
APP_IN_PAYLOAD="${TMP_DIR}/Payload/CodexMonitor.app"
OUT_APP="${ROOT_DIR}/src-tauri/gen/apple/build/arm64/CodexMonitor.app"
rm -rf "${OUT_APP}"
if [[ -d "${APP_IN_PAYLOAD}" ]]; then
cp -R "${APP_IN_PAYLOAD}" "${OUT_APP}"
echo "[ios] Extracted app bundle to: ${OUT_APP}"
else
echo "[ios] Warning: could not find Payload/CodexMonitor.app inside ipa." >&2
fi
fi
20 changes: 20 additions & 0 deletions scripts/ios-build-sim.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"

# Ensure we don't accidentally pick up an older MacPorts cargo (e.g. /opt/local/bin/cargo).
NODE_BIN="$(command -v node)"
NODE_DIR="$(cd "$(dirname "${NODE_BIN}")" && pwd)"

export PATH="${ROOT_DIR}/node_modules/.bin:${HOME}/.cargo/bin:${NODE_DIR}:/usr/bin:/bin:/usr/sbin:/sbin"

cd "${ROOT_DIR}"

echo "[ios] Using cargo: $(command -v cargo)"
cargo -V

rm -rf "${ROOT_DIR}/src-tauri/gen/apple/build"

echo "[ios] Building (simulator)..."
npm run tauri -- ios build -d -t aarch64-sim --ci
114 changes: 114 additions & 0 deletions scripts/ios-e2e-joke-device.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#!/usr/bin/env bash
set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "${ROOT_DIR}"

DEVICE="${1:-iPad von Peter (2)}"
CONTAINER_ID="${CODEXMONITOR_CLOUDKIT_CONTAINER_ID:-iCloud.com.ilass.codexmonitor}"
BUNDLE_ID="${BUNDLE_ID:-com.ilass.codexmonitor}"
APP_BIN="${APP_BIN:-${ROOT_DIR}/src-tauri/target/release/bundle/macos/CodexMonitor.app/Contents/MacOS/codex-monitor}"

OUT_DIR="${ROOT_DIR}/.run/ios/device"
mkdir -p "${OUT_DIR}"

export VITE_E2E=1
export CODEXMONITOR_CLOUDKIT_CONTAINER_ID="${CONTAINER_ID}"

echo "[ios-e2e-device] Building + installing with VITE_E2E=1..."
scripts/ios-build-device.sh

APP_PATH="${ROOT_DIR}/src-tauri/gen/apple/build/arm64/CodexMonitor.app"
if [[ ! -d "${APP_PATH}" ]]; then
echo "[ios-e2e-device] Expected app bundle not found at: ${APP_PATH}" >&2
exit 1
fi

echo "[ios-e2e-device] Installing to device: ${DEVICE}"
xcrun devicectl device install app --device "${DEVICE}" "${APP_PATH}"

STAMP="$(date +%Y%m%d-%H%M%S)"
LOG_PATH="${OUT_DIR}/e2e-${STAMP}.log"
echo "[ios-e2e-device] Launching ${BUNDLE_ID} on ${DEVICE}..."

START_MS="$(python3 -c 'import time; print(int(time.time()*1000))')"

/usr/bin/env DEVICECTL_CHILD_CODEXMONITOR_CLOUDKIT_CONTAINER_ID="${CONTAINER_ID}" \
xcrun devicectl device process launch \
--device "${DEVICE}" \
--terminate-existing \
--activate \
"${BUNDLE_ID}" > "${LOG_PATH}" 2>&1 || true

echo "[ios-e2e-device] Launch output:"
tail -n 120 "${LOG_PATH}" || true

if [[ ! -x "${APP_BIN}" ]]; then
echo "[ios-e2e-device] Error: macOS app binary not found/executable at: ${APP_BIN}" >&2
exit 1
fi

echo "[ios-e2e-device] Waiting for CloudKit command result (this verifies iPad -> CloudKit -> Mac runner -> Codex -> CloudKit)..."

DEADLINE_MS=$((START_MS + 180000))
while true; do
NOW_MS="$(python3 -c 'import time; print(int(time.time()*1000))')"
if (( NOW_MS > DEADLINE_MS )); then
echo "[ios-e2e-device] Timed out waiting for CloudKit command result." >&2
exit 1
fi

RUNNER_JSON="$("${APP_BIN}" --cloudkit-latest-runner "${CONTAINER_ID}" 2>/dev/null || true)"
RUNNER_ID="$(python3 - <<'PY' "${RUNNER_JSON}"
import json,sys
raw=sys.argv[1].strip()
if not raw:
sys.exit(0)
try:
data=json.loads(raw)
print(data.get("runnerId",""))
except Exception:
pass
PY
)"
if [[ -z "${RUNNER_ID}" ]]; then
sleep 2
continue
fi

RES_JSON="$("${APP_BIN}" --cloudkit-latest-command-result "${CONTAINER_ID}" "${RUNNER_ID}" 2>/dev/null || true)"
OK="$(python3 - <<'PY' "${RES_JSON}" "${START_MS}"
import json,sys
raw=sys.argv[1].strip()
start=int(sys.argv[2])
if not raw:
sys.exit(0)
try:
data=json.loads(raw)
except Exception:
sys.exit(0)
if not data:
sys.exit(0)
created=int(data.get("createdAtMs") or 0)
if created < start:
sys.exit(0)
if not data.get("ok"):
sys.exit(0)
payload=data.get("payloadJson") or ""
try:
inner=json.loads(payload)
except Exception:
inner={}
assistant=(inner.get("assistantText") or "").strip()
if not assistant:
sys.exit(0)
print("1")
PY
)"
if [[ "${OK}" == "1" ]]; then
echo "[ios-e2e-device] E2E SUCCESS"
exit 0
fi

sleep 2
done
40 changes: 40 additions & 0 deletions scripts/ios-e2e-joke-sim.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env bash
set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "${ROOT_DIR}"

UDID="${1:-}"
if [[ -z "${UDID}" ]]; then
UDID="$(xcrun simctl list devices booted | rg -o '[0-9A-Fa-f-]{36}' | head -n 1 || true)"
fi

if [[ -z "${UDID}" ]]; then
echo "[ios-e2e] No booted simulator found."
echo "[ios-e2e] Boot one first (e.g. via Simulator.app), then rerun:"
echo " scripts/ios-e2e-joke-sim.sh"
exit 1
fi

OUT_DIR="${ROOT_DIR}/.run/ios"
mkdir -p "${OUT_DIR}"

export VITE_E2E=1

if [[ -z "${CODEXMONITOR_CLOUDKIT_CONTAINER_ID:-}" ]]; then
echo "[ios-e2e] CODEXMONITOR_CLOUDKIT_CONTAINER_ID is not set."
echo "[ios-e2e] CloudKit access will likely fail without a container identifier."
fi

echo "[ios-e2e] Building + launching with VITE_E2E=1..."
scripts/ios-run-sim.sh "${UDID}"

echo "[ios-e2e] Waiting for CloudKit command/response..."
sleep 25

STAMP="$(date +%Y%m%d-%H%M%S)"
SCREENSHOT_PATH="${OUT_DIR}/e2e-joke-${STAMP}.png"
echo "[ios-e2e] Taking screenshot: ${SCREENSHOT_PATH}"
xcrun simctl io "${UDID}" screenshot "${SCREENSHOT_PATH}"

echo "[ios-e2e] Done."
54 changes: 54 additions & 0 deletions scripts/ios-run-sim.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env bash
set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"

cd "${ROOT_DIR}"

UDID="${1:-}"
if [[ -z "${UDID}" ]]; then
UDID="$(xcrun simctl list devices booted | rg -o '[0-9A-Fa-f-]{36}' | head -n 1 || true)"
fi

if [[ -z "${UDID}" ]]; then
echo "[ios] No booted simulator found."
echo "[ios] Boot one first (e.g. via Simulator.app), then rerun:"
echo " scripts/ios-run-sim.sh"
exit 1
fi

OUT_DIR="${ROOT_DIR}/.run/ios"
mkdir -p "${OUT_DIR}"

APP_PATH="${ROOT_DIR}/src-tauri/gen/apple/build/arm64-sim/CodexMonitor.app"
BUNDLE_ID="${BUNDLE_ID:-com.ilass.codexmonitor}"

scripts/ios-build-sim.sh

echo "[ios] Installing to simulator ${UDID}..."
xcrun simctl install "${UDID}" "${APP_PATH}"

STDOUT_LOG="${OUT_DIR}/app-stdout.log"
STDERR_LOG="${OUT_DIR}/app-stderr.log"

echo "[ios] Launching ${BUNDLE_ID} (logs: ${STDOUT_LOG}, ${STDERR_LOG})..."
if [[ -n "${CODEXMONITOR_CLOUDKIT_CONTAINER_ID:-}" ]]; then
echo "[ios] Setting CODEXMONITOR_CLOUDKIT_CONTAINER_ID for simulator runtime..."
xcrun simctl spawn "${UDID}" launchctl setenv \
CODEXMONITOR_CLOUDKIT_CONTAINER_ID "${CODEXMONITOR_CLOUDKIT_CONTAINER_ID}"
fi

xcrun simctl launch \
--terminate-running-process \
--stdout="${STDOUT_LOG}" \
--stderr="${STDERR_LOG}" \
"${UDID}" "${BUNDLE_ID}"

sleep 2

STAMP="$(date +%Y%m%d-%H%M%S)"
SCREENSHOT_PATH="${OUT_DIR}/screenshot-${STAMP}.png"
echo "[ios] Taking screenshot: ${SCREENSHOT_PATH}"
xcrun simctl io "${UDID}" screenshot "${SCREENSHOT_PATH}"

echo "[ios] Done."
48 changes: 48 additions & 0 deletions scripts/macos-build-signed.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env bash
set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"

APP_PATH="$ROOT_DIR/src-tauri/target/release/bundle/macos/CodexMonitor.app"
PROFILE_PATH="${CODEXMONITOR_PROVISIONPROFILE:-$ROOT_DIR/codexmonitorMac.provisionprofile}"
ENTITLEMENTS_PATH="${CODEXMONITOR_ENTITLEMENTS:-$ROOT_DIR/src-tauri/entitlements.macos.plist}"
SIGNING_IDENTITY="${CODEXMONITOR_CODESIGN_IDENTITY:-Apple Development: Peter Vogel (HUDS4L39Y8)}"

echo "[macos-build-signed] building…"
cd "$ROOT_DIR"
PATH="$HOME/.cargo/bin:$PATH" npm run tauri build

if [[ ! -d "$APP_PATH" ]]; then
echo "[macos-build-signed] error: app bundle not found at: $APP_PATH" >&2
exit 1
fi

if [[ ! -f "$ENTITLEMENTS_PATH" ]]; then
echo "[macos-build-signed] error: entitlements file not found at: $ENTITLEMENTS_PATH" >&2
exit 1
fi

if [[ ! -f "$PROFILE_PATH" ]]; then
echo "[macos-build-signed] error: provisioning profile not found at: $PROFILE_PATH" >&2
echo "[macos-build-signed] tip: set CODEXMONITOR_PROVISIONPROFILE=/path/to/profile.provisionprofile" >&2
exit 1
fi

echo "[macos-build-signed] embedding provisioning profile…"
cp "$PROFILE_PATH" "$APP_PATH/Contents/embedded.provisionprofile"

# Provisioning profiles downloaded from the Apple Developer portal can carry a
# quarantine xattr (e.g. if downloaded via Safari). Keeping it inside the app
# bundle can prevent the app from launching via LaunchServices.
xattr -dr com.apple.quarantine "$APP_PATH" 2>/dev/null || true

echo "[macos-build-signed] signing (nested)…"
codesign --force --deep --sign "$SIGNING_IDENTITY" "$APP_PATH"

echo "[macos-build-signed] signing (app entitlements)…"
codesign --force --sign "$SIGNING_IDENTITY" --entitlements "$ENTITLEMENTS_PATH" "$APP_PATH"

echo "[macos-build-signed] verifying…"
codesign --verify --deep --strict --verbose=2 "$APP_PATH"

echo "[macos-build-signed] done: $APP_PATH"
Loading