@countfinancial/cli 0.1.8 → 0.2.1

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 (58) hide show
  1. package/README.md +9 -1
  2. package/dist/__tests__/doctor.test.d.ts +1 -0
  3. package/dist/__tests__/doctor.test.js +30 -0
  4. package/dist/__tests__/doctor.test.js.map +1 -0
  5. package/dist/__tests__/mcpInstall.test.d.ts +1 -0
  6. package/dist/__tests__/mcpInstall.test.js +25 -0
  7. package/dist/__tests__/mcpInstall.test.js.map +1 -0
  8. package/dist/__tests__/profileStore.test.d.ts +1 -0
  9. package/dist/__tests__/profileStore.test.js +53 -0
  10. package/dist/__tests__/profileStore.test.js.map +1 -0
  11. package/dist/cli.js +108 -9
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/doctor.command.d.ts +6 -0
  14. package/dist/commands/doctor.command.js +12 -0
  15. package/dist/commands/doctor.command.js.map +1 -0
  16. package/dist/commands/init.command.d.ts +1 -0
  17. package/dist/commands/init.command.js +6 -1
  18. package/dist/commands/init.command.js.map +1 -1
  19. package/dist/commands/login.command.d.ts +1 -0
  20. package/dist/commands/login.command.js +3 -3
  21. package/dist/commands/login.command.js.map +1 -1
  22. package/dist/commands/logout.command.d.ts +5 -1
  23. package/dist/commands/logout.command.js +3 -3
  24. package/dist/commands/logout.command.js.map +1 -1
  25. package/dist/commands/mcp.command.d.ts +5 -1
  26. package/dist/commands/mcp.command.js +7 -4
  27. package/dist/commands/mcp.command.js.map +1 -1
  28. package/dist/commands/mcpInstall.command.d.ts +7 -0
  29. package/dist/commands/mcpInstall.command.js +9 -0
  30. package/dist/commands/mcpInstall.command.js.map +1 -0
  31. package/dist/commands/profiles.command.d.ts +17 -0
  32. package/dist/commands/profiles.command.js +48 -0
  33. package/dist/commands/profiles.command.js.map +1 -0
  34. package/dist/commands/setup.command.d.ts +11 -0
  35. package/dist/commands/setup.command.js +85 -0
  36. package/dist/commands/setup.command.js.map +1 -0
  37. package/dist/commands/status.command.d.ts +6 -1
  38. package/dist/commands/status.command.js +7 -4
  39. package/dist/commands/status.command.js.map +1 -1
  40. package/dist/services/credentialStore.service.d.ts +8 -2
  41. package/dist/services/credentialStore.service.js +22 -10
  42. package/dist/services/credentialStore.service.js.map +1 -1
  43. package/dist/services/doctor.service.d.ts +22 -0
  44. package/dist/services/doctor.service.js +186 -0
  45. package/dist/services/doctor.service.js.map +1 -0
  46. package/dist/services/mcpInstall.service.d.ts +43 -0
  47. package/dist/services/mcpInstall.service.js +117 -0
  48. package/dist/services/mcpInstall.service.js.map +1 -0
  49. package/dist/services/mcpLauncher.service.d.ts +2 -0
  50. package/dist/services/mcpLauncher.service.js +6 -3
  51. package/dist/services/mcpLauncher.service.js.map +1 -1
  52. package/dist/services/profileStore.service.d.ts +53 -0
  53. package/dist/services/profileStore.service.js +129 -0
  54. package/dist/services/profileStore.service.js.map +1 -0
  55. package/dist/services/setupPrompt.service.d.ts +25 -0
  56. package/dist/services/setupPrompt.service.js +40 -0
  57. package/dist/services/setupPrompt.service.js.map +1 -0
  58. package/package.json +1 -1
