@cubic-dev-ai/cli 0.15.0 → 0.16.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/bin/cubic CHANGED
@@ -57,5 +57,15 @@ fi
57
57
  # Handle SIGINT gracefully
58
58
  trap '' INT
59
59
 
60
+ # Intercept installer command from npx wrapper context
61
+ if [ "$1" = "install" ]; then
62
+ exec "$resolved" "$@"
63
+ fi
64
+
65
+ # npx with no args should bootstrap setup flow in exec context
66
+ if [ "$#" -eq 0 ] && [ "${npm_command:-}" = "exec" ]; then
67
+ exec "$resolved" setup --mode install
68
+ fi
69
+
60
70
  # Execute the binary with all arguments
61
71
  exec "$resolved" "$@"
package/bin/cubic.cmd CHANGED
@@ -52,6 +52,17 @@ echo It seems that your package manager failed to install the right version of t
52
52
  exit /b 1
53
53
 
54
54
  :execute
55
+ rem Intercept installer command from npx wrapper context
56
+ if "%~1"=="install" (
57
+ start /b /wait "" "%resolved%" %*
58
+ exit /b !ERRORLEVEL!
59
+ )
60
+
61
+ if "%~1"=="" if /i "%npm_command%"=="exec" (
62
+ start /b /wait "" "%resolved%" setup --mode install
63
+ exit /b !ERRORLEVEL!
64
+ )
65
+
55
66
  rem Execute the binary with all arguments in the same console window
56
67
  rem Use start /b /wait to ensure it runs in the current shell context for all shells
57
68
  start /b /wait "" "%resolved%" %*
