@ekanos/cli 0.12.0 → 0.14.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 +25 -8
- package/dist/agents-api.d.ts +11 -2
- package/dist/agents-api.js +39 -3
- package/dist/agents-api.js.map +1 -1
- package/dist/apps-api.d.ts +3 -2
- package/dist/apps-api.js +3 -7
- package/dist/apps-api.js.map +1 -1
- package/dist/auth/ekanos-api.d.ts +16 -2
- package/dist/auth/ekanos-api.js +101 -15
- package/dist/auth/ekanos-api.js.map +1 -1
- package/dist/auth/host-trust.d.ts +46 -0
- package/dist/auth/host-trust.js +79 -0
- package/dist/auth/host-trust.js.map +1 -0
- package/dist/auth/session.d.ts +10 -1
- package/dist/auth/session.js +28 -28
- package/dist/auth/session.js.map +1 -1
- package/dist/commands/agents-edit.d.ts +6 -2
- package/dist/commands/agents-edit.js +57 -26
- package/dist/commands/agents-edit.js.map +1 -1
- package/dist/commands/agents.d.ts +13 -2
- package/dist/commands/agents.js +148 -36
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/apps.d.ts +15 -4
- package/dist/commands/apps.js +133 -51
- package/dist/commands/apps.js.map +1 -1
- package/dist/commands/catalog.js +7 -6
- package/dist/commands/catalog.js.map +1 -1
- package/dist/commands/knowledge.d.ts +56 -0
- package/dist/commands/knowledge.js +456 -0
- package/dist/commands/knowledge.js.map +1 -0
- package/dist/commands/login.d.ts +4 -0
- package/dist/commands/login.js +30 -2
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.d.ts +9 -1
- package/dist/commands/logout.js +56 -7
- package/dist/commands/logout.js.map +1 -1
- package/dist/commands/publish.js +3 -3
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/reviewers.d.ts +2 -0
- package/dist/commands/reviewers.js +7 -3
- package/dist/commands/reviewers.js.map +1 -1
- package/dist/commands/routes.d.ts +2 -0
- package/dist/commands/routes.js +42 -9
- package/dist/commands/routes.js.map +1 -1
- package/dist/commands/runs.d.ts +13 -2
- package/dist/commands/runs.js +96 -15
- package/dist/commands/runs.js.map +1 -1
- package/dist/commands/scope-notice.d.ts +21 -0
- package/dist/commands/scope-notice.js +35 -0
- package/dist/commands/scope-notice.js.map +1 -0
- package/dist/commands/skills.d.ts +7 -1
- package/dist/commands/skills.js +80 -24
- package/dist/commands/skills.js.map +1 -1
- package/dist/commands/sources.d.ts +4 -0
- package/dist/commands/sources.js +233 -5
- package/dist/commands/sources.js.map +1 -1
- package/dist/commands/status.js +5 -4
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/team-agent-readiness.d.ts +59 -0
- package/dist/commands/team-agent-readiness.js +341 -0
- package/dist/commands/team-agent-readiness.js.map +1 -0
- package/dist/commands/team-agents-agents.d.ts +24 -3
- package/dist/commands/team-agents-agents.js +336 -35
- package/dist/commands/team-agents-agents.js.map +1 -1
- package/dist/commands/team-agents-mcp.js +32 -3
- package/dist/commands/team-agents-mcp.js.map +1 -1
- package/dist/commands/team-agents-triggers.js +230 -54
- package/dist/commands/team-agents-triggers.js.map +1 -1
- package/dist/commands/team-agents.d.ts +3 -1
- package/dist/commands/team-agents.js +27 -7
- package/dist/commands/team-agents.js.map +1 -1
- package/dist/commands/teams-channel-install.d.ts +24 -0
- package/dist/commands/teams-channel-install.js +94 -0
- package/dist/commands/teams-channel-install.js.map +1 -0
- package/dist/commands/teams-connect.d.ts +66 -0
- package/dist/commands/teams-connect.js +397 -0
- package/dist/commands/teams-connect.js.map +1 -0
- package/dist/commands/teams-events.d.ts +12 -0
- package/dist/commands/teams-events.js +138 -0
- package/dist/commands/teams-events.js.map +1 -0
- package/dist/commands/teams-onboard.d.ts +16 -5
- package/dist/commands/teams-onboard.js +61 -36
- package/dist/commands/teams-onboard.js.map +1 -1
- package/dist/commands/teams-overview.d.ts +11 -0
- package/dist/commands/teams-overview.js +160 -0
- package/dist/commands/teams-overview.js.map +1 -0
- package/dist/commands/teams-scope.d.ts +10 -0
- package/dist/commands/teams-scope.js +109 -0
- package/dist/commands/teams-scope.js.map +1 -0
- package/dist/commands/teams.d.ts +64 -7
- package/dist/commands/teams.js +254 -60
- package/dist/commands/teams.js.map +1 -1
- package/dist/commands/upgrade.js +12 -2
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/commands/use.js +2 -2
- package/dist/commands/use.js.map +1 -1
- package/dist/commands/whoami.js +1 -1
- package/dist/commands/whoami.js.map +1 -1
- package/dist/connections-api.js +1 -1
- package/dist/connections-api.js.map +1 -1
- package/dist/delegate.js +11 -4
- package/dist/delegate.js.map +1 -1
- package/dist/harness-scaffold.js +12 -0
- package/dist/harness-scaffold.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.js +724 -152
- package/dist/index.js.map +1 -1
- package/dist/knowledge-api.d.ts +175 -0
- package/dist/knowledge-api.js +169 -0
- package/dist/knowledge-api.js.map +1 -0
- package/dist/open-url.d.ts +16 -0
- package/dist/open-url.js +73 -0
- package/dist/open-url.js.map +1 -0
- package/dist/parse-argv.d.ts +2 -0
- package/dist/parse-argv.js.map +1 -1
- package/dist/publish-api.d.ts +2 -1
- package/dist/publish-api.js +4 -3
- package/dist/publish-api.js.map +1 -1
- package/dist/pull-write.d.ts +27 -0
- package/dist/pull-write.js +60 -0
- package/dist/pull-write.js.map +1 -0
- package/dist/routes-api.d.ts +3 -0
- package/dist/routes-api.js +9 -4
- package/dist/routes-api.js.map +1 -1
- package/dist/runs-api.d.ts +7 -1
- package/dist/runs-api.js +21 -6
- package/dist/runs-api.js.map +1 -1
- package/dist/safe-fs.d.ts +2 -0
- package/dist/safe-fs.js +12 -6
- package/dist/safe-fs.js.map +1 -1
- package/dist/secret-file.d.ts +17 -0
- package/dist/secret-file.js +69 -0
- package/dist/secret-file.js.map +1 -0
- package/dist/skills-api.d.ts +10 -2
- package/dist/skills-api.js +37 -2
- package/dist/skills-api.js.map +1 -1
- package/dist/source-products-api.d.ts +63 -0
- package/dist/source-products-api.js +123 -0
- package/dist/source-products-api.js.map +1 -0
- package/dist/source-target.js +2 -1
- package/dist/source-target.js.map +1 -1
- package/dist/sources-api.d.ts +2 -1
- package/dist/sources-api.js +3 -2
- package/dist/sources-api.js.map +1 -1
- package/dist/team-connect-api.d.ts +286 -0
- package/dist/team-connect-api.js +107 -0
- package/dist/team-connect-api.js.map +1 -0
- package/dist/teams-api.d.ts +42 -1
- package/dist/teams-api.js +98 -20
- package/dist/teams-api.js.map +1 -1
- package/dist/toolchain-api.d.ts +9 -0
- package/dist/toolchain-api.js +17 -2
- package/dist/toolchain-api.js.map +1 -1
- package/dist/toolchain-resolve.d.ts +3 -0
- package/dist/toolchain-resolve.js +15 -1
- package/dist/toolchain-resolve.js.map +1 -1
- package/dist/toolchain.d.ts +6 -0
- package/dist/toolchain.js +19 -0
- package/dist/toolchain.js.map +1 -1
- package/dist/update-notice.js +2 -1
- package/dist/update-notice.js.map +1 -1
- package/package.json +2 -2
- package/templates/AGENTS.md.tmpl +6 -1
- package/templates/claude-skill.md.tmpl +5 -0
- package/templates/package.json.tmpl +4 -4
- package/templates/skills/build-agent/SKILL.md +115 -16
- package/templates/skills/build-agent/references/agent-json.md +26 -8
- package/templates/skills/build-agent/references/app-setup.md +2 -1
- package/templates/skills/build-agent/references/rollout.md +27 -4
- package/templates/skills/build-agent/references/set-up-an-integration.md +74 -15
- package/templates/skills/build-agent/references/skills.md +20 -1
- package/templates/skills/build-agent/references/triggers.md +84 -20
- package/templates/skills/build-integration/references/widget-design.md +3 -3
- package/templates/skills/ekanos-platform/SKILL.md +70 -17
- package/templates/skills/polish-widgets/references/patterns.md +2 -2
package/dist/commands/apps.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { setProviderApp, showProviderApp, } from '../apps-api.js';
|
|
2
|
+
import { loginHint } from '../auth/host-trust.js';
|
|
2
3
|
import { refreshStoredSession, requireSession, resolveAuthEnvironment, } from '../auth/session.js';
|
|
3
4
|
import { deleteConnection, listConnections, showConnection, startConnection, } from '../connections-api.js';
|
|
4
5
|
import { authRequiredError, invalidStateError, usageError, validationError, } from '../errors.js';
|
|
@@ -15,9 +16,9 @@ export const APPS_SUBCOMMANDS = [
|
|
|
15
16
|
* `apps` — a Source's provider apps: the OAuth client an integration signs
|
|
16
17
|
* every team in through (Linear's, say). `show` says whether the Source has
|
|
17
18
|
* one and which callback URL to register; `set` takes the client id and
|
|
18
|
-
* secret from the Source admin at the terminal —
|
|
19
|
-
*
|
|
20
|
-
* secret.
|
|
19
|
+
* secret from the Source admin at the terminal — either on its own, Enter
|
|
20
|
+
* keeping the saved one — never from a flag, a file or a non-interactive
|
|
21
|
+
* run, so an agent driving the CLI never handles the secret.
|
|
21
22
|
*/
|
|
22
23
|
export async function runApps(ctx, args) {
|
|
23
24
|
var _a, _b, _c;
|
|
@@ -34,7 +35,7 @@ export async function runApps(ctx, args) {
|
|
|
34
35
|
const env = resolveAuthEnvironment(ctx, args.host, args.env, {
|
|
35
36
|
projectDir: args.dir,
|
|
36
37
|
});
|
|
37
|
-
const resolved = await resolveSourceTarget(env, requireSession(env
|
|
38
|
+
const resolved = await resolveSourceTarget(env, requireSession(env), args);
|
|
38
39
|
const client = new AppsClient(env, resolved.session);
|
|
39
40
|
const source = resolved.source;
|
|
40
41
|
if (subcommand === 'show') {
|
|
@@ -42,29 +43,32 @@ export async function runApps(ctx, args) {
|
|
|
42
43
|
}
|
|
43
44
|
const status = await client.call((token) => showProviderApp(env.host, token, source, product));
|
|
44
45
|
ctx.log(walkthrough(status).join('\n'));
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
const
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
46
|
+
// Either credential on its own: Enter keeps what is saved. An older host
|
|
47
|
+
// sends no `fields`; then `configured` says whether both are saved.
|
|
48
|
+
const saved = (name) => { var _a; var _b; return (_b = (_a = status.fields) === null || _a === void 0 ? void 0 : _a.find((field) => field.name === name)) !== null && _b !== void 0 ? _b : {
|
|
49
|
+
set: status.configured,
|
|
50
|
+
value: null,
|
|
51
|
+
}; };
|
|
52
|
+
const savedId = saved('clientId');
|
|
53
|
+
const savedSecret = saved('clientSecret');
|
|
54
|
+
const clientId = (await ((_a = args.ask) !== null && _a !== void 0 ? _a : promptLine)(savedId.set
|
|
55
|
+
? `Client ID (current: ${(_b = savedId.value) !== null && _b !== void 0 ? _b : 'saved'} — Enter to keep): `
|
|
56
|
+
: 'Client ID: ')).trim();
|
|
57
|
+
const clientSecret = (await ((_c = args.askSecret) !== null && _c !== void 0 ? _c : promptHidden)(savedSecret.set
|
|
58
|
+
? 'Client secret (saved — Enter to keep, hidden): '
|
|
59
|
+
: 'Client secret (hidden): ')).trim();
|
|
60
|
+
if (!clientId && !clientSecret) {
|
|
61
|
+
throw validationError('Nothing was changed.', `Run "ekanos apps show ${product}" to see the current state.`);
|
|
55
62
|
}
|
|
56
|
-
const result = await client.call((token) => setProviderApp(env.host, token, {
|
|
57
|
-
|
|
58
|
-
product,
|
|
59
|
-
clientId,
|
|
60
|
-
clientSecret,
|
|
61
|
-
}));
|
|
63
|
+
const result = await client.call((token) => setProviderApp(env.host, token, Object.assign(Object.assign({ source,
|
|
64
|
+
product }, (clientId ? { clientId } : {})), (clientSecret ? { clientSecret } : {}))));
|
|
62
65
|
return ctx.succeed(Object.assign({ host: env.host }, result), ctx.ui.result({
|
|
63
66
|
title: result.replaced
|
|
64
|
-
? `
|
|
67
|
+
? `Updated the ${result.product.name} app`
|
|
65
68
|
: `Set up the ${result.product.name} app`,
|
|
66
69
|
rows: [
|
|
67
70
|
['Source', result.source.slug],
|
|
71
|
+
...providerFieldRows(result),
|
|
68
72
|
['Teams can connect', result.configured ? 'yes' : 'not yet'],
|
|
69
73
|
['Callback URLs', callbackUrls(result)],
|
|
70
74
|
],
|
|
@@ -112,8 +116,9 @@ function summary(ctx, status) {
|
|
|
112
116
|
],
|
|
113
117
|
]
|
|
114
118
|
: []),
|
|
119
|
+
...providerFieldRows(status),
|
|
115
120
|
[
|
|
116
|
-
'
|
|
121
|
+
'App ready',
|
|
117
122
|
status.configured
|
|
118
123
|
? 'yes — teams can connect'
|
|
119
124
|
: 'no — no team can connect yet',
|
|
@@ -209,7 +214,7 @@ async function runConnection(ctx, args, subcommand, product) {
|
|
|
209
214
|
}
|
|
210
215
|
const shown = await client.connection((token) => showConnection(env.host, token, source, product));
|
|
211
216
|
if (shown.status === 'unsupported') {
|
|
212
|
-
throw invalidStateError(shown.message, `Each team connects ${product} itself
|
|
217
|
+
throw invalidStateError(shown.message, `Each team connects ${product} itself: "ekanos teams connect <team> ${product}".`);
|
|
213
218
|
}
|
|
214
219
|
if (shown.status !== 'ok') {
|
|
215
220
|
throw invalidStateError('The host could not read the connection.', 'Retry shortly.');
|
|
@@ -284,7 +289,10 @@ async function askFields(ctx, args, current, product) {
|
|
|
284
289
|
}
|
|
285
290
|
async function disconnect(ctx, args, client, host, source, product) {
|
|
286
291
|
var _a;
|
|
287
|
-
if (canPrompt(ctx, args)) {
|
|
292
|
+
if (!args.yes && !canPrompt(ctx, args)) {
|
|
293
|
+
throw invalidStateError(`Disconnecting ${product} on ${source} stops it for every team's provided agents that use the Source connection, until someone connects it again.`, `Re-run with --yes: ekanos apps disconnect ${product} --source ${source} --yes`);
|
|
294
|
+
}
|
|
295
|
+
if (!args.yes) {
|
|
288
296
|
const sure = await ((_a = args.confirm) !== null && _a !== void 0 ? _a : promptYesNo)(`Disconnect ${product} for every team's provided agents on ${source}? [y/N]`);
|
|
289
297
|
if (!sure) {
|
|
290
298
|
throw validationError('Nothing was changed.', `Run "ekanos apps show ${product}" to see the current state.`);
|
|
@@ -292,15 +300,15 @@ async function disconnect(ctx, args, client, host, source, product) {
|
|
|
292
300
|
}
|
|
293
301
|
const result = await client.connection((token) => deleteConnection(host, token, source, product));
|
|
294
302
|
if (result.status === 'unsupported') {
|
|
295
|
-
throw invalidStateError(result.message, `Each team connects ${product} itself
|
|
303
|
+
throw invalidStateError(result.message, `Each team connects ${product} itself: "ekanos teams connect <team> ${product}".`);
|
|
296
304
|
}
|
|
297
305
|
if (result.status !== 'ok') {
|
|
298
306
|
throw invalidStateError('The host could not disconnect.', 'Retry shortly.');
|
|
299
307
|
}
|
|
300
308
|
return ctx.succeed(Object.assign({ host, product }, result.data), ctx.ui.result({
|
|
301
309
|
title: result.data.removed
|
|
302
|
-
? `Disconnected ${product}
|
|
303
|
-
: `${product}
|
|
310
|
+
? `Disconnected the ${product} Source connection on ${source}`
|
|
311
|
+
: `${product} had no Source connection on ${source}`,
|
|
304
312
|
rows: [
|
|
305
313
|
[
|
|
306
314
|
'Provided agents',
|
|
@@ -325,12 +333,12 @@ function connectionSummary(ctx, connection, meta) {
|
|
|
325
333
|
['Redirect URL', meta.callbackUrls],
|
|
326
334
|
[
|
|
327
335
|
'Used by',
|
|
328
|
-
|
|
336
|
+
`provided agents whose template says connections.${connection.slug}.owner: "source", in every team`,
|
|
329
337
|
],
|
|
330
338
|
];
|
|
331
339
|
return [
|
|
332
340
|
ctx.ui.result({
|
|
333
|
-
title: `${connection.name} —
|
|
341
|
+
title: `${connection.name} — Source connection (one for every team's provided agents)`,
|
|
334
342
|
rows,
|
|
335
343
|
}),
|
|
336
344
|
...(connection.connected
|
|
@@ -344,7 +352,7 @@ async function openClient(ctx, args) {
|
|
|
344
352
|
const env = resolveAuthEnvironment(ctx, args.host, args.env, {
|
|
345
353
|
projectDir: args.dir,
|
|
346
354
|
});
|
|
347
|
-
const resolved = await resolveSourceTarget(env, requireSession(env
|
|
355
|
+
const resolved = await resolveSourceTarget(env, requireSession(env), args);
|
|
348
356
|
return {
|
|
349
357
|
env,
|
|
350
358
|
client: new AppsClient(env, resolved.session),
|
|
@@ -364,7 +372,7 @@ class AppsClient {
|
|
|
364
372
|
}
|
|
365
373
|
if (result.status === 'ok')
|
|
366
374
|
return result.data;
|
|
367
|
-
throw authRequiredError(`The session for ${this.env.host} could not authorize the apps call.`,
|
|
375
|
+
throw authRequiredError(`The session for ${this.env.host} could not authorize the apps call.`, loginHint(this.env));
|
|
368
376
|
}
|
|
369
377
|
/** As `call`, for the connections client, whose 409s are answers. */
|
|
370
378
|
async connection(send) {
|
|
@@ -375,7 +383,7 @@ class AppsClient {
|
|
|
375
383
|
}
|
|
376
384
|
if (result.status !== 'unauthorized')
|
|
377
385
|
return result;
|
|
378
|
-
throw authRequiredError(`The session for ${this.env.host} could not authorize the connections call.`,
|
|
386
|
+
throw authRequiredError(`The session for ${this.env.host} could not authorize the connections call.`, loginHint(this.env));
|
|
379
387
|
}
|
|
380
388
|
}
|
|
381
389
|
function canPrompt(ctx, args) {
|
|
@@ -409,27 +417,101 @@ export async function promptLine(question) {
|
|
|
409
417
|
rl.close();
|
|
410
418
|
}
|
|
411
419
|
}
|
|
412
|
-
/**
|
|
420
|
+
/**
|
|
421
|
+
* Read a line without echoing it: the secret never appears on screen or in
|
|
422
|
+
* scrollback. The question is always printed; only the typed characters are
|
|
423
|
+
* hidden (each shows as `*`, so a paste visibly landed).
|
|
424
|
+
*
|
|
425
|
+
* Raw mode by hand rather than readline: a terminal readline redraws its
|
|
426
|
+
* line on `question()` — cursor to column 0, clear to the end of the screen —
|
|
427
|
+
* which erased the question written before it, so the terminal sat on an
|
|
428
|
+
* empty line and a hidden field looked skipped.
|
|
429
|
+
*/
|
|
413
430
|
export async function promptHidden(question) {
|
|
414
|
-
const
|
|
415
|
-
process.stderr
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
finally {
|
|
430
|
-
rl.close();
|
|
431
|
-
process.stderr.write('\n');
|
|
431
|
+
const stdin = process.stdin;
|
|
432
|
+
const stderr = process.stderr;
|
|
433
|
+
stderr.write(question);
|
|
434
|
+
if (!stdin.isTTY) {
|
|
435
|
+
// Piped stdin echoes nothing: read one line as is.
|
|
436
|
+
const readline = await import('node:readline/promises');
|
|
437
|
+
const rl = readline.createInterface({ input: stdin, terminal: false });
|
|
438
|
+
try {
|
|
439
|
+
return await rl.question('');
|
|
440
|
+
}
|
|
441
|
+
finally {
|
|
442
|
+
rl.close();
|
|
443
|
+
stderr.write('\n');
|
|
444
|
+
}
|
|
432
445
|
}
|
|
446
|
+
return new Promise((resolve) => {
|
|
447
|
+
let value = '';
|
|
448
|
+
let inEscape = false;
|
|
449
|
+
const wasRaw = stdin.isRaw;
|
|
450
|
+
const finish = () => {
|
|
451
|
+
stdin.off('data', onData);
|
|
452
|
+
stdin.setRawMode(wasRaw);
|
|
453
|
+
stdin.pause();
|
|
454
|
+
stderr.write('\n');
|
|
455
|
+
};
|
|
456
|
+
const onData = (chunk) => {
|
|
457
|
+
for (const char of typeof chunk === 'string'
|
|
458
|
+
? chunk
|
|
459
|
+
: chunk.toString('utf8')) {
|
|
460
|
+
if (inEscape) {
|
|
461
|
+
// An escape sequence (an arrow key) ends at its final letter.
|
|
462
|
+
if (/[A-Za-z~]/.test(char))
|
|
463
|
+
inEscape = false;
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
if (char === '\u001b') {
|
|
467
|
+
inEscape = true;
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
if (char === '\r' || char === '\n' || char === '\u0004') {
|
|
471
|
+
finish();
|
|
472
|
+
resolve(value);
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
if (char === '\u0003') {
|
|
476
|
+
// Ctrl-C: raw mode swallowed the signal, so leave as SIGINT would.
|
|
477
|
+
finish();
|
|
478
|
+
process.exit(130);
|
|
479
|
+
}
|
|
480
|
+
if (char === '\u007f' || char === '\b') {
|
|
481
|
+
if (value.length > 0) {
|
|
482
|
+
value = value.slice(0, -1);
|
|
483
|
+
stderr.write('\b \b');
|
|
484
|
+
}
|
|
485
|
+
continue;
|
|
486
|
+
}
|
|
487
|
+
if (char === '\u0015') {
|
|
488
|
+
// Ctrl-U: clear what was typed.
|
|
489
|
+
stderr.write('\b \b'.repeat(value.length));
|
|
490
|
+
value = '';
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
if (char < ' ')
|
|
494
|
+
continue;
|
|
495
|
+
value += char;
|
|
496
|
+
stderr.write('*');
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
stdin.setRawMode(true);
|
|
500
|
+
stdin.resume();
|
|
501
|
+
stdin.on('data', onData);
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
/** Each credential's state: the client id's value, the secret as saved or not. */
|
|
505
|
+
function providerFieldRows(status) {
|
|
506
|
+
var _a;
|
|
507
|
+
return ((_a = status.fields) !== null && _a !== void 0 ? _a : []).map((field) => { var _a; return [
|
|
508
|
+
field.label,
|
|
509
|
+
!field.set
|
|
510
|
+
? 'not set'
|
|
511
|
+
: field.sensitive
|
|
512
|
+
? 'saved'
|
|
513
|
+
: ((_a = field.value) !== null && _a !== void 0 ? _a : 'saved'),
|
|
514
|
+
]; });
|
|
433
515
|
}
|
|
434
516
|
/** Every redirect URI to register; an older host sends only the one. */
|
|
435
517
|
function callbackUrls(status) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apps.js","sourceRoot":"","sources":["../../src/commands/apps.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ProviderAppStatus } from '@ekanos/integration-schema';\n\nimport {\n type AppsApiResult,\n setProviderApp,\n showProviderApp,\n} from '../apps-api';\nimport type { StoredSession } from '../auth/credential-store';\nimport {\n type AuthEnvironment,\n refreshStoredSession,\n requireSession,\n resolveAuthEnvironment,\n} from '../auth/session';\nimport {\n type ConnectionsApiResult,\n type SourceConnection,\n deleteConnection,\n listConnections,\n showConnection,\n startConnection,\n} from '../connections-api';\nimport type { CliContext } from '../context';\nimport {\n authRequiredError,\n invalidStateError,\n usageError,\n validationError,\n} from '../errors';\nimport type { ExitCode } from '../exit-codes';\nimport { resolveSourceTarget } from '../source-target';\nimport type { ResultRow } from '../ui';\nimport { promptYesNo } from './publish';\n\nexport const APPS_SUBCOMMANDS = [\n 'show',\n 'set',\n 'list',\n 'connect',\n 'disconnect',\n] as const;\ntype AppsSubcommand = (typeof APPS_SUBCOMMANDS)[number];\n\nexport interface AppsArgs {\n host?: string;\n source?: string;\n subcommand?: string;\n product?: string;\n dir: string;\n env: Record<string, string | undefined>;\n stdinIsTTY?: boolean;\n /** Test seams for the questions `set` and `connect` ask. */\n ask?: (question: string) => Promise<string>;\n askSecret?: (question: string) => Promise<string>;\n confirm?: (question: string) => Promise<boolean>;\n /** Test seam: `connect`'s wait between status polls. */\n pollDelayMs?: number;\n /** `connect --no-wait`: print the URL and return without polling. */\n noWait?: boolean;\n}\n\n/**\n * `apps` — a Source's provider apps: the OAuth client an integration signs\n * every team in through (Linear's, say). `show` says whether the Source has\n * one and which callback URL to register; `set` takes the client id and\n * secret from the Source admin at the terminal — never from a flag, a file\n * or a non-interactive run, so an agent driving the CLI never handles the\n * secret.\n */\nexport async function runApps(\n ctx: CliContext,\n args: AppsArgs,\n): Promise<ExitCode> {\n const subcommand = parseSubcommand(args.subcommand);\n if (subcommand === 'list') return runList(ctx, args);\n const product = requireProduct(args.product, subcommand);\n if (subcommand === 'connect' || subcommand === 'disconnect') {\n return runConnection(ctx, args, subcommand, product);\n }\n\n if (subcommand === 'set' && !canPrompt(ctx, args)) {\n throw usageError(\n 'apps set takes the client secret at a terminal, never in a script or an agent run.',\n `Run it yourself in your terminal: npx @ekanos/cli apps set ${product}${args.source ? ` --source ${args.source}` : ''}`,\n );\n }\n\n const env = resolveAuthEnvironment(ctx, args.host, args.env, {\n projectDir: args.dir,\n });\n const resolved = await resolveSourceTarget(\n env,\n requireSession(env.store, env.host),\n args,\n );\n const client = new AppsClient(env, resolved.session);\n const source = resolved.source;\n\n if (subcommand === 'show') {\n return showApp(ctx, env.host, client, source, product);\n }\n\n const status = await client.call((token) =>\n showProviderApp(env.host, token, source, product),\n );\n\n ctx.log(walkthrough(status).join('\\n'));\n if (status.configured) {\n const replace = await (args.confirm ?? promptYesNo)(\n `${status.source.slug} already has ${status.product.name} credentials. Replace them? [y/N]`,\n );\n if (!replace) {\n throw validationError(\n 'Nothing was changed.',\n `Run \"ekanos apps show ${product}\" to see the current state.`,\n );\n }\n }\n\n const clientId = (await (args.ask ?? promptLine)('Client ID: ')).trim();\n const clientSecret = (\n await (args.askSecret ?? promptHidden)('Client secret (hidden): ')\n ).trim();\n if (!clientId || !clientSecret) {\n throw validationError(\n 'Both the client ID and the client secret are needed.',\n `Run \"ekanos apps set ${product}\" again.`,\n );\n }\n\n const result = await client.call((token) =>\n setProviderApp(env.host, token, {\n source,\n product,\n clientId,\n clientSecret,\n }),\n );\n return ctx.succeed(\n { host: env.host, ...result },\n ctx.ui.result({\n title: result.replaced\n ? `Replaced the ${result.product.name} app`\n : `Set up the ${result.product.name} app`,\n rows: [\n ['Source', result.source.slug],\n ['Teams can connect', result.configured ? 'yes' : 'not yet'],\n ['Callback URLs', callbackUrls(result)],\n ],\n }),\n );\n}\n\n/**\n * How to create the app: the integration's own steps (`oauth.setup`, with the\n * callback URL filled in) when it declares them, else the generic three.\n */\nexport function walkthrough(status: ProviderAppStatus): string[] {\n const name = status.product.name;\n const lines = [`${name} app for ${status.source.slug}`];\n if (status.setup?.consoleUrl) {\n lines.push(` Open: ${status.setup.consoleUrl}`);\n }\n const steps = status.setup?.steps.length\n ? [\n ...status.setup.steps,\n `Check the app lists exactly: ${callbackUrls(status).join(', ')}`,\n ]\n : [\n `In ${name}, create an OAuth app (or open the one you use).`,\n `Register exactly these callback URLs: ${callbackUrls(status).join(', ')}`,\n ];\n steps.push(\n \"Enter its client ID and secret below. The secret is stored in Ekanos's vault and never shown again.\",\n );\n lines.push(...steps.map((step, index) => ` ${index + 1}. ${step}`));\n if (status.setup?.guideUrl) lines.push(` Guide: ${status.setup.guideUrl}`);\n return lines;\n}\n\nfunction summary(ctx: CliContext, status: ProviderAppStatus): string {\n const rows: ResultRow[] = [\n ['Source', status.source.slug],\n ...(status.setup\n ? ([\n [\n 'How to create it',\n [\n ...(status.setup.consoleUrl\n ? [`Open ${status.setup.consoleUrl}`]\n : []),\n ...status.setup.steps.map(\n (step, index) => `${index + 1}. ${step}`,\n ),\n ],\n ],\n ] as const)\n : []),\n [\n 'Set up',\n status.configured\n ? 'yes — teams can connect'\n : 'no — no team can connect yet',\n ],\n ['Callback URLs', callbackUrls(status)],\n ];\n return [\n ctx.ui.result({ title: `${status.product.name} app`, rows }),\n ...(status.configured\n ? []\n : [\n ctx.ui.hint(\n `Run \"ekanos apps set ${status.product.slug}\" in your terminal to enter its credentials.`,\n ),\n ]),\n ].join('\\n');\n}\n\n/**\n * `apps show <product>`: the Source provider app, and — for an integration\n * that supports one — the Source connection (plan 241). A `teamApp`\n * integration (Zendesk) has no provider app but can have a Source\n * connection, so either half may be absent.\n */\nasync function showApp(\n ctx: CliContext,\n host: string,\n client: AppsClient,\n source: string,\n product: string,\n): Promise<ExitCode> {\n const [app, connection] = await Promise.all([\n client\n .call((token) => showProviderApp(host, token, source, product))\n .then(\n (status) => ({ ok: true as const, status }),\n (error: unknown) => ({ ok: false as const, error }),\n ),\n // A host without the connections routes (before plan 241), or one that\n // refuses, leaves `show` exactly as it was: the provider app alone.\n client\n .connection((token) => showConnection(host, token, source, product))\n .catch(() => ({ status: 'unavailable' as const })),\n ]);\n\n if (!app.ok && connection.status !== 'ok') throw app.error;\n\n const parts: string[] = [];\n if (app.ok) parts.push(summary(ctx, app.status));\n if (connection.status === 'ok') {\n parts.push(\n connectionSummary(ctx, connection.data.connection, {\n sourceSlug: connection.data.source.slug,\n callbackUrls: connection.data.callbackUrls,\n }),\n );\n }\n\n return ctx.succeed(\n {\n host,\n ...(app.ok ? app.status : {}),\n ...(connection.status === 'ok'\n ? {\n sourceConnection: connection.data.connection,\n sourceConnectionCallbackUrls: connection.data.callbackUrls,\n }\n : {}),\n },\n parts.join('\\n'),\n );\n}\n\n/** `apps list`: every integration the Source can connect once, with status. */\nasync function runList(ctx: CliContext, args: AppsArgs): Promise<ExitCode> {\n const { env, client, source } = await openClient(ctx, args);\n const result = await client.connection((token) =>\n listConnections(env.host, token, source),\n );\n if (result.status !== 'ok') {\n throw invalidStateError(\n 'The host could not list the connections.',\n 'Retry shortly.',\n );\n }\n const { connections } = result.data;\n const rows: ResultRow[] = connections.map((connection) => [\n `${connection.name} (${connection.slug})`,\n connectionState(connection),\n ]);\n return ctx.succeed(\n { host: env.host, ...result.data },\n connections.length === 0\n ? ctx.ui.hint(\n `No integration on ${result.data.source.slug} supports one connection for the whole Source yet.`,\n )\n : ctx.ui.result({\n title: `Source connections on ${result.data.source.slug}`,\n rows,\n }),\n );\n}\n\nfunction connectionState(connection: SourceConnection): string {\n if (connection.connected) {\n return [\n 'connected',\n connection.connectedAt ? ` ${connection.connectedAt}` : '',\n connection.connectedBy ? ` by ${connection.connectedBy}` : '',\n ].join('');\n }\n return connection.missing.length > 0\n ? `not connected — app fields missing: ${connection.missing.join(', ')}`\n : 'not connected';\n}\n\n/**\n * `apps connect <product>`: connect the integration ONCE for the whole Source,\n * for the Source's provided agents whose template says `owner: \"source\"`.\n * Asks for any missing app fields at the terminal (secrets hidden, never from\n * a flag), prints the provider's consent URL, then waits until the browser\n * finishes. `apps disconnect <product>` removes it.\n */\nasync function runConnection(\n ctx: CliContext,\n args: AppsArgs,\n subcommand: 'connect' | 'disconnect',\n product: string,\n): Promise<ExitCode> {\n const { env, client, source } = await openClient(ctx, args);\n\n if (subcommand === 'disconnect') {\n return disconnect(ctx, args, client, env.host, source, product);\n }\n\n const shown = await client.connection((token) =>\n showConnection(env.host, token, source, product),\n );\n if (shown.status === 'unsupported') {\n throw invalidStateError(\n shown.message,\n `Each team connects ${product} itself, from the team's Integrations page.`,\n );\n }\n if (shown.status !== 'ok') {\n throw invalidStateError(\n 'The host could not read the connection.',\n 'Retry shortly.',\n );\n }\n const current = shown.data.connection;\n\n if (current.app === 'fields') {\n ctx.log(\n [\n `${current.name} app for ${shown.data.source.slug} (one for the whole Source)`,\n ` Register this redirect URL in the app: ${shown.data.callbackUrls.join(', ')}`,\n ].join('\\n'),\n );\n }\n\n const fields = await askFields(ctx, args, current, product);\n\n const started = await client.connection((token) =>\n startConnection(env.host, token, {\n source,\n product,\n ...(Object.keys(fields).length > 0 ? { fields } : {}),\n }),\n );\n if (started.status === 'not-configured') {\n throw validationError(\n `${current.name} is not set up for the Source yet — missing: ${started.missing.join(', ')}.`,\n current.app === 'source-app'\n ? `Run \"ekanos apps set ${product}\" to enter the Source's app first.`\n : `Run \"ekanos apps connect ${product}\" again and fill every field.`,\n );\n }\n if (started.status !== 'ok') {\n throw invalidStateError(\n 'The host could not start the connection.',\n 'Retry shortly.',\n );\n }\n\n ctx.log(\n [\n `Open this link and approve ${current.name} as the account the Source's agents should act as:`,\n ` ${started.data.authorizeUrl}`,\n ].join('\\n'),\n );\n\n if (args.noWait || ctx.jsonMode) {\n return ctx.succeed(\n {\n host: env.host,\n product,\n authorizeUrl: started.data.authorizeUrl,\n callbackUrl: started.data.callbackUrl,\n connected: false,\n },\n ctx.ui.hint(`Then check with \"ekanos apps show ${product}\".`),\n );\n }\n\n const deadline = Date.now() + 10 * 60 * 1000;\n const before = current.connectedAt;\n while (Date.now() < deadline) {\n await new Promise((resolve) =>\n setTimeout(resolve, args.pollDelayMs ?? 3000),\n );\n const polled = await client.connection((token) =>\n showConnection(env.host, token, source, product),\n );\n if (\n polled.status === 'ok' &&\n polled.data.connection.connected &&\n polled.data.connection.connectedAt !== before\n ) {\n return ctx.succeed(\n { host: env.host, product, connection: polled.data.connection },\n connectionSummary(ctx, polled.data.connection, {\n sourceSlug: polled.data.source.slug,\n callbackUrls: polled.data.callbackUrls,\n }),\n );\n }\n }\n throw validationError(\n 'The connection did not finish within ten minutes.',\n `Run \"ekanos apps connect ${product}\" again for a fresh link.`,\n );\n}\n\nasync function askFields(\n ctx: CliContext,\n args: AppsArgs,\n current: SourceConnection,\n product: string,\n): Promise<Record<string, string>> {\n const toAsk = current.fields.filter(\n (field) => !field.set || current.missing.includes(field.name),\n );\n if (toAsk.length === 0) return {};\n if (!canPrompt(ctx, args)) {\n throw usageError(\n `${current.name} needs its app fields entered for the Source: ${toAsk.map((field) => field.label).join(', ')}.`,\n `Run it yourself in your terminal: npx @ekanos/cli apps connect ${product}${args.source ? ` --source ${args.source}` : ''}`,\n );\n }\n const fields: Record<string, string> = {};\n for (const field of toAsk) {\n const question = field.sensitive\n ? `${field.label} (hidden): `\n : `${field.label}: `;\n const value = (\n await (\n field.sensitive\n ? (args.askSecret ?? promptHidden)\n : (args.ask ?? promptLine)\n )(question)\n ).trim();\n if (value) fields[field.name] = value;\n }\n return fields;\n}\n\nasync function disconnect(\n ctx: CliContext,\n args: AppsArgs,\n client: AppsClient,\n host: string,\n source: string,\n product: string,\n): Promise<ExitCode> {\n if (canPrompt(ctx, args)) {\n const sure = await (args.confirm ?? promptYesNo)(\n `Disconnect ${product} for every team's provided agents on ${source}? [y/N]`,\n );\n if (!sure) {\n throw validationError(\n 'Nothing was changed.',\n `Run \"ekanos apps show ${product}\" to see the current state.`,\n );\n }\n }\n const result = await client.connection((token) =>\n deleteConnection(host, token, source, product),\n );\n if (result.status === 'unsupported') {\n throw invalidStateError(\n result.message,\n `Each team connects ${product} itself, from the team's Integrations page.`,\n );\n }\n if (result.status !== 'ok') {\n throw invalidStateError('The host could not disconnect.', 'Retry shortly.');\n }\n return ctx.succeed(\n { host, product, ...result.data },\n ctx.ui.result({\n title: result.data.removed\n ? `Disconnected ${product} for ${source}`\n : `${product} was not connected for ${source}`,\n rows: [\n [\n 'Provided agents',\n 'their tools for this product stop until you connect again',\n ],\n ],\n }),\n );\n}\n\nfunction connectionSummary(\n ctx: CliContext,\n connection: SourceConnection,\n meta: { sourceSlug: string; callbackUrls: string[] },\n): string {\n const rows: ResultRow[] = [\n ['Source', meta.sourceSlug],\n ['Connected', connectionState(connection)],\n ...(connection.scope ? ([['Scope', connection.scope]] as ResultRow[]) : []),\n ...(connection.fields.length > 0\n ? ([\n [\n 'App fields',\n connection.fields.map(\n (field) =>\n `${field.label}: ${field.set ? (field.value ?? 'set') : 'missing'}`,\n ),\n ],\n ] as ResultRow[])\n : []),\n ['Redirect URL', meta.callbackUrls],\n [\n 'Used by',\n 'provided agents whose template says connections.<product>.owner: \"source\", in every team',\n ],\n ];\n return [\n ctx.ui.result({\n title: `${connection.name} — one connection for the whole Source`,\n rows,\n }),\n ...(connection.connected\n ? []\n : [\n ctx.ui.hint(\n `Run \"ekanos apps connect ${connection.slug}\" in your terminal to connect it.`,\n ),\n ]),\n ].join('\\n');\n}\n\nasync function openClient(ctx: CliContext, args: AppsArgs) {\n const env = resolveAuthEnvironment(ctx, args.host, args.env, {\n projectDir: args.dir,\n });\n const resolved = await resolveSourceTarget(\n env,\n requireSession(env.store, env.host),\n args,\n );\n return {\n env,\n client: new AppsClient(env, resolved.session),\n source: resolved.source,\n };\n}\n\nclass AppsClient {\n constructor(\n private readonly env: AuthEnvironment,\n private session: StoredSession,\n ) {}\n\n async call<T>(\n send: (accessToken: string) => Promise<AppsApiResult<T>>,\n ): Promise<T> {\n let result = await send(this.session.accessToken);\n if (result.status === 'unauthorized') {\n this.session = await refreshStoredSession(this.env, this.session);\n result = await send(this.session.accessToken);\n }\n if (result.status === 'ok') return result.data;\n throw authRequiredError(\n `The session for ${this.env.host} could not authorize the apps call.`,\n `Run \"ekanos login --host ${this.env.host}\" and retry.`,\n );\n }\n\n /** As `call`, for the connections client, whose 409s are answers. */\n async connection<T>(\n send: (accessToken: string) => Promise<ConnectionsApiResult<T>>,\n ): Promise<Exclude<ConnectionsApiResult<T>, { status: 'unauthorized' }>> {\n let result = await send(this.session.accessToken);\n if (result.status === 'unauthorized') {\n this.session = await refreshStoredSession(this.env, this.session);\n result = await send(this.session.accessToken);\n }\n if (result.status !== 'unauthorized') return result;\n throw authRequiredError(\n `The session for ${this.env.host} could not authorize the connections call.`,\n `Run \"ekanos login --host ${this.env.host}\" and retry.`,\n );\n }\n}\n\nfunction canPrompt(ctx: CliContext, args: AppsArgs): boolean {\n return !ctx.jsonMode && (args.stdinIsTTY ?? process.stdin.isTTY === true);\n}\n\nfunction parseSubcommand(value: string | undefined): AppsSubcommand {\n const match = APPS_SUBCOMMANDS.find((name) => name === value);\n if (match) return match;\n throw usageError(\n value ? `Unknown apps subcommand \"${value}\".` : 'apps needs a subcommand.',\n `Run one of: ${APPS_SUBCOMMANDS.map((name) => `ekanos apps ${name} <product>`).join(', ')}.`,\n );\n}\n\nfunction requireProduct(value: string | undefined, verb: string): string {\n const slug = value?.trim().toLowerCase();\n if (slug && /^[a-z0-9][a-z0-9-]*$/.test(slug)) return slug;\n throw usageError(\n value\n ? `\"${value}\" is not a product slug.`\n : `apps ${verb} needs a product.`,\n `Pass the product's slug, e.g. \"ekanos apps ${verb} linear\". \"ekanos catalog\" lists them.`,\n );\n}\n\nexport async function promptLine(question: string): Promise<string> {\n const readline = await import('node:readline/promises');\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n try {\n return await rl.question(question);\n } finally {\n rl.close();\n }\n}\n\n/** Read a line without echoing it: the secret never appears on screen or in scrollback. */\nexport async function promptHidden(question: string): Promise<string> {\n const readline = await import('node:readline');\n process.stderr.write(question);\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n terminal: true,\n });\n // Swallow readline's echo of each keystroke; the question is already written.\n (rl as unknown as { _writeToOutput: (text: string) => void })._writeToOutput =\n () => {};\n try {\n return await new Promise<string>((resolve) => {\n rl.question('', resolve);\n });\n } finally {\n rl.close();\n process.stderr.write('\\n');\n }\n}\n\n/** Every redirect URI to register; an older host sends only the one. */\nfunction callbackUrls(status: ProviderAppStatus): string[] {\n return status.callbackUrls?.length\n ? status.callbackUrls\n : [status.callbackUrl];\n}\n"]}
|
|
1
|
+
{"version":3,"file":"apps.js","sourceRoot":"","sources":["../../src/commands/apps.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ProviderAppStatus } from '@ekanos/integration-schema';\n\nimport {\n type AppsApiResult,\n setProviderApp,\n showProviderApp,\n} from '../apps-api';\nimport type { StoredSession } from '../auth/credential-store';\nimport { loginHint } from '../auth/host-trust';\nimport {\n type AuthEnvironment,\n refreshStoredSession,\n requireSession,\n resolveAuthEnvironment,\n} from '../auth/session';\nimport {\n type ConnectionsApiResult,\n type SourceConnection,\n deleteConnection,\n listConnections,\n showConnection,\n startConnection,\n} from '../connections-api';\nimport type { CliContext } from '../context';\nimport {\n authRequiredError,\n invalidStateError,\n usageError,\n validationError,\n} from '../errors';\nimport type { ExitCode } from '../exit-codes';\nimport { resolveSourceTarget } from '../source-target';\nimport type { ResultRow } from '../ui';\nimport { promptYesNo } from './publish';\n\nexport const APPS_SUBCOMMANDS = [\n 'show',\n 'set',\n 'list',\n 'connect',\n 'disconnect',\n] as const;\ntype AppsSubcommand = (typeof APPS_SUBCOMMANDS)[number];\n\nexport interface AppsArgs {\n host?: string;\n source?: string;\n subcommand?: string;\n product?: string;\n dir: string;\n env: Record<string, string | undefined>;\n stdinIsTTY?: boolean;\n /** Test seams for the questions `set` and `connect` ask. */\n ask?: (question: string) => Promise<string>;\n askSecret?: (question: string) => Promise<string>;\n confirm?: (question: string) => Promise<boolean>;\n /** Test seam: `connect`'s wait between status polls. */\n pollDelayMs?: number;\n /** `connect --no-wait`: print the URL and return without polling. */\n noWait?: boolean;\n /** `disconnect --yes`: confirm without the question (a script, an agent run). */\n yes?: boolean;\n}\n\n/**\n * `apps` — a Source's provider apps: the OAuth client an integration signs\n * every team in through (Linear's, say). `show` says whether the Source has\n * one and which callback URL to register; `set` takes the client id and\n * secret from the Source admin at the terminal — either on its own, Enter\n * keeping the saved one — never from a flag, a file or a non-interactive\n * run, so an agent driving the CLI never handles the secret.\n */\nexport async function runApps(\n ctx: CliContext,\n args: AppsArgs,\n): Promise<ExitCode> {\n const subcommand = parseSubcommand(args.subcommand);\n if (subcommand === 'list') return runList(ctx, args);\n const product = requireProduct(args.product, subcommand);\n if (subcommand === 'connect' || subcommand === 'disconnect') {\n return runConnection(ctx, args, subcommand, product);\n }\n\n if (subcommand === 'set' && !canPrompt(ctx, args)) {\n throw usageError(\n 'apps set takes the client secret at a terminal, never in a script or an agent run.',\n `Run it yourself in your terminal: npx @ekanos/cli apps set ${product}${args.source ? ` --source ${args.source}` : ''}`,\n );\n }\n\n const env = resolveAuthEnvironment(ctx, args.host, args.env, {\n projectDir: args.dir,\n });\n const resolved = await resolveSourceTarget(env, requireSession(env), args);\n const client = new AppsClient(env, resolved.session);\n const source = resolved.source;\n\n if (subcommand === 'show') {\n return showApp(ctx, env.host, client, source, product);\n }\n\n const status = await client.call((token) =>\n showProviderApp(env.host, token, source, product),\n );\n\n ctx.log(walkthrough(status).join('\\n'));\n\n // Either credential on its own: Enter keeps what is saved. An older host\n // sends no `fields`; then `configured` says whether both are saved.\n const saved = (name: 'clientId' | 'clientSecret') =>\n status.fields?.find((field) => field.name === name) ?? {\n set: status.configured,\n value: null,\n };\n const savedId = saved('clientId');\n const savedSecret = saved('clientSecret');\n const clientId = (\n await (args.ask ?? promptLine)(\n savedId.set\n ? `Client ID (current: ${savedId.value ?? 'saved'} — Enter to keep): `\n : 'Client ID: ',\n )\n ).trim();\n const clientSecret = (\n await (args.askSecret ?? promptHidden)(\n savedSecret.set\n ? 'Client secret (saved — Enter to keep, hidden): '\n : 'Client secret (hidden): ',\n )\n ).trim();\n if (!clientId && !clientSecret) {\n throw validationError(\n 'Nothing was changed.',\n `Run \"ekanos apps show ${product}\" to see the current state.`,\n );\n }\n\n const result = await client.call((token) =>\n setProviderApp(env.host, token, {\n source,\n product,\n ...(clientId ? { clientId } : {}),\n ...(clientSecret ? { clientSecret } : {}),\n }),\n );\n return ctx.succeed(\n { host: env.host, ...result },\n ctx.ui.result({\n title: result.replaced\n ? `Updated the ${result.product.name} app`\n : `Set up the ${result.product.name} app`,\n rows: [\n ['Source', result.source.slug],\n ...providerFieldRows(result),\n ['Teams can connect', result.configured ? 'yes' : 'not yet'],\n ['Callback URLs', callbackUrls(result)],\n ],\n }),\n );\n}\n\n/**\n * How to create the app: the integration's own steps (`oauth.setup`, with the\n * callback URL filled in) when it declares them, else the generic three.\n */\nexport function walkthrough(status: ProviderAppStatus): string[] {\n const name = status.product.name;\n const lines = [`${name} app for ${status.source.slug}`];\n if (status.setup?.consoleUrl) {\n lines.push(` Open: ${status.setup.consoleUrl}`);\n }\n const steps = status.setup?.steps.length\n ? [\n ...status.setup.steps,\n `Check the app lists exactly: ${callbackUrls(status).join(', ')}`,\n ]\n : [\n `In ${name}, create an OAuth app (or open the one you use).`,\n `Register exactly these callback URLs: ${callbackUrls(status).join(', ')}`,\n ];\n steps.push(\n \"Enter its client ID and secret below. The secret is stored in Ekanos's vault and never shown again.\",\n );\n lines.push(...steps.map((step, index) => ` ${index + 1}. ${step}`));\n if (status.setup?.guideUrl) lines.push(` Guide: ${status.setup.guideUrl}`);\n return lines;\n}\n\nfunction summary(ctx: CliContext, status: ProviderAppStatus): string {\n const rows: ResultRow[] = [\n ['Source', status.source.slug],\n ...(status.setup\n ? ([\n [\n 'How to create it',\n [\n ...(status.setup.consoleUrl\n ? [`Open ${status.setup.consoleUrl}`]\n : []),\n ...status.setup.steps.map(\n (step, index) => `${index + 1}. ${step}`,\n ),\n ],\n ],\n ] as const)\n : []),\n ...providerFieldRows(status),\n [\n 'App ready',\n status.configured\n ? 'yes — teams can connect'\n : 'no — no team can connect yet',\n ],\n ['Callback URLs', callbackUrls(status)],\n ];\n return [\n ctx.ui.result({ title: `${status.product.name} app`, rows }),\n ...(status.configured\n ? []\n : [\n ctx.ui.hint(\n `Run \"ekanos apps set ${status.product.slug}\" in your terminal to enter its credentials.`,\n ),\n ]),\n ].join('\\n');\n}\n\n/**\n * `apps show <product>`: the Source provider app, and — for an integration\n * that supports one — the Source connection (plan 241). A `teamApp`\n * integration (Zendesk) has no provider app but can have a Source\n * connection, so either half may be absent.\n */\nasync function showApp(\n ctx: CliContext,\n host: string,\n client: AppsClient,\n source: string,\n product: string,\n): Promise<ExitCode> {\n const [app, connection] = await Promise.all([\n client\n .call((token) => showProviderApp(host, token, source, product))\n .then(\n (status) => ({ ok: true as const, status }),\n (error: unknown) => ({ ok: false as const, error }),\n ),\n // A host without the connections routes (before plan 241), or one that\n // refuses, leaves `show` exactly as it was: the provider app alone.\n client\n .connection((token) => showConnection(host, token, source, product))\n .catch(() => ({ status: 'unavailable' as const })),\n ]);\n\n if (!app.ok && connection.status !== 'ok') throw app.error;\n\n const parts: string[] = [];\n if (app.ok) parts.push(summary(ctx, app.status));\n if (connection.status === 'ok') {\n parts.push(\n connectionSummary(ctx, connection.data.connection, {\n sourceSlug: connection.data.source.slug,\n callbackUrls: connection.data.callbackUrls,\n }),\n );\n }\n\n return ctx.succeed(\n {\n host,\n ...(app.ok ? app.status : {}),\n ...(connection.status === 'ok'\n ? {\n sourceConnection: connection.data.connection,\n sourceConnectionCallbackUrls: connection.data.callbackUrls,\n }\n : {}),\n },\n parts.join('\\n'),\n );\n}\n\n/** `apps list`: every integration the Source can connect once, with status. */\nasync function runList(ctx: CliContext, args: AppsArgs): Promise<ExitCode> {\n const { env, client, source } = await openClient(ctx, args);\n const result = await client.connection((token) =>\n listConnections(env.host, token, source),\n );\n if (result.status !== 'ok') {\n throw invalidStateError(\n 'The host could not list the connections.',\n 'Retry shortly.',\n );\n }\n const { connections } = result.data;\n const rows: ResultRow[] = connections.map((connection) => [\n `${connection.name} (${connection.slug})`,\n connectionState(connection),\n ]);\n return ctx.succeed(\n { host: env.host, ...result.data },\n connections.length === 0\n ? ctx.ui.hint(\n `No integration on ${result.data.source.slug} supports one connection for the whole Source yet.`,\n )\n : ctx.ui.result({\n title: `Source connections on ${result.data.source.slug}`,\n rows,\n }),\n );\n}\n\nfunction connectionState(connection: SourceConnection): string {\n if (connection.connected) {\n return [\n 'connected',\n connection.connectedAt ? ` ${connection.connectedAt}` : '',\n connection.connectedBy ? ` by ${connection.connectedBy}` : '',\n ].join('');\n }\n return connection.missing.length > 0\n ? `not connected — app fields missing: ${connection.missing.join(', ')}`\n : 'not connected';\n}\n\n/**\n * `apps connect <product>`: connect the integration ONCE for the whole Source,\n * for the Source's provided agents whose template says `owner: \"source\"`.\n * Asks for any missing app fields at the terminal (secrets hidden, never from\n * a flag), prints the provider's consent URL, then waits until the browser\n * finishes. `apps disconnect <product>` removes it.\n */\nasync function runConnection(\n ctx: CliContext,\n args: AppsArgs,\n subcommand: 'connect' | 'disconnect',\n product: string,\n): Promise<ExitCode> {\n const { env, client, source } = await openClient(ctx, args);\n\n if (subcommand === 'disconnect') {\n return disconnect(ctx, args, client, env.host, source, product);\n }\n\n const shown = await client.connection((token) =>\n showConnection(env.host, token, source, product),\n );\n if (shown.status === 'unsupported') {\n throw invalidStateError(\n shown.message,\n `Each team connects ${product} itself: \"ekanos teams connect <team> ${product}\".`,\n );\n }\n if (shown.status !== 'ok') {\n throw invalidStateError(\n 'The host could not read the connection.',\n 'Retry shortly.',\n );\n }\n const current = shown.data.connection;\n\n if (current.app === 'fields') {\n ctx.log(\n [\n `${current.name} app for ${shown.data.source.slug} (one for the whole Source)`,\n ` Register this redirect URL in the app: ${shown.data.callbackUrls.join(', ')}`,\n ].join('\\n'),\n );\n }\n\n const fields = await askFields(ctx, args, current, product);\n\n const started = await client.connection((token) =>\n startConnection(env.host, token, {\n source,\n product,\n ...(Object.keys(fields).length > 0 ? { fields } : {}),\n }),\n );\n if (started.status === 'not-configured') {\n throw validationError(\n `${current.name} is not set up for the Source yet — missing: ${started.missing.join(', ')}.`,\n current.app === 'source-app'\n ? `Run \"ekanos apps set ${product}\" to enter the Source's app first.`\n : `Run \"ekanos apps connect ${product}\" again and fill every field.`,\n );\n }\n if (started.status !== 'ok') {\n throw invalidStateError(\n 'The host could not start the connection.',\n 'Retry shortly.',\n );\n }\n\n ctx.log(\n [\n `Open this link and approve ${current.name} as the account the Source's agents should act as:`,\n ` ${started.data.authorizeUrl}`,\n ].join('\\n'),\n );\n\n if (args.noWait || ctx.jsonMode) {\n return ctx.succeed(\n {\n host: env.host,\n product,\n authorizeUrl: started.data.authorizeUrl,\n callbackUrl: started.data.callbackUrl,\n connected: false,\n },\n ctx.ui.hint(`Then check with \"ekanos apps show ${product}\".`),\n );\n }\n\n const deadline = Date.now() + 10 * 60 * 1000;\n const before = current.connectedAt;\n while (Date.now() < deadline) {\n await new Promise((resolve) =>\n setTimeout(resolve, args.pollDelayMs ?? 3000),\n );\n const polled = await client.connection((token) =>\n showConnection(env.host, token, source, product),\n );\n if (\n polled.status === 'ok' &&\n polled.data.connection.connected &&\n polled.data.connection.connectedAt !== before\n ) {\n return ctx.succeed(\n { host: env.host, product, connection: polled.data.connection },\n connectionSummary(ctx, polled.data.connection, {\n sourceSlug: polled.data.source.slug,\n callbackUrls: polled.data.callbackUrls,\n }),\n );\n }\n }\n throw validationError(\n 'The connection did not finish within ten minutes.',\n `Run \"ekanos apps connect ${product}\" again for a fresh link.`,\n );\n}\n\nasync function askFields(\n ctx: CliContext,\n args: AppsArgs,\n current: SourceConnection,\n product: string,\n): Promise<Record<string, string>> {\n const toAsk = current.fields.filter(\n (field) => !field.set || current.missing.includes(field.name),\n );\n if (toAsk.length === 0) return {};\n if (!canPrompt(ctx, args)) {\n throw usageError(\n `${current.name} needs its app fields entered for the Source: ${toAsk.map((field) => field.label).join(', ')}.`,\n `Run it yourself in your terminal: npx @ekanos/cli apps connect ${product}${args.source ? ` --source ${args.source}` : ''}`,\n );\n }\n const fields: Record<string, string> = {};\n for (const field of toAsk) {\n const question = field.sensitive\n ? `${field.label} (hidden): `\n : `${field.label}: `;\n const value = (\n await (\n field.sensitive\n ? (args.askSecret ?? promptHidden)\n : (args.ask ?? promptLine)\n )(question)\n ).trim();\n if (value) fields[field.name] = value;\n }\n return fields;\n}\n\nasync function disconnect(\n ctx: CliContext,\n args: AppsArgs,\n client: AppsClient,\n host: string,\n source: string,\n product: string,\n): Promise<ExitCode> {\n if (!args.yes && !canPrompt(ctx, args)) {\n throw invalidStateError(\n `Disconnecting ${product} on ${source} stops it for every team's provided agents that use the Source connection, until someone connects it again.`,\n `Re-run with --yes: ekanos apps disconnect ${product} --source ${source} --yes`,\n );\n }\n if (!args.yes) {\n const sure = await (args.confirm ?? promptYesNo)(\n `Disconnect ${product} for every team's provided agents on ${source}? [y/N]`,\n );\n if (!sure) {\n throw validationError(\n 'Nothing was changed.',\n `Run \"ekanos apps show ${product}\" to see the current state.`,\n );\n }\n }\n const result = await client.connection((token) =>\n deleteConnection(host, token, source, product),\n );\n if (result.status === 'unsupported') {\n throw invalidStateError(\n result.message,\n `Each team connects ${product} itself: \"ekanos teams connect <team> ${product}\".`,\n );\n }\n if (result.status !== 'ok') {\n throw invalidStateError('The host could not disconnect.', 'Retry shortly.');\n }\n return ctx.succeed(\n { host, product, ...result.data },\n ctx.ui.result({\n title: result.data.removed\n ? `Disconnected the ${product} Source connection on ${source}`\n : `${product} had no Source connection on ${source}`,\n rows: [\n [\n 'Provided agents',\n 'their tools for this product stop until you connect again',\n ],\n ],\n }),\n );\n}\n\nfunction connectionSummary(\n ctx: CliContext,\n connection: SourceConnection,\n meta: { sourceSlug: string; callbackUrls: string[] },\n): string {\n const rows: ResultRow[] = [\n ['Source', meta.sourceSlug],\n ['Connected', connectionState(connection)],\n ...(connection.scope ? ([['Scope', connection.scope]] as ResultRow[]) : []),\n ...(connection.fields.length > 0\n ? ([\n [\n 'App fields',\n connection.fields.map(\n (field) =>\n `${field.label}: ${field.set ? (field.value ?? 'set') : 'missing'}`,\n ),\n ],\n ] as ResultRow[])\n : []),\n ['Redirect URL', meta.callbackUrls],\n [\n 'Used by',\n `provided agents whose template says connections.${connection.slug}.owner: \"source\", in every team`,\n ],\n ];\n return [\n ctx.ui.result({\n title: `${connection.name} — Source connection (one for every team's provided agents)`,\n rows,\n }),\n ...(connection.connected\n ? []\n : [\n ctx.ui.hint(\n `Run \"ekanos apps connect ${connection.slug}\" in your terminal to connect it.`,\n ),\n ]),\n ].join('\\n');\n}\n\nasync function openClient(ctx: CliContext, args: AppsArgs) {\n const env = resolveAuthEnvironment(ctx, args.host, args.env, {\n projectDir: args.dir,\n });\n const resolved = await resolveSourceTarget(env, requireSession(env), args);\n return {\n env,\n client: new AppsClient(env, resolved.session),\n source: resolved.source,\n };\n}\n\nclass AppsClient {\n constructor(\n private readonly env: AuthEnvironment,\n private session: StoredSession,\n ) {}\n\n async call<T>(\n send: (accessToken: string) => Promise<AppsApiResult<T>>,\n ): Promise<T> {\n let result = await send(this.session.accessToken);\n if (result.status === 'unauthorized') {\n this.session = await refreshStoredSession(this.env, this.session);\n result = await send(this.session.accessToken);\n }\n if (result.status === 'ok') return result.data;\n throw authRequiredError(\n `The session for ${this.env.host} could not authorize the apps call.`,\n loginHint(this.env),\n );\n }\n\n /** As `call`, for the connections client, whose 409s are answers. */\n async connection<T>(\n send: (accessToken: string) => Promise<ConnectionsApiResult<T>>,\n ): Promise<Exclude<ConnectionsApiResult<T>, { status: 'unauthorized' }>> {\n let result = await send(this.session.accessToken);\n if (result.status === 'unauthorized') {\n this.session = await refreshStoredSession(this.env, this.session);\n result = await send(this.session.accessToken);\n }\n if (result.status !== 'unauthorized') return result;\n throw authRequiredError(\n `The session for ${this.env.host} could not authorize the connections call.`,\n loginHint(this.env),\n );\n }\n}\n\nfunction canPrompt(ctx: CliContext, args: AppsArgs): boolean {\n return !ctx.jsonMode && (args.stdinIsTTY ?? process.stdin.isTTY === true);\n}\n\nfunction parseSubcommand(value: string | undefined): AppsSubcommand {\n const match = APPS_SUBCOMMANDS.find((name) => name === value);\n if (match) return match;\n throw usageError(\n value ? `Unknown apps subcommand \"${value}\".` : 'apps needs a subcommand.',\n `Run one of: ${APPS_SUBCOMMANDS.map((name) => `ekanos apps ${name} <product>`).join(', ')}.`,\n );\n}\n\nfunction requireProduct(value: string | undefined, verb: string): string {\n const slug = value?.trim().toLowerCase();\n if (slug && /^[a-z0-9][a-z0-9-]*$/.test(slug)) return slug;\n throw usageError(\n value\n ? `\"${value}\" is not a product slug.`\n : `apps ${verb} needs a product.`,\n `Pass the product's slug, e.g. \"ekanos apps ${verb} linear\". \"ekanos catalog\" lists them.`,\n );\n}\n\nexport async function promptLine(question: string): Promise<string> {\n const readline = await import('node:readline/promises');\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n try {\n return await rl.question(question);\n } finally {\n rl.close();\n }\n}\n\n/**\n * Read a line without echoing it: the secret never appears on screen or in\n * scrollback. The question is always printed; only the typed characters are\n * hidden (each shows as `*`, so a paste visibly landed).\n *\n * Raw mode by hand rather than readline: a terminal readline redraws its\n * line on `question()` — cursor to column 0, clear to the end of the screen —\n * which erased the question written before it, so the terminal sat on an\n * empty line and a hidden field looked skipped.\n */\nexport async function promptHidden(question: string): Promise<string> {\n const stdin = process.stdin;\n const stderr = process.stderr;\n stderr.write(question);\n\n if (!stdin.isTTY) {\n // Piped stdin echoes nothing: read one line as is.\n const readline = await import('node:readline/promises');\n const rl = readline.createInterface({ input: stdin, terminal: false });\n try {\n return await rl.question('');\n } finally {\n rl.close();\n stderr.write('\\n');\n }\n }\n\n return new Promise<string>((resolve) => {\n let value = '';\n let inEscape = false;\n const wasRaw = stdin.isRaw;\n const finish = () => {\n stdin.off('data', onData);\n stdin.setRawMode(wasRaw);\n stdin.pause();\n stderr.write('\\n');\n };\n const onData = (chunk: Buffer | string) => {\n for (const char of typeof chunk === 'string'\n ? chunk\n : chunk.toString('utf8')) {\n if (inEscape) {\n // An escape sequence (an arrow key) ends at its final letter.\n if (/[A-Za-z~]/.test(char)) inEscape = false;\n continue;\n }\n if (char === '\\u001b') {\n inEscape = true;\n continue;\n }\n if (char === '\\r' || char === '\\n' || char === '\\u0004') {\n finish();\n resolve(value);\n return;\n }\n if (char === '\\u0003') {\n // Ctrl-C: raw mode swallowed the signal, so leave as SIGINT would.\n finish();\n process.exit(130);\n }\n if (char === '\\u007f' || char === '\\b') {\n if (value.length > 0) {\n value = value.slice(0, -1);\n stderr.write('\\b \\b');\n }\n continue;\n }\n if (char === '\\u0015') {\n // Ctrl-U: clear what was typed.\n stderr.write('\\b \\b'.repeat(value.length));\n value = '';\n continue;\n }\n if (char < ' ') continue;\n value += char;\n stderr.write('*');\n }\n };\n stdin.setRawMode(true);\n stdin.resume();\n stdin.on('data', onData);\n });\n}\n\n/** Each credential's state: the client id's value, the secret as saved or not. */\nfunction providerFieldRows(status: ProviderAppStatus): ResultRow[] {\n return (status.fields ?? []).map((field) => [\n field.label,\n !field.set\n ? 'not set'\n : field.sensitive\n ? 'saved'\n : (field.value ?? 'saved'),\n ]);\n}\n\n/** Every redirect URI to register; an older host sends only the one. */\nfunction callbackUrls(status: ProviderAppStatus): string[] {\n return status.callbackUrls?.length\n ? status.callbackUrls\n : [status.callbackUrl];\n}\n"]}
|
package/dist/commands/catalog.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { loginHint } from '../auth/host-trust.js';
|
|
1
2
|
import { refreshStoredSession, requireSession, resolveAuthEnvironment, } from '../auth/session.js';
|
|
2
3
|
import { fetchSourceCatalog, } from '../catalog-api.js';
|
|
3
4
|
import { authRequiredError } from '../errors.js';
|
|
@@ -18,7 +19,7 @@ export async function runCatalog(ctx, args) {
|
|
|
18
19
|
const env = resolveAuthEnvironment(ctx, args.host, args.env, {
|
|
19
20
|
projectDir: args.dir,
|
|
20
21
|
});
|
|
21
|
-
let session = requireSession(env
|
|
22
|
+
let session = requireSession(env);
|
|
22
23
|
const resolved = await resolveSourceTarget(env, session, args);
|
|
23
24
|
session = resolved.session;
|
|
24
25
|
const query = { source: resolved.source, product: args.product };
|
|
@@ -27,20 +28,20 @@ export async function runCatalog(ctx, args) {
|
|
|
27
28
|
session = await refreshStoredSession(env, session);
|
|
28
29
|
result = await fetchSourceCatalog(env.host, session.accessToken, query);
|
|
29
30
|
}
|
|
30
|
-
const catalog = requireCatalog(result, env
|
|
31
|
+
const catalog = requireCatalog(result, env);
|
|
31
32
|
return ctx.succeed(Object.assign({ host: env.host }, catalog), withDocsHint(ctx.ui, args.dir, args.product
|
|
32
33
|
? productDetail(ctx.ui, catalog.products[0])
|
|
33
34
|
: catalogSummary(ctx.ui, catalog)));
|
|
34
35
|
}
|
|
35
|
-
function requireCatalog(result,
|
|
36
|
+
function requireCatalog(result, env) {
|
|
36
37
|
if (result.status === 'ok')
|
|
37
38
|
return result.catalog;
|
|
38
|
-
throw authRequiredError(`The session for ${host} could not authorize the catalog read.`,
|
|
39
|
+
throw authRequiredError(`The session for ${env.host} could not authorize the catalog read.`, loginHint(env));
|
|
39
40
|
}
|
|
40
41
|
const AVAILABILITY_LABEL = {
|
|
41
42
|
enabled: 'Enabled on this Source',
|
|
42
|
-
'turned-off': '
|
|
43
|
-
available: '
|
|
43
|
+
'turned-off': 'Not enabled — granted, but switched off',
|
|
44
|
+
available: 'Not enabled — only a super-admin enables it',
|
|
44
45
|
};
|
|
45
46
|
function catalogSummary(ui, catalog) {
|
|
46
47
|
const blocks = ['enabled', 'turned-off', 'available']
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/commands/catalog.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CatalogProduct, SourceCatalog } from '@ekanos/integration-schema';\n\nimport {\n refreshStoredSession,\n requireSession,\n resolveAuthEnvironment,\n} from '../auth/session';\nimport {\n type FetchSourceCatalogResult,\n fetchSourceCatalog,\n} from '../catalog-api';\nimport type { CliContext } from '../context';\nimport { authRequiredError } from '../errors';\nimport type { ExitCode } from '../exit-codes';\nimport { resolveSourceTarget } from '../source-target';\nimport { type Ui, pluralize } from '../ui';\nimport { withDocsHint } from './agents-init';\n\nexport interface CatalogArgs {\n host?: string;\n source?: string;\n /** One product's detail, when given. */\n product?: string;\n dir: string;\n env: Record<string, string | undefined>;\n}\n\n/**\n * `catalog` — what the Source can already do (plan 239.0). Lists every\n * product the Source can use, with its tools, agent events and the steps\n * left to set it up; `ekanos catalog <product>` shows one in full.\n *\n * Read before building: an agent migration asks it first, so a capability\n * the Source already has is set up rather than rebuilt. Works outside a\n * project — the Source comes from `--source`, else `ekanos.json`, else the\n * caller's only seat.\n */\nexport async function runCatalog(\n ctx: CliContext,\n args: CatalogArgs,\n): Promise<ExitCode> {\n const env = resolveAuthEnvironment(ctx, args.host, args.env, {\n projectDir: args.dir,\n });\n let session = requireSession(env.store, env.host);\n\n const resolved = await resolveSourceTarget(env, session, args);\n session = resolved.session;\n\n const query = { source: resolved.source, product: args.product };\n let result = await fetchSourceCatalog(env.host, session.accessToken, query);\n if (result.status === 'unauthorized') {\n session = await refreshStoredSession(env, session);\n result = await fetchSourceCatalog(env.host, session.accessToken, query);\n }\n const catalog = requireCatalog(result, env.host);\n\n return ctx.succeed(\n { host: env.host, ...catalog },\n withDocsHint(\n ctx.ui,\n args.dir,\n args.product\n ? productDetail(ctx.ui, catalog.products[0]!)\n : catalogSummary(ctx.ui, catalog),\n ),\n );\n}\n\nfunction requireCatalog(\n result: FetchSourceCatalogResult,\n host: string,\n): SourceCatalog {\n if (result.status === 'ok') return result.catalog;\n throw authRequiredError(\n `The session for ${host} could not authorize the catalog read.`,\n `Run \"ekanos login --host ${host}\" and retry.`,\n );\n}\n\nconst AVAILABILITY_LABEL = {\n enabled: 'Enabled on this Source',\n 'turned-off': 'Granted but switched off',\n available: 'Available — ask Ekanos to enable',\n} as const;\n\nfunction catalogSummary(ui: Ui, catalog: SourceCatalog): string {\n const blocks = (['enabled', 'turned-off', 'available'] as const)\n .map((availability) => {\n const products = catalog.products.filter(\n (product) => product.availability === availability,\n );\n if (products.length === 0) return null;\n return ui.result({\n title: `${AVAILABILITY_LABEL[availability]} (${products.length})`,\n tone: availability === 'enabled' ? 'ok' : 'warn',\n rows: products.map((product): [string, string] => [\n product.slug,\n [product.name, describeShape(product), openSteps(product)]\n .filter(Boolean)\n .join(' · '),\n ]),\n });\n })\n .filter((block): block is string => block !== null);\n\n return [\n ...blocks,\n ui.hint(\n `${pluralize(catalog.products.length, 'product')} on ${catalog.source.slug}. ` +\n `\"ekanos catalog <product>\" shows tools, agent events and setup steps.`,\n ),\n ].join('\\n\\n');\n}\n\nfunction productDetail(ui: Ui, product: CatalogProduct): string {\n const rows: [string, string | string[]][] = [\n ['What', product.summary ?? '—'],\n [\n 'Kind',\n product.kind === 'experience' ? 'Ekanos Experience' : 'Integration',\n ],\n ['Status', AVAILABILITY_LABEL[product.availability]],\n ];\n if (product.connectedTeams !== null) {\n rows.push(['Teams connected', String(product.connectedTeams)]);\n }\n if (product.tools.length > 0) {\n rows.push([\n 'Tools',\n product.tools.map(\n (tool) =>\n `${tool.name} (${tool.effect}${tool.sensitivity === 'undeclared' ? '' : `, ${tool.sensitivity}`})`,\n ),\n ]);\n }\n if (product.agentEvents.length > 0) {\n rows.push([\n 'Agent triggers',\n product.agentEvents.map((event) => `${event.id} — ${event.label}`),\n ]);\n }\n if (product.agentReplyTool) {\n rows.push(['Replies with', product.agentReplyTool]);\n }\n rows.push([\n 'Setup',\n product.setupSteps.flatMap((step, index) => [\n `${index + 1}. [${step.state}] ${step.title} (${step.actor}) — ${step.detail}` +\n (step.guideUrl ? ` ${step.guideUrl}` : ''),\n ...(step.consoleUrl ? [` Open ${step.consoleUrl}`] : []),\n ...(step.instructions ?? []).map(\n (line, lineIndex) =>\n ` ${String.fromCharCode(97 + lineIndex)}. ${line}`,\n ),\n ]),\n ]);\n\n return ui.result({ title: `${product.name} (${product.slug})`, rows });\n}\n\nfunction describeShape(product: CatalogProduct): string {\n const parts = [\n product.tools.length > 0 ? pluralize(product.tools.length, 'tool') : null,\n product.agentEvents.length > 0\n ? pluralize(product.agentEvents.length, 'agent trigger')\n : null,\n ].filter(Boolean);\n return parts.join(', ');\n}\n\nfunction openSteps(product: CatalogProduct): string {\n const open = product.setupSteps.filter((step) => step.state === 'todo');\n return open.length === 0 ? '' : `${pluralize(open.length, 'step')} left`;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/commands/catalog.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CatalogProduct, SourceCatalog } from '@ekanos/integration-schema';\n\nimport { loginHint } from '../auth/host-trust';\nimport {\n type AuthEnvironment,\n refreshStoredSession,\n requireSession,\n resolveAuthEnvironment,\n} from '../auth/session';\nimport {\n type FetchSourceCatalogResult,\n fetchSourceCatalog,\n} from '../catalog-api';\nimport type { CliContext } from '../context';\nimport { authRequiredError } from '../errors';\nimport type { ExitCode } from '../exit-codes';\nimport { resolveSourceTarget } from '../source-target';\nimport { type Ui, pluralize } from '../ui';\nimport { withDocsHint } from './agents-init';\n\nexport interface CatalogArgs {\n host?: string;\n source?: string;\n /** One product's detail, when given. */\n product?: string;\n dir: string;\n env: Record<string, string | undefined>;\n}\n\n/**\n * `catalog` — what the Source can already do (plan 239.0). Lists every\n * product the Source can use, with its tools, agent events and the steps\n * left to set it up; `ekanos catalog <product>` shows one in full.\n *\n * Read before building: an agent migration asks it first, so a capability\n * the Source already has is set up rather than rebuilt. Works outside a\n * project — the Source comes from `--source`, else `ekanos.json`, else the\n * caller's only seat.\n */\nexport async function runCatalog(\n ctx: CliContext,\n args: CatalogArgs,\n): Promise<ExitCode> {\n const env = resolveAuthEnvironment(ctx, args.host, args.env, {\n projectDir: args.dir,\n });\n let session = requireSession(env);\n\n const resolved = await resolveSourceTarget(env, session, args);\n session = resolved.session;\n\n const query = { source: resolved.source, product: args.product };\n let result = await fetchSourceCatalog(env.host, session.accessToken, query);\n if (result.status === 'unauthorized') {\n session = await refreshStoredSession(env, session);\n result = await fetchSourceCatalog(env.host, session.accessToken, query);\n }\n const catalog = requireCatalog(result, env);\n\n return ctx.succeed(\n { host: env.host, ...catalog },\n withDocsHint(\n ctx.ui,\n args.dir,\n args.product\n ? productDetail(ctx.ui, catalog.products[0]!)\n : catalogSummary(ctx.ui, catalog),\n ),\n );\n}\n\nfunction requireCatalog(\n result: FetchSourceCatalogResult,\n env: AuthEnvironment,\n): SourceCatalog {\n if (result.status === 'ok') return result.catalog;\n throw authRequiredError(\n `The session for ${env.host} could not authorize the catalog read.`,\n loginHint(env),\n );\n}\n\nconst AVAILABILITY_LABEL = {\n enabled: 'Enabled on this Source',\n 'turned-off': 'Not enabled — granted, but switched off',\n available: 'Not enabled — only a super-admin enables it',\n} as const;\n\nfunction catalogSummary(ui: Ui, catalog: SourceCatalog): string {\n const blocks = (['enabled', 'turned-off', 'available'] as const)\n .map((availability) => {\n const products = catalog.products.filter(\n (product) => product.availability === availability,\n );\n if (products.length === 0) return null;\n return ui.result({\n title: `${AVAILABILITY_LABEL[availability]} (${products.length})`,\n tone: availability === 'enabled' ? 'ok' : 'warn',\n rows: products.map((product): [string, string] => [\n product.slug,\n [product.name, describeShape(product), openSteps(product)]\n .filter(Boolean)\n .join(' · '),\n ]),\n });\n })\n .filter((block): block is string => block !== null);\n\n return [\n ...blocks,\n ui.hint(\n `${pluralize(catalog.products.length, 'product')} on ${catalog.source.slug}. ` +\n `\"ekanos catalog <product>\" shows tools, agent events and setup steps.`,\n ),\n ].join('\\n\\n');\n}\n\nfunction productDetail(ui: Ui, product: CatalogProduct): string {\n const rows: [string, string | string[]][] = [\n ['What', product.summary ?? '—'],\n [\n 'Kind',\n product.kind === 'experience' ? 'Ekanos Experience' : 'Integration',\n ],\n ['Status', AVAILABILITY_LABEL[product.availability]],\n ];\n if (product.connectedTeams !== null) {\n rows.push(['Teams connected', String(product.connectedTeams)]);\n }\n if (product.tools.length > 0) {\n rows.push([\n 'Tools',\n product.tools.map(\n (tool) =>\n `${tool.name} (${tool.effect}${tool.sensitivity === 'undeclared' ? '' : `, ${tool.sensitivity}`})`,\n ),\n ]);\n }\n if (product.agentEvents.length > 0) {\n rows.push([\n 'Agent triggers',\n product.agentEvents.map((event) => `${event.id} — ${event.label}`),\n ]);\n }\n if (product.agentReplyTool) {\n rows.push(['Replies with', product.agentReplyTool]);\n }\n rows.push([\n 'Setup',\n product.setupSteps.flatMap((step, index) => [\n `${index + 1}. [${step.state}] ${step.title} (${step.actor}) — ${step.detail}` +\n (step.guideUrl ? ` ${step.guideUrl}` : ''),\n ...(step.consoleUrl ? [` Open ${step.consoleUrl}`] : []),\n ...(step.instructions ?? []).map(\n (line, lineIndex) =>\n ` ${String.fromCharCode(97 + lineIndex)}. ${line}`,\n ),\n ]),\n ]);\n\n return ui.result({ title: `${product.name} (${product.slug})`, rows });\n}\n\nfunction describeShape(product: CatalogProduct): string {\n const parts = [\n product.tools.length > 0 ? pluralize(product.tools.length, 'tool') : null,\n product.agentEvents.length > 0\n ? pluralize(product.agentEvents.length, 'agent trigger')\n : null,\n ].filter(Boolean);\n return parts.join(', ');\n}\n\nfunction openSteps(product: CatalogProduct): string {\n const open = product.setupSteps.filter((step) => step.state === 'todo');\n return open.length === 0 ? '' : `${pluralize(open.length, 'step')} left`;\n}\n"]}
|