@usecontextlayer/cli 0.13.0 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { _ as url, a as whoami, c as array, d as literal, f as looseObject, g as unknown, h as string, i as login, l as boolean, m as record, n as getAccessToken, o as env, p as object, r as getCurrentUser, s as _enum, t as getLocalAppId, u as hostname, v as uuid, y as execa } from "./app-CRgSQabE.mjs";
2
+ import { S as execa, _ as record, a as getAccessToken, b as url, c as whoami, d as boolean, f as discriminatedUnion, g as object, h as looseObject, i as secretNameSchema, l as env, m as literal, n as readLocalManifest, o as getCurrentUser, p as hostname, r as connectionRequirementSchema, s as login, t as getLocalAppId, u as array, v as string, x as uuid, y as unknown } from "./app-CJgT3IKd.mjs";
3
3
  import { cp, readFile, writeFile } from "node:fs/promises";
4
4
  import path, { join } from "node:path";
5
5
  import { EventEmitter } from "node:events";
@@ -3004,7 +3004,41 @@ async function runLocalAgent(name, prompt) {
3004
3004
  }
3005
3005
  }
3006
3006
  //#endregion
3007
+ //#region ../shared/dist/app-connections.mjs
3008
+ const appConnectionSchema = connectionRequirementSchema.extend({
3009
+ connection_id: string().nullable(),
3010
+ slug: string()
3011
+ });
3012
+ const appConnectionsSchema = object({ connections: array(appConnectionSchema) });
3013
+ //#endregion
3014
+ //#region owner.ts
3015
+ const ownerOptionsSchema = object({ org: string().min(1).optional() });
3016
+ async function resolveOwner(org, headers) {
3017
+ if (!org) return {
3018
+ id: (await getCurrentUser(headers)).id,
3019
+ type: "user"
3020
+ };
3021
+ const response = await fetch(new URL("/api/platform/organizations", env.CTX_AUTH_ISSUER), { headers });
3022
+ if (!response.ok) throw new Error(`Organization lookup failed: HTTP ${response.status}`);
3023
+ const { organizations } = object({ organizations: array(object({
3024
+ id: string().min(1),
3025
+ slug: string()
3026
+ })) }).parse(await response.json());
3027
+ const organization = organizations.find((organization) => organization.slug === org);
3028
+ if (!organization) throw new Error("Organization is not in your memberships");
3029
+ return {
3030
+ id: organization.id,
3031
+ type: "organization"
3032
+ };
3033
+ }
3034
+ function ownerPath(owner) {
3035
+ return `${owner.type === "organization" ? "org" : "user"}/${encodeURIComponent(owner.id)}`;
3036
+ }
3037
+ //#endregion
3007
3038
  //#region connections.ts