@@ -0,0 +1,71 @@
1
+ #!/bin/sh
2
+ set -e
3
+
4
+ if [ -n "$CUBIC_BIN_PATH" ]; then
5
+ resolved="$CUBIC_BIN_PATH"
6
+ else
7
+ # Get the real path of this script, resolving any symlinks
8
+ script_path="$0"
9
+ while [ -L "$script_path" ]; do
10
+ link_target="$(readlink "$script_path")"
11
+ case "$link_target" in
12
+ /*) script_path="$link_target" ;;
13
+ *) script_path="$(dirname "$script_path")/$link_target" ;;
14
+ esac
15
+ done
16
+ script_dir="$(dirname "$script_path")"
17
+ script_dir="$(cd "$script_dir" && pwd)"
18
+
19
+ # Map platform names
20
+ case "$(uname -s)" in
21
+ Darwin) platform="darwin" ;;
22
+ Linux) platform="linux" ;;
23
+ MINGW*|CYGWIN*|MSYS*) platform="win32" ;;
24
+ *) platform="$(uname -s | tr '[:upper:]' '[:lower:]')" ;;
25
+ esac
26
+
27
+ # Map architecture names
28
+ case "$(uname -m)" in
29
+ x86_64|amd64) arch="x64" ;;
30
+ aarch64) arch="arm64" ;;
31
+ armv7l) arch="arm" ;;
32
+ *) arch="$(uname -m)" ;;
33
+ esac
34
+
35
+ name="@cubic-dev-ai/cli-${platform}-${arch}"
36
+ binary="cubic"
37
+ [ "$platform" = "win32" ] && binary="cubic.exe"
38
+
39
+ # Search for the binary starting from real script location
40
+ resolved=""
41
+ current_dir="$script_dir"
42
+ while [ "$current_dir" != "/" ]; do
43
+ candidate="$current_dir/node_modules/$name/bin/$binary"
44
+ if [ -f "$candidate" ]; then
45
+ resolved="$candidate"
46
+ break
47
+ fi
48
+ current_dir="$(dirname "$current_dir")"
49
+ done
50
+
51
+ if [ -z "$resolved" ]; then
52
+ printf "It seems that your package manager failed to install the right version of the cubic CLI for your platform. You can try manually installing the \"%s\" package\n" "$name" >&2
53
+ exit 1
54
+ fi
55
+ fi
56
+
57
+ # Handle SIGINT gracefully
58
+ trap '' INT
59
+
60
+ # Intercept installer command from npx wrapper context
61
+ if [ "$1" = "install" ]; then
62
+ exec "$resolved" "$@"
63
+ fi
64
+
65
+ # npx with no args should bootstrap setup flow in exec context
66
+ if [ "$#" -eq 0 ] && [ "${npm_command:-}" = "exec" ]; then
67
+ exec "$resolved" setup --mode install
68
+ fi
69
+
70
+ # Execute the binary with all arguments
71
+ exec "$resolved" "$@"
package/package.json CHANGED
@@ -7,18 +7,18 @@
7
7
  "preinstall": "bun ./preinstall.mjs || node ./preinstall.mjs",
8
8
  "postinstall": "bun ./postinstall.mjs || node ./postinstall.mjs"
9
9
  },
10
- "version": "0.15.0",
10
+ "version": "0.16.0",
11
11
  "optionalDependencies": {
12
- "@cubic-dev-ai/cli-linux-arm64": "0.15.0",
13
- "@cubic-dev-ai/cli-linux-x64": "0.15.0",
14
- "@cubic-dev-ai/cli-linux-x64-baseline": "0.15.0",
15
- "@cubic-dev-ai/cli-linux-arm64-musl": "0.15.0",
16
- "@cubic-dev-ai/cli-linux-x64-musl": "0.15.0",
17
- "@cubic-dev-ai/cli-linux-x64-baseline-musl": "0.15.0",
18
- "@cubic-dev-ai/cli-darwin-arm64": "0.15.0",
19
- "@cubic-dev-ai/cli-darwin-x64": "0.15.0",
20
- "@cubic-dev-ai/cli-darwin-x64-baseline": "0.15.0",
21
- "@cubic-dev-ai/cli-windows-x64": "0.15.0",
22
- "@cubic-dev-ai/cli-windows-x64-baseline": "0.15.0"
12
+ "@cubic-dev-ai/cli-linux-arm64": "0.16.0",
13
+ "@cubic-dev-ai/cli-linux-x64": "0.16.0",
14
+ "@cubic-dev-ai/cli-linux-x64-baseline": "0.16.0",
15
+ "@cubic-dev-ai/cli-linux-arm64-musl": "0.16.0",
16
+ "@cubic-dev-ai/cli-linux-x64-musl": "0.16.0",
17
+ "@cubic-dev-ai/cli-linux-x64-baseline-musl": "0.16.0",
18
+ "@cubic-dev-ai/cli-darwin-arm64": "0.16.0",
19
+ "@cubic-dev-ai/cli-darwin-x64": "0.16.0",
20
+ "@cubic-dev-ai/cli-darwin-x64-baseline": "0.16.0",
21
+ "@cubic-dev-ai/cli-windows-x64": "0.16.0",
22
+ "@cubic-dev-ai/cli-windows-x64-baseline": "0.16.0"
23
23
  }
24
24
  }
package/postinstall.mjs CHANGED
@@ -5,7 +5,26 @@ import path from "path"
5
5
  import os from "os"
6
6
  import { fileURLToPath } from "url"
7
7
  import { createRequire } from "module"
8
- import { execSync } from "child_process"
8
+ import { execFileSync, execSync } from "child_process"
9
+
10
+ const CUBIC_WRAPPER_MODE = process.env.CUBIC_WRAPPER_MODE !== "0"
11
+
12
+ function packagePrefix() {
13
+ return process.env.CUBIC_PACKAGE_PREFIX || "@cubic-dev-ai/cli-"
14
+ }
15
+
16
+ function shouldRunInstallWizard() {
17
+ if (process.env.CUBIC_DISABLE_INSTALL_WIZARD === "true") return false
18
+ if (process.env.npm_config_ignore_scripts === "true") return false
19
+ if (process.env.CI && process.env.CI !== "false") return false
20
+ if (process.env.npm_config_yes === "true") return false
21
+ if (process.env.TERM === "dumb") return false
22
+ if (!process.stdin.isTTY) return false
23
+ if (!process.stdout.isTTY) return false
24
+ if (process.platform === "win32") return false
25
+ if (!fs.existsSync("/dev/tty")) return false
26
+ return true
27
+ }
9
28
 
10
29
  const __dirname = path.dirname(fileURLToPath(import.meta.url))
11
30
  const require = createRequire(import.meta.url)
@@ -26,9 +45,9 @@ try {
26
45
  // Use fallback
27
46
  }
28
47
 
29
- // Validate version format to prevent command injection (must be vX.Y.Z format)
48
+ // Validate version format to prevent command injection (must be [v]X.Y.Z format)
30
49
  function isValidVersion(version) {
31
- return /^v\d+\.\d+\.\d+$/.test(version)
50
+ return /^v?\d+\.\d+\.\d+$/.test(version)
32
51
  }
33
52
 
34
53
  if (!isValidVersion(GIT_AI_VERSION)) {
@@ -76,7 +95,7 @@ function detectPlatformAndArch() {
76
95
 
77
96
  function findBinary() {
78
97
  const { platform, arch } = detectPlatformAndArch()
79
- const packageName = `@cubic-dev-ai/cli-${platform}-${arch}`
98
+ const packageName = `${packagePrefix()}${platform}-${arch}`
80
99
  const binary = platform === "windows" ? "cubic.exe" : "cubic"
81
100
 
82
101
  try {
@@ -123,52 +142,93 @@ async function regenerateWindowsCmdWrappers() {
123
142
  }
124
143
  }
125
144
 
126
- // Install git-ai using official installer
145
+ // Install git-ai silently using official installer
127
146
  // 2 minute timeout to prevent indefinite hangs during npm install
128
147
  const GIT_AI_INSTALL_TIMEOUT = 120000
148
+ const GIT_AI_COMPATIBLE_MAJOR = 1
149
+ const GIT_AI_REPO_URL = "https://github.com/git-ai-project/git-ai"
150
+
151
+ function getGitAiBinary() {
152
+ return path.join(os.homedir(), ".git-ai", "bin", os.platform() === "win32" ? "git-ai.exe" : "git-ai")
153
+ }
154
+
155
+ // Returns "none", "compatible", or "incompatible"
156
+ function checkGitAiVersion() {
157
+ const binary = getGitAiBinary()
158
+ try {
159
+ fs.accessSync(binary, fs.constants.X_OK)
160
+ } catch {
161
+ return "none"
162
+ }
163
+
164
+ try {
165
+ const version = execSync(`"${binary}" --version`, { stdio: ["pipe", "pipe", "pipe"], timeout: 5000 })
166
+ .toString()
167
+ .trim()
168
+ const match = version.match(/^v?(\d+)\./)
169
+ if (!match) return "none"
170
+ return parseInt(match[1], 10) === GIT_AI_COMPATIBLE_MAJOR ? "compatible" : "incompatible"
171
+ } catch {
172
+ return "none"
173
+ }
174
+ }
129
175
 
130
176
  function setupGitAi() {
131
177
  // Allow users to opt-out of automatic git-ai installation
132
178
  if (process.env.CUBIC_DISABLE_GIT_AI === "true") {
133
- console.log("Skipping git-ai installation (CUBIC_DISABLE_GIT_AI=true)")
134
- console.log("You can install it later with: cubic stats enable")
135
179
  return
136
180
  }
137
181
 
138
- console.log(`Installing git-ai ${GIT_AI_VERSION} for AI code tracking...`)
182
+ const status = checkGitAiVersion()
183
+
184
+ // Already have a compatible version — nothing to do
185
+ if (status === "compatible") return
139
186
 
187
+ // Incompatible version — warn and skip
188
+ if (status === "incompatible") {
189
+ console.warn(
190
+ "git-ai is already installed, but this version is incompatible with cubic AI stats. " +
191
+ "Please uninstall git-ai and run `cubic stats enable` to install a compatible version. " +
192
+ GIT_AI_REPO_URL,
193
+ )
194
+ return
195
+ }
196
+
197
+ // Not installed — install silently
140
198
  try {
141
199
  if (os.platform() === "win32") {
142
- // PowerShell installer for Windows
143
200
  execSync(
144
201
  `powershell -NoProfile -ExecutionPolicy Bypass -Command "$env:GIT_AI_RELEASE_TAG='${GIT_AI_VERSION}'; irm https://usegitai.com/install.ps1 | iex"`,
145
- { stdio: "inherit", shell: true, timeout: GIT_AI_INSTALL_TIMEOUT },
202
+ { stdio: "ignore", shell: true, timeout: GIT_AI_INSTALL_TIMEOUT },
146
203
  )
147
204
  } else {
148
- // Bash installer for macOS/Linux
149
205
  execSync(`export GIT_AI_RELEASE_TAG="${GIT_AI_VERSION}" && curl -sSL https://usegitai.com/install.sh | bash`, {
150
- stdio: "inherit",
206
+ stdio: "ignore",
151
207
  shell: "/bin/bash",
152
208
  timeout: GIT_AI_INSTALL_TIMEOUT,
153
209
  })
154
210
  }
155
211
 
156
- console.log("git-ai installed successfully")
157
-
158
- // Configure git-ai to run in quiet mode (suppress chart output after commits)
159
- const gitAiBinary = path.join(os.homedir(), ".git-ai", "bin", os.platform() === "win32" ? "git-ai.exe" : "git-ai")
212
+ // Configure git-ai to run in quiet mode
213
+ const binary = getGitAiBinary()
160
214
  try {
161
- execSync(`"${gitAiBinary}" config set quiet true`, { stdio: "ignore", timeout: 5000 })
215
+ execSync(`"${binary}" config set quiet true`, { stdio: "ignore", timeout: 5000 })
162
216
  } catch {
163
217
  // Ignore if config fails - git-ai will work without quiet mode
164
218
  }
219
+
220
+ console.log("Close and reopen your IDE and terminal sessions in order to use AI attribution stats.")
165
221
  } catch (error) {
166
- console.warn("git-ai installation failed, continuing without it:", error.message)
167
- console.log("You can install it later with: cubic stats enable")
222
+ console.warn(
223
+ "cubic AI stats use git-ai under the hood. git-ai failed to install. " +
224
+ "Make sure git-ai installation succeeds in order to use cubic AI stats. " +
225
+ GIT_AI_REPO_URL,
226
+ )
168
227
  }
169
228
  }
170
229
 
171
230
  async function main() {
231
+ let binaryPath = ""
172
232
  try {
173
233
  if (os.platform() === "win32") {
174
234
  // NPM eg format - npm/11.4.2 node/v24.4.1 win32 x64
@@ -178,29 +238,65 @@ async function main() {
178
238
  } else {
179
239
  console.log("Windows detected but not npm, skipping binary symlink")
180
240
  }
181
- // Install git-ai on Windows too
182
- setupGitAi()
183
- return
184
- }
241
+ } else {
242
+ try {
243
+ binaryPath = findBinary()
244
+ } catch (error) {
245
+ const message = error instanceof Error ? error.message : String(error)
246
+ console.log(
247
+ `cubic: setup skipped (${message}) - run \`npm i -g @cubic-plugin/cli-manila-test\` again in a minute`,
248
+ )
249
+ return
250
+ }
251
+ const binScript = path.join(__dirname, "bin", "cubic")
252
+ const wrapperPath = path.join(__dirname, "bin", "cubic.wrapper")
185
253
 
186
- const binaryPath = findBinary()
187
- const binScript = path.join(__dirname, "bin", "cubic")
254
+ if (CUBIC_WRAPPER_MODE && fs.existsSync(wrapperPath)) {
255
+ if (fs.existsSync(binScript)) {
256
+ fs.unlinkSync(binScript)
257
+ }
258
+ fs.copyFileSync(wrapperPath, binScript)
259
+ fs.chmodSync(binScript, 0o755)
260
+ process.env.CUBIC_BIN_PATH = binaryPath
261
+ console.log(`cubic wrapper configured: ${binScript} -> ${binaryPath}`)
262
+ } else {
263
+ // Remove existing bin script if it exists
264
+ if (fs.existsSync(binScript)) {
265
+ fs.unlinkSync(binScript)
266
+ }
188
267
 
189
- // Remove existing bin script if it exists
190
- if (fs.existsSync(binScript)) {
191
- fs.unlinkSync(binScript)
268
+ // Create symlink to the actual binary
269
+ fs.symlinkSync(binaryPath, binScript)
270
+ console.log(`cubic binary symlinked: ${binScript} -> ${binaryPath}`)
271
+ }
192
272
  }
193
273
 
194
- // Create symlink to the actual binary
195
- fs.symlinkSync(binaryPath, binScript)
196
- console.log(`cubic binary symlinked: ${binScript} -> ${binaryPath}`)
197
-
198
- // Install git-ai
199
- setupGitAi()
274
+ // Install-time wizard (opt-in)
275
+ if (shouldRunInstallWizard()) {
276
+ console.log("\n◆ Optional: connect cubic to your coding agent")
277
+ try {
278
+ execFileSync(binaryPath, ["setup", "--mode", "install-time"], {
279
+ stdio: "inherit",
280
+ timeout: 60000,
281
+ env: {
282
+ ...process.env,
283
+ CUBIC_INSTALL_TTY: "0",
284
+ },
285
+ })
286
+ } catch (error) {
287
+ const m = error instanceof Error ? error.message : String(error)
288
+ console.log(`cubic: setup skipped (${m}) - run \`cubic setup\` later`)
289
+ }
290
+ } else {
291
+ console.log("cubic: Run `cubic setup` to connect your coding agent")
292
+ }
200
293
  } catch (error) {
201
294
  console.error("Failed to create cubic binary symlink:", error.message)
202
295
  process.exit(1)
203
296
  }
297
+
298
+ // Only install git-ai after cubic binary is confirmed working
299
+ setupGitAi()
204
300
  }
205
301
 
206
302
  try {