opensteer 0.8.10 → 0.8.11

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/cli/bin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { assertProviderSupportsEngine, createOpensteerSemanticRuntime, OpensteerBrowserManager, dispatchSemanticOperation, loadEnvironment, normalizeOpensteerProviderMode, discoverLocalCdpBrowsers, inspectCdpEndpoint, resolveOpensteerRuntimeConfig, resolveOpensteerEngineName, resolveOpensteerProvider, resolveFilesystemWorkspacePath, FlowRecorderCollector, generateReplayScript, pathExists, readPersistedLocalBrowserSessionRecord, readPersistedCloudSessionRecord, OpensteerCloudClient, isProcessRunning } from '../chunk-F3X6UOEN.js';
2
+ import { assertProviderSupportsEngine, createOpensteerSemanticRuntime, OpensteerBrowserManager, dispatchSemanticOperation, loadEnvironment, normalizeOpensteerProviderMode, discoverLocalCdpBrowsers, inspectCdpEndpoint, resolveOpensteerRuntimeConfig, resolveOpensteerEngineName, resolveOpensteerProvider, resolveFilesystemWorkspacePath, CloudSessionProxy, FlowRecorderCollector, generateReplayScript, pathExists, readPersistedLocalBrowserSessionRecord, readPersistedCloudSessionRecord, OpensteerCloudClient, isProcessRunning } from '../chunk-33FDEOQY.js';
3
3
  import process2 from 'process';
4
4
  import { spawn } from 'child_process';
5
5
  import { existsSync } from 'fs';
@@ -10,7 +10,7 @@ import { mkdir, writeFile } from 'fs/promises';
10
10
 
11
11
  // package.json
12
12
  var package_default = {
13
- version: "0.8.9"};
13
+ version: "0.8.10"};
14
14
 
15
15
  // src/cli/env-loader.ts
16
16
  async function loadCliEnvironment(cwd) {
@@ -313,6 +313,65 @@ async function runOpensteerRecordCommand(input) {
313
313
  }
314
314
  }
315
315
  }
316
+ async function runOpensteerCloudRecordCommand(input) {
317
+ const stdout = input.stdout ?? process.stdout;
318
+ const stderr = input.stderr ?? process.stderr;
319
+ const outputPath = resolveRecordOutputPath({
320
+ rootDir: input.rootDir,
321
+ workspace: input.workspace,
322
+ ...input.outputPath === void 0 ? {} : { outputPath: input.outputPath }
323
+ });
324
+ let cloud;
325
+ const resolveCloud = () => {
326
+ cloud ??= new OpensteerCloudClient(input.cloudConfig);
327
+ return cloud;
328
+ };
329
+ const runtime = input.runtime ?? new CloudSessionProxy(resolveCloud(), {
330
+ rootDir: input.rootDir,
331
+ workspace: input.workspace
332
+ });
333
+ const client = input.client ?? resolveCloud();
334
+ const sleep = input.sleep ?? delay;
335
+ let closed = false;
336
+ try {
337
+ await runtime.open({
338
+ url: input.url,
339
+ ...input.browser === void 0 ? {} : { browser: input.browser },
340
+ ...input.launch === void 0 ? {} : { launch: input.launch },
341
+ ...input.context === void 0 ? {} : { context: input.context }
342
+ });
343
+ const sessionId = await resolveCloudRecordingSessionId(runtime);
344
+ const sessionUrl = buildCloudRecordingSessionUrl(input.cloudConfig, sessionId);
345
+ await client.startSessionRecording(sessionId);
346
+ stderr.write(
347
+ `Recording browser actions for workspace "${input.workspace}". Open ${sessionUrl} and click "Stop recording" in the browser session toolbar when you're done.
348
+ `
349
+ );
350
+ const completed = await waitForCloudRecordingCompletion({
351
+ client,
352
+ sessionId,
353
+ ...input.pollIntervalMs === void 0 ? {} : { pollIntervalMs: input.pollIntervalMs },
354
+ sleep
355
+ });
356
+ if (completed.result === void 0) {
357
+ throw new Error("Cloud recording completed without a replay script.");
358
+ }
359
+ await mkdir(path.dirname(outputPath), { recursive: true });
360
+ await writeFile(outputPath, completed.result.script, "utf8");
361
+ await runtime.close();
362
+ closed = true;
363
+ stdout.write(`${outputPath}
364
+ `);
365
+ stderr.write(`Cloud browser session: ${sessionUrl}
366
+ `);
367
+ stderr.write(`Wrote replay script to ${outputPath}
368
+ `);
369
+ } finally {
370
+ if (!closed) {
371
+ await runtime.close().catch(() => void 0);
372
+ }
373
+ }
374
+ }
316
375
  function resolveRecordOutputPath(input) {
317
376
  if (input.outputPath !== void 0) {
318
377
  return path.resolve(input.rootDir, input.outputPath);
@@ -347,6 +406,35 @@ function createRecorderRuntimeAdapter(runtime) {
347
406
  }
348
407
  };
349
408
  }
