@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.
- package/.github/workflows/publish.yml +2 -3
- package/AGENTS.md +7 -7
- package/README.md +15 -15
- package/package.json +1 -1
- package/src/commands/collect.ts +2 -2
- package/src/commands/init.ts +6 -6
- package/src/commands/sync.ts +5 -1
- package/src/index.ts +12 -1
- package/src/mcp.ts +36 -29
- package/src/providers/claude-code.ts +17 -2
- package/src/providers/types.ts +9 -0
- package/src/utils/update-checker.ts +126 -0
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:
|
|
70
|
-
args: ["
|
|
69
|
+
command: bunx
|
|
70
|
+
args: ["--bun", "taal-mcp"]
|
|
71
71
|
|
|
72
72
|
# stdio server example
|
|
73
73
|
filesystem:
|
|
74
|
-
command:
|
|
75
|
-
args: ["
|
|
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:
|
|
179
|
-
# args: ["
|
|
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:
|
|
159
|
-
args: ["
|
|
158
|
+
command: bunx
|
|
159
|
+
args: ["--bun", "taal-mcp"]
|
|
160
160
|
|
|
161
161
|
# Stdio server example
|
|
162
162
|
filesystem:
|
|
163
|
-
command:
|
|
164
|
-
args: ["
|
|
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:
|
|
224
|
-
args: ["
|
|
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
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
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
|
-
-
|
|
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
package/src/commands/collect.ts
CHANGED
|
@@ -182,8 +182,8 @@ export async function collectAndUpdateConfig(
|
|
|
182
182
|
version: "1",
|
|
183
183
|
mcp: {
|
|
184
184
|
taal: {
|
|
185
|
-
command: "
|
|
186
|
-
args: ["
|
|
185
|
+
command: "bunx",
|
|
186
|
+
args: ["--bun", "taal-mcp"],
|
|
187
187
|
},
|
|
188
188
|
},
|
|
189
189
|
skills: { paths: ["~/.taal/skills"] },
|
package/src/commands/init.ts
CHANGED
|
@@ -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/
|
|
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:
|
|
15
|
-
args: ["
|
|
14
|
+
command: bunx
|
|
15
|
+
args: ["--bun", "taal-mcp"]
|
|
16
16
|
# Example stdio server
|
|
17
17
|
# example-server:
|
|
18
|
-
# command:
|
|
19
|
-
# args: ["
|
|
18
|
+
# command: bunx
|
|
19
|
+
# args: ["--bun", "@example/mcp-server"]
|
|
20
20
|
# env:
|
|
21
21
|
# API_KEY: "\${API_KEY}"
|
|
22
22
|
|
package/src/commands/sync.ts
CHANGED
|
@@ -70,11 +70,15 @@ export async function sync(
|
|
|
70
70
|
const taalServers = config.mcp || {};
|
|
71
71
|
const transformedServers = provider.transformMcpServers(taalServers);
|
|
72
72
|
|
|
73
|
-
|
|
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(
|
|
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
|
|
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: "
|
|
59
|
-
args: ["
|
|
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:
|
|
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
|
}
|
package/src/providers/types.ts
CHANGED
|
@@ -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
|
+
}
|