@remixhq/cli 0.1.12 → 0.1.13

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.js CHANGED
@@ -1923,6 +1923,9 @@ function buildKeyName(params) {
1923
1923
  const ts = Math.floor(Date.now() / 1e3);
1924
1924
  return `cli_${user}_${hostname}_${ts}`;
1925
1925
  }
1926
+ function buildDashboardAppUrl(appId) {
1927
+ return `https://dashboard.remix.one/apps/${encodeURIComponent(appId)}`;
1928
+ }
1926
1929
  async function initLocal(params) {
1927
1930
  await ensureAuth({ yes: params.yes, json: params.json });
1928
1931
  const cfg = await resolveConfig({ yes: params.yes });
@@ -1992,6 +1995,7 @@ async function initLocal(params) {
1992
1995
  });
1993
1996
  return {
1994
1997
  appId: imported.appId,
1998
+ dashboardUrl: buildDashboardAppUrl(imported.appId),
1995
1999
  uploadId: imported.uploadId,
1996
2000
  projectId: imported.projectId,
1997
2001
  threadId: imported.threadId,
@@ -2018,6 +2022,7 @@ function registerInitCommands(program) {
2018
2022
  return;
2019
2023
  }
2020
2024
  console.log(pc9.green(`Completed. appId=${res.appId}`));
2025
+ console.log(pc9.dim(`Dashboard: ${res.dashboardUrl}`));
2021
2026
  if (res.status) console.log(pc9.dim(`Status: ${res.status}`));
2022
2027
  });
2023
2028
  }
@@ -2027,9 +2032,13 @@ import fs15 from "fs/promises";
2027
2032
  import path13 from "path";
2028
2033
  import pc10 from "picocolors";
2029
2034
  import {
2035
+ collabListMembers as collabListMembersCore,
2036
+ collabUpdateMemberRole as collabUpdateMemberRoleCore,
2037
+ getMemberRolesForScope,
2030
2038
  collabAdd as collabAddCore,
2031
2039
  collabRecordTurn as collabRecordTurnCore,
2032
2040
  collabApprove as collabApproveCore,
2041
+ collabCheckout as collabCheckoutCore,
2033
2042
  collabListMergeRequests as collabListMergeRequestsCore,
2034
2043
  collabInit as collabInitCore,
2035
2044
  collabInvite as collabInviteCore,
@@ -2139,6 +2148,7 @@ async function collabInit(params) {
2139
2148
  } else {
2140
2149
  console.log(pc10.green(`Initialized repository in Remix. appId=${result.appId}`));
2141
2150
  }
2151
+ console.log(pc10.dim(`Dashboard: ${result.dashboardUrl}`));
2142
2152
  printResultWarnings(params.json, result);
2143
2153
  }
2144
2154
  return result;
@@ -2249,7 +2259,24 @@ async function collabRemix(params) {
2249
2259
  appId: params.appId,
2250
2260
  name: params.name
2251
2261
  });
2252
- if (!params.json) console.log(pc10.green(`Created remix. appId=${result.appId} path=${result.repoRoot}`));
2262
+ if (!params.json) {
2263
+ console.log(pc10.green(`Created remix. appId=${result.appId} path=${result.repoRoot}`));
2264
+ console.log(pc10.dim(`Dashboard: ${result.dashboardUrl}`));
2265
+ }
2266
+ return result;
2267
+ }
2268
+ async function collabCheckout(params) {
2269
+ const api = await createCollabApi(params);
2270
+ const result = await collabCheckoutCore({
2271
+ api,
2272
+ cwd: params.cwd,
2273
+ outputDir: params.outputDir ?? null,
2274
+ appId: params.appId
2275
+ });
2276
+ if (!params.json) {
2277
+ console.log(pc10.green(`Checked out app. appId=${result.appId} path=${result.repoRoot}`));
2278
+ console.log(pc10.dim(`Dashboard: ${result.dashboardUrl}`));
2279
+ }
2253
2280
  return result;
2254
2281
  }
