opensteer 0.6.3 → 0.6.4

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.
Files changed (33) hide show
  1. package/bin/opensteer.mjs +94 -8
  2. package/dist/{browser-profile-client-DK9qa_Dj.d.cts → browser-profile-client-D6PuRefA.d.cts} +1 -1
  3. package/dist/{browser-profile-client-CaL-mwqs.d.ts → browser-profile-client-OUHaODro.d.ts} +1 -1
  4. package/dist/{chunk-SCNX4NN3.js → chunk-54KNQTOL.js} +141 -2
  5. package/dist/{chunk-FTKWQ6X3.js → chunk-6B6LOYU3.js} +1 -1
  6. package/dist/{chunk-3OMXCBPD.js → chunk-G6V2DJRN.js} +442 -591
  7. package/dist/chunk-K5CL76MG.js +81 -0
  8. package/dist/{chunk-KE35RQOJ.js → chunk-KPPOTU3D.js} +53 -144
  9. package/dist/cli/auth.cjs +53 -6
  10. package/dist/cli/auth.d.cts +1 -1
  11. package/dist/cli/auth.d.ts +1 -1
  12. package/dist/cli/auth.js +2 -2
  13. package/dist/cli/local-profile.cjs +197 -0
  14. package/dist/cli/local-profile.d.cts +18 -0
  15. package/dist/cli/local-profile.d.ts +18 -0
  16. package/dist/cli/local-profile.js +97 -0
  17. package/dist/cli/profile.cjs +2844 -2412
  18. package/dist/cli/profile.d.cts +2 -2
  19. package/dist/cli/profile.d.ts +2 -2
  20. package/dist/cli/profile.js +469 -7
  21. package/dist/cli/server.cjs +649 -204
  22. package/dist/cli/server.js +69 -16
  23. package/dist/index.cjs +578 -185
  24. package/dist/index.d.cts +7 -5
  25. package/dist/index.d.ts +7 -5
  26. package/dist/index.js +4 -3
  27. package/dist/{types-BxiRblC7.d.cts → types-BWItZPl_.d.cts} +31 -13
  28. package/dist/{types-BxiRblC7.d.ts → types-BWItZPl_.d.ts} +31 -13
  29. package/package.json +2 -2
  30. package/skills/opensteer/SKILL.md +34 -14
  31. package/skills/opensteer/references/cli-reference.md +1 -1
  32. package/skills/opensteer/references/examples.md +5 -3
  33. package/skills/opensteer/references/sdk-reference.md +16 -14
