@zentao-hub/cli 0.1.0

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.
Files changed (81) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +175 -0
  3. package/README.zh-CN.md +192 -0
  4. package/dist/agents.d.ts +62 -0
  5. package/dist/agents.js +202 -0
  6. package/dist/agents.js.map +1 -0
  7. package/dist/commands/init.d.ts +9 -0
  8. package/dist/commands/init.js +94 -0
  9. package/dist/commands/init.js.map +1 -0
  10. package/dist/commands/install-claude-md.d.ts +12 -0
  11. package/dist/commands/install-claude-md.js +25 -0
  12. package/dist/commands/install-claude-md.js.map +1 -0
  13. package/dist/commands/install-commands.d.ts +8 -0
  14. package/dist/commands/install-commands.js +27 -0
  15. package/dist/commands/install-commands.js.map +1 -0
  16. package/dist/commands/install-hooks.d.ts +7 -0
  17. package/dist/commands/install-hooks.js +31 -0
  18. package/dist/commands/install-hooks.js.map +1 -0
  19. package/dist/commands/install-mcp.d.ts +20 -0
  20. package/dist/commands/install-mcp.js +203 -0
  21. package/dist/commands/install-mcp.js.map +1 -0
  22. package/dist/commands/login.d.ts +17 -0
  23. package/dist/commands/login.js +110 -0
  24. package/dist/commands/login.js.map +1 -0
  25. package/dist/commands/logout.d.ts +7 -0
  26. package/dist/commands/logout.js +59 -0
  27. package/dist/commands/logout.js.map +1 -0
  28. package/dist/commands/profiles.d.ts +5 -0
  29. package/dist/commands/profiles.js +26 -0
  30. package/dist/commands/profiles.js.map +1 -0
  31. package/dist/commands/register.d.ts +12 -0
  32. package/dist/commands/register.js +26 -0
  33. package/dist/commands/register.js.map +1 -0
  34. package/dist/commands/repos.d.ts +8 -0
  35. package/dist/commands/repos.js +28 -0
  36. package/dist/commands/repos.js.map +1 -0
  37. package/dist/commands/uninstall-claude-md.d.ts +6 -0
  38. package/dist/commands/uninstall-claude-md.js +13 -0
  39. package/dist/commands/uninstall-claude-md.js.map +1 -0
  40. package/dist/commands/uninstall-commands.d.ts +7 -0
  41. package/dist/commands/uninstall-commands.js +21 -0
  42. package/dist/commands/uninstall-commands.js.map +1 -0
  43. package/dist/commands/uninstall-hooks.d.ts +6 -0
  44. package/dist/commands/uninstall-hooks.js +36 -0
  45. package/dist/commands/uninstall-hooks.js.map +1 -0
  46. package/dist/commands/uninstall-mcp.d.ts +8 -0
  47. package/dist/commands/uninstall-mcp.js +99 -0
  48. package/dist/commands/uninstall-mcp.js.map +1 -0
  49. package/dist/commands/uninstall.d.ts +14 -0
  50. package/dist/commands/uninstall.js +28 -0
  51. package/dist/commands/uninstall.js.map +1 -0
  52. package/dist/commands/use.d.ts +6 -0
  53. package/dist/commands/use.js +20 -0
  54. package/dist/commands/use.js.map +1 -0
  55. package/dist/commands/whoami.d.ts +6 -0
  56. package/dist/commands/whoami.js +48 -0
  57. package/dist/commands/whoami.js.map +1 -0
  58. package/dist/commands/workspace.d.ts +8 -0
  59. package/dist/commands/workspace.js +28 -0
  60. package/dist/commands/workspace.js.map +1 -0
  61. package/dist/index.d.ts +2 -0
  62. package/dist/index.js +496 -0
  63. package/dist/index.js.map +1 -0
  64. package/dist/paths.d.ts +16 -0
  65. package/dist/paths.js +36 -0
  66. package/dist/paths.js.map +1 -0
  67. package/dist/prompt.d.ts +7 -0
  68. package/dist/prompt.js +43 -0
  69. package/dist/prompt.js.map +1 -0
  70. package/dist/registry.d.ts +16 -0
  71. package/dist/registry.js +42 -0
  72. package/dist/registry.js.map +1 -0
  73. package/dist/util.d.ts +27 -0
  74. package/dist/util.js +70 -0
  75. package/dist/util.js.map +1 -0
  76. package/package.json +57 -0
  77. package/templates/.claude/commands/bug-analyze.md +46 -0
  78. package/templates/.claude/commands/fix-bug.md +193 -0
  79. package/templates/.githooks/commit-msg +47 -0
  80. package/templates/CLAUDE.md +86 -0
  81. package/templates/repos.yaml.example +26 -0
