@visa/cli 1.0.3 → 1.0.4-rc.3

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.
@@ -1,6 +1,7 @@
1
1
  #import <Foundation/Foundation.h>
2
2
  #import <Security/Security.h>
3
3
  #import <LocalAuthentication/LocalAuthentication.h>
4
+ #import <AppKit/AppKit.h>
4
5
 
5
6
  // SPKI DER header for P-256 (prime256v1) uncompressed public key
6
7
  static const unsigned char SPKI_HEADER[] = {
@@ -132,21 +133,62 @@ int cmd_sign(const char *challenge, const char *reason) {
132
133
  return 1;
133
134
  }
134
135
 
135
- // Touch ID gate
136
+ // Authentication gate (Touch ID OR password — whichever the user has).
137
+ //
138
+ // We use LAPolicyDeviceOwnerAuthentication, which presents a single
139
+ // system dialog: Touch ID on enrolled hardware, password fallback
140
+ // everywhere else (including users who skipped biometric setup and
141
+ // Macs without a Touch ID sensor). This front-focus fix applies to
142
+ // BOTH dialogs — they are the same system-level window, just with
143
+ // different input modes. If we only fixed the Touch ID path we would
144
+ // still be burying the password prompt behind the terminal for every
145
+ // non-biometric user.
146
+ //
147
+ // Front-focus fix: bare CLI binaries have no NSApplication, so the
148
+ // system LAContext dialog gets parented to whichever process happens to
149
+ // be frontmost (usually the terminal or Claude Code), which puts the
150
+ // prompt *behind* the user's current window — users never see it, time
151
+ // out, and their spend gets cancelled.
152
+ //
153
+ // Making the binary an Accessory-policy NSApplication and explicitly
154
+ // calling activateIgnoringOtherApps: before evaluatePolicy tells the
155
+ // window server this process is the new frontmost app, so the auth
156
+ // prompt (biometric or password) is raised on top of all other
157
+ // windows. Accessory policy means no Dock icon, no menu bar — the
158
+ // binary stays invisible except for the dialog itself.
159
+ [NSApplication sharedApplication];
160
+ [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
161
+ [NSApp activateIgnoringOtherApps:YES];
162
+
136
163
  LAContext *ctx = [[LAContext alloc] init];
137
164
  NSString *reasonStr = reason
138
165
  ? [NSString stringWithUTF8String:reason]
139
166
  : @"approve payment";
140
167
 
141
- dispatch_semaphore_t sem = dispatch_semaphore_create(0);
168
+ __block BOOL done = NO;
142
169
  __block BOOL authOk = NO;
143
170
  [ctx evaluatePolicy:LAPolicyDeviceOwnerAuthentication
144
171
  localizedReason:reasonStr
145
172
  reply:^(BOOL success, NSError *err) {
146
173
  authOk = success;
147
- dispatch_semaphore_signal(sem);
174
+ done = YES;
148
175
  }];
149
- dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
176
+
177
+ // Pump the main run loop while waiting for the reply block. Using
178
+ // dispatch_semaphore_wait here would freeze the main thread and
179
+ // prevent the WindowServer from delivering the activation we just
180
+ // requested — the dialog would come up, but not on top.
181
+ NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:55.0];
182
+ while (!done) {
183
+ @autoreleasepool {
184
+ [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
185
+ beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.05]];
186
+ if ([[NSDate date] compare:timeout] == NSOrderedDescending) {
187
+ printf("ERROR:Authentication timed out\n");
188
+ return 1;
189
+ }
190
+ }
191
+ }
150
192
 
151
193
  if (!authOk) {
152
194
  printf("ERROR:Authentication cancelled by user\n");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@visa/cli",
3
- "version": "1.0.3",
3
+ "version": "1.0.4-rc.3",
4
4
  "description": "AI-powered payments for Claude Code",
5
5
  "bin": {
6
6
  "visa-cli": "./bin/visa-cli.js"
@@ -16,8 +16,8 @@
16
16
  "test:smoke": "VISA_AUTH_URL=https://auth.visacli.sh jest --config jest.smoke.config.js",
17
17
  "test:integration": "jest --config jest.integration.config.js",
18
18
  "test:e2e": "jest --config jest.e2e.config.js",
19
+ "test:catalog-e2e": "jest --config jest.catalog-e2e.config.js",
19
20
  "test:all": "npm run test:unit && npm run test:integration && npm run test:e2e",
20
- "prepare": "husky",
21
21
  "prepublishOnly": "npm run build && npm test",
22
22
  "lint": "eslint src/**/*.ts",
23
23
  "format": "prettier --write \"src/**/*.ts\"",
@@ -37,7 +37,9 @@
37
37
  "license": "SEE LICENSE IN LICENSE",
38
38
  "dependencies": {
39
39
  "@modelcontextprotocol/sdk": "^1.0.0",
40
- "commander": "^12.1.0"
40
+ "@visa-cli/tools": "workspace:*",
41
+ "commander": "^12.1.0",
42
+ "zod": "^3.23.0"
41
43
  },
42
44
  "devDependencies": {
43
45
  "@changesets/changelog-git": "^0.2.1",
@@ -51,7 +53,6 @@
51
53
  "express": "^4.21.0",
52
54
  "eslint": "^10.0.2",
53
55
  "eslint-config-prettier": "^10.1.8",
54
- "husky": "^9.1.7",
55
56
  "jest": "^29.7.0",
56
57
  "prettier": "^3.8.1",
57
58
  "ts-jest": "^29.2.0",
package/LICENSE DELETED
@@ -1,8 +0,0 @@
1
- Copyright (c) 2026 Visa International Service Association. All rights reserved.
2
-
3
- Use of this software is governed by the Visa CLI Terms of Use, available at:
4
- https://auth.visacli.sh/legal/terms
5
-
6
- This software is proprietary and confidential. Unauthorized copying, distribution,
7
- or use of this software, in whole or in part, is strictly prohibited except as
8
- expressly permitted by the Visa CLI Terms of Use.