@@ -0,0 +1,81 @@
1
+ // src/browser/chrome.ts
2
+ import { homedir, platform } from "os";
3
+ import { join } from "path";
4
+ import { existsSync, readFileSync } from "fs";
5
+ function detectChromePaths() {
6
+ const os = platform();
7
+ if (os === "darwin") {
8
+ const executable2 = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
9
+ return {
10
+ executable: existsSync(executable2) ? executable2 : null,
11
+ defaultUserDataDir: join(
12
+ homedir(),
13
+ "Library",
14
+ "Application Support",
15
+ "Google",
16
+ "Chrome"
17
+ )
18
+ };
19
+ }
20
+ if (os === "win32") {
21
+ const executable2 = join(
22
+ process.env.PROGRAMFILES || "C:\\Program Files",
23
+ "Google",
24
+ "Chrome",
25
+ "Application",
26
+ "chrome.exe"
27
+ );
28
+ return {
29
+ executable: existsSync(executable2) ? executable2 : null,
30
+ defaultUserDataDir: join(
31
+ process.env.LOCALAPPDATA || join(homedir(), "AppData", "Local"),
32
+ "Google",
33
+ "Chrome",
34
+ "User Data"
35
+ )
36
+ };
37
+ }
38
+ const executable = "/usr/bin/google-chrome";
39
+ return {
40
+ executable: existsSync(executable) ? executable : null,
41
+ defaultUserDataDir: join(homedir(), ".config", "google-chrome")
42
+ };
43
+ }
44
+ function expandHome(p) {
45
+ if (p.startsWith("~/") || p === "~") {
46
+ return join(homedir(), p.slice(1));
47
+ }
48
+ return p;
49
+ }
50
+ function listLocalChromeProfiles(userDataDir = detectChromePaths().defaultUserDataDir) {
51
+ const resolvedUserDataDir = expandHome(userDataDir);
52
+ const localStatePath = join(resolvedUserDataDir, "Local State");
53
+ if (!existsSync(localStatePath)) {
54
+ return [];
55
+ }
56
+ try {
57
+ const raw = JSON.parse(readFileSync(localStatePath, "utf-8"));
58
+ const infoCache = raw && typeof raw === "object" && !Array.isArray(raw) && raw.profile && typeof raw.profile === "object" && !Array.isArray(raw.profile) ? raw.profile.info_cache : void 0;
59
+ if (!infoCache || typeof infoCache !== "object") {
60
+ return [];
61
+ }
62
+ return Object.entries(infoCache).map(([directory, info]) => {
63
+ const record = info && typeof info === "object" && !Array.isArray(info) ? info : {};
64
+ const name = typeof record.name === "string" && record.name.trim() ? record.name.trim() : directory;
65
+ return {
66
+ directory,
67
+ name
68
+ };
69
+ }).filter((profile) => profile.directory.trim().length > 0).sort(
70
+ (left, right) => left.directory.localeCompare(right.directory)
71
+ );
72
+ } catch {
73
+ return [];
74
+ }
75
+ }
76
+
77
+ export {
78
+ detectChromePaths,
79
+ expandHome,
80
+ listLocalChromeProfiles
81
+ };
@@ -327,9 +327,10 @@ var DEFAULT_CONFIG = {
327
327
  headless: false,
328
328
  executablePath: void 0,
329
329
  slowMo: 0,
330
- connectUrl: void 0,
331
- channel: void 0,
332
- profileDir: void 0
330
+ mode: void 0,
331
+ cdpUrl: void 0,
332
+ userDataDir: void 0,
333
+ profileDirectory: void 0
333
334
  },