@@ -0,0 +1,9 @@
1
+ interface Options {
2
+ workspace?: string;
3
+ profile?: string;
4
+ credentials?: string;
5
+ force?: boolean;
6
+ migrateLegacy?: boolean;
7
+ }
8
+ export declare function init(opts: Options): Promise<void>;
9
+ export {};
@@ -0,0 +1,94 @@
1
+ import fs from "node:fs/promises";
2
+ import { existsSync } from "node:fs";
3
+ import path from "node:path";
4
+ import { TEMPLATES_DIR, resolveWorkspace, resolveHubRoot } from "../paths.js";
5
+ import { DEFAULT_PROFILE_NAME, resolveCredentialsPath, resolveProfileName, } from "@zentao-hub/sdk";
6
+ import { CliError, copyFile, info, warn } from "../util.js";
7
+ export async function init(opts) {
8
+ const credsPath = resolveCredentialsPath(opts.credentials);
9
+ const profile = await resolveProfileName(opts.profile, credsPath);
10
+ const workspace = resolveWorkspace(profile, opts.workspace);
11
+ const root = resolveHubRoot();
12
+ await maybeMigrateLegacy({
13
+ root,
14
+ workspace,
15
+ profile,
16
+ explicitWorkspace: opts.workspace,
17
+ migrate: opts.migrateLegacy ?? false,
18
+ });
19
+ info(`Initializing workspace at ${workspace} (profile '${profile}')`);
20
+ await fs.mkdir(path.join(workspace, "bugs"), { recursive: true });
21
+ info(` ok bugs/`);
22
+ const example = path.join(TEMPLATES_DIR, "repos.yaml.example");
23
+ const exampleOut = path.join(workspace, "repos.yaml.example");
24
+ await copyFile(example, exampleOut, { overwrite: true });
25
+ info(` ok repos.yaml.example`);
26
+ const registry = path.join(workspace, "repos.yaml");
27
+ if (!existsSync(registry) || opts.force) {
28
+ await fs.writeFile(registry, "products: {}\n", "utf8");
29
+ info(` ok repos.yaml`);
30
+ }
31
+ else {
32
+ info(` skip repos.yaml (exists; pass --force to overwrite)`);
33
+ }
34
+ info(``);
35
+ info(`Tip: export ZENTAO_HUB=${root}`);
36
+ info(` (the CLI / slash commands append the active profile to that root.)`);
37
+ }
38
+ async function maybeMigrateLegacy(opts) {
39
+ // When the user passes --workspace explicitly they have chosen an exact
40
+ // directory; skip the legacy detection so we don't surprise them.
41
+ if (opts.explicitWorkspace)
42
+ return;
43
+ const legacyBugs = path.join(opts.root, "bugs");
44
+ const legacyRegistry = path.join(opts.root, "repos.yaml");
45
+ const legacyExample = path.join(opts.root, "repos.yaml.example");
46
+ const hasLegacy = existsSync(legacyBugs) || existsSync(legacyRegistry);
47
+ if (!hasLegacy)
48
+ return;
49
+ if (!opts.migrate) {
50
+ warn(`Detected legacy layout at ${opts.root} (bugs/ or repos.yaml at the root).`);
51
+ warn(`Workspaces are now per-profile: ${opts.workspace}`);
52
+ warn(`Re-run with --migrate-legacy to move the legacy files into the '${opts.profile}' profile, or pass --workspace ${opts.root} to keep using the flat layout for this profile.`);
53
+ return;
54
+ }
55
+ if (opts.profile !== DEFAULT_PROFILE_NAME) {
56
+ throw new CliError(`--migrate-legacy only makes sense for the default profile; got '${opts.profile}'. The legacy flat layout never had a notion of profiles.`);
57
+ }
58
+ await fs.mkdir(opts.workspace, { recursive: true });
59
+ for (const [src, name] of [
60
+ [legacyBugs, "bugs/"],
61
+ [legacyRegistry, "repos.yaml"],
62
+ [legacyExample, "repos.yaml.example"],
63
+ ]) {
64
+ if (!existsSync(src))
65
+ continue;
66
+ const dest = path.join(opts.workspace, name.replace(/\/$/, ""));
67
+ if (existsSync(dest)) {
68
+ // A prior no-flag init may have left an empty placeholder here;
69
+ // overwrite it so the migration still works on a second pass.
70
+ const overridable = await isEmptyPlaceholder(dest);
71
+ if (!overridable) {
72
+ warn(` skip ${name} (already exists at ${dest} with content)`);
73
+ continue;
74
+ }
75
+ await fs.rm(dest, { recursive: true, force: true });
76
+ }
77
+ await fs.rename(src, dest);
78
+ info(` move ${src} → ${dest}`);
79
+ }
80
+ }
81
+ async function isEmptyPlaceholder(p) {
82
+ const stat = await fs.stat(p);
83
+ if (stat.isDirectory()) {
84
+ const entries = await fs.readdir(p);
85
+ return entries.length === 0;
86
+ }
87
+ if (stat.isFile()) {
88
+ const text = (await fs.readFile(p, "utf8")).trim();
89
+ // Empty file, or the default registry skeleton written by init.
90
+ return text === "" || text === "products: {}";
91
+ }
92
+ return false;
93
+ }
94
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ interface Options {
2
+ agent?: string;
3
+ repo?: string;
4
+ force?: boolean;
5
+ }
6
+ /**
7
+ * Install the AI-collaboration instructions file for the chosen agent.
8
+ * The template is the same regardless of agent — only the destination
9
+ * filename differs (CLAUDE.md / AGENTS.md / .github/copilot-instructions.md).
10
+ */
11
+ export declare function installClaudeMd(opts: Options): Promise<void>;
12
+ export {};
@@ -0,0 +1,25 @@
1
+ import path from "node:path";
2
+ import { describeAgent, resolveAgent, resolveAgentInstructionsFile, } from "../agents.js";
3
+ import { TEMPLATES_DIR } from "../paths.js";
4
+ import { copyFile, info } from "../util.js";
5
+ /**
6
+ * Install the AI-collaboration instructions file for the chosen agent.
7
+ * The template is the same regardless of agent — only the destination
8
+ * filename differs (CLAUDE.md / AGENTS.md / .github/copilot-instructions.md).
9
+ */
10
+ export async function installClaudeMd(opts) {
11
+ const agent = await resolveAgent(opts.agent);
12
+ const repo = path.resolve(opts.repo ?? process.cwd());
13
+ const { abs: dest, rel } = resolveAgentInstructionsFile(agent, repo);
14
+ const src = path.join(TEMPLATES_DIR, "CLAUDE.md");
15
+ info(`Installing ${describeAgent(agent)} instructions to ${dest}`);
16
+ const result = await copyFile(src, dest, { overwrite: opts.force });
17
+ if (result === "skipped") {
18
+ info(` skip ${rel} (exists; pass --force to overwrite)`);
19
+ }
20
+ else {
21
+ info(` ok ${rel}`);
22
+ info(` Remember to fill in the "Test commands" and "Code style" sections.`);
23
+ }
24
+ }
25
+ //# sourceMappingURL=install-claude-md.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-claude-md.js","sourceRoot":"","sources":["../../src/commands/install-claude-md.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,aAAa,EACb,YAAY,EACZ,4BAA4B,GAC7B,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAQ5C;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAa;IACjD,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACtD,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,4BAA4B,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACrE,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IAClD,IAAI,CAAC,cAAc,aAAa,CAAC,KAAK,CAAC,oBAAoB,IAAI,EAAE,CAAC,CAAC;IACnE,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IACpE,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,IAAI,CAAC,WAAW,GAAG,sCAAsC,CAAC,CAAC;IAC7D,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC,CAAC;QACvB,IAAI,CAAC,sEAAsE,CAAC,CAAC;IAC/E,CAAC;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ interface Options {
2
+ agent?: string;
3
+ dest?: string;
4
+ repo?: string;
5
+ force?: boolean;
6
+ }
7
+ export declare function installCommands(opts: Options): Promise<void>;
8
+ export {};
@@ -0,0 +1,27 @@
1
+ import path from "node:path";
2
+ import { describeAgent, resolveAgent, resolveAgentPromptsDir, } from "../agents.js";
3
+ import { TEMPLATES_DIR } from "../paths.js";
4
+ import { copyFile, info } from "../util.js";
5
+ const FILES = ["fix-bug.md", "bug-analyze.md"];
6
+ export async function installCommands(opts) {
7
+ const agent = await resolveAgent(opts.agent);
8
+ const { dir: dest, suffix, scope } = resolveAgentPromptsDir(agent, {
9
+ explicit: opts.dest,
10
+ repo: opts.repo,
11
+ });
12
+ info(`Installing slash commands for ${describeAgent(agent)} (${scope}-scope) → ${dest}`);
13
+ for (const name of FILES) {
14
+ const src = path.join(TEMPLATES_DIR, ".claude", "commands", name);
15
+ const outName = suffix === ".md" ? name : name.replace(/\.md$/, suffix);
16
+ const out = path.join(dest, outName);
17
+ const result = await copyFile(src, out, { overwrite: opts.force });
18
+ if (result === "skipped") {
19
+ info(` skip ${outName} (exists; pass --force to overwrite)`);
20
+ }
21
+ else {
22
+ info(` ok ${outName}`);
23
+ }
24
+ }
25
+ info(`Done. Tip: export ZENTAO_HUB=<path> so the commands know where to drop bug context (default: ~/.zentao-hub).`);
26
+ }
27
+ //# sourceMappingURL=install-commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-commands.js","sourceRoot":"","sources":["../../src/commands/install-commands.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,aAAa,EACb,YAAY,EACZ,sBAAsB,GACvB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAS5C,MAAM,KAAK,GAAG,CAAC,YAAY,EAAE,gBAAgB,CAAU,CAAC;AAExD,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAa;IACjD,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7C,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,sBAAsB,CAAC,KAAK,EAAE;QACjE,QAAQ,EAAE,IAAI,CAAC,IAAI;QACnB,IAAI,EAAE,IAAI,CAAC,IAAI;KAChB,CAAC,CAAC;IACH,IAAI,CACF,iCAAiC,aAAa,CAAC,KAAK,CAAC,KAAK,KAAK,aAAa,IAAI,EAAE,CACnF,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;QAClE,MAAM,OAAO,GAAG,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACxE,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACrC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QACnE,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,IAAI,CAAC,WAAW,OAAO,sCAAsC,CAAC,CAAC;QACjE,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,WAAW,OAAO,EAAE,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IACD,IAAI,CAAC,8GAA8G,CAAC,CAAC;AACvH,CAAC"}
@@ -0,0 +1,7 @@
1
+ interface Options {
2
+ repo?: string;
3
+ force?: boolean;
4
+ setHooksPath?: boolean;
5
+ }
6
+ export declare function installHooks(opts: Options): Promise<void>;
7
+ export {};
@@ -0,0 +1,31 @@
1
+ import path from "node:path";
2
+ import { TEMPLATES_DIR } from "../paths.js";
3
+ import { CliError, copyFile, ensureExecutable, git, info, isGitRepo } from "../util.js";
4
+ export async function installHooks(opts) {
5
+ const repo = path.resolve(opts.repo ?? process.cwd());
6
+ if (!isGitRepo(repo)) {
7
+ throw new CliError(`${repo} is not a git repository`);
8
+ }
9
+ const srcHook = path.join(TEMPLATES_DIR, ".githooks", "commit-msg");
10
+ const destHook = path.join(repo, ".githooks", "commit-msg");
11
+ info(`Installing commit-msg hook to ${destHook}`);
12
+ const result = await copyFile(srcHook, destHook, { overwrite: opts.force });
13
+ if (result === "skipped") {
14
+ info(` skip commit-msg (exists; pass --force to overwrite)`);
15
+ }
16
+ else {
17
+ info(` ok commit-msg`);
18
+ }
19
+ await ensureExecutable(destHook);
20
+ if (opts.setHooksPath !== false) {
21
+ const r = git(repo, ["config", "core.hooksPath", ".githooks"]);
22
+ if (r.status === 0) {
23
+ info(` ok git config core.hooksPath .githooks`);
24
+ }
25
+ else {
26
+ throw new CliError(`failed to set core.hooksPath: ${r.stderr.trim() || r.stdout.trim()}`);
27
+ }
28
+ }
29
+ info(`Done. Verify: echo "fix: test 🤖 generated with claude" | .githooks/commit-msg /dev/stdin`);
30
+ }
31
+ //# sourceMappingURL=install-hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-hooks.js","sourceRoot":"","sources":["../../src/commands/install-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,gBAAgB,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAQxF,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAa;IAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACtD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,QAAQ,CAAC,GAAG,IAAI,0BAA0B,CAAC,CAAC;IACxD,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,EAAE,YAAY,CAAC,CAAC;IACpE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,YAAY,CAAC,CAAC;IAC5D,IAAI,CAAC,iCAAiC,QAAQ,EAAE,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IAC5E,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,IAAI,CAAC,wDAAwD,CAAC,CAAC;IACjE,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,oBAAoB,CAAC,CAAC;IAC7B,CAAC;IACD,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAEjC,IAAI,IAAI,CAAC,YAAY,KAAK,KAAK,EAAE,CAAC;QAChC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,gBAAgB,EAAE,WAAW,CAAC,CAAC,CAAC;QAC/D,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnB,IAAI,CAAC,6CAA6C,CAAC,CAAC;QACtD,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,QAAQ,CAAC,iCAAiC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC5F,CAAC;IACH,CAAC;IACD,IAAI,CAAC,2FAA2F,CAAC,CAAC;AACpG,CAAC"}
@@ -0,0 +1,20 @@
1
+ interface Options {
2
+ agent?: string;
3
+ /** "user" (default) or "workspace". */
4
+ scope?: string;
5
+ /** Repo root for workspace scope. */
6
+ repo?: string;
7
+ /** MCP server name to register under (default "zentao-hub"). */
8
+ name?: string;
9
+ /** Override the command used to spawn the server (default "zentao-hub-mcp"). */
10
+ command?: string;
11
+ /** Bind a specific credentials profile. Defaults to the active default. */
12
+ profile?: string;
13
+ /** Skip ZENTAO_PROFILE env binding (server will fall back to file default). */
14
+ noProfile?: boolean;
15
+ /** Force overwrite an existing entry with the same name. */
16
+ force?: boolean;
17
+ credentials?: string;
18
+ }
19
+ export declare function installMcp(opts: Options): Promise<void>;
20
+ export {};
@@ -0,0 +1,203 @@
1
+ import fs from "node:fs/promises";
2
+ import { existsSync } from "node:fs";
3
+ import path from "node:path";
4
+ import { describeAgent, resolveAgent, resolveMcpTarget, } from "../agents.js";
5
+ import { DEFAULT_PROFILE_NAME, readStore, resolveCredentialsPath, } from "@zentao-hub/sdk";
6
+ import { CliError, info, warn } from "../util.js";
7
+ const DEFAULT_SERVER_NAME = "zentao-hub";
8
+ const DEFAULT_COMMAND = "zentao-hub-mcp";
9
+ export async function installMcp(opts) {
10
+ const agent = await resolveAgent(opts.agent);
11
+ const scope = parseScope(opts.scope);
12
+ const target = resolveMcpTarget(agent, { scope, repo: opts.repo });
13
+ // Default ZENTAO_PROFILE to the active profile, but only when the store is
14
+ // available — otherwise the user clearly intends to wire env vars manually.
15
+ const profile = await resolveProfile(opts);
16
+ const serverName = (opts.name ?? DEFAULT_SERVER_NAME).trim();
17
+ if (!serverName)
18
+ throw new CliError("--name must not be empty");
19
+ const command = (opts.command ?? DEFAULT_COMMAND).trim();
20
+ if (!command)
21
+ throw new CliError("--command must not be empty");
22
+ const env = {};
23
+ if (profile && !opts.noProfile) {
24
+ env.ZENTAO_PROFILE = profile;
25
+ }
26
+ info(`Configuring MCP server '${serverName}' for ${describeAgent(agent)}`);
27
+ info(` target ${target.path}`);
28
+ info(` format ${target.format}${target.scope === "workspace" ? " (workspace)" : " (user)"}`);
29
+ await ensureParentDir(target.path);
30
+ if (target.format === "json") {
31
+ await writeJsonMcp(target, serverName, command, env, !!opts.force);
32
+ }
33
+ else {
34
+ await writeTomlMcp(target, serverName, command, env, !!opts.force);
35
+ }
36
+ info(` ok server '${serverName}' written`);
37
+ if (!profile && !opts.noProfile) {
38
+ warn(`no credentials file found — wrote MCP entry without ZENTAO_PROFILE. ` +
39
+ `Run 'zentao-hub login' first, or set ZENTAO_URL/USERNAME/PASSWORD manually.`);
40
+ }
41
+ printHints(agent, target, serverName);
42
+ }
43
+ function parseScope(raw) {
44
+ if (!raw)
45
+ return "user";
46
+ const v = raw.toLowerCase();
47
+ if (v === "user" || v === "workspace" || v === "project") {
48
+ return v === "project" ? "workspace" : v;
49
+ }
50
+ throw new CliError(`--scope must be 'user' or 'workspace', got '${raw}'`);
51
+ }
52
+ async function resolveProfile(opts) {
53
+ if (opts.profile)
54
+ return opts.profile;
55
+ if (opts.noProfile)
56
+ return undefined;
57
+ const credsPath = resolveCredentialsPath(opts.credentials);
58
+ const store = await readStore(credsPath).catch(() => undefined);
59
+ if (!store)
60
+ return undefined;
61
+ return store.default ?? DEFAULT_PROFILE_NAME;
62
+ }
63
+ async function ensureParentDir(filePath) {
64
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
65
+ }
66
+ async function writeJsonMcp(target, name, command, env, force) {
67
+ const key = target.jsonKey ?? "mcpServers";
68
+ const existing = await readJsonObject(target.path);
69
+ const map = existing[key] ?? {};
70
+ if (map[name] && !force) {
71
+ throw new CliError(`Server '${name}' is already configured in ${target.path}. ` +
72
+ `Pass --force to overwrite, or --name <other> to add a second entry.`);
73
+ }
74
+ // Copilot uses { type: "stdio", command, args, env }. Claude omits "type"
75
+ // and only requires command/args/env. Both accept the Copilot shape, but
76
+ // including a stray "type" breaks Claude — so we branch.
77
+ const entry = key === "servers"
78
+ ? { type: "stdio", command, args: [], env }
79
+ : { command, args: [], env };
80
+ if (Object.keys(env).length === 0) {
81
+ delete entry.env;
82
+ }
83
+ map[name] = entry;
84
+ existing[key] = map;
85
+ await fs.writeFile(target.path, JSON.stringify(existing, null, 2) + "\n", "utf8");
86
+ }
87
+ async function readJsonObject(filePath) {
88
+ if (!existsSync(filePath))
89
+ return {};
90
+ const text = await fs.readFile(filePath, "utf8");
91
+ const trimmed = text.trim();
92
+ if (!trimmed)
93
+ return {};
94
+ try {
95
+ const parsed = JSON.parse(trimmed);
96
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
97
+ return parsed;
98
+ }
99
+ }
100
+ catch (err) {
101
+ throw new CliError(`Failed to parse ${filePath} as JSON: ${err.message}. ` +
102
+ `Fix the file by hand or remove it and re-run.`);
103
+ }
104
+ throw new CliError(`${filePath} does not contain a JSON object at the top level`);
105
+ }
106
+ async function writeTomlMcp(target, name, command, env, force) {
107
+ const prefix = target.tomlSectionPrefix ?? "mcp_servers";
108
+ const header = `[${prefix}.${name}]`;
109
+ const existing = existsSync(target.path) ? await fs.readFile(target.path, "utf8") : "";
110
+ if (sectionExists(existing, header) && !force) {
111
+ throw new CliError(`Section '${header}' already exists in ${target.path}. ` +
112
+ `Pass --force to overwrite, or --name <other> to add a second entry.`);
113
+ }
114
+ const block = renderTomlSection(header, command, env);
115
+ const next = upsertTomlSection(existing, header, block);
116
+ await fs.writeFile(target.path, next, "utf8");
117
+ }
118
+ function sectionExists(text, header) {
119
+ return text.split("\n").some((line) => line.trim() === header);
120
+ }
121
+ function renderTomlSection(header, command, env) {
122
+ const lines = [header];
123
+ lines.push(`command = ${tomlString(command)}`);
124
+ lines.push(`args = []`);
125
+ const envKeys = Object.keys(env);
126
+ if (envKeys.length > 0) {
127
+ const pairs = envKeys.map((k) => `${k} = ${tomlString(env[k])}`).join(", ");
128
+ lines.push(`env = { ${pairs} }`);
129
+ }
130
+ return lines.join("\n") + "\n";
131
+ }
132
+ function tomlString(value) {
133
+ // Basic-string escaping per TOML spec.
134
+ const escaped = value
135
+ .replace(/\\/g, "\\\\")
136
+ .replace(/"/g, '\\"')
137
+ .replace(/\n/g, "\\n")
138
+ .replace(/\r/g, "\\r")
139
+ .replace(/\t/g, "\\t");
140
+ return `"${escaped}"`;
141
+ }
142
+ /**
143
+ * Replace an existing `[section]` block with `block`, or append it. The block
144
+ * runs until the next top-level `[...]` header. This is intentionally a
145
+ * text-level edit so we don't depend on a TOML library — Codex's config is
146
+ * small and the section header we touch is well-defined.
147
+ */
148
+ function upsertTomlSection(text, header, block) {
149
+ const lines = text.length === 0 ? [] : text.split("\n");
150
+ let startIdx = -1;
151
+ let endIdx = -1;
152
+ for (let i = 0; i < lines.length; i++) {
153
+ if (lines[i].trim() === header) {
154
+ startIdx = i;
155
+ for (let j = i + 1; j < lines.length; j++) {
156
+ if (/^\s*\[/.test(lines[j])) {
157
+ endIdx = j;
158
+ break;
159
+ }
160
+ }
161
+ if (endIdx === -1)
162
+ endIdx = lines.length;
163
+ break;
164
+ }
165
+ }
166
+ if (startIdx === -1) {
167
+ const needsSep = text.length > 0 && !text.endsWith("\n\n");
168
+ const sep = text.length === 0 ? "" : text.endsWith("\n") ? "\n" : "\n\n";
169
+ const prefix = needsSep ? sep : "";
170
+ const suffix = block.endsWith("\n") ? "" : "\n";
171
+ return text + prefix + block + suffix;
172
+ }
173
+ const before = lines.slice(0, startIdx).join("\n");
174
+ const after = lines.slice(endIdx).join("\n");
175
+ const beforePart = before.length > 0 && !before.endsWith("\n") ? before + "\n" : before;
176
+ const blockPart = block.endsWith("\n") ? block : block + "\n";
177
+ return beforePart + blockPart + after;
178
+ }
179
+ function printHints(agent, target, serverName) {
180
+ info(``);
181
+ switch (agent) {
182
+ case "claude":
183
+ info(`Tip: restart Claude Code (or run '/mcp') and you should see '${serverName}'.`);
184
+ break;
185
+ case "copilot":
186
+ info(`Tip: reload the VS Code window. Open the Chat view and pick '${serverName}' as a tool.`);
187
+ if (target.scope === "workspace") {
188
+ info(` Commit .vscode/mcp.json if you want teammates to share this config.`);
189
+ }
190
+ break;
191
+ case "copilot-cli":
192
+ info(`Tip: restart 'copilot' and run '/mcp list' to confirm '${serverName}' is registered.`);
193
+ if (target.scope === "workspace") {
194
+ info(` Commit .mcp.json if you want teammates to share this config — both`);
195
+ info(` Copilot CLI and Claude Code read it.`);
196
+ }
197
+ break;
198
+ case "codex":
199
+ info(`Tip: restart 'codex' and run '/mcp' to confirm '${serverName}' is registered.`);
200
+ break;
201
+ }
202
+ }
203
+ //# sourceMappingURL=install-mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-mcp.js","sourceRoot":"","sources":["../../src/commands/install-mcp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ interface Options {
2
+ url?: string;
3
+ username?: string;
4
+ password?: string;
5
+ profile?: string;
6
+ setDefault?: boolean;
7
+ credentials?: string;
8
+ /** Tri-state for password caching:
9
+ * undefined → auto (save if keychain available, skip otherwise)
10
+ * true → fail loudly if keychain unavailable
11
+ * false → never save, even if keychain available
12
+ */
13
+ savePassword?: boolean;
14
+ timeoutMs?: number;
15
+ }
16
+ export declare function login(opts: Options): Promise<void>;
17
+ export {};
@@ -0,0 +1,110 @@
1
+ import { DEFAULT_PROFILE_NAME, ZentaoClient, accountKey, detectBackend, readStore, resolveCredentialsPath, writeStore, } from "@zentao-hub/sdk";
2
+ import { promptLine, promptSecret } from "../prompt.js";
3
+ import { CliError, info, warn } from "../util.js";
4
+ const PROFILE_NAME_PATTERN = /^[a-zA-Z0-9._-]+$/;
5
+ export async function login(opts) {
6
+ // Read existing store first: it's needed both for the prompt suggestion
7
+ // and (later) for merging the new profile in.
8
+ const credsPath = resolveCredentialsPath(opts.credentials);
9
+ const existing = (await readStore(credsPath).catch(() => undefined));
10
+ // Interactive mode = at least one of url/username/password was not supplied
11
+ // via flags. In script mode (everything via flags) we skip the profile
12
+ // prompt too, so the call doesn't block waiting on stdin.
13
+ const interactive = !opts.url || !opts.username || !opts.password;
14
+ const profile = (opts.profile ?? (await resolveProfileName(existing, interactive))).trim();
15
+ if (!PROFILE_NAME_PATTERN.test(profile)) {
16
+ throw new CliError(`Invalid profile name '${profile}'. Allowed: letters, digits, '.', '_', '-'`);
17
+ }
18
+ if (existing?.profiles[profile]) {
19
+ info(`Note: profile '${profile}' already exists and will be overwritten.`);
20
+ }
21
+ const baseUrl = (opts.url ?? (await promptLine("ZenTao URL: "))).trim();
22
+ if (!baseUrl)
23
+ throw new CliError("ZenTao URL is required");
24
+ if (!/^https?:\/\//i.test(baseUrl)) {
25
+ throw new CliError(`ZenTao URL must start with http(s)://, got '${baseUrl}'`);
26
+ }
27
+ const username = (opts.username ?? (await promptLine("Username: "))).trim();
28
+ if (!username)
29
+ throw new CliError("username is required");
30
+ const password = opts.password ?? (await promptSecret("Password: "));
31
+ if (!password)
32
+ throw new CliError("password is required");
33
+ info(`Authenticating against ${baseUrl} as ${username} (profile '${profile}')...`);
34
+ const token = await ZentaoClient.fetchToken(baseUrl, username, password, opts.timeoutMs);
35
+ const cleanUrl = baseUrl.replace(/\/+$/, "");
36
+ const newProfile = {
37
+ baseUrl: cleanUrl,
38
+ username,
39
+ token,
40
+ createdAt: new Date().toISOString(),
41
+ };
42
+ const store = existing
43
+ ? { ...existing, profiles: { ...existing.profiles, [profile]: newProfile } }
44
+ : {
45
+ schemaVersion: 2,
46
+ default: profile,
47
+ profiles: { [profile]: newProfile },
48
+ };
49
+ // First profile in a fresh file is always the default; explicit
50
+ // --set-default flips it regardless.
51
+ if (!existing) {
52
+ store.default = profile;
53
+ }
54
+ else if (opts.setDefault) {
55
+ store.default = profile;
56
+ }
57
+ await writeStore(credsPath, store);
58
+ const isDefault = store.default === profile;
59
+ info(`Logged in. Profile '${profile}'${isDefault ? " (default)" : ""} saved to ${credsPath}`);
60
+ await savePasswordIfApplicable(cleanUrl, username, password, opts.savePassword);
61
+ }
62
+ /**
63
+ * Resolve the profile name. In interactive mode prompt for it (defaulting
64
+ * to "default"); in script mode (all flags supplied) silently use "default"
65
+ * so the call never blocks waiting on stdin. If a file already exists, list
66
+ * its profiles to help the user avoid accidental name collisions — the main
67
+ * flow still prints a clear "will overwrite" note if they pick an existing
68
+ * name, which is fine when re-logging the same profile to refresh its token.
69
+ */
70
+ async function resolveProfileName(existing, interactive) {
71
+ if (!interactive)
72
+ return DEFAULT_PROFILE_NAME;
73
+ if (existing) {
74
+ info(`Existing profiles: ${Object.keys(existing.profiles).join(", ")} ` +
75
+ `(default: ${existing.default})`);
76
+ }
77
+ const entered = (await promptLine(`Profile name [${DEFAULT_PROFILE_NAME}]: `)).trim();
78
+ return entered || DEFAULT_PROFILE_NAME;
79
+ }
80
+ async function savePasswordIfApplicable(baseUrl, username, password, preference) {
81
+ if (preference === false) {
82
+ info(``);
83
+ info(`Password not cached (--no-save-password). MCP server will be unable`);
84
+ info(`to auto-refresh the token; rerun 'zentao-hub login' when it expires.`);
85
+ return;
86
+ }
87
+ const backend = detectBackend();
88
+ if (!backend.available) {
89
+ const msg = `No system keychain available: ${backend.unavailableReason ?? "unsupported platform"}`;
90
+ if (preference === true)
91
+ throw new CliError(msg);
92
+ warn(msg);
93
+ warn(`Password will not be cached. Token works until it expires; rerun 'zentao-hub login' afterwards.`);
94
+ return;
95
+ }
96
+ try {
97
+ await backend.set(accountKey(baseUrl, username), password);
98
+ info(``);
99
+ info(`Password saved to ${backend.name}. MCP server will auto-refresh the`);
100
+ info(`token when it expires.`);
101
+ }
102
+ catch (err) {
103
+ const msg = `Failed to save password to ${backend.name}: ${err.message}`;
104
+ if (preference === true)
105
+ throw new CliError(msg);
106
+ warn(msg);
107
+ warn(`Token was still stored, but auto-refresh is disabled.`);
108
+ }
109
+ }
110
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ interface Options {
2
+ profile?: string;
3
+ all?: boolean;
4
+ credentials?: string;
5
+ }
6
+ export declare function logout(opts: Options): Promise<void>;
7
+ export {};