@lattices/cli 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -9
- package/app/Package.swift +8 -1
- package/app/Sources/AdvisorLearningStore.swift +90 -0
- package/app/Sources/AgentSession.swift +377 -0
- package/app/Sources/AppDelegate.swift +44 -12
- package/app/Sources/AppShellView.swift +81 -8
- package/app/Sources/AudioProvider.swift +386 -0
- package/app/Sources/CheatSheetHUD.swift +261 -19
- package/app/Sources/DaemonProtocol.swift +13 -0
- package/app/Sources/DaemonServer.swift +8 -0
- package/app/Sources/DesktopModel.swift +164 -5
- package/app/Sources/DesktopModelTypes.swift +2 -0
- package/app/Sources/DiagnosticLog.swift +104 -2
- package/app/Sources/EventBus.swift +1 -0
- package/app/Sources/HUDBottomBar.swift +279 -0
- package/app/Sources/HUDController.swift +1158 -0
- package/app/Sources/HUDLeftBar.swift +849 -0
- package/app/Sources/HUDMinimap.swift +179 -0
- package/app/Sources/HUDRightBar.swift +774 -0
- package/app/Sources/HUDState.swift +367 -0
- package/app/Sources/HUDTopBar.swift +243 -0
- package/app/Sources/HandsOffSession.swift +733 -0
- package/app/Sources/HomeDashboardView.swift +125 -0
- package/app/Sources/HotkeyManager.swift +2 -0
- package/app/Sources/HotkeyStore.swift +45 -9
- package/app/Sources/IntentEngine.swift +925 -0
- package/app/Sources/Intents/CreateLayerIntent.swift +54 -0
- package/app/Sources/Intents/DistributeIntent.swift +56 -0
- package/app/Sources/Intents/FocusIntent.swift +69 -0
- package/app/Sources/Intents/HelpIntent.swift +41 -0
- package/app/Sources/Intents/KillIntent.swift +47 -0
- package/app/Sources/Intents/LatticeIntent.swift +78 -0
- package/app/Sources/Intents/LaunchIntent.swift +67 -0
- package/app/Sources/Intents/ListSessionsIntent.swift +32 -0
- package/app/Sources/Intents/ListWindowsIntent.swift +30 -0
- package/app/Sources/Intents/ScanIntent.swift +52 -0
- package/app/Sources/Intents/SearchIntent.swift +190 -0
- package/app/Sources/Intents/SwitchLayerIntent.swift +50 -0
- package/app/Sources/Intents/TileIntent.swift +61 -0
- package/app/Sources/LatticesApi.swift +1235 -30
- package/app/Sources/LauncherHUD.swift +348 -0
- package/app/Sources/MainView.swift +147 -44
- package/app/Sources/OcrModel.swift +34 -1
- package/app/Sources/OmniSearchState.swift +99 -102
- package/app/Sources/OnboardingView.swift +457 -0
- package/app/Sources/PermissionChecker.swift +2 -12
- package/app/Sources/PiChatDock.swift +454 -0
- package/app/Sources/PiChatSession.swift +815 -0
- package/app/Sources/PiWorkspaceView.swift +364 -0
- package/app/Sources/PlacementSpec.swift +195 -0
- package/app/Sources/Preferences.swift +59 -0
- package/app/Sources/ProjectScanner.swift +1 -1
- package/app/Sources/ScreenMapState.swift +701 -55
- package/app/Sources/ScreenMapView.swift +843 -103
- package/app/Sources/ScreenMapWindowController.swift +22 -0
- package/app/Sources/SessionLayerStore.swift +285 -0
- package/app/Sources/SessionManager.swift +4 -1
- package/app/Sources/SettingsView.swift +186 -3
- package/app/Sources/Theme.swift +9 -8
- package/app/Sources/TmuxModel.swift +7 -0
- package/app/Sources/TmuxQuery.swift +27 -3
- package/app/Sources/VoiceChatView.swift +192 -0
- package/app/Sources/VoiceCommandWindow.swift +1594 -0
- package/app/Sources/VoiceIntentResolver.swift +671 -0
- package/app/Sources/VoxClient.swift +454 -0
- package/app/Sources/WindowTiler.swift +348 -87
- package/app/Sources/WorkspaceManager.swift +127 -18
- package/bin/client.ts +16 -0
- package/bin/{daemon-client.js → daemon-client.ts} +49 -30
- package/bin/handsoff-infer.ts +280 -0
- package/bin/handsoff-worker.ts +731 -0
- package/bin/{lattices-app.js → lattices-app.ts} +67 -32
- package/bin/lattices-dev +160 -0
- package/bin/{lattices.js → lattices.ts} +600 -137
- package/bin/project-twin.ts +645 -0
- package/docs/agent-execution-plan.md +562 -0
- package/docs/agents.md +142 -0
- package/docs/api.md +153 -34
- package/docs/app.md +29 -1
- package/docs/config.md +5 -1
- package/docs/handsoff-test-scenarios.md +84 -0
- package/docs/layers.md +20 -20
- package/docs/ocr.md +14 -5
- package/docs/overview.md +5 -1
- package/docs/presentation-execution-review.md +491 -0
- package/docs/prompts/hands-off-system.md +374 -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/tiling-reference.md +167 -0
- package/docs/twins.md +138 -0
- package/docs/voice-command-protocol.md +278 -0
- package/docs/voice.md +219 -0
- package/package.json +21 -10
- package/bin/client.js +0 -4
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
3
|
import { execSync, spawn } from "node:child_process";
|
|
4
4
|
import { existsSync, mkdirSync, chmodSync, createWriteStream } from "node:fs";
|
|
5
|
-
import { resolve
|
|
6
|
-
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { resolve } from "node:path";
|
|
7
6
|
import { get } from "node:https";
|
|
7
|
+
import type { IncomingMessage } from "node:http";
|
|
8
8
|
|
|
9
|
-
const __dirname =
|
|
9
|
+
const __dirname = import.meta.dir;
|
|
10
10
|
const appDir = resolve(__dirname, "../app");
|
|
11
11
|
const bundlePath = resolve(appDir, "Lattices.app");
|
|
12
12
|
const binaryDir = resolve(bundlePath, "Contents/MacOS");
|
|
13
13
|
const binaryPath = resolve(binaryDir, "Lattices");
|
|
14
|
+
const entitlementsPath = resolve(__dirname, "../app/Lattices.entitlements");
|
|
14
15
|
|
|
15
16
|
const REPO = "arach/lattices";
|
|
16
17
|
const ASSET_NAME = "Lattices-macos-arm64";
|
|
17
18
|
|
|
18
19
|
// ── Helpers ──────────────────────────────────────────────────────────
|
|
19
20
|
|
|
20
|
-
function isRunning() {
|
|
21
|
+
function isRunning(): boolean {
|
|
21
22
|
try {
|
|
22
23
|
execSync("pgrep -x Lattices", { stdio: "pipe" });
|
|
23
24
|
return true;
|
|
@@ -26,7 +27,7 @@ function isRunning() {
|
|
|
26
27
|
}
|
|
27
28
|
}
|
|
28
29
|
|
|
29
|
-
function quit() {
|
|
30
|
+
function quit(): boolean {
|
|
30
31
|
try {
|
|
31
32
|
execSync("pkill -x Lattices", { stdio: "pipe" });
|
|
32
33
|
// Wait briefly for process to exit
|
|
@@ -41,7 +42,7 @@ function quit() {
|
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
function hasSwift() {
|
|
45
|
+
function hasSwift(): boolean {
|
|
45
46
|
try {
|
|
46
47
|
execSync("which swift", { stdio: "pipe" });
|
|
47
48
|
return true;
|
|
@@ -50,7 +51,7 @@ function hasSwift() {
|
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
function launch(extraArgs = []) {
|
|
54
|
+
function launch(extraArgs: string[] = []): void {
|
|
54
55
|
if (isRunning()) {
|
|
55
56
|
console.log("lattices app is already running.");
|
|
56
57
|
return;
|
|
@@ -61,9 +62,45 @@ function launch(extraArgs = []) {
|
|
|
61
62
|
console.log("lattices app launched.");
|
|
62
63
|
}
|
|
63
64
|
|
|
65
|
+
function resolveSigningIdentity(): string | null {
|
|
66
|
+
try {
|
|
67
|
+
const identities = execSync("security find-identity -v -p codesigning", { stdio: "pipe" }).toString();
|
|
68
|
+
return identities.match(/"(Developer ID Application:[^"]+)"/)?.[1]
|
|
69
|
+
|| identities.match(/"(Apple Development:[^"]+)"/)?.[1]
|
|
70
|
+
|| null;
|
|
71
|
+
} catch {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function signBundle(): void {
|
|
77
|
+
const identity = resolveSigningIdentity();
|
|
78
|
+
const entFlag = existsSync(entitlementsPath) ? ` --entitlements '${entitlementsPath}'` : "";
|
|
79
|
+
|
|
80
|
+
if (identity) {
|
|
81
|
+
console.log(`Signing with: ${identity}`);
|
|
82
|
+
try {
|
|
83
|
+
execSync(
|
|
84
|
+
`codesign --force --sign '${identity}'${entFlag} --identifier com.arach.lattices '${bundlePath}'`,
|
|
85
|
+
{ stdio: "pipe" }
|
|
86
|
+
);
|
|
87
|
+
return;
|
|
88
|
+
} catch {
|
|
89
|
+
console.log(`Warning: signing with '${identity}' failed — falling back to ad-hoc.`);
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
console.log("Warning: no local signing identity found — falling back to ad-hoc.");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
execSync(
|
|
96
|
+
`codesign --force --sign -${entFlag} --identifier com.arach.lattices '${bundlePath}'`,
|
|
97
|
+
{ stdio: "pipe" }
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
64
101
|
// ── Build from source (current arch only) ────────────────────────────
|
|
65
102
|
|
|
66
|
-
function buildFromSource() {
|
|
103
|
+
function buildFromSource(): boolean {
|
|
67
104
|
console.log("Building lattices app from source...");
|
|
68
105
|
try {
|
|
69
106
|
execSync("swift build -c release", {
|
|
@@ -80,6 +117,12 @@ function buildFromSource() {
|
|
|
80
117
|
mkdirSync(binaryDir, { recursive: true });
|
|
81
118
|
execSync(`cp '${builtPath}' '${binaryPath}'`);
|
|
82
119
|
|
|
120
|
+
// Copy Info.plist into bundle
|
|
121
|
+
const plistSrc = resolve(__dirname, "../app/Info.plist");
|
|
122
|
+
if (existsSync(plistSrc)) {
|
|
123
|
+
execSync(`cp '${plistSrc}' '${resolve(bundlePath, "Contents/Info.plist")}'`);
|
|
124
|
+
}
|
|
125
|
+
|
|
83
126
|
// Copy app icon into bundle
|
|
84
127
|
const iconSrc = resolve(__dirname, "../assets/AppIcon.icns");
|
|
85
128
|
const resourcesDir = resolve(bundlePath, "Contents/Resources");
|
|
@@ -89,18 +132,10 @@ function buildFromSource() {
|
|
|
89
132
|
}
|
|
90
133
|
|
|
91
134
|
// Re-sign the bundle so macOS TCC recognizes a stable identity across rebuilds.
|
|
92
|
-
//
|
|
135
|
+
// Prefer a real local signing identity; only fall back to ad-hoc when necessary.
|
|
93
136
|
try {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const devId = identities.match(/"(Developer ID Application:[^"]+)"/)?.[1]
|
|
97
|
-
|| identities.match(/"(Apple Development:[^"]+)"/)?.[1];
|
|
98
|
-
const signArg = devId ? `'${devId}'` : "-";
|
|
99
|
-
execSync(
|
|
100
|
-
`codesign --force --sign ${signArg} --identifier com.arach.lattices '${bundlePath}'`,
|
|
101
|
-
{ stdio: "pipe" }
|
|
102
|
-
);
|
|
103
|
-
} catch (e) {
|
|
137
|
+
signBundle();
|
|
138
|
+
} catch {
|
|
104
139
|
// Non-fatal — app still works, just permissions won't persist across rebuilds
|
|
105
140
|
console.log("Warning: code signing failed — permissions may not persist across rebuilds.");
|
|
106
141
|
}
|
|
@@ -112,10 +147,10 @@ function buildFromSource() {
|
|
|
112
147
|
|
|
113
148
|
// ── Download from GitHub releases ────────────────────────────────────
|
|
114
149
|
|
|
115
|
-
function httpsGet(url) {
|
|
150
|
+
function httpsGet(url: string): Promise<IncomingMessage> {
|
|
116
151
|
return new Promise((resolve, reject) => {
|
|
117
152
|
get(url, { headers: { "User-Agent": "lattices" } }, (res) => {
|
|
118
|
-
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
153
|
+
if (res.statusCode! >= 300 && res.statusCode! < 400 && res.headers.location) {
|
|
119
154
|
return httpsGet(res.headers.location).then(resolve, reject);
|
|
120
155
|
}
|
|
121
156
|
if (res.statusCode !== 200) {
|
|
@@ -128,24 +163,24 @@ function httpsGet(url) {
|
|
|
128
163
|
});
|
|
129
164
|
}
|
|
130
165
|
|
|
131
|
-
async function download() {
|
|
166
|
+
async function download(): Promise<boolean> {
|
|
132
167
|
console.log("Downloading pre-built binary...");
|
|
133
168
|
|
|
134
169
|
try {
|
|
135
170
|
const apiUrl = `https://api.github.com/repos/${REPO}/releases/latest`;
|
|
136
171
|
const apiRes = await httpsGet(apiUrl);
|
|
137
|
-
const chunks = [];
|
|
138
|
-
for await (const chunk of apiRes) chunks.push(chunk);
|
|
172
|
+
const chunks: Buffer[] = [];
|
|
173
|
+
for await (const chunk of apiRes) chunks.push(chunk as Buffer);
|
|
139
174
|
const release = JSON.parse(Buffer.concat(chunks).toString());
|
|
140
175
|
|
|
141
|
-
const asset = release.assets?.find((a) => a.name === ASSET_NAME);
|
|
176
|
+
const asset = release.assets?.find((a: { name: string }) => a.name === ASSET_NAME);
|
|
142
177
|
if (!asset) throw new Error("Binary not found in release assets");
|
|
143
178
|
|
|
144
179
|
const dlRes = await httpsGet(asset.browser_download_url);
|
|
145
180
|
|
|
146
181
|
mkdirSync(binaryDir, { recursive: true });
|
|
147
182
|
const ws = createWriteStream(binaryPath);
|
|
148
|
-
await new Promise((resolve, reject) => {
|
|
183
|
+
await new Promise<void>((resolve, reject) => {
|
|
149
184
|
dlRes.pipe(ws);
|
|
150
185
|
ws.on("finish", resolve);
|
|
151
186
|
ws.on("error", reject);
|
|
@@ -155,14 +190,14 @@ async function download() {
|
|
|
155
190
|
console.log("Download complete.");
|
|
156
191
|
return true;
|
|
157
192
|
} catch (e) {
|
|
158
|
-
console.log(`Download failed: ${e.message}`);
|
|
193
|
+
console.log(`Download failed: ${(e as Error).message}`);
|
|
159
194
|
return false;
|
|
160
195
|
}
|
|
161
196
|
}
|
|
162
197
|
|
|
163
198
|
// ── Commands ─────────────────────────────────────────────────────────
|
|
164
199
|
|
|
165
|
-
async function ensureBinary() {
|
|
200
|
+
async function ensureBinary(): Promise<void> {
|
|
166
201
|
if (existsSync(binaryPath)) return;
|
|
167
202
|
|
|
168
203
|
// 1. Try local compile (fast, matches exact system)
|
|
@@ -179,15 +214,15 @@ async function ensureBinary() {
|
|
|
179
214
|
console.error(
|
|
180
215
|
"Could not build or download the lattices app.\n" +
|
|
181
216
|
"Options:\n" +
|
|
182
|
-
"
|
|
183
|
-
"
|
|
217
|
+
" \u2022 Install Xcode CLI tools: xcode-select --install\n" +
|
|
218
|
+
" \u2022 Download manually from: https://github.com/" + REPO + "/releases"
|
|
184
219
|
);
|
|
185
220
|
process.exit(1);
|
|
186
221
|
}
|
|
187
222
|
|
|
188
223
|
const cmd = process.argv[2];
|
|
189
224
|
const flags = process.argv.slice(3);
|
|
190
|
-
const launchFlags = [];
|
|
225
|
+
const launchFlags: string[] = [];
|
|
191
226
|
if (flags.includes("--diagnostics") || flags.includes("-d")) launchFlags.push("--diagnostics");
|
|
192
227
|
if (flags.includes("--screen-map") || flags.includes("-m")) launchFlags.push("--screen-map");
|
|
193
228
|
|
package/bin/lattices-dev
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
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")/../app" && pwd)"
|
|
8
|
+
LOG_FILE="$HOME/.lattices/lattices.log"
|
|
9
|
+
BINARY="$APP_DIR/.build/release/Lattices"
|
|
10
|
+
BUNDLE="$APP_DIR/Lattices.app"
|
|
11
|
+
BUNDLE_BIN="$BUNDLE/Contents/MacOS/Lattices"
|
|
12
|
+
ENTITLEMENTS="$APP_DIR/Lattices.entitlements"
|
|
13
|
+
|
|
14
|
+
red() { printf "\033[31m%s\033[0m\n" "$*"; }
|
|
15
|
+
green() { printf "\033[32m%s\033[0m\n" "$*"; }
|
|
16
|
+
dim() { printf "\033[2m%s\033[0m\n" "$*"; }
|
|
17
|
+
|
|
18
|
+
select_sign_identity() {
|
|
19
|
+
local identities identity=""
|
|
20
|
+
identities="$(security find-identity -v -p codesigning 2>/dev/null || true)"
|
|
21
|
+
identity="$(printf '%s\n' "$identities" | sed -n 's/.*"\(Developer ID Application:[^"]*\)".*/\1/p' | head -n 1)"
|
|
22
|
+
if [ -z "$identity" ]; then
|
|
23
|
+
identity="$(printf '%s\n' "$identities" | sed -n 's/.*"\(Apple Development:[^"]*\)".*/\1/p' | head -n 1)"
|
|
24
|
+
fi
|
|
25
|
+
printf '%s' "$identity"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
sign_bundle() {
|
|
29
|
+
local identity sign_status=0
|
|
30
|
+
local -a ent_flags=()
|
|
31
|
+
|
|
32
|
+
if [ -f "$ENTITLEMENTS" ]; then
|
|
33
|
+
ent_flags=(--entitlements "$ENTITLEMENTS")
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
identity="$(select_sign_identity)"
|
|
37
|
+
if [ -n "$identity" ]; then
|
|
38
|
+
dim "Signing with: $identity"
|
|
39
|
+
if ! codesign --force --sign "$identity" "${ent_flags[@]}" --identifier com.arach.lattices "$BUNDLE"; then
|
|
40
|
+
red "Signing with '$identity' failed. Falling back to ad-hoc."
|
|
41
|
+
sign_status=1
|
|
42
|
+
fi
|
|
43
|
+
else
|
|
44
|
+
sign_status=1
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
if [ "$sign_status" -ne 0 ]; then
|
|
48
|
+
dim "No usable signing identity found. Using ad-hoc signature."
|
|
49
|
+
codesign --force --sign - "${ent_flags[@]}" --identifier com.arach.lattices "$BUNDLE"
|
|
50
|
+
fi
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
cmd_build() {
|
|
54
|
+
echo "Building release..."
|
|
55
|
+
cd "$APP_DIR" && swift build -c release
|
|
56
|
+
# Copy into app bundle so it runs with the proper bundle ID
|
|
57
|
+
mkdir -p "$(dirname "$BUNDLE_BIN")" "$BUNDLE/Contents/Resources"
|
|
58
|
+
cp "$BINARY" "$BUNDLE_BIN"
|
|
59
|
+
cp "$APP_DIR/Info.plist" "$BUNDLE/Contents/Info.plist" 2>/dev/null || true
|
|
60
|
+
# Re-sign so TCC permissions persist across rebuilds
|
|
61
|
+
sign_bundle
|
|
62
|
+
green "Build complete."
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
cmd_restart() {
|
|
66
|
+
echo "Restarting Lattices..."
|
|
67
|
+
pkill -x Lattices 2>/dev/null && sleep 1 || true
|
|
68
|
+
cmd_build
|
|
69
|
+
open "$BUNDLE"
|
|
70
|
+
green "Lattices restarted."
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
cmd_quit() {
|
|
74
|
+
if pkill -x Lattices 2>/dev/null; then
|
|
75
|
+
green "Lattices stopped."
|
|
76
|
+
else
|
|
77
|
+
dim "Lattices is not running."
|
|
78
|
+
fi
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
cmd_launch() {
|
|
82
|
+
if pgrep -x Lattices >/dev/null 2>&1; then
|
|
83
|
+
dim "Lattices is already running."
|
|
84
|
+
else
|
|
85
|
+
open "$BUNDLE"
|
|
86
|
+
green "Lattices launched."
|
|
87
|
+
fi
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
cmd_logs() {
|
|
91
|
+
if [ -f "$LOG_FILE" ]; then
|
|
92
|
+
tail -f "$LOG_FILE"
|
|
93
|
+
else
|
|
94
|
+
red "No log file at $LOG_FILE"
|
|
95
|
+
fi
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
cmd_log() {
|
|
99
|
+
# Show last N lines (default 30)
|
|
100
|
+
local n="${1:-30}"
|
|
101
|
+
if [ -f "$LOG_FILE" ]; then
|
|
102
|
+
tail -n "$n" "$LOG_FILE"
|
|
103
|
+
else
|
|
104
|
+
red "No log file at $LOG_FILE"
|
|
105
|
+
fi
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
cmd_clear_logs() {
|
|
109
|
+
if [ -f "$LOG_FILE" ]; then
|
|
110
|
+
> "$LOG_FILE"
|
|
111
|
+
green "Logs cleared."
|
|
112
|
+
else
|
|
113
|
+
dim "No log file to clear."
|
|
114
|
+
fi
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
cmd_status() {
|
|
118
|
+
if pgrep -x Lattices >/dev/null 2>&1; then
|
|
119
|
+
local pid=$(pgrep -x Lattices)
|
|
120
|
+
green "Lattices running (pid $pid)"
|
|
121
|
+
else
|
|
122
|
+
dim "Lattices is not running."
|
|
123
|
+
fi
|
|
124
|
+
if [ -f "$LOG_FILE" ]; then
|
|
125
|
+
local lines=$(wc -l < "$LOG_FILE" | tr -d ' ')
|
|
126
|
+
local size=$(du -h "$LOG_FILE" | cut -f1 | tr -d ' ')
|
|
127
|
+
dim "Log: $lines lines, $size"
|
|
128
|
+
fi
|
|
129
|
+
if [ -f "$HOME/.lattices/advisor-learning.jsonl" ]; then
|
|
130
|
+
local entries=$(wc -l < "$HOME/.lattices/advisor-learning.jsonl" | tr -d ' ')
|
|
131
|
+
dim "Advisor learning: $entries entries"
|
|
132
|
+
fi
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
cmd_help() {
|
|
136
|
+
echo "lattices-dev — Lattices development commands"
|
|
137
|
+
echo ""
|
|
138
|
+
echo " restart Quit + rebuild + relaunch"
|
|
139
|
+
echo " build Build release binary"
|
|
140
|
+
echo " quit Stop the running app"
|
|
141
|
+
echo " launch Start the app (if not running)"
|
|
142
|
+
echo " logs Tail the log file (live)"
|
|
143
|
+
echo " log [N] Show last N log lines (default 30)"
|
|
144
|
+
echo " clear-logs Clear the log file"
|
|
145
|
+
echo " status Show running state and stats"
|
|
146
|
+
echo " help Show this help"
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
case "${1:-help}" in
|
|
150
|
+
restart) cmd_restart ;;
|
|
151
|
+
build) cmd_build ;;
|
|
152
|
+
quit|stop) cmd_quit ;;
|
|
153
|
+
launch|start) cmd_launch ;;
|
|
154
|
+
logs) cmd_logs ;;
|
|
155
|
+
log) cmd_log "${2:-30}" ;;
|
|
156
|
+
clear-logs) cmd_clear_logs ;;
|
|
157
|
+
status) cmd_status ;;
|
|
158
|
+
help|--help|-h) cmd_help ;;
|
|
159
|
+
*) red "Unknown command: $1"; cmd_help; exit 1 ;;
|
|
160
|
+
esac
|