VoiceWake: document escape path and reset stale forward command
This commit is contained in:
@@ -157,6 +157,7 @@ final class AppState: ObservableObject {
|
|||||||
|
|
||||||
var storedForwardCommand = UserDefaults.standard
|
var storedForwardCommand = UserDefaults.standard
|
||||||
.string(forKey: voiceWakeForwardCommandKey) ?? defaultVoiceWakeForwardCommand
|
.string(forKey: voiceWakeForwardCommandKey) ?? defaultVoiceWakeForwardCommand
|
||||||
|
// Guard against older prefs missing flags; the forwarder depends on these for replies.
|
||||||
if !storedForwardCommand.contains("--deliver") || !storedForwardCommand.contains("--session") {
|
if !storedForwardCommand.contains("--deliver") || !storedForwardCommand.contains("--session") {
|
||||||
storedForwardCommand = defaultVoiceWakeForwardCommand
|
storedForwardCommand = defaultVoiceWakeForwardCommand
|
||||||
UserDefaults.standard.set(storedForwardCommand, forKey: voiceWakeForwardCommandKey)
|
UserDefaults.standard.set(storedForwardCommand, forKey: voiceWakeForwardCommandKey)
|
||||||
|
|||||||
@@ -108,21 +108,23 @@ final class HealthStore: ObservableObject {
|
|||||||
env: env,
|
env: env,
|
||||||
timeout: 15)
|
timeout: 15)
|
||||||
|
|
||||||
guard response.ok, let data = response.payload, !data.isEmpty else {
|
// Always try to decode JSON even when the CLI exits non-zero; it prints the
|
||||||
self.lastError = response.message ?? "health probe failed"
|
// failure snapshot before exiting so we can surface a useful message.
|
||||||
if onDemand { self.snapshot = nil }
|
if let data = response.payload, !data.isEmpty,
|
||||||
|
let decoded = try? JSONDecoder().decode(HealthSnapshot.self, from: data)
|
||||||
|
{
|
||||||
|
self.snapshot = decoded
|
||||||
|
if response.ok {
|
||||||
|
self.lastSuccess = Date()
|
||||||
|
self.lastError = nil
|
||||||
|
} else {
|
||||||
|
self.lastError = self.describeFailure(from: decoded)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
self.lastError = response.message ?? "health probe failed"
|
||||||
let decoded = try JSONDecoder().decode(HealthSnapshot.self, from: data)
|
if onDemand { self.snapshot = nil }
|
||||||
self.snapshot = decoded
|
|
||||||
self.lastSuccess = Date()
|
|
||||||
self.lastError = nil
|
|
||||||
} catch {
|
|
||||||
self.lastError = error.localizedDescription
|
|
||||||
if onDemand { self.snapshot = nil }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var state: HealthState {
|
var state: HealthState {
|
||||||
@@ -147,6 +149,22 @@ final class HealthStore: ObservableObject {
|
|||||||
}
|
}
|
||||||
return "linked · auth \(auth) · socket ok"
|
return "linked · auth \(auth) · socket ok"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func describeFailure(from snap: HealthSnapshot) -> String {
|
||||||
|
if !snap.web.linked {
|
||||||
|
return "Not linked — run clawdis login"
|
||||||
|
}
|
||||||
|
if let connect = snap.web.connect, !connect.ok {
|
||||||
|
let code = connect.status.map { "status \($0)" } ?? "status unknown"
|
||||||
|
let elapsed = connect.elapsedMs.map { "\(Int($0))ms" } ?? "unknown duration"
|
||||||
|
let reason = connect.error ?? "connect failed"
|
||||||
|
return "\(reason) (\(code), \(elapsed))"
|
||||||
|
}
|
||||||
|
if !snap.ipc.exists {
|
||||||
|
return "IPC socket missing at \(snap.ipc.path)"
|
||||||
|
}
|
||||||
|
return "health probe failed"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func msToAge(_ ms: Double) -> String {
|
func msToAge(_ ms: Double) -> String {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
onlyBuiltDependencies:
|
onlyBuiltDependencies:
|
||||||
- '@whiskeysockets/baileys'
|
- '@whiskeysockets/baileys'
|
||||||
|
- esbuild
|
||||||
- sharp
|
- sharp
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ set -euo pipefail
|
|||||||
|
|
||||||
APP_BUNDLE="${1:-dist/Clawdis.app}"
|
APP_BUNDLE="${1:-dist/Clawdis.app}"
|
||||||
IDENTITY="${SIGN_IDENTITY:-}"
|
IDENTITY="${SIGN_IDENTITY:-}"
|
||||||
ENT_TMP=$(mktemp /tmp/clawdis-entitlements.XXXXXX.plist)
|
ENT_TMP=$(mktemp -t clawdis-entitlements)
|
||||||
|
|
||||||
if [ ! -d "$APP_BUNDLE" ]; then
|
if [ ! -d "$APP_BUNDLE" ]; then
|
||||||
echo "App bundle not found: $APP_BUNDLE" >&2
|
echo "App bundle not found: $APP_BUNDLE" >&2
|
||||||
@@ -51,6 +51,8 @@ cat > "$ENT_TMP" <<'PLIST'
|
|||||||
<dict>
|
<dict>
|
||||||
<key>com.apple.security.hardened-runtime</key>
|
<key>com.apple.security.hardened-runtime</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>com.apple.security.cs.allow-jit</key>
|
||||||
|
<true/>
|
||||||
<key>com.apple.security.automation.apple-events</key>
|
<key>com.apple.security.automation.apple-events</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.security.device.audio-input</key>
|
<key>com.apple.security.device.audio-input</key>
|
||||||
@@ -75,6 +77,13 @@ if [ -f "$APP_BUNDLE/Contents/MacOS/ClawdisCLI" ]; then
|
|||||||
echo "Signing CLI helper"; sign_item "$APP_BUNDLE/Contents/MacOS/ClawdisCLI"
|
echo "Signing CLI helper"; sign_item "$APP_BUNDLE/Contents/MacOS/ClawdisCLI"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Sign bundled relay runtime bits (bun, native addons, libvips dylibs)
|
||||||
|
if [ -d "$APP_BUNDLE/Contents/Resources/Relay" ]; then
|
||||||
|
find "$APP_BUNDLE/Contents/Resources/Relay" -type f \( -name "bun" -o -name "*.node" -o -name "*.dylib" \) -print0 | while IFS= read -r -d '' f; do
|
||||||
|
echo "Signing relay payload: $f"; sign_item "$f"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
# Sign any embedded frameworks/dylibs if they ever appear
|
# Sign any embedded frameworks/dylibs if they ever appear
|
||||||
if [ -d "$APP_BUNDLE/Contents/Frameworks" ]; then
|
if [ -d "$APP_BUNDLE/Contents/Frameworks" ]; then
|
||||||
find "$APP_BUNDLE/Contents/Frameworks" \( -name "*.framework" -o -name "*.dylib" \) -print0 | while IFS= read -r -d '' f; do
|
find "$APP_BUNDLE/Contents/Frameworks" \( -name "*.framework" -o -name "*.dylib" \) -print0 | while IFS= read -r -d '' f; do
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ GIT_COMMIT=$(cd "$ROOT_DIR" && git rev-parse --short HEAD 2>/dev/null || echo "u
|
|||||||
APP_VERSION="${APP_VERSION:-$PKG_VERSION}"
|
APP_VERSION="${APP_VERSION:-$PKG_VERSION}"
|
||||||
APP_BUILD="${APP_BUILD:-$PKG_VERSION}"
|
APP_BUILD="${APP_BUILD:-$PKG_VERSION}"
|
||||||
|
|
||||||
|
echo "📦 Building JS (pnpm build)"
|
||||||
|
(cd "$ROOT_DIR" && pnpm build)
|
||||||
|
|
||||||
cd "$ROOT_DIR/apps/macos"
|
cd "$ROOT_DIR/apps/macos"
|
||||||
|
|
||||||
echo "🔨 Building $PRODUCT (debug)"
|
echo "🔨 Building $PRODUCT (debug)"
|
||||||
@@ -26,6 +29,7 @@ echo "🧹 Cleaning old app bundle"
|
|||||||
rm -rf "$APP_ROOT"
|
rm -rf "$APP_ROOT"
|
||||||
mkdir -p "$APP_ROOT/Contents/MacOS"
|
mkdir -p "$APP_ROOT/Contents/MacOS"
|
||||||
mkdir -p "$APP_ROOT/Contents/Resources"
|
mkdir -p "$APP_ROOT/Contents/Resources"
|
||||||
|
mkdir -p "$APP_ROOT/Contents/Resources/Relay"
|
||||||
|
|
||||||
echo "📄 Writing Info.plist"
|
echo "📄 Writing Info.plist"
|
||||||
cat > "$APP_ROOT/Contents/Info.plist" <<PLIST
|
cat > "$APP_ROOT/Contents/Info.plist" <<PLIST
|
||||||
@@ -79,6 +83,36 @@ cp "$ROOT_DIR/apps/macos/Sources/Clawdis/Resources/Clawdis.icns" "$APP_ROOT/Cont
|
|||||||
echo "📦 Copying WebChat resources"
|
echo "📦 Copying WebChat resources"
|
||||||
rsync -a "$ROOT_DIR/apps/macos/Sources/Clawdis/Resources/WebChat" "$APP_ROOT/Contents/Resources/"
|
rsync -a "$ROOT_DIR/apps/macos/Sources/Clawdis/Resources/WebChat" "$APP_ROOT/Contents/Resources/"
|
||||||
|
|
||||||
|
RELAY_DIR="$APP_ROOT/Contents/Resources/Relay"
|
||||||
|
BUN_SRC="${BUN_PATH:-$(command -v bun || true)}"
|
||||||
|
if [ -z "$BUN_SRC" ] || [ ! -x "$BUN_SRC" ]; then
|
||||||
|
echo "bun binary not found (set BUN_PATH to override)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "🧰 Staging relay runtime (bun + dist + node_modules)"
|
||||||
|
cp "$BUN_SRC" "$RELAY_DIR/bun"
|
||||||
|
chmod +x "$RELAY_DIR/bun"
|
||||||
|
rsync -a --delete --exclude "Clawdis.app" "$ROOT_DIR/dist/" "$RELAY_DIR/dist/"
|
||||||
|
cp "$ROOT_DIR/package.json" "$RELAY_DIR/"
|
||||||
|
cp "$ROOT_DIR/pnpm-lock.yaml" "$RELAY_DIR/"
|
||||||
|
if [ -f "$ROOT_DIR/.npmrc" ]; then
|
||||||
|
cp "$ROOT_DIR/.npmrc" "$RELAY_DIR/"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "📦 Installing prod node_modules into bundle (hoisted, scripts enabled for sharp)"
|
||||||
|
PNPM_STORE_DIR="$RELAY_DIR/.pnpm-store" \
|
||||||
|
PNPM_HOME="$HOME/Library/pnpm" \
|
||||||
|
pnpm install \
|
||||||
|
--prod \
|
||||||
|
--frozen-lockfile \
|
||||||
|
--config.node-linker=hoisted \
|
||||||
|
--config.ignore-workspace-root-check=true \
|
||||||
|
--config.shared-workspace-lockfile=false \
|
||||||
|
--modules-dir "$RELAY_DIR/node_modules" \
|
||||||
|
--lockfile-dir "$ROOT_DIR" \
|
||||||
|
--dir "$RELAY_DIR"
|
||||||
|
|
||||||
if [ -f "$CLI_BIN" ]; then
|
if [ -f "$CLI_BIN" ]; then
|
||||||
echo "🔧 Copying CLI helper"
|
echo "🔧 Copying CLI helper"
|
||||||
cp "$CLI_BIN" "$APP_ROOT/Contents/MacOS/ClawdisCLI"
|
cp "$CLI_BIN" "$APP_ROOT/Contents/MacOS/ClawdisCLI"
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import {
|
|||||||
setHeartbeatsEnabled,
|
setHeartbeatsEnabled,
|
||||||
type WebMonitorTuning,
|
type WebMonitorTuning,
|
||||||
} from "../provider-web.js";
|
} from "../provider-web.js";
|
||||||
import { defaultRuntime } from "../runtime.js";
|
import { defaultRuntime, type RuntimeEnv } from "../runtime.js";
|
||||||
import { VERSION } from "../version.js";
|
import { VERSION } from "../version.js";
|
||||||
import {
|
import {
|
||||||
resolveHeartbeatSeconds,
|
resolveHeartbeatSeconds,
|
||||||
@@ -252,10 +252,12 @@ Examples:
|
|||||||
}
|
}
|
||||||
|
|
||||||
const logs: string[] = [];
|
const logs: string[] = [];
|
||||||
const runtime = {
|
const runtime: RuntimeEnv = {
|
||||||
log: (msg: string) => logs.push(String(msg)),
|
log: (msg: string) => logs.push(String(msg)),
|
||||||
error: (msg: string) => logs.push(String(msg)),
|
error: (msg: string) => logs.push(String(msg)),
|
||||||
exit: (_code: number) => {},
|
exit: (_code: number): never => {
|
||||||
|
throw new Error("agentCommand requested exit");
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const opts: {
|
const opts: {
|
||||||
|
|||||||
Reference in New Issue
Block a user