@arach/lattices 0.2.0 → 0.6.1
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/LICENSE +21 -0
- package/README.md +172 -86
- package/apps/mac/Info.plist +43 -0
- package/apps/mac/Lattices.app/Contents/Info.plist +43 -0
- package/apps/mac/Lattices.app/Contents/MacOS/Lattices +0 -0
- package/apps/mac/Lattices.app/Contents/Resources/AppIcon.icns +0 -0
- package/apps/mac/Lattices.app/Contents/Resources/docs/assistant-knowledge.md +130 -0
- package/apps/mac/Lattices.app/Contents/Resources/tap.wav +0 -0
- package/apps/mac/Lattices.app/Contents/_CodeSignature/CodeResources +150 -0
- package/apps/mac/Lattices.entitlements +21 -0
- package/apps/mac/Resources/Pets/assistant-spark/pet.json +62 -0
- package/apps/mac/Resources/Pets/assistant-spark/spritesheet.webp +0 -0
- package/apps/mac/Resources/Pets/scout-ranger/pet.json +6 -0
- package/apps/mac/Resources/Pets/scout-ranger/spritesheet.webp +0 -0
- package/apps/mac/Resources/tap.wav +0 -0
- package/assets/AppIcon.icns +0 -0
- package/bin/assistant-intelligence.ts +912 -0
- package/bin/cli/capture.ts +252 -0
- package/bin/cli/daemon.ts +22 -0
- package/bin/cli/helpers.ts +105 -0
- package/bin/cli/layer.ts +178 -0
- package/bin/cli/runs.ts +43 -0
- package/bin/cli/search.ts +141 -0
- package/bin/cli/session.ts +32 -0
- package/bin/client.ts +17 -0
- package/bin/cua.ts +26 -0
- package/bin/{daemon-client.js → daemon-client.ts} +49 -30
- package/bin/handsoff-infer.ts +96 -0
- package/bin/handsoff-worker.ts +531 -0
- package/bin/infer.ts +424 -0
- package/bin/keychain.ts +75 -0
- package/bin/lattices-app.ts +655 -0
- package/bin/lattices-build +125 -0
- package/bin/lattices-build-env.ts +77 -0
- package/bin/lattices-dev +362 -0
- package/bin/lattices.ts +3260 -0
- package/bin/project-twin.ts +645 -0
- package/docs/agent-execution-plan.md +562 -0
- package/docs/agent-layer-guide.md +207 -0
- package/docs/agents.md +233 -0
- package/docs/ai-chat-ux-review.md +416 -0
- package/docs/api.md +1041 -47
- package/docs/app.md +96 -13
- package/docs/assistant-knowledge.md +130 -0
- package/docs/companion-deck.md +209 -0
- package/docs/component-extraction-roadmap.md +392 -0
- package/docs/concepts.md +13 -12
- package/docs/config.md +83 -10
- package/docs/gesture-customization-proposal.md +520 -0
- package/docs/handsoff-test-scenarios.md +84 -0
- package/docs/hyperspace-grid-snappiness.md +210 -0
- package/docs/layers.md +176 -28
- package/docs/mouse-gestures.md +244 -0
- package/docs/ocr.md +21 -9
- package/docs/overview.md +42 -23
- package/docs/presentation-execution-review.md +491 -0
- package/docs/prompts/hands-off-system.md +382 -0
- package/docs/prompts/hands-off-turn.md +30 -0
- package/docs/prompts/voice-advisor.md +31 -0
- package/docs/prompts/voice-fallback.md +23 -0
- package/docs/proposals/LAT-001-gesture-visual-customization.md +522 -0
- package/docs/proposals/LAT-002-shared-overlay-canvas.md +353 -0
- package/docs/proposals/LAT-003-menu-bar-controller-architecture.md +291 -0
- package/docs/proposals/LAT-004-interactive-overlay-actors.md +534 -0
- package/docs/proposals/LAT-005-action-runtime-product-spine.md +914 -0
- package/docs/proposals/LAT-006-followup-gaps.md +103 -0
- package/docs/proposals/LAT-006-runs-and-capture-in-lattices.md +566 -0
- package/docs/proposals/LAT-007-unified-app-shell.md +128 -0
- package/docs/quickstart.md +8 -12
- package/docs/reference/dewey.config.ts +74 -0
- package/docs/reference/install-agent.md +79 -0
- package/docs/release.md +172 -0
- package/docs/repo-structure.md +100 -0
- package/docs/terminal-kit.md +87 -0
- package/docs/tiling-reference.md +224 -0
- package/docs/twins.md +138 -0
- package/docs/voice-command-protocol.md +278 -0
- package/docs/voice-error-model.md +73 -0
- package/docs/voice.md +221 -0
- package/package.json +69 -16
- package/packages/npm/sdk/cua.d.mts +1 -0
- package/packages/npm/sdk/cua.d.ts +188 -0
- package/packages/npm/sdk/cua.mjs +376 -0
- package/app/Lattices.app/Contents/Info.plist +0 -24
- package/app/Package.swift +0 -13
- package/app/Sources/ActionRow.swift +0 -61
- package/app/Sources/App.swift +0 -10
- package/app/Sources/AppDelegate.swift +0 -234
- package/app/Sources/AppShellView.swift +0 -62
- package/app/Sources/AppTypeClassifier.swift +0 -70
- package/app/Sources/AppWindowShell.swift +0 -63
- package/app/Sources/CheatSheetHUD.swift +0 -332
- package/app/Sources/CommandModeState.swift +0 -1362
- package/app/Sources/CommandModeView.swift +0 -1405
- package/app/Sources/CommandModeWindow.swift +0 -192
- package/app/Sources/CommandPaletteView.swift +0 -307
- package/app/Sources/CommandPaletteWindow.swift +0 -134
- package/app/Sources/DaemonProtocol.swift +0 -101
- package/app/Sources/DaemonServer.swift +0 -414
- package/app/Sources/DesktopModel.swift +0 -121
- package/app/Sources/DesktopModelTypes.swift +0 -71
- package/app/Sources/DiagnosticLog.swift +0 -271
- package/app/Sources/EventBus.swift +0 -30
- package/app/Sources/HotkeyManager.swift +0 -250
- package/app/Sources/HotkeyStore.swift +0 -338
- package/app/Sources/InventoryManager.swift +0 -35
- package/app/Sources/InventoryPath.swift +0 -43
- package/app/Sources/KeyRecorderView.swift +0 -210
- package/app/Sources/LatticesApi.swift +0 -1125
- package/app/Sources/MainView.swift +0 -467
- package/app/Sources/MainWindow.swift +0 -83
- package/app/Sources/OcrModel.swift +0 -309
- package/app/Sources/OcrStore.swift +0 -295
- package/app/Sources/OmniSearchState.swift +0 -283
- package/app/Sources/OmniSearchView.swift +0 -288
- package/app/Sources/OmniSearchWindow.swift +0 -105
- package/app/Sources/OrphanRow.swift +0 -129
- package/app/Sources/PaletteCommand.swift +0 -419
- package/app/Sources/PermissionChecker.swift +0 -125
- package/app/Sources/Preferences.swift +0 -92
- package/app/Sources/ProcessModel.swift +0 -199
- package/app/Sources/ProcessQuery.swift +0 -151
- package/app/Sources/Project.swift +0 -28
- package/app/Sources/ProjectRow.swift +0 -368
- package/app/Sources/ProjectScanner.swift +0 -121
- package/app/Sources/ScreenMapState.swift +0 -2387
- package/app/Sources/ScreenMapView.swift +0 -2820
- package/app/Sources/ScreenMapWindowController.swift +0 -89
- package/app/Sources/SessionManager.swift +0 -72
- package/app/Sources/SettingsView.swift +0 -1053
- package/app/Sources/SettingsWindow.swift +0 -20
- package/app/Sources/TabGroupRow.swift +0 -178
- package/app/Sources/Terminal.swift +0 -259
- package/app/Sources/TerminalQuery.swift +0 -156
- package/app/Sources/TerminalSynthesizer.swift +0 -200
- package/app/Sources/Theme.swift +0 -163
- package/app/Sources/TilePickerView.swift +0 -209
- package/app/Sources/TmuxModel.swift +0 -53
- package/app/Sources/TmuxQuery.swift +0 -81
- package/app/Sources/WindowTiler.swift +0 -1755
- package/app/Sources/WorkspaceManager.swift +0 -434
- package/bin/lattices-app.js +0 -221
- package/bin/lattices.js +0 -1418
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# lattices-build - explicit dev/package/dist build entry points
|
|
3
|
+
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
SCRIPT_PATH="$(readlink -f "$0" 2>/dev/null || python3 -c "import os,sys; print(os.path.realpath(sys.argv[1]))" "$0")"
|
|
7
|
+
ROOT="$(cd "$(dirname "$SCRIPT_PATH")/.." && pwd)"
|
|
8
|
+
|
|
9
|
+
DEV_APPS_DIR="${LATTICES_DEV_APPS_DIR:-$HOME/Applications/dev/Lattices}"
|
|
10
|
+
DEV_BUNDLE="${LATTICES_DEV_APP:-$DEV_APPS_DIR/Lattices.app}"
|
|
11
|
+
DEV_BUNDLE_ID="${LATTICES_DEV_BUNDLE_ID:-dev.lattices.app.dev}"
|
|
12
|
+
RELEASE_BUNDLE="$ROOT/apps/mac/Lattices.app"
|
|
13
|
+
RELEASE_BUNDLE_ID="dev.lattices.app"
|
|
14
|
+
DIST_BUNDLE="$ROOT/dist/Lattices.app"
|
|
15
|
+
DIST_DMG="$ROOT/dist/Lattices.dmg"
|
|
16
|
+
PROD_INSTALL_BUNDLE="/Applications/Lattices.app"
|
|
17
|
+
|
|
18
|
+
green() { printf "\033[32m%s\033[0m\n" "$*"; }
|
|
19
|
+
dim() { printf "\033[2m%s\033[0m\n" "$*"; }
|
|
20
|
+
red() { printf "\033[31m%s\033[0m\n" "$*"; }
|
|
21
|
+
|
|
22
|
+
usage() {
|
|
23
|
+
cat <<EOF
|
|
24
|
+
lattices-build - build Lattices without mixing dev and release identities
|
|
25
|
+
|
|
26
|
+
Usage:
|
|
27
|
+
bin/lattices-build dev Build/install dev app
|
|
28
|
+
bin/lattices-build dev:restart Build/install/relaunch dev app
|
|
29
|
+
bin/lattices-build package Build repo app bundle for npm packaging
|
|
30
|
+
bin/lattices-build dist Build signed/notarized release DMG
|
|
31
|
+
bin/lattices-build dist:local Build local release DMG without notarizing
|
|
32
|
+
bin/lattices-build where Show canonical paths and bundle ids
|
|
33
|
+
|
|
34
|
+
Channels:
|
|
35
|
+
dev $DEV_BUNDLE_ID -> $DEV_BUNDLE
|
|
36
|
+
release $RELEASE_BUNDLE_ID -> $PROD_INSTALL_BUNDLE via $DIST_DMG
|
|
37
|
+
EOF
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
plist_value() {
|
|
41
|
+
local app="$1"
|
|
42
|
+
local key="$2"
|
|
43
|
+
[ -d "$app" ] || return 0
|
|
44
|
+
/usr/bin/defaults read "$app/Contents/Info.plist" "$key" 2>/dev/null || true
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
show_app() {
|
|
48
|
+
local label="$1"
|
|
49
|
+
local app="$2"
|
|
50
|
+
|
|
51
|
+
echo "$label"
|
|
52
|
+
echo " path: $app"
|
|
53
|
+
if [ -d "$app" ]; then
|
|
54
|
+
echo " bundle id: $(plist_value "$app" CFBundleIdentifier)"
|
|
55
|
+
echo " channel: $(plist_value "$app" LatticesBuildChannel)"
|
|
56
|
+
echo " built at: $(plist_value "$app" LatticesBuildTimestamp)"
|
|
57
|
+
else
|
|
58
|
+
echo " status: not built"
|
|
59
|
+
fi
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
cmd_dev() {
|
|
63
|
+
"$ROOT/bin/lattices-dev" build
|
|
64
|
+
show_app "Dev app" "$DEV_BUNDLE"
|
|
65
|
+
green "Dev permission target: $DEV_BUNDLE"
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
cmd_dev_restart() {
|
|
69
|
+
"$ROOT/bin/lattices-dev" restart
|
|
70
|
+
show_app "Running dev app" "$DEV_BUNDLE"
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
cmd_package() {
|
|
74
|
+
if ! command -v bun >/dev/null 2>&1; then
|
|
75
|
+
red "bun is required for package builds."
|
|
76
|
+
exit 1
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
bun "$ROOT/bin/lattices-app.ts" build
|
|
80
|
+
show_app "Package app bundle" "$RELEASE_BUNDLE"
|
|
81
|
+
green "Package bundle ready: $RELEASE_BUNDLE"
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
cmd_dist() {
|
|
85
|
+
"$ROOT/tools/release/build-dmg.sh" "$@"
|
|
86
|
+
show_app "Release app artifact" "$DIST_BUNDLE"
|
|
87
|
+
[ -f "$DIST_DMG" ] && ls -lh "$DIST_DMG"
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
cmd_dist_local() {
|
|
91
|
+
LATTICES_SKIP_NOTARIZE=1 "$ROOT/tools/release/build-dmg.sh" "$@"
|
|
92
|
+
show_app "Local release app artifact" "$DIST_BUNDLE"
|
|
93
|
+
[ -f "$DIST_DMG" ] && ls -lh "$DIST_DMG"
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
cmd_where() {
|
|
97
|
+
show_app "Dev app" "$DEV_BUNDLE"
|
|
98
|
+
echo " expected bundle id: $DEV_BUNDLE_ID"
|
|
99
|
+
echo
|
|
100
|
+
show_app "Package app bundle" "$RELEASE_BUNDLE"
|
|
101
|
+
echo " expected bundle id: $RELEASE_BUNDLE_ID"
|
|
102
|
+
echo
|
|
103
|
+
show_app "Release app artifact" "$DIST_BUNDLE"
|
|
104
|
+
echo " expected install target: $PROD_INSTALL_BUNDLE"
|
|
105
|
+
[ -f "$DIST_DMG" ] && echo " dmg: $DIST_DMG"
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
cmd="${1:-help}"
|
|
109
|
+
shift || true
|
|
110
|
+
|
|
111
|
+
case "$cmd" in
|
|
112
|
+
dev) cmd_dev ;;
|
|
113
|
+
dev:restart|restart) cmd_dev_restart ;;
|
|
114
|
+
package) cmd_package ;;
|
|
115
|
+
dist) cmd_dist "$@" ;;
|
|
116
|
+
dist:local) cmd_dist_local "$@" ;;
|
|
117
|
+
where) cmd_where ;;
|
|
118
|
+
help|-h|--help) usage ;;
|
|
119
|
+
*)
|
|
120
|
+
red "Unknown command: $cmd"
|
|
121
|
+
echo
|
|
122
|
+
usage
|
|
123
|
+
exit 1
|
|
124
|
+
;;
|
|
125
|
+
esac
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* lattices-build-env — declarative build-feature resolver.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors openscout's `hkit` style: an app names *features* in a manifest
|
|
6
|
+
* (apps/mac/build.json), never raw env vars. The feature → build-env mapping
|
|
7
|
+
* lives in the catalog below, so every build entrypoint (package / dev / dist)
|
|
8
|
+
* resolves the same way from one source of truth, instead of each hardcoding
|
|
9
|
+
* its own `HUDSONKIT_WITH_*` flags.
|
|
10
|
+
*
|
|
11
|
+
* import { resolveBuildEnv } from "./lattices-build-env"; // TS callers
|
|
12
|
+
* eval "$(bun bin/lattices-build-env.ts shell)" // bash callers
|
|
13
|
+
* bun bin/lattices-build-env.ts json // inspect
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
17
|
+
import { join } from "node:path";
|
|
18
|
+
|
|
19
|
+
// Feature catalog: feature name -> build env HudsonKit gates on at SwiftPM
|
|
20
|
+
// manifest-eval time. HudsonVoice (Vox/Parakeet dictation) is an optional
|
|
21
|
+
// backend HudsonKit only declares when HUDSONKIT_WITH_VOICE=1 is set at build
|
|
22
|
+
// time. Name a *feature* here; never sprinkle the env var across build scripts.
|
|
23
|
+
export const FEATURE_CATALOG: Record<string, { env: Record<string, string>; note: string }> = {
|
|
24
|
+
voice: { env: { HUDSONKIT_WITH_VOICE: "1" }, note: "HudsonVoice — Vox/Parakeet dictation" },
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export interface BuildManifest {
|
|
28
|
+
app?: string;
|
|
29
|
+
features?: string[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const MANIFEST_PATH = join(import.meta.dir, "../apps/mac/build.json");
|
|
33
|
+
|
|
34
|
+
export function loadManifest(path = MANIFEST_PATH): BuildManifest {
|
|
35
|
+
if (!existsSync(path)) return {};
|
|
36
|
+
return JSON.parse(readFileSync(path, "utf8")) as BuildManifest;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function resolveFeatureEnv(features: string[] = []): Record<string, string> {
|
|
40
|
+
const env: Record<string, string> = {};
|
|
41
|
+
for (const f of features) {
|
|
42
|
+
const entry = FEATURE_CATALOG[f];
|
|
43
|
+
if (!entry) {
|
|
44
|
+
throw new Error(
|
|
45
|
+
`unknown build feature "${f}" — known features: ${Object.keys(FEATURE_CATALOG).join(", ")}`,
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
Object.assign(env, entry.env);
|
|
49
|
+
}
|
|
50
|
+
return env;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Resolve the manifest's declared features into a build-env map. */
|
|
54
|
+
export function resolveBuildEnv(manifestPath?: string): Record<string, string> {
|
|
55
|
+
const features = loadManifest(manifestPath).features ?? [];
|
|
56
|
+
const env = resolveFeatureEnv(features);
|
|
57
|
+
// HudsonKit enables HudsonVoice by default; opt out unless the voice feature is declared.
|
|
58
|
+
if (!features.includes("voice")) {
|
|
59
|
+
env.HUDSONKIT_WITH_VOICE = "0";
|
|
60
|
+
}
|
|
61
|
+
return env;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// --- CLI: emit the resolved env for shell / json consumers -------------------
|
|
65
|
+
if (import.meta.main) {
|
|
66
|
+
const mode = process.argv[2] ?? "shell";
|
|
67
|
+
const env = resolveBuildEnv();
|
|
68
|
+
if (mode === "json") {
|
|
69
|
+
console.log(JSON.stringify(env, null, 2));
|
|
70
|
+
} else if (mode === "shell") {
|
|
71
|
+
// eval-able by bash: `eval "$(bun bin/lattices-build-env.ts shell)"`
|
|
72
|
+
for (const [k, v] of Object.entries(env)) console.log(`export ${k}=${JSON.stringify(v)}`);
|
|
73
|
+
} else {
|
|
74
|
+
console.error(`lattices-build-env: unknown mode "${mode}" (use: shell | json)`);
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
}
|
package/bin/lattices-dev
ADDED
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# lattices-dev — convenience commands for Lattices development
|
|
3
|
+
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
SCRIPT_PATH="$(readlink -f "$0" 2>/dev/null || python3 -c "import os,sys; print(os.path.realpath(sys.argv[1]))" "$0")"
|
|
7
|
+
APP_DIR="$(cd "$(dirname "$SCRIPT_PATH")/../apps/mac" && pwd)"
|
|
8
|
+
ROOT="$(cd "$(dirname "$SCRIPT_PATH")/.." && pwd)"
|
|
9
|
+
LOG_FILE="$HOME/.lattices/lattices.log"
|
|
10
|
+
BINARY="$APP_DIR/.build/release/Lattices"
|
|
11
|
+
BUILD_BASE="$ROOT/build/macos/Lattices"
|
|
12
|
+
BUNDLE="$BUILD_BASE/Build/Products/Debug/Lattices.app"
|
|
13
|
+
DEV_APPS_DIR="${LATTICES_DEV_APPS_DIR:-$HOME/Applications/dev/Lattices}"
|
|
14
|
+
INSTALL_BUNDLE="${LATTICES_DEV_APP:-$DEV_APPS_DIR/Lattices.app}"
|
|
15
|
+
BUNDLE_BIN="$BUNDLE/Contents/MacOS/Lattices"
|
|
16
|
+
RESOURCES_DIR="$BUNDLE/Contents/Resources"
|
|
17
|
+
ENTITLEMENTS="$APP_DIR/Lattices.entitlements"
|
|
18
|
+
BUNDLE_ID="${LATTICES_DEV_BUNDLE_ID:-dev.lattices.app.dev}"
|
|
19
|
+
ICON="$ROOT/assets/AppIcon.icns"
|
|
20
|
+
TAP_SOUND="$APP_DIR/Resources/tap.wav"
|
|
21
|
+
VERSION="$(node -p "require('$ROOT/package.json').version" 2>/dev/null || echo '0.1.0')"
|
|
22
|
+
GIT_REVISION="$(git -C "$ROOT" rev-parse --short HEAD 2>/dev/null || echo 'unknown')"
|
|
23
|
+
BUILD_TIMESTAMP="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
|
24
|
+
|
|
25
|
+
red() { printf "\033[31m%s\033[0m\n" "$*"; }
|
|
26
|
+
green() { printf "\033[32m%s\033[0m\n" "$*"; }
|
|
27
|
+
dim() { printf "\033[2m%s\033[0m\n" "$*"; }
|
|
28
|
+
|
|
29
|
+
select_sign_identity() {
|
|
30
|
+
local identities identity=""
|
|
31
|
+
identities="$(security find-identity -v -p codesigning 2>/dev/null || true)"
|
|
32
|
+
# Prefer Developer ID Application: its designated requirement pins to the stable
|
|
33
|
+
# team OU, so TCC permissions survive rebuilds and Apple Development cert rotations.
|
|
34
|
+
# Apple Development is only a fallback (its DR pins a specific cert that Xcode rotates,
|
|
35
|
+
# which silently resets every granted permission). Keep this order in sync with
|
|
36
|
+
# resolveSigningIdentity() in bin/lattices-app.ts.
|
|
37
|
+
identity="$(printf '%s\n' "$identities" | sed -n 's/^[[:space:]]*[0-9]*)[[:space:]]*\([A-F0-9]\{40\}\)[[:space:]]*"Developer ID Application:[^"]*".*/\1/p' | head -n 1)"
|
|
38
|
+
if [ -z "$identity" ]; then
|
|
39
|
+
identity="$(printf '%s\n' "$identities" | sed -n 's/^[[:space:]]*[0-9]*)[[:space:]]*\([A-F0-9]\{40\}\)[[:space:]]*"Apple Development:[^"]*".*/\1/p' | head -n 1)"
|
|
40
|
+
fi
|
|
41
|
+
printf '%s' "$identity"
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
sign_bundle() {
|
|
45
|
+
local identity sign_status=0
|
|
46
|
+
local -a ent_flags=()
|
|
47
|
+
|
|
48
|
+
rm -f "$BUNDLE_BIN".cstemp
|
|
49
|
+
|
|
50
|
+
if [ -f "$ENTITLEMENTS" ]; then
|
|
51
|
+
ent_flags=(--entitlements "$ENTITLEMENTS")
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
identity="$(select_sign_identity)"
|
|
55
|
+
if [ -n "$identity" ]; then
|
|
56
|
+
dim "Signing with: $identity"
|
|
57
|
+
if ! codesign --force --options runtime --deep --sign "$identity" "${ent_flags[@]}" --identifier "$BUNDLE_ID" "$BUNDLE"; then
|
|
58
|
+
red "Signing with '$identity' failed. Falling back to ad-hoc."
|
|
59
|
+
sign_status=1
|
|
60
|
+
fi
|
|
61
|
+
else
|
|
62
|
+
sign_status=1
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
if [ "$sign_status" -ne 0 ]; then
|
|
66
|
+
dim "No usable signing identity found. Using ad-hoc signature."
|
|
67
|
+
codesign --force --options runtime --deep --sign - "${ent_flags[@]}" --identifier "$BUNDLE_ID" "$BUNDLE"
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
rm -f "$BUNDLE_BIN".cstemp
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
sync_bundle_copy() {
|
|
74
|
+
local destination="$1"
|
|
75
|
+
|
|
76
|
+
mkdir -p "$(dirname "$destination")"
|
|
77
|
+
rm -rf "$destination"
|
|
78
|
+
ditto "$BUNDLE" "$destination"
|
|
79
|
+
xattr -dr com.apple.quarantine "$destination" 2>/dev/null || true
|
|
80
|
+
touch "$destination" "$destination/Contents"
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
ensure_install_bundle() {
|
|
84
|
+
if [ -d "$INSTALL_BUNDLE" ]; then
|
|
85
|
+
return
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
if [ -d "$BUNDLE" ]; then
|
|
89
|
+
sync_bundle_copy "$INSTALL_BUNDLE"
|
|
90
|
+
return
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
cmd_build
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
clear_lattices_drag_cache() {
|
|
97
|
+
local cache_dir
|
|
98
|
+
|
|
99
|
+
for cache_dir in "$HOME"/Library/Caches/com.apple.SwiftUI.Drag-*; do
|
|
100
|
+
[ -d "$cache_dir" ] || continue
|
|
101
|
+
if [ -d "$cache_dir/Lattices.app" ]; then
|
|
102
|
+
rm -rf "$cache_dir/Lattices.app"
|
|
103
|
+
rmdir "$cache_dir" 2>/dev/null || true
|
|
104
|
+
fi
|
|
105
|
+
done
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
is_bundle_running() {
|
|
109
|
+
local bundle="$1"
|
|
110
|
+
local target="$bundle/Contents/MacOS/Lattices"
|
|
111
|
+
local pid args
|
|
112
|
+
|
|
113
|
+
while IFS= read -r pid; do
|
|
114
|
+
[ -n "$pid" ] || continue
|
|
115
|
+
args="$(ps -p "$pid" -o args= 2>/dev/null || true)"
|
|
116
|
+
case "$args" in
|
|
117
|
+
"$target"|"${target} "*) return 0 ;;
|
|
118
|
+
esac
|
|
119
|
+
done < <(pgrep -x Lattices 2>/dev/null || true)
|
|
120
|
+
|
|
121
|
+
return 1
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
is_install_bundle_running() {
|
|
125
|
+
is_bundle_running "$INSTALL_BUNDLE"
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
require_build_targets_not_running() {
|
|
129
|
+
if is_bundle_running "$BUNDLE"; then
|
|
130
|
+
red "Refusing to rebuild the repo-local app artifact while it is running."
|
|
131
|
+
dim "Rewriting or re-signing a live Mach-O can make macOS kill it later with Code Signature Invalid."
|
|
132
|
+
dim "Use \`lattices-dev restart\` to quit, rebuild, and relaunch."
|
|
133
|
+
exit 1
|
|
134
|
+
fi
|
|
135
|
+
|
|
136
|
+
if is_install_bundle_running; then
|
|
137
|
+
red "Refusing to install over the running dev app bundle."
|
|
138
|
+
dim "Rewriting or re-signing a live Mach-O can make macOS kill it later with Code Signature Invalid."
|
|
139
|
+
dim "Use \`lattices-dev restart\` or \`lattices app restart\` to quit, rebuild, and relaunch."
|
|
140
|
+
exit 1
|
|
141
|
+
fi
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
write_info_plist() {
|
|
145
|
+
mkdir -p "$BUNDLE/Contents"
|
|
146
|
+
cat > "$BUNDLE/Contents/Info.plist" <<PLIST
|
|
147
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
148
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
149
|
+
<plist version="1.0">
|
|
150
|
+
<dict>
|
|
151
|
+
<key>CFBundleIdentifier</key>
|
|
152
|
+
<string>$BUNDLE_ID</string>
|
|
153
|
+
<key>CFBundleName</key>
|
|
154
|
+
<string>Lattices</string>
|
|
155
|
+
<key>CFBundleDisplayName</key>
|
|
156
|
+
<string>Lattices</string>
|
|
157
|
+
<key>CFBundleExecutable</key>
|
|
158
|
+
<string>Lattices</string>
|
|
159
|
+
<key>CFBundleIconFile</key>
|
|
160
|
+
<string>AppIcon</string>
|
|
161
|
+
<key>CFBundlePackageType</key>
|
|
162
|
+
<string>APPL</string>
|
|
163
|
+
<key>CFBundleURLTypes</key>
|
|
164
|
+
<array>
|
|
165
|
+
<dict>
|
|
166
|
+
<key>CFBundleURLName</key>
|
|
167
|
+
<string>$BUNDLE_ID</string>
|
|
168
|
+
<key>CFBundleURLSchemes</key>
|
|
169
|
+
<array>
|
|
170
|
+
<string>lattices</string>
|
|
171
|
+
</array>
|
|
172
|
+
</dict>
|
|
173
|
+
</array>
|
|
174
|
+
<key>CFBundleVersion</key>
|
|
175
|
+
<string>$VERSION</string>
|
|
176
|
+
<key>CFBundleShortVersionString</key>
|
|
177
|
+
<string>$VERSION</string>
|
|
178
|
+
<key>LatticesBuildChannel</key>
|
|
179
|
+
<string>dev</string>
|
|
180
|
+
<key>LatticesBuildTrack</key>
|
|
181
|
+
<string>latest</string>
|
|
182
|
+
<key>LatticesBuildRevision</key>
|
|
183
|
+
<string>$GIT_REVISION</string>
|
|
184
|
+
<key>LatticesBuildTimestamp</key>
|
|
185
|
+
<string>$BUILD_TIMESTAMP</string>
|
|
186
|
+
<key>LSMinimumSystemVersion</key>
|
|
187
|
+
<string>13.0</string>
|
|
188
|
+
<key>LSUIElement</key>
|
|
189
|
+
<true/>
|
|
190
|
+
<key>NSHighResolutionCapable</key>
|
|
191
|
+
<true/>
|
|
192
|
+
<key>NSMicrophoneUsageDescription</key>
|
|
193
|
+
<string>Lattices uses the microphone for Hudson Voice dictation and voice commands.</string>
|
|
194
|
+
<key>NSSupportsAutomaticTermination</key>
|
|
195
|
+
<true/>
|
|
196
|
+
</dict>
|
|
197
|
+
</plist>
|
|
198
|
+
PLIST
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
cmd_build() {
|
|
202
|
+
echo "Building dev app..."
|
|
203
|
+
require_build_targets_not_running
|
|
204
|
+
# Build features are declared in apps/mac/build.json and resolved to the
|
|
205
|
+
# HUDSONKIT_WITH_* env HudsonKit gates on (see bin/lattices-build-env.ts).
|
|
206
|
+
eval "$(bun "$ROOT/bin/lattices-build-env.ts" shell)"
|
|
207
|
+
cd "$APP_DIR" && swift build -c release
|
|
208
|
+
# Build into a repo-local dev artifact, then install to a stable app path
|
|
209
|
+
# that macOS permissions can trust across rebuilds.
|
|
210
|
+
rm -rf "$BUNDLE"
|
|
211
|
+
mkdir -p "$(dirname "$BUNDLE_BIN")" "$RESOURCES_DIR"
|
|
212
|
+
cp "$BINARY" "$BUNDLE_BIN"
|
|
213
|
+
if [ -f "$ICON" ]; then
|
|
214
|
+
cp "$ICON" "$RESOURCES_DIR/AppIcon.icns"
|
|
215
|
+
fi
|
|
216
|
+
if [ -f "$TAP_SOUND" ]; then
|
|
217
|
+
cp "$TAP_SOUND" "$RESOURCES_DIR/tap.wav"
|
|
218
|
+
fi
|
|
219
|
+
write_info_plist
|
|
220
|
+
# Re-sign so TCC permissions persist across rebuilds
|
|
221
|
+
sign_bundle
|
|
222
|
+
touch "$BUNDLE" "$BUNDLE/Contents"
|
|
223
|
+
sync_bundle_copy "$INSTALL_BUNDLE"
|
|
224
|
+
clear_lattices_drag_cache
|
|
225
|
+
green "Build complete."
|
|
226
|
+
dim "Installed: $INSTALL_BUNDLE"
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
cmd_restart() {
|
|
230
|
+
echo "Restarting Lattices..."
|
|
231
|
+
/usr/bin/osascript -e 'tell application id "dev.lattices.app.dev" to quit' >/dev/null 2>&1 || true
|
|
232
|
+
/usr/bin/osascript -e 'tell application id "dev.lattices.app" to quit' >/dev/null 2>&1 || true
|
|
233
|
+
pkill -x Lattices 2>/dev/null && sleep 1 || true
|
|
234
|
+
cmd_build
|
|
235
|
+
open "$INSTALL_BUNDLE" --args --lattices-cli-root "$ROOT" "$@"
|
|
236
|
+
green "Lattices restarted."
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
cmd_quit() {
|
|
240
|
+
/usr/bin/osascript -e 'tell application id "dev.lattices.app.dev" to quit' >/dev/null 2>&1 || true
|
|
241
|
+
/usr/bin/osascript -e 'tell application id "dev.lattices.app" to quit' >/dev/null 2>&1 || true
|
|
242
|
+
if pkill -x Lattices 2>/dev/null; then
|
|
243
|
+
green "Lattices stopped."
|
|
244
|
+
else
|
|
245
|
+
dim "Lattices is not running."
|
|
246
|
+
fi
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
cmd_launch() {
|
|
250
|
+
if is_install_bundle_running; then
|
|
251
|
+
dim "Lattices dev app is already running."
|
|
252
|
+
else
|
|
253
|
+
if pgrep -x Lattices >/dev/null 2>&1; then
|
|
254
|
+
dim "A different Lattices bundle is running. Switching to the dev permission target."
|
|
255
|
+
cmd_quit
|
|
256
|
+
fi
|
|
257
|
+
ensure_install_bundle
|
|
258
|
+
open "$INSTALL_BUNDLE" --args --lattices-cli-root "$ROOT" "$@"
|
|
259
|
+
green "Lattices launched."
|
|
260
|
+
fi
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
cmd_logs() {
|
|
264
|
+
if [ -f "$LOG_FILE" ]; then
|
|
265
|
+
tail -f "$LOG_FILE"
|
|
266
|
+
else
|
|
267
|
+
red "No log file at $LOG_FILE"
|
|
268
|
+
fi
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
cmd_log() {
|
|
272
|
+
# Show last N lines (default 30)
|
|
273
|
+
local n="${1:-30}"
|
|
274
|
+
if [ -f "$LOG_FILE" ]; then
|
|
275
|
+
tail -n "$n" "$LOG_FILE"
|
|
276
|
+
else
|
|
277
|
+
red "No log file at $LOG_FILE"
|
|
278
|
+
fi
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
cmd_clear_logs() {
|
|
282
|
+
if [ -f "$LOG_FILE" ]; then
|
|
283
|
+
> "$LOG_FILE"
|
|
284
|
+
green "Logs cleared."
|
|
285
|
+
else
|
|
286
|
+
dim "No log file to clear."
|
|
287
|
+
fi
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
cmd_link() {
|
|
291
|
+
if ! command -v bun >/dev/null 2>&1; then
|
|
292
|
+
red "bun not found. Install: curl -fsSL https://bun.sh/install | bash"
|
|
293
|
+
exit 1
|
|
294
|
+
fi
|
|
295
|
+
cd "$ROOT"
|
|
296
|
+
bun link
|
|
297
|
+
bun link @lattices/cli
|
|
298
|
+
if command -v lattices >/dev/null 2>&1; then
|
|
299
|
+
green "Linked. \`lattices\` -> $(command -v lattices)"
|
|
300
|
+
else
|
|
301
|
+
red "Linked, but \`lattices\` is not on PATH. Add bun's global bin to PATH:"
|
|
302
|
+
dim " export PATH=\"\$HOME/.bun/bin:\$PATH\""
|
|
303
|
+
fi
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
cmd_unlink() {
|
|
307
|
+
if ! command -v bun >/dev/null 2>&1; then
|
|
308
|
+
red "bun not found."
|
|
309
|
+
exit 1
|
|
310
|
+
fi
|
|
311
|
+
bun remove -g @lattices/cli >/dev/null 2>&1 || true
|
|
312
|
+
green "Unlinked."
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
cmd_status() {
|
|
316
|
+
if pgrep -x Lattices >/dev/null 2>&1; then
|
|
317
|
+
local pid=$(pgrep -x Lattices)
|
|
318
|
+
green "Lattices running (pid $pid)"
|
|
319
|
+
else
|
|
320
|
+
dim "Lattices is not running."
|
|
321
|
+
fi
|
|
322
|
+
if [ -f "$LOG_FILE" ]; then
|
|
323
|
+
local lines=$(wc -l < "$LOG_FILE" | tr -d ' ')
|
|
324
|
+
local size=$(du -h "$LOG_FILE" | cut -f1 | tr -d ' ')
|
|
325
|
+
dim "Log: $lines lines, $size"
|
|
326
|
+
fi
|
|
327
|
+
if [ -f "$HOME/.lattices/advisor-learning.jsonl" ]; then
|
|
328
|
+
local entries=$(wc -l < "$HOME/.lattices/advisor-learning.jsonl" | tr -d ' ')
|
|
329
|
+
dim "Advisor learning: $entries entries"
|
|
330
|
+
fi
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
cmd_help() {
|
|
334
|
+
echo "lattices-dev — Lattices development commands"
|
|
335
|
+
echo ""
|
|
336
|
+
echo " link Symlink \`lattices\` to this checkout (bun link)"
|
|
337
|
+
echo " unlink Remove the bun link"
|
|
338
|
+
echo " restart Quit + rebuild + relaunch"
|
|
339
|
+
echo " build Build release binary"
|
|
340
|
+
echo " quit Stop the running app"
|
|
341
|
+
echo " launch Start the app (if not running)"
|
|
342
|
+
echo " logs Tail the log file (live)"
|
|
343
|
+
echo " log [N] Show last N log lines (default 30)"
|
|
344
|
+
echo " clear-logs Clear the log file"
|
|
345
|
+
echo " status Show running state and stats"
|
|
346
|
+
echo " help Show this help"
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
case "${1:-help}" in
|
|
350
|
+
link) cmd_link ;;
|
|
351
|
+
unlink) cmd_unlink ;;
|
|
352
|
+
restart) cmd_restart "${@:2}" ;;
|
|
353
|
+
build) cmd_build ;;
|
|
354
|
+
quit|stop) cmd_quit ;;
|
|
355
|
+
launch|start) cmd_launch "${@:2}" ;;
|
|
356
|
+
logs) cmd_logs ;;
|
|
357
|
+
log) cmd_log "${2:-30}" ;;
|
|
358
|
+
clear-logs) cmd_clear_logs ;;
|
|
359
|
+
status) cmd_status ;;
|
|
360
|
+
help|--help|-h) cmd_help ;;
|
|
361
|
+
*) red "Unknown command: $1"; cmd_help; exit 1 ;;
|
|
362
|
+
esac
|