@meistrari/tela-cli 0.7.58 → 1.0.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 +24 -3
- package/dist/commands/auth.js +131 -0
- package/dist/commands/context.js +118 -0
- package/dist/commands/doctor-auth.js +41 -0
- package/dist/commands/env.js +40 -0
- package/dist/commands/ingredients.js +824 -0
- package/dist/credentials.js +7 -0
- package/dist/docs/workflow-code/api-reference.md +604 -0
- package/dist/docs/workflow-code/cli.md +210 -0
- package/dist/docs/workflow-code/config.md +69 -0
- package/dist/docs/workflow-code/guides.md +56 -0
- package/dist/docs/workflow-code/installation.md +33 -0
- package/dist/docs/workflow-code/manifest.json +50 -0
- package/dist/docs/workflow-code/overview.md +14 -0
- package/dist/docs/workflow-code/quick-start.md +124 -0
- package/dist/index.js +63720 -26470
- package/dist/output.js +18 -0
- package/dist/program.js +96 -0
- package/package.json +5 -2
- package/scripts/install-skills.cjs +120 -111
package/README.md
CHANGED
|
@@ -73,7 +73,12 @@ TELA_HOME=/tmp/tela-home node apps/tela-cli/dist/index.js env list --json
|
|
|
73
73
|
The CLI uses the credential adapter contract from `local-config`.
|
|
74
74
|
|
|
75
75
|
- `env` credentials read `TELA_ACCESS_TOKEN`, `TELA_REFRESH_TOKEN`, or `TELA_DATA_TOKEN`.
|
|
76
|
-
-
|
|
76
|
+
- `keychain` credentials use the OS keychain: the system `security` command on
|
|
77
|
+
macOS, or the freedesktop Secret Service via `secret-tool` (libsecret) on
|
|
78
|
+
Linux. Linux needs `secret-tool` on `PATH` (Arch: `sudo pacman -S libsecret`,
|
|
79
|
+
Debian/Ubuntu: `sudo apt install libsecret-tools`) and a running Secret
|
|
80
|
+
Service such as gnome-keyring or kwallet; otherwise the adapter reports a
|
|
81
|
+
clear diagnostic instead of a token.
|
|
77
82
|
- expired user-session access tokens with a refresh token are reported as
|
|
78
83
|
`refreshable`, not as a hard auth failure.
|
|
79
84
|
- `auth token` refreshes expired user-session access tokens when a refresh token
|
|
@@ -85,9 +90,25 @@ Default and `--json` output stay redacted.
|
|
|
85
90
|
|
|
86
91
|
## Tests
|
|
87
92
|
|
|
88
|
-
Tests are black-box `node --test` cases that execute the
|
|
89
|
-
isolated `TELA_HOME`.
|
|
93
|
+
Tests are strict TypeScript black-box `node --test` cases that execute the
|
|
94
|
+
compiled CLI with an isolated `TELA_HOME`. Node strips the test-only types at
|
|
95
|
+
runtime; consumers do not need a TypeScript runtime.
|
|
90
96
|
|
|
91
97
|
```bash
|
|
92
98
|
pnpm --filter @meistrari/tela-cli run test
|
|
93
99
|
```
|
|
100
|
+
|
|
101
|
+
## Published skill installer
|
|
102
|
+
|
|
103
|
+
[`scripts/install-skills.ts`](scripts/install-skills.ts) is the source for the
|
|
104
|
+
postinstall skill sync. `release:prepare` bundles it deterministically with
|
|
105
|
+
esbuild into `scripts/install-skills.cjs`, then copies that CJS artifact into
|
|
106
|
+
the publish directory. The generated artifact is kept in the workspace so a
|
|
107
|
+
fresh workspace install and an npm consumer both run plain Node through:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
node scripts/install-skills.cjs --quiet
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The published package does not require `tsx`, TypeScript, or esbuild at
|
|
114
|
+
postinstall time.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runAuthCommand = runAuthCommand;
|
|
4
|
+
const tela_local_config_1 = require("@meistrari/tela-local-config");
|
|
5
|
+
const credentials_1 = require("../credentials");
|
|
6
|
+
const output_1 = require("../output");
|
|
7
|
+
async function runAuthCommand(args, options, io) {
|
|
8
|
+
const [action, ...rest] = args;
|
|
9
|
+
if (!action || action === 'help' || action === '--help' || action === '-h') {
|
|
10
|
+
writeAuthHelp(io);
|
|
11
|
+
return 0;
|
|
12
|
+
}
|
|
13
|
+
if (action === 'token')
|
|
14
|
+
return await authToken(rest, options, io);
|
|
15
|
+
(0, output_1.writeError)(io, `Unknown auth command: ${action}`);
|
|
16
|
+
return 1;
|
|
17
|
+
}
|
|
18
|
+
async function authToken(args, options, io) {
|
|
19
|
+
const parsed = parseTokenOptions(args);
|
|
20
|
+
if ('error' in parsed) {
|
|
21
|
+
(0, output_1.writeError)(io, parsed.error);
|
|
22
|
+
return 1;
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const result = await resolveToken(parsed);
|
|
26
|
+
if (parsed.raw) {
|
|
27
|
+
(0, output_1.writeLine)(io, result.value);
|
|
28
|
+
return 0;
|
|
29
|
+
}
|
|
30
|
+
const payload = {
|
|
31
|
+
token: {
|
|
32
|
+
kind: parsed.kind,
|
|
33
|
+
contextId: result.resolved.id,
|
|
34
|
+
environmentId: result.resolved.context.environmentId,
|
|
35
|
+
workspaceId: result.resolved.context.workspaceId,
|
|
36
|
+
credentialProvider: result.credentialRef.provider,
|
|
37
|
+
credentialKind: result.credential.kind,
|
|
38
|
+
refreshed: result.refreshed,
|
|
39
|
+
expiresAt: result.credential.expiresAt,
|
|
40
|
+
issuedAt: result.credential.issuedAt,
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
if (options.json) {
|
|
44
|
+
(0, output_1.writeJson)(io, payload);
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
47
|
+
(0, output_1.writeLine)(io, `${payload.token.kind} for ${payload.token.contextId}`);
|
|
48
|
+
(0, output_1.writeLine)(io, `Provider: ${payload.token.credentialProvider}`);
|
|
49
|
+
(0, output_1.writeLine)(io, `Credential: ${payload.token.credentialKind}`);
|
|
50
|
+
(0, output_1.writeLine)(io, `Refreshed: ${payload.token.refreshed ? 'yes' : 'no'}`);
|
|
51
|
+
if (payload.token.expiresAt)
|
|
52
|
+
(0, output_1.writeLine)(io, `Expires: ${payload.token.expiresAt}`);
|
|
53
|
+
return 0;
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
57
|
+
(0, output_1.writeError)(io, message);
|
|
58
|
+
return 1;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async function resolveToken(options) {
|
|
62
|
+
const config = await (0, tela_local_config_1.loadConfig)();
|
|
63
|
+
const resolved = (0, tela_local_config_1.resolveContext)(config, { contextId: options.contextId });
|
|
64
|
+
const credentials = (0, credentials_1.createCliCredentialAdapter)();
|
|
65
|
+
const credentialRef = resolved.context.credentialRef;
|
|
66
|
+
const originalCredential = await credentials.get(credentialRef);
|
|
67
|
+
if (!originalCredential) {
|
|
68
|
+
throw new Error(`Missing credential for Tela context ${resolved.id}`);
|
|
69
|
+
}
|
|
70
|
+
const credential = originalCredential.kind === 'user-session'
|
|
71
|
+
? await (0, tela_local_config_1.refreshUserSessionCredential)(resolved.environment, credentialRef, originalCredential, credentials)
|
|
72
|
+
: originalCredential;
|
|
73
|
+
const refreshed = credential !== originalCredential;
|
|
74
|
+
if (options.kind === 'access-token') {
|
|
75
|
+
if (credential.kind !== 'user-session' || !credential.accessToken) {
|
|
76
|
+
throw new Error(`Context ${resolved.id} does not have an access token credential.`);
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
resolved,
|
|
80
|
+
credentialRef,
|
|
81
|
+
credential,
|
|
82
|
+
refreshed,
|
|
83
|
+
value: credential.accessToken,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
if (credential.kind !== 'data-token' || !credential.dataToken) {
|
|
87
|
+
throw new Error(`Context ${resolved.id} does not have a data token credential.`);
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
resolved,
|
|
91
|
+
credentialRef,
|
|
92
|
+
credential,
|
|
93
|
+
refreshed,
|
|
94
|
+
value: credential.dataToken,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function parseTokenOptions(args) {
|
|
98
|
+
const options = {
|
|
99
|
+
kind: 'access-token',
|
|
100
|
+
raw: false,
|
|
101
|
+
};
|
|
102
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
103
|
+
const arg = args[index];
|
|
104
|
+
if (arg === '--context') {
|
|
105
|
+
const value = args[index + 1];
|
|
106
|
+
if (!value)
|
|
107
|
+
return { error: 'Usage: tela auth token --context <context-id>' };
|
|
108
|
+
options.contextId = value;
|
|
109
|
+
index += 1;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (arg === '--kind') {
|
|
113
|
+
const value = args[index + 1];
|
|
114
|
+
if (value !== 'access-token' && value !== 'data-token') {
|
|
115
|
+
return { error: 'Usage: tela auth token --kind <access-token|data-token>' };
|
|
116
|
+
}
|
|
117
|
+
options.kind = value;
|
|
118
|
+
index += 1;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (arg === '--raw') {
|
|
122
|
+
options.raw = true;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
return { error: `Unknown auth token option: ${arg}` };
|
|
126
|
+
}
|
|
127
|
+
return options;
|
|
128
|
+
}
|
|
129
|
+
function writeAuthHelp(io) {
|
|
130
|
+
(0, output_1.writeLine)(io, 'Usage: tela auth token [--context <context-id>] [--kind access-token|data-token] [--raw] [--json]');
|
|
131
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runContextCommand = runContextCommand;
|
|
4
|
+
const tela_local_config_1 = require("@meistrari/tela-local-config");
|
|
5
|
+
const output_1 = require("../output");
|
|
6
|
+
const credentials_1 = require("../credentials");
|
|
7
|
+
async function runContextCommand(args, options, io) {
|
|
8
|
+
const [action, ...rest] = args;
|
|
9
|
+
if (!action || action === 'help' || action === '--help' || action === '-h') {
|
|
10
|
+
writeContextHelp(io);
|
|
11
|
+
return 0;
|
|
12
|
+
}
|
|
13
|
+
if (action === 'current')
|
|
14
|
+
return await currentContext(options, io);
|
|
15
|
+
if (action === 'list')
|
|
16
|
+
return await listContexts(options, io);
|
|
17
|
+
if (action === 'show')
|
|
18
|
+
return await showContext(rest[0], options, io);
|
|
19
|
+
if (action === 'use')
|
|
20
|
+
return await useContext(rest[0], options, io);
|
|
21
|
+
(0, output_1.writeError)(io, `Unknown context command: ${action}`);
|
|
22
|
+
return 1;
|
|
23
|
+
}
|
|
24
|
+
async function currentContext(options, io) {
|
|
25
|
+
const config = await (0, tela_local_config_1.loadConfig)();
|
|
26
|
+
const credentials = (0, credentials_1.createCliCredentialAdapter)();
|
|
27
|
+
const activeContextId = config.activeContextId;
|
|
28
|
+
const activeContext = activeContextId ? config.contexts[activeContextId] : undefined;
|
|
29
|
+
if (!activeContextId || !activeContext) {
|
|
30
|
+
if (options.json)
|
|
31
|
+
(0, output_1.writeJson)(io, { activeContext: null });
|
|
32
|
+
else
|
|
33
|
+
(0, output_1.writeLine)(io, 'No active Tela context.');
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
const summary = await (0, tela_local_config_1.toContextSummary)(activeContextId, activeContext, config, credentials);
|
|
37
|
+
if (options.json) {
|
|
38
|
+
(0, output_1.writeJson)(io, { activeContext: summary });
|
|
39
|
+
return 0;
|
|
40
|
+
}
|
|
41
|
+
writeContextSummary(io, summary);
|
|
42
|
+
return 0;
|
|
43
|
+
}
|
|
44
|
+
async function listContexts(options, io) {
|
|
45
|
+
const config = await (0, tela_local_config_1.loadConfig)();
|
|
46
|
+
const credentials = (0, credentials_1.createCliCredentialAdapter)();
|
|
47
|
+
const publicConfig = await (0, tela_local_config_1.toPublicConfig)(config, credentials);
|
|
48
|
+
const contexts = Object.values(publicConfig.contexts);
|
|
49
|
+
if (options.json) {
|
|
50
|
+
(0, output_1.writeJson)(io, { contexts });
|
|
51
|
+
return 0;
|
|
52
|
+
}
|
|
53
|
+
if (contexts.length === 0) {
|
|
54
|
+
(0, output_1.writeLine)(io, 'No Tela contexts configured.');
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
for (const context of contexts) {
|
|
58
|
+
const marker = context.isActive ? '*' : ' ';
|
|
59
|
+
const workspace = context.workspaceName ?? context.workspaceSlug ?? context.workspaceId;
|
|
60
|
+
const credential = credentialStatus(context.credential);
|
|
61
|
+
(0, output_1.writeLine)(io, `${marker} ${context.id} ${workspace} ${context.accountEmail ?? '-'} credential=${credential}`);
|
|
62
|
+
}
|
|
63
|
+
return 0;
|
|
64
|
+
}
|
|
65
|
+
async function showContext(contextId, options, io) {
|
|
66
|
+
if (!contextId) {
|
|
67
|
+
(0, output_1.writeError)(io, 'Usage: tela context show <context-id>');
|
|
68
|
+
return 1;
|
|
69
|
+
}
|
|
70
|
+
const config = await (0, tela_local_config_1.loadConfig)();
|
|
71
|
+
const context = config.contexts[contextId];
|
|
72
|
+
if (!context) {
|
|
73
|
+
(0, output_1.writeError)(io, `Unknown Tela context: ${contextId}`);
|
|
74
|
+
return 1;
|
|
75
|
+
}
|
|
76
|
+
const summary = await (0, tela_local_config_1.toContextSummary)(contextId, context, config, (0, credentials_1.createCliCredentialAdapter)());
|
|
77
|
+
if (options.json) {
|
|
78
|
+
(0, output_1.writeJson)(io, { context: summary });
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
|
81
|
+
writeContextSummary(io, summary);
|
|
82
|
+
return 0;
|
|
83
|
+
}
|
|
84
|
+
async function useContext(contextId, options, io) {
|
|
85
|
+
if (!contextId) {
|
|
86
|
+
(0, output_1.writeError)(io, 'Usage: tela context use <context-id>');
|
|
87
|
+
return 1;
|
|
88
|
+
}
|
|
89
|
+
const config = await (0, tela_local_config_1.updateConfig)(current => (0, tela_local_config_1.setActiveContext)(current, contextId));
|
|
90
|
+
const context = config.contexts[contextId];
|
|
91
|
+
if (!context)
|
|
92
|
+
throw new Error(`Unknown context: ${contextId}`);
|
|
93
|
+
const summary = await (0, tela_local_config_1.toContextSummary)(contextId, context, config, (0, credentials_1.createCliCredentialAdapter)());
|
|
94
|
+
if (options.json) {
|
|
95
|
+
(0, output_1.writeJson)(io, { activeContext: summary });
|
|
96
|
+
return 0;
|
|
97
|
+
}
|
|
98
|
+
(0, output_1.writeLine)(io, `Active Tela context set to ${contextId}.`);
|
|
99
|
+
return 0;
|
|
100
|
+
}
|
|
101
|
+
function writeContextSummary(io, context) {
|
|
102
|
+
const workspace = context.workspaceName ?? context.workspaceSlug ?? context.workspaceId;
|
|
103
|
+
const credential = credentialStatus(context.credential);
|
|
104
|
+
(0, output_1.writeLine)(io, `${context.id}`);
|
|
105
|
+
(0, output_1.writeLine)(io, `Environment: ${context.environmentLabel} (${context.environmentId})`);
|
|
106
|
+
(0, output_1.writeLine)(io, `Workspace: ${workspace} (${context.workspaceId})`);
|
|
107
|
+
(0, output_1.writeLine)(io, `Account: ${context.accountEmail ?? '-'}`);
|
|
108
|
+
(0, output_1.writeLine)(io, `Active: ${context.isActive ? 'yes' : 'no'}`);
|
|
109
|
+
(0, output_1.writeLine)(io, `Credential: ${credential}`);
|
|
110
|
+
}
|
|
111
|
+
function credentialStatus(context) {
|
|
112
|
+
if (context.refreshable && context.problem === 'expired')
|
|
113
|
+
return 'refreshable';
|
|
114
|
+
return context.ok ? 'valid' : context.problem ?? 'unknown';
|
|
115
|
+
}
|
|
116
|
+
function writeContextHelp(io) {
|
|
117
|
+
(0, output_1.writeLine)(io, 'Usage: tela context <current|list|show|use> [args] [--json]');
|
|
118
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runDoctorCommand = runDoctorCommand;
|
|
4
|
+
const tela_local_config_1 = require("@meistrari/tela-local-config");
|
|
5
|
+
const credentials_1 = require("../credentials");
|
|
6
|
+
const output_1 = require("../output");
|
|
7
|
+
async function runDoctorCommand(args, options, io) {
|
|
8
|
+
const [action] = args;
|
|
9
|
+
if (!action || action === 'help' || action === '--help' || action === '-h') {
|
|
10
|
+
writeDoctorHelp(io);
|
|
11
|
+
return 0;
|
|
12
|
+
}
|
|
13
|
+
if (action === 'auth')
|
|
14
|
+
return await doctorAuth(options, io);
|
|
15
|
+
(0, output_1.writeError)(io, `Unknown doctor command: ${action}`);
|
|
16
|
+
return 1;
|
|
17
|
+
}
|
|
18
|
+
async function doctorAuth(options, io) {
|
|
19
|
+
const config = await (0, tela_local_config_1.loadConfig)();
|
|
20
|
+
const publicConfig = await (0, tela_local_config_1.toPublicConfig)(config, (0, credentials_1.createCliCredentialAdapter)());
|
|
21
|
+
const contexts = Object.values(publicConfig.contexts);
|
|
22
|
+
const ok = contexts.every(context => context.credential.ok);
|
|
23
|
+
if (options.json) {
|
|
24
|
+
(0, output_1.writeJson)(io, { ok, contexts });
|
|
25
|
+
return ok ? 0 : 2;
|
|
26
|
+
}
|
|
27
|
+
if (contexts.length === 0) {
|
|
28
|
+
(0, output_1.writeLine)(io, 'No Tela contexts configured.');
|
|
29
|
+
return 0;
|
|
30
|
+
}
|
|
31
|
+
for (const context of contexts) {
|
|
32
|
+
const status = context.credential.refreshable && context.credential.problem === 'expired'
|
|
33
|
+
? 'refreshable'
|
|
34
|
+
: context.credential.ok ? 'ok' : context.credential.problem ?? 'failed';
|
|
35
|
+
(0, output_1.writeLine)(io, `${context.id} credential=${status}`);
|
|
36
|
+
}
|
|
37
|
+
return ok ? 0 : 2;
|
|
38
|
+
}
|
|
39
|
+
function writeDoctorHelp(io) {
|
|
40
|
+
(0, output_1.writeLine)(io, 'Usage: tela doctor auth [--json]');
|
|
41
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runEnvCommand = runEnvCommand;
|
|
4
|
+
const tela_local_config_1 = require("@meistrari/tela-local-config");
|
|
5
|
+
const credentials_1 = require("../credentials");
|
|
6
|
+
const ingredients_1 = require("./ingredients");
|
|
7
|
+
const output_1 = require("../output");
|
|
8
|
+
async function runEnvCommand(args, options, io) {
|
|
9
|
+
const [action] = args;
|
|
10
|
+
if (!action || action === 'help' || action === '--help' || action === '-h') {
|
|
11
|
+
writeEnvHelp(io);
|
|
12
|
+
return 0;
|
|
13
|
+
}
|
|
14
|
+
const ingredientResult = await (0, ingredients_1.runIngredientEnvCommand)(args, options, io);
|
|
15
|
+
if (ingredientResult !== null)
|
|
16
|
+
return ingredientResult;
|
|
17
|
+
if (action === 'list')
|
|
18
|
+
return await listEnvironments(options, io);
|
|
19
|
+
(0, output_1.writeError)(io, `Unknown env command: ${action}`);
|
|
20
|
+
return 1;
|
|
21
|
+
}
|
|
22
|
+
async function listEnvironments(options, io) {
|
|
23
|
+
const config = await (0, tela_local_config_1.loadConfig)();
|
|
24
|
+
const publicConfig = await (0, tela_local_config_1.toPublicConfig)(config, (0, credentials_1.createCliCredentialAdapter)());
|
|
25
|
+
const environments = Object.values(publicConfig.environments);
|
|
26
|
+
if (options.json) {
|
|
27
|
+
(0, output_1.writeJson)(io, { environments });
|
|
28
|
+
return 0;
|
|
29
|
+
}
|
|
30
|
+
for (const environment of environments) {
|
|
31
|
+
const serviceCount = Object.keys(environment.services).length;
|
|
32
|
+
(0, output_1.writeLine)(io, `${environment.id} ${environment.label} ${environment.kind} services=${serviceCount}`);
|
|
33
|
+
}
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
function writeEnvHelp(io) {
|
|
37
|
+
(0, output_1.writeLine)(io, 'Usage: tela env list [--json]');
|
|
38
|
+
(0, output_1.writeLine)(io, 'Usage: tela env list <ingredient-slug> [-p|--pretty|--json]');
|
|
39
|
+
(0, output_1.writeLine)(io, 'Usage: tela env set <ingredient-slug> <environment>');
|
|
40
|
+
}
|