409
+ function buildCloudRecordingSessionUrl(cloudConfig, sessionId) {
410
+ const baseUrl = cloudConfig.appBaseUrl;
411
+ if (!baseUrl || baseUrl.trim().length === 0) {
412
+ throw new Error(
413
+ 'record with provider=cloud requires OPENSTEER_CLOUD_APP_BASE_URL or "--cloud-app-base-url".'
414
+ );
415
+ }
416
+ return `${baseUrl.replace(/\/+$/, "")}/browsers/${encodeURIComponent(sessionId)}`;
417
+ }
418
+ async function resolveCloudRecordingSessionId(runtime) {
419
+ const info = await runtime.info();
420
+ if (typeof info.sessionId !== "string" || info.sessionId.length === 0) {
421
+ throw new Error("Cloud recording could not resolve the created session id.");
422
+ }
423
+ return info.sessionId;
424
+ }
425
+ async function waitForCloudRecordingCompletion(input) {
426
+ const pollIntervalMs = input.pollIntervalMs ?? 1e3;
427
+ for (; ; ) {
428
+ const state = await input.client.getSessionRecording(input.sessionId);
429
+ if (state.status === "completed") {
430
+ return state;
431
+ }
432
+ if (state.status === "failed") {
433
+ throw new Error(state.error ?? "Cloud recording failed.");
434
+ }
435
+ await input.sleep(pollIntervalMs);
436
+ }
437
+ }
350
438
  function formatRecordedAction(action) {
351
439
  const time = new Date(action.timestamp).toISOString().slice(11, 19);
352
440
  switch (action.kind) {
@@ -378,6 +466,11 @@ function formatRecordedAction(action) {
378
466
  return `[${time}] reload ${action.pageId}`;
379
467
  }
380
468
  }
469
+ function delay(ms) {
470
+ return new Promise((resolve) => {
471
+ setTimeout(resolve, ms);
472
+ });
473
+ }
381
474
 
382
475
  // src/cli/bin.ts
383
476
  var OPERATION_ALIASES = /* @__PURE__ */ new Map([
@@ -627,22 +720,39 @@ async function handleRecordCommandEntry(parsed) {
627
720
  }
628
721
  const provider = resolveCliProvider(parsed);
629
722
  assertCloudCliOptionsMatchProvider(parsed, provider.mode);
630
- if (provider.mode !== "local") {
631
- throw new Error(
632
- 'record requires provider=local. Set "--provider local" or clear OPENSTEER_PROVIDER.'
633
- );
634
- }
635
723
  const engineName = resolveCliEngineName(parsed);
636
724
  if (engineName !== "playwright") {
637
725
  throw new Error("record requires engine=playwright.");
638
726
  }
639
- if (parsed.options.browser !== void 0 && parsed.options.browser !== "persistent") {
640
- throw new Error('record only supports "--browser persistent".');
727
+ const rootDir = process2.cwd();
728
+ const recordBrowser = parsed.options.browser;
729
+ if (provider.mode === "cloud") {
730
+ if (typeof recordBrowser === "object") {
731
+ throw new Error('record does not support browser.mode="attach".');
732
+ }
733
+ const runtimeProvider = buildCliRuntimeProvider(parsed, provider.mode);
734
+ const runtimeConfig = resolveOpensteerRuntimeConfig({
735
+ ...runtimeProvider === void 0 ? {} : { provider: runtimeProvider },
736
+ environment: process2.env
737
+ });
738
+ await runOpensteerCloudRecordCommand({
739
+ cloudConfig: runtimeConfig.cloud,
740
+ workspace: parsed.options.workspace,
741
+ url,
742
+ rootDir,
743
+ ...recordBrowser === void 0 ? {} : { browser: recordBrowser },
744
+ ...parsed.options.launch === void 0 ? {} : { launch: parsed.options.launch },
745
+ ...parsed.options.context === void 0 ? {} : { context: parsed.options.context },
746
+ ...parsed.options.output === void 0 ? {} : { outputPath: parsed.options.output }
747
+ });
748
+ return;
641
749
  }
642
750
  if (parsed.options.launch?.headless === true) {
643
751
  throw new Error('record requires a headed browser. Remove "--headless true".');
644
752
  }
645
- const rootDir = process2.cwd();
753
+ if (recordBrowser !== void 0 && recordBrowser !== "persistent") {
754
+ throw new Error('record only supports "--browser persistent".');
755
+ }
646
756
  const launch = {
647
757
  ...parsed.options.launch ?? {},
648
758
  headless: false
@@ -782,6 +892,7 @@ var CLI_OPTION_SPECS = {
782
892
  provider: { kind: "value" },
783
893
  "cloud-base-url": { kind: "value" },
784
894
  "cloud-api-key": { kind: "value" },
895
+ "cloud-app-base-url": { kind: "value" },
785
896
  "cloud-profile-id": { kind: "value" },
786
897
  "cloud-profile-reuse-if-active": { kind: "boolean" },
787
898
  json: { kind: "boolean" },
@@ -911,6 +1022,7 @@ function parseCommandLine(argv) {
911
1022
  const provider = providerValue === void 0 ? void 0 : normalizeOpensteerProviderMode(providerValue, "--provider");
912
1023
  const cloudBaseUrl = readSingle(rawOptions, "cloud-base-url");
913
1024
  const cloudApiKey = readSingle(rawOptions, "cloud-api-key");
1025
+ const cloudAppBaseUrl = readSingle(rawOptions, "cloud-app-base-url");
914
1026
  const cloudProfileId = readSingle(rawOptions, "cloud-profile-id");
915
1027
  const cloudProfileReuseIfActive = readOptionalBoolean(
916
1028
  rawOptions,
@@ -932,6 +1044,7 @@ function parseCommandLine(argv) {
932
1044
  ...provider === void 0 ? {} : { provider },
933
1045
  ...cloudBaseUrl === void 0 ? {} : { cloudBaseUrl },
934
1046
  ...cloudApiKey === void 0 ? {} : { cloudApiKey },
1047
+ ...cloudAppBaseUrl === void 0 ? {} : { cloudAppBaseUrl },
935
1048
  ...cloudProfileId === void 0 ? {} : { cloudProfileId },
936
1049
  ...cloudProfileReuseIfActive === void 0 ? {} : { cloudProfileReuseIfActive },
937
1050
  ...json === void 0 ? {} : { json },
@@ -1016,7 +1129,7 @@ function buildCliRuntimeProvider(parsed, providerMode) {
1016
1129
  return explicitProvider?.mode === "local" ? explicitProvider : void 0;
1017
1130
  }
1018
1131
  const browserProfile = buildCliBrowserProfile(parsed);
1019
- const hasCloudOverrides = parsed.options.cloudBaseUrl !== void 0 || parsed.options.cloudApiKey !== void 0 || browserProfile !== void 0;
1132
+ const hasCloudOverrides = parsed.options.cloudBaseUrl !== void 0 || parsed.options.cloudApiKey !== void 0 || parsed.options.cloudAppBaseUrl !== void 0 || browserProfile !== void 0;
1020
1133
  if (!hasCloudOverrides && explicitProvider?.mode !== "cloud") {
1021
1134
  return void 0;
1022
1135
  }
@@ -1024,11 +1137,12 @@ function buildCliRuntimeProvider(parsed, providerMode) {
1024
1137
  mode: "cloud",
1025
1138
  ...parsed.options.cloudBaseUrl === void 0 ? {} : { baseUrl: parsed.options.cloudBaseUrl },
1026
1139
  ...parsed.options.cloudApiKey === void 0 ? {} : { apiKey: parsed.options.cloudApiKey },
1140
+ ...parsed.options.cloudAppBaseUrl === void 0 ? {} : { appBaseUrl: parsed.options.cloudAppBaseUrl },
1027
1141
  ...browserProfile === void 0 ? {} : { browserProfile }
1028
1142
  };
1029
1143
  }
1030
1144
  function assertCloudCliOptionsMatchProvider(parsed, providerMode) {
1031
- if (providerMode !== "cloud" && (parsed.options.cloudBaseUrl !== void 0 || parsed.options.cloudApiKey !== void 0 || parsed.options.cloudProfileId !== void 0 || parsed.options.cloudProfileReuseIfActive === true)) {
1145
+ if (providerMode !== "cloud" && (parsed.options.cloudBaseUrl !== void 0 || parsed.options.cloudApiKey !== void 0 || parsed.options.cloudAppBaseUrl !== void 0 || parsed.options.cloudProfileId !== void 0 || parsed.options.cloudProfileReuseIfActive === true)) {
1032
1146
  throw new Error(
1033
1147
  'Cloud-specific options require provider=cloud. Set "--provider cloud" or OPENSTEER_PROVIDER=cloud.'
1034
1148
  );
@@ -1170,6 +1284,7 @@ Common options:
1170
1284
  --provider local|cloud
1171
1285
  --cloud-base-url <url>
1172
1286
  --cloud-api-key <key>
1287
+ --cloud-app-base-url <url>
1173
1288
  --cloud-profile-id <id>
1174
1289
  --cloud-profile-reuse-if-active <true|false>
1175
1290
  --json <true|false>