cuekit 0.0.12
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/bin/cuekit.js +114341 -0
- package/package.json +53 -0
- package/src/bin.ts +158 -0
- package/src/dispatch.ts +93 -0
- package/src/doctor.ts +438 -0
- package/src/human-commands.ts +188 -0
- package/src/index.ts +6 -0
- package/src/jcode-mcp-config.ts +85 -0
- package/src/output.ts +21 -0
- package/src/update.ts +76 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import {
|
|
2
|
+
chmodSync,
|
|
3
|
+
existsSync,
|
|
4
|
+
mkdirSync,
|
|
5
|
+
readFileSync,
|
|
6
|
+
renameSync,
|
|
7
|
+
statSync,
|
|
8
|
+
writeFileSync,
|
|
9
|
+
} from "node:fs";
|
|
10
|
+
import { homedir } from "node:os";
|
|
11
|
+
import { dirname, join, resolve } from "node:path";
|
|
12
|
+
|
|
13
|
+
export interface JcodeMcpRegistrationOptions {
|
|
14
|
+
global: boolean;
|
|
15
|
+
cwd?: string;
|
|
16
|
+
home?: string;
|
|
17
|
+
jcodeHome?: string;
|
|
18
|
+
serverName?: string;
|
|
19
|
+
command?: string;
|
|
20
|
+
args?: string[];
|
|
21
|
+
env?: Record<string, string>;
|
|
22
|
+
shared?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface JcodeMcpRegistrationResult {
|
|
26
|
+
path: string;
|
|
27
|
+
serverName: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface JcodeMcpConfigFile {
|
|
31
|
+
servers?: Record<string, unknown>;
|
|
32
|
+
[key: string]: unknown;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function readConfig(path: string): JcodeMcpConfigFile {
|
|
36
|
+
if (!existsSync(path)) return {};
|
|
37
|
+
const parsed = JSON.parse(readFileSync(path, "utf8")) as unknown;
|
|
38
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
39
|
+
return parsed as JcodeMcpConfigFile;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function writeConfig(path: string, config: JcodeMcpConfigFile): void {
|
|
43
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
44
|
+
const tmpPath = `${path}.${process.pid}.tmp`;
|
|
45
|
+
const mode = existsSync(path) ? statSync(path).mode & 0o777 : 0o600;
|
|
46
|
+
writeFileSync(tmpPath, `${JSON.stringify(config, null, 2)}\n`, "utf8");
|
|
47
|
+
chmodSync(tmpPath, mode);
|
|
48
|
+
renameSync(tmpPath, path);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function getJcodeMcpConfigPath(
|
|
52
|
+
options: Pick<JcodeMcpRegistrationOptions, "global" | "cwd" | "home" | "jcodeHome">,
|
|
53
|
+
): string {
|
|
54
|
+
if (options.global) {
|
|
55
|
+
return join(
|
|
56
|
+
options.jcodeHome ??
|
|
57
|
+
(options.home ? join(options.home, ".jcode") : process.env.JCODE_HOME) ??
|
|
58
|
+
join(homedir(), ".jcode"),
|
|
59
|
+
"mcp.json",
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
return resolve(options.cwd ?? process.cwd(), ".jcode", "mcp.json");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function registerJcodeMcpServer(
|
|
66
|
+
options: JcodeMcpRegistrationOptions,
|
|
67
|
+
): JcodeMcpRegistrationResult {
|
|
68
|
+
const path = getJcodeMcpConfigPath(options);
|
|
69
|
+
const serverName = options.serverName ?? "cuekit";
|
|
70
|
+
const config = readConfig(path);
|
|
71
|
+
const servers =
|
|
72
|
+
config.servers && typeof config.servers === "object" && !Array.isArray(config.servers)
|
|
73
|
+
? config.servers
|
|
74
|
+
: {};
|
|
75
|
+
|
|
76
|
+
servers[serverName] = {
|
|
77
|
+
command: options.command ?? "cuekit",
|
|
78
|
+
args: options.args ?? ["--mcp"],
|
|
79
|
+
env: options.env ?? {},
|
|
80
|
+
shared: options.shared ?? true,
|
|
81
|
+
};
|
|
82
|
+
config.servers = servers;
|
|
83
|
+
writeConfig(path, config);
|
|
84
|
+
return { path, serverName };
|
|
85
|
+
}
|
package/src/output.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type CheckLevel = "ok" | "warn" | "fail";
|
|
2
|
+
|
|
3
|
+
export type CheckLine = {
|
|
4
|
+
level: CheckLevel;
|
|
5
|
+
label: string;
|
|
6
|
+
detail: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const SYMBOLS: Record<CheckLevel, string> = {
|
|
10
|
+
ok: "✓",
|
|
11
|
+
warn: "!",
|
|
12
|
+
fail: "✗",
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export function formatCheckLine(line: CheckLine): string {
|
|
16
|
+
return `${SYMBOLS[line.level]} ${line.label}: ${line.detail}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function formatCommandBlock(label: string, command: string): string {
|
|
20
|
+
return `${label}:\n\n ${command}\n`;
|
|
21
|
+
}
|
package/src/update.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import pkg from "../package.json" with { type: "json" };
|
|
2
|
+
|
|
3
|
+
export type UpdateLatestReleaseResult = { ok: true; tag: string } | { ok: false; reason: string };
|
|
4
|
+
|
|
5
|
+
export type UpdateResult = {
|
|
6
|
+
exitCode: number;
|
|
7
|
+
stdout: string;
|
|
8
|
+
stderr?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type RunUpdateOptions = {
|
|
12
|
+
getCurrentVersion?: () => string | undefined;
|
|
13
|
+
getLatestRelease?: () => Promise<UpdateLatestReleaseResult>;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const REPO = "takemo101/cuekit";
|
|
17
|
+
|
|
18
|
+
export async function getLatestGitHubRelease(): Promise<UpdateLatestReleaseResult> {
|
|
19
|
+
try {
|
|
20
|
+
const response = await fetch(`https://api.github.com/repos/${REPO}/releases/latest`, {
|
|
21
|
+
headers: { accept: "application/vnd.github+json" },
|
|
22
|
+
});
|
|
23
|
+
if (!response.ok) return { ok: false, reason: `HTTP ${response.status}` };
|
|
24
|
+
const body = (await response.json()) as { tag_name?: unknown };
|
|
25
|
+
return typeof body.tag_name === "string" && body.tag_name.length > 0
|
|
26
|
+
? { ok: true, tag: body.tag_name }
|
|
27
|
+
: { ok: false, reason: "missing tag_name" };
|
|
28
|
+
} catch (error) {
|
|
29
|
+
return { ok: false, reason: error instanceof Error ? error.message : String(error) };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function installCommand(tag: string): string {
|
|
34
|
+
return `bun install -g github:${REPO}#${tag}`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const REMOVE_COMMAND = "bun remove -g cuekit-workspace";
|
|
38
|
+
|
|
39
|
+
export async function runUpdate(options: RunUpdateOptions = {}): Promise<UpdateResult> {
|
|
40
|
+
const current =
|
|
41
|
+
options.getCurrentVersion !== undefined
|
|
42
|
+
? (options.getCurrentVersion() ?? "unknown")
|
|
43
|
+
: (pkg.version ?? "unknown");
|
|
44
|
+
const latest = await (options.getLatestRelease ?? getLatestGitHubRelease)();
|
|
45
|
+
const lines = ["cuekit update", "", `Current: ${current}`];
|
|
46
|
+
|
|
47
|
+
if (latest.ok) {
|
|
48
|
+
lines.push(
|
|
49
|
+
`Latest: ${latest.tag}`,
|
|
50
|
+
"",
|
|
51
|
+
"Run:",
|
|
52
|
+
"",
|
|
53
|
+
` ${REMOVE_COMMAND}`,
|
|
54
|
+
` ${installCommand(latest.tag)}`,
|
|
55
|
+
"",
|
|
56
|
+
"Removing first avoids Bun global GitHub dependency-loop errors when upgrading from an older cuekit tag.",
|
|
57
|
+
"",
|
|
58
|
+
);
|
|
59
|
+
} else {
|
|
60
|
+
lines.push(
|
|
61
|
+
"Latest: unknown",
|
|
62
|
+
"",
|
|
63
|
+
`Could not fetch the latest release tag: ${latest.reason}`,
|
|
64
|
+
"Open https://github.com/takemo101/cuekit/releases and choose a release tag.",
|
|
65
|
+
"",
|
|
66
|
+
"Manual update pattern:",
|
|
67
|
+
` ${REMOVE_COMMAND}`,
|
|
68
|
+
` ${installCommand("<release-tag>")}`,
|
|
69
|
+
"(<release-tag> is a placeholder, not a discovered version.)",
|
|
70
|
+
"",
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
lines.push("Then restart any MCP client using cuekit.", "");
|
|
75
|
+
return { exitCode: 0, stdout: lines.join("\n") };
|
|
76
|
+
}
|