@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/{app-CRgSQabE.mjs → app-CJgT3IKd.mjs} +94 -2
- package/dist/app-CJgT3IKd.mjs.map +1 -0
- package/dist/cli.mjs +76 -48
- package/dist/cli.mjs.map +1 -1
- package/dist/template/app/root.tsx +1 -1
- package/dist/template/public/slate.json +2 -1
- package/dist/template/workers/local-tools/index.ts +1 -1
- package/dist/vite.d.mts +19 -4
- package/dist/vite.d.mts.map +1 -1
- package/dist/vite.mjs +10 -5
- package/dist/vite.mjs.map +1 -1
- package/package.json +3 -2
- package/dist/app-CRgSQabE.mjs.map +0 -1
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { _ as
|
|
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 =
|
|
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 } =
|
|
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
|
|
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
|
-
|
|
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
|
|
3071
|
-
console.log(
|
|
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
|
|
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.
|
|
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
|
|
3823
|
-
const
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
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:
|
|
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
|
-
|
|
3838
|
-
|
|
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
|
|
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
|
|
4005
|
-
|
|
4006
|
-
|
|
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) => {
|