@@ -0,0 +1,11 @@
1
+ interface RunSetupCommandParams {
2
+ profileName?: string;
3
+ skipLogin?: boolean;
4
+ skipInstall?: boolean;
5
+ nonInteractive?: boolean;
6
+ clientId?: string;
7
+ clientSecret?: string;
8
+ apiBaseUrl?: string;
9
+ }
10
+ export declare function runSetupCommand(params?: RunSetupCommandParams): Promise<number>;
11
+ export {};
@@ -0,0 +1,85 @@
1
+ import { DEFAULT_API_BASE_URL, DEFAULT_CALLBACK_HOST, DEFAULT_CALLBACK_PATH, DEFAULT_CALLBACK_PORT, PARTNERS_PORTAL_URL, } from '../constants.js';
2
+ import { runDoctorCommand } from './doctor.command.js';
3
+ import { runInitCommand } from './init.command.js';
4
+ import { runLoginCommand } from './login.command.js';
5
+ import { runMcpInstallCommand } from './mcpInstall.command.js';
6
+ import { getConfigFilePath, loadCredentials } from '../services/credentialStore.service.js';
7
+ import { DEFAULT_PROFILE_NAME, ensureProfileDirectory, setActiveProfileName, } from '../services/profileStore.service.js';
8
+ import { createPromptInterface, promptChoice, promptLine, promptYesNo, } from '../services/setupPrompt.service.js';
9
+ export async function runSetupCommand(params = {}) {
10
+ const readlineInterface = createPromptInterface();
11
+ try {
12
+ process.stdout.write('COUNT CLI setup\n');
13
+ process.stdout.write('This wizard saves partner credentials, signs you in, installs MCP config, and runs health checks.\n\n');
14
+ const profileName = params.profileName ??
15
+ (params.nonInteractive
16
+ ? DEFAULT_PROFILE_NAME
17
+ : await promptLine({
18
+ readlineInterface,
19
+ question: 'Profile name',
20
+ defaultValue: DEFAULT_PROFILE_NAME,
21
+ }));
22
+ await ensureProfileDirectory({ profileName });
23
+ await setActiveProfileName({ profileName });
24
+ const existingCredentials = await loadCredentials({ profileName });
25
+ let clientId = params.clientId ?? existingCredentials?.clientId;
26
+ let clientSecret = params.clientSecret ?? existingCredentials?.clientSecret;
27
+ let apiBaseUrl = params.apiBaseUrl ?? existingCredentials?.apiBaseUrl ?? DEFAULT_API_BASE_URL;
28
+ if (!clientId || !clientSecret) {
29
+ if (params.nonInteractive) {
30
+ throw new Error('Partner credentials are required. Pass --client-id and --client-secret for non-interactive setup.');
31
+ }
32
+ process.stdout.write(`Create a partner app at ${PARTNERS_PORTAL_URL} if you have not already.\n\n`);
33
+ clientId = await promptLine({ readlineInterface, question: 'Partner client ID' });
34
+ clientSecret = await promptLine({ readlineInterface, question: 'Partner client secret' });
35
+ apiBaseUrl = await promptLine({
36
+ readlineInterface,
37
+ question: 'API base URL',
38
+ defaultValue: apiBaseUrl,
39
+ });
40
+ }
41
+ if (!clientId || !clientSecret) {
42
+ throw new Error('Partner client ID and client secret are required.');
43
+ }
44
+ await runInitCommand({
45
+ clientId,
46
+ clientSecret,
47
+ apiBaseUrl,
48
+ profileName,
49
+ });
50
+ const redirectUri = `http://${DEFAULT_CALLBACK_HOST}:${DEFAULT_CALLBACK_PORT}${DEFAULT_CALLBACK_PATH}`;
51
+ process.stdout.write(`\nEnsure this redirect URI is registered on your partner app:\n ${redirectUri}\n\n`);
52
+ const shouldLogin = !params.skipLogin &&
53
+ (params.nonInteractive
54
+ ? !(await loadCredentials({ profileName }))?.accessToken
55
+ : await promptYesNo({
56
+ readlineInterface,
57
+ question: 'Sign in to COUNT now?',
58
+ defaultYes: true,
59
+ }));
60
+ if (shouldLogin) {
61
+ await runLoginCommand({ profileName });
62
+ }
63
+ if (!params.skipInstall && !params.nonInteractive) {
64
+ const installChoice = await promptChoice({
65
+ readlineInterface,
66
+ question: 'Install MCP config for',
67
+ choices: ['skip', 'cursor', 'claude-code', 'claude-desktop', 'all'],
68
+ defaultChoice: 'cursor',
69
+ });
70
+ if (installChoice !== 'skip') {
71
+ await runMcpInstallCommand({ target: installChoice });
72
+ }
73
+ }
74
+ process.stdout.write('\nRunning health checks...\n\n');
75
+ const doctorExitCode = await runDoctorCommand({ profileName });
76
+ process.stdout.write(`\nSetup complete for profile "${profileName}".\n`);
77
+ process.stdout.write(`Credentials: ${getConfigFilePath({ profileName })}\n`);
78
+ process.stdout.write('Run `count mcp` to start the local MCP server.\n');
79
+ return doctorExitCode;
80
+ }
81
+ finally {
82
+ readlineInterface.close();
83
+ }
84
+ }
85
+ //# sourceMappingURL=setup.command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.command.js","sourceRoot":"","sources":["../../src/commands/setup.command.ts"],"names":[],"mappings":"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"}
@@ -1 +1,6 @@
1
- export declare function runStatusCommand(): Promise<void>;
1
+ interface RunStatusCommandParams {
2
+ profileName?: string;
3
+ json?: boolean;
4
+ }
5
+ export declare function runStatusCommand(params?: RunStatusCommandParams): Promise<void>;
6
+ export {};
@@ -1,13 +1,16 @@
1
1
  import { getConfigFilePath, loadCredentials } from '../services/credentialStore.service.js';
