libretto 0.6.31 → 0.6.32

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,7 +1,8 @@
1
1
  import { z } from "zod";
2
2
  import { SimpleCLI } from "affordance";
3
- import { orpcCall, resolveApiUrl } from "../core/auth-fetch.js";
3
+ import { orpcCall } from "../core/auth-fetch.js";
4
4
  import { normalizeProfileName } from "../core/profiles.js";
5
+ import { withCloudApiKey } from "./shared.js";
5
6
 
6
7
  type ListProfilesResponse = {
7
8
  profiles: Array<{
@@ -17,30 +18,17 @@ type DeleteProfileResponse = {
17
18
  deleted_count: number;
18
19
  };
19
20
 
20
- function requireApiKeyCredential() {
21
- const apiKey = process.env.LIBRETTO_API_KEY?.trim();
22
- if (!apiKey) {
23
- throw new Error(
24
- "LIBRETTO_API_KEY is required to manage Libretto Cloud profiles. Issue one with `libretto cloud auth api-key issue --label <label>`.",
25
- );
26
- }
27
- return {
28
- apiUrl: resolveApiUrl(null),
29
- credential: { source: "env-api-key" as const, apiKey },
30
- };
31
- }
32
-
33
21
  export const listProfilesCommand = SimpleCLI.command({
34
22
  description: "List Libretto Cloud auth profiles",
35
23
  })
36
24
  .input(SimpleCLI.input({ positionals: [], named: {} }))
37
- .handle(async () => {
38
- const { apiUrl, credential } = requireApiKeyCredential();
25
+ .use(withCloudApiKey("manage Libretto Cloud profiles"))
26
+ .handle(async ({ ctx }) => {
39
27
  const response = await orpcCall<ListProfilesResponse>({
40
- apiUrl,
28
+ apiUrl: ctx.apiUrl,
41
29
  path: "/v1/browserProfiles/list",
42
30
  input: {},
43
- credential,
31
+ credential: ctx.credential,
44
32
  });
45
33
  if (response.profiles.length === 0) {
46
34
  console.log("No cloud profiles found.");
@@ -65,14 +53,14 @@ export const deleteProfileCommand = SimpleCLI.command({
65
53
  ],
66
54
  named: {},
67
55
  }))
68
- .handle(async ({ input }) => {
56
+ .use(withCloudApiKey("manage Libretto Cloud profiles"))
57
+ .handle(async ({ input, ctx }) => {
69
58
  const profileName = normalizeProfileName(input.profileName);
70
- const { apiUrl, credential } = requireApiKeyCredential();
71
59
  const response = await orpcCall<DeleteProfileResponse>({
72
- apiUrl,
60
+ apiUrl: ctx.apiUrl,
73
61
  path: "/v1/browserProfiles/delete",
74
62
  input: { name: profileName },
75
- credential,
63
+ credential: ctx.credential,
76
64
  });
77
65
  if (!response.success || response.deleted_count === 0) {
78
66
  console.log(`No cloud profile found for ${profileName}.`);
@@ -9,6 +9,7 @@ import {
9
9
  type SessionState,
10
10
  validateSessionName,
11
11
  } from "../core/session.js";
12
+ import { resolveApiUrl } from "../core/auth-fetch.js";
12
13
  import {
13
14
  SimpleCLI,
14
15
  type SimpleCLIContext,
@@ -40,6 +41,11 @@ export type ExperimentsContext = {
40
41
  experiments: Experiments;
41
42
  };
42
43
 
44
+ export type CloudApiKeyContext = {
45
+ apiUrl: string;
46
+ credential: { source: "env-api-key"; apiKey: string };
47
+ };
48
+
43
49
  export function withExperiments<
44
50
  TContext extends SimpleCLIContext,
45
51
  >(): SimpleCLIMiddleware<unknown, TContext, TContext & ExperimentsContext> {
@@ -49,6 +55,29 @@ export function withExperiments<
49
55
  });
50
56
  }
51
57
 
58
+ export function withCloudApiKey<
59
+ TContext extends SimpleCLIContext,
60
+ >(
61
+ action: string,
62
+ formatMissingMessage?: () => string | Promise<string>,
63
+ ): SimpleCLIMiddleware<unknown, TContext, TContext & CloudApiKeyContext> {
64
+ return async ({ ctx }) => {
65
+ const apiKey = process.env.LIBRETTO_API_KEY?.trim();
66
+ if (!apiKey) {
67
+ throw new Error(
68
+ formatMissingMessage
69
+ ? await formatMissingMessage()
70
+ : `LIBRETTO_API_KEY is required to ${action}. Issue one with \`libretto cloud auth api-key issue --label <label>\`.`,
71
+ );
72
+ }
73
+ return {
74
+ ...ctx,
75
+ apiUrl: resolveApiUrl(null),
76
+ credential: { source: "env-api-key", apiKey },
77
+ };
78
+ };
79
+ }
80
+
52
81
  export function withRequiredSession(): SimpleCLIMiddleware<
53
82
  { session?: string },
54
83
  {},
@@ -2,7 +2,7 @@ import { createHash } from "node:crypto";
2
2
  import type { ChildProcess } from "node:child_process";
3
3
  import { spawn } from "node:child_process";
4
4
  import { openSync, closeSync } from "node:fs";
5
- import { createRequire } from "node:module";
5
+ import * as moduleBuiltin from "node:module";
6
6
  import { homedir, userInfo } from "node:os";
7
7
  import { fileURLToPath } from "node:url";
8
8
  import { createIpcPeer, type IpcPeer } from "../../../shared/ipc/ipc.js";
@@ -246,25 +246,34 @@ export class DaemonClient {
246
246
  const daemonEntryPath = fileURLToPath(
247
247
  new URL("./daemon.js", import.meta.url),
248
248
  );
249
- const require = createRequire(import.meta.url);
250
- const tsxCliPath = require.resolve("tsx/cli");
249
+ const childArgs = [daemonEntryPath, JSON.stringify(config)];
250
+ const childEnv: NodeJS.ProcessEnv = { ...process.env };
251
+
252
+ if (config.workflow) {
253
+ const tsxPreflightPath = fileURLToPath(
254
+ import.meta.resolve("tsx/preflight"),
255
+ );
256
+ const tsxLoaderFlag =
257
+ typeof moduleBuiltin.register === "function" ? "--import" : "--loader";
258
+
259
+ childArgs.unshift(
260
+ "--require",
261
+ tsxPreflightPath,
262
+ tsxLoaderFlag,
263
+ import.meta.resolve("tsx"),
264
+ );
265
+
266
+ if (config.workflow.tsconfigPath) {
267
+ childEnv.TSX_TSCONFIG_PATH = config.workflow.tsconfigPath;
268
+ }
269
+ }
251
270
 
252
271
  const childStderrFd = openSync(logPath, "a");
253
- const child = spawn(
254
- process.execPath,
255
- [
256
- tsxCliPath,
257
- ...(config.workflow?.tsconfigPath
258
- ? ["--tsconfig", config.workflow.tsconfigPath]
259
- : []),
260
- daemonEntryPath,
261
- JSON.stringify(config),
262
- ],
263
- {
264
- detached: true,
265
- stdio: ["ignore", "ignore", childStderrFd, "ipc"],
266
- },
267
- );
272
+ const child = spawn(process.execPath, childArgs, {
273
+ detached: true,
274
+ stdio: ["ignore", "ignore", childStderrFd, "ipc"],
275
+ env: childEnv,
276
+ });
268
277
  closeSync(childStderrFd);
269
278
 
270
279
  const pid = child.pid!;
package/src/cli/router.ts CHANGED
@@ -2,6 +2,9 @@ import { authCommands } from "./commands/auth.js";
2
2
  import { billingCommands } from "./commands/billing.js";
3
3
  import { browserCommands } from "./commands/browser.js";
4
4
  import { cloudCredentialCommands } from "./commands/cloud-credentials.js";
5
+ import { cloudJobCommands } from "./commands/cloud-jobs.js";
6
+ import { cloudScheduleCommands } from "./commands/cloud-schedules.js";
7
+ import { settingsCommands } from "./commands/cloud-settings.js";
5
8
  import { codeSharingCommands, shareWorkflowCommand } from "./commands/cloud-sharing.js";
6
9
  import { deployCommand } from "./commands/deploy.js";
7
10
  import { executionCommands } from "./commands/execution.js";
@@ -25,7 +28,10 @@ export const cliRoutes = {
25
28
  auth: authCommands,
26
29
  billing: billingCommands,
27
30
  credentials: cloudCredentialCommands,
31
+ jobs: cloudJobCommands,
28
32
  profiles: profileCommands,
33
+ schedules: cloudScheduleCommands,
34
+ settings: settingsCommands,
29
35
  share: shareWorkflowCommand,
30
36
  sharing: codeSharingCommands,
31
37
  },