@spader/dotllm 1.3.2 → 1.3.4
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/README.md +12 -0
- package/package.json +1 -1
- package/src/cli/commands/add.js +537 -30
- package/src/cli/commands/completions.js +514 -26
- package/src/cli/commands/index.js +1276 -16
- package/src/cli/commands/link.js +524 -17
- package/src/cli/commands/list.js +636 -9
- package/src/cli/commands/remove.js +493 -5
- package/src/cli/commands/sync.js +519 -12
- package/src/cli/commands/which.js +496 -8
- package/src/cli/index.js +1446 -10
- package/src/cli/layout.js +22 -6
- package/src/cli/prompt.js +0 -2
- package/src/cli/theme.js +0 -2
- package/src/cli/yargs.js +165 -8
- package/src/core/add.js +170 -14
- package/src/core/config.js +139 -115
- package/src/core/index.js +475 -13
- package/src/core/link.js +329 -3
- package/src/core/remove.js +164 -8
- package/src/core/sync.js +198 -33
- package/src/core/unlink.js +162 -6
package/src/core/sync.js
CHANGED
|
@@ -1,17 +1,166 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var
|
|
2
|
+
var __esm = (fn, res, err) => () => {
|
|
3
|
+
if (fn)
|
|
4
|
+
try {
|
|
5
|
+
res = fn(fn = 0);
|
|
6
|
+
} catch (e) {
|
|
7
|
+
err = [e];
|
|
8
|
+
}
|
|
9
|
+
if (err)
|
|
10
|
+
throw err[0];
|
|
11
|
+
return res;
|
|
12
|
+
};
|
|
3
13
|
|
|
4
|
-
// src/core/
|
|
14
|
+
// src/core/config.ts
|
|
5
15
|
import fs from "fs";
|
|
16
|
+
import os from "os";
|
|
6
17
|
import path from "path";
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
18
|
+
import { z } from "zod";
|
|
19
|
+
function readJson(filepath) {
|
|
20
|
+
if (!fs.existsSync(filepath))
|
|
21
|
+
return null;
|
|
22
|
+
const raw = fs.readFileSync(filepath, "utf-8");
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(raw);
|
|
25
|
+
} catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
var LOCAL_DIR = ".llm", LOCAL_FILE, REF_DIR, RepoEntry, GlobalShape, LocalShape, Config;
|
|
30
|
+
var init_config = __esm(() => {
|
|
31
|
+
LOCAL_FILE = path.join(LOCAL_DIR, "dotllm.json");
|
|
32
|
+
REF_DIR = path.join(LOCAL_DIR, "reference");
|
|
33
|
+
RepoEntry = z.object({
|
|
34
|
+
kind: z.enum(["url", "file"]),
|
|
35
|
+
name: z.string(),
|
|
36
|
+
uri: z.string(),
|
|
37
|
+
description: z.string()
|
|
38
|
+
});
|
|
39
|
+
GlobalShape = z.object({
|
|
40
|
+
store: z.string().optional(),
|
|
41
|
+
repos: z.array(RepoEntry)
|
|
42
|
+
});
|
|
43
|
+
LocalShape = z.object({
|
|
44
|
+
refs: z.record(z.string(), RepoEntry)
|
|
45
|
+
});
|
|
46
|
+
((Config) => {
|
|
47
|
+
function home() {
|
|
48
|
+
if (process.platform === "win32") {
|
|
49
|
+
const appData = process.env.LOCALAPPDATA ?? path.join(os.homedir(), "AppData", "Local");
|
|
50
|
+
return path.join(appData, "dotllm");
|
|
51
|
+
}
|
|
52
|
+
return path.join(process.env.HOME ?? os.homedir(), ".local", "share", "dotllm");
|
|
53
|
+
}
|
|
54
|
+
Config.home = home;
|
|
55
|
+
function storeDir() {
|
|
56
|
+
const store = Global.read().store;
|
|
57
|
+
if (!store)
|
|
58
|
+
return path.join(home(), "store");
|
|
59
|
+
return expand(store);
|
|
60
|
+
}
|
|
61
|
+
Config.storeDir = storeDir;
|
|
62
|
+
function refDir() {
|
|
63
|
+
return REF_DIR;
|
|
64
|
+
}
|
|
65
|
+
Config.refDir = refDir;
|
|
66
|
+
let Global;
|
|
67
|
+
((Global) => {
|
|
68
|
+
function read() {
|
|
69
|
+
const raw = readJson(path.join(home(), "dotllm.json"));
|
|
70
|
+
if (!raw)
|
|
71
|
+
return { repos: [] };
|
|
72
|
+
const result = GlobalShape.safeParse(raw);
|
|
73
|
+
if (!result.success)
|
|
74
|
+
return { repos: [] };
|
|
75
|
+
return result.data;
|
|
76
|
+
}
|
|
77
|
+
Global.read = read;
|
|
78
|
+
function write(config) {
|
|
79
|
+
const dir = home();
|
|
80
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
81
|
+
fs.writeFileSync(path.join(dir, "dotllm.json"), JSON.stringify(config, null, 2) + `
|
|
82
|
+
`);
|
|
83
|
+
}
|
|
84
|
+
Global.write = write;
|
|
85
|
+
function find(config, name) {
|
|
86
|
+
const lower = name.toLowerCase();
|
|
87
|
+
return config.repos.find((r) => r.name.toLowerCase() === lower);
|
|
88
|
+
}
|
|
89
|
+
Global.find = find;
|
|
90
|
+
function add(config, entry) {
|
|
91
|
+
const lower = entry.name.toLowerCase();
|
|
92
|
+
const filtered = config.repos.filter((r) => r.name.toLowerCase() !== lower);
|
|
93
|
+
return { ...config, repos: [...filtered, entry] };
|
|
94
|
+
}
|
|
95
|
+
Global.add = add;
|
|
96
|
+
function remove(config, name) {
|
|
97
|
+
const lower = name.toLowerCase();
|
|
98
|
+
return { ...config, repos: config.repos.filter((r) => r.name.toLowerCase() !== lower) };
|
|
99
|
+
}
|
|
100
|
+
Global.remove = remove;
|
|
101
|
+
})(Global = Config.Global ||= {});
|
|
102
|
+
let Local;
|
|
103
|
+
((Local) => {
|
|
104
|
+
function read() {
|
|
105
|
+
const raw = readJson(LOCAL_FILE);
|
|
106
|
+
if (!raw)
|
|
107
|
+
return { refs: {} };
|
|
108
|
+
const result = LocalShape.safeParse(raw);
|
|
109
|
+
if (!result.success)
|
|
110
|
+
return { refs: {} };
|
|
111
|
+
return result.data;
|
|
112
|
+
}
|
|
113
|
+
Local.read = read;
|
|
114
|
+
function write(config) {
|
|
115
|
+
fs.mkdirSync(LOCAL_DIR, { recursive: true });
|
|
116
|
+
fs.writeFileSync(LOCAL_FILE, JSON.stringify(config, null, 2) + `
|
|
117
|
+
`);
|
|
118
|
+
}
|
|
119
|
+
Local.write = write;
|
|
120
|
+
function find(config, name) {
|
|
121
|
+
const lower = name.toLowerCase();
|
|
122
|
+
for (const [key, value] of Object.entries(config.refs)) {
|
|
123
|
+
if (key.toLowerCase() === lower)
|
|
124
|
+
return value;
|
|
125
|
+
}
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
Local.find = find;
|
|
129
|
+
function has(config, name) {
|
|
130
|
+
return find(config, name) !== undefined;
|
|
131
|
+
}
|
|
132
|
+
Local.has = has;
|
|
133
|
+
function add(config, repo) {
|
|
134
|
+
const lower = repo.name.toLowerCase();
|
|
135
|
+
const refs = Object.fromEntries(Object.entries(config.refs).filter(([key]) => key.toLowerCase() !== lower));
|
|
136
|
+
refs[repo.name] = repo;
|
|
137
|
+
return { refs };
|
|
138
|
+
}
|
|
139
|
+
Local.add = add;
|
|
140
|
+
function remove(config, name) {
|
|
141
|
+
const lower = name.toLowerCase();
|
|
142
|
+
const refs = Object.fromEntries(Object.entries(config.refs).filter(([key]) => key.toLowerCase() !== lower));
|
|
143
|
+
return { refs };
|
|
144
|
+
}
|
|
145
|
+
Local.remove = remove;
|
|
146
|
+
})(Local = Config.Local ||= {});
|
|
147
|
+
function expand(dir) {
|
|
148
|
+
const tilde = dir === "~" || dir.startsWith("~/") || dir.startsWith("~\\");
|
|
149
|
+
if (!tilde)
|
|
150
|
+
return path.resolve(home(), dir);
|
|
151
|
+
return path.join(os.homedir(), dir.slice(1));
|
|
152
|
+
}
|
|
153
|
+
})(Config ||= {});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// src/core/sync.ts
|
|
157
|
+
import fs2 from "fs";
|
|
158
|
+
import path2 from "path";
|
|
10
159
|
function shouldPull(storeDir, force) {
|
|
11
160
|
if (force)
|
|
12
161
|
return true;
|
|
13
|
-
const head =
|
|
14
|
-
const headStat =
|
|
162
|
+
const head = path2.join(storeDir, ".git", "HEAD");
|
|
163
|
+
const headStat = fs2.statSync(head, { throwIfNoEntry: false });
|
|
15
164
|
if (!headStat)
|
|
16
165
|
return true;
|
|
17
166
|
const age = Date.now() - headStat.mtimeMs;
|
|
@@ -19,7 +168,7 @@ function shouldPull(storeDir, force) {
|
|
|
19
168
|
return false;
|
|
20
169
|
if (age > STALE_MS)
|
|
21
170
|
return true;
|
|
22
|
-
const dirStat =
|
|
171
|
+
const dirStat = fs2.statSync(storeDir, { throwIfNoEntry: false });
|
|
23
172
|
if (!dirStat)
|
|
24
173
|
return true;
|
|
25
174
|
return dirStat.atimeMs > headStat.mtimeMs;
|
|
@@ -28,20 +177,20 @@ async function pull(names, options = {}) {
|
|
|
28
177
|
const force = options.force === true;
|
|
29
178
|
const global = Config.Global.read();
|
|
30
179
|
const states = await Promise.all(names.map(async (name) => {
|
|
31
|
-
const cwd =
|
|
32
|
-
if (!
|
|
180
|
+
const cwd = path2.join(Config.refDir(), name);
|
|
181
|
+
if (!fs2.existsSync(cwd)) {
|
|
33
182
|
return { kind: "failed", name, error: "reference directory missing" };
|
|
34
183
|
}
|
|
35
184
|
const repo = Config.Global.find(global, name);
|
|
36
185
|
if (repo && repo.kind === "file") {
|
|
37
186
|
return { kind: "skipped", name };
|
|
38
187
|
}
|
|
39
|
-
const storeDir =
|
|
40
|
-
const storeStat =
|
|
188
|
+
const storeDir = path2.join(Config.storeDir(), name);
|
|
189
|
+
const storeStat = fs2.lstatSync(storeDir, { throwIfNoEntry: false });
|
|
41
190
|
if (!storeStat || storeStat.isSymbolicLink()) {
|
|
42
191
|
return { kind: "skipped", name };
|
|
43
192
|
}
|
|
44
|
-
if (!
|
|
193
|
+
if (!fs2.existsSync(path2.join(storeDir, ".git"))) {
|
|
45
194
|
return { kind: "failed", name, error: "store directory is not a git repo" };
|
|
46
195
|
}
|
|
47
196
|
if (!shouldPull(storeDir, force)) {
|
|
@@ -101,30 +250,30 @@ function sync() {
|
|
|
101
250
|
Config.Global.write(merged);
|
|
102
251
|
}
|
|
103
252
|
const refDir = Config.refDir();
|
|
104
|
-
|
|
105
|
-
|
|
253
|
+
fs2.mkdirSync(refDir, { recursive: true });
|
|
254
|
+
fs2.mkdirSync(Config.storeDir(), { recursive: true });
|
|
106
255
|
const linked = [];
|
|
107
256
|
const removed = [];
|
|
108
257
|
const missing = [];
|
|
109
258
|
const unchanged = [];
|
|
110
259
|
const wanted = new Set(Object.keys(local.refs));
|
|
111
|
-
for (const entry of
|
|
260
|
+
for (const entry of fs2.readdirSync(refDir)) {
|
|
112
261
|
if (wanted.has(entry))
|
|
113
262
|
continue;
|
|
114
|
-
const target =
|
|
115
|
-
const stat =
|
|
263
|
+
const target = path2.join(refDir, entry);
|
|
264
|
+
const stat = fs2.lstatSync(target);
|
|
116
265
|
if (stat.isSymbolicLink()) {
|
|
117
|
-
|
|
266
|
+
fs2.unlinkSync(target);
|
|
118
267
|
removed.push(entry);
|
|
119
268
|
}
|
|
120
269
|
}
|
|
121
270
|
for (const [name, repo] of Object.entries(local.refs)) {
|
|
122
|
-
const store =
|
|
123
|
-
const storeBroken = repo.kind === "url" &&
|
|
271
|
+
const store = path2.join(Config.storeDir(), name);
|
|
272
|
+
const storeBroken = repo.kind === "url" && fs2.existsSync(store) && !fs2.existsSync(path2.join(store, ".git"));
|
|
124
273
|
if (storeBroken) {
|
|
125
|
-
|
|
274
|
+
fs2.rmSync(store, { recursive: true, force: true });
|
|
126
275
|
}
|
|
127
|
-
if (!
|
|
276
|
+
if (!fs2.existsSync(store) && repo.kind === "url") {
|
|
128
277
|
const clone = Bun.spawnSync(["git", "clone", "--depth=1", repo.uri, store], {
|
|
129
278
|
stdout: "pipe",
|
|
130
279
|
stderr: "pipe"
|
|
@@ -134,32 +283,48 @@ function sync() {
|
|
|
134
283
|
continue;
|
|
135
284
|
}
|
|
136
285
|
}
|
|
137
|
-
if (!
|
|
138
|
-
if (!
|
|
286
|
+
if (!fs2.existsSync(store) && repo.kind === "file") {
|
|
287
|
+
if (!fs2.existsSync(repo.uri)) {
|
|
139
288
|
missing.push(name);
|
|
140
289
|
continue;
|
|
141
290
|
}
|
|
142
|
-
if (!
|
|
291
|
+
if (!fs2.statSync(repo.uri).isDirectory()) {
|
|
143
292
|
missing.push(name);
|
|
144
293
|
continue;
|
|
145
294
|
}
|
|
146
|
-
|
|
295
|
+
fs2.symlinkSync(repo.uri, store, "dir");
|
|
147
296
|
}
|
|
148
|
-
if (!
|
|
297
|
+
if (!fs2.existsSync(store)) {
|
|
149
298
|
missing.push(name);
|
|
150
299
|
continue;
|
|
151
300
|
}
|
|
152
|
-
const target =
|
|
153
|
-
|
|
301
|
+
const target = path2.join(refDir, name);
|
|
302
|
+
const stat = fs2.lstatSync(target, { throwIfNoEntry: false });
|
|
303
|
+
if (stat && !stat.isSymbolicLink()) {
|
|
154
304
|
unchanged.push(name);
|
|
155
305
|
continue;
|
|
156
306
|
}
|
|
157
|
-
|
|
307
|
+
if (stat && fs2.readlinkSync(target) === store) {
|
|
308
|
+
unchanged.push(name);
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
if (stat) {
|
|
312
|
+
fs2.unlinkSync(target);
|
|
313
|
+
}
|
|
314
|
+
fs2.symlinkSync(store, target, "dir");
|
|
158
315
|
linked.push(name);
|
|
159
316
|
}
|
|
160
317
|
return { linked, removed, missing, unchanged };
|
|
161
318
|
}
|
|
319
|
+
var FRESH_MS, STALE_MS;
|
|
320
|
+
var init_sync = __esm(() => {
|
|
321
|
+
init_config();
|
|
322
|
+
FRESH_MS = 24 * 60 * 60 * 1000;
|
|
323
|
+
STALE_MS = 7 * FRESH_MS;
|
|
324
|
+
});
|
|
325
|
+
init_sync();
|
|
326
|
+
|
|
162
327
|
export {
|
|
163
|
-
|
|
164
|
-
|
|
328
|
+
pull,
|
|
329
|
+
sync
|
|
165
330
|
};
|
package/src/core/unlink.js
CHANGED
|
@@ -1,23 +1,179 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var
|
|
2
|
+
var __esm = (fn, res, err) => () => {
|
|
3
|
+
if (fn)
|
|
4
|
+
try {
|
|
5
|
+
res = fn(fn = 0);
|
|
6
|
+
} catch (e) {
|
|
7
|
+
err = [e];
|
|
8
|
+
}
|
|
9
|
+
if (err)
|
|
10
|
+
throw err[0];
|
|
11
|
+
return res;
|
|
12
|
+
};
|
|
3
13
|
|
|
4
|
-
// src/core/
|
|
14
|
+
// src/core/config.ts
|
|
5
15
|
import fs from "fs";
|
|
16
|
+
import os from "os";
|
|
6
17
|
import path from "path";
|
|
7
|
-
import {
|
|
18
|
+
import { z } from "zod";
|
|
19
|
+
function readJson(filepath) {
|
|
20
|
+
if (!fs.existsSync(filepath))
|
|
21
|
+
return null;
|
|
22
|
+
const raw = fs.readFileSync(filepath, "utf-8");
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(raw);
|
|
25
|
+
} catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
var LOCAL_DIR = ".llm", LOCAL_FILE, REF_DIR, RepoEntry, GlobalShape, LocalShape, Config;
|
|
30
|
+
var init_config = __esm(() => {
|
|
31
|
+
LOCAL_FILE = path.join(LOCAL_DIR, "dotllm.json");
|
|
32
|
+
REF_DIR = path.join(LOCAL_DIR, "reference");
|
|
33
|
+
RepoEntry = z.object({
|
|
34
|
+
kind: z.enum(["url", "file"]),
|
|
35
|
+
name: z.string(),
|
|
36
|
+
uri: z.string(),
|
|
37
|
+
description: z.string()
|
|
38
|
+
});
|
|
39
|
+
GlobalShape = z.object({
|
|
40
|
+
store: z.string().optional(),
|
|
41
|
+
repos: z.array(RepoEntry)
|
|
42
|
+
});
|
|
43
|
+
LocalShape = z.object({
|
|
44
|
+
refs: z.record(z.string(), RepoEntry)
|
|
45
|
+
});
|
|
46
|
+
((Config) => {
|
|
47
|
+
function home() {
|
|
48
|
+
if (process.platform === "win32") {
|
|
49
|
+
const appData = process.env.LOCALAPPDATA ?? path.join(os.homedir(), "AppData", "Local");
|
|
50
|
+
return path.join(appData, "dotllm");
|
|
51
|
+
}
|
|
52
|
+
return path.join(process.env.HOME ?? os.homedir(), ".local", "share", "dotllm");
|
|
53
|
+
}
|
|
54
|
+
Config.home = home;
|
|
55
|
+
function storeDir() {
|
|
56
|
+
const store = Global.read().store;
|
|
57
|
+
if (!store)
|
|
58
|
+
return path.join(home(), "store");
|
|
59
|
+
return expand(store);
|
|
60
|
+
}
|
|
61
|
+
Config.storeDir = storeDir;
|
|
62
|
+
function refDir() {
|
|
63
|
+
return REF_DIR;
|
|
64
|
+
}
|
|
65
|
+
Config.refDir = refDir;
|
|
66
|
+
let Global;
|
|
67
|
+
((Global) => {
|
|
68
|
+
function read() {
|
|
69
|
+
const raw = readJson(path.join(home(), "dotllm.json"));
|
|
70
|
+
if (!raw)
|
|
71
|
+
return { repos: [] };
|
|
72
|
+
const result = GlobalShape.safeParse(raw);
|
|
73
|
+
if (!result.success)
|
|
74
|
+
return { repos: [] };
|
|
75
|
+
return result.data;
|
|
76
|
+
}
|
|
77
|
+
Global.read = read;
|
|
78
|
+
function write(config) {
|
|
79
|
+
const dir = home();
|
|
80
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
81
|
+
fs.writeFileSync(path.join(dir, "dotllm.json"), JSON.stringify(config, null, 2) + `
|
|
82
|
+
`);
|
|
83
|
+
}
|
|
84
|
+
Global.write = write;
|
|
85
|
+
function find(config, name) {
|
|
86
|
+
const lower = name.toLowerCase();
|
|
87
|
+
return config.repos.find((r) => r.name.toLowerCase() === lower);
|
|
88
|
+
}
|
|
89
|
+
Global.find = find;
|
|
90
|
+
function add(config, entry) {
|
|
91
|
+
const lower = entry.name.toLowerCase();
|
|
92
|
+
const filtered = config.repos.filter((r) => r.name.toLowerCase() !== lower);
|
|
93
|
+
return { ...config, repos: [...filtered, entry] };
|
|
94
|
+
}
|
|
95
|
+
Global.add = add;
|
|
96
|
+
function remove(config, name) {
|
|
97
|
+
const lower = name.toLowerCase();
|
|
98
|
+
return { ...config, repos: config.repos.filter((r) => r.name.toLowerCase() !== lower) };
|
|
99
|
+
}
|
|
100
|
+
Global.remove = remove;
|
|
101
|
+
})(Global = Config.Global ||= {});
|
|
102
|
+
let Local;
|
|
103
|
+
((Local) => {
|
|
104
|
+
function read() {
|
|
105
|
+
const raw = readJson(LOCAL_FILE);
|
|
106
|
+
if (!raw)
|
|
107
|
+
return { refs: {} };
|
|
108
|
+
const result = LocalShape.safeParse(raw);
|
|
109
|
+
if (!result.success)
|
|
110
|
+
return { refs: {} };
|
|
111
|
+
return result.data;
|
|
112
|
+
}
|
|
113
|
+
Local.read = read;
|
|
114
|
+
function write(config) {
|
|
115
|
+
fs.mkdirSync(LOCAL_DIR, { recursive: true });
|
|
116
|
+
fs.writeFileSync(LOCAL_FILE, JSON.stringify(config, null, 2) + `
|
|
117
|
+
`);
|
|
118
|
+
}
|
|
119
|
+
Local.write = write;
|
|
120
|
+
function find(config, name) {
|
|
121
|
+
const lower = name.toLowerCase();
|
|
122
|
+
for (const [key, value] of Object.entries(config.refs)) {
|
|
123
|
+
if (key.toLowerCase() === lower)
|
|
124
|
+
return value;
|
|
125
|
+
}
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
Local.find = find;
|
|
129
|
+
function has(config, name) {
|
|
130
|
+
return find(config, name) !== undefined;
|
|
131
|
+
}
|
|
132
|
+
Local.has = has;
|
|
133
|
+
function add(config, repo) {
|
|
134
|
+
const lower = repo.name.toLowerCase();
|
|
135
|
+
const refs = Object.fromEntries(Object.entries(config.refs).filter(([key]) => key.toLowerCase() !== lower));
|
|
136
|
+
refs[repo.name] = repo;
|
|
137
|
+
return { refs };
|
|
138
|
+
}
|
|
139
|
+
Local.add = add;
|
|
140
|
+
function remove(config, name) {
|
|
141
|
+
const lower = name.toLowerCase();
|
|
142
|
+
const refs = Object.fromEntries(Object.entries(config.refs).filter(([key]) => key.toLowerCase() !== lower));
|
|
143
|
+
return { refs };
|
|
144
|
+
}
|
|
145
|
+
Local.remove = remove;
|
|
146
|
+
})(Local = Config.Local ||= {});
|
|
147
|
+
function expand(dir) {
|
|
148
|
+
const tilde = dir === "~" || dir.startsWith("~/") || dir.startsWith("~\\");
|
|
149
|
+
if (!tilde)
|
|
150
|
+
return path.resolve(home(), dir);
|
|
151
|
+
return path.join(os.homedir(), dir.slice(1));
|
|
152
|
+
}
|
|
153
|
+
})(Config ||= {});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// src/core/unlink.ts
|
|
157
|
+
import fs2 from "fs";
|
|
158
|
+
import path2 from "path";
|
|
8
159
|
function unlink(name) {
|
|
9
160
|
const local = Config.Local.read();
|
|
10
161
|
const found = Config.Local.find(local, name);
|
|
11
162
|
if (!found) {
|
|
12
163
|
return { ok: false, error: `"${name}" is not linked in local config` };
|
|
13
164
|
}
|
|
14
|
-
const target =
|
|
15
|
-
if (
|
|
16
|
-
|
|
165
|
+
const target = path2.join(Config.refDir(), found.name);
|
|
166
|
+
if (fs2.lstatSync(target, { throwIfNoEntry: false })) {
|
|
167
|
+
fs2.unlinkSync(target);
|
|
17
168
|
}
|
|
18
169
|
Config.Local.write(Config.Local.remove(local, found.name));
|
|
19
170
|
return { ok: true };
|
|
20
171
|
}
|
|
172
|
+
var init_unlink = __esm(() => {
|
|
173
|
+
init_config();
|
|
174
|
+
});
|
|
175
|
+
init_unlink();
|
|
176
|
+
|
|
21
177
|
export {
|
|
22
178
|
unlink
|
|
23
179
|
};
|