@anaclumos/taal 2.0.0 → 2.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.
@@ -1,9 +1,8 @@
1
1
  name: Publish to NPM
2
2
 
3
3
  on:
4
- push:
5
- tags:
6
- - 'v*' # Triggers on v1.0.0, v1.2.3, etc.
4
+ release:
5
+ types: [published]
7
6
 
8
7
  permissions:
9
8
  contents: read
package/AGENTS.md CHANGED
@@ -64,15 +64,15 @@ npm install -g @anaclumos/taal
64
64
  version: "1"
65
65
 
66
66
  mcp:
67
- # TAAL MCP server
67
+ # TAAL MCP server (requires bun: https://bun.sh)
68
68
  taal:
69
- command: npx
70
- args: ["-y", "@anaclumos/taal", "taal-mcp"]
69
+ command: bunx
70
+ args: ["--bun", "taal-mcp"]
71
71
 
72
72
  # stdio server example
73
73
  filesystem:
74
- command: npx
75
- args: ["-y", "@modelcontextprotocol/server-filesystem", "/path"]
74
+ command: bunx
75
+ args: ["--bun", "@modelcontextprotocol/server-filesystem", "/path"]
76
76
  env:
77
77
  LOG_LEVEL: "info"
78
78
 
@@ -175,8 +175,8 @@ vim ~/.taal/config.yaml
175
175
  # 2. Add server configuration
176
176
  # mcp:
177
177
  # new-server:
178
- # command: npx
179
- # args: ["-y", "package-name"]
178
+ # command: bunx
179
+ # args: ["--bun", "package-name"]
180
180
 
181
181
  # 3. Validate
182
182
  taal validate
package/README.md CHANGED
@@ -153,15 +153,15 @@ Shows for each provider:
153
153
  version: "1"
154
154
 
155
155
  mcp:
156
- # TAAL MCP server
156
+ # TAAL MCP server (requires bun: https://bun.sh)
157
157
  taal:
158
- command: npx
159
- args: ["-y", "@anaclumos/taal", "taal-mcp"]
158
+ command: bunx
159
+ args: ["--bun", "taal-mcp"]
160
160
 
161
161
  # Stdio server example
162
162
  filesystem:
