@anaclumos/taal 1.1.2 → 1.1.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/package.json +5 -4
- package/src/commands/collect.ts +41 -0
- package/src/commands/init.ts +17 -1
- package/src/index.ts +20 -3
- package/src/providers/opencode.ts +1 -1
- package/src/providers/utils.ts +4 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anaclumos/taal",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"description": "CLI tool to sync MCP server configs and Agent Skills across AI coding assistants",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -36,11 +36,12 @@
|
|
|
36
36
|
"node": ">=18.0.0"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
+
"@iarna/toml": "^2.2.5",
|
|
40
|
+
"chalk": "^5.3.0",
|
|
39
41
|
"commander": "^12.0.0",
|
|
42
|
+
"jsonc-parser": "^3.3.1",
|
|
40
43
|
"yaml": "^2.3.4",
|
|
41
|
-
"
|
|
42
|
-
"zod": "^3.22.4",
|
|
43
|
-
"@iarna/toml": "^2.2.5"
|
|
44
|
+
"zod": "^3.22.4"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|
|
46
47
|
"@biomejs/biome": "2.3.11",
|
package/src/commands/collect.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
1
2
|
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
2
4
|
import type { McpServer } from "../config/schema.js";
|
|
3
5
|
import { initializeProviders, registry } from "../providers/index.js";
|
|
6
|
+
import { copySkillsToProvider } from "../skills/copy.js";
|
|
7
|
+
import { discoverSkills } from "../skills/discovery.js";
|
|
4
8
|
|
|
5
9
|
export interface CollectConflict {
|
|
6
10
|
serverName: string;
|
|
@@ -11,6 +15,7 @@ export interface CollectConflict {
|
|
|
11
15
|
export interface CollectResult {
|
|
12
16
|
servers: Record<string, McpServer>;
|
|
13
17
|
conflicts: CollectConflict[];
|
|
18
|
+
skillsCollected: number;
|
|
14
19
|
summary: {
|
|
15
20
|
totalServers: number;
|
|
16
21
|
providersScanned: number;
|
|
@@ -103,9 +108,45 @@ export async function collect(baseDir?: string): Promise<CollectResult> {
|
|
|
103
108
|
}
|
|
104
109
|
}
|
|
105
110
|
|
|
111
|
+
// Collect skills from providers
|
|
112
|
+
const taalSkillsDir = join(home, ".taal", "skills");
|
|
113
|
+
let skillsCollected = 0;
|
|
114
|
+
|
|
115
|
+
for (const provider of allProviders) {
|
|
116
|
+
if (!provider.skillsPath) {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
const isInstalled = await provider.isInstalled(home);
|
|
122
|
+
if (!isInstalled) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const skillsPath =
|
|
127
|
+
typeof provider.skillsPath === "function"
|
|
128
|
+
? provider.skillsPath(home)
|
|
129
|
+
: provider.skillsPath;
|
|
130
|
+
|
|
131
|
+
if (existsSync(skillsPath)) {
|
|
132
|
+
const providerSkills = discoverSkills([skillsPath], home);
|
|
133
|
+
if (providerSkills.length > 0) {
|
|
134
|
+
await copySkillsToProvider(providerSkills, taalSkillsDir);
|
|
135
|
+
skillsCollected += providerSkills.length;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
} catch (error) {
|
|
139
|
+
console.warn(
|
|
140
|
+
`Warning: Failed to collect skills from ${provider.name}:`,
|
|
141
|
+
error
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
106
146
|
return {
|
|
107
147
|
servers,
|
|
108
148
|
conflicts,
|
|
149
|
+
skillsCollected,
|
|
109
150
|
summary: {
|
|
110
151
|
totalServers: Object.keys(servers).length,
|
|
111
152
|
providersScanned,
|
package/src/commands/init.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { exists, mkdir, writeFile } from "node:fs/promises";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
+
import { collect } from "./collect.js";
|
|
4
5
|
|
|
5
6
|
const SAMPLE_CONFIG = `# TAAL Configuration
|
|
6
7
|
# https://github.com/user/taal
|
|
@@ -42,10 +43,16 @@ export interface InitOptions {
|
|
|
42
43
|
force?: boolean;
|
|
43
44
|
}
|
|
44
45
|
|
|
46
|
+
export interface InitResult {
|
|
47
|
+
configPath: string;
|
|
48
|
+
collected: boolean;
|
|
49
|
+
serversFound: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
45
52
|
export async function init(
|
|
46
53
|
baseDir?: string,
|
|
47
54
|
options: InitOptions = {}
|
|
48
|
-
): Promise<
|
|
55
|
+
): Promise<InitResult> {
|
|
49
56
|
const taalDir = join(baseDir || homedir(), ".taal");
|
|
50
57
|
const configPath = join(taalDir, "config.yaml");
|
|
51
58
|
const skillsDir = join(taalDir, "skills");
|
|
@@ -63,4 +70,13 @@ export async function init(
|
|
|
63
70
|
|
|
64
71
|
// Write sample config
|
|
65
72
|
await writeFile(configPath, SAMPLE_CONFIG, "utf-8");
|
|
73
|
+
|
|
74
|
+
// Automatically collect existing MCP configs from installed providers
|
|
75
|
+
const collectResult = await collect(baseDir);
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
configPath,
|
|
79
|
+
collected: collectResult.summary.totalServers > 0,
|
|
80
|
+
serversFound: collectResult.summary.totalServers,
|
|
81
|
+
};
|
|
66
82
|
}
|
package/src/index.ts
CHANGED
|
@@ -28,10 +28,23 @@ program
|
|
|
28
28
|
.option("-f, --force", "Overwrite existing configuration")
|
|
29
29
|
.action(async (options) => {
|
|
30
30
|
try {
|
|
31
|
-
await init(homedir(), options);
|
|
31
|
+
const result = await init(homedir(), options);
|
|
32
32
|
console.log("✓ TAAL initialized successfully");
|
|
33
|
-
console.log(` Config: ${
|
|
33
|
+
console.log(` Config: ${result.configPath}`);
|
|
34
34
|
console.log(` Skills: ${homedir()}/.taal/skills/`);
|
|
35
|
+
|
|
36
|
+
if (result.collected && result.serversFound > 0) {
|
|
37
|
+
console.log(
|
|
38
|
+
`\n✓ Collected ${result.serversFound} MCP server(s) from installed providers`
|
|
39
|
+
);
|
|
40
|
+
console.log(
|
|
41
|
+
"\nRun 'taal sync' to sync these servers to all enabled providers."
|
|
42
|
+
);
|
|
43
|
+
} else {
|
|
44
|
+
console.log(
|
|
45
|
+
"\nNo existing MCP servers found. Edit ~/.taal/config.yaml to add servers."
|
|
46
|
+
);
|
|
47
|
+
}
|
|
35
48
|
} catch (error) {
|
|
36
49
|
console.error("Error:", error instanceof Error ? error.message : error);
|
|
37
50
|
process.exit(1);
|
|
@@ -47,9 +60,13 @@ program
|
|
|
47
60
|
const result = await collect();
|
|
48
61
|
|
|
49
62
|
console.log(
|
|
50
|
-
`\n✓ Found ${result.summary.totalServers}
|
|
63
|
+
`\n✓ Found ${result.summary.totalServers} server(s) from ${result.summary.providersWithConfigs} provider(s)`
|
|
51
64
|
);
|
|
52
65
|
|
|
66
|
+
if (result.skillsCollected > 0) {
|
|
67
|
+
console.log(`✓ Collected ${result.skillsCollected} skill(s)`);
|
|
68
|
+
}
|
|
69
|
+
|
|
53
70
|
if (result.conflicts.length > 0) {
|
|
54
71
|
console.log("\n⚠ Conflicts detected:");
|
|
55
72
|
for (const conflict of result.conflicts) {
|
|
@@ -8,7 +8,7 @@ export class OpenCodeProvider extends BaseProvider {
|
|
|
8
8
|
join(home, ".config", "opencode", "opencode.json");
|
|
9
9
|
format = "json" as const;
|
|
10
10
|
mcpKey = "mcp";
|
|
11
|
-
skillsPath = (home: string) => join(home, ".opencode", "
|
|
11
|
+
skillsPath = (home: string) => join(home, ".config", "opencode", "skill");
|
|
12
12
|
|
|
13
13
|
transformMcpServers(
|
|
14
14
|
servers: Record<string, McpServer>
|
package/src/providers/utils.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import type { JsonMap } from "@iarna/toml";
|
|
3
3
|
import { parse as parseToml, stringify as stringifyToml } from "@iarna/toml";
|
|
4
|
+
import { parse as parseJsonc } from "jsonc-parser";
|
|
4
5
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
5
6
|
import { atomicWrite } from "../utils/atomic-write.js";
|
|
6
7
|
import { backupConfig } from "../utils/backup.js";
|
|
7
8
|
import type { ConfigFormat } from "./types.js";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
|
-
* Read and parse a JSON config file
|
|
11
|
+
* Read and parse a JSON config file (supports JSONC - JSON with Comments)
|
|
11
12
|
*/
|
|
12
13
|
export function readJsonConfig(path: string): unknown {
|
|
13
14
|
if (!existsSync(path)) {
|
|
@@ -16,7 +17,8 @@ export function readJsonConfig(path: string): unknown {
|
|
|
16
17
|
|
|
17
18
|
try {
|
|
18
19
|
const content = readFileSync(path, "utf-8");
|
|
19
|
-
|
|
20
|
+
// Use JSONC parser to support comments and trailing commas (used by Zed, VS Code, etc.)
|
|
21
|
+
return parseJsonc(content);
|
|
20
22
|
} catch (error) {
|
|
21
23
|
throw new Error(`Failed to read JSON config at ${path}: ${error}`);
|
|
22
24
|
}
|