Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

release: v0.1.8#3

Merged
code-crusher merged 1 commit into
mainMatterAIOrg/OrbCode:mainfrom
release/v0.1.8MatterAIOrg/OrbCode:release/v0.1.8Copy head branch name to clipboard
Jun 12, 2026
Merged

release: v0.1.8#3
code-crusher merged 1 commit into
mainMatterAIOrg/OrbCode:mainfrom
release/v0.1.8MatterAIOrg/OrbCode:release/v0.1.8Copy head branch name to clipboard

Conversation

@code-crusher

Copy link
Copy Markdown
Member

Bumps version to 0.1.8 and ships:

  • orbcode update --force/-f to force a global install with a warning
  • isGlobalInstall now realpathSyncs symlinks so symlinked global installs are no longer mis-detected as local
  • overrides.formdata-node: ^6.0.3 to silence the node-domexception@1.0.0 deprecated install warning

Tagged v0.1.8 on main will trigger the existing .github/workflows/release.yml to publish to npm + create the GitHub Release.

@code-crusher code-crusher merged commit da0039c into main Jun 12, 2026
1 check was pending
@matterai-app

matterai-app Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Summary By MatterAI MatterAI logo

🔄 What Changed

Released version 0.1.8. This update fixes a critical bug in global installation detection by resolving symlinks in the execution path. It also introduces a --force (or -f) flag to the update command, allowing users to bypass environment checks, and adds MIT license metadata with dependency overrides for formdata-node.

🔍 Impact of the Change

Improves the reliability of the CLI update mechanism, specifically for users who install the tool globally via NPM where symlinks are standard. The --force flag provides an essential escape hatch for non-standard environments, ensuring users can always access the latest features.

📁 Total Files Changed

Click to Expand
File ChangeLog
Version Bump package.json Incremented version to 0.1.8, added MIT license, and implemented dependency overrides for formdata-node.
CLI Logic src/index.tsx Added --force flag support to the update command and improved error messaging for local installs.
Path Resolution src/utils/updateCheck.ts Refactored isGlobalInstall to use fs.realpathSync, ensuring symlinked global installs are correctly identified.

🧪 Test Recommended

Recommended

  • Unit Test: Validate resolveEntrypoint logic using mocked process.argv and symlinked file paths.
  • Integration Test: Verify that orbcode update --force successfully triggers the update process even when isGlobalInstall returns false.

🔒 Security Vulnerabilities

No direct vulnerabilities detected. The addition of overrides for formdata-node suggests a proactive fix for potential downstream dependency issues. 🛡️

@matterai-app matterai-app Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧪 PR Review is completed: Release PR bumps version to 0.1.8, adds --force flag to update command, and fixes global install detection by resolving symlinks. Found one potential crash path and a logic edge case in the new symlink resolution.

Skipped files
  • CHANGELOG.md: Skipped file pattern
  • package-lock.json: Skipped file pattern
⬇️ Low Priority Suggestions (2)
src/utils/updateCheck.ts (1 suggestion)

Location: src/utils/updateCheck.ts (Lines 178-193)

🔴 Error Handling

Issue: resolveEntrypoint() catches errors from fs.realpathSync() silently with an empty catch block, but if argvPath exists and is a broken symlink, realpathSync throws and we silently fall through to import.meta.url. More critically, if argvPath is provided but realpathSync throws for any reason (permissions, broken symlink), we ignore the error and fall through. The bigger issue: if argvPath is a directory or non-existent path that doesn't throw, realpathSync returns it, but then isGlobalInstall regex might fail. However, the actual crash risk: if process.argv[1] is undefined, we check import.meta.url, but in some bundled/compiled environments (e.g., pkg, nexe, esbuild), import.meta.url can be undefined or not a string despite the check, and we return "". Then isGlobalInstall() regex on empty string returns false, which is fine. But the real issue: if argvPath is a relative path like node_modules/.bin/orbcode, realpathSync resolves it relative to CWD, not the actual install location, giving wrong results.

Actually, re-reading: realpathSync resolves relative to process.cwd(), but argv[1] is usually absolute. The more concrete issue: fs.realpathSync is sync I/O on the main thread; not critical but acceptable for CLI startup. The actual bug: if argvPath exists but realpathSync throws for any reason, we fall through silently and may return import.meta.url which could be file:///.../src/index.tsx (not node_modules), causing isGlobalInstall() to falsely return false for a global install. This breaks the update flow for users with broken symlinks or permission issues.

Fix: At minimum log the realpathSync failure for debugging, and consider falling back more carefully. The primary fix: also try fs.realpathSync on import.meta.url if it's a file: URL to ensure we get the real filesystem path, not a symlinked path.

Impact: Prevents false "local install" detection for global installs with symlink issues, ensuring orbcode update works correctly

-  function resolveEntrypoint(): string {
-    const argvPath = process.argv[1];
-    if (argvPath) {
-      try {
-        return fs.realpathSync(argvPath);
-      } catch {
-        // fall through to import.meta.url
-      }
-    }
-    // import.meta.url is the real file:// URL of the running module, which
-    // already points inside node_modules for a global install.
-    if (typeof import.meta.url === "string" && import.meta.url) {
-      return import.meta.url;
-    }
-    return "";
-  }
+  function resolveEntrypoint(): string {
+    const argvPath = process.argv[1];
+    if (argvPath) {
+      try {
+        return fs.realpathSync(argvPath);
+      } catch (err) {
+        // fall through to import.meta.url
+      }
+    }
+    if (typeof import.meta.url === "string" && import.meta.url) {
+      try {
+        const filePath = fileURLToPath(import.meta.url);
+        return fs.realpathSync(filePath);
+      } catch {
+        return fileURLToPath(import.meta.url);
+      }
+    }
+    return "";
+  }
src/index.tsx (1 suggestion)

Location: src/index.tsx (Lines 99-100)

🟡 Code Quality

Issue: The --force flag parsing uses args.includes("--force") || args.includes("-f"), but args is process.argv.slice(2) per context. There's no check that --force or -f isn't being interpreted as a prompt value or other positional argument. More importantly, if a user runs orbcode update --force --force or -f -f, it's harmless, but if they run orbcode "update --force" as a prompt string, the shell quotes won't matter here. The real issue: args.includes("-f") is very broad — -f is a common flag. What if someone runs orbcode -f "my prompt" intending -f for something else? But in this context, args[0] === "update" is checked first, so it's only for the update command. Still, args.includes doesn't validate position — orbcode update some-prompt --force would still trigger force. That's probably intended (flag can be anywhere). Not a bug.

Wait, looking closer: args[0] === "update" is checked, but what if args is ["update", "--force"]? Then force = true, correct. What about args = ["update", "--force", "something"]? force = true, still works. The issue is minor: using .includes() means --force could be confused with a prompt that contains --force as a substring, but .includes() checks exact array element equality, not substring. So "--force" as a prompt would need to be the exact argument. A user running orbcode update "fix the --force bug" would pass args = ["update", "fix the --force bug"] and includes returns false. So it's safe.

However, there is a real issue: args.includes("-f") — if the user passes -f as a shorthand, it works, but this is inconsistent with the help text which only documents --force. The help text doesn't mention -f. This is a minor documentation/UX inconsistency.

Fix: Remove the -f shorthand or add it to help text. Given it's not documented, either remove it to match docs, or update docs.

Impact: Improves CLI UX consistency

-  		const force = args.includes("--force") || args.includes("-f")
-  		const code = await runUpdate(force)
+  		const force = args.includes("--force")
+  		const code = await runUpdate(force)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Morty Proxy This is a proxified and sanitized view of the page, visit original site.