2255
2282
  async function collabAdd(params) {
@@ -2594,6 +2621,50 @@ async function collabInviteRevoke(params) {
2594
2621
  if (!params.json) console.log(pc10.green(`Revoked ${params.scope} invite. id=${params.inviteId}`));
2595
2622
  return result;
2596
2623
  }
2624
+ async function collabMembersList(params) {
2625
+ const api = await createCollabApi(params);
2626
+ const result = await collabListMembersCore({
2627
+ api,
2628
+ cwd: params.cwd,
2629
+ scope: params.scope,
2630
+ targetId: params.targetId ?? null
2631
+ });
2632
+ if (!params.json) {
2633
+ for (const member of result.members) {
2634
+ console.log(
2635
+ `${String(member.userId ?? "")} role=${String(member.role ?? "")} invitedBy=${String(member.invitedBy ?? "")}`
2636
+ );
2637
+ }
2638
+ }
2639
+ return result;
2640
+ }
2641
+ async function collabMembersUpdate(params) {
2642
+ const normalizedRole = params.role.trim().toLowerCase();
2643
+ if (!getMemberRolesForScope(params.scope).includes(normalizedRole)) {
2644
+ throw new CliError(`Invalid ${params.scope} member role.`, {
2645
+ exitCode: 2,
2646
+ hint: `Allowed roles: ${getMemberRolesForScope(params.scope).join(", ")}`
2647
+ });
2648
+ }
2649
+ const api = await createCollabApi(params);
2650
+ const result = await collabUpdateMemberRoleCore({
2651
+ api,
2652
+ cwd: params.cwd,
2653
+ scope: params.scope,
2654
+ targetId: params.targetId ?? null,
2655
+ userId: params.userId,
2656
+ role: normalizedRole
2657
+ });
2658
+ if (!params.json) {
2659
+ const member = result.member;
2660
+ console.log(
2661
+ pc10.green(
2662
+ `Updated ${result.scopeType} member. userId=${String(member.userId ?? params.userId)} role=${String(member.role ?? normalizedRole)}`
2663
+ )
2664
+ );
2665
+ }
2666
+ return result;
2667
+ }
2597
2668
 
2598
2669
  // src/services/memory.ts
2599
2670
  import pc11 from "picocolors";
@@ -2903,6 +2974,16 @@ function registerCollabCommands(program) {
2903
2974
  });
2904
2975
  if (opts.json) console.log(JSON.stringify(result, null, 2));
2905
2976
  });
