@liangmi/mo 1.0.0 → 1.0.2

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 (3) hide show
  1. package/README.md +13 -0
  2. package/dist/mo.mjs +75 -27
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -47,8 +47,21 @@ mo setup
47
47
 
48
48
  `mo cd`, `mo edit`, and `mo open` open an interactive selector when called without arguments.
49
49
 
50
+ > [!TIP]
51
+ > If you are using `mo` with VS Code based editors, you can add this line to your editor config to prevent `mo edit` popping up a new separated window.
52
+ >
53
+ > ```json
54
+ > "window.openFoldersInNewWindow": "off"
55
+ > ```
56
+ >
57
+ > Setting `code -r` as your editor in `mo setup` have the same effect as well.
58
+
50
59
  ## Config
51
60
 
61
+ The config file should be generated by running `mo setup`. Modifying `~/.config/morc.json` manually is not recommended.
62
+
63
+ Please follow the [config_schema.json](./config_schema.json) if you are developing `mo`.
64
+
52
65
  `~/.config/morc.json`:
53
66
 
54
67
  ```json
package/dist/mo.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { n as __require, r as __toESM, t as __commonJSMin } from "./chunk-CBBoxR_p.mjs";
2
2
  import { C as untildify, S as parseAliasInput, _ as require_picocolors, a as ensureToolReady, b as defaultAliases, c as getDefaultConfigPath, d as error, f as icons, g as toTildePath, h as success, i as preventRunning, l as loadConfig, m as stopSpinner, n as getRestartFlagPath, o as runCommand, p as startSpinner, r as innerBinName, s as R, t as checkRestartRequired, u as supportedShells, v as aliasCommands, w as cac, x as getAliasPromptLabel } from "./runner-DW0Q4OMK.mjs";
3
3
  import * as fs$1 from "node:fs";
4
- import fs, { existsSync, mkdirSync, readdirSync, statSync, writeFileSync } from "node:fs";
4
+ import fs, { existsSync, mkdirSync, readdirSync, rmSync, rmdirSync, statSync, writeFileSync } from "node:fs";
5
5
  import os, { tmpdir } from "node:os";
6
6
  import path from "node:path";
7
7
  import { execFileSync, spawnSync } from "node:child_process";
@@ -13,7 +13,7 @@ import { Buffer as Buffer$1 } from "node:buffer";
13
13
  import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
14
14
  import prompts from "prompts";
15
15
  //#region package.json
16
- var version = "1.0.0";
16
+ var version = "1.0.2";
17
17
  //#endregion
18
18
  //#region src/commands/clone.ts
19
19
  var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
@@ -21,8 +21,9 @@ async function runCloneCommand(repo, config) {
21
21
  const parsedRepo = parseRepo(repo);
22
22
  const ownerDir = path.join(config.root, parsedRepo.owner);
23
23
  const targetDir = path.join(ownerDir, parsedRepo.name);
24
+ const ownerExisted = existsSync(ownerDir);
24
25
  if (existsSync(targetDir)) error(`Repository already exists at ${import_picocolors.default.cyan(toTildePath(targetDir))}`);
25
- mkdirSync(ownerDir, { recursive: true });
26
+ if (!ownerExisted) mkdirSync(ownerDir, { recursive: true });
26
27
  const cloneUrl = `https://github.com/${parsedRepo.owner}/${parsedRepo.name}.git`;
27
28
  const spinner = startSpinner(`Cloning ${import_picocolors.default.bold(`${parsedRepo.owner}/${parsedRepo.name}`)}...`);
28
29
  try {
@@ -32,10 +33,20 @@ async function runCloneCommand(repo, config) {
32
33
  console.log(` ${import_picocolors.default.dim("→")} ${import_picocolors.default.cyan(toTildePath(targetDir))}`);
33
34
  } catch (err) {
34
35
  stopSpinner(spinner);
36
+ cleanupFailedClone(targetDir, ownerDir, ownerExisted);
35
37
  const details = err instanceof Error ? `: ${err.message}` : "";
36
38
  error(`Git clone failed for ${parsedRepo.owner}/${parsedRepo.name}${details}`);
37
39
  }
38
40
  }
