signetai 0.214.21 → 0.214.24

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/dist/mcp-stdio.js CHANGED
@@ -26310,7 +26310,7 @@ function getDbAccessor() {
26310
26310
  }
26311
26311
  return accessor;
26312
26312
  }
26313
- var isBun, require3, Database, accessor = null, MIGRATION_BACKUP_CHUNK_BYTES, MIGRATION_BACKUP_SPACE_MARGIN_BYTES, migrationBackupDeps;
26313
+ var isBun, require3, accessor = null, MIGRATION_BACKUP_CHUNK_BYTES, MIGRATION_BACKUP_SPACE_MARGIN_BYTES, migrationBackupDeps;
26314
26314
  var init_db_accessor = __esm(() => {
26315
26315
  init_dist();
26316
26316
  init_db_vacuum();
@@ -26321,12 +26321,6 @@ var init_db_accessor = __esm(() => {
26321
26321
  init_sync_db_attribution();
26322
26322
  isBun = typeof globalThis.Bun !== "undefined";
26323
26323
  require3 = createRequire4(import.meta.url);
26324
- if (isBun) {
26325
- const mod = require3("bun:sqlite");
26326
- Database = mod.Database;
26327
- } else {
26328
- Database = require3("better-sqlite3");
26329
- }
26330
26324
  MIGRATION_BACKUP_CHUNK_BYTES = 64 * 1024 * 1024;
26331
26325
  MIGRATION_BACKUP_SPACE_MARGIN_BYTES = MIGRATION_BACKUP_CHUNK_BYTES * 2;
26332
26326
  migrationBackupDeps = {
@@ -26437,7 +26431,7 @@ var require_base64_js = __commonJS((exports) => {
26437
26431
  }
26438
26432
  });
26439
26433
 
26440
- // ../../platform/daemon/src/mcp-stdio.ts
26434
+ // ../../platform/daemon/src/mcp-stdio-runtime.ts
26441
26435
  import { existsSync as existsSync15, statSync as statSync4 } from "node:fs";
26442
26436
  import { isAbsolute } from "node:path";
26443
26437
 
@@ -59525,8 +59519,7 @@ function resolveMcpDaemonUrl(env = process.env) {
59525
59519
  return resolveSignetDaemonUrl({ env });
59526
59520
  }
59527
59521
 
59528
- // ../../platform/daemon/src/mcp-stdio.ts
59529
- var DAEMON_URL = resolveMcpDaemonUrl();
59522
+ // ../../platform/daemon/src/mcp-stdio-runtime.ts
59530
59523
  function isLocalDaemonUrl(url2) {
59531
59524
  let parsed;
59532
59525
  try {
@@ -59559,46 +59552,52 @@ async function resolveAgentsDir(daemonUrl) {
59559
59552
  } catch {}
59560
59553
  return;
59561
59554
  }
59562
- var resolvedAgentsDir = await resolveAgentsDir(DAEMON_URL);
59563
- if (resolvedAgentsDir) {
59564
- process.env.SIGNET_PATH = resolvedAgentsDir;
59565
- } else if (process.env.SIGNET_PATH && !isValidAgentsDir(process.env.SIGNET_PATH)) {
59566
- delete process.env.SIGNET_PATH;
59567
- }
59568
- var dreamingAgentId = process.env.SIGNET_DREAMING_AGENT_ID?.trim();
59569
- var dreamingPassId = process.env.SIGNET_DREAMING_PASS_ID?.trim();
59570
- var server = dreamingAgentId ? createDreamingMcpServer({
59571
- daemonUrl: DAEMON_URL,
59572
- agentId: dreamingAgentId,
59573
- passId: dreamingPassId,
59574
- version: "0.1.0"
59575
- }) : await createMcpServer({
59576
- daemonUrl: DAEMON_URL,
59577
- version: "0.1.0",
59578
- context: {
59579
- harness: process.env.SIGNET_HARNESS,
59580
- workspace: process.env.SIGNET_WORKSPACE ?? process.cwd(),
59581
- channel: process.env.SIGNET_CHANNEL
59582
- }
59583
- });
59584
- var transport = new StdioServerTransport;
59585
- await server.connect(transport);
59586
- var refreshMsRaw = Number(process.env.SIGNET_MCP_PROXY_REFRESH_MS ?? "15000");
59587
- var refreshMs = Number.isFinite(refreshMsRaw) && refreshMsRaw >= 1000 ? refreshMsRaw : 15000;
59588
- var refreshTimer = dreamingAgentId ? null : setInterval(() => {
59589
- refreshMarketplaceProxyTools(server, { notify: true });
59590
- }, refreshMs);
59591
- var closing = false;
59592
- var shutdown = () => {
59593
- if (closing)
59594
- return;
59595
- closing = true;
59596
- if (refreshTimer)
59597
- clearInterval(refreshTimer);
59598
- const deadline = setTimeout(() => process.exit(0), 3000);
59599
- deadline.unref();
59600
- server.close().finally(() => process.exit(0));
59601
- };
59602
- process.on("SIGINT", shutdown);
59603
- process.on("SIGTERM", shutdown);
59604
- process.stdin.on("end", shutdown);
59555
+ async function runMcpStdio() {
59556
+ const daemonUrl = resolveMcpDaemonUrl();
59557
+ const resolvedAgentsDir = await resolveAgentsDir(daemonUrl);
59558
+ if (resolvedAgentsDir) {
59559
+ process.env.SIGNET_PATH = resolvedAgentsDir;
59560
+ } else if (process.env.SIGNET_PATH && !isValidAgentsDir(process.env.SIGNET_PATH)) {
59561
+ delete process.env.SIGNET_PATH;
59562
+ }
59563
+ const dreamingAgentId = process.env.SIGNET_DREAMING_AGENT_ID?.trim();
59564
+ const dreamingPassId = process.env.SIGNET_DREAMING_PASS_ID?.trim();
59565
+ const server = dreamingAgentId ? createDreamingMcpServer({
59566
+ daemonUrl,
59567
+ agentId: dreamingAgentId,
59568
+ passId: dreamingPassId,
59569
+ version: "0.1.0"
59570
+ }) : await createMcpServer({
59571
+ daemonUrl,
59572
+ version: "0.1.0",
59573
+ context: {
59574
+ harness: process.env.SIGNET_HARNESS,
59575
+ workspace: process.env.SIGNET_WORKSPACE ?? process.cwd(),
59576
+ channel: process.env.SIGNET_CHANNEL
59577
+ }
59578
+ });
59579
+ const transport = new StdioServerTransport;
59580
+ await server.connect(transport);
59581
+ const refreshMsRaw = Number(process.env.SIGNET_MCP_PROXY_REFRESH_MS ?? "15000");
59582
+ const refreshMs = Number.isFinite(refreshMsRaw) && refreshMsRaw >= 1000 ? refreshMsRaw : 15000;
59583
+ const refreshTimer = dreamingAgentId ? null : setInterval(() => {
59584
+ refreshMarketplaceProxyTools(server, { notify: true });
59585
+ }, refreshMs);
59586
+ let closing = false;
59587
+ const shutdown = () => {
59588
+ if (closing)
59589
+ return;
59590
+ closing = true;
59591
+ if (refreshTimer)
59592
+ clearInterval(refreshTimer);
59593
+ const deadline = setTimeout(() => process.exit(0), 3000);
59594
+ deadline.unref();
59595
+ server.close().finally(() => process.exit(0));
59596
+ };
59597
+ process.on("SIGINT", shutdown);
59598
+ process.on("SIGTERM", shutdown);
59599
+ process.stdin.on("end", shutdown);
59600
+ }
59601
+
59602
+ // ../../platform/daemon/src/mcp-stdio.ts
59603
+ await runMcpStdio();
@@ -1,43 +1,43 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "version": "0.214.21",
3
+ "version": "0.214.24",
4
4
  "assets": [
5
5
  {
6
6
  "name": "signet-darwin-arm64",
7
7
  "platform": "darwin-arm64",
8
- "sha256": "d0e68f095b511c1574e27699520a09a2c81f52e7db5cb4e276d6f4ab98135959",
9
- "size": 163724320
8
+ "sha256": "1e4e3c649941f2f1bb3fa699d0adb16dac6c49e7900ac84697b486fbefab471c",
9
+ "size": 163757344
10
10
  },
11
11
  {
12
12
  "name": "signet-darwin-x64",
13
13
  "platform": "darwin-x64",
14
- "sha256": "5248fbfd43871eb90c6c0a9f8766539ddbc2020a25e424c96ab0b89343a2af46",
15
- "size": 168430144
14
+ "sha256": "a36c8039575248a8553181f36f4dd011bda7379827b42a524f255189df24edb4",
15
+ "size": 168462912
16
16
  },
17
17
  {
18
18
  "name": "signet-linux-arm64",
19
19
  "platform": "linux-arm64",
20
- "sha256": "18156212eb3c04c0817ba84c8fa8ca531669ab9c86141dbf1087748ab84639b7",
21
- "size": 210996398
20
+ "sha256": "65af3e93b005502be1018159fb5e812558204657de11d4feaaa60b7a9637abff",
21
+ "size": 211035903
22
22
  },
23
23
  {
24
24
  "name": "signet-linux-x64",
25
25
  "platform": "linux-x64",
26
- "sha256": "2cb2d44aba6369933dd86dc0befd5e8640470364e538a5f5ede820729a1250fb",
27
- "size": 213785117
26
+ "sha256": "33f5b45de85196ab0d60d520e9cf119c0c44b417c833ee5618b5a12ffa25e8e2",
27
+ "size": 213824622
28
28
  },
29
29
  {
30
30
  "name": "signet-win32-x64.exe",
31
31
  "platform": "win32-x64",
32
- "sha256": "976c18d7f30c50092c4b302e32b0abb49d949001a48c50934976158a17fbefa6",
33
- "size": 220270080
32
+ "sha256": "b419b010fca6237d36a00db69b20be581a16f73cada6a6dfca7f1127a7271046",
33
+ "size": 220310016
34
34
  }
35
35
  ],
36
36
  "components": {
37
37
  "connectors": {
38
- "url": "signet-connectors-0.214.21.tar.gz",
39
- "sha256": "45d4c57c355b0403235509dd61575d432a0a6413753fdcdf7aca41d7766bed45",
40
- "size": 21940
38
+ "url": "signet-connectors-0.214.24.tar.gz",
39
+ "sha256": "ad55bfe3b76bf8b961a49bc956da3bd34f6c35d25cb0741759840adb404155ff",
40
+ "size": 21944
41
41
  }
42
42
  }
43
43
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "signetai",
3
- "version": "0.214.21",
3
+ "version": "0.214.24",
4
4
  "description": "Signet native CLI installer wrapper",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,14 +13,14 @@
13
13
  "bin/signet.js",
14
14
  "dist/mcp-stdio.js",
15
15
  "native-manifest.json",
16
- "scripts/install-native.js",
17
- "scripts/verify-wrapper.js",
16
+ "scripts",
18
17
  "README.md",
19
18
  "LICENSE"
20
19
  ],
21
20
  "scripts": {
22
21
  "// prebuild": "Release-only: rebuilds dist/mcp-stdio.js from the daemon's MCP stdio source. Runs on `bun run build:signetai` during the release pipeline, NOT on `npm install` — consumers receive whatever the publisher shipped. The npm tarball is built from a tree where this prebuild has already run.",
23
- "prebuild": "bun ../../scripts/build-signet-mcp.ts",
22
+ "copy:scripts": "mkdir -p scripts && cp ../../scripts/install-graphiq.sh scripts/install-graphiq.sh",
23
+ "prebuild": "bun run copy:scripts && bun ../../scripts/build-signet-mcp.ts",
24
24
  "build": "node scripts/verify-wrapper.js",
25
25
  "postinstall": "node scripts/install-native.js"
26
26
  },
@@ -65,10 +65,10 @@
65
65
  "access": "public"
66
66
  },
67
67
  "optionalDependencies": {
68
- "signetai-darwin-arm64": "https://github.com/Signet-AI/signetai/releases/download/v0.214.21/signetai-darwin-arm64-0.214.21.tgz",
69
- "signetai-darwin-x64": "https://github.com/Signet-AI/signetai/releases/download/v0.214.21/signetai-darwin-x64-0.214.21.tgz",
70
- "signetai-linux-arm64": "https://github.com/Signet-AI/signetai/releases/download/v0.214.21/signetai-linux-arm64-0.214.21.tgz",
71
- "signetai-linux-x64": "https://github.com/Signet-AI/signetai/releases/download/v0.214.21/signetai-linux-x64-0.214.21.tgz",
72
- "signetai-win32-x64": "https://github.com/Signet-AI/signetai/releases/download/v0.214.21/signetai-win32-x64-0.214.21.tgz"
68
+ "signetai-darwin-arm64": "https://github.com/Signet-AI/signetai/releases/download/v0.214.24/signetai-darwin-arm64-0.214.24.tgz",
69
+ "signetai-darwin-x64": "https://github.com/Signet-AI/signetai/releases/download/v0.214.24/signetai-darwin-x64-0.214.24.tgz",
70
+ "signetai-linux-arm64": "https://github.com/Signet-AI/signetai/releases/download/v0.214.24/signetai-linux-arm64-0.214.24.tgz",
71
+ "signetai-linux-x64": "https://github.com/Signet-AI/signetai/releases/download/v0.214.24/signetai-linux-x64-0.214.24.tgz",
72
+ "signetai-win32-x64": "https://github.com/Signet-AI/signetai/releases/download/v0.214.24/signetai-win32-x64-0.214.24.tgz"
73
73
  }
74
74
  }
@@ -0,0 +1,332 @@
1
+ #!/usr/bin/env bash
2
+ # GraphIQ install/uninstall script
3
+ #
4
+ # Usage:
5
+ # curl -fsSL https://raw.githubusercontent.com/aaf2tbz/graphiq/main/install.sh | bash
6
+ # curl -fsSL https://raw.githubusercontent.com/aaf2tbz/graphiq/main/install.sh | bash -s -- uninstall
7
+ #
8
+ # Environment variables:
9
+ # GRAPHIQ_INSTALL_DIR — installation directory (default: existing graphiq dir, then /usr/local/bin)
10
+ # GRAPHIQ_VERSION — specific version to install (default: latest)
11
+ set -euo pipefail
12
+
13
+ REPO="aaf2tbz/graphiq"
14
+ COMMAND="${1:-install}"
15
+
16
+ if [ -n "${GRAPHIQ_INSTALL_DIR:-}" ]; then
17
+ INSTALL_DIR="$GRAPHIQ_INSTALL_DIR"
18
+ elif command -v graphiq >/dev/null 2>&1; then
19
+ INSTALL_DIR="$(dirname "$(command -v graphiq)")"
20
+ else
21
+ INSTALL_DIR="/usr/local/bin"
22
+ fi
23
+
24
+ RED='\033[0;31m'
25
+ GREEN='\033[0;32m'
26
+ YELLOW='\033[1;33m'
27
+ BOLD='\033[1m'
28
+ RESET='\033[0m'
29
+
30
+ info() { echo "${GREEN} ✓${RESET} $*"; }
31
+ warn() { echo "${YELLOW} ⚠${RESET} $*"; }
32
+ _GRAPHIQ_TMPDIR=""
33
+
34
+ cleanup() {
35
+ if [ -n "$_GRAPHIQ_TMPDIR" ] && [ -d "$_GRAPHIQ_TMPDIR" ]; then
36
+ rm -rf "$_GRAPHIQ_TMPDIR"
37
+ fi
38
+ }
39
+ trap cleanup EXIT
40
+
41
+ error() { echo "${RED} ✗${RESET} $*" >&2; }
42
+
43
+ confirm() {
44
+ printf " %s [y/N] " "$1"
45
+ read -r reply
46
+ [ "$reply" = "y" ] || [ "$reply" = "Y" ] || [ "$reply" = "yes" ]
47
+ }
48
+
49
+ need_cmd() {
50
+ if ! command -v "$1" >/dev/null 2>&1; then
51
+ error "requires '$1' but it is not installed"
52
+ if [ -n "${2:-}" ]; then
53
+ echo " Install: $2" >&2
54
+ fi
55
+ exit 1
56
+ fi
57
+ }
58
+
59
+ install_file() {
60
+ local src="$1"
61
+ local dst="$2"
62
+ local tmp="${dst}.tmp.$$"
63
+ local need_sudo="${3:-}"
64
+
65
+ $need_sudo cp "$src" "$tmp"
66
+ $need_sudo chmod 755 "$tmp"
67
+ $need_sudo mv "$tmp" "$dst"
68
+ }
69
+
70
+ detect_platform() {
71
+ OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
72
+ ARCH="$(uname -m)"
73
+
74
+ case "$OS" in
75
+ darwin)
76
+ if [ "$ARCH" = "arm64" ]; then
77
+ echo "aarch64-apple-darwin"
78
+ elif [ "$ARCH" = "x86_64" ]; then
79
+ echo "x86_64-apple-darwin"
80
+ else
81
+ error "unsupported macOS architecture: $ARCH"
82
+ exit 1
83
+ fi
84
+ ;;
85
+ linux)
86
+ if [ "$ARCH" = "x86_64" ]; then
87
+ echo "x86_64-unknown-linux-gnu"
88
+ elif [ "$ARCH" = "aarch64" ]; then
89
+ echo "aarch64-unknown-linux-gnu"
90
+ else
91
+ error "unsupported Linux architecture: $ARCH"
92
+ exit 1
93
+ fi
94
+ ;;
95
+ *)
96
+ error "unsupported OS: $OS (supported: macOS, Linux)"
97
+ exit 1
98
+ ;;
99
+ esac
100
+ }
101
+
102
+ fetch_latest_version() {
103
+ local version
104
+ version=$(curl -fsSL --max-time 10 "https://api.github.com/repos/${REPO}/releases/latest" \
105
+ | grep '"tag_name"' | head -1 | sed -E 's/.*"v([^"]+)".*/\1/')
106
+ if [ -z "$version" ]; then
107
+ error "could not determine latest version from GitHub"
108
+ error "check your internet connection or set GRAPHIQ_VERSION manually"
109
+ exit 1
110
+ fi
111
+ echo "$version"
112
+ }
113
+
114
+ verify_checksum() {
115
+ local archive="$1"
116
+ local version="$2"
117
+ local expected=""
118
+
119
+ if command -v jq >/dev/null 2>&1; then
120
+ expected=$(curl -fsSL --max-time 10 "https://api.github.com/repos/${REPO}/releases/tags/v${version}" \
121
+ | jq -r --arg name "$(basename "$archive")" '.assets[] | select(.name == $name) | .digest // ""' \
122
+ | sed -E 's/^sha256://')
123
+ else
124
+ expected=$(curl -fsSL --max-time 10 "https://api.github.com/repos/${REPO}/releases/tags/v${version}" \
125
+ | awk -v name="$(basename "$archive")" '
126
+ BEGIN { RS = "{"; in_asset = 0; asset_name = "" }
127
+ /"name"\s*:\s*"/ { gsub(/.*"name"\s*:\s*"/, ""); gsub(/".*/, ""); asset_name = $0 }
128
+ /"digest"\s*:\s*"/ && asset_name == name {
129
+ gsub(/.*"digest"\s*:\s*"/, ""); gsub(/".*/, "");
130
+ gsub(/^sha256:/, ""); print; found = 1; exit
131
+ }
132
+ ' 2>/dev/null)
133
+ fi
134
+
135
+ if [ -z "$expected" ]; then
136
+ error "no checksum found in release metadata — cannot verify integrity"
137
+ error "this may indicate a corrupted or incomplete release"
138
+ exit 1
139
+ fi
140
+
141
+ local actual
142
+ if command -v sha256sum >/dev/null 2>&1; then
143
+ actual=$(sha256sum "$archive" | awk '{print $1}')
144
+ elif command -v shasum >/dev/null 2>&1; then
145
+ actual=$(shasum -a 256 "$archive" | awk '{print $1}')
146
+ else
147
+ error "no sha256sum or shasum found — cannot verify integrity"
148
+ error "install coreutils (Linux) or Xcode Command Line Tools (macOS)"
149
+ exit 1
150
+ fi
151
+
152
+ if [ "$expected" != "$actual" ]; then
153
+ error "SHA256 checksum mismatch"
154
+ echo " expected: ${expected}" >&2
155
+ echo " actual: ${actual}" >&2
156
+ exit 1
157
+ fi
158
+ info "checksum verified"
159
+ }
160
+
161
+ do_install() {
162
+ echo ""
163
+ echo "${BOLD} GraphIQ Installer${RESET}"
164
+ echo ""
165
+
166
+ # Prerequisites
167
+ need_cmd curl "https://curl.se/"
168
+ need_cmd tar "system package manager"
169
+
170
+ if [ "$(uname -s)" = "Linux" ]; then
171
+ # graphiq's binaries load Vulkan lazily at runtime (wgpu dlopens it), so
172
+ # the binary STARTS and runs on CPU+rayon even with no Vulkan installed.
173
+ # This prompt only offers the loader+driver for optional GPU acceleration.
174
+ if ! ldconfig -p 2>/dev/null | grep -q "libvulkan.so.1" && \
175
+ ! [ -f /usr/lib/x86_64-linux-gnu/libvulkan.so.1 ] && \
176
+ ! [ -f /usr/lib/aarch64-linux-gnu/libvulkan.so.1 ]; then
177
+ info "No Vulkan loader found — graphiq will run on CPU; install Vulkan for optional GPU acceleration."
178
+ if confirm "Install Vulkan (loader + Mesa driver) now?"; then
179
+ if command -v apt >/dev/null 2>&1; then
180
+ sudo apt install -y libvulkan1 mesa-vulkan-drivers
181
+ elif command -v dnf >/dev/null 2>&1; then
182
+ sudo dnf install -y vulkan-loader mesa-vulkan-drivers
183
+ elif command -v pacman >/dev/null 2>&1; then
184
+ sudo pacman -S --noconfirm vulkan-driver
185
+ else
186
+ echo " Optional for GPU accel: libvulkan1 + mesa-vulkan-drivers (apt), vulkan-loader+mesa-vulkan-drivers (dnf), vulkan-driver (pacman)"
187
+ fi
188
+ fi
189
+ else
190
+ info "Vulkan loader found"
191
+ fi
192
+ fi
193
+
194
+ local platform
195
+ platform="$(detect_platform)"
196
+ local version="${GRAPHIQ_VERSION:-$(fetch_latest_version)}"
197
+
198
+ local archive="graphiq-${platform}.tar.gz"
199
+ local url="https://github.com/${REPO}/releases/download/v${version}/${archive}"
200
+
201
+ _GRAPHIQ_TMPDIR="$(mktemp -d)"
202
+
203
+ echo " version: ${version}"
204
+ echo " platform: ${platform}"
205
+ echo " target: ${INSTALL_DIR}"
206
+ echo ""
207
+
208
+ # Check for existing installation
209
+ if command -v graphiq >/dev/null 2>&1; then
210
+ local existing
211
+ existing=$(graphiq --version 2>/dev/null || echo "unknown")
212
+ echo " existing: graphiq ${existing} at $(command -v graphiq)"
213
+ echo ""
214
+ fi
215
+
216
+ echo " downloading ${archive}..."
217
+ if ! curl -fsSL --max-time 60 --retry 3 "$url" -o "${_GRAPHIQ_TMPDIR}/${archive}"; then
218
+ error "failed to download ${url}"
219
+ echo " The release may not include a binary for ${platform}." >&2
220
+ echo " Check available releases at:" >&2
221
+ echo " https://github.com/${REPO}/releases" >&2
222
+ exit 1
223
+ fi
224
+
225
+ verify_checksum "${_GRAPHIQ_TMPDIR}/${archive}" "$version"
226
+
227
+ echo " extracting..."
228
+ tar xzf "${_GRAPHIQ_TMPDIR}/${archive}" -C "$_GRAPHIQ_TMPDIR"
229
+
230
+ local need_sudo=""
231
+ if [ -d "$INSTALL_DIR" ]; then
232
+ if [ ! -w "$INSTALL_DIR" ]; then
233
+ need_sudo="sudo"
234
+ fi
235
+ else
236
+ local parent
237
+ parent="$(dirname "$INSTALL_DIR")"
238
+ if [ ! -w "$parent" ]; then
239
+ need_sudo="sudo"
240
+ fi
241
+ echo " creating ${INSTALL_DIR}..."
242
+ $need_sudo mkdir -p "$INSTALL_DIR"
243
+ fi
244
+
245
+ local installed=0
246
+ for bin in graphiq graphiq-mcp graphiq-bench; do
247
+ if [ -f "${_GRAPHIQ_TMPDIR}/${bin}" ]; then
248
+ install_file "${_GRAPHIQ_TMPDIR}/${bin}" "${INSTALL_DIR}/${bin}" "$need_sudo"
249
+ info "${bin} -> ${INSTALL_DIR}/${bin}"
250
+ installed=$((installed + 1))
251
+ else
252
+ warn "${bin} not found in archive (may not be built for this platform)"
253
+ fi
254
+ done
255
+
256
+ if [ "$installed" -eq 0 ]; then
257
+ error "no binaries were installed"
258
+ exit 1
259
+ fi
260
+
261
+ echo ""
262
+
263
+ # Verify installation — run the binary we just installed, not whatever is on PATH
264
+ local fail=0
265
+ local ver
266
+ ver=$("${INSTALL_DIR}/graphiq" --version 2>/dev/null || echo "?")
267
+ info "graphiq ${ver} at ${INSTALL_DIR}/graphiq"
268
+
269
+ # Detect shadowing without deleting user-managed binaries.
270
+ if command -v graphiq >/dev/null 2>&1; then
271
+ local on_path
272
+ on_path="$(command -v graphiq)"
273
+ if [ "$on_path" != "${INSTALL_DIR}/graphiq" ]; then
274
+ warn "another graphiq at ${on_path} shadows the new install"
275
+ echo " Put ${INSTALL_DIR} earlier in PATH or remove the old binary manually." >&2
276
+ fi
277
+ else
278
+ warn "${INSTALL_DIR} is not on PATH"
279
+ fail=1
280
+ fi
281
+
282
+ if [ -x "${INSTALL_DIR}/graphiq-mcp" ]; then
283
+ info "graphiq-mcp available"
284
+ else
285
+ warn "graphiq-mcp not found in ${INSTALL_DIR}"
286
+ fail=1
287
+ fi
288
+
289
+ if [ "$fail" -eq 1 ]; then
290
+ echo ""
291
+ echo " Add to your shell profile:"
292
+ echo " export PATH=\"${INSTALL_DIR}:\$PATH\""
293
+ fi
294
+
295
+ echo ""
296
+ echo "${BOLD} Next steps:${RESET}"
297
+ echo " graphiq setup --project /path/to/project"
298
+ echo " graphiq index /path/to/project"
299
+ echo " graphiq search \"rate limit middleware\""
300
+ echo " graphiq impact --project /path/to/project"
301
+ echo " graphiq doctor"
302
+ echo ""
303
+ }
304
+
305
+ do_uninstall() {
306
+ echo "uninstalling graphiq..."
307
+ for bin in graphiq graphiq-mcp graphiq-bench; do
308
+ local target="${INSTALL_DIR}/${bin}"
309
+ if [ -f "$target" ]; then
310
+ local need_sudo=""
311
+ if [ ! -w "$target" ]; then
312
+ need_sudo="sudo"
313
+ fi
314
+ $need_sudo rm -f "$target"
315
+ info "removed ${target}"
316
+ fi
317
+ done
318
+ info "done"
319
+ }
320
+
321
+ case "$COMMAND" in
322
+ install)
323
+ do_install
324
+ ;;
325
+ uninstall)
326
+ do_uninstall
327
+ ;;
328
+ *)
329
+ echo "usage: $0 [install|uninstall]" >&2
330
+ exit 1
331
+ ;;
332
+ esac