3039
+ async function getLocalManifest(target) {
3040
+ return target === "local" ? readLocalManifest() : void 0;
3041
+ }
3008
3042
  async function resolveAppTarget(target) {
3009
3043
  if (target !== "local") return target;
3010
3044
  return getLocalAppId();
@@ -3014,6 +3048,7 @@ async function assignAppConnection(target, slug, connectionId) {
3014
3048
  const response = await fetch(new URL(`/api/apps/${encodeURIComponent(appTarget)}/connections/assign`, env.CTX_PLATFORM_URL), {
3015
3049
  body: JSON.stringify({
3016
3050
  connection_id: connectionId,
3051
+ manifest: await getLocalManifest(target),
3017
3052
  slug
3018
3053
  }),
3019
3054
  headers: {
@@ -3031,7 +3066,7 @@ async function assignAppConnection(target, slug, connectionId) {
3031
3066
  }
3032
3067
  async function listAppConnections(target) {
3033
3068
  const appTarget = await resolveAppTarget(target);
3034
- const manifest = target === "local" ? JSON.parse(await readFile("public/slate.json", "utf8")) : void 0;
3069
+ const manifest = await getLocalManifest(target);
3035
3070
  const response = await fetch(new URL(`/api/apps/${encodeURIComponent(appTarget)}/connections/list`, env.CTX_PLATFORM_URL), {
3036
3071
  body: JSON.stringify({ manifest }),
3037
3072
  headers: {
@@ -3041,12 +3076,7 @@ async function listAppConnections(target) {
3041
3076
  method: "POST"
3042
3077
  });
3043
3078
  if (!response.ok) throw new Error(`App connections request failed: HTTP ${response.status}`);
3044
- const { connections } = object({ connections: array(object({
3045
- connection_id: string().nullable(),
3046
- mode: _enum(["individual", "shared"]),
3047
- slug: string(),
3048
- toolkit: string()
3049
- })) }).parse(await response.json());
3079
+ const { connections } = appConnectionsSchema.parse(await response.json());
3050
3080
  if (!connections.length) {
3051
3081
  console.log("No connection requirements.");
3052
3082
  return;
@@ -3056,22 +3086,26 @@ async function listAppConnections(target) {
3056
3086
  connection: connection_id ?? "unassigned"
3057
3087
  })));
3058
3088
  }
3059
- async function addConnection(toolkit) {
3060
- const response = await fetch(new URL("/api/connections", env.CTX_PLATFORM_URL), {
3089
+ async function addConnection(toolkit, org) {
3090
+ const headers = { authorization: `Bearer ${await getAccessToken()}` };
3091
+ const owner = await resolveOwner(org, headers);
3092
+ const response = await fetch(new URL(`/api/connections/${ownerPath(owner)}`, env.CTX_PLATFORM_URL), {
3061
3093
  body: JSON.stringify({ toolkit }),
3062
3094
  headers: {
3063
- authorization: `Bearer ${await getAccessToken()}`,
3095
+ ...headers,
3064
3096
  "content-type": "application/json"
3065
3097
  },
3066
3098
  method: "POST"
3067
3099
  });
3068
3100
  if (!response.ok) throw new Error(`Connection authorization failed: HTTP ${response.status}`);
3069
3101
  const { redirect_url } = object({ redirect_url: url() }).parse(await response.json());
3070
- console.log(`Open this link to connect your account:\n${redirect_url}`);
3071
- console.log("After authorization, run ctx connections list to see your account.");
3102
+ console.log(`Open this link to authorize the Owner's account:\n${redirect_url}`);
3103
+ console.log(`After authorization, run ctx connections${org ? ` --org ${org}` : ""} list to see the Owner's account.`);
3072
3104
  }
3073
- async function listConnections() {
3074
- const response = await fetch(new URL("/api/connections", env.CTX_PLATFORM_URL), { headers: { authorization: `Bearer ${await getAccessToken()}` } });
3105
+ async function listConnections(org) {
3106
+ const headers = { authorization: `Bearer ${await getAccessToken()}` };
3107
+ const owner = await resolveOwner(org, headers);
3108
+ const response = await fetch(new URL(`/api/connections/${ownerPath(owner)}`, env.CTX_PLATFORM_URL), { headers });
3075
3109
  if (!response.ok) throw new Error(`Connection list failed: HTTP ${response.status}`);
3076
3110
  const { connections } = object({ connections: array(object({
3077
3111
  alias: string().nullable(),
@@ -3128,7 +3162,7 @@ async function gitCredential(operation) {
3128
3162
  }
3129
3163
  //#endregion
3130
3164
  //#region package.json
3131
- var version = "0.13.0";
3165
+ var version = "0.14.1";
3132
3166
  //#endregion
3133
3167
  //#region ../../node_modules/.pnpm/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/utils.js
3134
3168
  const getCodePointsLength = (() => {
@@ -3819,40 +3853,29 @@ ${r ? styleText("cyan", S_BAR_END) : ""}
3819
3853
  `${styleText("dim", "↑/↓")}`, `${styleText("dim", "Enter:")}`;
3820
3854
  `${styleText("gray", S_BAR)}`;
3821
3855
  //#endregion
3822
- //#region secrets.ts
3823
- const secretNameSchema = string().regex(/^[A-Z_][A-Z0-9_]*$/);
3824
- const secretOptionsSchema = object({
3825
- org: string().min(1).optional(),
3826
- stdin: boolean().default(false)
3856
+ //#region ../shared/dist/app-usage.mjs
3857
+ const ownerSchema = discriminatedUnion("type", [object({
3858
+ id: string().min(1),
3859
+ type: literal("user")
3860
+ }), object({
3861
+ id: string().min(1),
3862
+ type: literal("organization")
3863
+ })]);
3864
+ object({
3865
+ id: uuid(),
3866
+ owner: ownerSchema
3827
3867
  });
3868
+ //#endregion
3869
+ //#region secrets.ts
3870
+ const secretOptionsSchema = ownerOptionsSchema.extend({ stdin: boolean().default(false) });
3828
3871
  const valueSchema = string().min(1);
3829
3872
  const confirmationSchema = object({
3830
3873
  name: secretNameSchema,
3831
- owner: object({
3832
- id: string().min(1),
3833
- type: _enum(["organization", "user"])
3834
- })
3874
+ owner: ownerSchema
3835
3875
  });
3836
3876
  async function resolveSecretUrl(name, org, headers) {
3837
- let type;
3838
- let id;
3839
- if (org) {
3840
- const url = new URL("/api/platform/organizations", env.CTX_AUTH_ISSUER);
3841
- const response = await fetch(url, { headers });
3842
- if (!response.ok) throw new Error(`Organization lookup failed: HTTP ${response.status}`);
3843
- const { organizations } = object({ organizations: array(object({
3844
- id: string().min(1),
3845
- slug: string()
3846
- })) }).parse(await response.json());
3847
- const organization = organizations.find((organization) => organization.slug === org);
3848
- if (!organization) throw new Error("Organization is not in your memberships");
3849
- type = "org";
3850
- id = organization.id;
3851
- } else {
3852
- id = (await getCurrentUser(headers)).id;
3853
- type = "user";
3854
- }
3855
- return new URL(`/api/secrets/${type}/${encodeURIComponent(id)}/${encodeURIComponent(name)}`, env.CTX_PLATFORM_URL);
3877
+ const owner = await resolveOwner(org, headers);
3878
+ return new URL(`/api/secrets/${ownerPath(owner)}/${encodeURIComponent(name)}`, env.CTX_PLATFORM_URL);
3856
3879
  }
3857
3880
  async function setSecret(name, options) {
3858
3881
  const headers = { authorization: `Bearer ${await getAccessToken()}` };
@@ -3997,13 +4020,18 @@ program.command("login").description("Sign in by approving a browser code and co
3997
4020
  });
3998
4021
  program.command("git-credential <operation>").description("Git credential helper using the saved login; invoked automatically by Git").action(gitCredential);
3999
4022
  program.command("whoami").description("Show your ContextLayer user ID using the saved login").action(whoami);
4000
- const connections = program.command("connections").description("Manage your connected accounts").argument("[target]", "AppID, public hostname, or local (run from the app root)").addArgument(new Argument("[operation]", "App connection operation").choices(["list"])).action(async (target, operation) => {
4023
+ const connections = program.command("connections").description("Manage Owner-owned connected accounts or list an app's requirements").option("--org <org_slug>", "Manage this organization's connections; defaults to the signed-in user").argument("[target]", "AppID, public hostname, or local (run from the app root)").addArgument(new Argument("[operation]", "App connection operation").choices(["list"])).action(async (target, operation) => {
4001
4024
  if (!target || !operation) connections.error("Expected: ctx connections <target> list");
4002
4025
  await listAppConnections(target);
4003
4026
  });
4004
- connections.command("list").description("List your Composio accounts with their toolkit, identity, and status").action(listConnections);
4005
- connections.command("add <toolset>").description("Print a Composio authorization link to connect an account (for example, gmail)").action(addConnection);
4006
- program.command("connection").description("Assign a connection to an app requirement").argument("<target>", "AppID, public hostname, or local (run from the app root)").addArgument(new Argument("<operation>").choices(["assign"])).argument("<slug>", "Connection requirement slug").argument("<connection_id>", "Composio connected-account ID").action(async (target, _operation, slug, connectionId) => {
4027
+ connections.command("list").description("List the selected Owner's Composio accounts with their toolkit, identity, and status").action(async (_options, command) => {
4028
+ await listConnections(ownerOptionsSchema.parse(command.optsWithGlobals()).org);
4029
+ });
4030
+ connections.command("add <toolkit>").description("Print a Composio authorization link for the selected Owner's account (for example, gmail)").action(async (toolkit, _options, command) => {
4031
+ const options = ownerOptionsSchema.parse(command.optsWithGlobals());
4032
+ await addConnection(string().min(1).parse(toolkit), options.org);
4033
+ });
4034
+ program.command("connection").description("Assign a connection using the requirement’s viewer or owner mode; owner mode requires app management").argument("<target>", "AppID, public hostname, or local (run from the app root)").addArgument(new Argument("<operation>").choices(["assign"])).argument("<slug>", "Connection requirement slug").argument("<connection_id>", "Composio connected-account ID").action(async (target, _operation, slug, connectionId) => {
4007
4035
  await assignAppConnection(target, slug, connectionId);
4008
4036
  });
4009
4037
  program.command("agent").addArgument(new Argument("<target>", "Run from the app root").choices(["local"])).addArgument(new Argument("<operation>").choices(["run"])).argument("<name>", "Agent directory under agents/").argument("<prompt>", "Task to send as the user message").description("Run agents/<name>/instructions.md locally with Claude Agent SDK and native Claude authentication; no platform server or ctx login required").action(async (_target, _operation, name, prompt) => {