41
+ function cleanupFailedClone(targetDir, ownerDir, ownerExisted) {
42
+ try {
43
+ if (existsSync(targetDir)) rmSync(targetDir, {
44
+ recursive: true,
45
+ force: true
46
+ });
47
+ if (!ownerExisted && existsSync(ownerDir) && readdirSync(ownerDir).length === 0) rmdirSync(ownerDir);
48
+ } catch {}
49
+ }
39
50
  async function runGitClone(url, targetDir) {
40
51
  const result = await R("git", [
41
52
  "clone",
@@ -25187,6 +25198,53 @@ const useInput = (inputHandler, options = {}) => {
25187
25198
  ]);
25188
25199
  };
25189
25200
  //#endregion
25201
+ //#region src/utils/search.ts
25202
+ function getMatchScore(text, query) {
25203
+ const normalizedText = text.toLowerCase();
25204
+ const normalizedQuery = query.trim().toLowerCase();
25205
+ if (!normalizedQuery) return null;
25206
+ if (!normalizedText.includes(normalizedQuery)) return null;
25207
+ if (normalizedText === normalizedQuery) return 0;
25208
+ if (normalizedText.startsWith(normalizedQuery)) return 1;
25209
+ return 2;
25210
+ }
25211
+ function searchReposByName(query, groups) {
25212
+ const matches = [];
25213
+ for (const group of groups) for (const repo of group.repos) {
25214
+ const score = getMatchScore(repo.name, query);
25215
+ if (score === null) continue;
25216
+ matches.push({
25217
+ repo,
25218
+ score
25219
+ });
25220
+ }
25221
+ matches.sort((a, b) => {
25222
+ if (a.score !== b.score) return a.score - b.score;
25223
+ if (a.repo.name.length !== b.repo.name.length) return a.repo.name.length - b.repo.name.length;
25224
+ const byName = a.repo.name.localeCompare(b.repo.name);
25225
+ if (byName !== 0) return byName;
25226
+ return a.repo.owner.localeCompare(b.repo.owner);
25227
+ });
25228
+ return matches;
25229
+ }
25230
+ function searchOwnerGroupsByName(query, groups) {
25231
+ const matches = [];
25232
+ for (const group of groups) {
25233
+ const score = getMatchScore(group.owner, query);
25234
+ if (score === null) continue;
25235
+ matches.push({
25236
+ group,
25237
+ score
25238
+ });
25239
+ }
25240
+ matches.sort((a, b) => {
25241
+ if (a.score !== b.score) return a.score - b.score;
25242
+ if (a.group.owner.length !== b.group.owner.length) return a.group.owner.length - b.group.owner.length;
25243
+ return a.group.owner.localeCompare(b.group.owner);
25244
+ });
25245
+ return matches.map((match) => match.group);
25246
+ }
25247
+ //#endregion
25190
25248
  //#region node_modules/.pnpm/react@19.2.4/node_modules/react/cjs/react-jsx-runtime.production.js
25191
25249
  /**
25192
25250
  * @license React
@@ -25464,28 +25522,17 @@ function buildListItems(root, groups) {
25464
25522
  function searchItems(query, groups, root) {
25465
25523
  const q = query.toLowerCase();
25466
25524
  const items = [];
25467
- const matchedOwners = /* @__PURE__ */ new Set();
25468
- const projectMatches = [];
25469
- for (const group of groups) for (const repo of group.repos) {
25470
- const name = repo.name.toLowerCase();
25471
- if (!name.includes(q)) continue;
25472
- const score = name === q ? 0 : name.startsWith(q) ? 1 : 2;
25473
- projectMatches.push({
25474
- score,
25475
- item: {
25476
- type: "project",
25477
- label: repo.name,
25478
- owner: repo.owner,
25479
- path: repo.path,
25480
- selectable: true
25481
- }
25482
- });
25483
- matchedOwners.add(repo.owner);
25484
- }
25485
- projectMatches.sort((a, b) => a.score - b.score || a.item.label.length - b.item.label.length);
25486
- const sortedProjects = projectMatches.map((m) => m.item);
25525
+ const projectMatches = searchReposByName(query, groups);
25526
+ const sortedProjects = projectMatches.map((match) => ({
25527
+ type: "project",
25528
+ label: match.repo.name,
25529
+ owner: match.repo.owner,
25530
+ path: match.repo.path,
25531
+ selectable: true
25532
+ }));
25533
+ const matchedOwners = new Set(projectMatches.map((match) => match.repo.owner));
25487
25534
  if ("<root>".includes(q)) {
25488
- const rootScore = "<root>" === q ? 0 : "<root>".startsWith(q) ? 1 : 2;
25535
+ const rootScore = getMatchScore("<root>", query) ?? 3;
25489
25536
  const rootItem = {
25490
25537
  type: "project",
25491
25538
  label: "<root>",
@@ -25824,9 +25871,10 @@ function resolveTarget(root, target, groups) {
25824
25871
  const candidate = path.join(root, ...segments);
25825
25872
  if (existsSync(candidate) && statSync(candidate).isDirectory()) return candidate;
25826
25873
  }
25827
- const q = target.toLowerCase();
25828
- for (const group of groups) for (const repo of group.repos) if (repo.name.toLowerCase().includes(q)) return repo.path;
25829
- for (const group of groups) if (group.owner.toLowerCase().includes(q)) return group.path;
25874
+ const repoMatches = searchReposByName(target, groups);
25875
+ if (repoMatches.length) return repoMatches[0].repo.path;
25876
+ const ownerMatches = searchOwnerGroupsByName(target, groups);
25877
+ if (ownerMatches.length) return ownerMatches[0].path;
25830
25878
  return null;
25831
25879
  }
25832
25880
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liangmi/mo",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Manage your open source projects",
5
5
  "homepage": "https://github.com/liangmiQwQ/mo#readme",
6
6
  "bugs": {