334
335
  storage: {
335
336
  rootDir: process.cwd()
@@ -673,6 +674,8 @@ function resolveConfigWithEnv(input = {}, options = {}) {
673
674
  const fileHasCloudApiKey = hasOwn(fileCloudOptions, "apiKey");
674
675
  const fileHasCloudAccessToken = hasOwn(fileCloudOptions, "accessToken");
675
676
  const fileRootDir = typeof fileConfig.storage?.rootDir === "string" ? fileConfig.storage.rootDir : void 0;
677
+ assertNoRemovedBrowserConfig(input.browser, "Opensteer constructor config");
678
+ assertNoRemovedBrowserConfig(fileConfig.browser, ".opensteer/config.json");
676
679
  const envRootDir = input.storage?.rootDir ?? fileRootDir ?? initialRootDir;
677
680
  const env = resolveEnv(envRootDir, {
678
681
  debug: debugHint,
@@ -688,14 +691,30 @@ function resolveConfigWithEnv(input = {}, options = {}) {
688
691
  "OPENSTEER_RUNTIME is no longer supported. Use OPENSTEER_MODE instead."
689
692
  );
690
693
  }
694
+ if (env.OPENSTEER_CONNECT_URL != null) {
695
+ throw new Error(
696
+ "OPENSTEER_CONNECT_URL is no longer supported. Use OPENSTEER_CDP_URL instead."
697
+ );
698
+ }
699
+ if (env.OPENSTEER_CHANNEL != null) {
700
+ throw new Error(
701
+ "OPENSTEER_CHANNEL is no longer supported. Use OPENSTEER_BROWSER plus OPENSTEER_BROWSER_PATH when needed."
702
+ );
703
+ }
704
+ if (env.OPENSTEER_PROFILE_DIR != null) {
705
+ throw new Error(
706
+ "OPENSTEER_PROFILE_DIR is no longer supported. Use OPENSTEER_USER_DATA_DIR and OPENSTEER_PROFILE_DIRECTORY instead."
707
+ );
708
+ }
691
709
  const envConfig = {
692
710
  browser: {
693
711
  headless: parseBool(env.OPENSTEER_HEADLESS),
694
712
  executablePath: env.OPENSTEER_BROWSER_PATH || void 0,
695
713
  slowMo: parseNumber(env.OPENSTEER_SLOW_MO),
696
- connectUrl: env.OPENSTEER_CONNECT_URL || void 0,
697
- channel: env.OPENSTEER_CHANNEL || void 0,
698
- profileDir: env.OPENSTEER_PROFILE_DIR || void 0
714
+ mode: env.OPENSTEER_BROWSER === "real" || env.OPENSTEER_BROWSER === "chromium" ? env.OPENSTEER_BROWSER : void 0,
715
+ cdpUrl: env.OPENSTEER_CDP_URL || void 0,
716
+ userDataDir: env.OPENSTEER_USER_DATA_DIR || void 0,
717
+ profileDirectory: env.OPENSTEER_PROFILE_DIRECTORY || void 0
699
718
  },
700
719
  cursor: {
701
720
  enabled: parseBool(env.OPENSTEER_CURSOR)
@@ -706,6 +725,34 @@ function resolveConfigWithEnv(input = {}, options = {}) {
706
725
  const mergedWithFile = mergeDeep(runtimeDefaults, fileConfig);
707
726
  const mergedWithEnv = mergeDeep(mergedWithFile, envConfig);
708
727
  const resolved = mergeDeep(mergedWithEnv, input);
728
+ const browserHeadlessExplicit = input.browser?.headless !== void 0 || fileConfig.browser?.headless !== void 0 || envConfig.browser?.headless !== void 0;
729
+ if (!browserHeadlessExplicit && resolved.browser?.mode === "real") {
730
+ resolved.browser = {
731
+ ...resolved.browser,
732
+ headless: true
733
+ };
734
+ }
735
+ function assertNoRemovedBrowserConfig(value, source) {
736
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
737
+ return;
738
+ }
739
+ const record = value;
740
+ if (record.connectUrl !== void 0) {
741
+ throw new Error(
742
+ `${source}.browser.connectUrl is no longer supported. Use browser.cdpUrl instead.`
743
+ );
744
+ }
745
+ if (record.channel !== void 0) {
746
+ throw new Error(
747
+ `${source}.browser.channel is no longer supported. Use browser.mode plus browser.executablePath instead.`
748
+ );
749
+ }
750
+ if (record.profileDir !== void 0) {
751
+ throw new Error(
752
+ `${source}.browser.profileDir is no longer supported. Use browser.userDataDir and browser.profileDirectory instead.`
753
+ );
754
+ }
755
+ }
709
756
  const envApiKey = resolveOpensteerApiKey(env);
710
757
  const envAccessTokenRaw = resolveOpensteerAccessToken(env);
711
758
  const envBaseUrl = resolveOpensteerBaseUrl(env);
@@ -1228,145 +1275,7 @@ function readCloudActionDescription(payload) {
1228
1275
  return normalized.length ? normalized : void 0;
1229
1276
  }
1230
1277
 
1231
- // src/auth/keychain-store.ts
1232
- import { spawnSync } from "child_process";
1233
- function commandExists(command) {
1234
- const result = spawnSync(command, ["--help"], {
1235
- encoding: "utf8",
1236
- stdio: "ignore"
1237
- });
1238
- return result.error == null;
1239
- }
1240
- function commandFailed(result) {
1241
- return typeof result.status === "number" && result.status !== 0;
1242
- }
1243
- function sanitizeCommandArgs(command, args) {
1244
- if (command !== "security") {
1245
- return args;
1246
- }
1247
- const sanitized = [];
1248
- for (let index = 0; index < args.length; index += 1) {
1249
- const value = args[index];
1250
- sanitized.push(value);
1251
- if (value === "-w" && index + 1 < args.length) {
1252
- sanitized.push("[REDACTED]");
1253
- index += 1;
1254
- }
1255
- }
1256
- return sanitized;
1257
- }
1258
- function buildCommandError(command, args, result) {
1259
- const stderr = typeof result.stderr === "string" && result.stderr.trim() ? result.stderr.trim() : `Command "${command}" failed with status ${String(result.status)}.`;
1260
- const sanitizedArgs = sanitizeCommandArgs(command, args);
1261
- return new Error(
1262
- [
1263
- `Unable to persist credential via ${command}.`,
1264
- `${command} ${sanitizedArgs.join(" ")}`,
1265
- stderr
1266
- ].join(" ")
1267
- );
1268
- }
1269
- function createMacosSecurityStore() {
1270
- return {
1271
- backend: "macos-security",
1272
- get(service, account) {
1273
- const result = spawnSync(
1274
- "security",
1275
- ["find-generic-password", "-s", service, "-a", account, "-w"],
1276
- { encoding: "utf8" }
1277
- );
1278
- if (commandFailed(result)) {
1279
- return null;
1280
- }
1281
- const secret = result.stdout.trim();
1282
- return secret.length ? secret : null;
1283
- },
1284
- set(service, account, secret) {
1285
- const args = [
1286
- "add-generic-password",
1287
- "-U",
1288
- "-s",
1289
- service,
1290
- "-a",
1291
- account,
1292
- "-w",
1293
- secret
1294
- ];
1295
- const result = spawnSync("security", args, { encoding: "utf8" });
1296
- if (commandFailed(result)) {
1297
- throw buildCommandError("security", args, result);
1298
- }
1299
- },
1300
- delete(service, account) {
1301
- const args = ["delete-generic-password", "-s", service, "-a", account];
1302
- const result = spawnSync("security", args, { encoding: "utf8" });
1303
- if (commandFailed(result)) {
1304
- return;
1305
- }
1306
- }
1307
- };
1308
- }
1309
- function createLinuxSecretToolStore() {
1310
- return {
1311
- backend: "linux-secret-tool",
1312
- get(service, account) {
1313
- const result = spawnSync(
1314
- "secret-tool",
1315
- ["lookup", "service", service, "account", account],
1316
- {
1317
- encoding: "utf8"
1318
- }
1319
- );
1320
- if (commandFailed(result)) {
1321
- return null;
1322
- }
1323
- const secret = result.stdout.trim();
1324
- return secret.length ? secret : null;
1325
- },
1326
- set(service, account, secret) {
1327
- const args = [
1328
- "store",
1329
- "--label",
1330
- "Opensteer CLI",
1331
- "service",
1332
- service,
1333
- "account",
1334
- account
1335
- ];
1336
- const result = spawnSync("secret-tool", args, {
1337
- encoding: "utf8",
1338
- input: secret
1339
- });
1340
- if (commandFailed(result)) {
1341
- throw buildCommandError("secret-tool", args, result);
1342
- }
1343
- },
1344
- delete(service, account) {
1345
- const args = ["clear", "service", service, "account", account];
1346
- spawnSync("secret-tool", args, {
1347
- encoding: "utf8"
1348
- });
1349
- }
1350
- };
1351
- }
1352
- function createKeychainStore() {
1353
- if (process.platform === "darwin") {
1354
- if (!commandExists("security")) {
1355
- return null;
1356
- }
1357
- return createMacosSecurityStore();
1358
- }
1359
- if (process.platform === "linux") {
1360
- if (!commandExists("secret-tool")) {
1361
- return null;
1362
- }
1363
- return createLinuxSecretToolStore();
1364
- }
1365
- return null;
1366
- }
1367
-
1368
1278
  export {
1369
- createKeychainStore,
1370
1279
  extractErrorMessage,
1371
1280
  normalizeError,
1372
1281
  selectCloudCredential,
package/dist/cli/auth.cjs CHANGED
@@ -159,9 +159,10 @@ var DEFAULT_CONFIG = {
159
159
  headless: false,
160
160
  executablePath: void 0,
161
161
  slowMo: 0,
162
- connectUrl: void 0,
163
- channel: void 0,
164
- profileDir: void 0
162
+ mode: void 0,
163
+ cdpUrl: void 0,
164
+ userDataDir: void 0,
165
+ profileDirectory: void 0
165
166
  },
166
167
  storage: {
167
168
  rootDir: process.cwd()
@@ -505,6 +506,8 @@ function resolveConfigWithEnv(input = {}, options = {}) {
505
506
  const fileHasCloudApiKey = hasOwn(fileCloudOptions, "apiKey");
506
507
  const fileHasCloudAccessToken = hasOwn(fileCloudOptions, "accessToken");
507
508
  const fileRootDir = typeof fileConfig.storage?.rootDir === "string" ? fileConfig.storage.rootDir : void 0;
509
+ assertNoRemovedBrowserConfig(input.browser, "Opensteer constructor config");
510
+ assertNoRemovedBrowserConfig(fileConfig.browser, ".opensteer/config.json");
508
511
  const envRootDir = input.storage?.rootDir ?? fileRootDir ?? initialRootDir;
509
512
  const env = resolveEnv(envRootDir, {
510
513
  debug: debugHint,
@@ -520,14 +523,30 @@ function resolveConfigWithEnv(input = {}, options = {}) {
520
523
  "OPENSTEER_RUNTIME is no longer supported. Use OPENSTEER_MODE instead."
521
524
  );
522
525
  }
526
+ if (env.OPENSTEER_CONNECT_URL != null) {
527
+ throw new Error(
528
+ "OPENSTEER_CONNECT_URL is no longer supported. Use OPENSTEER_CDP_URL instead."
529
+ );
530
+ }
531
+ if (env.OPENSTEER_CHANNEL != null) {
532
+ throw new Error(
533
+ "OPENSTEER_CHANNEL is no longer supported. Use OPENSTEER_BROWSER plus OPENSTEER_BROWSER_PATH when needed."
534
+ );
535
+ }
536
+ if (env.OPENSTEER_PROFILE_DIR != null) {
537
+ throw new Error(
538
+ "OPENSTEER_PROFILE_DIR is no longer supported. Use OPENSTEER_USER_DATA_DIR and OPENSTEER_PROFILE_DIRECTORY instead."
539
+ );
540
+ }
523
541
  const envConfig = {
524
542
  browser: {
525
543
  headless: parseBool(env.OPENSTEER_HEADLESS),
526
544
  executablePath: env.OPENSTEER_BROWSER_PATH || void 0,
527
545
  slowMo: parseNumber(env.OPENSTEER_SLOW_MO),
528
- connectUrl: env.OPENSTEER_CONNECT_URL || void 0,
529
- channel: env.OPENSTEER_CHANNEL || void 0,
530
- profileDir: env.OPENSTEER_PROFILE_DIR || void 0
546
+ mode: env.OPENSTEER_BROWSER === "real" || env.OPENSTEER_BROWSER === "chromium" ? env.OPENSTEER_BROWSER : void 0,
547
+ cdpUrl: env.OPENSTEER_CDP_URL || void 0,
548
+ userDataDir: env.OPENSTEER_USER_DATA_DIR || void 0,
549
+ profileDirectory: env.OPENSTEER_PROFILE_DIRECTORY || void 0
531
550
  },
532
551
  cursor: {
533
552
  enabled: parseBool(env.OPENSTEER_CURSOR)
@@ -538,6 +557,34 @@ function resolveConfigWithEnv(input = {}, options = {}) {
538
557
  const mergedWithFile = mergeDeep(runtimeDefaults, fileConfig);
539
558
  const mergedWithEnv = mergeDeep(mergedWithFile, envConfig);
540
559
  const resolved = mergeDeep(mergedWithEnv, input);
560
+ const browserHeadlessExplicit = input.browser?.headless !== void 0 || fileConfig.browser?.headless !== void 0 || envConfig.browser?.headless !== void 0;
561
+ if (!browserHeadlessExplicit && resolved.browser?.mode === "real") {
562
+ resolved.browser = {
563
+ ...resolved.browser,
564
+ headless: true
565
+ };
566
+ }
567
+ function assertNoRemovedBrowserConfig(value, source) {
568
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
569
+ return;
570
+ }
571
+ const record = value;
572
+ if (record.connectUrl !== void 0) {
573
+ throw new Error(
574
+ `${source}.browser.connectUrl is no longer supported. Use browser.cdpUrl instead.`
575
+ );
576
+ }
577
+ if (record.channel !== void 0) {
578
+ throw new Error(
579
+ `${source}.browser.channel is no longer supported. Use browser.mode plus browser.executablePath instead.`
580
+ );
581
+ }
582
+ if (record.profileDir !== void 0) {
583
+ throw new Error(
584
+ `${source}.browser.profileDir is no longer supported. Use browser.userDataDir and browser.profileDirectory instead.`
585
+ );
586
+ }
587
+ }
541
588
  const envApiKey = resolveOpensteerApiKey(env);
542
589
  const envAccessTokenRaw = resolveOpensteerAccessToken(env);
543
590
  const envBaseUrl = resolveOpensteerBaseUrl(env);
@@ -1,4 +1,4 @@
1
- import { O as OpensteerAuthScheme } from '../types-BxiRblC7.cjs';
1
+ import { O as OpensteerAuthScheme } from '../types-BWItZPl_.cjs';
2
2
  import 'playwright';
3
3
 
4
4
  interface StoredMachineCloudCredential {
@@ -1,4 +1,4 @@
1
- import { O as OpensteerAuthScheme } from '../types-BxiRblC7.js';
1
+ import { O as OpensteerAuthScheme } from '../types-BWItZPl_.js';
2
2
  import 'playwright';
3
3
 
4
4
  interface StoredMachineCloudCredential {
package/dist/cli/auth.js CHANGED
@@ -4,8 +4,8 @@ import {
4
4
  isCloudModeEnabledForRootDir,
5
5
  parseOpensteerAuthArgs,
6
6
  runOpensteerAuthCli
7
- } from "../chunk-SCNX4NN3.js";
8
- import "../chunk-KE35RQOJ.js";
7
+ } from "../chunk-54KNQTOL.js";
8
+ import "../chunk-KPPOTU3D.js";
9
9
  export {
10
10
  ensureCloudCredentialsForCommand,
11
11
  ensureCloudCredentialsForOpenCommand,
@@ -0,0 +1,197 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/cli/local-profile.ts
21
+ var local_profile_exports = {};
22
+ __export(local_profile_exports, {
23
+ parseOpensteerLocalProfileArgs: () => parseOpensteerLocalProfileArgs,
24
+ runOpensteerLocalProfileCli: () => runOpensteerLocalProfileCli
25
+ });
26
+ module.exports = __toCommonJS(local_profile_exports);
27
+
28
+ // src/browser/chrome.ts
29
+ var import_os = require("os");
30
+ var import_path = require("path");
31
+ var import_fs = require("fs");
32
+ function detectChromePaths() {
33
+ const os = (0, import_os.platform)();
34
+ if (os === "darwin") {
35
+ const executable2 = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
36
+ return {
37
+ executable: (0, import_fs.existsSync)(executable2) ? executable2 : null,
38
+ defaultUserDataDir: (0, import_path.join)(
39
+ (0, import_os.homedir)(),
40
+ "Library",
41
+ "Application Support",
42
+ "Google",
43
+ "Chrome"
44
+ )
45
+ };
46
+ }
47
+ if (os === "win32") {
48
+ const executable2 = (0, import_path.join)(
49
+ process.env.PROGRAMFILES || "C:\\Program Files",
50
+ "Google",
51
+ "Chrome",
52
+ "Application",
53
+ "chrome.exe"
54
+ );
55
+ return {
56
+ executable: (0, import_fs.existsSync)(executable2) ? executable2 : null,
57
+ defaultUserDataDir: (0, import_path.join)(
58
+ process.env.LOCALAPPDATA || (0, import_path.join)((0, import_os.homedir)(), "AppData", "Local"),
59
+ "Google",
60
+ "Chrome",
61
+ "User Data"
62
+ )
63
+ };
64
+ }
65
+ const executable = "/usr/bin/google-chrome";
66
+ return {
67
+ executable: (0, import_fs.existsSync)(executable) ? executable : null,
68
+ defaultUserDataDir: (0, import_path.join)((0, import_os.homedir)(), ".config", "google-chrome")
69
+ };
70
+ }
71
+ function expandHome(p) {
72
+ if (p.startsWith("~/") || p === "~") {
73
+ return (0, import_path.join)((0, import_os.homedir)(), p.slice(1));
74
+ }
75
+ return p;
76
+ }
77
+ function listLocalChromeProfiles(userDataDir = detectChromePaths().defaultUserDataDir) {
78
+ const resolvedUserDataDir = expandHome(userDataDir);
79
+ const localStatePath = (0, import_path.join)(resolvedUserDataDir, "Local State");
80
+ if (!(0, import_fs.existsSync)(localStatePath)) {
81
+ return [];
82
+ }
83
+ try {
84
+ const raw = JSON.parse((0, import_fs.readFileSync)(localStatePath, "utf-8"));
85
+ const infoCache = raw && typeof raw === "object" && !Array.isArray(raw) && raw.profile && typeof raw.profile === "object" && !Array.isArray(raw.profile) ? raw.profile.info_cache : void 0;
86
+ if (!infoCache || typeof infoCache !== "object") {
87
+ return [];
88
+ }
89
+ return Object.entries(infoCache).map(([directory, info]) => {
90
+ const record = info && typeof info === "object" && !Array.isArray(info) ? info : {};
91
+ const name = typeof record.name === "string" && record.name.trim() ? record.name.trim() : directory;
92
+ return {
93
+ directory,
94
+ name
95
+ };
96
+ }).filter((profile) => profile.directory.trim().length > 0).sort(
97
+ (left, right) => left.directory.localeCompare(right.directory)
98
+ );
99
+ } catch {
100
+ return [];
101
+ }
102
+ }
103
+
104
+ // src/cli/local-profile.ts
105
+ var HELP_TEXT = `Usage: opensteer local-profile <command> [options]
106
+
107
+ Inspect local Chrome profiles for real-browser mode.
108
+
109
+ Commands:
110
+ list List available local Chrome profiles
111
+
112
+ Options:
113
+ --json JSON output
114
+ --user-data-dir <path> Override Chrome user-data root
115
+ -h, --help Show this help
116
+ `;
117
+ function parseOpensteerLocalProfileArgs(argv) {
118
+ const [command, ...rest] = argv;
119
+ if (!command || command === "help" || command === "--help" || command === "-h") {
120
+ return { mode: "help" };
121
+ }
122
+ if (command !== "list") {
123
+ return {
124
+ mode: "error",
125
+ error: `Unsupported local-profile command "${command}".`
126
+ };
127
+ }
128
+ let json = false;
129
+ let userDataDir;
130
+ for (let index = 0; index < rest.length; index += 1) {
131
+ const arg = rest[index];
132
+ if (arg === "--json") {
133
+ json = true;
134
+ continue;
135
+ }
136
+ if (arg === "--help" || arg === "-h") {
137
+ return { mode: "help" };
138
+ }
139
+ if (arg === "--user-data-dir") {
140
+ const value = rest[index + 1];
141
+ if (!value) {
142
+ return {
143
+ mode: "error",
144
+ error: "--user-data-dir requires a path value."
145
+ };
146
+ }
147
+ userDataDir = value;
148
+ index += 1;
149
+ continue;
150
+ }
151
+ return {
152
+ mode: "error",
153
+ error: `Unsupported option "${arg}" for "opensteer local-profile list".`
154
+ };
155
+ }
156
+ return {
157
+ mode: "list",
158
+ json,
159
+ userDataDir
160
+ };
161
+ }
162
+ async function runOpensteerLocalProfileCli(argv, overrides = {}) {
163
+ const deps = {
164
+ writeStdout: (message) => process.stdout.write(message),
165
+ writeStderr: (message) => process.stderr.write(message),
166
+ ...overrides
167
+ };
168
+ const parsed = parseOpensteerLocalProfileArgs(argv);
169
+ if (parsed.mode === "help") {
170
+ deps.writeStdout(HELP_TEXT);
171
+ return 0;
172
+ }
173
+ if (parsed.mode === "error") {
174
+ deps.writeStderr(`${parsed.error}
175
+ `);
176
+ return 1;
177
+ }
178
+ const profiles = listLocalChromeProfiles(parsed.userDataDir);
179
+ if (parsed.json) {
180
+ deps.writeStdout(JSON.stringify({ profiles }, null, 2));
181
+ return 0;
182
+ }
183
+ if (!profiles.length) {
184
+ deps.writeStdout("No local Chrome profiles found.\n");
185
+ return 0;
186
+ }
187
+ for (const profile of profiles) {
188
+ deps.writeStdout(`${profile.directory} ${profile.name}
189
+ `);
190
+ }
191
+ return 0;
192
+ }
193
+ // Annotate the CommonJS export names for ESM import in node:
194
+ 0 && (module.exports = {
195
+ parseOpensteerLocalProfileArgs,
196
+ runOpensteerLocalProfileCli
197
+ });
@@ -0,0 +1,18 @@
1
+ interface LocalProfileCliDeps {
2
+ writeStdout: (message: string) => void;
3
+ writeStderr: (message: string) => void;
4
+ }
5
+ type ParsedLocalProfileArgs = {
6
+ mode: 'help';
7
+ } | {
8
+ mode: 'error';
9
+ error: string;
10
+ } | {
11
+ mode: 'list';
12
+ json: boolean;
13
+ userDataDir?: string;
14
+ };
15
+ declare function parseOpensteerLocalProfileArgs(argv: string[]): ParsedLocalProfileArgs;
16
+ declare function runOpensteerLocalProfileCli(argv: string[], overrides?: Partial<LocalProfileCliDeps>): Promise<number>;
17
+
18
+ export { type LocalProfileCliDeps, type ParsedLocalProfileArgs, parseOpensteerLocalProfileArgs, runOpensteerLocalProfileCli };
@@ -0,0 +1,18 @@
1
+ interface LocalProfileCliDeps {
2
+ writeStdout: (message: string) => void;
3
+ writeStderr: (message: string) => void;
4
+ }
5
+ type ParsedLocalProfileArgs = {
6
+ mode: 'help';
7
+ } | {
8
+ mode: 'error';
9
+ error: string;
10
+ } | {
11
+ mode: 'list';
12
+ json: boolean;
13
+ userDataDir?: string;
14
+ };
15
+ declare function parseOpensteerLocalProfileArgs(argv: string[]): ParsedLocalProfileArgs;
16
+ declare function runOpensteerLocalProfileCli(argv: string[], overrides?: Partial<LocalProfileCliDeps>): Promise<number>;
17
+
18
+ export { type LocalProfileCliDeps, type ParsedLocalProfileArgs, parseOpensteerLocalProfileArgs, runOpensteerLocalProfileCli };