2
- export async function runStatusCommand() {
3
- const credentials = await loadCredentials();
4
- const configFilePath = getConfigFilePath();
2
+ import { getActiveProfileName } from '../services/profileStore.service.js';
3
+ export async function runStatusCommand(params = {}) {
4
+ const credentials = await loadCredentials({ profileName: params.profileName });
5
+ const configFilePath = getConfigFilePath({ profileName: params.profileName });
6
+ const activeProfileName = await getActiveProfileName();
5
7
  if (!credentials) {
6
8
  process.stdout.write(`No credentials file at ${configFilePath}\n`);
7
- process.stdout.write('Run `count init` then `count login`.\n');
9
+ process.stdout.write('Run `count init` then `count login`, or run `count setup`.\n');
8
10
  return;
9
11
  }
10
12
  const status = {
13
+ activeProfile: params.profileName ?? activeProfileName,
11
14
  configFilePath,
12
15
  apiBaseUrl: credentials.apiBaseUrl,
13
16
  hasClientId: Boolean(credentials.clientId),
@@ -1 +1 @@
1
- {"version":3,"file":"status.command.js","sourceRoot":"","sources":["../../src/commands/status.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,wCAAwC,CAAC;AAE5F,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,WAAW,GAAG,MAAM,eAAe,EAAE,CAAC;IAC5C,MAAM,cAAc,GAAG,iBAAiB,EAAE,CAAC;IAE3C,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,cAAc,IAAI,CAAC,CAAC;QACnE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC/D,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG;QACb,cAAc;QACd,UAAU,EAAE,WAAW,CAAC,UAAU;QAClC,WAAW,EAAE,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC;QAC1C,eAAe,EAAE,OAAO,CAAC,WAAW,CAAC,YAAY,CAAC;QAClD,cAAc,EAAE,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC;QAChD,eAAe,EAAE,OAAO,CAAC,WAAW,CAAC,YAAY,CAAC;QAClD,WAAW,EAAE,WAAW,CAAC,WAAW,IAAI,IAAI;QAC5C,aAAa,EAAE,WAAW,CAAC,aAAa,IAAI,IAAI;KACjD,CAAC;IAEF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AAC/D,CAAC"}
1
+ {"version":3,"file":"status.command.js","sourceRoot":"","sources":["../../src/commands/status.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,wCAAwC,CAAC;AAC5F,OAAO,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAC;AAO3E,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,SAAiC,EAAE;IACxE,MAAM,WAAW,GAAG,MAAM,eAAe,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;IAC/E,MAAM,cAAc,GAAG,iBAAiB,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;IAC9E,MAAM,iBAAiB,GAAG,MAAM,oBAAoB,EAAE,CAAC;IAEvD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,cAAc,IAAI,CAAC,CAAC;QACnE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8DAA8D,CAAC,CAAC;QACrF,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG;QACb,aAAa,EAAE,MAAM,CAAC,WAAW,IAAI,iBAAiB;QACtD,cAAc;QACd,UAAU,EAAE,WAAW,CAAC,UAAU;QAClC,WAAW,EAAE,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC;QAC1C,eAAe,EAAE,OAAO,CAAC,WAAW,CAAC,YAAY,CAAC;QAClD,cAAc,EAAE,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC;QAChD,eAAe,EAAE,OAAO,CAAC,WAAW,CAAC,YAAY,CAAC;QAClD,WAAW,EAAE,WAAW,CAAC,WAAW,IAAI,IAAI;QAC5C,aAAa,EAAE,WAAW,CAAC,aAAa,IAAI,IAAI;KACjD,CAAC;IAEF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AAC/D,CAAC"}
@@ -1,20 +1,27 @@
1
1
  import type { CountCliCredentials } from '../types.js';
2
+ export { getConfigDirectoryPath } from './profileStore.service.js';
2
3
  interface GetConfigFilePathParams {
3
4
  homeDirectory?: string;
5
+ profileName?: string;
4
6
  }
5
- export declare function getConfigDirectoryPath(params?: GetConfigFilePathParams): string;
6
7
  export declare function getConfigFilePath(params?: GetConfigFilePathParams): string;
7
8
  interface LoadCredentialsParams {
8
9
  configFilePath?: string;
10
+ profileName?: string;
11
+ homeDirectory?: string;
9
12
  }
10
13
  export declare function loadCredentials(params?: LoadCredentialsParams): Promise<CountCliCredentials | null>;
11
14
  interface SaveCredentialsParams {
12
15
  credentials: CountCliCredentials;
13
16
  configFilePath?: string;
17
+ profileName?: string;
18
+ homeDirectory?: string;
14
19
  }
15
20
  export declare function saveCredentials(params: SaveCredentialsParams): Promise<void>;
16
21
  interface DeleteCredentialsParams {
17
22
  configFilePath?: string;
23
+ profileName?: string;
24
+ homeDirectory?: string;
18
25
  }
19
26
  export declare function deleteCredentials(params?: DeleteCredentialsParams): Promise<void>;
20
27
  interface BuildDefaultCredentialsParams {
@@ -23,4 +30,3 @@ interface BuildDefaultCredentialsParams {
23
30
  apiBaseUrl?: string;
24
31
  }
25
32
  export declare function buildDefaultCredentials(params: BuildDefaultCredentialsParams): CountCliCredentials;
26
- export {};
@@ -1,8 +1,9 @@
1
1
  import fs from 'node:fs/promises';
2
- import os from 'node:os';
3
2
  import path from 'node:path';
4
3
  import { z } from 'zod';
5
- import { DEFAULT_API_BASE_URL, DEFAULT_CONFIG_DIRECTORY_NAME, DEFAULT_CONFIG_FILE_NAME, DEFAULT_REQUEST_TIMEOUT_MS, } from '../constants.js';
4
+ import { DEFAULT_API_BASE_URL, DEFAULT_REQUEST_TIMEOUT_MS } from '../constants.js';
5
+ import { resolveCredentialsFilePath } from './profileStore.service.js';
6
+ export { getConfigDirectoryPath } from './profileStore.service.js';
6
7
  const credentialsSchema = z.object({
7
8
  apiBaseUrl: z.string().trim().min(1),
8
9
  clientId: z.string().trim().min(1),
@@ -13,15 +14,18 @@ const credentialsSchema = z.object({
13
14
  workspaceName: z.string().trim().min(1).optional(),
14
15
  requestTimeoutMs: z.number().int().positive(),
15
16
  });
16
- export function getConfigDirectoryPath(params = {}) {
17
- const { homeDirectory = os.homedir() } = params;
18
- return path.join(homeDirectory, DEFAULT_CONFIG_DIRECTORY_NAME);
19
- }
20
17
  export function getConfigFilePath(params = {}) {
21
- return path.join(getConfigDirectoryPath(params), DEFAULT_CONFIG_FILE_NAME);
18
+ return resolveCredentialsFilePath({
19
+ profileName: params.profileName,
20
+ homeDirectory: params.homeDirectory,
21
+ });
22
22
  }
23
23
  export async function loadCredentials(params = {}) {
24
- const configFilePath = params.configFilePath ?? getConfigFilePath();
24
+ const configFilePath = params.configFilePath ??
25
+ resolveCredentialsFilePath({
26
+ profileName: params.profileName,
27
+ homeDirectory: params.homeDirectory,
28
+ });
25
29
  try {
26
30
  const rawContents = await fs.readFile(configFilePath, 'utf8');
27
31
  const parsedJson = JSON.parse(rawContents);
@@ -35,7 +39,11 @@ export async function loadCredentials(params = {}) {
35
39
  }
36
40
  }
37
41
  export async function saveCredentials(params) {
38
- const configFilePath = params.configFilePath ?? getConfigFilePath();
42
+ const configFilePath = params.configFilePath ??
43
+ resolveCredentialsFilePath({
44
+ profileName: params.profileName,
45
+ homeDirectory: params.homeDirectory,
46
+ });
39
47
  const configDirectoryPath = path.dirname(configFilePath);
40
48
  const validatedCredentials = credentialsSchema.parse(params.credentials);
41
49
  await fs.mkdir(configDirectoryPath, { recursive: true, mode: 0o700 });
@@ -45,7 +53,11 @@ export async function saveCredentials(params) {
45
53
  });
46
54
  }
47
55
  export async function deleteCredentials(params = {}) {
48
- const configFilePath = params.configFilePath ?? getConfigFilePath();
56
+ const configFilePath = params.configFilePath ??
57
+ resolveCredentialsFilePath({
58
+ profileName: params.profileName,
59
+ homeDirectory: params.homeDirectory,
60
+ });
49
61
  try {
50
62
  await fs.unlink(configFilePath);
51
63
  }
@@ -1 +1 @@
1
- {"version":3,"file":"credentialStore.service.js","sourceRoot":"","sources":["../../src/services/credentialStore.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"credentialStore.service.js","sourceRoot":"","sources":["../../src/services/credentialStore.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export type DoctorCheckStatus = 'pass' | 'warn' | 'fail';
2
+ export interface DoctorCheckResult {
3
+ checkId: string;
4
+ label: string;
5
+ status: DoctorCheckStatus;
6
+ message: string;
7
+ }
8
+ export interface RunDoctorChecksParams {
9
+ profileName?: string;
10
+ homeDirectory?: string;
11
+ fetchImplementation?: typeof fetch;
12
+ }
13
+ export interface RunDoctorChecksResult {
14
+ checks: DoctorCheckResult[];
15
+ passed: boolean;
16
+ }
17
+ export declare function runDoctorChecks(params?: RunDoctorChecksParams): Promise<RunDoctorChecksResult>;
18
+ interface FormatDoctorReportParams {
19
+ result: RunDoctorChecksResult;
20
+ }
21
+ export declare function formatDoctorReport(params: FormatDoctorReportParams): string;
22
+ export {};
@@ -0,0 +1,186 @@
1
+ import { CLI_VERSION, DEFAULT_CALLBACK_HOST, DEFAULT_CALLBACK_PATH, DEFAULT_CALLBACK_PORT, DEVELOPER_DOCS_URL, PARTNERS_PORTAL_URL, } from '../constants.js';
2
+ import { PartnerApiClient } from '../partner-mcp/partnerApiClient.js';
3
+ import { toolDefinitions } from '../partner-mcp/tools/definitions.js';
4
+ import { getActiveProfileName, resolveCredentialsFilePath } from './profileStore.service.js';
5
+ import { loadCredentials } from './credentialStore.service.js';
6
+ function appendDoctorCheck(params) {
7
+ params.checks.push({
8
+ checkId: params.checkId,
9
+ label: params.label,
10
+ status: params.status,
11
+ message: params.message,
12
+ });
13
+ }
14
+ export async function runDoctorChecks(params = {}) {
15
+ const { profileName, homeDirectory, fetchImplementation = fetch } = params;
16
+ const checks = [];
17
+ appendDoctorCheck({
18
+ checks,
19
+ checkId: 'cli_version',
20
+ label: 'CLI version',
21
+ status: 'pass',
22
+ message: CLI_VERSION,
23
+ });
24
+ const credentialsFilePath = resolveCredentialsFilePath({ profileName, homeDirectory });
25
+ let activeProfileName = profileName;
26
+ if (!activeProfileName) {
27
+ activeProfileName = await getActiveProfileName({ homeDirectory });
28
+ }
29
+ appendDoctorCheck({
30
+ checks,
31
+ checkId: 'active_profile',
32
+ label: 'Active profile',
33
+ status: 'pass',
34
+ message: activeProfileName,
35
+ });
36
+ appendDoctorCheck({
37
+ checks,
38
+ checkId: 'credentials_path',
39
+ label: 'Credentials file',
40
+ status: 'pass',
41
+ message: credentialsFilePath,
42
+ });
43
+ const credentials = await loadCredentials({ profileName, homeDirectory, configFilePath: credentialsFilePath });
44
+ if (!credentials?.clientId || !credentials.clientSecret) {
45
+ appendDoctorCheck({
46
+ checks,
47
+ checkId: 'partner_credentials',
48
+ label: 'Partner app credentials',
49
+ status: 'fail',
50
+ message: 'Missing client ID or secret. Run `count init` or `count setup`.',
51
+ });
52
+ }
53
+ else {
54
+ appendDoctorCheck({
55
+ checks,
56
+ checkId: 'partner_credentials',
57
+ label: 'Partner app credentials',
58
+ status: 'pass',
59
+ message: `Configured for ${credentials.apiBaseUrl}`,
60
+ });
61
+ }
62
+ const redirectUri = `http://${DEFAULT_CALLBACK_HOST}:${DEFAULT_CALLBACK_PORT}${DEFAULT_CALLBACK_PATH}`;
63
+ appendDoctorCheck({
64
+ checks,
65
+ checkId: 'redirect_uri',
66
+ label: 'OAuth redirect URI',
67
+ status: 'pass',
68
+ message: `${redirectUri} (register at ${PARTNERS_PORTAL_URL})`,
69
+ });
70
+ appendDoctorCheck({
71
+ checks,
72
+ checkId: 'mcp_tools',
73
+ label: 'MCP tool registry',
74
+ status: 'pass',
75
+ message: `${toolDefinitions.length} COUNT_* tools loaded`,
76
+ });
77
+ if (!credentials?.accessToken || !credentials.refreshToken) {
78
+ appendDoctorCheck({
79
+ checks,
80
+ checkId: 'login_tokens',
81
+ label: 'Workspace login',
82
+ status: 'fail',
83
+ message: 'Not logged in. Run `count login`.',
84
+ });
85
+ }
86
+ else {
87
+ const workspaceLabel = credentials.workspaceName ?? credentials.workspaceId ?? 'authenticated workspace';
88
+ appendDoctorCheck({
89
+ checks,
90
+ checkId: 'login_tokens',
91
+ label: 'Workspace login',
92
+ status: 'pass',
93
+ message: workspaceLabel,
94
+ });
95
+ }
96
+ if (credentials?.clientId && credentials.clientSecret) {
97
+ await appendApiConnectivityCheck({
98
+ checks,
99
+ credentials,
100
+ fetchImplementation,
101
+ });
102
+ }
103
+ appendDoctorCheck({
104
+ checks,
105
+ checkId: 'developer_docs',
106
+ label: 'Partner API docs',
107
+ status: 'pass',
108
+ message: DEVELOPER_DOCS_URL,
109
+ });
110
+ const passed = checks.every((_check) => _check.status !== 'fail');
111
+ return { checks, passed };
112
+ }
113
+ async function appendApiConnectivityCheck(params) {
114
+ const { checks, credentials, fetchImplementation } = params;
115
+ try {
116
+ const partnerClient = new PartnerApiClient({
117
+ config: {
118
+ apiBaseUrl: credentials.apiBaseUrl,
119
+ clientId: credentials.clientId,
120
+ clientSecret: credentials.clientSecret,
121
+ accessToken: credentials.accessToken,
122
+ refreshToken: credentials.refreshToken,
123
+ requestTimeoutMs: credentials.requestTimeoutMs,
124
+ },
125
+ fetchImplementation,
126
+ });
127
+ if (credentials.accessToken && credentials.refreshToken) {
128
+ await partnerClient.request({
129
+ method: 'GET',
130
+ path: '/partners/chart-of-accounts',
131
+ query: { limit: 1 },
132
+ requiresUserAuth: true,
133
+ });
134
+ appendDoctorCheck({
135
+ checks,
136
+ checkId: 'api_connectivity',
137
+ label: 'COUNT API connectivity',
138
+ status: 'pass',
139
+ message: `Authenticated request succeeded against ${credentials.apiBaseUrl}`,
140
+ });
141
+ return;
142
+ }
143
+ const healthResponse = await fetchImplementation(credentials.apiBaseUrl, { method: 'HEAD' });
144
+ if (healthResponse.ok || healthResponse.status === 404 || healthResponse.status === 405) {
145
+ appendDoctorCheck({
146
+ checks,
147
+ checkId: 'api_connectivity',
148
+ label: 'COUNT API connectivity',
149
+ status: 'warn',
150
+ message: `API host reachable at ${credentials.apiBaseUrl}. Run \`count login\` to verify workspace access.`,
151
+ });
152
+ return;
153
+ }
154
+ appendDoctorCheck({
155
+ checks,
156
+ checkId: 'api_connectivity',
157
+ label: 'COUNT API connectivity',
158
+ status: 'fail',
159
+ message: `API host returned HTTP ${healthResponse.status} for ${credentials.apiBaseUrl}`,
160
+ });
161
+ }
162
+ catch (error) {
163
+ const message = error instanceof Error ? error.message : String(error);
164
+ appendDoctorCheck({
165
+ checks,
166
+ checkId: 'api_connectivity',
167
+ label: 'COUNT API connectivity',
168
+ status: 'fail',
169
+ message,
170
+ });
171
+ }
172
+ }
173
+ export function formatDoctorReport(params) {
174
+ const statusSymbol = {
175
+ pass: '✓',
176
+ warn: '!',
177
+ fail: '✗',
178
+ };
179
+ const lines = params.result.checks.map((_check) => {
180
+ return `${statusSymbol[_check.status]} ${_check.label}: ${_check.message}`;
181
+ });
182
+ lines.push('');
183
+ lines.push(params.result.passed ? 'All required checks passed.' : 'One or more checks failed.');
184
+ return `${lines.join('\n')}\n`;
185
+ }
186
+ //# sourceMappingURL=doctor.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.service.js","sourceRoot":"","sources":["../../src/services/doctor.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ export declare function resolveCursorMcpConfigPath(params?: {
2
+ homeDirectory?: string;
3
+ }): string;
4
+ export declare function resolveClaudeCodeSettingsPath(params?: {
5
+ homeDirectory?: string;
6
+ }): string;
7
+ export declare function resolveClaudeDesktopConfigPath(params?: {
8
+ homeDirectory?: string;
9
+ }): string;
10
+ export type McpInstallTarget = 'cursor' | 'claude-code' | 'claude-desktop' | 'all';
11
+ export interface McpInstallTargetDefinition {
12
+ targetId: McpInstallTarget;
13
+ label: string;
14
+ configFilePath: string;
15
+ }
16
+ interface ResolveMcpInstallTargetsParams {
17
+ target: McpInstallTarget;
18
+ homeDirectory?: string;
19
+ }
20
+ export declare function resolveMcpInstallTargets(params: ResolveMcpInstallTargetsParams): McpInstallTargetDefinition[];
21
+ interface MergeCountMcpServerConfigParams {
22
+ existingConfiguration: Record<string, unknown>;
23
+ countServerConfiguration: Record<string, unknown>;
24
+ }
25
+ export declare function mergeCountMcpServerConfig(params: MergeCountMcpServerConfigParams): Record<string, unknown>;
26
+ export interface InstallMcpConfigurationParams {
27
+ target: McpInstallTarget;
28
+ homeDirectory?: string;
29
+ dryRun?: boolean;
30
+ }
31
+ export interface InstallMcpConfigurationResult {
32
+ targetId: McpInstallTarget;
33
+ label: string;
34
+ configFilePath: string;
35
+ dryRun: boolean;
36
+ mergedConfiguration: Record<string, unknown>;
37
+ }
38
+ export declare function installMcpConfiguration(params: InstallMcpConfigurationParams): Promise<InstallMcpConfigurationResult[]>;
39
+ interface FormatInstallMcpReportParams {
40
+ installationResults: InstallMcpConfigurationResult[];
41
+ }
42
+ export declare function formatInstallMcpReport(params: FormatInstallMcpReportParams): string;
43
+ export {};
@@ -0,0 +1,117 @@
1
+ import fs from 'node:fs/promises';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { buildClaudeCodeMcpConfig } from './mcpLauncher.service.js';
5
+ export function resolveCursorMcpConfigPath(params = {}) {
6
+ return path.join(params.homeDirectory ?? os.homedir(), '.cursor', 'mcp.json');
7
+ }
8
+ export function resolveClaudeCodeSettingsPath(params = {}) {
9
+ return path.join(params.homeDirectory ?? os.homedir(), '.claude', 'settings.json');
10
+ }
11
+ export function resolveClaudeDesktopConfigPath(params = {}) {
12
+ const homeDirectory = params.homeDirectory ?? os.homedir();
13
+ if (process.platform === 'darwin') {
14
+ return path.join(homeDirectory, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
15
+ }
16
+ if (process.platform === 'win32') {
17
+ const applicationDataDirectory = process.env.APPDATA ?? path.join(homeDirectory, 'AppData', 'Roaming');
18
+ return path.join(applicationDataDirectory, 'Claude', 'claude_desktop_config.json');
19
+ }
20
+ return path.join(homeDirectory, '.config', 'Claude', 'claude_desktop_config.json');
21
+ }
22
+ export function resolveMcpInstallTargets(params) {
23
+ const { target, homeDirectory } = params;
24
+ const allTargets = [
25
+ {
26
+ targetId: 'cursor',
27
+ label: 'Cursor',
28
+ configFilePath: resolveCursorMcpConfigPath({ homeDirectory }),
29
+ },
30
+ {
31
+ targetId: 'claude-code',
32
+ label: 'Claude Code',
33
+ configFilePath: resolveClaudeCodeSettingsPath({ homeDirectory }),
34
+ },
35
+ {
36
+ targetId: 'claude-desktop',
37
+ label: 'Claude Desktop',
38
+ configFilePath: resolveClaudeDesktopConfigPath({ homeDirectory }),
39
+ },
40
+ ];
41
+ if (target === 'all') {
42
+ return allTargets;
43
+ }
44
+ const matchingTarget = allTargets.find((_entry) => _entry.targetId === target);
45
+ if (!matchingTarget) {
46
+ throw new Error(`Unsupported MCP install target "${target}".`);
47
+ }
48
+ return [matchingTarget];
49
+ }
50
+ async function readJsonFile(params) {
51
+ try {
52
+ const rawContents = await fs.readFile(params.filePath, 'utf8');
53
+ const parsedJson = JSON.parse(rawContents);
54
+ if (!parsedJson || typeof parsedJson !== 'object' || Array.isArray(parsedJson)) {
55
+ return {};
56
+ }
57
+ return parsedJson;
58
+ }
59
+ catch (error) {
60
+ if (error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT') {
61
+ return {};
62
+ }
63
+ throw error;
64
+ }
65
+ }
66
+ export function mergeCountMcpServerConfig(params) {
67
+ const existingMcpServers = params.existingConfiguration.mcpServers && typeof params.existingConfiguration.mcpServers === 'object'
68
+ ? params.existingConfiguration.mcpServers
69
+ : {};
70
+ return {
71
+ ...params.existingConfiguration,
72
+ mcpServers: {
73
+ ...existingMcpServers,
74
+ count: params.countServerConfiguration,
75
+ },
76
+ };
77
+ }
78
+ export async function installMcpConfiguration(params) {
79
+ const { target, homeDirectory, dryRun = false } = params;
80
+ const installTargets = resolveMcpInstallTargets({ target, homeDirectory });
81
+ const countMcpConfiguration = buildClaudeCodeMcpConfig();
82
+ const countServerConfiguration = countMcpConfiguration.mcpServers.count;
83
+ const installationResults = [];
84
+ for (const installTarget of installTargets) {
85
+ const existingConfiguration = await readJsonFile({ filePath: installTarget.configFilePath });
86
+ const mergedConfiguration = mergeCountMcpServerConfig({
87
+ existingConfiguration,
88
+ countServerConfiguration,
89
+ });
90
+ if (!dryRun) {
91
+ await fs.mkdir(path.dirname(installTarget.configFilePath), { recursive: true });
92
+ await fs.writeFile(installTarget.configFilePath, `${JSON.stringify(mergedConfiguration, null, 2)}\n`, {
93
+ encoding: 'utf8',
94
+ });
95
+ }
96
+ installationResults.push({
97
+ targetId: installTarget.targetId,
98
+ label: installTarget.label,
99
+ configFilePath: installTarget.configFilePath,
100
+ dryRun,
101
+ mergedConfiguration,
102
+ });
103
+ }
104
+ return installationResults;
105
+ }
106
+ export function formatInstallMcpReport(params) {
107
+ const lines = [];
108
+ for (const installationResult of params.installationResults) {
109
+ const actionLabel = installationResult.dryRun ? 'Would install MCP config for' : 'Installed MCP config for';
110
+ lines.push(`${actionLabel} ${installationResult.label}`);
111
+ lines.push(` ${installationResult.configFilePath}`);
112
+ }
113
+ lines.push('');
114
+ lines.push('Restart your editor or reload MCP servers to pick up the change.');
115
+ return `${lines.join('\n')}\n`;
116
+ }
117
+ //# sourceMappingURL=mcpInstall.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcpInstall.service.js","sourceRoot":"","sources":["../../src/services/mcpInstall.service.ts"],"names":[],"mappings":"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"}