163
- command: npx
164
- args: ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/files"]
163
+ command: bunx
164
+ args: ["--bun", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/files"]
165
165
  env:
166
166
  LOG_LEVEL: "info"
167
167
 
@@ -215,13 +215,13 @@ mcp:
215
215
 
216
216
  ### TAAL MCP Server
217
217
 
218
- TAAL can run as an MCP server to expose its CLI features as tools.
218
+ TAAL can run as an MCP server to expose its CLI features as tools. Requires [Bun](https://bun.sh).
219
219
 
220
220
  ```yaml
221
221
  mcp:
222
222
  taal:
223
- command: npx
224
- args: ["-y", "@anaclumos/taal", "taal-mcp"]
223
+ command: bunx
224
+ args: ["--bun", "taal-mcp"]
225
225
  ```
226
226
 
227
227
  Tools exposed:
@@ -527,7 +527,7 @@ taal/
527
527
 
528
528
  ## Publishing
529
529
 
530
- TAAL uses automated NPM publishing via GitHub Actions.
530
+ TAAL uses automated NPM publishing via GitHub Actions, triggered by GitHub Releases.
531
531
 
532
532
  ### Release Process
533
533
 
@@ -545,11 +545,11 @@ TAAL uses automated NPM publishing via GitHub Actions.
545
545
  git push origin main
546
546
  ```
547
547
 
548
- 3. **Create and push tag**:
549
- ```bash
550
- git tag v1.0.1
551
- git push origin v1.0.1
552
- ```
548
+ 3. **Create a GitHub Release**:
549
+ - Go to GitHub → Releases → "Create a new release"
550
+ - Create a new tag (e.g., `v1.0.1`)
551
+ - Add release notes
552
+ - Click "Publish release"
553
553
 
554
554
  4. **GitHub Actions automatically**:
555
555
  - Runs tests
@@ -559,7 +559,7 @@ TAAL uses automated NPM publishing via GitHub Actions.
559
559
  ### Prerequisites
560
560
 
561
561
  Repository maintainers must configure:
562
- - `NPM_TOKEN` secret in GitHub repository settings
562
+ - NPM trusted publishing (OIDC) - no NPM_TOKEN needed
563
563
  - NPM account with 2FA enabled
564
564
  - Package access permissions
565
565
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anaclumos/taal",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "CLI tool to sync MCP server configs and Agent Skills across AI coding assistants",
5
5
  "type": "module",
6
6
  "bin": {
@@ -182,8 +182,8 @@ export async function collectAndUpdateConfig(
182
182
  version: "1",
183
183
  mcp: {
184
184
  taal: {
185
- command: "npx",
186
- args: ["-y", "@anaclumos/taal", "taal-mcp"],
185
+ command: "bunx",
186
+ args: ["--bun", "taal-mcp"],
187
187
  },
188
188
  },
189
189
  skills: { paths: ["~/.taal/skills"] },
@@ -4,19 +4,19 @@ import { join } from "node:path";
4
4
  import { collect } from "./collect.js";
5
5
 
6
6
  const SAMPLE_CONFIG = `# TAAL Configuration
7
- # https://github.com/user/taal
7
+ # https://github.com/anaclumos/taal
8
8
 
9
9
  version: "1"
10
10
 
11
11
  mcp:
12
- # TAAL MCP server
12
+ # TAAL MCP server (requires bun: https://bun.sh)
13
13
  taal:
14
- command: npx
15
- args: ["-y", "@anaclumos/taal", "taal-mcp"]
14
+ command: bunx
15
+ args: ["--bun", "taal-mcp"]
16
16
  # Example stdio server
17
17
  # example-server:
18
- # command: npx
19
- # args: ["-y", "@example/mcp-server"]
18
+ # command: bunx
19
+ # args: ["--bun", "@example/mcp-server"]
20
20
  # env:
21
21
  # API_KEY: "\${API_KEY}"
22
22
 
@@ -70,11 +70,15 @@ export async function sync(
70
70
  const taalServers = config.mcp || {};
71
71
  const transformedServers = provider.transformMcpServers(taalServers);
72
72
 
73
- const newConfig = {
73
+ let newConfig: Record<string, unknown> = {
74
74
  ...(currentConfig as object),
75
75
  [provider.mcpKey]: transformedServers,
76
76
  };
77
77
 
78
+ if (provider.transformConfig) {
79
+ newConfig = provider.transformConfig(newConfig, taalServers);
80
+ }
81
+
78
82
  await provider.writeConfig(newConfig, home);
79
83
 
80
84
  if (provider.skillsPath && config.skills?.paths) {
package/src/index.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  #!/usr/bin/env bun
2
+ import { readFileSync } from "node:fs";
2
3
  import { homedir } from "node:os";
4
+ import { dirname, join } from "node:path";
5
+ import { fileURLToPath } from "node:url";
3
6
  import chalk from "chalk";
4
7
  import { Command } from "commander";
5
8
  import { isError } from "es-toolkit/predicate";
@@ -10,15 +13,23 @@ import { list } from "./commands/list";
10
13
  import { providers } from "./commands/providers";
11
14
  import { sync } from "./commands/sync";
12
15
  import { validate } from "./commands/validate";
16
+ import { checkForUpdates } from "./utils/update-checker";
17
+
18
+ const __dirname = dirname(fileURLToPath(import.meta.url));
19
+ const packageJson = JSON.parse(
20
+ readFileSync(join(__dirname, "..", "package.json"), "utf-8")
21
+ ) as { version: string };
13
22
 
14
23
  const program = new Command();
15
24
 
25
+ checkForUpdates().catch(() => undefined);
26
+
16
27
  program
17
28
  .name("taal")
18
29
  .description(
19
30
  "CLI to sync MCP server configs and Agent Skills across AI providers"
20
31
  )
21
- .version("2.0.0");
32
+ .version(packageJson.version);
22
33
 
23
34
  program
24
35
  .command("init")
package/src/mcp.ts CHANGED
@@ -1,12 +1,14 @@
1
1
  #!/usr/bin/env bun
2
+ import { readFileSync } from "node:fs";
2
3
  import { exists, readFile, writeFile } from "node:fs/promises";
3
4
  import { homedir } from "node:os";
4
- import { join } from "node:path";
5
+ import { dirname, join } from "node:path";
6
+ import { fileURLToPath } from "node:url";
5
7
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6
8
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
9
  import { isError } from "es-toolkit/predicate";
8
10
  import YAML from "yaml";
9
- import { z } from "zod/v4";
11
+ import { z } from "zod";
10
12
  import { collectAndUpdateConfig } from "./commands/collect.js";
11
13
  import { diff } from "./commands/diff.js";
12
14
  import { init } from "./commands/init.js";
@@ -16,6 +18,11 @@ import { sync } from "./commands/sync.js";
16
18
  import { validate } from "./commands/validate.js";
17
19
  import { McpServerSchema, TaalConfigSchema } from "./config/schema.js";
18
20
 
21
+ const __dirname = dirname(fileURLToPath(import.meta.url));
22
+ const packageJson = JSON.parse(
23
+ readFileSync(join(__dirname, "..", "package.json"), "utf-8")
24
+ ) as { version: string };
25
+
19
26
  function createToolResult(data: unknown) {
20
27
  return {
21
28
  content: [
@@ -55,8 +62,8 @@ function createDefaultConfig(): RawTaalConfig {
55
62
  version: "1",
56
63
  mcp: {
57
64
  taal: {
58
- command: "npx",
59
- args: ["-y", "@anaclumos/taal", "taal-mcp"],
65
+ command: "bunx",
66
+ args: ["--bun", "taal-mcp"],
60
67
  },
61
68
  },
62
69
  skills: { paths: ["~/.taal/skills"] },
@@ -141,7 +148,7 @@ async function writeValidatedConfig(configPath: string, config: RawTaalConfig) {
141
148
  export function createTaalMcpServer() {
142
149
  const server = new McpServer({
143
150
  name: "taal",
144
- version: "2.0.0",
151
+ version: packageJson.version,
145
152
  });
146
153
 
147
154
  const baseDirSchema = z
@@ -198,10 +205,10 @@ export function createTaalMcpServer() {
198
205
  "taal_init",
199
206
  {
200
207
  description: "Initialize TAAL configuration and collect existing MCPs.",
201
- inputSchema: {
208
+ inputSchema: z.object({
202
209
  baseDir: baseDirSchema,
203
210
  force: forceSchema,
204
- },
211
+ }),
205
212
  },
206
213
  async ({ baseDir, force }) => {
207
214
  try {
@@ -217,10 +224,10 @@ export function createTaalMcpServer() {
217
224
  "taal_config_read",
218
225
  {
219
226
  description: "Read TAAL config.yaml (parsed and optionally raw).",
220
- inputSchema: {
227
+ inputSchema: z.object({
221
228
  baseDir: baseDirSchema,
222
229
  includeRaw: includeRawSchema,
223
- },
230
+ }),
224
231
  },
225
232
  async ({ baseDir, includeRaw }) => {
226
233
  try {
@@ -249,9 +256,9 @@ export function createTaalMcpServer() {
249
256
  {
250
257
  description:
251
258
  "Collect MCP servers from installed providers and merge into config.",
252
- inputSchema: {
259
+ inputSchema: z.object({
253
260
  baseDir: baseDirSchema,
254
- },
261
+ }),
255
262
  },
256
263
  async ({ baseDir }) => {
257
264
  try {
@@ -267,13 +274,13 @@ export function createTaalMcpServer() {
267
274
  "taal_mcp_add",
268
275
  {
269
276
  description: "Add or update an MCP server entry in config.yaml.",
270
- inputSchema: {
277
+ inputSchema: z.object({
271
278
  baseDir: baseDirSchema,
272
279
  createIfMissing: createIfMissingSchema,
273
280
  overwrite: overwriteSchema,
274
281
  name: mcpNameSchema,
275
282
  server: z.object(mcpServerInputSchema),
276
- },
283
+ }),
277
284
  },
278
285
  async ({
279
286
  baseDir,
@@ -324,11 +331,11 @@ export function createTaalMcpServer() {
324
331
  "taal_mcp_delete",
325
332
  {
326
333
  description: "Delete an MCP server entry from config.yaml.",
327
- inputSchema: {
334
+ inputSchema: z.object({
328
335
  baseDir: baseDirSchema,
329
336
  errorIfMissing: errorIfMissingSchema,
330
337
  name: mcpNameSchema,
331
- },
338
+ }),
332
339
  },
333
340
  async ({ baseDir, errorIfMissing, name }) => {
334
341
  try {
@@ -371,11 +378,11 @@ export function createTaalMcpServer() {
371
378
  "taal_skill_path_add",
372
379
  {
373
380
  description: "Add a skills path to config.yaml.",
374
- inputSchema: {
381
+ inputSchema: z.object({
375
382
  baseDir: baseDirSchema,
376
383
  createIfMissing: createIfMissingSchema,
377
384
  path: skillPathSchema,
378
- },
385
+ }),
379
386
  },
380
387
  async ({ baseDir, createIfMissing, path }) => {
381
388
  try {
@@ -417,11 +424,11 @@ export function createTaalMcpServer() {
417
424
  "taal_skill_path_delete",
418
425
  {
419
426
  description: "Remove a skills path from config.yaml.",
420
- inputSchema: {
427
+ inputSchema: z.object({
421
428
  baseDir: baseDirSchema,
422
429
  errorIfMissing: errorIfMissingSchema,
423
430
  path: skillPathSchema,
424
- },
431
+ }),
425
432
  },
426
433
  async ({ baseDir, errorIfMissing, path }) => {
427
434
  try {
@@ -469,9 +476,9 @@ export function createTaalMcpServer() {
469
476
  "taal_validate",
470
477
  {
471
478
  description: "Validate TAAL configuration.",
472
- inputSchema: {
479
+ inputSchema: z.object({
473
480
  baseDir: baseDirSchema,
474
- },
481
+ }),
475
482
  },
476
483
  async ({ baseDir }) => {
477
484
  try {
@@ -487,10 +494,10 @@ export function createTaalMcpServer() {
487
494
  "taal_diff",
488
495
  {
489
496
  description: "Show pending MCP changes without writing.",
490
- inputSchema: {
497
+ inputSchema: z.object({
491
498
  baseDir: baseDirSchema,
492
499
  provider: providerSchema,
493
- },
500
+ }),
494
501
  },
495
502
  async ({ baseDir, provider }) => {
496
503
  try {
@@ -506,10 +513,10 @@ export function createTaalMcpServer() {
506
513
  "taal_sync",
507
514
  {
508
515
  description: "Sync MCP configs and skills to enabled providers.",
509
- inputSchema: {
516
+ inputSchema: z.object({
510
517
  baseDir: baseDirSchema,
511
518
  provider: providerSchema,
512
- },
519
+ }),
513
520
  },
514
521
  async ({ baseDir, provider }) => {
515
522
  try {
@@ -525,9 +532,9 @@ export function createTaalMcpServer() {
525
532
  "taal_list",
526
533
  {
527
534
  description: "List configured MCP servers, skills, and providers.",
528
- inputSchema: {
535
+ inputSchema: z.object({
529
536
  baseDir: baseDirSchema,
530
- },
537
+ }),
531
538
  },
532
539
  async ({ baseDir }) => {
533
540
  try {
@@ -543,9 +550,9 @@ export function createTaalMcpServer() {
543
550
  "taal_providers",
544
551
  {
545
552
  description: "List supported providers and their status.",
546
- inputSchema: {
553
+ inputSchema: z.object({
547
554
  baseDir: baseDirSchema,
548
- },
555
+ }),
549
556
  },
550
557
  async ({ baseDir }) => {
551
558
  try {
@@ -16,14 +16,12 @@ export class ClaudeCodeProvider extends BaseProvider {
16
16
 
17
17
  for (const [name, server] of Object.entries(servers)) {
18
18
  if (server.url) {
19
- // HTTP server - Claude Code supports HTTP transport
20
19
  transformed[name] = {
21
20
  type: "http",
22
21
  url: server.url,
23
22
  ...(server.headers && { headers: server.headers }),
24
23
  };
25
24
  } else if (server.command) {
26
- // stdio server - Claude Code supports stdio transport
27
25
  transformed[name] = {
28
26
  type: "stdio",
29
27
  command: server.command,
@@ -37,4 +35,21 @@ export class ClaudeCodeProvider extends BaseProvider {
37
35
 
38
36
  return transformed;
39
37
  }
38
+
39
+ transformConfig(
40
+ config: Record<string, unknown>,
41
+ servers: Record<string, McpServer>
42
+ ): Record<string, unknown> {
43
+ const serverNames = Object.keys(servers);
44
+ const existingEnabled = Array.isArray(config.enabledMcpjsonServers)
45
+ ? (config.enabledMcpjsonServers as string[])
46
+ : [];
47
+
48
+ const mergedEnabled = [...new Set([...existingEnabled, ...serverNames])];
49
+
50
+ return {
51
+ ...config,
52
+ enabledMcpjsonServers: mergedEnabled,
53
+ };
54
+ }
40
55
  }
@@ -85,6 +85,15 @@ export interface Provider {
85
85
  * Optional: Transform skills to provider-specific format
86
86
  */
87
87
  transformSkills?(skills: unknown[]): unknown;
88
+
89
+ /**
90
+ * Optional: Apply additional transformations to the full config
91
+ * Called after mcpKey is set, allows providers to add extra keys
92
+ */
93
+ transformConfig?(
94
+ config: Record<string, unknown>,
95
+ servers: Record<string, McpServer>
96
+ ): Record<string, unknown>;
88
97
  }
89
98
 
90
99
  /**
@@ -0,0 +1,126 @@
1
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import chalk from "chalk";
6
+
7
+ const PACKAGE_NAME = "@anaclumos/taal";
8
+ const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
9
+ const CACHE_FILE = join(homedir(), ".taal", ".update-check-cache.json");
10
+
11
+ const __dirname = dirname(fileURLToPath(import.meta.url));
12
+ const packageJsonPath = join(__dirname, "..", "..", "package.json");
13
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8")) as {
14
+ version: string;
15
+ };
16
+ const CURRENT_VERSION = packageJson.version;
17
+
18
+ interface UpdateCache {
19
+ lastCheck: number;
20
+ latestVersion: string | null;
21
+ }
22
+
23
+ function readCache(): UpdateCache {
24
+ try {
25
+ if (existsSync(CACHE_FILE)) {
26
+ return JSON.parse(readFileSync(CACHE_FILE, "utf-8"));
27
+ }
28
+ } catch {
29
+ return { lastCheck: 0, latestVersion: null };
30
+ }
31
+ return { lastCheck: 0, latestVersion: null };
32
+ }
33
+
34
+ function writeCache(cache: UpdateCache): void {
35
+ try {
36
+ writeFileSync(CACHE_FILE, JSON.stringify(cache), "utf-8");
37
+ } catch {
38
+ return;
39
+ }
40
+ }
41
+
42
+ async function fetchLatestVersion(): Promise<string | null> {
43
+ try {
44
+ const response = await fetch(
45
+ `https://registry.npmjs.org/${PACKAGE_NAME}/latest`
46
+ );
47
+ if (!response.ok) {
48
+ return null;
49
+ }
50
+ const data = (await response.json()) as { version?: string };
51
+ return data.version || null;
52
+ } catch {
53
+ return null;
54
+ }
55
+ }
56
+
57
+ function getCurrentVersion(): string {
58
+ return CURRENT_VERSION;
59
+ }
60
+
61
+ function compareVersions(current: string, latest: string): number {
62
+ const currentParts = current.split(".").map(Number);
63
+ const latestParts = latest.split(".").map(Number);
64
+
65
+ for (let i = 0; i < 3; i++) {
66
+ const c = currentParts[i] || 0;
67
+ const l = latestParts[i] || 0;
68
+ if (l > c) {
69
+ return 1;
70
+ }
71
+ if (l < c) {
72
+ return -1;
73
+ }
74
+ }
75
+ return 0;
76
+ }
77
+
78
+ export async function checkForUpdates(): Promise<void> {
79
+ const cache = readCache();
80
+ const now = Date.now();
81
+
82
+ if (now - cache.lastCheck < CHECK_INTERVAL_MS && cache.latestVersion) {
83
+ const current = getCurrentVersion();
84
+ if (compareVersions(current, cache.latestVersion) > 0) {
85
+ printUpdateNotice(current, cache.latestVersion);
86
+ }
87
+ return;
88
+ }
89
+
90
+ const latestVersion = await fetchLatestVersion();
91
+ writeCache({ lastCheck: now, latestVersion });
92
+
93
+ if (latestVersion) {
94
+ const current = getCurrentVersion();
95
+ if (compareVersions(current, latestVersion) > 0) {
96
+ printUpdateNotice(current, latestVersion);
97
+ }
98
+ }
99
+ }
100
+
101
+ function printUpdateNotice(current: string, latest: string): void {
102
+ console.log();
103
+ console.log(
104
+ chalk.yellow(" ╭─────────────────────────────────────────────────────╮")
105
+ );
106
+ console.log(
107
+ chalk.yellow(" │ │")
108
+ );
109
+ console.log(
110
+ chalk.yellow(
111
+ ` │ Update available: ${chalk.dim(current)} → ${chalk.green(latest)} │`
112
+ )
113
+ );
114
+ console.log(
115
+ chalk.yellow(
116
+ ` │ Run ${chalk.cyan("bun add -g @anaclumos/taal")} to update │`
117
+ )
118
+ );
119
+ console.log(
120
+ chalk.yellow(" │ │")
121
+ );
122
+ console.log(
123
+ chalk.yellow(" ╰─────────────────────────────────────────────────────╯")
124
+ );
125
+ console.log();
126
+ }