@channelfactory/cliend 0.1.0 → 0.3.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.
- package/README.md +301 -0
- package/dist/src/auth/auth-manager.js +1 -1
- package/dist/src/auth/auth-manager.js.map +1 -1
- package/dist/src/config/config.schema.d.ts +5 -0
- package/dist/src/config/config.schema.d.ts.map +1 -1
- package/dist/src/config/config.schema.js +1 -0
- package/dist/src/config/config.schema.js.map +1 -1
- package/dist/src/config/defaults.d.ts.map +1 -1
- package/dist/src/config/defaults.js +1 -0
- package/dist/src/config/defaults.js.map +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +5 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/integrations/atlassian/mcp-client.d.ts +40 -0
- package/dist/src/integrations/atlassian/mcp-client.d.ts.map +1 -0
- package/dist/src/integrations/atlassian/mcp-client.js +198 -0
- package/dist/src/integrations/atlassian/mcp-client.js.map +1 -0
- package/dist/src/repl/commands/breakdown.d.ts +3 -0
- package/dist/src/repl/commands/breakdown.d.ts.map +1 -0
- package/dist/src/repl/commands/breakdown.js +141 -0
- package/dist/src/repl/commands/breakdown.js.map +1 -0
- package/dist/src/repl/commands/config.d.ts.map +1 -1
- package/dist/src/repl/commands/config.js +8 -2
- package/dist/src/repl/commands/config.js.map +1 -1
- package/dist/src/repl/commands/help.d.ts.map +1 -1
- package/dist/src/repl/commands/help.js +3 -0
- package/dist/src/repl/commands/help.js.map +1 -1
- package/dist/src/repl/commands/search.d.ts +3 -0
- package/dist/src/repl/commands/search.d.ts.map +1 -0
- package/dist/src/repl/commands/search.js +49 -0
- package/dist/src/repl/commands/search.js.map +1 -0
- package/dist/src/repl/commands/ticket.d.ts.map +1 -1
- package/dist/src/repl/commands/ticket.js +12 -2
- package/dist/src/repl/commands/ticket.js.map +1 -1
- package/dist/src/repl/repl.d.ts.map +1 -1
- package/dist/src/repl/repl.js +4 -0
- package/dist/src/repl/repl.js.map +1 -1
- package/dist/src/types/config.d.ts +1 -0
- package/dist/src/types/config.d.ts.map +1 -1
- package/dist/src/ui/setup-wizard.d.ts +3 -0
- package/dist/src/ui/setup-wizard.d.ts.map +1 -0
- package/dist/src/ui/setup-wizard.js +135 -0
- package/dist/src/ui/setup-wizard.js.map +1 -0
- package/dist/src/ui/welcome.js +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-wizard.d.ts","sourceRoot":"","sources":["../../../src/ui/setup-wizard.ts"],"names":[],"mappings":"AAmEA,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAiDpD;AAwCD,wBAAgB,UAAU,IAAI,OAAO,CAGpC"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import * as readline from 'node:readline';
|
|
2
|
+
import { writeFile, mkdir } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
import { existsSync } from 'node:fs';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
function ask(rl, question, opts) {
|
|
8
|
+
const defaultHint = opts?.defaultValue ? chalk.dim(` [${opts.defaultValue}]`) : '';
|
|
9
|
+
const prefix = chalk.cyan(' ? ');
|
|
10
|
+
return new Promise((resolve) => {
|
|
11
|
+
if (opts?.mask) {
|
|
12
|
+
// For secret inputs, handle character-by-character
|
|
13
|
+
const stdout = process.stdout;
|
|
14
|
+
stdout.write(`${prefix}${question}${defaultHint}: `);
|
|
15
|
+
const stdin = process.stdin;
|
|
16
|
+
const wasRaw = stdin.isRaw;
|
|
17
|
+
stdin.setRawMode(true);
|
|
18
|
+
stdin.resume();
|
|
19
|
+
let input = '';
|
|
20
|
+
const onData = (ch) => {
|
|
21
|
+
const c = ch.toString('utf8');
|
|
22
|
+
if (c === '\n' || c === '\r') {
|
|
23
|
+
stdin.setRawMode(wasRaw ?? false);
|
|
24
|
+
stdin.removeListener('data', onData);
|
|
25
|
+
stdout.write('\n');
|
|
26
|
+
resolve(input || opts?.defaultValue || '');
|
|
27
|
+
}
|
|
28
|
+
else if (c === '\u007F' || c === '\b') {
|
|
29
|
+
// Backspace
|
|
30
|
+
if (input.length > 0) {
|
|
31
|
+
input = input.slice(0, -1);
|
|
32
|
+
stdout.write('\b \b');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
else if (c === '\u0003') {
|
|
36
|
+
// Ctrl+C
|
|
37
|
+
process.exit(0);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
input += c;
|
|
41
|
+
stdout.write('*');
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
stdin.on('data', onData);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
rl.question(`${prefix}${question}${defaultHint}: `, (answer) => {
|
|
48
|
+
resolve(answer.trim() || opts?.defaultValue || '');
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
export async function runSetupWizard() {
|
|
54
|
+
const configDir = join(homedir(), '.cliend');
|
|
55
|
+
const configPath = join(configDir, 'config.json');
|
|
56
|
+
console.log('');
|
|
57
|
+
console.log(chalk.bold.cyan(' Welcome to cliend! Let\'s set you up.\n'));
|
|
58
|
+
console.log(chalk.dim(' Your config will be saved to ~/.cliend/config.json'));
|
|
59
|
+
console.log(chalk.dim(' You can re-run this anytime with /config setup\n'));
|
|
60
|
+
const rl = readline.createInterface({
|
|
61
|
+
input: process.stdin,
|
|
62
|
+
output: process.stdout,
|
|
63
|
+
terminal: true,
|
|
64
|
+
});
|
|
65
|
+
try {
|
|
66
|
+
console.log(chalk.bold(' AI Providers'));
|
|
67
|
+
const anthropicApiKey = await ask(rl, 'Anthropic API Key', { mask: true });
|
|
68
|
+
const openaiApiKey = await ask(rl, 'OpenAI API Key', { mask: true });
|
|
69
|
+
console.log('');
|
|
70
|
+
console.log(chalk.bold(' Atlassian OAuth'));
|
|
71
|
+
const atlassianClientId = await ask(rl, 'Atlassian Client ID', { mask: true });
|
|
72
|
+
const atlassianClientSecret = await ask(rl, 'Atlassian Client Secret', { mask: true });
|
|
73
|
+
console.log('');
|
|
74
|
+
console.log(chalk.bold(' Bitbucket (Obsidian vault repo)'));
|
|
75
|
+
const bitbucketWorkspace = await ask(rl, 'Bitbucket Workspace');
|
|
76
|
+
const bitbucketRepoSlug = await ask(rl, 'Bitbucket Repo Slug');
|
|
77
|
+
const obsidianPath = await ask(rl, 'Obsidian path in repo', { defaultValue: 'docs/obsidian' });
|
|
78
|
+
const answers = {
|
|
79
|
+
anthropicApiKey,
|
|
80
|
+
openaiApiKey,
|
|
81
|
+
atlassianClientId,
|
|
82
|
+
atlassianClientSecret,
|
|
83
|
+
bitbucketWorkspace,
|
|
84
|
+
bitbucketRepoSlug,
|
|
85
|
+
obsidianPath,
|
|
86
|
+
};
|
|
87
|
+
await saveConfig(configDir, configPath, answers);
|
|
88
|
+
console.log('');
|
|
89
|
+
console.log(chalk.green(' ✓ Config saved to ~/.cliend/config.json'));
|
|
90
|
+
console.log(chalk.dim(' Run /auth to connect your Atlassian account.\n'));
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
rl.close();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async function saveConfig(configDir, configPath, answers) {
|
|
97
|
+
if (!existsSync(configDir)) {
|
|
98
|
+
await mkdir(configDir, { recursive: true });
|
|
99
|
+
}
|
|
100
|
+
// Load existing config to preserve any extra fields
|
|
101
|
+
let existing = {};
|
|
102
|
+
if (existsSync(configPath)) {
|
|
103
|
+
try {
|
|
104
|
+
const { readFile } = await import('node:fs/promises');
|
|
105
|
+
const raw = await readFile(configPath, 'utf-8');
|
|
106
|
+
existing = JSON.parse(raw);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Ignore parse errors, start fresh
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const config = {
|
|
113
|
+
...existing,
|
|
114
|
+
providers: {
|
|
115
|
+
claude: { apiKey: answers.anthropicApiKey },
|
|
116
|
+
codex: { apiKey: answers.openaiApiKey },
|
|
117
|
+
chatgpt: { apiKey: answers.openaiApiKey },
|
|
118
|
+
},
|
|
119
|
+
atlassian: {
|
|
120
|
+
clientId: answers.atlassianClientId,
|
|
121
|
+
clientSecret: answers.atlassianClientSecret,
|
|
122
|
+
},
|
|
123
|
+
bitbucket: {
|
|
124
|
+
workspace: answers.bitbucketWorkspace,
|
|
125
|
+
repoSlug: answers.bitbucketRepoSlug,
|
|
126
|
+
obsidianPath: answers.obsidianPath,
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
await writeFile(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
130
|
+
}
|
|
131
|
+
export function needsSetup() {
|
|
132
|
+
const configPath = join(homedir(), '.cliend', 'config.json');
|
|
133
|
+
return !existsSync(configPath);
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=setup-wizard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-wizard.js","sourceRoot":"","sources":["../../../src/ui/setup-wizard.ts"],"names":[],"mappings":"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"}
|
package/dist/src/ui/welcome.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { basename } from 'node:path';
|
|
3
3
|
export function showWelcome(projectDir) {
|
|
4
|
-
const version = '0.
|
|
4
|
+
const version = '0.3.0';
|
|
5
5
|
const project = basename(projectDir);
|
|
6
6
|
console.log('');
|
|
7
7
|
console.log(chalk.cyan(' ╭──────────────────────────────────────────╮'));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@channelfactory/cliend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Internal CLI tool",
|
|
5
5
|
"private-note": "Unlisted — do not add keywords for discoverability",
|
|
6
6
|
"type": "module",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"license": "MIT",
|
|
29
29
|
"repository": {
|
|
30
30
|
"type": "git",
|
|
31
|
-
"url": ""
|
|
31
|
+
"url": "git+ssh://git@bitbucket.org/sigmacf/cliend.git"
|
|
32
32
|
},
|
|
33
33
|
"engines": {
|
|
34
34
|
"node": ">=22.0.0"
|