@meistrari/tela-cli 1.10.1 → 1.11.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 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 workflows.
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
- Canonical commands:
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 feedback --list --apply <all|select> --json --verbose
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 Keychain credential adapter as Dock. `auth token` may refresh that session
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;
@@ -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
- const targetApplicationId = environment.authApplication?.targetApplicationId;
53
- if (!requesterApplicationId || !targetApplicationId) {
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/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@1.39.3_@better-auth+core@1.6.26_@better-auth+utils@0.4.2_@better-f_5390ce4efcf7171453cb5c87c666430d/node_modules/@meistrari/auth-core/dist/index.mjs
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@1.39.3_@better-auth+core@1.6.26_@better-auth+utils@0.4.2_@better-f_5390ce4efcf7171453cb5c87c666430d/node_modules/@meistrari/auth-core/dist/index.mjs"() {
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 = "1.39.3";
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.Saml
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 application has been enabled with appropriate entitlement rules.
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
- * The target organization must be entitled to the application and the entitlement's
38317
- * access rules must allow the current user.
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 - Optional access token for authentication (uses cookie if not provided)
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 SAML-based Single Sign-On authentication flow.
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 - SAML sign-in configuration
38658
- * @param options.email - User's email to determine the SAML provider
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 signInWithSaml({
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 the active organization.
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.6.0_@better-auth+core@1.6.26_@better-auth+utils@0.4.2_@better-fet_0bf65f4b8ffb95a65428638518b6161c/node_modules/@meistrari/auth-cli/dist/index.mjs
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.6.0_@better-auth+core@1.6.26_@better-auth+utils@0.4.2_@better-fet_0bf65f4b8ffb95a65428638518b6161c/node_modules/@meistrari/auth-cli/dist/index.mjs"() {
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
  /**
@@ -387685,10 +387938,9 @@ async function authLogin(args, options2, io) {
387685
387938
  if (!environment)
387686
387939
  throw new Error(`Unknown Tela environment: ${environmentId}`);
387687
387940
  const requesterApplicationId = environment.authApplication?.requesterApplicationId;
387688
- const targetApplicationId = environment.authApplication?.targetApplicationId;
387689
- if (!requesterApplicationId || !targetApplicationId) {
387941
+ if (!requesterApplicationId) {
387690
387942
  throw new Error(
387691
- `Environment '${environmentId}' does not define auth application IDs. Configure them before logging in.`
387943
+ `Environment '${environmentId}' does not define an auth application ID. Configure it before logging in.`
387692
387944
  );
387693
387945
  }
387694
387946
  const { DeviceFlow: DeviceFlow2 } = await Promise.resolve().then(() => (init_dist3(), dist_exports));
@@ -387696,7 +387948,6 @@ async function authLogin(args, options2, io) {
387696
387948
  const flowOptions = {
387697
387949
  apiUrl: parsed.authUrl ?? environment.authApiUrl,
387698
387950
  requesterApplicationId,
387699
- targetApplicationId,
387700
387951
  storage
387701
387952
  };
387702
387953
  const loginContext = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meistrari/tela-cli",
3
- "version": "1.10.1",
3
+ "version": "1.11.0",
4
4
  "description": "Tela command line tools for local state and agent workflows.",
5
5
  "engines": {
6
6
  "node": ">=22"
@@ -1,17 +1,18 @@
1
1
  ---
2
2
  name: tela-cli
3
- description: Use when a coding agent needs to operate Tela Agent repositories or Tela Pantry/service ingredients through the local `tela` CLI with non-interactive, flag-driven commands and JSON output.
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 and Pantry-backed
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: