@uniformdev/cli 20.31.1-alpha.0 → 20.31.1-alpha.1

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/index.mjs +110 -141
  2. package/package.json +9 -9
package/dist/index.mjs CHANGED
@@ -31,7 +31,7 @@ import yargs from "yargs";
31
31
 
32
32
  // src/commands/ai/commands/mcp/install.ts
33
33
  import { blue, green as green2, red as red3, yellow as yellow2 } from "colorette";
34
- import { existsSync as existsSync3, readFileSync, writeFileSync } from "fs";
34
+ import { existsSync as existsSync2, readFileSync, writeFileSync } from "fs";
35
35
  import inquirer4 from "inquirer";
36
36
  import { join as join3 } from "path";
37
37
 
@@ -272,6 +272,28 @@ var createClient = (baseUrl, authToken) => {
272
272
  };
273
273
  };
274
274
 
275
+ // src/fs.ts
276
+ import { promises as fs } from "fs";
277
+ async function readJSON(path6) {
278
+ const fileContents = await fs.readFile(path6, "utf-8");
279
+ return JSON.parse(fileContents);
280
+ }
281
+ async function tryReadJSON(path6, missingValue = null) {
282
+ try {
283
+ const stat = await fs.stat(path6);
284
+ return stat.isFile() ? await readJSON(path6) : missingValue;
285
+ } catch {
286
+ return missingValue;
287
+ }
288
+ }
289
+ async function ensureDirectoryExists(dirPath) {
290
+ try {
291
+ await fs.access(dirPath);
292
+ } catch {
293
+ await fs.mkdir(dirPath, { recursive: true });
294
+ }
295
+ }
296
+
275
297
  // src/spinner.ts
276
298
  import ora from "ora";
