@cspeach/cli 1.1.7 → 1.1.8
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/dist/agent/providers/ai-hub-provider.js +3 -3
- package/dist/agent/providers/byok-provider.js +3 -3
- package/dist/auth/api-key.js +9 -9
- package/dist/auth/keychain.js +0 -0
- package/dist/cli.js +27 -27
- package/dist/commands/config-set.js +3 -3
- package/dist/commands/login.js +2 -2
- package/dist/commands/logout.js +1 -1
- package/dist/commands/whoami.js +1 -1
- package/dist/doctor/checks/keychain.js +4 -4
- package/dist/doctor/checks/zcspeach.js +2 -2
- package/dist/sap/connection-manager.js +2 -2
- package/dist/sap/onboarding.js +4 -4
- package/dist/skills/bundled-skills.js +1 -1
- package/package.json +2 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Anthropic from '@anthropic-ai/sdk';
|
|
2
|
-
import
|
|
2
|
+
import keychain from '../../auth/keychain.js';
|
|
3
3
|
import { createManifestSkillSource } from '../../skills/source-manifest.js';
|
|
4
4
|
import { DEFAULT_MANIFEST_URL } from '../../skills/manifest-client.js';
|
|
5
5
|
const KEYCHAIN_SERVICE = 'cspeach.ai-hub';
|
|
@@ -26,7 +26,7 @@ export function createAiHubProvider(cfg) {
|
|
|
26
26
|
return sdk.messages.stream({ ...params, model: modelAlias }, options.signal ? { signal: options.signal } : undefined);
|
|
27
27
|
},
|
|
28
28
|
async healthCheck() {
|
|
29
|
-
const token = await
|
|
29
|
+
const token = await keychain.getPassword(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT);
|
|
30
30
|
if (!token)
|
|
31
31
|
return { ok: false, message: 'AI Hub token not in keychain', hint: 'Run: cspeach config set llm.ai_hub_token <token>' };
|
|
32
32
|
try {
|
|
@@ -51,7 +51,7 @@ export function createAiHubProvider(cfg) {
|
|
|
51
51
|
};
|
|
52
52
|
}
|
|
53
53
|
async function getToken() {
|
|
54
|
-
const t = await
|
|
54
|
+
const t = await keychain.getPassword(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT);
|
|
55
55
|
if (!t)
|
|
56
56
|
throw new Error('AI Hub token not configured');
|
|
57
57
|
return t;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Anthropic from '@anthropic-ai/sdk';
|
|
2
|
-
import
|
|
2
|
+
import keychain from '../../auth/keychain.js';
|
|
3
3
|
import { createManifestSkillSource } from '../../skills/source-manifest.js';
|
|
4
4
|
import { DEFAULT_MANIFEST_URL } from '../../skills/manifest-client.js';
|
|
5
5
|
const KEYCHAIN_SERVICE = 'cspeach.anthropic';
|
|
@@ -21,7 +21,7 @@ export function createByokProvider(_cfg) {
|
|
|
21
21
|
return sdk.messages.stream(params, options.signal ? { signal: options.signal } : undefined);
|
|
22
22
|
},
|
|
23
23
|
async healthCheck() {
|
|
24
|
-
const key = await
|
|
24
|
+
const key = await keychain.getPassword(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT);
|
|
25
25
|
if (!key)
|
|
26
26
|
return { ok: false, message: 'Anthropic API key not in keychain', hint: 'Run: cspeach config set llm.byok_key <your-anthropic-key>' };
|
|
27
27
|
try {
|
|
@@ -46,7 +46,7 @@ export function createByokProvider(_cfg) {
|
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
48
|
async function getKey() {
|
|
49
|
-
const key = await
|
|
49
|
+
const key = await keychain.getPassword(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT);
|
|
50
50
|
if (!key)
|
|
51
51
|
throw new Error('BYOK Anthropic API key not configured — run: cspeach config set llm.byok_key <key>');
|
|
52
52
|
return key;
|
package/dist/auth/api-key.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import
|
|
1
|
+
import keychain from './keychain.js';
|
|
2
2
|
const SERVICE = 'cspeach';
|
|
3
3
|
const ACCOUNT = 'api-key';
|
|
4
|
-
class
|
|
5
|
-
async get() { return
|
|
6
|
-
async set(key) { await
|
|
7
|
-
async delete() { await
|
|
4
|
+
class KeychainStore {
|
|
5
|
+
async get() { return keychain.getPassword(SERVICE, ACCOUNT); }
|
|
6
|
+
async set(key) { await keychain.setPassword(SERVICE, ACCOUNT, key); }
|
|
7
|
+
async delete() { await keychain.deletePassword(SERVICE, ACCOUNT); }
|
|
8
8
|
async isKeychainAvailable() {
|
|
9
9
|
try {
|
|
10
10
|
const probe = `probe-${Date.now()}`;
|
|
11
|
-
await
|
|
12
|
-
const ok = (await
|
|
13
|
-
await
|
|
11
|
+
await keychain.setPassword(SERVICE, 'probe', probe);
|
|
12
|
+
const ok = (await keychain.getPassword(SERVICE, 'probe')) === probe;
|
|
13
|
+
await keychain.deletePassword(SERVICE, 'probe');
|
|
14
14
|
return ok;
|
|
15
15
|
}
|
|
16
16
|
catch {
|
|
@@ -29,7 +29,7 @@ let store;
|
|
|
29
29
|
export async function getStore() {
|
|
30
30
|
if (store)
|
|
31
31
|
return store;
|
|
32
|
-
const ktr = new
|
|
32
|
+
const ktr = new KeychainStore();
|
|
33
33
|
if (await ktr.isKeychainAvailable()) {
|
|
34
34
|
store = ktr;
|
|
35
35
|
}
|
|
Binary file
|
package/dist/cli.js
CHANGED
|
@@ -162,32 +162,32 @@ export async function main(argv) {
|
|
|
162
162
|
return runRepl({ sapAlias, noSap });
|
|
163
163
|
}
|
|
164
164
|
function printHelp() {
|
|
165
|
-
console.log(`
|
|
166
|
-
CSPeach — AI-assisted ABAP development CLI
|
|
167
|
-
|
|
168
|
-
Usage:
|
|
169
|
-
cspeach Start interactive REPL
|
|
170
|
-
cspeach "<prompt>" One-shot — runs one turn and exits
|
|
171
|
-
cspeach --one-shot "<prompt>" Same as above, explicit flag
|
|
172
|
-
cspeach --sap-alias <name> Use a specific SAP alias (overrides default)
|
|
173
|
-
cspeach --no-sap Start without a SAP system (paste-mode skills only)
|
|
174
|
-
cspeach --resume [id] Resume a previous session (list if no id)
|
|
175
|
-
cspeach config add-sap Add a SAP system interactively
|
|
176
|
-
cspeach config standalone Set the standalone SAP profile (no system)
|
|
177
|
-
cspeach standards init Capture your team's ABAP development standards
|
|
178
|
-
cspeach configure Alias for \`cspeach config add-sap\`
|
|
179
|
-
cspeach config set <key> <value> Update a config key
|
|
180
|
-
cspeach config unset <key> Remove a config key (revert to default)
|
|
181
|
-
cspeach config show [key] Show config (full or single key)
|
|
182
|
-
cspeach doctor Diagnose install + connectivity
|
|
183
|
-
cspeach login Sign in via device-code flow
|
|
184
|
-
cspeach logout Sign out (keep
|
|
185
|
-
cspeach whoami Print current account info
|
|
186
|
-
cspeach analyze project-context Compare flag-on vs flag-off session metrics
|
|
187
|
-
cspeach --upgrade Upgrade to latest via npm
|
|
188
|
-
cspeach --version Print version
|
|
189
|
-
cspeach --help Show this help
|
|
190
|
-
|
|
191
|
-
Docs: https://cspeach.dev
|
|
165
|
+
console.log(`
|
|
166
|
+
CSPeach — AI-assisted ABAP development CLI
|
|
167
|
+
|
|
168
|
+
Usage:
|
|
169
|
+
cspeach Start interactive REPL
|
|
170
|
+
cspeach "<prompt>" One-shot — runs one turn and exits
|
|
171
|
+
cspeach --one-shot "<prompt>" Same as above, explicit flag
|
|
172
|
+
cspeach --sap-alias <name> Use a specific SAP alias (overrides default)
|
|
173
|
+
cspeach --no-sap Start without a SAP system (paste-mode skills only)
|
|
174
|
+
cspeach --resume [id] Resume a previous session (list if no id)
|
|
175
|
+
cspeach config add-sap Add a SAP system interactively
|
|
176
|
+
cspeach config standalone Set the standalone SAP profile (no system)
|
|
177
|
+
cspeach standards init Capture your team's ABAP development standards
|
|
178
|
+
cspeach configure Alias for \`cspeach config add-sap\`
|
|
179
|
+
cspeach config set <key> <value> Update a config key
|
|
180
|
+
cspeach config unset <key> Remove a config key (revert to default)
|
|
181
|
+
cspeach config show [key] Show config (full or single key)
|
|
182
|
+
cspeach doctor Diagnose install + connectivity
|
|
183
|
+
cspeach login Sign in via device-code flow
|
|
184
|
+
cspeach logout Sign out (keep keychain key, if any)
|
|
185
|
+
cspeach whoami Print current account info
|
|
186
|
+
cspeach analyze project-context Compare flag-on vs flag-off session metrics
|
|
187
|
+
cspeach --upgrade Upgrade to latest via npm
|
|
188
|
+
cspeach --version Print version
|
|
189
|
+
cspeach --help Show this help
|
|
190
|
+
|
|
191
|
+
Docs: https://cspeach.dev
|
|
192
192
|
`);
|
|
193
193
|
}
|
|
@@ -400,12 +400,12 @@ export async function runConfigSet(args) {
|
|
|
400
400
|
else {
|
|
401
401
|
console.log(chalk.yellow(`WARN: secret passed as shell argument — will land in shell history. Prefer: cat key.txt | cspeach config set ${key} -`));
|
|
402
402
|
}
|
|
403
|
-
const { default:
|
|
403
|
+
const { default: keychain } = await import('../auth/keychain.js');
|
|
404
404
|
if (key === 'llm.byok_key') {
|
|
405
|
-
await
|
|
405
|
+
await keychain.setPassword('cspeach.anthropic', 'api-key', secret);
|
|
406
406
|
}
|
|
407
407
|
else {
|
|
408
|
-
await
|
|
408
|
+
await keychain.setPassword('cspeach.ai-hub', 'token', secret);
|
|
409
409
|
}
|
|
410
410
|
console.log(chalk.green(`✓ Secret stored in OS keychain (service: ${key === 'llm.byok_key' ? 'cspeach.anthropic' : 'cspeach.ai-hub'})`));
|
|
411
411
|
return;
|
package/dist/commands/login.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* Dependencies (open, print, prompt) are injected so the command is
|
|
14
14
|
* unit-testable without stubbing platform globals.
|
|
15
15
|
*/
|
|
16
|
-
import
|
|
16
|
+
import keychain from '../auth/keychain.js';
|
|
17
17
|
import { writeAuthFile } from '../auth/auth-file.js';
|
|
18
18
|
import { fetchOrgAnthropicKey } from '../auth/org-anthropic-key.js';
|
|
19
19
|
const ANTHROPIC_KEYCHAIN_SERVICE = 'cspeach.anthropic';
|
|
@@ -101,7 +101,7 @@ export async function runLoginCommand(deps) {
|
|
|
101
101
|
fetchImpl: deps.fetchImpl,
|
|
102
102
|
});
|
|
103
103
|
const setKey = deps.setKeychainKey ??
|
|
104
|
-
((svc, acct, k) =>
|
|
104
|
+
((svc, acct, k) => keychain.setPassword(svc, acct, k));
|
|
105
105
|
if (orgKey !== null) {
|
|
106
106
|
await setKey(ANTHROPIC_KEYCHAIN_SERVICE, ANTHROPIC_KEYCHAIN_ACCOUNT, orgKey);
|
|
107
107
|
deps.print('Using your organization\'s Anthropic key.');
|
package/dist/commands/logout.js
CHANGED
|
@@ -8,7 +8,7 @@ export async function runLogoutCommand(deps) {
|
|
|
8
8
|
await deleteAuthFile();
|
|
9
9
|
if (before) {
|
|
10
10
|
deps.print('✓ Signed out — removed ~/.cspeach/auth.json');
|
|
11
|
-
deps.print(' (the REPL will use the
|
|
11
|
+
deps.print(' (the REPL will use the keychain-stored key if you have one)');
|
|
12
12
|
}
|
|
13
13
|
else {
|
|
14
14
|
deps.print('Already signed out — no auth.json present.');
|
package/dist/commands/whoami.js
CHANGED
|
@@ -10,7 +10,7 @@ export async function runWhoamiCommand(deps) {
|
|
|
10
10
|
const auth = await readAuthFile();
|
|
11
11
|
if (!auth) {
|
|
12
12
|
deps.print('Not signed in via cspeach login (no ~/.cspeach/auth.json).');
|
|
13
|
-
deps.print('Your REPL may still authenticate via the
|
|
13
|
+
deps.print('Your REPL may still authenticate via the keychain-stored key — run `cspeach` to check.');
|
|
14
14
|
return 0;
|
|
15
15
|
}
|
|
16
16
|
const me = await fetchMe({ proxyUrl: deps.proxyUrl, apiKey: auth.apiKey });
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import keychain from '../../auth/keychain.js';
|
|
2
2
|
export async function checkKeychain() {
|
|
3
3
|
try {
|
|
4
4
|
const probe = `probe-${Date.now()}`;
|
|
5
|
-
await
|
|
6
|
-
const ok = (await
|
|
7
|
-
await
|
|
5
|
+
await keychain.setPassword('cspeach', 'probe', probe);
|
|
6
|
+
const ok = (await keychain.getPassword('cspeach', 'probe')) === probe;
|
|
7
|
+
await keychain.deletePassword('cspeach', 'probe');
|
|
8
8
|
if (ok)
|
|
9
9
|
return { name: 'keychain', ok: true, message: 'OS keychain working' };
|
|
10
10
|
return { name: 'keychain', ok: false, message: 'probe write/read mismatch', hint: 'Per-session fallback mode will be used' };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import keychain from '../../auth/keychain.js';
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
3
|
import { loadConfig, resolveSapTls } from '../../config/loader.js';
|
|
4
4
|
import { probeGet } from './_http-probe.js';
|
|
@@ -26,7 +26,7 @@ export async function checkZcspeach() {
|
|
|
26
26
|
const url = `${protocol}://${sys.host}:${sys.port}/sap/bc/zcspeach/discovery`;
|
|
27
27
|
let pwd = null;
|
|
28
28
|
try {
|
|
29
|
-
pwd = await
|
|
29
|
+
pwd = await keychain.getPassword(SAP_SERVICE, alias);
|
|
30
30
|
}
|
|
31
31
|
catch {
|
|
32
32
|
// keychain unavailable — fall through, will be skipped below
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import keychain from '../auth/keychain.js';
|
|
2
2
|
import { SapConnection } from '@cspeach/sap-client';
|
|
3
3
|
import { resolveSapTls } from '../config/loader.js';
|
|
4
4
|
import { password as promptPassword } from '@inquirer/prompts';
|
|
@@ -12,7 +12,7 @@ export async function getConnection(alias, cfg) {
|
|
|
12
12
|
let passwordValue;
|
|
13
13
|
if (cfg.authType === 'basic') {
|
|
14
14
|
try {
|
|
15
|
-
passwordValue = (await
|
|
15
|
+
passwordValue = (await keychain.getPassword(SAP_SERVICE, alias)) ?? undefined;
|
|
16
16
|
}
|
|
17
17
|
catch { /* keychain unavailable */ }
|
|
18
18
|
if (!passwordValue) {
|
package/dist/sap/onboarding.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { input, select, password, confirm } from '@inquirer/prompts';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
-
import
|
|
3
|
+
import keychain from '../auth/keychain.js';
|
|
4
4
|
import { loadConfig, saveConfig } from '../config/loader.js';
|
|
5
5
|
const SAP_SERVICE = 'cspeach-sap';
|
|
6
6
|
export async function runAddSapWizard() {
|
|
@@ -87,7 +87,7 @@ export async function runAddSapWizard() {
|
|
|
87
87
|
mask: '*',
|
|
88
88
|
});
|
|
89
89
|
try {
|
|
90
|
-
await
|
|
90
|
+
await keychain.setPassword(SAP_SERVICE, alias, pwd);
|
|
91
91
|
}
|
|
92
92
|
catch {
|
|
93
93
|
console.log(chalk.yellow('Warning: keychain unavailable; password will be prompted per session.'));
|
|
@@ -166,7 +166,7 @@ export async function runAddSapWizard() {
|
|
|
166
166
|
mask: '*',
|
|
167
167
|
});
|
|
168
168
|
try {
|
|
169
|
-
await
|
|
169
|
+
await keychain.setPassword('cspeach.ai-hub', 'token', aiHubToken);
|
|
170
170
|
}
|
|
171
171
|
catch {
|
|
172
172
|
console.log(chalk.yellow('Warning: keychain unavailable; AI Hub token will be prompted per session.'));
|
|
@@ -188,7 +188,7 @@ export async function runAddSapWizard() {
|
|
|
188
188
|
mask: '*',
|
|
189
189
|
});
|
|
190
190
|
try {
|
|
191
|
-
await
|
|
191
|
+
await keychain.setPassword('cspeach.anthropic', 'api-key', byokKey);
|
|
192
192
|
}
|
|
193
193
|
catch {
|
|
194
194
|
console.log(chalk.yellow('Warning: keychain unavailable; Anthropic key will be prompted per session.'));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// GENERATED FILE — bundled skills for local mode.
|
|
2
2
|
// Source: https://manifest.cspeach.dev/v1.json
|
|
3
|
-
// Generated: 2026-09-17T15:
|
|
3
|
+
// Generated: 2026-09-17T15:45:29.783Z
|
|
4
4
|
// Manifest signature verified at build time.
|
|
5
5
|
export const BUNDLED_SKILLS = {
|
|
6
6
|
"abap-atc-fix": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cspeach/cli",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.8",
|
|
4
4
|
"description": "CSPeach — AI-assisted ABAP development CLI. Direct SAP access, 34 skills, safety gates.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"abap",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"ink": "^5.0.0",
|
|
72
72
|
"ink-text-input": "^6.0.0",
|
|
73
73
|
"jose": "^5.9.0",
|
|
74
|
-
"
|
|
74
|
+
"@napi-rs/keyring": "2.1.0",
|
|
75
75
|
"mammoth": "^1.8.0",
|
|
76
76
|
"marked": "^11.2.0",
|
|
77
77
|
"marked-terminal": "^6.2.0",
|
|
@@ -102,7 +102,6 @@
|
|
|
102
102
|
},
|
|
103
103
|
"pnpm": {
|
|
104
104
|
"onlyBuiltDependencies": [
|
|
105
|
-
"keytar",
|
|
106
105
|
"esbuild"
|
|
107
106
|
]
|
|
108
107
|
}
|