2977
+ collab.command("checkout <appId>").description("Check out an existing Remix app as-is into a new local checkout").option("--output-dir <path>", "Exact destination path for the checked out app").option("--cwd <path>", "Parent directory where the checked out app will be created when --output-dir is not provided").option("--yes", "Run non-interactively", false).option("--non-interactive", "Run non-interactively", false).option("--json", "Output JSON", false).action(async (appId, opts) => {
2978
+ const result = await collabCheckout({
2979
+ cwd: opts.cwd ? String(opts.cwd) : process.cwd(),
2980
+ outputDir: opts.outputDir ? String(opts.outputDir) : null,
2981
+ appId: appId ? String(appId) : null,
2982
+ json: Boolean(opts.json),
2983
+ yes: Boolean(opts.yes || opts.nonInteractive)
2984
+ });
2985
+ if (opts.json) console.log(JSON.stringify(result, null, 2));
2986
+ });
2906
2987
  collab.command("remix <appId>").description("Create a remix/fork and materialize a new local checkout").option("--name <name>", "Optional name for the remix").option("--output-dir <path>", "Exact destination path for the new remix checkout").option("--cwd <path>", "Parent directory where the new remix checkout will be created when --output-dir is not provided").option("--yes", "Run non-interactively", false).option("--non-interactive", "Run non-interactively", false).option("--json", "Output JSON", false).action(async (appId, opts) => {
2907
2988
  const result = await collabRemix({
2908
2989
  cwd: opts.cwd ? String(opts.cwd) : process.cwd(),
@@ -2967,7 +3048,7 @@ function registerCollabCommands(program) {
2967
3048
  });
2968
3049
  if (opts.json) console.log(JSON.stringify(result, null, 2));
2969
3050
  });
2970
- collab.command("sync-upstream").description("Sync upstream changes into the current remix and update the local checkout").option("--cwd <path>", "Working directory for repository detection").option("--yes", "Run non-interactively", false).option("--non-interactive", "Run non-interactively", false).option("--json", "Output JSON", false).action(async (opts) => {
3051
+ collab.command("sync-upstream").description("Create an upstream catch-up sync for the current remix, then update the local checkout").option("--cwd <path>", "Working directory for repository detection").option("--yes", "Run non-interactively", false).option("--non-interactive", "Run non-interactively", false).option("--json", "Output JSON", false).action(async (opts) => {
2971
3052
  const result = await collabSyncUpstream({
2972
3053
  cwd: opts.cwd ? String(opts.cwd) : process.cwd(),
2973
3054
  json: Boolean(opts.json),
@@ -2975,7 +3056,7 @@ function registerCollabCommands(program) {
2975
3056
  });
2976
3057
  if (opts.json) console.log(JSON.stringify(result, null, 2));
2977
3058
  });
2978
- collab.command("request-merge").description("Open a merge request from the current remix to its upstream app").option("--yes", "Run non-interactively", false).option("--cwd <path>", "Working directory for repository detection").option("--non-interactive", "Run non-interactively", false).option("--json", "Output JSON", false).action(async (opts) => {
3059
+ collab.command("request-merge").description("Open a prompt-backed merge request from the current remix to its upstream app").option("--yes", "Run non-interactively", false).option("--cwd <path>", "Working directory for repository detection").option("--non-interactive", "Run non-interactively", false).option("--json", "Output JSON", false).action(async (opts) => {
2979
3060
  const result = await collabRequestMerge({
2980
3061
  cwd: opts.cwd ? String(opts.cwd) : process.cwd(),
2981
3062
  json: Boolean(opts.json),
@@ -3017,7 +3098,7 @@ function registerCollabCommands(program) {
3017
3098
  });
3018
3099
  if (opts.json) console.log(JSON.stringify(result, null, 2));
3019
3100
  });
3020
- collab.command("view <mrId>").description("View merge request prompts and diffs").option("--yes", "Run non-interactively", false).option("--non-interactive", "Run non-interactively", false).option("--json", "Output JSON", false).action(async (mrId, opts) => {
3101
+ collab.command("view <mrId>").description("View merge request review groups and diffs").option("--yes", "Run non-interactively", false).option("--non-interactive", "Run non-interactively", false).option("--json", "Output JSON", false).action(async (mrId, opts) => {
3021
3102
  const result = await collabView({
3022
3103
  mrId: String(mrId),
3023
3104
  json: Boolean(opts.json),
@@ -3025,7 +3106,7 @@ function registerCollabCommands(program) {
3025
3106
  });
3026
3107
  if (opts.json) console.log(JSON.stringify(result, null, 2));
3027
3108
  });
3028
- collab.command("approve <mrId>").description("Approve a merge request").option("--yes", "Run non-interactively", false).option("--non-interactive", "Run non-interactively", false).option("--remote-only", "Approve remotely and wait for merge completion without touching the local repo", false).option("--sync-target-repo", "Approve, wait for merge completion, and sync the current target repo checkout", false).option("--allow-branch-mismatch", "Allow syncing the target repo from a branch that does not match the checkout's preferred Remix branch", false).option("--json", "Output JSON", false).action(async (mrId, opts) => {
3109
+ collab.command("approve <mrId>").description("Approve a merge request or upstream sync request").option("--yes", "Run non-interactively", false).option("--non-interactive", "Run non-interactively", false).option("--remote-only", "Approve remotely and wait for merge completion without touching the local repo", false).option("--sync-target-repo", "Approve, wait for merge completion, and sync the current target repo checkout", false).option("--allow-branch-mismatch", "Allow syncing the target repo from a branch that does not match the checkout's preferred Remix branch", false).option("--json", "Output JSON", false).action(async (mrId, opts) => {
3029
3110
  const result = await collabApprove({
3030
3111
  mrId: String(mrId),
3031
3112
  cwd: process.cwd(),
@@ -3092,6 +3173,29 @@ function registerCollabCommands(program) {
3092
3173
  });
3093
3174
  if (opts.json) console.log(JSON.stringify(result, null, 2));
3094
3175
  });
3176
+ const members = collab.command("members").description("List members and update membership roles");
3177
+ members.command("list").description("List members for an organization, project, or app").option("--scope <scope>", "Membership scope (organization|project|app)", parseInviteScope, "project").option("--target-id <id>", "Explicit organization/project/app id instead of using the current repository binding").option("--cwd <path>", "Working directory for repository detection").option("--yes", "Run non-interactively", false).option("--non-interactive", "Run non-interactively", false).option("--json", "Output JSON", false).action(async (opts) => {
3178
+ const result = await collabMembersList({
3179
+ cwd: opts.cwd ? String(opts.cwd) : process.cwd(),
3180
+ scope: parseInviteScope(String(opts.scope ?? "project")),
3181
+ targetId: opts.targetId ? String(opts.targetId) : null,
3182
+ json: Boolean(opts.json),
3183
+ yes: Boolean(opts.yes || opts.nonInteractive)
3184
+ });
3185
+ if (opts.json) console.log(JSON.stringify(result, null, 2));
3186
+ });
3187
+ members.command("update <userId>").description("Update a member role for an organization, project, or app").requiredOption("--role <role>", "Role for the membership").option("--scope <scope>", "Membership scope (organization|project|app)", parseInviteScope, "project").option("--target-id <id>", "Explicit organization/project/app id instead of using the current repository binding").option("--cwd <path>", "Working directory for repository detection").option("--yes", "Run non-interactively", false).option("--non-interactive", "Run non-interactively", false).option("--json", "Output JSON", false).action(async (userId, opts) => {
3188
+ const result = await collabMembersUpdate({
3189
+ cwd: opts.cwd ? String(opts.cwd) : process.cwd(),
3190
+ scope: parseInviteScope(String(opts.scope ?? "project")),
3191
+ userId: String(userId),
3192
+ role: String(opts.role),
3193
+ targetId: opts.targetId ? String(opts.targetId) : null,
3194
+ json: Boolean(opts.json),
3195
+ yes: Boolean(opts.yes || opts.nonInteractive)
3196
+ });
3197
+ if (opts.json) console.log(JSON.stringify(result, null, 2));
3198
+ });
3095
3199
  }
3096
3200
 
3097
3201
  // src/cli.ts