277
299
  var makeSpinner = () => {
@@ -357,7 +379,7 @@ import { extname, join } from "path";
357
379
  // src/util.ts
358
380
  import { cosmiconfigSync } from "cosmiconfig";
359
381
  import { TypeScriptLoader } from "cosmiconfig-typescript-loader";
360
- import fs from "fs";
382
+ import fs2 from "fs";
361
383
  var omit = (object, keys) => {
362
384
  const result = keys.reduce((current, key) => {
363
385
  const { [key]: _, ...rest } = current;
@@ -379,7 +401,7 @@ var loadConfig = (configPath) => {
379
401
  });
380
402
  let loadedConfig;
381
403
  if (configPath) {
382
- if (!fs.existsSync(configPath)) {
404
+ if (!fs2.existsSync(configPath)) {
383
405
  throw new Error(
384
406
  `Invalid --config file path: ${configPath}. File does not exist.
385
407
 
@@ -491,9 +513,9 @@ ${e?.message}`));
491
513
  }
492
514
 
493
515
  // src/sync/package.ts
494
- import fs2 from "fs";
516
+ import fs3 from "fs";
495
517
  function readUniformPackage(filename, assertExists) {
496
- if (!assertExists && !fs2.existsSync(filename)) {
518
+ if (!assertExists && !fs3.existsSync(filename)) {
497
519
  return {};
498
520
  }
499
521
  const packageContents = readFileToObject(filename);
@@ -1050,81 +1072,13 @@ var Telemetry = class {
1050
1072
  // src/commands/ai/lib/agentUtils.ts
1051
1073
  import inquirer3 from "inquirer";
1052
1074
  import * as path from "path";
1053
-
1054
- // src/commands/ai/lib/directoryUtils.ts
1055
- import { promises as fs3 } from "fs";
1056
- import { existsSync as existsSync2, mkdirSync as mkdirSync2 } from "fs";
1057
- async function directoryExists(dirPath) {
1058
- try {
1059
- const stats = await fs3.stat(dirPath);
1060
- return stats.isDirectory();
1061
- } catch (error) {
1062
- console.error(error);
1063
- return false;
1064
- }
1065
- }
1066
- async function ensureDirectoryExists(dirPath) {
1067
- try {
1068
- await fs3.access(dirPath);
1069
- } catch {
1070
- await fs3.mkdir(dirPath, { recursive: true });
1071
- }
1072
- }
1073
- function ensureDirectoryExistsSync(dirPath) {
1074
- if (!existsSync2(dirPath)) {
1075
- mkdirSync2(dirPath, { recursive: true });
1076
- }
1077
- }
1078
-
1079
- // src/commands/ai/lib/agentUtils.ts
1080
- function detectAgent() {
1081
- if (process.env.CURSOR || process.env.CURSOR_USER || process.argv[0]?.includes("cursor")) {
1082
- return {
1083
- type: "cursor",
1084
- confidence: "high",
1085
- detected: true
1086
- };
1087
- }
1088
- if (process.env.CLAUDE_DESKTOP || process.argv[0]?.includes("claude")) {
1089
- return {
1090
- type: "claude",
1091
- confidence: "high",
1092
- detected: true
1093
- };
1094
- }
1095
- return {
1096
- type: "unknown",
1097
- confidence: "low",
1098
- detected: false
1099
- };
1100
- }
1101
1075
  async function detectOrSelectAgent(agentOption, options = {}) {
1102
1076
  const { allowInteractive = true } = options;
1103
1077
  if (agentOption && agentOption !== "auto") {
1104
1078
  return agentOption;
1105
1079
  }
1106
- const detectionResult = detectAgent();
1107
- if (allowInteractive && detectionResult.type === "unknown") {
1108
- const hasCursorDir = await directoryExists(".cursor");
1109
- if (hasCursorDir) {
1110
- const { useDetected } = await inquirer3.prompt([
1111
- {
1112
- type: "confirm",
1113
- name: "useDetected",
1114
- message: "Detected Cursor project. Install for Cursor?",
1115
- default: true
1116
- }
1117
- ]);
1118
- if (useDetected) {
1119
- return "cursor";
1120
- }
1121
- }
1122
- }
1123
- if (detectionResult.confidence === "high") {
1124
- return detectionResult.type;
1125
- }
1126
1080
  if (!allowInteractive) {
1127
- return detectionResult.type;
1081
+ throw new Error("Agent type must be specified when running in non-interactive mode. Use --agent flag.");
1128
1082
  }
1129
1083
  const { agentType } = await inquirer3.prompt([
1130
1084
  {
@@ -1133,7 +1087,7 @@ async function detectOrSelectAgent(agentOption, options = {}) {
1133
1087
  message: "Which AI development assistant are you using?",
1134
1088
  choices: [
1135
1089
  { name: "Cursor", value: "cursor" },
1136
- { name: "Claude Code", value: "claude" },
1090
+ { name: "Claude Desktop", value: "claude" },
1137
1091
  { name: "Other AI assistant", value: "other" }
1138
1092
  ]
1139
1093
  }
@@ -1158,7 +1112,6 @@ function getRulesDirectory(agentType, customDir) {
1158
1112
  };
1159
1113
  case "claude":
1160
1114
  case "other":
1161
- case "unknown":
1162
1115
  default:
1163
1116
  return {
1164
1117
  path: path.join(currentDir, "rules"),
@@ -1189,7 +1142,6 @@ function getMcpDirectory(agentType, customDir) {
1189
1142
  isCustom: false
1190
1143
  };
1191
1144
  case "other":
1192
- case "unknown":
1193
1145
  default:
1194
1146
  return {
1195
1147
  path: process.cwd(),
@@ -1215,7 +1167,7 @@ function createUniformMcpServer(apiKey, projectId, apiHost) {
1215
1167
  };
1216
1168
  }
1217
1169
  function readOrCreateMcpConfig(mcpConfigPath) {
1218
- if (existsSync3(mcpConfigPath)) {
1170
+ if (existsSync2(mcpConfigPath)) {
1219
1171
  try {
1220
1172
  const existingConfig = readFileSync(mcpConfigPath, "utf8");
1221
1173
  return JSON.parse(existingConfig);
@@ -1273,14 +1225,13 @@ async function chooseProject(user, teamId, explicitProjectId) {
1273
1225
  }
1274
1226
  var InstallMcpCommand = {
1275
1227
  command: "install",
1276
- describe: "Install Uniform MCP server configuration",
1228
+ describe: "Install Uniform MCP server configuration (use --team, --project, and --apiKey for non-interactive mode)",
1277
1229
  builder: (yargs38) => withConfiguration(
1278
1230
  yargs38.option("agent", {
1279
1231
  alias: "a",
1280
- describe: "Specify agent type (cursor, claude, auto)",
1232
+ describe: "Specify agent type (cursor, claude, other)",
1281
1233
  type: "string",
1282
- default: "auto",
1283
- choices: ["cursor", "claude", "auto"]
1234
+ choices: ["cursor", "claude", "other"]
1284
1235
  }).option("directory", {
1285
1236
  alias: "d",
1286
1237
  describe: "Custom installation directory for mcp.json",
@@ -1298,47 +1249,76 @@ var InstallMcpCommand = {
1298
1249
  default: apiHostDefault,
1299
1250
  demandOption: true,
1300
1251
  type: "string"
1252
+ }).option("apiKey", {
1253
+ describe: "Uniform API key with write access rights (skips API key generation)",
1254
+ type: "string"
1301
1255
  })
1302
1256
  ),
1303
1257
  handler: async function(argv) {
1304
- const { agent, directory, project, team, apiHost } = argv;
1258
+ const { agent, directory, project, team, apiHost, apiKey } = argv;
1305
1259
  const { stopAllSpinners, spin } = makeSpinner();
1306
1260
  const telemetry = new Telemetry("mcp");
1307
1261
  try {
1308
1262
  console.log(blue("\n\u{1F680} Welcome to Uniform MCP Server Installer\n"));
1309
- const auth = await getBearerToken(apiHost);
1310
- const { authToken } = auth;
1311
- const uniformClient = createClient(apiHost, authToken);
1312
- let done = await spin("Fetching user information...");
1313
- const user = await fetchUserAndEnsureFirstTeamExists({
1314
- auth,
1315
- baseUrl: apiHost,
1316
- spin,
1317
- telemetry
1318
- });
1319
- await done();
1320
- let teamId = team;
1321
- if (!teamId) {
1322
- const teamResult = await chooseTeam(
1323
- user,
1324
- `Hey ${user.name}! Choose a Uniform team for MCP integration`,
1263
+ const isNonInteractive = team && project && apiKey;
1264
+ let teamId;
1265
+ let projectId;
1266
+ let projectName;
1267
+ let writeApiKey;
1268
+ let user = null;
1269
+ if (isNonInteractive) {
1270
+ console.log(yellow2("Running in non-interactive mode"));
1271
+ teamId = team;
1272
+ projectId = project;
1273
+ projectName = `Project ${projectId}`;
1274
+ writeApiKey = apiKey;
1275
+ } else {
1276
+ console.log(yellow2("Running in interactive mode teamId and projectId are ignored"));
1277
+ const auth = await getBearerToken(apiHost);
1278
+ const { authToken } = auth;
1279
+ const uniformClient = createClient(apiHost, authToken);
1280
+ let done2 = await spin("Fetching user information...");
1281
+ user = await fetchUserAndEnsureFirstTeamExists({
1282
+ auth,
1283
+ baseUrl: apiHost,
1284
+ spin,
1325
1285
  telemetry
1326
- );
1327
- teamId = teamResult.teamId;
1286
+ });
1287
+ await done2();
1288
+ teamId = team || "";
1289
+ if (!teamId) {
1290
+ const teamResult = await chooseTeam(
1291
+ user,
1292
+ `Hey ${user.name}! Choose a Uniform team for MCP integration`,
1293
+ telemetry
1294
+ );
1295
+ teamId = teamResult.teamId;
1296
+ }
1297
+ const projectSelection = await chooseProject(user, teamId, project);
1298
+ projectId = projectSelection.projectId;
1299
+ projectName = projectSelection.projectName;
1300
+ if (apiKey) {
1301
+ writeApiKey = apiKey;
1302
+ console.log(yellow2("Using provided API key"));
1303
+ } else {
1304
+ done2 = await spin("Generating API keys...");
1305
+ const apiKeyResponse = await uniformClient.createApiKeys(teamId, projectId);
1306
+ writeApiKey = apiKeyResponse.writeApiKey;
1307
+ await done2();
1308
+ }
1328
1309
  }
1329
- const { projectId, projectName } = await chooseProject(user, teamId, project);
1330
- done = await spin("Generating API keys...");
1331
- const { writeApiKey } = await uniformClient.createApiKeys(teamId, projectId);
1332
- await done();
1333
- const detectionResult = detectAgent();
1334
- const agentType = agent === "auto" || !agent ? detectionResult.type : agent;
1310
+ const agentType = await detectOrSelectAgent(agent, {
1311
+ allowInteractive: !isNonInteractive
1312
+ });
1335
1313
  const directoryConfig = getMcpDirectory(agentType, directory);
1336
1314
  const mcpDirectory = directoryConfig.path;
1337
1315
  console.log(yellow2(`
1338
- Detected agent: ${agentType}`));
1316
+ Selected agent: ${agentType}`));
1339
1317
  console.log(yellow2(`Installing MCP configuration to: ${mcpDirectory}
1340
1318
  `));
1341
- ensureDirectoryExistsSync(mcpDirectory);
1319
+ let done = await spin("Creating directory if needed...");
1320
+ await ensureDirectoryExists(mcpDirectory);
1321
+ await done();
1342
1322
  const mcpConfigPath = join3(mcpDirectory, "mcp.json");
1343
1323
  done = await spin("Reading existing MCP configuration...");
1344
1324
  const existingConfig = readOrCreateMcpConfig(mcpConfigPath);
@@ -1359,7 +1339,11 @@ Detected agent: ${agentType}`));
1359
1339
  }
1360
1340
  }
1361
1341
  console.log(`\u{1F4C1} Configuration file: ${mcpConfigPath}`);
1362
- console.log(`\u{1F3E2} Team: ${user.teams.find((t) => t.team.id === teamId)?.team.name}`);
1342
+ if (isNonInteractive) {
1343
+ console.log(`\u{1F3E2} Team ID: ${teamId}`);
1344
+ } else {
1345
+ console.log(`\u{1F3E2} Team: ${user.teams.find((t) => t.team.id === teamId)?.team.name}`);
1346
+ }
1363
1347
  console.log(`\u{1F4E6} Project: ${projectName} (${projectId})`);
1364
1348
  if (agentType === "cursor") {
1365
1349
  console.log(blue("\n\u{1F4CB} Next steps for Cursor:"));
@@ -1378,7 +1362,9 @@ Detected agent: ${agentType}`));
1378
1362
  agent: agentType,
1379
1363
  projectId,
1380
1364
  teamId,
1381
- customDirectory: directory ? "true" : "false"
1365
+ customDirectory: directory ? "true" : "false",
1366
+ customApiKey: apiKey ? "true" : "false",
1367
+ nonInteractive: isNonInteractive ? "true" : "false"
1382
1368
  });
1383
1369
  stopAllSpinners();
1384
1370
  process.exit(0);
@@ -1717,7 +1703,7 @@ var InstallRulesCommand = {
1717
1703
  alias: "a",
1718
1704
  describe: "Specify agent type (cursor, claude, other)",
1719
1705
  type: "string",
1720
- default: "auto"
1706
+ choices: ["cursor", "claude", "other"]
1721
1707
  }).option("directory", {
1722
1708
  alias: "d",
1723
1709
  describe: "Custom installation directory",
@@ -1730,7 +1716,7 @@ var InstallRulesCommand = {
1730
1716
  console.log(blue3("\n\u{1F680} Welcome to Uniform AI Rules Installer\n"));
1731
1717
  await installRules(
1732
1718
  {
1733
- agent: agent === "auto" ? void 0 : agent,
1719
+ agent,
1734
1720
  directory
1735
1721
  },
1736
1722
  spin
@@ -9928,7 +9914,7 @@ Installing project dependencies...
9928
9914
  }
9929
9915
 
9930
9916
  // src/projects/getOrCreateProject.ts
9931
- import fs6, { existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
9917
+ import fs6, { existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
9932
9918
  import inquirer6 from "inquirer";
9933
9919
  import path4 from "path";
9934
9920
  import slugify from "slugify";
@@ -10051,8 +10037,8 @@ function validateProjectName(projectName, checkTargetDir, explicitTargetDir) {
10051
10037
  }
10052
10038
  if (checkTargetDir) {
10053
10039
  let targetDir = explicitTargetDir ?? process.cwd();
10054
- if (!existsSync4(targetDir)) {
10055
- mkdirSync3(targetDir, { recursive: true });
10040
+ if (!existsSync3(targetDir)) {
10041
+ mkdirSync2(targetDir, { recursive: true });
10056
10042
  }
10057
10043
  if (fs6.readdirSync(targetDir).length > 0) {
10058
10044
  targetDir = path4.resolve(targetDir, projectNameSlug);
@@ -10223,7 +10209,7 @@ npm run dev
10223
10209
  }
10224
10210
 
10225
10211
  // src/commands/new/commands/new-mesh-integration.ts
10226
- import { existsSync as existsSync5, mkdirSync as mkdirSync4, readdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
10212
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
10227
10213
  import inquirer8 from "inquirer";
10228
10214
  import path5 from "path";
10229
10215
  import slugify2 from "slugify";
@@ -10272,7 +10258,7 @@ async function newMeshIntegrationHandler({
10272
10258
  });
10273
10259
  let done = await spin("Registering integration to team...");
10274
10260
  const pathToManifest = path5.resolve(targetDir, "mesh-manifest.json");
10275
- if (!existsSync5(pathToManifest)) {
10261
+ if (!existsSync4(pathToManifest)) {
10276
10262
  throw new Error("Invalid integration starter cloned: missing `mesh-manifest.json`");
10277
10263
  }
10278
10264
  const manifestContents = readFileSync3(pathToManifest, "utf-8");
@@ -10326,12 +10312,12 @@ function validateIntegrationName(integrationName, explicitOutputPath) {
10326
10312
  throw new Error("Integration name cannot be shorter than 6 characters.");
10327
10313
  }
10328
10314
  let targetDir = explicitOutputPath ?? process.cwd();
10329
- if (!existsSync5(targetDir)) {
10330
- mkdirSync4(targetDir, { recursive: true });
10315
+ if (!existsSync4(targetDir)) {
10316
+ mkdirSync3(targetDir, { recursive: true });
10331
10317
  }
10332
10318
  if (readdirSync(targetDir).length > 0) {
10333
10319
  targetDir = path5.resolve(targetDir, typeSlug);
10334
- if (existsSync5(targetDir)) {
10320
+ if (existsSync4(targetDir)) {
10335
10321
  throw new Error(`${targetDir} directory already exists, choose a different name.`);
10336
10322
  }
10337
10323
  }
@@ -11822,7 +11808,7 @@ var SyncCommand = {
11822
11808
  import { bold as bold3, gray as gray6, green as green7 } from "colorette";
11823
11809
 
11824
11810
  // src/updateCheck.ts
11825
- import { existsSync as existsSync6, promises as fs7 } from "fs";
11811
+ import { existsSync as existsSync5, promises as fs7 } from "fs";
11826
11812
  import { get as getHttp } from "http";
11827
11813
  import { get as getHttps } from "https";
11828
11814
  import { tmpdir } from "os";
@@ -11834,7 +11820,7 @@ var encode = (value) => encodeURIComponent(value).replace(/^%40/, "@");
11834
11820
  var getFile = async (details, distTag) => {
11835
11821
  const rootDir = tmpdir();
11836
11822
  const subDir = join10(rootDir, "update-check");
11837
- if (!existsSync6(subDir)) {
11823
+ if (!existsSync5(subDir)) {
11838
11824
  await fs7.mkdir(subDir);
11839
11825
  }
11840
11826
  let name = `${details.name}-${distTag}.json`;
@@ -11844,7 +11830,7 @@ var getFile = async (details, distTag) => {
11844
11830
  return join10(subDir, name);
11845
11831
  };
11846
11832
  var evaluateCache = async (file, time, interval) => {
11847
- if (existsSync6(file)) {
11833
+ if (existsSync5(file)) {
11848
11834
  const content = await fs7.readFile(file, "utf8");
11849
11835
  const { lastUpdate, latest } = JSON.parse(content);
11850
11836
  const nextCheck = lastUpdate + interval;
@@ -11997,23 +11983,6 @@ var checkForUpdateMiddleware = async ({ verbose }) => {
11997
11983
  // src/middleware/checkLocalDepsVersionsMiddleware.ts
11998
11984
  import { magenta, red as red8 } from "colorette";
11999
11985
  import { join as join11 } from "path";
12000
-
12001
- // src/fs.ts
12002
- import { promises as fs8 } from "fs";
12003
- async function readJSON(path6) {
12004
- const fileContents = await fs8.readFile(path6, "utf-8");
12005
- return JSON.parse(fileContents);
12006
- }
12007
- async function tryReadJSON(path6, missingValue = null) {
12008
- try {
12009
- const stat = await fs8.stat(path6);
12010
- return stat.isFile() ? await readJSON(path6) : missingValue;
12011
- } catch {
12012
- return missingValue;
12013
- }
12014
- }
12015
-
12016
- // src/middleware/checkLocalDepsVersionsMiddleware.ts
12017
11986
  var uniformStrictVersions = [
12018
11987
  "@uniformdev/canvas",
12019
11988
  "@uniformdev/canvas-next",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniformdev/cli",
3
- "version": "20.31.1-alpha.0+7a19e04af6",
3
+ "version": "20.31.1-alpha.1+b3b021f551",
4
4
  "description": "Uniform command line interface tool",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "main": "./cli.js",
@@ -27,13 +27,13 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "@thi.ng/mime": "^2.2.23",
30
- "@uniformdev/assets": "20.31.1-alpha.0+7a19e04af6",
31
- "@uniformdev/canvas": "20.31.1-alpha.0+7a19e04af6",
32
- "@uniformdev/context": "20.31.1-alpha.0+7a19e04af6",
33
- "@uniformdev/files": "20.31.1-alpha.0+7a19e04af6",
34
- "@uniformdev/project-map": "20.31.1-alpha.0+7a19e04af6",
35
- "@uniformdev/redirect": "20.31.1-alpha.0+7a19e04af6",
36
- "@uniformdev/richtext": "20.31.1-alpha.0+7a19e04af6",
30
+ "@uniformdev/assets": "20.31.1-alpha.1+b3b021f551",
31
+ "@uniformdev/canvas": "20.31.1-alpha.1+b3b021f551",
32
+ "@uniformdev/context": "20.31.1-alpha.1+b3b021f551",
33
+ "@uniformdev/files": "20.31.1-alpha.1+b3b021f551",
34
+ "@uniformdev/project-map": "20.31.1-alpha.1+b3b021f551",
35
+ "@uniformdev/redirect": "20.31.1-alpha.1+b3b021f551",
36
+ "@uniformdev/richtext": "20.31.1-alpha.1+b3b021f551",
37
37
  "call-bind": "^1.0.2",
38
38
  "colorette": "2.0.20",
39
39
  "cosmiconfig": "9.0.0",
@@ -80,5 +80,5 @@
80
80
  "publishConfig": {
81
81
  "access": "public"
82
82
  },
83
- "gitHead": "7a19e04af69e2c0699440eaa4e602cd171530f63"
83
+ "gitHead": "b3b021f551f35362f521966890475a86353ee1f3"
84
84
  }