@keywaysh/cli 0.1.6 → 0.1.7

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 (2) hide show
  1. package/dist/cli.js +84 -29
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -101,7 +101,7 @@ var INTERNAL_POSTHOG_HOST = "https://eu.i.posthog.com";
101
101
  // package.json
102
102
  var package_default = {
103
103
  name: "@keywaysh/cli",
104
- version: "0.1.6",
104
+ version: "0.1.7",
105
105
  description: "One link to all your secrets",
106
106
  type: "module",
107
107
  bin: {
@@ -444,6 +444,29 @@ async function getSyncStatus(accessToken, repoFullName, connectionId, projectId,
444
444
  const wrapped = await handleResponse(response);
445
445
  return wrapped.data;
446
446
  }
447
+ async function getSyncDiff(accessToken, repoFullName, options) {
448
+ const [owner, repo] = repoFullName.split("/");
449
+ const params = new URLSearchParams({
450
+ connectionId: options.connectionId,
451
+ projectId: options.projectId,
452
+ keywayEnvironment: options.keywayEnvironment || "production",
453
+ providerEnvironment: options.providerEnvironment || "production"
454
+ });
455
+ const response = await fetchWithTimeout(
456
+ `${API_BASE_URL}/v1/integrations/vaults/${owner}/${repo}/sync/diff?${params}`,
457
+ {
458
+ method: "GET",
459
+ headers: {
460
+ "User-Agent": USER_AGENT,
461
+ Authorization: `Bearer ${accessToken}`
462
+ }
463
+ },
464
+ 6e4
465
+ // 60 seconds
466
+ );
467
+ const wrapped = await handleResponse(response);
468
+ return wrapped.data;
469
+ }
447
470
  async function getSyncPreview(accessToken, repoFullName, options) {
448
471
  const [owner, repo] = repoFullName.split("/");
449
472
  const params = new URLSearchParams({
@@ -1087,6 +1110,9 @@ async function pushCommand(options) {
1087
1110
  let environment = options.env;
1088
1111
  let envFile = options.file;
1089
1112
  const candidates = discoverEnvCandidates(process.cwd());
1113
+ if (candidates.length === 0 && !envFile) {
1114
+ throw new Error("No .env file found. Create a .env file first, or use --file <path> to specify one.");
1115
+ }
1090
1116
  if (environment && !envFile) {
1091
1117
  const match = candidates.find((c) => c.env === environment);
1092
1118
  if (match) {
@@ -1145,34 +1171,9 @@ async function pushCommand(options) {
1145
1171
  if (!envFile) {
1146
1172
  envFile = ".env";
1147
1173
  }
1148
- let envFilePath = path4.resolve(process.cwd(), envFile);
1174
+ const envFilePath = path4.resolve(process.cwd(), envFile);
1149
1175
  if (!fs4.existsSync(envFilePath)) {
1150
- if (!isInteractive2) {
1151
- throw new Error(`File not found: ${envFile}. Provide --file <path> or run interactively to choose a file.`);
1152
- }
1153
- const { newPath } = await prompts3(
1154
- {
1155
- type: "text",
1156
- name: "newPath",
1157
- message: `File not found: ${envFile}. Enter an env file path to use:`,
1158
- validate: (value) => {
1159
- if (!value || typeof value !== "string") return "Path is required";
1160
- const resolved = path4.resolve(process.cwd(), value);
1161
- if (!fs4.existsSync(resolved)) return `File not found: ${value}`;
1162
- return true;
1163
- }
1164
- },
1165
- {
1166
- onCancel: () => {
1167
- throw new Error("Push cancelled (no env file provided).");
1168
- }
1169
- }
1170
- );
1171
- if (!newPath || typeof newPath !== "string") {
1172
- throw new Error("Push cancelled (no env file provided).");
1173
- }
1174
- envFile = newPath.trim();
1175
- envFilePath = path4.resolve(process.cwd(), envFile);
1176
+ throw new Error(`File not found: ${envFile}`);
1176
1177
  }
1177
1178
  const content = fs4.readFileSync(envFilePath, "utf-8");
1178
1179
  if (content.trim().length === 0) {
@@ -1231,7 +1232,9 @@ async function pushCommand(options) {
1231
1232
  }
1232
1233
  console.log(`
1233
1234
  Your secrets are now encrypted and stored securely.`);
1234
- console.log(`To retrieve them, run: ${pc5.cyan(`keyway pull --env ${environment}`)}`);
1235
+ const dashboardLink = `https://www.keyway.sh/dashboard/vaults/${repoFullName}`;
1236
+ console.log(`
1237
+ ${pc5.blue("\u2394")} Dashboard: ${pc5.underline(dashboardLink)}`);
1235
1238
  await shutdownAnalytics();
1236
1239
  } catch (error) {
1237
1240
  let message;
@@ -2136,6 +2139,42 @@ function mapToProviderEnvironment(provider, keywayEnv) {
2136
2139
  return keywayEnv;
2137
2140
  }
2138
2141
  }
2142
+ function displayDiffSummary(diff, providerName) {
2143
+ const totalDiff = diff.onlyInKeyway.length + diff.onlyInProvider.length + diff.different.length;
2144
+ if (totalDiff === 0 && diff.same.length > 0) {
2145
+ console.log(pc10.green(`
2146
+ \u2713 Already in sync (${diff.same.length} secrets)`));
2147
+ return;
2148
+ }
2149
+ console.log(pc10.blue("\n\u{1F4CA} Comparison Summary\n"));
2150
+ console.log(pc10.gray(` Keyway: ${diff.keywayCount} secrets | ${providerName}: ${diff.providerCount} secrets
2151
+ `));
2152
+ if (diff.onlyInKeyway.length > 0) {
2153
+ console.log(pc10.cyan(` \u2192 ${diff.onlyInKeyway.length} only in Keyway`));
2154
+ diff.onlyInKeyway.slice(0, 3).forEach((key) => console.log(pc10.gray(` ${key}`)));
2155
+ if (diff.onlyInKeyway.length > 3) {
2156
+ console.log(pc10.gray(` ... and ${diff.onlyInKeyway.length - 3} more`));
2157
+ }
2158
+ }
2159
+ if (diff.onlyInProvider.length > 0) {
2160
+ console.log(pc10.magenta(` \u2190 ${diff.onlyInProvider.length} only in ${providerName}`));
2161
+ diff.onlyInProvider.slice(0, 3).forEach((key) => console.log(pc10.gray(` ${key}`)));
2162
+ if (diff.onlyInProvider.length > 3) {
2163
+ console.log(pc10.gray(` ... and ${diff.onlyInProvider.length - 3} more`));
2164
+ }
2165
+ }
2166
+ if (diff.different.length > 0) {
2167
+ console.log(pc10.yellow(` \u2260 ${diff.different.length} with different values`));
2168
+ diff.different.slice(0, 3).forEach((key) => console.log(pc10.gray(` ${key}`)));
2169
+ if (diff.different.length > 3) {
2170
+ console.log(pc10.gray(` ... and ${diff.different.length - 3} more`));
2171
+ }
2172
+ }
2173
+ if (diff.same.length > 0) {
2174
+ console.log(pc10.gray(` = ${diff.same.length} identical`));
2175
+ }
2176
+ console.log("");
2177
+ }
2139
2178
  function findMatchingProject(projects, repoFullName) {
2140
2179
  const repoFullNameLower = repoFullName.toLowerCase();
2141
2180
  const repoName = repoFullName.split("/")[1]?.toLowerCase();
@@ -2369,6 +2408,22 @@ Connection to ${providerDisplayName} failed.`));
2369
2408
  providerEnv = mapToProviderEnvironment(provider, keywayEnv);
2370
2409
  }
2371
2410
  }
2411
+ if (needsDirectionPrompt) {
2412
+ const effectiveKeywayEnv = keywayEnv || "production";
2413
+ const effectiveProviderEnv = providerEnv || mapToProviderEnvironment(provider, effectiveKeywayEnv);
2414
+ console.log(pc10.gray("\nComparing secrets..."));
2415
+ const diff = await getSyncDiff(accessToken, repoFullName, {
2416
+ connectionId: connection.id,
2417
+ projectId: selectedProject.id,
2418
+ keywayEnvironment: effectiveKeywayEnv,
2419
+ providerEnvironment: effectiveProviderEnv
2420
+ });
2421
+ displayDiffSummary(diff, providerName);
2422
+ const totalDiff = diff.onlyInKeyway.length + diff.onlyInProvider.length + diff.different.length;
2423
+ if (totalDiff === 0) {
2424
+ return;
2425
+ }
2426
+ }
2372
2427
  if (needsDirectionPrompt) {
2373
2428
  const { selectedDirection } = await prompts7({
2374
2429
  type: "select",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keywaysh/cli",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "One link to all your secrets",
5
5
  "type": "module",
6
6
  "bin": {