@meistrari/tela-cli 1.10.1 → 1.12.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 +46 -5
- package/dist/commands/auth.js +4 -4
- package/dist/commands/skills.js +9 -3
- package/dist/index.js +493 -92
- package/package.json +1 -1
- package/skills/tela-cli/SKILL.md +42 -3
- package/skills/tela-cli/references/agent.md +40 -0
package/README.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# Tela CLI
|
|
2
2
|
|
|
3
3
|
`@meistrari/tela-cli` owns the local `tela` binary for scriptable access to
|
|
4
|
-
Tela Local state and agent
|
|
4
|
+
Tela Local state, Pantry services and skills, agent repositories, and Workflow
|
|
5
|
+
Code projects.
|
|
5
6
|
|
|
6
7
|
The CLI reads and writes the same `~/.tela/config.json` state as Tela Dock
|
|
7
8
|
through `@meistrari/tela-local-config`. It should not parse local config files
|
|
@@ -9,7 +10,10 @@ directly, and normal output must not print token material.
|
|
|
9
10
|
|
|
10
11
|
## Commands
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
Run `tela help`, `tela agent --help`, `tela skills --help`, or
|
|
14
|
+
`tela workflow --help` for the authoritative flag list.
|
|
15
|
+
|
|
16
|
+
Local state, auth, and Pantry services:
|
|
13
17
|
|
|
14
18
|
```bash
|
|
15
19
|
tela auth login --no-interactive
|
|
@@ -32,14 +36,51 @@ tela service docs guide <slug> [path]
|
|
|
32
36
|
tela service env list <slug> --pretty
|
|
33
37
|
tela service env use <slug> <environment>
|
|
34
38
|
tela doctor auth --json
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Managed Pantry skills:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
tela skills list --json
|
|
45
|
+
tela skills search <query> --json
|
|
46
|
+
tela skills files <slug> --json
|
|
47
|
+
tela skills cat <slug> [path]
|
|
48
|
+
tela skills install <slug...> --force --no-symlink --ignore-scripts --json
|
|
49
|
+
tela skills upgrade [slug...] --ignore-scripts --json
|
|
50
|
+
tela skills uninstall <slug...> --ignore-scripts --json
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Agent repository workflows:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
tela agent setup --list-options --context <context-id> --organization <id-or-name> --clone-root <path> --dry-run --json
|
|
35
57
|
tela agent sync [repo] --current --all --dry-run --json --verbose
|
|
36
|
-
tela agent run --input <name=path>... --plain --json --verbose
|
|
58
|
+
tela agent run --input <name=path>... --mode <one-shot|chat> --input-conflict <fail|overwrite|rename> --plain --json --verbose
|
|
37
59
|
tela agent push --message <text> --claude --manual --dry-run --json --verbose
|
|
38
|
-
tela agent
|
|
60
|
+
tela agent merge [branch] --base <branch> --strategy <squash|merge> --keep-branch --yes --dry-run --json --verbose
|
|
61
|
+
tela agent feedback --list --apply <all|select> --feedback-id <id>... --json --verbose
|
|
39
62
|
```
|
|
40
63
|
|
|
64
|
+
Workflow Code:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
tela workflow init --directory <path> --workflow <key>... --package-manager <bun|pnpm|npm|yarn> --yes --json
|
|
68
|
+
tela workflow create <target> --project <project-id> --json
|
|
69
|
+
tela workflow compile [target] --config <path> --env <path> --json
|
|
70
|
+
tela workflow sync [target] --yes --json
|
|
71
|
+
tela workflow publish [target] --environment <name> --create-environment-if-missing --yes --json
|
|
72
|
+
tela workflow watch [target] --json
|
|
73
|
+
tela workflow codegen --json
|
|
74
|
+
tela workflow docs [page]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`tela workflow` is routed into `@meistrari/workflow-code`; see
|
|
78
|
+
[`docs/workflow-code/`](../../docs/workflow-code/README.md) for its authoring
|
|
79
|
+
API, compiler, and state model. `tela workflow docs [page]` prints the
|
|
80
|
+
user-facing Workflow Code Page documentation bundled with the CLI.
|
|
81
|
+
|
|
41
82
|
`auth login` uses device flow and creates or updates a context backed by the
|
|
42
|
-
same
|
|
83
|
+
same OS keychain credential adapter as Dock. `auth token` may refresh that session
|
|
43
84
|
before returning metadata or printing a raw token. On macOS, renewing a Keychain
|
|
44
85
|
session is delegated to Tela Dock, so sandboxed agents only read the saved
|
|
45
86
|
credential. The CLI opens the installed Dock in the background if needed;
|
package/dist/commands/auth.js
CHANGED
|
@@ -48,10 +48,11 @@ async function authLogin(args, options, io) {
|
|
|
48
48
|
const environment = config.environments[environmentId];
|
|
49
49
|
if (!environment)
|
|
50
50
|
throw new Error(`Unknown Tela environment: ${environmentId}`);
|
|
51
|
+
// The CLI signs in to its own application; a configured
|
|
52
|
+
// targetApplicationId (older configs) is ignored.
|
|
51
53
|
const requesterApplicationId = environment.authApplication?.requesterApplicationId;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
throw new Error(`Environment '${environmentId}' does not define auth application IDs. Configure them before logging in.`);
|
|
54
|
+
if (!requesterApplicationId) {
|
|
55
|
+
throw new Error(`Environment '${environmentId}' does not define an auth application ID. Configure it before logging in.`);
|
|
55
56
|
}
|
|
56
57
|
// auth-cli is ESM-only with no `require` export condition, so this
|
|
57
58
|
// CJS bundle can only reach it through a dynamic import.
|
|
@@ -60,7 +61,6 @@ async function authLogin(args, options, io) {
|
|
|
60
61
|
const flowOptions = {
|
|
61
62
|
apiUrl: parsed.authUrl ?? environment.authApiUrl,
|
|
62
63
|
requesterApplicationId,
|
|
63
|
-
targetApplicationId,
|
|
64
64
|
storage,
|
|
65
65
|
};
|
|
66
66
|
const loginContext = {
|
package/dist/commands/skills.js
CHANGED
|
@@ -177,15 +177,21 @@ async function installSkills(args, options, io) {
|
|
|
177
177
|
ignoreScripts: flags.ignoreScripts,
|
|
178
178
|
...(flags.symlink ? {} : { targets: [] }),
|
|
179
179
|
});
|
|
180
|
+
// A failed install script rolls back only its own skill, so report the rest and still fail.
|
|
181
|
+
const installedSlugs = new Set(installed.map(entry => entry.slug));
|
|
182
|
+
const failed = flags.rest.filter(slug => !installedSlugs.has(slug));
|
|
180
183
|
if (options.json) {
|
|
181
|
-
(0, output_1.writeJson)(io, { installed });
|
|
182
|
-
return 0;
|
|
184
|
+
(0, output_1.writeJson)(io, failed.length > 0 ? { installed, failed } : { installed });
|
|
185
|
+
return failed.length > 0 ? 1 : 0;
|
|
183
186
|
}
|
|
184
187
|
for (const entry of installed)
|
|
185
188
|
(0, output_1.writeLine)(io, `Installed ${entry.slug}@${entry.sha.slice(0, 7)} to ${entry.dir}`);
|
|
186
|
-
return 0;
|
|
189
|
+
return failed.length > 0 ? 1 : 0;
|
|
187
190
|
}
|
|
188
191
|
function writeSkillManagerDiagnostic(io, diagnostic) {
|
|
192
|
+
// A failed uninstall script throws, and the command prints that error.
|
|
193
|
+
if (diagnostic.type === 'lifecycle-failed' && diagnostic.phase === 'uninstall')
|
|
194
|
+
return;
|
|
189
195
|
(0, output_1.writeError)(io, diagnostic.message);
|
|
190
196
|
}
|
|
191
197
|
async function upgradeSkills(args, options, io) {
|
package/dist/index.js
CHANGED
|
@@ -1790,6 +1790,8 @@ var require_auth = __commonJS({
|
|
|
1790
1790
|
exports2.refreshUserSessionCredential = refreshUserSessionCredential2;
|
|
1791
1791
|
exports2.createStoredUserSession = createStoredUserSession;
|
|
1792
1792
|
exports2.getJwtExpiresAt = getJwtExpiresAt;
|
|
1793
|
+
exports2.listApplicationOrganizations = listApplicationOrganizations;
|
|
1794
|
+
exports2.switchApplicationOrganization = switchApplicationOrganization;
|
|
1793
1795
|
var node_buffer_1 = require("node:buffer");
|
|
1794
1796
|
var credential_mutations_1 = require_credential_mutations();
|
|
1795
1797
|
var credentials_1 = require_credentials();
|
|
@@ -1876,6 +1878,62 @@ var require_auth = __commonJS({
|
|
|
1876
1878
|
return void 0;
|
|
1877
1879
|
}
|
|
1878
1880
|
}
|
|
1881
|
+
async function listApplicationOrganizations(environment, accessToken) {
|
|
1882
|
+
const applicationId = getJwtAudience(accessToken);
|
|
1883
|
+
if (!applicationId)
|
|
1884
|
+
throw new Error("The Tela session does not name its application. Sign in again.");
|
|
1885
|
+
const data = await authApiRequest(environment.authApiUrl, `/applications/candidate-organizations?applicationId=${encodeURIComponent(applicationId)}`, {
|
|
1886
|
+
headers: { authorization: `Bearer ${accessToken}` }
|
|
1887
|
+
});
|
|
1888
|
+
const organizations = Array.isArray(data.organizations) ? data.organizations : [];
|
|
1889
|
+
return organizations.flatMap((organization) => {
|
|
1890
|
+
if (!isPlainObject5(organization))
|
|
1891
|
+
return [];
|
|
1892
|
+
const id = stringField(organization.id);
|
|
1893
|
+
if (!id)
|
|
1894
|
+
return [];
|
|
1895
|
+
const slug = stringField(organization.slug);
|
|
1896
|
+
const logo = httpsUrlField(organization.logo);
|
|
1897
|
+
return [{
|
|
1898
|
+
id,
|
|
1899
|
+
name: stringField(organization.name) ?? stringField(organization.title) ?? slug ?? id,
|
|
1900
|
+
...slug ? { slug } : {},
|
|
1901
|
+
...logo ? { logo } : {}
|
|
1902
|
+
}];
|
|
1903
|
+
});
|
|
1904
|
+
}
|
|
1905
|
+
function httpsUrlField(value) {
|
|
1906
|
+
const text2 = stringField(value);
|
|
1907
|
+
if (!text2)
|
|
1908
|
+
return void 0;
|
|
1909
|
+
try {
|
|
1910
|
+
return new URL(text2).protocol === "https:" ? text2 : void 0;
|
|
1911
|
+
} catch {
|
|
1912
|
+
return void 0;
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
async function switchApplicationOrganization(environment, accessToken, organizationId) {
|
|
1916
|
+
return await authApiRequest(environment.authApiUrl, "/applications/switch-organization", {
|
|
1917
|
+
method: "POST",
|
|
1918
|
+
headers: {
|
|
1919
|
+
"authorization": `Bearer ${accessToken}`,
|
|
1920
|
+
"x-tela-access-token": accessToken
|
|
1921
|
+
},
|
|
1922
|
+
body: { organizationId }
|
|
1923
|
+
});
|
|
1924
|
+
}
|
|
1925
|
+
function getJwtAudience(token) {
|
|
1926
|
+
try {
|
|
1927
|
+
const [, payload] = token.split(".");
|
|
1928
|
+
if (!payload)
|
|
1929
|
+
return void 0;
|
|
1930
|
+
const decoded = JSON.parse(node_buffer_1.Buffer.from(payload, "base64url").toString("utf8"));
|
|
1931
|
+
const audience = Array.isArray(decoded.aud) ? decoded.aud[0] : decoded.aud;
|
|
1932
|
+
return typeof audience === "string" && audience ? audience : void 0;
|
|
1933
|
+
} catch {
|
|
1934
|
+
return void 0;
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1879
1937
|
async function refreshApplicationToken(authApiUrl, refreshToken) {
|
|
1880
1938
|
return await authApiRequest(authApiUrl, "/applications/token/refresh", {
|
|
1881
1939
|
method: "POST",
|
|
@@ -1968,8 +2026,7 @@ var require_defaults = __commonJS({
|
|
|
1968
2026
|
authApiUrl: "https://auth.tela.com",
|
|
1969
2027
|
defaultApiUrl: "https://api.tela.com",
|
|
1970
2028
|
authApplication: {
|
|
1971
|
-
requesterApplicationId: "860d5506-cab2-4b8b-b08b-fb4222b65bb2"
|
|
1972
|
-
targetApplicationId: "fe9fa028-4d34-407c-b27a-2ecc4779ae69"
|
|
2029
|
+
requesterApplicationId: "860d5506-cab2-4b8b-b08b-fb4222b65bb2"
|
|
1973
2030
|
},
|
|
1974
2031
|
services: {
|
|
1975
2032
|
pantry: "https://pantry-api.tela.tools",
|
|
@@ -1984,8 +2041,7 @@ var require_defaults = __commonJS({
|
|
|
1984
2041
|
authApiUrl: "https://auth-api.telastaging.com",
|
|
1985
2042
|
defaultApiUrl: "https://api.telastaging.com",
|
|
1986
2043
|
authApplication: {
|
|
1987
|
-
requesterApplicationId: "2d2785a9-f79b-442c-a00c-5e41b25538ff"
|
|
1988
|
-
targetApplicationId: "1c021ec1-b7d1-4d72-8733-ac69d930b2df"
|
|
2044
|
+
requesterApplicationId: "2d2785a9-f79b-442c-a00c-5e41b25538ff"
|
|
1989
2045
|
},
|
|
1990
2046
|
services: {
|
|
1991
2047
|
agent: "https://agent-api.telastaging.com",
|
|
@@ -1998,8 +2054,7 @@ var require_defaults = __commonJS({
|
|
|
1998
2054
|
authApiUrl: "http://127.0.0.1:3003",
|
|
1999
2055
|
defaultApiUrl: "http://127.0.0.1:4000",
|
|
2000
2056
|
authApplication: {
|
|
2001
|
-
requesterApplicationId: "297ad7a7-d003-4097-b27a-f31498226f6e"
|
|
2002
|
-
targetApplicationId: "4a727eb5-3933-4c4d-aa0e-620727c25181"
|
|
2057
|
+
requesterApplicationId: "297ad7a7-d003-4097-b27a-f31498226f6e"
|
|
2003
2058
|
},
|
|
2004
2059
|
services: {
|
|
2005
2060
|
vault: "http://127.0.0.1:8443/_services/vault/"
|
|
@@ -18083,6 +18138,8 @@ var require_schema = __commonJS({
|
|
|
18083
18138
|
}).strict();
|
|
18084
18139
|
var authApplicationSchema = zod_1.z.object({
|
|
18085
18140
|
requesterApplicationId: optionalNonEmptyString,
|
|
18141
|
+
// Written by older releases, which signed in to a second (target) app.
|
|
18142
|
+
// Logins now sign in to the requester alone, so it is read and ignored.
|
|
18086
18143
|
targetApplicationId: optionalNonEmptyString
|
|
18087
18144
|
}).strict();
|
|
18088
18145
|
var environmentSchema = zod_1.z.object({
|
|
@@ -36886,7 +36943,7 @@ var init_zod = __esm({
|
|
|
36886
36943
|
}
|
|
36887
36944
|
});
|
|
36888
36945
|
|
|
36889
|
-
// ../../node_modules/.pnpm/@meistrari+auth-core@
|
|
36946
|
+
// ../../node_modules/.pnpm/@meistrari+auth-core@2.8.0_@better-auth+core@1.6.26_@better-auth+utils@0.4.2_@better-fe_c2707dc7f0525f2bbdb85ba87f9e4cbd/node_modules/@meistrari/auth-core/dist/index.mjs
|
|
36890
36947
|
function parsedEnumValues(schema) {
|
|
36891
36948
|
return Object.fromEntries(
|
|
36892
36949
|
Object.entries(schema.enum).map(([key, value]) => [
|
|
@@ -36895,6 +36952,9 @@ function parsedEnumValues(schema) {
|
|
|
36895
36952
|
])
|
|
36896
36953
|
);
|
|
36897
36954
|
}
|
|
36955
|
+
function normalizeAmr(amr) {
|
|
36956
|
+
return amr === AMRs.Saml ? AMRs.Sso : amr;
|
|
36957
|
+
}
|
|
36898
36958
|
function normalizeOrganizationsResponse(response) {
|
|
36899
36959
|
if (Array.isArray(response)) {
|
|
36900
36960
|
return {
|
|
@@ -37053,8 +37113,8 @@ function customEndpointsPluginClient() {
|
|
|
37053
37113
|
getActions: ($fetch) => ({
|
|
37054
37114
|
customEndpoints: {
|
|
37055
37115
|
organizations: {
|
|
37056
|
-
apiKeys: async () => {
|
|
37057
|
-
return await $fetch("/custom-endpoints/organizations/api-keys");
|
|
37116
|
+
apiKeys: async (organizationId) => {
|
|
37117
|
+
return await $fetch("/custom-endpoints/organizations/api-keys", organizationId === void 0 ? void 0 : { query: { organizationId } });
|
|
37058
37118
|
}
|
|
37059
37119
|
},
|
|
37060
37120
|
teams: {
|
|
@@ -37080,6 +37140,26 @@ function handshakePluginClient() {
|
|
|
37080
37140
|
})
|
|
37081
37141
|
};
|
|
37082
37142
|
}
|
|
37143
|
+
function invitationSignupPluginClient() {
|
|
37144
|
+
return {
|
|
37145
|
+
id: "invitation-signup",
|
|
37146
|
+
getActions: ($fetch) => ({
|
|
37147
|
+
invitationSignup: {
|
|
37148
|
+
status: async (invitationId) => {
|
|
37149
|
+
return await $fetch("/invitation/signup-status", {
|
|
37150
|
+
query: { invitationId }
|
|
37151
|
+
});
|
|
37152
|
+
},
|
|
37153
|
+
setupPassword: async (invitationId, password2) => {
|
|
37154
|
+
return await $fetch("/invitation/setup-password", {
|
|
37155
|
+
method: "POST",
|
|
37156
|
+
body: { invitationId, password: password2 }
|
|
37157
|
+
});
|
|
37158
|
+
}
|
|
37159
|
+
}
|
|
37160
|
+
})
|
|
37161
|
+
};
|
|
37162
|
+
}
|
|
37083
37163
|
function sessionAssurancePluginClient() {
|
|
37084
37164
|
return {
|
|
37085
37165
|
id: "session-assurance",
|
|
@@ -37107,6 +37187,20 @@ function sessionAssurancePluginClient() {
|
|
|
37107
37187
|
})
|
|
37108
37188
|
};
|
|
37109
37189
|
}
|
|
37190
|
+
function loginMethodsPluginClient() {
|
|
37191
|
+
return {
|
|
37192
|
+
id: "login-methods",
|
|
37193
|
+
getActions: ($fetch) => {
|
|
37194
|
+
return {
|
|
37195
|
+
loginMethods: {
|
|
37196
|
+
get: async () => {
|
|
37197
|
+
return await $fetch("/login-methods", { method: "GET" });
|
|
37198
|
+
}
|
|
37199
|
+
}
|
|
37200
|
+
};
|
|
37201
|
+
}
|
|
37202
|
+
};
|
|
37203
|
+
}
|
|
37110
37204
|
function createAPIClient(apiUrl, fetchOptions = {}) {
|
|
37111
37205
|
const serviceName2 = typeof process !== "undefined" ? process.env.SERVICE_NAME : "";
|
|
37112
37206
|
const userAgent2 = `auth-sdk:core:${version3}${serviceName2 ? `@${serviceName2}` : ""}`;
|
|
@@ -37123,6 +37217,7 @@ function createAPIClient(apiUrl, fetchOptions = {}) {
|
|
|
37123
37217
|
}),
|
|
37124
37218
|
customEndpointsPluginClient(),
|
|
37125
37219
|
handshakePluginClient(),
|
|
37220
|
+
invitationSignupPluginClient(),
|
|
37126
37221
|
ssoClient(),
|
|
37127
37222
|
twoFactorClient(),
|
|
37128
37223
|
jwtClient(),
|
|
@@ -37133,6 +37228,7 @@ function createAPIClient(apiUrl, fetchOptions = {}) {
|
|
|
37133
37228
|
}),
|
|
37134
37229
|
applicationsPluginClient(),
|
|
37135
37230
|
sessionAssurancePluginClient(),
|
|
37231
|
+
loginMethodsPluginClient(),
|
|
37136
37232
|
emailOTPClient()
|
|
37137
37233
|
],
|
|
37138
37234
|
fetchOptions: {
|
|
@@ -37249,7 +37345,7 @@ function extractTokenPayload(token) {
|
|
|
37249
37345
|
}
|
|
37250
37346
|
var version3, AMRBrand, AALBrand, ACRBrand, AuthMethodBrand, AMR, AAL, ACR, AuthMethod, AMRs, AALs, ACRs, AuthMethods, statements, ac, Roles, rolesAccessControl, userAdditionalFields, JWTPayloadUser, JWTPayloadWorkspace, JWTPayloadAssurance, DEFAULT_JWT_ASSURANCE, JWTPayload, DEVICE_CODE_GRANT, CLIENT_CREDENTIALS_GRANT, ApplicationRouteError, AdminService, BaseError, ApplicationError, RefreshTokenExpiredError, ApplicationSessionAssuranceError, DeviceAuthorizationPendingError, DeviceAuthorizationSlowDownError, DeviceAccessDeniedError, DeviceCodeExpiredError, DeviceTransientServerError, OAuthStepUpProvider, StepUpOption, SessionAssurancePolicy, SENSITIVE_ACTION_ASSURANCE_POLICY, STEP_UP_MAX_AGE_SECONDS, SessionAssuranceRequiredCode, SessionAssurancePayloadAssurance, SessionAssuranceRequiredPayload, SessionAssuranceRequiredError, DEFAULT_SESSION_ASSURANCE_CONFIG, ApplicationSessionAssuranceConfig, ApplicationConfig, ApplicationService, OrganizationService, InvalidSocialProvider, InvalidCallbackURL, EmailRequired, SessionService, ApiKeyService, EmailOTPService, ClientJWTPayloadAssurance, SessionAssuranceResponse, OAuthBeginStepUpResponse, OAuthCompleteStepUpResponse, SendOtpResponse, SessionAssuranceService, UserService, ApiKeyMetadata, AuthClient;
|
|
37251
37347
|
var init_dist2 = __esm({
|
|
37252
|
-
"../../node_modules/.pnpm/@meistrari+auth-core@
|
|
37348
|
+
"../../node_modules/.pnpm/@meistrari+auth-core@2.8.0_@better-auth+core@1.6.26_@better-auth+utils@0.4.2_@better-fe_c2707dc7f0525f2bbdb85ba87f9e4cbd/node_modules/@meistrari/auth-core/dist/index.mjs"() {
|
|
37253
37349
|
init_webapi();
|
|
37254
37350
|
init_client();
|
|
37255
37351
|
init_client2();
|
|
@@ -37258,7 +37354,7 @@ var init_dist2 = __esm({
|
|
|
37258
37354
|
init_access2();
|
|
37259
37355
|
init_access3();
|
|
37260
37356
|
init_zod();
|
|
37261
|
-
version3 = "
|
|
37357
|
+
version3 = "2.8.0";
|
|
37262
37358
|
AMRBrand = /* @__PURE__ */ Symbol("amr");
|
|
37263
37359
|
AALBrand = /* @__PURE__ */ Symbol("aal");
|
|
37264
37360
|
ACRBrand = /* @__PURE__ */ Symbol("acr");
|
|
@@ -37268,6 +37364,11 @@ var init_dist2 = __esm({
|
|
|
37268
37364
|
Otp: "otp",
|
|
37269
37365
|
Oauth: "oauth",
|
|
37270
37366
|
Sso: "sso",
|
|
37367
|
+
/**
|
|
37368
|
+
* @deprecated Issued to SSO sessions before SAML and OIDC were unified
|
|
37369
|
+
* under `sso`. Still parsed so existing sessions and application policies
|
|
37370
|
+
* remain valid, and read as `sso` (see `normalizeAmr`). Never issued.
|
|
37371
|
+
*/
|
|
37271
37372
|
Saml: "saml"
|
|
37272
37373
|
}).brand(AMRBrand);
|
|
37273
37374
|
AAL = zod_default.enum({
|
|
@@ -37282,6 +37383,11 @@ var init_dist2 = __esm({
|
|
|
37282
37383
|
Password: "password",
|
|
37283
37384
|
EmailOTP: "email_otp",
|
|
37284
37385
|
OAuth: "oauth",
|
|
37386
|
+
SSO: "sso",
|
|
37387
|
+
/**
|
|
37388
|
+
* @deprecated Recorded on SSO sessions before SAML and OIDC were unified
|
|
37389
|
+
* under `sso`. Kept so existing sessions still parse; never recorded.
|
|
37390
|
+
*/
|
|
37285
37391
|
SAML: "saml",
|
|
37286
37392
|
Unknown: "unknown"
|
|
37287
37393
|
}).brand(AuthMethodBrand);
|
|
@@ -37402,6 +37508,8 @@ var init_dist2 = __esm({
|
|
|
37402
37508
|
this.client = client;
|
|
37403
37509
|
this.apiUrl = apiUrl;
|
|
37404
37510
|
}
|
|
37511
|
+
client;
|
|
37512
|
+
apiUrl;
|
|
37405
37513
|
/**
|
|
37406
37514
|
* Requests an application management route.
|
|
37407
37515
|
*
|
|
@@ -37683,6 +37791,47 @@ var init_dist2 = __esm({
|
|
|
37683
37791
|
});
|
|
37684
37792
|
return data;
|
|
37685
37793
|
}
|
|
37794
|
+
/**
|
|
37795
|
+
* Lists applications with their entitlements as a global admin. Unlike
|
|
37796
|
+
* {@link listApplications}, which goes through the session-only application
|
|
37797
|
+
* routes, this uses the admin endpoint and so also works with a bearer token.
|
|
37798
|
+
*
|
|
37799
|
+
* @param options - Pagination, ordering, organization filter, search, and member preview options
|
|
37800
|
+
* @returns The application listing with entitlement details
|
|
37801
|
+
*/
|
|
37802
|
+
async listAdminApplications(options2 = {}) {
|
|
37803
|
+
return await this.client.$fetch("/admin/applications", {
|
|
37804
|
+
method: "GET",
|
|
37805
|
+
query: {
|
|
37806
|
+
...options2.limit !== void 0 ? { limit: options2.limit } : {},
|
|
37807
|
+
...options2.offset !== void 0 ? { offset: options2.offset } : {},
|
|
37808
|
+
...options2.search ? { search: options2.search } : {},
|
|
37809
|
+
...options2.organizationId ? { organization_id: options2.organizationId } : {},
|
|
37810
|
+
...options2.membersPreview !== void 0 ? { members_preview: options2.membersPreview } : {},
|
|
37811
|
+
...options2.orderBy ? { sortBy: options2.orderBy } : {},
|
|
37812
|
+
...options2.orderDirection ? { sortDirection: options2.orderDirection } : {}
|
|
37813
|
+
}
|
|
37814
|
+
});
|
|
37815
|
+
}
|
|
37816
|
+
/**
|
|
37817
|
+
* Lists the users with access to an application as a global admin, one row
|
|
37818
|
+
* per user with every organization that grants them access and the role it
|
|
37819
|
+
* grants.
|
|
37820
|
+
*
|
|
37821
|
+
* @param options - Application ID, organization filter, pagination, and search options
|
|
37822
|
+
* @returns The paginated application member listing
|
|
37823
|
+
*/
|
|
37824
|
+
async listApplicationMembers(options2) {
|
|
37825
|
+
return await this.client.$fetch(`/admin/applications/${encodeURIComponent(options2.applicationId)}/members`, {
|
|
37826
|
+
method: "GET",
|
|
37827
|
+
query: {
|
|
37828
|
+
...options2.limit !== void 0 ? { limit: options2.limit } : {},
|
|
37829
|
+
...options2.offset !== void 0 ? { offset: options2.offset } : {},
|
|
37830
|
+
...options2.query ? { query: options2.query } : {},
|
|
37831
|
+
...options2.organizationId ? { organization_id: options2.organizationId } : {}
|
|
37832
|
+
}
|
|
37833
|
+
});
|
|
37834
|
+
}
|
|
37686
37835
|
/**
|
|
37687
37836
|
* Lists active members for one organization as a global admin.
|
|
37688
37837
|
*
|
|
@@ -37740,6 +37889,36 @@ var init_dist2 = __esm({
|
|
|
37740
37889
|
});
|
|
37741
37890
|
return data;
|
|
37742
37891
|
}
|
|
37892
|
+
/**
|
|
37893
|
+
* Updates a team for one organization. Global admins may update any
|
|
37894
|
+
* organization; an organization admin only their own.
|
|
37895
|
+
*
|
|
37896
|
+
* @param options - Organization ID, team ID, new name, and optional replacement member IDs
|
|
37897
|
+
* @returns The updated team
|
|
37898
|
+
*/
|
|
37899
|
+
async updateOrganizationTeam(options2) {
|
|
37900
|
+
const { data } = await this.client.$fetch(`/admin/organizations/${encodeURIComponent(options2.organizationId)}/teams/update`, {
|
|
37901
|
+
method: "POST",
|
|
37902
|
+
body: {
|
|
37903
|
+
teamId: options2.teamId,
|
|
37904
|
+
name: options2.name,
|
|
37905
|
+
...options2.memberIds !== void 0 ? { memberIds: options2.memberIds } : {}
|
|
37906
|
+
}
|
|
37907
|
+
});
|
|
37908
|
+
return data;
|
|
37909
|
+
}
|
|
37910
|
+
/**
|
|
37911
|
+
* Deletes a team for one organization, detaching its members with it.
|
|
37912
|
+
* Global admins may delete from any organization; an organization admin
|
|
37913
|
+
* only from their own.
|
|
37914
|
+
*
|
|
37915
|
+
* @param options - Organization ID and team ID
|
|
37916
|
+
*/
|
|
37917
|
+
async deleteOrganizationTeam(options2) {
|
|
37918
|
+
await this.client.$fetch(`/admin/organizations/${encodeURIComponent(options2.organizationId)}/teams/${encodeURIComponent(options2.teamId)}`, {
|
|
37919
|
+
method: "DELETE"
|
|
37920
|
+
});
|
|
37921
|
+
}
|
|
37743
37922
|
/**
|
|
37744
37923
|
* Fetches a single entitlement together with its ordered access rules.
|
|
37745
37924
|
*
|
|
@@ -37889,6 +38068,22 @@ var init_dist2 = __esm({
|
|
|
37889
38068
|
async unbanUser(userId) {
|
|
37890
38069
|
await this.client.$fetch("/admin/unban-user", { method: "POST", body: { userId } });
|
|
37891
38070
|
}
|
|
38071
|
+
/**
|
|
38072
|
+
* Sets a user's password directly, without sending any email. Requires the
|
|
38073
|
+
* global admin role.
|
|
38074
|
+
* @param options - The user and their new password
|
|
38075
|
+
*/
|
|
38076
|
+
async setUserPassword(options2) {
|
|
38077
|
+
await this.client.$fetch("/admin/set-user-password", { method: "POST", body: options2 });
|
|
38078
|
+
}
|
|
38079
|
+
/**
|
|
38080
|
+
* Signs a user out everywhere by revoking all of their sessions. Requires
|
|
38081
|
+
* the global admin role.
|
|
38082
|
+
* @param userId - The ID of the user whose sessions are revoked
|
|
38083
|
+
*/
|
|
38084
|
+
async revokeUserSessions(userId) {
|
|
38085
|
+
await this.client.$fetch("/admin/revoke-user-sessions", { method: "POST", body: { userId } });
|
|
38086
|
+
}
|
|
37892
38087
|
/**
|
|
37893
38088
|
* Permanently removes a user from the auth system.
|
|
37894
38089
|
* @param userId - The ID of the user to remove
|
|
@@ -38062,12 +38257,12 @@ var init_dist2 = __esm({
|
|
|
38062
38257
|
acceptedAmr: [
|
|
38063
38258
|
AMRs.Pwd,
|
|
38064
38259
|
AMRs.Oauth,
|
|
38065
|
-
AMRs.
|
|
38260
|
+
AMRs.Sso
|
|
38066
38261
|
],
|
|
38067
38262
|
minAal: AALs.Aal1
|
|
38068
38263
|
};
|
|
38069
38264
|
ApplicationSessionAssuranceConfig = zod_default.object({
|
|
38070
|
-
acceptedAmr: AMR.array().optional().default(DEFAULT_SESSION_ASSURANCE_CONFIG.acceptedAmr),
|
|
38265
|
+
acceptedAmr: AMR.array().overwrite((amrs) => [...new Set(amrs.map(normalizeAmr))]).optional().default(DEFAULT_SESSION_ASSURANCE_CONFIG.acceptedAmr),
|
|
38071
38266
|
minAal: AAL.refine(
|
|
38072
38267
|
(aal) => aal !== AALs.Aal3,
|
|
38073
38268
|
"Application session assurance currently supports aal1 and aal2 policies"
|
|
@@ -38086,6 +38281,7 @@ var init_dist2 = __esm({
|
|
|
38086
38281
|
constructor(client) {
|
|
38087
38282
|
this.client = client;
|
|
38088
38283
|
}
|
|
38284
|
+
client;
|
|
38089
38285
|
/**
|
|
38090
38286
|
* Gets public display context for an application auth redirect.
|
|
38091
38287
|
*
|
|
@@ -38103,7 +38299,9 @@ var init_dist2 = __esm({
|
|
|
38103
38299
|
* Lists candidate organizations for a specific application.
|
|
38104
38300
|
*
|
|
38105
38301
|
* Returns organizations where the authenticated user is a member and
|
|
38106
|
-
* the
|
|
38302
|
+
* the effective entitlement grants access through its rules. An enabled global
|
|
38303
|
+
* entitlement is selected first; organization entitlements are considered only
|
|
38304
|
+
* when no global entitlement is enabled.
|
|
38107
38305
|
*
|
|
38108
38306
|
* @param applicationId - The application ID to get candidate organizations for
|
|
38109
38307
|
* @returns The list of candidate organizations
|
|
@@ -38152,7 +38350,7 @@ var init_dist2 = __esm({
|
|
|
38152
38350
|
* on the verification URI to authorize the device.
|
|
38153
38351
|
*
|
|
38154
38352
|
* @param requesterApplicationId - The application requesting authorization
|
|
38155
|
-
* @param targetApplicationId - The target application to gain access to
|
|
38353
|
+
* @param targetApplicationId - The target application to gain access to. Omit it to sign the user in to the requester application itself.
|
|
38156
38354
|
* @returns Device authorization details including codes and verification URI
|
|
38157
38355
|
*/
|
|
38158
38356
|
async startDeviceAuthorizationFlow(requesterApplicationId, targetApplicationId) {
|
|
@@ -38313,11 +38511,13 @@ var init_dist2 = __esm({
|
|
|
38313
38511
|
* Switches the active organization for the authenticated user.
|
|
38314
38512
|
*
|
|
38315
38513
|
* Issues new access and refresh tokens scoped to the specified organization.
|
|
38316
|
-
*
|
|
38317
|
-
*
|
|
38514
|
+
* Requires active membership in the target organization and an enabled entitlement
|
|
38515
|
+
* whose rules allow the user. The global entitlement is selected first, and its
|
|
38516
|
+
* denial never falls back to an organization entitlement. Organization entitlements
|
|
38517
|
+
* are considered only when no global entitlement is enabled.
|
|
38318
38518
|
*
|
|
38319
38519
|
* @param organizationId - The ID of the organization to switch to
|
|
38320
|
-
* @param accessToken -
|
|
38520
|
+
* @param accessToken - Access token for authentication, sent as the `x-tela-access-token` header
|
|
38321
38521
|
* @returns New authentication tokens and user/organization details
|
|
38322
38522
|
*/
|
|
38323
38523
|
async switchOrganization(organizationId, accessToken) {
|
|
@@ -38348,6 +38548,7 @@ var init_dist2 = __esm({
|
|
|
38348
38548
|
constructor(client) {
|
|
38349
38549
|
this.client = client;
|
|
38350
38550
|
}
|
|
38551
|
+
client;
|
|
38351
38552
|
/**
|
|
38352
38553
|
* Retrieves a single organization by ID with optional related data.
|
|
38353
38554
|
*
|
|
@@ -38465,6 +38666,33 @@ var init_dist2 = __esm({
|
|
|
38465
38666
|
member: response.member
|
|
38466
38667
|
};
|
|
38467
38668
|
}
|
|
38669
|
+
/**
|
|
38670
|
+
* Gets the pre-login signup status for an invitation.
|
|
38671
|
+
*
|
|
38672
|
+
* Public endpoint keyed by the invitation id from the emailed invite link.
|
|
38673
|
+
* While the invitation is pending, the result includes the invited email
|
|
38674
|
+
* and whether the invited user still needs to set up their account.
|
|
38675
|
+
*
|
|
38676
|
+
* @param id - The invitation ID from the invite link
|
|
38677
|
+
* @returns The invitation status with account-setup information
|
|
38678
|
+
*/
|
|
38679
|
+
async getInvitationSignupStatus(id) {
|
|
38680
|
+
return await this.client.invitationSignup.status(id);
|
|
38681
|
+
}
|
|
38682
|
+
/**
|
|
38683
|
+
* Creates a password for an invited user who has no account yet.
|
|
38684
|
+
*
|
|
38685
|
+
* Only available once per invitation, while the invitation is pending and
|
|
38686
|
+
* the invited user has never signed in. The user is signed in as part of
|
|
38687
|
+
* the call; the session cookie is set on the response.
|
|
38688
|
+
*
|
|
38689
|
+
* @param id - The invitation ID from the invite link
|
|
38690
|
+
* @param password - The password to create (minimum 8 characters)
|
|
38691
|
+
* @returns The session token and signed-in user
|
|
38692
|
+
*/
|
|
38693
|
+
async setupInvitationPassword(id, password2) {
|
|
38694
|
+
return await this.client.invitationSignup.setupPassword(id, password2);
|
|
38695
|
+
}
|
|
38468
38696
|
/**
|
|
38469
38697
|
* Removes a user from the active organization.
|
|
38470
38698
|
*
|
|
@@ -38595,6 +38823,8 @@ var init_dist2 = __esm({
|
|
|
38595
38823
|
this.client = client;
|
|
38596
38824
|
this.apiUrl = apiUrl;
|
|
38597
38825
|
}
|
|
38826
|
+
client;
|
|
38827
|
+
apiUrl;
|
|
38598
38828
|
/**
|
|
38599
38829
|
* Retrieves the current user session.
|
|
38600
38830
|
*
|
|
@@ -38619,6 +38849,19 @@ var init_dist2 = __esm({
|
|
|
38619
38849
|
async getToken() {
|
|
38620
38850
|
return await this.client.token();
|
|
38621
38851
|
}
|
|
38852
|
+
/**
|
|
38853
|
+
* Lists the login methods enabled in the environment. Public; safe to call
|
|
38854
|
+
* before authentication to decide which sign-in options to render.
|
|
38855
|
+
*
|
|
38856
|
+
* @returns The enabled login methods
|
|
38857
|
+
*/
|
|
38858
|
+
async getLoginMethods() {
|
|
38859
|
+
const response = await this.client.loginMethods.get();
|
|
38860
|
+
if (!response.data) {
|
|
38861
|
+
throw new Error("No data returned from the API", { cause: response.error });
|
|
38862
|
+
}
|
|
38863
|
+
return response.data.loginMethods;
|
|
38864
|
+
}
|
|
38622
38865
|
/**
|
|
38623
38866
|
* Initiates social authentication flow with Google or Microsoft.
|
|
38624
38867
|
*
|
|
@@ -38626,6 +38869,7 @@ var init_dist2 = __esm({
|
|
|
38626
38869
|
* @param options.provider - The social provider
|
|
38627
38870
|
* @param options.callbackURL - URL to redirect to after successful authentication
|
|
38628
38871
|
* @param options.errorCallbackURL - URL to redirect to on error
|
|
38872
|
+
* @param options.loginHint - Email to preselect at the provider
|
|
38629
38873
|
*
|
|
38630
38874
|
* @throws {InvalidSocialProvider} When the provider is not 'google' or 'microsoft'
|
|
38631
38875
|
* @throws {InvalidCallbackURL} When callback URLs are malformed
|
|
@@ -38633,7 +38877,8 @@ var init_dist2 = __esm({
|
|
|
38633
38877
|
async signInWithSocialProvider({
|
|
38634
38878
|
provider,
|
|
38635
38879
|
callbackURL,
|
|
38636
|
-
errorCallbackURL
|
|
38880
|
+
errorCallbackURL,
|
|
38881
|
+
loginHint
|
|
38637
38882
|
}) {
|
|
38638
38883
|
if (provider !== "google" && provider !== "microsoft") {
|
|
38639
38884
|
throw new InvalidSocialProvider("Invalid social provider");
|
|
@@ -38648,21 +38893,23 @@ var init_dist2 = __esm({
|
|
|
38648
38893
|
await this.client.signIn.social({
|
|
38649
38894
|
provider,
|
|
38650
38895
|
callbackURL,
|
|
38651
|
-
errorCallbackURL: errorCallbackURL ?? `${this.apiUrl}/error?callbackURL=${appUrl}
|
|
38896
|
+
errorCallbackURL: errorCallbackURL ?? `${this.apiUrl}/error?callbackURL=${appUrl}`,
|
|
38897
|
+
...loginHint && { loginHint }
|
|
38652
38898
|
});
|
|
38653
38899
|
}
|
|
38654
38900
|
/**
|
|
38655
|
-
* Initiates
|
|
38901
|
+
* Initiates the Single Sign-On authentication flow. The provider resolved
|
|
38902
|
+
* from the email's domain determines whether SAML or OIDC is used.
|
|
38656
38903
|
*
|
|
38657
|
-
* @param options -
|
|
38658
|
-
* @param options.email - User's email to determine the
|
|
38904
|
+
* @param options - SSO sign-in configuration
|
|
38905
|
+
* @param options.email - User's email to determine the SSO provider
|
|
38659
38906
|
* @param options.callbackURL - URL to redirect to after successful authentication
|
|
38660
38907
|
* @param options.errorCallbackURL - URL to redirect to on error
|
|
38661
38908
|
*
|
|
38662
38909
|
* @throws {EmailRequired} When email is not provided
|
|
38663
38910
|
* @throws {InvalidCallbackURL} When callback URLs are malformed
|
|
38664
38911
|
*/
|
|
38665
|
-
async
|
|
38912
|
+
async signInWithSso({
|
|
38666
38913
|
email: email3,
|
|
38667
38914
|
callbackURL,
|
|
38668
38915
|
errorCallbackURL
|
|
@@ -38680,8 +38927,7 @@ var init_dist2 = __esm({
|
|
|
38680
38927
|
await this.client.signIn.sso({
|
|
38681
38928
|
email: email3,
|
|
38682
38929
|
callbackURL,
|
|
38683
|
-
errorCallbackURL: errorCallbackURL ?? `${this.apiUrl}/error?callbackURL=${appUrl}
|
|
38684
|
-
providerType: "saml"
|
|
38930
|
+
errorCallbackURL: errorCallbackURL ?? `${this.apiUrl}/error?callbackURL=${appUrl}`
|
|
38685
38931
|
});
|
|
38686
38932
|
}
|
|
38687
38933
|
/**
|
|
@@ -38758,6 +39004,7 @@ var init_dist2 = __esm({
|
|
|
38758
39004
|
constructor(client) {
|
|
38759
39005
|
this.client = client;
|
|
38760
39006
|
}
|
|
39007
|
+
client;
|
|
38761
39008
|
/**
|
|
38762
39009
|
* Creates a new API key.
|
|
38763
39010
|
*
|
|
@@ -38797,12 +39044,13 @@ var init_dist2 = __esm({
|
|
|
38797
39044
|
return await this.client.apiKey.list();
|
|
38798
39045
|
}
|
|
38799
39046
|
/**
|
|
38800
|
-
* Lists all API keys belonging to
|
|
39047
|
+
* Lists all API keys belonging to an organization.
|
|
38801
39048
|
*
|
|
39049
|
+
* @param organizationId - Defaults to the active organization. Only global admins may select another organization.
|
|
38802
39050
|
* @returns An array of API keys (without secret key values)
|
|
38803
39051
|
*/
|
|
38804
|
-
async listOrganizationApiKeys() {
|
|
38805
|
-
return await this.client.customEndpoints.organizations.apiKeys();
|
|
39052
|
+
async listOrganizationApiKeys(organizationId) {
|
|
39053
|
+
return await this.client.customEndpoints.organizations.apiKeys(organizationId);
|
|
38806
39054
|
}
|
|
38807
39055
|
/**
|
|
38808
39056
|
* Updates an existing API key.
|
|
@@ -38836,6 +39084,7 @@ var init_dist2 = __esm({
|
|
|
38836
39084
|
constructor(client) {
|
|
38837
39085
|
this.client = client;
|
|
38838
39086
|
}
|
|
39087
|
+
client;
|
|
38839
39088
|
/**
|
|
38840
39089
|
* Sends a sign-in verification OTP to an email address.
|
|
38841
39090
|
*
|
|
@@ -38881,6 +39130,7 @@ var init_dist2 = __esm({
|
|
|
38881
39130
|
constructor(client) {
|
|
38882
39131
|
this.client = client;
|
|
38883
39132
|
}
|
|
39133
|
+
client;
|
|
38884
39134
|
async get() {
|
|
38885
39135
|
return parseResponse(SessionAssuranceResponse, await this.client.sessionAssurance.getSessionAssurance());
|
|
38886
39136
|
}
|
|
@@ -38904,6 +39154,7 @@ var init_dist2 = __esm({
|
|
|
38904
39154
|
constructor(client) {
|
|
38905
39155
|
this.client = client;
|
|
38906
39156
|
}
|
|
39157
|
+
client;
|
|
38907
39158
|
async changePassword(currentPassword, newPassword) {
|
|
38908
39159
|
return await this.client.changePassword({ currentPassword, newPassword, revokeOtherSessions: true });
|
|
38909
39160
|
}
|
|
@@ -39876,7 +40127,7 @@ var init_emittery = __esm({
|
|
|
39876
40127
|
}
|
|
39877
40128
|
});
|
|
39878
40129
|
|
|
39879
|
-
// ../../node_modules/.pnpm/@meistrari+auth-cli@1.
|
|
40130
|
+
// ../../node_modules/.pnpm/@meistrari+auth-cli@1.7.0_@better-auth+core@1.6.26_@better-auth+utils@0.4.2_@better-fet_7a4cef6c29c6b591a268b55d655638b9/node_modules/@meistrari/auth-cli/dist/index.mjs
|
|
39880
40131
|
var dist_exports = {};
|
|
39881
40132
|
__export(dist_exports, {
|
|
39882
40133
|
ApplicationSessionAssuranceError: () => ApplicationSessionAssuranceError,
|
|
@@ -39895,7 +40146,7 @@ function isNotFound(err) {
|
|
|
39895
40146
|
}
|
|
39896
40147
|
var import_promises2, import_promises3, import_node_path, DeviceFlowAbortedError, DEFAULT_POLL_INTERVAL, DeviceFlow, JsonFileStorage;
|
|
39897
40148
|
var init_dist3 = __esm({
|
|
39898
|
-
"../../node_modules/.pnpm/@meistrari+auth-cli@1.
|
|
40149
|
+
"../../node_modules/.pnpm/@meistrari+auth-cli@1.7.0_@better-auth+core@1.6.26_@better-auth+utils@0.4.2_@better-fet_7a4cef6c29c6b591a268b55d655638b9/node_modules/@meistrari/auth-cli/dist/index.mjs"() {
|
|
39899
40150
|
import_promises2 = require("node:timers/promises");
|
|
39900
40151
|
init_dist2();
|
|
39901
40152
|
init_dist2();
|
|
@@ -39911,6 +40162,7 @@ var init_dist3 = __esm({
|
|
|
39911
40162
|
super("Device flow was aborted");
|
|
39912
40163
|
this.reason = reason;
|
|
39913
40164
|
}
|
|
40165
|
+
reason;
|
|
39914
40166
|
name = "DeviceFlowAbortedError";
|
|
39915
40167
|
};
|
|
39916
40168
|
DEFAULT_POLL_INTERVAL = 5;
|
|
@@ -40231,6 +40483,7 @@ var init_dist3 = __esm({
|
|
|
40231
40483
|
this.#indent = options2.indent ?? 2;
|
|
40232
40484
|
this.#mode = options2.mode ?? 384;
|
|
40233
40485
|
}
|
|
40486
|
+
path;
|
|
40234
40487
|
#indent;
|
|
40235
40488
|
#mode;
|
|
40236
40489
|
/**
|
|
@@ -76983,9 +77236,7 @@ var require_skill_filesystem = __commonJS({
|
|
|
76983
77236
|
var node_os_1 = require("node:os");
|
|
76984
77237
|
var node_path_1 = __importDefault(require("node:path"));
|
|
76985
77238
|
var node_process_1 = __importDefault(require("node:process"));
|
|
76986
|
-
var node_util_1 = require("node:util");
|
|
76987
77239
|
var archive_1 = require_archive();
|
|
76988
|
-
var run = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
76989
77240
|
function resolveDefaultSkillManagerPaths(home = (0, node_os_1.homedir)()) {
|
|
76990
77241
|
return {
|
|
76991
77242
|
installRoot: node_path_1.default.join(home, ".agents", "skills"),
|
|
@@ -77172,14 +77423,72 @@ There is now nothing at ${target}. The previous installation is intact at ${back
|
|
|
77172
77423
|
return { removed: false, reason: `Skipped ${linkPath}: ${describeError(error48)}` };
|
|
77173
77424
|
}
|
|
77174
77425
|
}
|
|
77175
|
-
|
|
77426
|
+
var SCRIPT_KILL_GRACE_MS = 3e3;
|
|
77427
|
+
var SCRIPT_GROUP_POLL_MS = 50;
|
|
77428
|
+
var MAX_SCRIPT_OUTPUT_LENGTH = 64 * 1024;
|
|
77429
|
+
async function runSkillScript(script, cwd, onOutput, signal) {
|
|
77430
|
+
if (signal?.aborted)
|
|
77431
|
+
return { ok: false, cancelled: true, output: "" };
|
|
77432
|
+
return await new Promise((resolve) => {
|
|
77433
|
+
const child = (0, node_child_process_1.spawn)("sh", ["-c", script], { cwd, detached: node_process_1.default.platform !== "win32" });
|
|
77434
|
+
let output = "";
|
|
77435
|
+
let settled = false;
|
|
77436
|
+
let cancelled = false;
|
|
77437
|
+
const append2 = (chunk) => {
|
|
77438
|
+
if (settled)
|
|
77439
|
+
return;
|
|
77440
|
+
const text2 = chunk.toString();
|
|
77441
|
+
output = `${output}${text2}`.slice(-MAX_SCRIPT_OUTPUT_LENGTH);
|
|
77442
|
+
onOutput?.(text2);
|
|
77443
|
+
};
|
|
77444
|
+
const finish = (ok) => {
|
|
77445
|
+
if (settled)
|
|
77446
|
+
return;
|
|
77447
|
+
settled = true;
|
|
77448
|
+
signal?.removeEventListener("abort", cancel2);
|
|
77449
|
+
resolve({ ok: ok && !cancelled, cancelled, output: output.trimEnd() });
|
|
77450
|
+
};
|
|
77451
|
+
function cancel2() {
|
|
77452
|
+
cancelled = true;
|
|
77453
|
+
killProcessTree(child, "SIGTERM");
|
|
77454
|
+
setTimeout(() => killProcessTree(child, "SIGKILL"), SCRIPT_KILL_GRACE_MS).unref();
|
|
77455
|
+
}
|
|
77456
|
+
signal?.addEventListener("abort", cancel2, { once: true });
|
|
77457
|
+
child.stdout.on("data", append2);
|
|
77458
|
+
child.stderr.on("data", append2);
|
|
77459
|
+
child.on("error", (error48) => {
|
|
77460
|
+
append2(`${describeError(error48)}
|
|
77461
|
+
`);
|
|
77462
|
+
finish(false);
|
|
77463
|
+
});
|
|
77464
|
+
child.on("exit", () => {
|
|
77465
|
+
if (cancelled)
|
|
77466
|
+
void waitForProcessGroupExit(child).then(() => finish(false));
|
|
77467
|
+
});
|
|
77468
|
+
child.on("close", (code) => finish(code === 0));
|
|
77469
|
+
});
|
|
77470
|
+
}
|
|
77471
|
+
async function waitForProcessGroupExit(child) {
|
|
77472
|
+
if (child.pid === void 0 || node_process_1.default.platform === "win32")
|
|
77473
|
+
return;
|
|
77474
|
+
while (true) {
|
|
77475
|
+
try {
|
|
77476
|
+
node_process_1.default.kill(-child.pid, 0);
|
|
77477
|
+
} catch {
|
|
77478
|
+
return;
|
|
77479
|
+
}
|
|
77480
|
+
await new Promise((resolve) => setTimeout(resolve, SCRIPT_GROUP_POLL_MS));
|
|
77481
|
+
}
|
|
77482
|
+
}
|
|
77483
|
+
function killProcessTree(child, signal) {
|
|
77484
|
+
if (child.pid === void 0)
|
|
77485
|
+
return;
|
|
77176
77486
|
try {
|
|
77177
|
-
|
|
77178
|
-
|
|
77179
|
-
|
|
77180
|
-
|
|
77181
|
-
|
|
77182
|
-
return { ok: false, output };
|
|
77487
|
+
if (node_process_1.default.platform === "win32")
|
|
77488
|
+
(0, node_child_process_1.spawn)("taskkill", ["/pid", String(child.pid), "/T", "/F"], { stdio: "ignore" });
|
|
77489
|
+
else
|
|
77490
|
+
node_process_1.default.kill(-child.pid, signal);
|
|
77491
|
+
} catch {
|
|
77183
77492
|
}
|
|
77184
77493
|
}
|
|
77185
77494
|
function describeError(error48) {
|
|
@@ -77236,8 +77545,8 @@ var require_skills = __commonJS({
|
|
|
77236
77545
|
...path2 ? { queries: { path: path2 } } : {}
|
|
77237
77546
|
}));
|
|
77238
77547
|
}
|
|
77239
|
-
async function downloadSkillArchive(archiveUrl) {
|
|
77240
|
-
const response = await fetch(archiveUrl);
|
|
77548
|
+
async function downloadSkillArchive(archiveUrl, signal) {
|
|
77549
|
+
const response = await fetch(archiveUrl, { signal });
|
|
77241
77550
|
if (!response.ok) {
|
|
77242
77551
|
(0, http_1.assertHttpOk)(response, await response.text().catch(() => ""), "Failed to download skill archive");
|
|
77243
77552
|
}
|
|
@@ -77254,7 +77563,7 @@ var require_skill_manager = __commonJS({
|
|
|
77254
77563
|
return mod && mod.__esModule ? mod : { "default": mod };
|
|
77255
77564
|
};
|
|
77256
77565
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
77257
|
-
exports2.SkillInstallDirectoryConflictError = exports2.SkillLifecycleError = exports2.resolveDefaultSkillManagerPaths = void 0;
|
|
77566
|
+
exports2.SkillInstallDirectoryConflictError = exports2.SkillInstallCancelledError = exports2.SkillLifecycleError = exports2.resolveDefaultSkillManagerPaths = void 0;
|
|
77258
77567
|
exports2.createSkillManager = createSkillManager2;
|
|
77259
77568
|
var promises_1 = require("node:fs/promises");
|
|
77260
77569
|
var node_path_1 = __importDefault(require("node:path"));
|
|
@@ -77276,10 +77585,22 @@ var require_skill_manager = __commonJS({
|
|
|
77276
77585
|
this.phase = phase;
|
|
77277
77586
|
this.name = "SkillLifecycleError";
|
|
77278
77587
|
this.slug = entry.slug;
|
|
77279
|
-
this.retainedState =
|
|
77588
|
+
this.retainedState = "unchanged";
|
|
77280
77589
|
}
|
|
77281
77590
|
};
|
|
77282
77591
|
exports2.SkillLifecycleError = SkillLifecycleError;
|
|
77592
|
+
var SkillInstallCancelledError = class extends Error {
|
|
77593
|
+
slug;
|
|
77594
|
+
installed;
|
|
77595
|
+
code = "skill-install-cancelled";
|
|
77596
|
+
constructor(slug, installed) {
|
|
77597
|
+
super(`Installation was cancelled before ${slug} finished.`);
|
|
77598
|
+
this.slug = slug;
|
|
77599
|
+
this.installed = installed;
|
|
77600
|
+
this.name = "SkillInstallCancelledError";
|
|
77601
|
+
}
|
|
77602
|
+
};
|
|
77603
|
+
exports2.SkillInstallCancelledError = SkillInstallCancelledError;
|
|
77283
77604
|
var SkillInstallDirectoryConflictError = class extends Error {
|
|
77284
77605
|
code = "skill-install-directory-conflict";
|
|
77285
77606
|
path;
|
|
@@ -77314,17 +77635,31 @@ Run \`tela skills install ${slug} --force\` to replace it, or remove it by hand.
|
|
|
77314
77635
|
const diagnostics = [];
|
|
77315
77636
|
const installed = [];
|
|
77316
77637
|
const emit = createDiagnosticEmitter(options2, diagnostics);
|
|
77638
|
+
const signal = installOptions.signal;
|
|
77317
77639
|
for (const slug of slugs) {
|
|
77318
|
-
|
|
77319
|
-
|
|
77320
|
-
|
|
77321
|
-
|
|
77322
|
-
|
|
77323
|
-
|
|
77324
|
-
|
|
77325
|
-
|
|
77326
|
-
|
|
77327
|
-
|
|
77640
|
+
if (signal?.aborted)
|
|
77641
|
+
throw new SkillInstallCancelledError(slug, installed);
|
|
77642
|
+
let entry;
|
|
77643
|
+
try {
|
|
77644
|
+
entry = await installOne({
|
|
77645
|
+
client,
|
|
77646
|
+
diagnostics: emit,
|
|
77647
|
+
force: installOptions.force ?? false,
|
|
77648
|
+
ignoreScripts: installOptions.ignoreScripts ?? false,
|
|
77649
|
+
inventoryFile,
|
|
77650
|
+
paths,
|
|
77651
|
+
progress: options2.onInstallProgress,
|
|
77652
|
+
signal,
|
|
77653
|
+
slug,
|
|
77654
|
+
targets
|
|
77655
|
+
});
|
|
77656
|
+
} catch (error48) {
|
|
77657
|
+
if (signal?.aborted)
|
|
77658
|
+
throw new SkillInstallCancelledError(slug, installed);
|
|
77659
|
+
if (error48 instanceof SkillLifecycleError && error48.phase === "install")
|
|
77660
|
+
continue;
|
|
77661
|
+
throw error48;
|
|
77662
|
+
}
|
|
77328
77663
|
if (!entry)
|
|
77329
77664
|
throw new Error(`Skill install for ${slug} did not produce an inventory entry.`);
|
|
77330
77665
|
installed.push(entry);
|
|
@@ -77358,6 +77693,7 @@ Run \`tela skills install ${slug} --force\` to replace it, or remove it by hand.
|
|
|
77358
77693
|
ignoreScripts: upgradeOptions.ignoreScripts ?? false,
|
|
77359
77694
|
inventoryFile,
|
|
77360
77695
|
paths,
|
|
77696
|
+
progress: options2.onInstallProgress,
|
|
77361
77697
|
slug: replacementSlug,
|
|
77362
77698
|
targets
|
|
77363
77699
|
});
|
|
@@ -77388,6 +77724,7 @@ Run \`tela skills install ${slug} --force\` to replace it, or remove it by hand.
|
|
|
77388
77724
|
inventoryFile,
|
|
77389
77725
|
operation: "upgrade",
|
|
77390
77726
|
paths,
|
|
77727
|
+
progress: options2.onInstallProgress,
|
|
77391
77728
|
slug: current.slug,
|
|
77392
77729
|
targets
|
|
77393
77730
|
});
|
|
@@ -77486,30 +77823,68 @@ Run \`tela skills install ${slug} --force\` to replace it, or remove it by hand.
|
|
|
77486
77823
|
};
|
|
77487
77824
|
}
|
|
77488
77825
|
async function installOne(options2) {
|
|
77826
|
+
options2.progress?.({
|
|
77827
|
+
type: "phase",
|
|
77828
|
+
slug: options2.slug,
|
|
77829
|
+
phase: "fetching-metadata",
|
|
77830
|
+
message: "Fetching skill metadata"
|
|
77831
|
+
});
|
|
77489
77832
|
const { ingredient, snapshot } = await (0, skills_1.fetchSkillFile)(options2.client, options2.slug);
|
|
77490
|
-
|
|
77833
|
+
options2.progress?.({
|
|
77834
|
+
type: "phase",
|
|
77835
|
+
slug: options2.slug,
|
|
77836
|
+
phase: "downloading",
|
|
77837
|
+
message: "Downloading skill files"
|
|
77838
|
+
});
|
|
77839
|
+
const archive = await (0, skills_1.downloadSkillArchive)(snapshot.archiveUrl, options2.signal);
|
|
77840
|
+
options2.signal?.throwIfAborted();
|
|
77841
|
+
options2.progress?.({
|
|
77842
|
+
type: "phase",
|
|
77843
|
+
slug: options2.slug,
|
|
77844
|
+
phase: "extracting",
|
|
77845
|
+
message: "Verifying and extracting files"
|
|
77846
|
+
});
|
|
77491
77847
|
const files = (0, archive_1.verifySnapshotFiles)((0, archive_1.parseTarGz)(archive), snapshot.manifest);
|
|
77492
77848
|
const target = (0, skill_filesystem_1.resolveInstallDir)(options2.paths, options2.slug);
|
|
77493
|
-
const
|
|
77849
|
+
const reportConcurrentChange = () => options2.diagnostics({
|
|
77850
|
+
type: "concurrent-change",
|
|
77851
|
+
slug: options2.slug,
|
|
77852
|
+
operation: options2.operation ?? "install",
|
|
77853
|
+
message: `Skipped ${options2.slug}: it was changed while this ${options2.operation ?? "install"} ran`
|
|
77854
|
+
});
|
|
77855
|
+
const before = (await (0, tela_local_config_1.listInstalledSkills)(options2.inventoryFile)).find((entry2) => entry2.slug === options2.slug) ?? null;
|
|
77856
|
+
if (options2.expectedCurrent && !isSameRegistration(before, options2.expectedCurrent)) {
|
|
77857
|
+
reportConcurrentChange();
|
|
77858
|
+
return null;
|
|
77859
|
+
}
|
|
77860
|
+
if ((0, skill_filesystem_1.isUnownedInstallDir)(target, before?.dir ?? null) && !options2.force)
|
|
77861
|
+
throw new SkillInstallDirectoryConflictError(options2.slug, target);
|
|
77862
|
+
const staged = await (0, skill_filesystem_1.stageSkillFiles)(target, files);
|
|
77494
77863
|
let concurrentChange = false;
|
|
77495
77864
|
let entry = null;
|
|
77496
77865
|
try {
|
|
77866
|
+
const lifecycleEntry = {
|
|
77867
|
+
slug: options2.slug,
|
|
77868
|
+
dir: target,
|
|
77869
|
+
sha: snapshot.sha,
|
|
77870
|
+
bundle: ingredient.bundle,
|
|
77871
|
+
symlinks: [],
|
|
77872
|
+
scripts: ingredient.scripts,
|
|
77873
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
77874
|
+
};
|
|
77875
|
+
await runLifecycle(lifecycleEntry, "install", options2.ignoreScripts, options2.diagnostics, options2.progress, options2.signal);
|
|
77876
|
+
options2.signal?.throwIfAborted();
|
|
77877
|
+
options2.progress?.({
|
|
77878
|
+
type: "phase",
|
|
77879
|
+
slug: options2.slug,
|
|
77880
|
+
phase: "finalizing",
|
|
77881
|
+
message: "Linking and finalizing installation"
|
|
77882
|
+
});
|
|
77497
77883
|
entry = await (0, tela_local_config_1.updateInstalledSkill)(options2.slug, async (registered) => {
|
|
77498
|
-
if (
|
|
77884
|
+
if (!isSameRegistration(registered, before)) {
|
|
77499
77885
|
concurrentChange = true;
|
|
77500
|
-
options2.diagnostics({
|
|
77501
|
-
type: "concurrent-change",
|
|
77502
|
-
slug: options2.slug,
|
|
77503
|
-
operation: options2.operation ?? "install",
|
|
77504
|
-
message: `Skipped ${options2.slug}: it was changed while this upgrade ran`
|
|
77505
|
-
});
|
|
77506
77886
|
return registered;
|
|
77507
77887
|
}
|
|
77508
|
-
if ((0, skill_filesystem_1.isUnownedInstallDir)(target, registered?.dir ?? null) && !options2.force) {
|
|
77509
|
-
throw new SkillInstallDirectoryConflictError(options2.slug, target);
|
|
77510
|
-
}
|
|
77511
|
-
const staged = await (0, skill_filesystem_1.stageSkillFiles)(target, files);
|
|
77512
|
-
stagedInstalls.push(staged);
|
|
77513
77888
|
const desiredLinkPaths = new Set(options2.targets.map((linkTarget) => node_path_1.default.join(linkTarget.root, options2.slug)));
|
|
77514
77889
|
for (const linkPath of registered?.symlinks ?? []) {
|
|
77515
77890
|
if (desiredLinkPaths.has(linkPath))
|
|
@@ -77538,25 +77913,27 @@ Run \`tela skills install ${slug} --force\` to replace it, or remove it by hand.
|
|
|
77538
77913
|
}
|
|
77539
77914
|
}
|
|
77540
77915
|
return {
|
|
77541
|
-
|
|
77542
|
-
|
|
77543
|
-
sha: snapshot.sha,
|
|
77544
|
-
bundle: ingredient.bundle,
|
|
77545
|
-
symlinks,
|
|
77546
|
-
scripts: ingredient.scripts,
|
|
77547
|
-
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
77916
|
+
...lifecycleEntry,
|
|
77917
|
+
symlinks
|
|
77548
77918
|
};
|
|
77549
77919
|
}, options2.inventoryFile);
|
|
77550
77920
|
} catch (error48) {
|
|
77551
|
-
|
|
77921
|
+
options2.progress?.({
|
|
77922
|
+
type: "phase",
|
|
77923
|
+
slug: options2.slug,
|
|
77924
|
+
phase: "rolling-back",
|
|
77925
|
+
message: "Rolling back failed installation"
|
|
77926
|
+
});
|
|
77927
|
+
await rollbackStagedInstall(staged, error48);
|
|
77552
77928
|
}
|
|
77553
|
-
if (concurrentChange)
|
|
77929
|
+
if (concurrentChange) {
|
|
77930
|
+
await staged.rollback();
|
|
77931
|
+
reportConcurrentChange();
|
|
77554
77932
|
return null;
|
|
77555
|
-
|
|
77556
|
-
|
|
77933
|
+
}
|
|
77934
|
+
await staged.commit();
|
|
77557
77935
|
if (!entry)
|
|
77558
77936
|
throw new Error(`Skill install for ${options2.slug} did not produce an inventory entry.`);
|
|
77559
|
-
await runLifecycle(entry, "install", options2.ignoreScripts, options2.diagnostics);
|
|
77560
77937
|
return entry;
|
|
77561
77938
|
}
|
|
77562
77939
|
function selectUpgradeTargets(installed, slugs) {
|
|
@@ -77575,6 +77952,11 @@ Run \`tela skills install ${slug} --force\` to replace it, or remove it by hand.
|
|
|
77575
77952
|
throw new Error(`${missing.join(", ")} not installed by tela. Nothing to remove.`);
|
|
77576
77953
|
return slugs.map((slug) => bySlug.get(slug));
|
|
77577
77954
|
}
|
|
77955
|
+
function isSameRegistration(left, right) {
|
|
77956
|
+
if (left === null || right === null)
|
|
77957
|
+
return left === right;
|
|
77958
|
+
return isSameInstall(left, right);
|
|
77959
|
+
}
|
|
77578
77960
|
function isSameInstall(left, right) {
|
|
77579
77961
|
return left.installedAt === right.installedAt && left.sha === right.sha && left.dir === right.dir;
|
|
77580
77962
|
}
|
|
@@ -77595,7 +77977,7 @@ Cleanup failed: ${describeError(cleanupError)}`);
|
|
|
77595
77977
|
}
|
|
77596
77978
|
throw error48;
|
|
77597
77979
|
}
|
|
77598
|
-
async function runLifecycle(entry, phase, ignoreScripts, emit) {
|
|
77980
|
+
async function runLifecycle(entry, phase, ignoreScripts, emit, progress2, signal) {
|
|
77599
77981
|
const script = entry.scripts?.[phase];
|
|
77600
77982
|
if (!script)
|
|
77601
77983
|
return;
|
|
@@ -77616,7 +77998,17 @@ Cleanup failed: ${describeError(cleanupError)}`);
|
|
|
77616
77998
|
script,
|
|
77617
77999
|
message: `Running ${phase} script for ${entry.slug}: ${script}`
|
|
77618
78000
|
});
|
|
77619
|
-
|
|
78001
|
+
if (phase === "install") {
|
|
78002
|
+
progress2?.({
|
|
78003
|
+
type: "phase",
|
|
78004
|
+
slug: entry.slug,
|
|
78005
|
+
phase: "running-install-script",
|
|
78006
|
+
message: "Running install script"
|
|
78007
|
+
});
|
|
78008
|
+
}
|
|
78009
|
+
const outcome = await (0, skill_filesystem_1.runSkillScript)(script, entry.dir, phase === "install" ? (output) => progress2?.({ type: "script-output", slug: entry.slug, output }) : void 0, signal);
|
|
78010
|
+
if (outcome.cancelled)
|
|
78011
|
+
signal?.throwIfAborted();
|
|
77620
78012
|
if (outcome.output) {
|
|
77621
78013
|
emit({
|
|
77622
78014
|
type: "lifecycle-output",
|
|
@@ -77627,7 +78019,14 @@ Cleanup failed: ${describeError(cleanupError)}`);
|
|
|
77627
78019
|
});
|
|
77628
78020
|
}
|
|
77629
78021
|
if (!outcome.ok) {
|
|
77630
|
-
|
|
78022
|
+
const error48 = new SkillLifecycleError(entry, phase);
|
|
78023
|
+
emit({
|
|
78024
|
+
type: "lifecycle-failed",
|
|
78025
|
+
slug: entry.slug,
|
|
78026
|
+
phase,
|
|
78027
|
+
message: error48.message
|
|
78028
|
+
});
|
|
78029
|
+
throw error48;
|
|
77631
78030
|
}
|
|
77632
78031
|
}
|
|
77633
78032
|
function lifecycleFailureMessage(entry, phase) {
|
|
@@ -77636,8 +78035,8 @@ Cleanup failed: ${describeError(cleanupError)}`);
|
|
|
77636
78035
|
return `${opener}
|
|
77637
78036
|
${entry.slug} was left in place. Re-run with --ignore-scripts to remove it anyway.`;
|
|
77638
78037
|
return `${opener}
|
|
77639
|
-
${entry.slug} was installed
|
|
77640
|
-
|
|
78038
|
+
${entry.slug} was not installed because its files and inventory entry were rolled back.
|
|
78039
|
+
Retry without the script with \`tela skills install ${entry.slug} --ignore-scripts\`.`;
|
|
77641
78040
|
}
|
|
77642
78041
|
function normalizePaths(paths) {
|
|
77643
78042
|
const installRoot = normalizeAbsolutePath(paths.installRoot, "installRoot");
|
|
@@ -387685,10 +388084,9 @@ async function authLogin(args, options2, io) {
|
|
|
387685
388084
|
if (!environment)
|
|
387686
388085
|
throw new Error(`Unknown Tela environment: ${environmentId}`);
|
|
387687
388086
|
const requesterApplicationId = environment.authApplication?.requesterApplicationId;
|
|
387688
|
-
|
|
387689
|
-
if (!requesterApplicationId || !targetApplicationId) {
|
|
388087
|
+
if (!requesterApplicationId) {
|
|
387690
388088
|
throw new Error(
|
|
387691
|
-
`Environment '${environmentId}' does not define auth application
|
|
388089
|
+
`Environment '${environmentId}' does not define an auth application ID. Configure it before logging in.`
|
|
387692
388090
|
);
|
|
387693
388091
|
}
|
|
387694
388092
|
const { DeviceFlow: DeviceFlow2 } = await Promise.resolve().then(() => (init_dist3(), dist_exports));
|
|
@@ -387696,7 +388094,6 @@ async function authLogin(args, options2, io) {
|
|
|
387696
388094
|
const flowOptions = {
|
|
387697
388095
|
apiUrl: parsed.authUrl ?? environment.authApiUrl,
|
|
387698
388096
|
requesterApplicationId,
|
|
387699
|
-
targetApplicationId,
|
|
387700
388097
|
storage
|
|
387701
388098
|
};
|
|
387702
388099
|
const loginContext = {
|
|
@@ -389081,15 +389478,19 @@ async function installSkills(args, options2, io) {
|
|
|
389081
389478
|
ignoreScripts: flags.ignoreScripts,
|
|
389082
389479
|
...flags.symlink ? {} : { targets: [] }
|
|
389083
389480
|
});
|
|
389481
|
+
const installedSlugs = new Set(installed.map((entry) => entry.slug));
|
|
389482
|
+
const failed = flags.rest.filter((slug) => !installedSlugs.has(slug));
|
|
389084
389483
|
if (options2.json) {
|
|
389085
|
-
writeJson(io, { installed });
|
|
389086
|
-
return 0;
|
|
389484
|
+
writeJson(io, failed.length > 0 ? { installed, failed } : { installed });
|
|
389485
|
+
return failed.length > 0 ? 1 : 0;
|
|
389087
389486
|
}
|
|
389088
389487
|
for (const entry of installed)
|
|
389089
389488
|
writeLine(io, `Installed ${entry.slug}@${entry.sha.slice(0, 7)} to ${entry.dir}`);
|
|
389090
|
-
return 0;
|
|
389489
|
+
return failed.length > 0 ? 1 : 0;
|
|
389091
389490
|
}
|
|
389092
389491
|
function writeSkillManagerDiagnostic(io, diagnostic) {
|
|
389492
|
+
if (diagnostic.type === "lifecycle-failed" && diagnostic.phase === "uninstall")
|
|
389493
|
+
return;
|
|
389093
389494
|
writeError(io, diagnostic.message);
|
|
389094
389495
|
}
|
|
389095
389496
|
async function upgradeSkills(args, options2, io) {
|
package/package.json
CHANGED
package/skills/tela-cli/SKILL.md
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: tela-cli
|
|
3
|
-
description: Use when a coding agent needs to operate Tela Agent repositories
|
|
3
|
+
description: Use when a coding agent needs to operate Tela Agent repositories, Tela Pantry/service ingredients, managed Pantry skills, or Workflow Code projects through the local `tela` CLI with non-interactive, flag-driven commands and JSON output.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Tela CLI
|
|
7
7
|
|
|
8
|
-
Use the local `tela` binary for Tela Agent repository workflows
|
|
9
|
-
service/library discovery. Prefer explicit flags and `--json` so commands are
|
|
8
|
+
Use the local `tela` binary for Tela Agent repository workflows, Pantry-backed
|
|
9
|
+
service/library discovery, managed skills, and Workflow Code projects. Prefer explicit flags and `--json` so commands are
|
|
10
10
|
safe in non-interactive agent sessions.
|
|
11
11
|
|
|
12
12
|
## Subpaths
|
|
13
13
|
|
|
14
14
|
- Agent workflows: read `references/agent.md` before running `tela agent ...`.
|
|
15
|
+
- Workflow Code: read `tela workflow docs` before authoring or changing workflows.
|
|
15
16
|
|
|
16
17
|
## Core Rules
|
|
17
18
|
|
|
@@ -21,6 +22,7 @@ safe in non-interactive agent sessions.
|
|
|
21
22
|
- Read endpoint or library docs before calling a service: `tela service docs endpoints <slug>` then `tela service docs reference <slug> <METHOD> <PATH>`.
|
|
22
23
|
- Prefer `--json` for machine-readable output and errors.
|
|
23
24
|
- Do not rely on prompts in coding-agent sessions; pass every required value by flag.
|
|
25
|
+
- Pass `--yes` to `tela workflow init`, `sync`, and `publish` in agent sessions; without it they prompt in a terminal or stop with a diagnostic when confirmation is needed.
|
|
24
26
|
- Do not print token material. Use `tela auth token --json` for metadata and `--raw` only when a shell command explicitly needs the token.
|
|
25
27
|
|
|
26
28
|
## Pantry and Service Commands
|
|
@@ -44,6 +46,43 @@ HTTPie-style args for `tela service api`:
|
|
|
44
46
|
- `name==value` sends a query parameter.
|
|
45
47
|
- `Header:value` sends a request header.
|
|
46
48
|
|
|
49
|
+
## Managed Skills
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
tela skills list --json
|
|
53
|
+
tela skills search <query> --json
|
|
54
|
+
tela skills files <slug> --json
|
|
55
|
+
tela skills cat <slug> [path]
|
|
56
|
+
tela skills install <slug...> --json
|
|
57
|
+
tela skills upgrade [slug...] --json
|
|
58
|
+
tela skills uninstall <slug...> --json
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Use `search`, `files`, and `cat` to inspect a skill before installing it.
|
|
62
|
+
`install` places the skill under `~/.agents/skills` and links it into the
|
|
63
|
+
configured provider directories; `--no-symlink` skips the links. `--force`
|
|
64
|
+
replaces a directory Tela did not install, so only use it when the error asks
|
|
65
|
+
for it. `--ignore-scripts` skips a skill's install/uninstall scripts; use it
|
|
66
|
+
only when a script failed and the error suggests it. `upgrade` without slugs
|
|
67
|
+
upgrades every installed skill.
|
|
68
|
+
|
|
69
|
+
## Workflow Code
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
tela workflow docs --json
|
|
73
|
+
tela workflow docs <page>
|
|
74
|
+
tela workflow init --directory <path> --workflow <key> --yes --json
|
|
75
|
+
tela workflow create <target> --project <project-id> --json
|
|
76
|
+
tela workflow compile [target] --json
|
|
77
|
+
tela workflow sync [target] --yes --json
|
|
78
|
+
tela workflow publish [target] --environment <name> --yes --json
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`tela workflow docs` lists the bundled documentation pages; read the relevant
|
|
82
|
+
page (for example `api-reference` or `cli`) before writing workflow code.
|
|
83
|
+
Compile locally before `sync`, and `sync` before `publish`. Run
|
|
84
|
+
`tela workflow --help` for every flag.
|
|
85
|
+
|
|
47
86
|
## Authentication
|
|
48
87
|
|
|
49
88
|
Use `tela auth login --no-interactive` in an agent session. Open the URL it
|
|
@@ -81,6 +81,46 @@ tela agent push --message "feat: update agent behavior" --json
|
|
|
81
81
|
Use `--message` for agent sessions. `--claude` asks the local Claude CLI to
|
|
82
82
|
write a message, and `--manual` relies on fallback behavior.
|
|
83
83
|
|
|
84
|
+
## Merge
|
|
85
|
+
|
|
86
|
+
Preview merging an agent branch into the repository's default branch:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
tela agent merge --dry-run --json
|
|
90
|
+
tela agent merge feature/my-branch --dry-run --json
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Merge after checking the dry run. JSON or non-interactive sessions must pass
|
|
94
|
+
`--yes`:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
tela agent merge feature/my-branch --yes --json
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The branch defaults to the current checkout's branch, and the base defaults to
|
|
101
|
+
the repository's default branch; override it with `--base <branch>`. Passing a
|
|
102
|
+
different branch checks it out, even with `--dry-run`. `--strategy squash`
|
|
103
|
+
(default) or `--strategy merge` selects how the Agent API merges, and the
|
|
104
|
+
remote branch is deleted unless `--keep-branch` is passed.
|
|
105
|
+
|
|
106
|
+
Merge stops before any remote merge call when the worktree is dirty
|
|
107
|
+
(`merge_dirty_worktree`), a merge is already in progress (`merge_in_progress`),
|
|
108
|
+
the branch is not on origin (`merge_branch_not_pushed`), or it has unpushed
|
|
109
|
+
commits (`merge_unpushed_commits`). Follow the error's `fixes`; most of these
|
|
110
|
+
are cleared by `tela agent push`.
|
|
111
|
+
|
|
112
|
+
When the Agent API reports conflicts, the command merges `origin/<base>` into
|
|
113
|
+
the branch locally and returns `status: "conflicts"`. Read `localMergeClean`:
|
|
114
|
+
|
|
115
|
+
- `true`: the local merge applied cleanly. Run `tela agent push`, then rerun
|
|
116
|
+
`tela agent merge <branch>`.
|
|
117
|
+
- `false`: conflict markers are left in the checkout. Resolve them, run
|
|
118
|
+
`tela agent push` to commit and upload the resolution, then rerun
|
|
119
|
+
`tela agent merge <branch>`.
|
|
120
|
+
|
|
121
|
+
Use `tela agent push` rather than raw git to commit the resolution, so the
|
|
122
|
+
branch is uploaded in the same step.
|
|
123
|
+
|
|
84
124
|
## Feedback
|
|
85
125
|
|
|
86
126
|
List feedback for the current commit:
|