skillmux 0.1.4 → 0.1.5
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/{chunk-EEIOA7GC.js → chunk-OY3C7VIL.js} +209 -102
- package/dist/chunk-OY3C7VIL.js.map +1 -0
- package/dist/{chunk-6TMTFWDX.js → chunk-R5V2WOZV.js} +4 -4
- package/dist/chunk-R5V2WOZV.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/index.js +2 -2
- package/dist/{launch-tui-IC7COEGE.js → launch-tui-4TJFQA3L.js} +3 -2
- package/dist/launch-tui-4TJFQA3L.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-6TMTFWDX.js.map +0 -1
- package/dist/chunk-EEIOA7GC.js.map +0 -1
- package/dist/launch-tui-IC7COEGE.js.map +0 -1
|
@@ -59,8 +59,8 @@ var defaultAgentRuleMap = Object.fromEntries(
|
|
|
59
59
|
);
|
|
60
60
|
|
|
61
61
|
// src/commands/adopt.ts
|
|
62
|
-
import { homedir } from "os";
|
|
63
|
-
import { join as
|
|
62
|
+
import { homedir as homedir2 } from "os";
|
|
63
|
+
import { join as join8, resolve as resolve8 } from "path";
|
|
64
64
|
|
|
65
65
|
// src/core/errors.ts
|
|
66
66
|
var SkillMuxError = class extends Error {
|
|
@@ -119,8 +119,13 @@ function resolveSkillmuxHome(homeDir) {
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
// src/discovery/discover-agents.ts
|
|
122
|
-
import * as
|
|
123
|
-
import { join as
|
|
122
|
+
import * as fs3 from "fs/promises";
|
|
123
|
+
import { join as join3, resolve as resolve2 } from "path";
|
|
124
|
+
|
|
125
|
+
// src/config/auto-register-agents.ts
|
|
126
|
+
import { readdirSync, statSync } from "fs";
|
|
127
|
+
import { homedir } from "os";
|
|
128
|
+
import { join as join2 } from "path";
|
|
124
129
|
|
|
125
130
|
// src/config/load-user-config.ts
|
|
126
131
|
import * as fs from "fs/promises";
|
|
@@ -131,16 +136,27 @@ var agentOverrideSchema = z.object({
|
|
|
131
136
|
supportedPlatforms: z.array(supportedPlatformSchema).min(1).optional(),
|
|
132
137
|
homeRelativeRootPath: z.string().min(1).optional(),
|
|
133
138
|
skillsDirectoryPath: z.string().min(1).optional(),
|
|
134
|
-
enabledByDefault: z.boolean().optional()
|
|
139
|
+
enabledByDefault: z.boolean().optional(),
|
|
140
|
+
autoDiscovered: z.literal(true).optional()
|
|
135
141
|
}).strict();
|
|
136
142
|
var userConfigSchema = z.object({
|
|
137
143
|
version: z.literal(1),
|
|
138
|
-
agents: z.record(z.string().min(1), agentOverrideSchema)
|
|
144
|
+
agents: z.record(z.string().min(1), agentOverrideSchema),
|
|
145
|
+
autoDiscover: z.object({
|
|
146
|
+
lastRunAt: z.string().nullable(),
|
|
147
|
+
intervalMs: z.number().int().nonnegative()
|
|
148
|
+
}).optional(),
|
|
149
|
+
removedAutoAgentIds: z.array(z.string().min(1)).optional()
|
|
139
150
|
}).strict();
|
|
140
151
|
function createEmptyUserConfig() {
|
|
141
152
|
return {
|
|
142
153
|
version: 1,
|
|
143
|
-
agents: {}
|
|
154
|
+
agents: {},
|
|
155
|
+
autoDiscover: {
|
|
156
|
+
lastRunAt: null,
|
|
157
|
+
intervalMs: 36e5
|
|
158
|
+
},
|
|
159
|
+
removedAutoAgentIds: []
|
|
144
160
|
};
|
|
145
161
|
}
|
|
146
162
|
function stripUtf8Bom(contents) {
|
|
@@ -177,6 +193,101 @@ async function loadUserConfig(skillmuxHome) {
|
|
|
177
193
|
}
|
|
178
194
|
}
|
|
179
195
|
|
|
196
|
+
// src/config/write-user-config.ts
|
|
197
|
+
import * as fs2 from "fs/promises";
|
|
198
|
+
async function writeUserConfig(skillmuxHome, config) {
|
|
199
|
+
const configPath = buildConfigPath(skillmuxHome);
|
|
200
|
+
await fs2.mkdir(skillmuxHome, { recursive: true });
|
|
201
|
+
await fs2.writeFile(configPath, `${JSON.stringify(config, null, 2)}
|
|
202
|
+
`, "utf8");
|
|
203
|
+
return {
|
|
204
|
+
skillmuxHome,
|
|
205
|
+
configPath
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// src/config/auto-register-agents.ts
|
|
210
|
+
function isDotDir(name) {
|
|
211
|
+
return name.startsWith(".");
|
|
212
|
+
}
|
|
213
|
+
function isValidAgentId(name) {
|
|
214
|
+
if (name.length < 2) return false;
|
|
215
|
+
const stem = name.slice(1);
|
|
216
|
+
return /^[a-z][a-z0-9-]*$/u.test(stem);
|
|
217
|
+
}
|
|
218
|
+
function dirExists(dirPath) {
|
|
219
|
+
try {
|
|
220
|
+
return statSync(dirPath).isDirectory();
|
|
221
|
+
} catch {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
function isBuiltInAgentId(id) {
|
|
226
|
+
return builtInAgentIds.includes(id);
|
|
227
|
+
}
|
|
228
|
+
function makeAutoDiscoveredOverride(dirName) {
|
|
229
|
+
const stem = dirName.slice(1);
|
|
230
|
+
return {
|
|
231
|
+
stableName: stem.charAt(0).toUpperCase() + stem.slice(1),
|
|
232
|
+
supportedPlatforms: ["win32", "linux", "darwin"],
|
|
233
|
+
homeRelativeRootPath: dirName,
|
|
234
|
+
skillsDirectoryPath: "skills",
|
|
235
|
+
enabledByDefault: true,
|
|
236
|
+
autoDiscovered: true
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
async function autoRegisterNewAgents(homeDir) {
|
|
240
|
+
const resolvedHomeDir = homeDir ?? homedir();
|
|
241
|
+
const { skillmuxHome } = resolveSkillmuxHome(resolvedHomeDir);
|
|
242
|
+
const config = await loadUserConfig(skillmuxHome);
|
|
243
|
+
const autoDiscover = config.autoDiscover ?? {
|
|
244
|
+
lastRunAt: null,
|
|
245
|
+
intervalMs: 36e5
|
|
246
|
+
};
|
|
247
|
+
if (autoDiscover.lastRunAt !== null && autoDiscover.intervalMs > 0) {
|
|
248
|
+
const elapsed = Date.now() - new Date(autoDiscover.lastRunAt).getTime();
|
|
249
|
+
if (elapsed < autoDiscover.intervalMs) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
const wellKnownNonAgentDirs = /* @__PURE__ */ new Set([".skillmux"]);
|
|
254
|
+
const removedIds = new Set(config.removedAutoAgentIds ?? []);
|
|
255
|
+
let changed = false;
|
|
256
|
+
let entries;
|
|
257
|
+
try {
|
|
258
|
+
entries = readdirSync(resolvedHomeDir);
|
|
259
|
+
} catch {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
const nextAgents = { ...config.agents };
|
|
263
|
+
for (const name of entries) {
|
|
264
|
+
if (!isDotDir(name)) continue;
|
|
265
|
+
if (wellKnownNonAgentDirs.has(name)) continue;
|
|
266
|
+
if (!isValidAgentId(name)) continue;
|
|
267
|
+
const agentId = name.slice(1).toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
268
|
+
if (agentId in nextAgents) continue;
|
|
269
|
+
if (isBuiltInAgentId(agentId)) continue;
|
|
270
|
+
if (removedIds.has(agentId)) continue;
|
|
271
|
+
const skillsDir = join2(resolvedHomeDir, name, "skills");
|
|
272
|
+
if (!dirExists(skillsDir)) continue;
|
|
273
|
+
nextAgents[agentId] = makeAutoDiscoveredOverride(name);
|
|
274
|
+
changed = true;
|
|
275
|
+
}
|
|
276
|
+
if (!changed && autoDiscover.lastRunAt !== null) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const nextConfig = {
|
|
280
|
+
...config,
|
|
281
|
+
agents: nextAgents,
|
|
282
|
+
autoDiscover: {
|
|
283
|
+
...autoDiscover,
|
|
284
|
+
lastRunAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
285
|
+
},
|
|
286
|
+
removedAutoAgentIds: [...removedIds]
|
|
287
|
+
};
|
|
288
|
+
await writeUserConfig(skillmuxHome, nextConfig);
|
|
289
|
+
}
|
|
290
|
+
|
|
180
291
|
// src/discovery/discover-agents.ts
|
|
181
292
|
function mergeRule(rule, override) {
|
|
182
293
|
if (override === void 0) {
|
|
@@ -205,7 +316,7 @@ function buildCustomRule(id, override) {
|
|
|
205
316
|
}
|
|
206
317
|
async function pathExists(path) {
|
|
207
318
|
try {
|
|
208
|
-
await
|
|
319
|
+
await fs3.access(path);
|
|
209
320
|
return true;
|
|
210
321
|
} catch {
|
|
211
322
|
return false;
|
|
@@ -215,7 +326,7 @@ function resolveAgentRulePaths(homeDir, rule) {
|
|
|
215
326
|
const absoluteRootPath = resolve2(homeDir, rule.homeRelativeRootPath);
|
|
216
327
|
return {
|
|
217
328
|
absoluteRootPath,
|
|
218
|
-
absoluteSkillsDirectoryPath:
|
|
329
|
+
absoluteSkillsDirectoryPath: join3(
|
|
219
330
|
absoluteRootPath,
|
|
220
331
|
rule.skillsDirectoryPath
|
|
221
332
|
)
|
|
@@ -225,6 +336,7 @@ async function discoverAgents(options) {
|
|
|
225
336
|
const platform = options.platform ?? process.platform;
|
|
226
337
|
const homeDir = resolve2(options.homeDir);
|
|
227
338
|
const skillmuxHome = options.skillmuxHome ?? resolveSkillmuxHome(homeDir).skillmuxHome;
|
|
339
|
+
await autoRegisterNewAgents(homeDir);
|
|
228
340
|
const userConfig = await loadUserConfig(skillmuxHome);
|
|
229
341
|
const discoveredAgents = [];
|
|
230
342
|
for (const agentId of builtInAgentIds) {
|
|
@@ -254,22 +366,23 @@ async function discoverAgents(options) {
|
|
|
254
366
|
exists: await pathExists(resolvedPaths.absoluteSkillsDirectoryPath),
|
|
255
367
|
supportedOnPlatform: customRule.supportedPlatforms.some(
|
|
256
368
|
(supportedPlatform) => supportedPlatform === platform
|
|
257
|
-
)
|
|
369
|
+
),
|
|
370
|
+
autoDiscovered: override.autoDiscovered === true || void 0
|
|
258
371
|
});
|
|
259
372
|
}
|
|
260
373
|
return discoveredAgents;
|
|
261
374
|
}
|
|
262
375
|
|
|
263
376
|
// src/discovery/scan-agent-skills.ts
|
|
264
|
-
import * as
|
|
265
|
-
import { join as
|
|
377
|
+
import * as fs6 from "fs/promises";
|
|
378
|
+
import { join as join4 } from "path";
|
|
266
379
|
|
|
267
380
|
// src/discovery/infer-skill-entry.ts
|
|
268
|
-
import * as
|
|
381
|
+
import * as fs5 from "fs/promises";
|
|
269
382
|
import { basename, resolve as resolve4 } from "path";
|
|
270
383
|
|
|
271
384
|
// src/fs/path-utils.ts
|
|
272
|
-
import * as
|
|
385
|
+
import * as fs4 from "fs/promises";
|
|
273
386
|
import { dirname, parse, relative, resolve as resolve3, sep } from "path";
|
|
274
387
|
function normalizeAbsolutePath(path) {
|
|
275
388
|
const normalized = resolve3(path);
|
|
@@ -300,7 +413,7 @@ async function assertNoSymlinkAncestors(path, options) {
|
|
|
300
413
|
let current = options?.includeLeaf === true ? resolve3(path) : dirname(resolve3(path));
|
|
301
414
|
while (true) {
|
|
302
415
|
try {
|
|
303
|
-
const entry = await
|
|
416
|
+
const entry = await fs4.lstat(current);
|
|
304
417
|
if (entry.isSymbolicLink()) {
|
|
305
418
|
throw new Error(`Refusing to use path with symlink ancestor at ${current}`);
|
|
306
419
|
}
|
|
@@ -324,10 +437,10 @@ function buildIssue(code, severity, message, path) {
|
|
|
324
437
|
async function inferSkillEntry(options) {
|
|
325
438
|
const absolutePath = resolve4(options.path);
|
|
326
439
|
const skillName = basename(absolutePath);
|
|
327
|
-
const stats = await
|
|
440
|
+
const stats = await fs5.lstat(absolutePath);
|
|
328
441
|
if (stats.isSymbolicLink()) {
|
|
329
442
|
try {
|
|
330
|
-
const targetPath = await
|
|
443
|
+
const targetPath = await fs5.realpath(absolutePath);
|
|
331
444
|
if (isPathInside(options.skillmuxHome, targetPath)) {
|
|
332
445
|
return {
|
|
333
446
|
entry: {
|
|
@@ -407,7 +520,7 @@ async function scanAgentSkills(agent, skillmuxHome) {
|
|
|
407
520
|
issues: []
|
|
408
521
|
};
|
|
409
522
|
}
|
|
410
|
-
const directoryEntries = await
|
|
523
|
+
const directoryEntries = await fs6.readdir(agent.absoluteSkillsDirectoryPath, {
|
|
411
524
|
withFileTypes: true
|
|
412
525
|
});
|
|
413
526
|
const sortedDirectoryEntries = [...directoryEntries].sort(
|
|
@@ -419,7 +532,7 @@ async function scanAgentSkills(agent, skillmuxHome) {
|
|
|
419
532
|
const result = await inferSkillEntry({
|
|
420
533
|
agentId: agent.id,
|
|
421
534
|
agentName: agent.stableName,
|
|
422
|
-
path:
|
|
535
|
+
path: join4(agent.absoluteSkillsDirectoryPath, directoryEntry.name),
|
|
423
536
|
skillmuxHome
|
|
424
537
|
});
|
|
425
538
|
entries.push(result.entry);
|
|
@@ -434,23 +547,23 @@ async function scanAgentSkills(agent, skillmuxHome) {
|
|
|
434
547
|
}
|
|
435
548
|
|
|
436
549
|
// src/fs/safe-copy.ts
|
|
437
|
-
import * as
|
|
438
|
-
import { dirname as dirname2, join as
|
|
550
|
+
import * as fs7 from "fs/promises";
|
|
551
|
+
import { dirname as dirname2, join as join5, resolve as resolve5 } from "path";
|
|
439
552
|
async function assertDirectory(path) {
|
|
440
|
-
const entry = await
|
|
553
|
+
const entry = await fs7.lstat(path);
|
|
441
554
|
if (!entry.isDirectory()) {
|
|
442
555
|
throw new Error(`Expected a directory at ${path}`);
|
|
443
556
|
}
|
|
444
557
|
}
|
|
445
558
|
async function assertRegularFile(path, label) {
|
|
446
|
-
const entry = await
|
|
559
|
+
const entry = await fs7.lstat(path);
|
|
447
560
|
if (!entry.isFile()) {
|
|
448
561
|
throw new Error(`Expected ${label} to be a regular file at ${path}`);
|
|
449
562
|
}
|
|
450
563
|
}
|
|
451
564
|
async function assertTargetDoesNotExist(path) {
|
|
452
565
|
try {
|
|
453
|
-
await
|
|
566
|
+
await fs7.lstat(path);
|
|
454
567
|
throw new Error(`Refusing to overwrite existing path at ${path}`);
|
|
455
568
|
} catch (error) {
|
|
456
569
|
if (error.code !== "ENOENT") {
|
|
@@ -459,12 +572,12 @@ async function assertTargetDoesNotExist(path) {
|
|
|
459
572
|
}
|
|
460
573
|
}
|
|
461
574
|
async function copyDirectoryContents(sourcePath, targetPath) {
|
|
462
|
-
await
|
|
463
|
-
const entries = await
|
|
575
|
+
await fs7.mkdir(targetPath, { recursive: true });
|
|
576
|
+
const entries = await fs7.readdir(sourcePath, { withFileTypes: true });
|
|
464
577
|
for (const entry of entries) {
|
|
465
|
-
const sourceEntryPath =
|
|
466
|
-
const targetEntryPath =
|
|
467
|
-
const entryStats = await
|
|
578
|
+
const sourceEntryPath = join5(sourcePath, entry.name);
|
|
579
|
+
const targetEntryPath = join5(targetPath, entry.name);
|
|
580
|
+
const entryStats = await fs7.lstat(sourceEntryPath);
|
|
468
581
|
if (entryStats.isSymbolicLink()) {
|
|
469
582
|
throw new Error(`Refusing to copy source symlink at ${sourceEntryPath}`);
|
|
470
583
|
}
|
|
@@ -473,8 +586,8 @@ async function copyDirectoryContents(sourcePath, targetPath) {
|
|
|
473
586
|
continue;
|
|
474
587
|
}
|
|
475
588
|
if (entryStats.isFile()) {
|
|
476
|
-
await
|
|
477
|
-
await
|
|
589
|
+
await fs7.mkdir(dirname2(targetEntryPath), { recursive: true });
|
|
590
|
+
await fs7.copyFile(sourceEntryPath, targetEntryPath);
|
|
478
591
|
continue;
|
|
479
592
|
}
|
|
480
593
|
throw new Error(`Unsupported filesystem entry at ${sourceEntryPath}`);
|
|
@@ -482,7 +595,7 @@ async function copyDirectoryContents(sourcePath, targetPath) {
|
|
|
482
595
|
}
|
|
483
596
|
async function assertSkillSourceLayout(sourcePath) {
|
|
484
597
|
const resolvedSourcePath = resolve5(sourcePath);
|
|
485
|
-
const skillFilePath =
|
|
598
|
+
const skillFilePath = join5(resolvedSourcePath, "SKILL.md");
|
|
486
599
|
await assertNoSymlinkAncestors(resolvedSourcePath, { includeLeaf: true });
|
|
487
600
|
await assertDirectory(resolvedSourcePath);
|
|
488
601
|
try {
|
|
@@ -496,7 +609,7 @@ async function assertSkillSourceLayout(sourcePath) {
|
|
|
496
609
|
}
|
|
497
610
|
async function hasRootSkillFile(sourcePath) {
|
|
498
611
|
const resolvedSourcePath = resolve5(sourcePath);
|
|
499
|
-
const skillFilePath =
|
|
612
|
+
const skillFilePath = join5(resolvedSourcePath, "SKILL.md");
|
|
500
613
|
try {
|
|
501
614
|
await assertDirectory(resolvedSourcePath);
|
|
502
615
|
await assertRegularFile(skillFilePath, "SKILL.md");
|
|
@@ -550,7 +663,7 @@ var BatchOperationError = class extends Error {
|
|
|
550
663
|
};
|
|
551
664
|
|
|
552
665
|
// src/fs/link-ops.ts
|
|
553
|
-
import * as
|
|
666
|
+
import * as fs8 from "fs/promises";
|
|
554
667
|
import { dirname as dirname3, resolve as resolve6 } from "path";
|
|
555
668
|
var directoryLinkType = process.platform === "win32" ? "junction" : "dir";
|
|
556
669
|
async function createManagedLink(linkPath, targetPath) {
|
|
@@ -558,25 +671,25 @@ async function createManagedLink(linkPath, targetPath) {
|
|
|
558
671
|
const resolvedTargetPath = resolve6(targetPath);
|
|
559
672
|
await assertNoSymlinkAncestors(resolvedLinkPath);
|
|
560
673
|
await assertNoSymlinkAncestors(resolvedTargetPath, { includeLeaf: true });
|
|
561
|
-
await
|
|
674
|
+
await fs8.mkdir(dirname3(resolvedLinkPath), { recursive: true });
|
|
562
675
|
try {
|
|
563
|
-
const existingEntry = await
|
|
676
|
+
const existingEntry = await fs8.lstat(resolvedLinkPath);
|
|
564
677
|
if (!existingEntry.isSymbolicLink()) {
|
|
565
678
|
throw new Error(`Refusing to replace non-link entry at ${resolvedLinkPath}`);
|
|
566
679
|
}
|
|
567
|
-
const currentTargetPath = await
|
|
680
|
+
const currentTargetPath = await fs8.realpath(resolvedLinkPath);
|
|
568
681
|
if (pathsAreEqual(currentTargetPath, resolvedTargetPath)) {
|
|
569
682
|
return;
|
|
570
683
|
}
|
|
571
684
|
throw new Error(`Refusing to replace link at ${resolvedLinkPath}`);
|
|
572
685
|
} catch (error) {
|
|
573
|
-
if (error.code === "ENOENT" && await
|
|
574
|
-
await
|
|
686
|
+
if (error.code === "ENOENT" && await fs8.lstat(resolvedLinkPath).then((entry) => entry.isSymbolicLink()).catch(() => false)) {
|
|
687
|
+
await fs8.rm(resolvedLinkPath, { recursive: true, force: false });
|
|
575
688
|
} else if (error.code !== "ENOENT") {
|
|
576
689
|
throw error;
|
|
577
690
|
}
|
|
578
691
|
}
|
|
579
|
-
await
|
|
692
|
+
await fs8.symlink(resolvedTargetPath, resolvedLinkPath, directoryLinkType);
|
|
580
693
|
}
|
|
581
694
|
async function replaceEntryWithManagedLink(linkPath, targetPath, expectedCurrentPath) {
|
|
582
695
|
const resolvedLinkPath = resolve6(linkPath);
|
|
@@ -584,38 +697,38 @@ async function replaceEntryWithManagedLink(linkPath, targetPath, expectedCurrent
|
|
|
584
697
|
const resolvedExpectedCurrentPath = resolve6(expectedCurrentPath);
|
|
585
698
|
await assertNoSymlinkAncestors(resolvedLinkPath);
|
|
586
699
|
await assertNoSymlinkAncestors(resolvedTargetPath, { includeLeaf: true });
|
|
587
|
-
await
|
|
588
|
-
const existingEntry = await
|
|
700
|
+
await fs8.mkdir(dirname3(resolvedLinkPath), { recursive: true });
|
|
701
|
+
const existingEntry = await fs8.lstat(resolvedLinkPath);
|
|
589
702
|
if (existingEntry.isSymbolicLink()) {
|
|
590
|
-
const currentTargetPath = await
|
|
703
|
+
const currentTargetPath = await fs8.realpath(resolvedLinkPath);
|
|
591
704
|
if (pathsAreEqual(currentTargetPath, resolvedTargetPath)) {
|
|
592
705
|
return false;
|
|
593
706
|
}
|
|
594
707
|
if (!pathsAreEqual(currentTargetPath, resolvedExpectedCurrentPath)) {
|
|
595
708
|
throw new Error(`Refusing to replace unexpected link at ${resolvedLinkPath}`);
|
|
596
709
|
}
|
|
597
|
-
await
|
|
598
|
-
await
|
|
710
|
+
await fs8.rm(resolvedLinkPath, { recursive: true, force: false });
|
|
711
|
+
await fs8.symlink(resolvedTargetPath, resolvedLinkPath, directoryLinkType);
|
|
599
712
|
return true;
|
|
600
713
|
}
|
|
601
714
|
if (!existingEntry.isDirectory()) {
|
|
602
715
|
throw new Error(`Refusing to replace non-directory entry at ${resolvedLinkPath}`);
|
|
603
716
|
}
|
|
604
|
-
const currentPath = await
|
|
717
|
+
const currentPath = await fs8.realpath(resolvedLinkPath);
|
|
605
718
|
if (!pathsAreEqual(currentPath, resolvedExpectedCurrentPath)) {
|
|
606
719
|
throw new Error(`Refusing to replace unexpected directory at ${resolvedLinkPath}`);
|
|
607
720
|
}
|
|
608
|
-
await
|
|
609
|
-
await
|
|
721
|
+
await fs8.rm(resolvedLinkPath, { recursive: true, force: false });
|
|
722
|
+
await fs8.symlink(resolvedTargetPath, resolvedLinkPath, directoryLinkType);
|
|
610
723
|
return true;
|
|
611
724
|
}
|
|
612
725
|
async function isLinkPointingToTarget(linkPath, targetPath) {
|
|
613
726
|
try {
|
|
614
|
-
const entry = await
|
|
727
|
+
const entry = await fs8.lstat(linkPath);
|
|
615
728
|
if (!entry.isSymbolicLink()) {
|
|
616
729
|
return false;
|
|
617
730
|
}
|
|
618
|
-
const resolvedTargetPath = await
|
|
731
|
+
const resolvedTargetPath = await fs8.realpath(linkPath);
|
|
619
732
|
return pathsAreEqual(resolvedTargetPath, targetPath);
|
|
620
733
|
} catch (error) {
|
|
621
734
|
if (error.code === "ENOENT") {
|
|
@@ -626,8 +739,8 @@ async function isLinkPointingToTarget(linkPath, targetPath) {
|
|
|
626
739
|
}
|
|
627
740
|
|
|
628
741
|
// src/manifest/read-manifest.ts
|
|
629
|
-
import * as
|
|
630
|
-
import { join as
|
|
742
|
+
import * as fs10 from "fs/promises";
|
|
743
|
+
import { join as join7, resolve as resolve7 } from "path";
|
|
631
744
|
|
|
632
745
|
// src/manifest/build-empty-manifest.ts
|
|
633
746
|
function buildEmptyManifest(skillmuxHome) {
|
|
@@ -752,32 +865,32 @@ var manifestSchema = z2.object({
|
|
|
752
865
|
|
|
753
866
|
// src/manifest/write-manifest.ts
|
|
754
867
|
import { randomUUID } from "crypto";
|
|
755
|
-
import * as
|
|
756
|
-
import { join as
|
|
868
|
+
import * as fs9 from "fs/promises";
|
|
869
|
+
import { join as join6 } from "path";
|
|
757
870
|
function getManifestPath(home) {
|
|
758
|
-
return
|
|
871
|
+
return join6(home, "manifest.json");
|
|
759
872
|
}
|
|
760
873
|
function createManifestTempPath(manifestPath) {
|
|
761
874
|
return `${manifestPath}.${process.pid}.${randomUUID()}.tmp`;
|
|
762
875
|
}
|
|
763
876
|
async function writeManifest(home, manifest) {
|
|
764
|
-
await
|
|
877
|
+
await fs9.mkdir(home, { recursive: true });
|
|
765
878
|
const manifestPath = getManifestPath(home);
|
|
766
879
|
const tempPath = createManifestTempPath(manifestPath);
|
|
767
880
|
const contents = `${JSON.stringify(manifest, null, 2)}
|
|
768
881
|
`;
|
|
769
|
-
await
|
|
882
|
+
await fs9.writeFile(tempPath, contents, "utf8");
|
|
770
883
|
try {
|
|
771
|
-
await
|
|
884
|
+
await fs9.rename(tempPath, manifestPath);
|
|
772
885
|
} catch (error) {
|
|
773
|
-
await
|
|
886
|
+
await fs9.unlink(tempPath).catch(() => void 0);
|
|
774
887
|
throw error;
|
|
775
888
|
}
|
|
776
889
|
}
|
|
777
890
|
|
|
778
891
|
// src/manifest/read-manifest.ts
|
|
779
892
|
function getManifestPath2(home) {
|
|
780
|
-
return
|
|
893
|
+
return join7(home, "manifest.json");
|
|
781
894
|
}
|
|
782
895
|
function normalizeHomePath(home) {
|
|
783
896
|
const resolvedHome = resolve7(home);
|
|
@@ -792,7 +905,7 @@ function formatValidationIssues2(error) {
|
|
|
792
905
|
async function readManifest(home) {
|
|
793
906
|
const manifestPath = getManifestPath2(home);
|
|
794
907
|
try {
|
|
795
|
-
const contents = await
|
|
908
|
+
const contents = await fs10.readFile(manifestPath, "utf8");
|
|
796
909
|
const parsedJson = JSON.parse(contents);
|
|
797
910
|
const parsedManifest = manifestSchema.safeParse(parsedJson);
|
|
798
911
|
if (!parsedManifest.success) {
|
|
@@ -937,7 +1050,7 @@ function buildOutput(result, json) {
|
|
|
937
1050
|
`;
|
|
938
1051
|
}
|
|
939
1052
|
async function runAdoptSingle(options) {
|
|
940
|
-
const homeDir = options.homeDir ??
|
|
1053
|
+
const homeDir = options.homeDir ?? homedir2();
|
|
941
1054
|
const { skillmuxHome: defaultSkillmuxHome } = resolveSkillmuxHome(homeDir);
|
|
942
1055
|
const skillmuxHome = options.skillmuxHome ?? defaultSkillmuxHome;
|
|
943
1056
|
const timestamp = (options.now ?? /* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1016,7 +1129,7 @@ async function runAdoptSingle(options) {
|
|
|
1016
1129
|
const activation = buildActivationRecord(
|
|
1017
1130
|
skillId,
|
|
1018
1131
|
agent.id,
|
|
1019
|
-
|
|
1132
|
+
join8(agent.absoluteSkillsDirectoryPath, entry.skillName),
|
|
1020
1133
|
timestamp
|
|
1021
1134
|
);
|
|
1022
1135
|
upsertActivation(manifest, activation);
|
|
@@ -1085,7 +1198,7 @@ async function runAdopt(options) {
|
|
|
1085
1198
|
}
|
|
1086
1199
|
|
|
1087
1200
|
// src/commands/config-add-agent.ts
|
|
1088
|
-
import { homedir as
|
|
1201
|
+
import { homedir as homedir3 } from "os";
|
|
1089
1202
|
|
|
1090
1203
|
// src/config/agent-override-validation.ts
|
|
1091
1204
|
import { isAbsolute } from "path";
|
|
@@ -1126,19 +1239,6 @@ function normalizePlatforms(value) {
|
|
|
1126
1239
|
return normalized;
|
|
1127
1240
|
}
|
|
1128
1241
|
|
|
1129
|
-
// src/config/write-user-config.ts
|
|
1130
|
-
import * as fs10 from "fs/promises";
|
|
1131
|
-
async function writeUserConfig(skillmuxHome, config) {
|
|
1132
|
-
const configPath = buildConfigPath(skillmuxHome);
|
|
1133
|
-
await fs10.mkdir(skillmuxHome, { recursive: true });
|
|
1134
|
-
await fs10.writeFile(configPath, `${JSON.stringify(config, null, 2)}
|
|
1135
|
-
`, "utf8");
|
|
1136
|
-
return {
|
|
1137
|
-
skillmuxHome,
|
|
1138
|
-
configPath
|
|
1139
|
-
};
|
|
1140
|
-
}
|
|
1141
|
-
|
|
1142
1242
|
// src/output/print-table.ts
|
|
1143
1243
|
function printTable(rows, columns) {
|
|
1144
1244
|
const renderedRows = rows.map(
|
|
@@ -1211,7 +1311,7 @@ function buildTableOutput(result) {
|
|
|
1211
1311
|
return `${summary}${detail}`;
|
|
1212
1312
|
}
|
|
1213
1313
|
async function runConfigAddAgent(options) {
|
|
1214
|
-
const homeDir = options.homeDir ??
|
|
1314
|
+
const homeDir = options.homeDir ?? homedir3();
|
|
1215
1315
|
const resolvedPaths = resolveSkillmuxHome(homeDir);
|
|
1216
1316
|
const skillmuxHome = options.skillmuxHome ?? resolvedPaths.skillmuxHome;
|
|
1217
1317
|
const configPath = buildConfigPath(skillmuxHome);
|
|
@@ -1242,7 +1342,7 @@ async function runConfigAddAgent(options) {
|
|
|
1242
1342
|
}
|
|
1243
1343
|
|
|
1244
1344
|
// src/commands/config-remove-agent.ts
|
|
1245
|
-
import { homedir as
|
|
1345
|
+
import { homedir as homedir4 } from "os";
|
|
1246
1346
|
function normalizeAgentId2(value) {
|
|
1247
1347
|
const trimmed = value.trim();
|
|
1248
1348
|
if (trimmed.length === 0 || /[a-z0-9]/i.test(trimmed) === false) {
|
|
@@ -1269,18 +1369,22 @@ function buildTableOutput2(result) {
|
|
|
1269
1369
|
);
|
|
1270
1370
|
}
|
|
1271
1371
|
async function runConfigRemoveAgent(options) {
|
|
1272
|
-
const homeDir = options.homeDir ??
|
|
1372
|
+
const homeDir = options.homeDir ?? homedir4();
|
|
1273
1373
|
const resolvedPaths = resolveSkillmuxHome(homeDir);
|
|
1274
1374
|
const skillmuxHome = options.skillmuxHome ?? resolvedPaths.skillmuxHome;
|
|
1275
1375
|
const configPath = buildConfigPath(skillmuxHome);
|
|
1276
1376
|
const config = await loadUserConfig(skillmuxHome);
|
|
1277
1377
|
const agentId = normalizeAgentId2(options.id);
|
|
1278
1378
|
const removed = agentId in config.agents;
|
|
1379
|
+
const removedOverride = config.agents[agentId];
|
|
1380
|
+
const wasAutoDiscovered = removedOverride?.autoDiscovered === true;
|
|
1381
|
+
const removedAutoAgentIds = wasAutoDiscovered ? [...config.removedAutoAgentIds ?? [], agentId] : config.removedAutoAgentIds;
|
|
1279
1382
|
const nextConfig = {
|
|
1280
1383
|
...config,
|
|
1281
1384
|
agents: Object.fromEntries(
|
|
1282
1385
|
Object.entries(config.agents).filter(([currentAgentId]) => currentAgentId !== agentId)
|
|
1283
|
-
)
|
|
1386
|
+
),
|
|
1387
|
+
...wasAutoDiscovered ? { removedAutoAgentIds } : {}
|
|
1284
1388
|
};
|
|
1285
1389
|
if (removed) {
|
|
1286
1390
|
await writeUserConfig(skillmuxHome, nextConfig);
|
|
@@ -1300,7 +1404,7 @@ async function runConfigRemoveAgent(options) {
|
|
|
1300
1404
|
}
|
|
1301
1405
|
|
|
1302
1406
|
// src/commands/config-update-agent.ts
|
|
1303
|
-
import { homedir as
|
|
1407
|
+
import { homedir as homedir5 } from "os";
|
|
1304
1408
|
function buildAgentPatch(options) {
|
|
1305
1409
|
const patch = {};
|
|
1306
1410
|
if (options.root !== void 0) {
|
|
@@ -1364,7 +1468,7 @@ function buildTableOutput3(result) {
|
|
|
1364
1468
|
return `${summary}${detail}`;
|
|
1365
1469
|
}
|
|
1366
1470
|
async function runConfigUpdateAgent(options) {
|
|
1367
|
-
const homeDir = options.homeDir ??
|
|
1471
|
+
const homeDir = options.homeDir ?? homedir5();
|
|
1368
1472
|
const resolvedPaths = resolveSkillmuxHome(homeDir);
|
|
1369
1473
|
const skillmuxHome = options.skillmuxHome ?? resolvedPaths.skillmuxHome;
|
|
1370
1474
|
const configPath = buildConfigPath(skillmuxHome);
|
|
@@ -1378,6 +1482,9 @@ async function runConfigUpdateAgent(options) {
|
|
|
1378
1482
|
...previous,
|
|
1379
1483
|
...buildAgentPatch(options)
|
|
1380
1484
|
};
|
|
1485
|
+
if (previous.autoDiscovered === true) {
|
|
1486
|
+
delete agent.autoDiscovered;
|
|
1487
|
+
}
|
|
1381
1488
|
const changed = JSON.stringify(previous) !== JSON.stringify(agent);
|
|
1382
1489
|
const nextConfig = {
|
|
1383
1490
|
...config,
|
|
@@ -1404,11 +1511,11 @@ async function runConfigUpdateAgent(options) {
|
|
|
1404
1511
|
}
|
|
1405
1512
|
|
|
1406
1513
|
// src/commands/doctor.ts
|
|
1407
|
-
import { homedir as
|
|
1514
|
+
import { homedir as homedir6 } from "os";
|
|
1408
1515
|
|
|
1409
1516
|
// src/diagnostics/collect-doctor-issues.ts
|
|
1410
1517
|
import * as fs11 from "fs/promises";
|
|
1411
|
-
import { join as
|
|
1518
|
+
import { join as join9 } from "path";
|
|
1412
1519
|
function buildIssue2(code, severity, message, path) {
|
|
1413
1520
|
return path === void 0 ? { code, severity, message } : { code, severity, message, path };
|
|
1414
1521
|
}
|
|
@@ -1428,7 +1535,7 @@ async function addUnmanagedDirectoryIssues(entries, issues) {
|
|
|
1428
1535
|
if (entry.kind !== "unmanaged-directory") {
|
|
1429
1536
|
continue;
|
|
1430
1537
|
}
|
|
1431
|
-
if (await pathExists2(
|
|
1538
|
+
if (await pathExists2(join9(entry.path, "SKILL.md"))) {
|
|
1432
1539
|
issues.push(
|
|
1433
1540
|
buildIssue2(
|
|
1434
1541
|
"unmanaged-skill-directory",
|
|
@@ -1534,7 +1641,7 @@ function buildJsonOutput(result) {
|
|
|
1534
1641
|
});
|
|
1535
1642
|
}
|
|
1536
1643
|
async function runDoctor(options = {}) {
|
|
1537
|
-
const homeDir = options.homeDir ??
|
|
1644
|
+
const homeDir = options.homeDir ?? homedir6();
|
|
1538
1645
|
const resolvedPaths = resolveSkillmuxHome(homeDir);
|
|
1539
1646
|
const skillmuxHome = options.skillmuxHome ?? resolvedPaths.skillmuxHome;
|
|
1540
1647
|
const [manifest, config, agents] = await Promise.all([
|
|
@@ -1575,8 +1682,8 @@ async function runDoctor(options = {}) {
|
|
|
1575
1682
|
|
|
1576
1683
|
// src/commands/disable.ts
|
|
1577
1684
|
import * as fs13 from "fs/promises";
|
|
1578
|
-
import { homedir as
|
|
1579
|
-
import { join as
|
|
1685
|
+
import { homedir as homedir7 } from "os";
|
|
1686
|
+
import { join as join10, resolve as resolve9 } from "path";
|
|
1580
1687
|
|
|
1581
1688
|
// src/fs/safe-remove-link.ts
|
|
1582
1689
|
import * as fs12 from "fs/promises";
|
|
@@ -1685,14 +1792,14 @@ async function runDisableSingle(options) {
|
|
|
1685
1792
|
if (options.agent === void 0) {
|
|
1686
1793
|
throw new Error("Disable requires one target agent");
|
|
1687
1794
|
}
|
|
1688
|
-
const homeDir = options.homeDir ??
|
|
1795
|
+
const homeDir = options.homeDir ?? homedir7();
|
|
1689
1796
|
const { skillmuxHome: defaultSkillmuxHome } = resolveSkillmuxHome(homeDir);
|
|
1690
1797
|
const skillmuxHome = options.skillmuxHome ?? defaultSkillmuxHome;
|
|
1691
1798
|
const timestamp = (options.now ?? /* @__PURE__ */ new Date()).toISOString();
|
|
1692
1799
|
const manifest = await readManifest(skillmuxHome);
|
|
1693
1800
|
const skillId = normalizeId(options.skill);
|
|
1694
1801
|
const agent = await resolveTargetAgent2(homeDir, skillmuxHome, options.agent);
|
|
1695
|
-
const linkPath =
|
|
1802
|
+
const linkPath = join10(agent.absoluteSkillsDirectoryPath, skillId);
|
|
1696
1803
|
const adoption = manifest.skills[skillId] ? void 0 : await tryAdoptManagedSkill(
|
|
1697
1804
|
manifest,
|
|
1698
1805
|
skillmuxHome,
|
|
@@ -1776,8 +1883,8 @@ async function runDisable(options) {
|
|
|
1776
1883
|
|
|
1777
1884
|
// src/commands/enable.ts
|
|
1778
1885
|
import * as fs14 from "fs/promises";
|
|
1779
|
-
import { homedir as
|
|
1780
|
-
import { join as
|
|
1886
|
+
import { homedir as homedir8 } from "os";
|
|
1887
|
+
import { join as join11 } from "path";
|
|
1781
1888
|
function buildAgentRecord3(agent, timestamp) {
|
|
1782
1889
|
return {
|
|
1783
1890
|
id: agent.id,
|
|
@@ -1823,7 +1930,7 @@ async function runEnableSingle(options) {
|
|
|
1823
1930
|
if (options.agent === void 0) {
|
|
1824
1931
|
throw new Error("Enable requires one target agent");
|
|
1825
1932
|
}
|
|
1826
|
-
const homeDir = options.homeDir ??
|
|
1933
|
+
const homeDir = options.homeDir ?? homedir8();
|
|
1827
1934
|
const { skillmuxHome: defaultSkillmuxHome } = resolveSkillmuxHome(homeDir);
|
|
1828
1935
|
const skillmuxHome = options.skillmuxHome ?? defaultSkillmuxHome;
|
|
1829
1936
|
const timestamp = (options.now ?? /* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1834,7 +1941,7 @@ async function runEnableSingle(options) {
|
|
|
1834
1941
|
throw new Error(`Managed skill not found: ${skillId}`);
|
|
1835
1942
|
}
|
|
1836
1943
|
const agent = await resolveTargetAgent3(homeDir, skillmuxHome, options.agent);
|
|
1837
|
-
const linkPath =
|
|
1944
|
+
const linkPath = join11(agent.absoluteSkillsDirectoryPath, skill.id);
|
|
1838
1945
|
const currentActivation = manifest.activations.find(
|
|
1839
1946
|
(entry) => entry.skillId === skill.id && entry.agentId === agent.id
|
|
1840
1947
|
);
|
|
@@ -1909,12 +2016,12 @@ async function runEnable(options) {
|
|
|
1909
2016
|
|
|
1910
2017
|
// src/commands/import.ts
|
|
1911
2018
|
import { resolve as resolve10 } from "path";
|
|
1912
|
-
import { homedir as
|
|
2019
|
+
import { homedir as homedir9 } from "os";
|
|
1913
2020
|
function buildManagedSkillPath3(skillmuxHome, skillId) {
|
|
1914
2021
|
return resolve10(skillmuxHome, "skills", skillId);
|
|
1915
2022
|
}
|
|
1916
2023
|
async function runImport(options) {
|
|
1917
|
-
const homeDir = options.homeDir ??
|
|
2024
|
+
const homeDir = options.homeDir ?? homedir9();
|
|
1918
2025
|
const resolvedPaths = resolveSkillmuxHome(homeDir);
|
|
1919
2026
|
const skillmuxHome = options.skillmuxHome ?? resolvedPaths.skillmuxHome;
|
|
1920
2027
|
const sourcePath = resolve10(options.sourcePath);
|
|
@@ -1948,7 +2055,7 @@ async function runImport(options) {
|
|
|
1948
2055
|
}
|
|
1949
2056
|
|
|
1950
2057
|
// src/commands/scan.ts
|
|
1951
|
-
import { homedir as
|
|
2058
|
+
import { homedir as homedir10 } from "os";
|
|
1952
2059
|
|
|
1953
2060
|
// src/output/format-issue.ts
|
|
1954
2061
|
function formatIssue(issue) {
|
|
@@ -2009,7 +2116,7 @@ ${result.issues.map(formatIssue).join("\n")}
|
|
|
2009
2116
|
`;
|
|
2010
2117
|
}
|
|
2011
2118
|
async function runScan(options = {}) {
|
|
2012
|
-
const homeDir = options.homeDir ??
|
|
2119
|
+
const homeDir = options.homeDir ?? homedir10();
|
|
2013
2120
|
const resolvedPaths = resolveSkillmuxHome(homeDir);
|
|
2014
2121
|
const skillmuxHome = options.skillmuxHome ?? resolvedPaths.skillmuxHome;
|
|
2015
2122
|
const manifest = await readManifest(skillmuxHome);
|
|
@@ -2050,7 +2157,7 @@ async function runScan(options = {}) {
|
|
|
2050
2157
|
|
|
2051
2158
|
// src/commands/remove.ts
|
|
2052
2159
|
import * as fs15 from "fs/promises";
|
|
2053
|
-
import { homedir as
|
|
2160
|
+
import { homedir as homedir11 } from "os";
|
|
2054
2161
|
import { resolve as resolve11 } from "path";
|
|
2055
2162
|
function buildManagedSkillPath4(skillmuxHome, skillId) {
|
|
2056
2163
|
return resolve11(skillmuxHome, "skills", skillId);
|
|
@@ -2126,7 +2233,7 @@ async function runRemoveSingle(options) {
|
|
|
2126
2233
|
if (options.skill === void 0) {
|
|
2127
2234
|
throw new Error("Remove requires one target skill");
|
|
2128
2235
|
}
|
|
2129
|
-
const homeDir = options.homeDir ??
|
|
2236
|
+
const homeDir = options.homeDir ?? homedir11();
|
|
2130
2237
|
const { skillmuxHome: defaultSkillmuxHome } = resolveSkillmuxHome(homeDir);
|
|
2131
2238
|
const skillmuxHome = options.skillmuxHome ?? defaultSkillmuxHome;
|
|
2132
2239
|
const manifestPath = buildManifestPath(skillmuxHome);
|
|
@@ -2236,4 +2343,4 @@ export {
|
|
|
2236
2343
|
runScan,
|
|
2237
2344
|
runRemove
|
|
2238
2345
|
};
|
|
2239
|
-
//# sourceMappingURL=chunk-
|
|
2346
|
+
//# sourceMappingURL=chunk-OY3C7VIL.js.map
|