@usecontextlayer/cli 0.16.1 → 0.17.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 +4 -4
- package/dist/auth-BL9AxZGb.mjs +1214 -0
- package/dist/auth-BL9AxZGb.mjs.map +1 -0
- package/dist/auth.d.mts +17 -2
- package/dist/auth.d.mts.map +1 -1
- package/dist/auth.mjs +1 -2
- package/dist/cli.mjs +153 -195
- package/dist/cli.mjs.map +1 -1
- package/dist/database-codegen-C5TEhR5_.mjs +24 -0
- package/dist/database-codegen-C5TEhR5_.mjs.map +1 -0
- package/dist/database-dialect-BLWWgYGo.mjs +56 -0
- package/dist/database-dialect-BLWWgYGo.mjs.map +1 -0
- package/dist/database.d.mts +35 -0
- package/dist/database.d.mts.map +1 -0
- package/dist/database.mjs +32 -0
- package/dist/database.mjs.map +1 -0
- package/dist/databases-SvX3IgqC.mjs +23 -0
- package/dist/databases-SvX3IgqC.mjs.map +1 -0
- package/dist/env-C_tllJ4u.mjs +98 -0
- package/dist/env-C_tllJ4u.mjs.map +1 -0
- package/dist/local-databases-ChvVgJH6.mjs +1 -0
- package/dist/local-databases-DVI3ngFq.mjs +53 -0
- package/dist/local-databases-DVI3ngFq.mjs.map +1 -0
- package/dist/{resources-B-EYHG1j.mjs → resources-BhJbHzU0.mjs} +24 -175
- package/dist/resources-BhJbHzU0.mjs.map +1 -0
- package/dist/{auth-DOsE8GwJ.mjs → schemas-D9UReYiT.mjs} +37 -1212
- package/dist/schemas-D9UReYiT.mjs.map +1 -0
- package/dist/schemas-DeaNWrS-.d.mts +2213 -0
- package/dist/schemas-DeaNWrS-.d.mts.map +1 -0
- package/dist/template.tar.gz +0 -0
- package/dist/vite.d.mts +5 -4330
- package/dist/vite.d.mts.map +1 -1
- package/dist/vite.mjs +16 -67
- package/dist/vite.mjs.map +1 -1
- package/package.json +12 -7
- package/dist/auth-DOsE8GwJ.mjs.map +0 -1
- package/dist/resources-B-EYHG1j.mjs.map +0 -1
- package/dist/rolldown-runtime-EAsCxrDo.mjs +0 -14
- package/dist/template/AGENTS.md +0 -13
- package/dist/template/README.md +0 -46
- package/dist/template/app/root.tsx +0 -66
- package/dist/template/app/routes/home.tsx +0 -25
- package/dist/template/databases/updates/drizzle.config.ts +0 -8
- package/dist/template/databases/updates/migrations/0000_create_updates.sql +0 -6
- package/dist/template/databases/updates/migrations/meta/0000_snapshot.json +0 -14
- package/dist/template/databases/updates/migrations/meta/_journal.json +0 -13
- package/dist/template/databases/updates/migrations/migrations.js +0 -10
- package/dist/template/databases/updates/schema.ts +0 -8
- package/dist/template/public/slate.json +0 -4
- package/dist/template/vite.config.ts +0 -9
- package/dist/template/workers/app.ts +0 -8
- package/dist/template/workers/local-resources/index.ts +0 -6
- package/dist/template/workers/local-resources/wrangler.jsonc +0 -19
package/dist/cli.mjs
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as
|
|
3
|
-
import {
|
|
4
|
-
import { a as
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
2
|
+
import { a as login, i as listOrganizations, n as getAccessToken, r as getCurrentUser, t as LoginRequiredError } from "./auth-BL9AxZGb.mjs";
|
|
3
|
+
import { a as boolean, c as literal, g as uuid, h as url, i as array, o as discriminatedUnion, p as string, r as _undefined, s as hostname, u as object } from "./schemas-D9UReYiT.mjs";
|
|
4
|
+
import { a as databaseSlugSchema, l as secretNameSchema, n as env, s as resourcesForConsumer } from "./env-C_tllJ4u.mjs";
|
|
5
|
+
import { a as noCommitSchema, c as execa, n as prepareLocalResourceConfiguration, o as slateResourceConfigurationSchema, r as saveLocalConnection, s as ownerSchema } from "./resources-BhJbHzU0.mjs";
|
|
6
|
+
import { t as databaseQuerySchema } from "./databases-SvX3IgqC.mjs";
|
|
7
|
+
import { readFile } from "node:fs/promises";
|
|
8
|
+
import path, { join, resolve } from "node:path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
7
10
|
import { EventEmitter } from "node:events";
|
|
8
11
|
import childProcess from "node:child_process";
|
|
9
12
|
import fs from "node:fs";
|
|
10
13
|
import process$1, { stdin, stdout } from "node:process";
|
|
11
14
|
import { stripVTControlCharacters, styleText } from "node:util";
|
|
12
|
-
import { fileURLToPath } from "node:url";
|
|
13
15
|
import l__default, { createInterface } from "node:readline";
|
|
16
|
+
//#region \0rolldown/runtime.js
|
|
17
|
+
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
18
|
+
//#endregion
|
|
14
19
|
//#region ../../node_modules/.pnpm/commander@15.0.0/node_modules/commander/lib/error.js
|
|
15
20
|
/**
|
|
16
21
|
* CommanderError class
|
|
@@ -2966,12 +2971,72 @@ function useColor() {
|
|
|
2966
2971
|
}
|
|
2967
2972
|
new Command();
|
|
2968
2973
|
//#endregion
|
|
2974
|
+
//#region ../shared/dist/connections.mjs
|
|
2975
|
+
const connectionSchema = object({
|
|
2976
|
+
alias: string().nullable(),
|
|
2977
|
+
display_name: string().nullable(),
|
|
2978
|
+
id: string(),
|
|
2979
|
+
status: literal("ACTIVE"),
|
|
2980
|
+
toolkit: string()
|
|
2981
|
+
});
|
|
2982
|
+
const connectionsSchema = object({ connections: array(connectionSchema) });
|
|
2983
|
+
//#endregion
|
|
2984
|
+
//#region owner.ts
|
|
2985
|
+
const ownerOptionsSchema = object({ org: string().min(1).optional() });
|
|
2986
|
+
async function resolveOwner(org, headers) {
|
|
2987
|
+
if (!org) return {
|
|
2988
|
+
id: (await getCurrentUser(env, headers)).id,
|
|
2989
|
+
type: "personal"
|
|
2990
|
+
};
|
|
2991
|
+
const organization = (await listOrganizations(env, headers)).find((organization) => organization.slug === org);
|
|
2992
|
+
if (!organization) throw new Error("Organization is not in your memberships");
|
|
2993
|
+
return {
|
|
2994
|
+
id: organization.id,
|
|
2995
|
+
type: "organization"
|
|
2996
|
+
};
|
|
2997
|
+
}
|
|
2998
|
+
function ownerPath(owner) {
|
|
2999
|
+
return `${owner.type === "organization" ? "org" : "personal"}/${encodeURIComponent(owner.id)}`;
|
|
3000
|
+
}
|
|
3001
|
+
//#endregion
|
|
3002
|
+
//#region accounts.ts
|
|
3003
|
+
async function connectAccount(toolkit, org) {
|
|
3004
|
+
const headers = { authorization: `Bearer ${await getAccessToken(env)}` };
|
|
3005
|
+
const owner = await resolveOwner(org, headers);
|
|
3006
|
+
const response = await fetch(new URL(`/api/connections/${ownerPath(owner)}`, env.CTX_PLATFORM_URL), {
|
|
3007
|
+
body: JSON.stringify({ toolkit }),
|
|
3008
|
+
headers: {
|
|
3009
|
+
...headers,
|
|
3010
|
+
"content-type": "application/json"
|
|
3011
|
+
},
|
|
3012
|
+
method: "POST"
|
|
3013
|
+
});
|
|
3014
|
+
if (!response.ok) throw new Error(`Connecting account failed: HTTP ${response.status}`);
|
|
3015
|
+
const { redirect_url } = object({ redirect_url: url() }).parse(await response.json());
|
|
3016
|
+
console.log(`Open this link to connect the Owner's account:\n${redirect_url}`);
|
|
3017
|
+
console.log("After connecting in your browser, assign the connected account to a slate's declared connection.");
|
|
3018
|
+
if (!org) console.log("From your checkout, assign your connected account to a connection declared in slate.json:\n npx @usecontextlayer/cli connections local assign <slug>");
|
|
3019
|
+
console.log(`For a hosted slate, get the connected account ID and assign it:\n npx @usecontextlayer/cli accounts${org ? ` --org '${org.replaceAll("'", "'\\''")}'` : ""} list\n npx @usecontextlayer/cli connections <SlateID-or-hostname> assign <slug> <connection_id>`);
|
|
3020
|
+
}
|
|
3021
|
+
async function listAccounts(org) {
|
|
3022
|
+
const headers = { authorization: `Bearer ${await getAccessToken(env)}` };
|
|
3023
|
+
const owner = await resolveOwner(org, headers);
|
|
3024
|
+
const response = await fetch(new URL(`/api/connections/${ownerPath(owner)}`, env.CTX_PLATFORM_URL), { headers });
|
|
3025
|
+
if (!response.ok) throw new Error(`Connected account list failed: HTTP ${response.status}`);
|
|
3026
|
+
const { connections } = connectionsSchema.parse(await response.json());
|
|
3027
|
+
if (connections.length === 0) {
|
|
3028
|
+
console.log("No connected accounts.");
|
|
3029
|
+
return;
|
|
3030
|
+
}
|
|
3031
|
+
console.table(connections);
|
|
3032
|
+
}
|
|
3033
|
+
//#endregion
|
|
2969
3034
|
//#region agents.ts
|
|
2970
|
-
const platformInstructions = "You are an agent of a ContextLayer slate.The user message is the task for this run. Work in the checkout and return the task's result. Use database_query to read and save persistent data in declared databases. Files are scratch data; schema changes belong in explicitly authored
|
|
3035
|
+
const platformInstructions = "You are an agent of a ContextLayer slate. The user message is the task for this run. Work in the checkout and return the task's result. Use database_query to read and save persistent data in declared databases. Files are scratch data; schema changes belong in explicitly authored Kysely migrations.";
|
|
2971
3036
|
async function runLocalAgent(name, prompt) {
|
|
2972
3037
|
const instructions = await readFile(join("agents", name, "instructions.md"), "utf8");
|
|
2973
3038
|
const { createServer } = await import("vite");
|
|
2974
|
-
const { getPreparedLocalBindings
|
|
3039
|
+
const { getPreparedLocalBindings } = await import("./vite.mjs");
|
|
2975
3040
|
const server = await createServer({
|
|
2976
3041
|
logLevel: "error",
|
|
2977
3042
|
server: {
|
|
@@ -2985,6 +3050,7 @@ async function runLocalAgent(name, prompt) {
|
|
|
2985
3050
|
name,
|
|
2986
3051
|
type: "agent"
|
|
2987
3052
|
});
|
|
3053
|
+
const { openLocalDatabases } = await import("./local-databases-ChvVgJH6.mjs");
|
|
2988
3054
|
const storage = await openLocalDatabases(bindings.workerName, configuration.databases);
|
|
2989
3055
|
const { query, createSdkMcpServer, tool } = await import("@anthropic-ai/claude-agent-sdk");
|
|
2990
3056
|
const run = query({
|
|
@@ -3880,41 +3946,19 @@ ${f}
|
|
|
3880
3946
|
};
|
|
3881
3947
|
`${styleText("gray", S_BAR)}`;
|
|
3882
3948
|
//#endregion
|
|
3883
|
-
//#region ../shared/dist/connections.mjs
|
|
3884
|
-
const connectionSchema = object({
|
|
3885
|
-
alias: string().nullable(),
|
|
3886
|
-
display_name: string().nullable(),
|
|
3887
|
-
id: string(),
|
|
3888
|
-
status: literal("ACTIVE"),
|
|
3889
|
-
toolkit: string()
|
|
3890
|
-
});
|
|
3891
|
-
const connectionsSchema = object({ connections: array(connectionSchema) });
|
|
3892
|
-
//#endregion
|
|
3893
3949
|
//#region ../shared/dist/slate-connections.mjs
|
|
3894
3950
|
const slateConnectionSchema = slateResourceConfigurationSchema.shape.connections.valueType.extend({ slug: string() });
|
|
3895
3951
|
const slateConnectionsSchema = object({ connections: array(slateConnectionSchema) });
|
|
3896
3952
|
//#endregion
|
|
3897
|
-
//#region owner.ts
|
|
3898
|
-
const ownerOptionsSchema = object({ org: string().min(1).optional() });
|
|
3899
|
-
async function resolveOwner(org, headers) {
|
|
3900
|
-
if (!org) return {
|
|
3901
|
-
id: (await getCurrentUser(env, headers)).id,
|
|
3902
|
-
type: "personal"
|
|
3903
|
-
};
|
|
3904
|
-
const organization = (await listOrganizations(env, headers)).find((organization) => organization.slug === org);
|
|
3905
|
-
if (!organization) throw new Error("Organization is not in your memberships");
|
|
3906
|
-
return {
|
|
3907
|
-
id: organization.id,
|
|
3908
|
-
type: "organization"
|
|
3909
|
-
};
|
|
3910
|
-
}
|
|
3911
|
-
function ownerPath(owner) {
|
|
3912
|
-
return `${owner.type === "organization" ? "org" : "personal"}/${encodeURIComponent(owner.id)}`;
|
|
3913
|
-
}
|
|
3914
|
-
//#endregion
|
|
3915
3953
|
//#region connections.ts
|
|
3916
|
-
const
|
|
3954
|
+
const connectionsCommandSchema = discriminatedUnion("operation", [object({
|
|
3955
|
+
connection_id: _undefined(),
|
|
3956
|
+
operation: literal("list"),
|
|
3957
|
+
slug: _undefined(),
|
|
3958
|
+
target: string().min(1)
|
|
3959
|
+
}), object({
|
|
3917
3960
|
connection_id: string().min(1).optional(),
|
|
3961
|
+
operation: literal("assign"),
|
|
3918
3962
|
slug: string().min(1),
|
|
3919
3963
|
target: string().min(1)
|
|
3920
3964
|
}).superRefine((input, ctx) => {
|
|
@@ -3923,7 +3967,7 @@ const connectionAssignmentSchema = object({
|
|
|
3923
3967
|
message: "Hosted assignment requires a connection ID",
|
|
3924
3968
|
path: ["connection_id"]
|
|
3925
3969
|
});
|
|
3926
|
-
});
|
|
3970
|
+
})]);
|
|
3927
3971
|
async function assignSlateConnection(target, slug, connectionId) {
|
|
3928
3972
|
if (target === "local") {
|
|
3929
3973
|
const configuration = await prepareLocalResourceConfiguration();
|
|
@@ -3935,7 +3979,7 @@ async function assignSlateConnection(target, slug, connectionId) {
|
|
|
3935
3979
|
const response = await fetch(url, { headers: { authorization: `Bearer ${await getAccessToken(env)}` } });
|
|
3936
3980
|
if (!response.ok) throw new Error(`Personal connected account list failed: HTTP ${response.status}`);
|
|
3937
3981
|
const { connections } = connectionsSchema.parse(await response.json());
|
|
3938
|
-
if (connections.length === 0) throw new Error(`No personal connected accounts for ${requirement.toolkit}. Run npx @usecontextlayer/cli
|
|
3982
|
+
if (connections.length === 0) throw new Error(`No personal connected accounts for ${requirement.toolkit}. Run npx @usecontextlayer/cli accounts add ${requirement.toolkit} to connect an account in your browser, then rerun this assignment.`);
|
|
3939
3983
|
if (connectionId === void 0) {
|
|
3940
3984
|
const accountId = await select({
|
|
3941
3985
|
message: `Assign a connected ${requirement.toolkit} account to ${slug}`,
|
|
@@ -3968,6 +4012,7 @@ async function assignSlateConnection(target, slug, connectionId) {
|
|
|
3968
4012
|
},
|
|
3969
4013
|
method: "POST"
|
|
3970
4014
|
});
|
|
4015
|
+
if (response.status === 409 && noCommitSchema.safeParse(await response.json()).success) throw new Error("Nothing has been pushed to this slate yet. Push to main before configuring hosted resources.");
|
|
3971
4016
|
if (!response.ok) throw new Error(`Connection assignment failed: HTTP ${response.status}`);
|
|
3972
4017
|
const assignment = object({
|
|
3973
4018
|
connection_id: string(),
|
|
@@ -3975,21 +4020,13 @@ async function assignSlateConnection(target, slug, connectionId) {
|
|
|
3975
4020
|
}).parse(await response.json());
|
|
3976
4021
|
console.log(`${assignment.slug} → ${assignment.connection_id}`);
|
|
3977
4022
|
}
|
|
3978
|
-
async function
|
|
4023
|
+
async function prepareSlateConnections(target) {
|
|
3979
4024
|
if (target === "local") {
|
|
3980
4025
|
const { connections } = await prepareLocalResourceConfiguration();
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
}
|
|
3985
|
-
console.table(Object.entries(connections).map(([slug, { connection_id, consumers, mode, toolkit }]) => ({
|
|
3986
|
-
connected_account: connection_id ?? "unassigned",
|
|
3987
|
-
consumers: consumers.map((consumer) => consumer.type === "app" ? "app" : `agent:${consumer.name}`).join(", "),
|
|
3988
|
-
mode,
|
|
3989
|
-
slug,
|
|
3990
|
-
toolkit
|
|
3991
|
-
})));
|
|
3992
|
-
return;
|
|
4026
|
+
return Object.entries(connections).map(([slug, connection]) => ({
|
|
4027
|
+
...connection,
|
|
4028
|
+
slug
|
|
4029
|
+
}));
|
|
3993
4030
|
}
|
|
3994
4031
|
const response = await fetch(new URL(`/api/slates/${encodeURIComponent(target)}/connections/list`, env.CTX_PLATFORM_URL), {
|
|
3995
4032
|
body: JSON.stringify({}),
|
|
@@ -3999,47 +4036,22 @@ async function listSlateConnections(target) {
|
|
|
3999
4036
|
},
|
|
4000
4037
|
method: "POST"
|
|
4001
4038
|
});
|
|
4039
|
+
if (response.status === 409 && noCommitSchema.safeParse(await response.json()).success) throw new Error("Nothing has been pushed to this slate yet. Push to main before configuring hosted resources.");
|
|
4002
4040
|
if (!response.ok) throw new Error(`Slate connections request failed: HTTP ${response.status}`);
|
|
4003
|
-
|
|
4041
|
+
return slateConnectionsSchema.parse(await response.json()).connections;
|
|
4042
|
+
}
|
|
4043
|
+
async function listSlateConnections(target) {
|
|
4044
|
+
const connections = await prepareSlateConnections(target);
|
|
4004
4045
|
if (!connections.length) {
|
|
4005
4046
|
console.log("No connection requirements.");
|
|
4006
4047
|
return;
|
|
4007
4048
|
}
|
|
4008
|
-
console.table(connections.map(({ connection_id, ...requirement }) => ({
|
|
4049
|
+
console.table(connections.map(({ connection_id, consumers, ...requirement }) => ({
|
|
4009
4050
|
...requirement,
|
|
4010
|
-
connected_account: connection_id ?? "unassigned"
|
|
4051
|
+
connected_account: connection_id ?? "unassigned",
|
|
4052
|
+
consumers: consumers.map((consumer) => consumer.type === "app" ? "app" : `agent:${consumer.name}`).join(", ")
|
|
4011
4053
|
})));
|
|
4012
4054
|
}
|
|
4013
|
-
async function connectAccount(toolkit, org) {
|
|
4014
|
-
const headers = { authorization: `Bearer ${await getAccessToken(env)}` };
|
|
4015
|
-
const owner = await resolveOwner(org, headers);
|
|
4016
|
-
const response = await fetch(new URL(`/api/connections/${ownerPath(owner)}`, env.CTX_PLATFORM_URL), {
|
|
4017
|
-
body: JSON.stringify({ toolkit }),
|
|
4018
|
-
headers: {
|
|
4019
|
-
...headers,
|
|
4020
|
-
"content-type": "application/json"
|
|
4021
|
-
},
|
|
4022
|
-
method: "POST"
|
|
4023
|
-
});
|
|
4024
|
-
if (!response.ok) throw new Error(`Connecting account failed: HTTP ${response.status}`);
|
|
4025
|
-
const { redirect_url } = object({ redirect_url: url() }).parse(await response.json());
|
|
4026
|
-
console.log(`Open this link to connect the Owner's account:\n${redirect_url}`);
|
|
4027
|
-
console.log("After connecting in your browser, assign the connected account to a slate's declared connection.");
|
|
4028
|
-
if (!org) console.log("From your checkout, assign your connected account to a connection declared in slate.json:\n npx @usecontextlayer/cli connection local assign <slug>");
|
|
4029
|
-
console.log(`For a hosted slate, get the connected account ID and assign it:\n npx @usecontextlayer/cli connections${org ? ` --org '${org.replaceAll("'", "'\\''")}'` : ""} list\n npx @usecontextlayer/cli connection <SlateID-or-hostname> assign <slug> <connection_id>`);
|
|
4030
|
-
}
|
|
4031
|
-
async function listConnections(org) {
|
|
4032
|
-
const headers = { authorization: `Bearer ${await getAccessToken(env)}` };
|
|
4033
|
-
const owner = await resolveOwner(org, headers);
|
|
4034
|
-
const response = await fetch(new URL(`/api/connections/${ownerPath(owner)}`, env.CTX_PLATFORM_URL), { headers });
|
|
4035
|
-
if (!response.ok) throw new Error(`Connected account list failed: HTTP ${response.status}`);
|
|
4036
|
-
const { connections } = connectionsSchema.parse(await response.json());
|
|
4037
|
-
if (connections.length === 0) {
|
|
4038
|
-
console.log("No connected accounts.");
|
|
4039
|
-
return;
|
|
4040
|
-
}
|
|
4041
|
-
console.table(connections);
|
|
4042
|
-
}
|
|
4043
4055
|
//#endregion
|
|
4044
4056
|
//#region git-credential.ts
|
|
4045
4057
|
async function configureGit(cli) {
|
|
@@ -4082,7 +4094,7 @@ async function gitCredential(operation) {
|
|
|
4082
4094
|
}
|
|
4083
4095
|
//#endregion
|
|
4084
4096
|
//#region package.json
|
|
4085
|
-
var version = "0.
|
|
4097
|
+
var version = "0.17.0";
|
|
4086
4098
|
//#endregion
|
|
4087
4099
|
//#region secrets.ts
|
|
4088
4100
|
const secretOptionsSchema = ownerOptionsSchema.extend({ stdin: boolean().default(false) });
|
|
@@ -4139,19 +4151,29 @@ async function dropSecret(name, org) {
|
|
|
4139
4151
|
//#endregion
|
|
4140
4152
|
//#region cli.ts
|
|
4141
4153
|
const program = new Command().name("ctx").description("ContextLayer CLI").version(version);
|
|
4142
|
-
program.addHelpText("afterAll",
|
|
4154
|
+
program.addHelpText("afterAll", `\nEnvironment (current values):\n CTX_PLATFORM_URL ${env.CTX_PLATFORM_URL}\n CTX_AUTH_ISSUER ${env.CTX_AUTH_ISSUER}\n CTX_AUTH_CLIENT_ID ${env.CTX_AUTH_CLIENT_ID}\n CTX_CONFIG_DIR ${env.CTX_CONFIG_DIR} Saved-login directory; one login per directory.\n\nRun without a global install: npx @usecontextlayer/cli <command>`);
|
|
4143
4155
|
async function authenticate(command) {
|
|
4144
4156
|
try {
|
|
4145
4157
|
return await getCurrentUser(env, { authorization: `Bearer ${await getAccessToken(env)}` });
|
|
4146
4158
|
} catch (error) {
|
|
4147
|
-
if (error instanceof LoginRequiredError)
|
|
4159
|
+
if (error instanceof LoginRequiredError) {
|
|
4160
|
+
const lines = [error.message];
|
|
4161
|
+
if (error.mismatch) {
|
|
4162
|
+
const { saved, expected } = error.mismatch;
|
|
4163
|
+
lines.push(`Saved issuer: ${saved.issuer}`, `Expected issuer: ${expected.issuer}`);
|
|
4164
|
+
if (saved.clientId !== expected.clientId) lines.push(`Saved client ID: ${saved.clientId}`, `Expected client ID: ${expected.clientId}`);
|
|
4165
|
+
}
|
|
4166
|
+
const settings = Object.entries(env).map(([key, value]) => `${key}='${value.replaceAll("'", "'\\''")}'`).join(" ");
|
|
4167
|
+
lines.push(`Run: ${settings} npx @usecontextlayer/cli login`);
|
|
4168
|
+
command.error(lines.join("\n"));
|
|
4169
|
+
}
|
|
4148
4170
|
throw error;
|
|
4149
4171
|
}
|
|
4150
4172
|
}
|
|
4151
4173
|
async function requireLogin(command) {
|
|
4152
4174
|
await authenticate(command);
|
|
4153
4175
|
}
|
|
4154
|
-
program.command("init <directory>").description("Create a private ContextLayer slate on main with React Router, Tailwind, and shadcn; requires login, Node.js
|
|
4176
|
+
program.command("init <directory>").description("Create a private ContextLayer slate on main with React Router, Tailwind, and shadcn; requires login, Node.js 22.22.0+, pnpm, and Git author identity; sets the Git remote and prints how to start and deploy the slate").option("--org <slug>", "Create the slate under an organization you belong to").hook("preAction", requireLogin).action(async (directory, options) => {
|
|
4155
4177
|
const input = object({ organization_slug: string().min(1).optional() }).parse({ organization_slug: options.org });
|
|
4156
4178
|
const accessToken = await getAccessToken(env);
|
|
4157
4179
|
const gitIdentity = await execa("git", ["var", "GIT_AUTHOR_IDENT"], {
|
|
@@ -4164,15 +4186,15 @@ program.command("init <directory>").description("Create a private ContextLayer s
|
|
|
4164
4186
|
});
|
|
4165
4187
|
process.exitCode = gitIdentity.exitCode;
|
|
4166
4188
|
if (gitIdentity.exitCode !== 0) return;
|
|
4167
|
-
const result = await execa(
|
|
4168
|
-
"create",
|
|
4169
|
-
"cloudflare@latest",
|
|
4189
|
+
const result = await execa(process.execPath, [
|
|
4190
|
+
fileURLToPath(new URL("./dist/cli.js", import.meta.resolve("create-react-router/package.json"))),
|
|
4170
4191
|
directory,
|
|
4171
|
-
"--
|
|
4172
|
-
"
|
|
4173
|
-
"--
|
|
4174
|
-
"
|
|
4175
|
-
"--",
|
|
4192
|
+
"--template",
|
|
4193
|
+
fileURLToPath(new URL("./template.tar.gz", import.meta.url)),
|
|
4194
|
+
"--package-manager",
|
|
4195
|
+
"pnpm",
|
|
4196
|
+
"--install",
|
|
4197
|
+
"--git-init",
|
|
4176
4198
|
"--yes"
|
|
4177
4199
|
], {
|
|
4178
4200
|
env: {
|
|
@@ -4185,80 +4207,6 @@ program.command("init <directory>").description("Create a private ContextLayer s
|
|
|
4185
4207
|
});
|
|
4186
4208
|
process.exitCode = result.exitCode;
|
|
4187
4209
|
if (result.exitCode !== 0) return;
|
|
4188
|
-
const tsconfigPath = join(directory, "tsconfig.json");
|
|
4189
|
-
const tsconfig = looseObject({ compilerOptions: record(string(), unknown()) }).parse(JSON.parse(await readFile(tsconfigPath, "utf8")));
|
|
4190
|
-
tsconfig.compilerOptions.paths = {
|
|
4191
|
-
"@/*": ["./*"],
|
|
4192
|
-
"~/*": ["./app/*"]
|
|
4193
|
-
};
|
|
4194
|
-
const cloudflareTsconfigPath = join(directory, "tsconfig.cloudflare.json");
|
|
4195
|
-
const cloudflareTsconfig = looseObject({
|
|
4196
|
-
compilerOptions: record(string(), unknown()),
|
|
4197
|
-
include: array(string())
|
|
4198
|
-
}).parse(JSON.parse(await readFile(cloudflareTsconfigPath, "utf8")));
|
|
4199
|
-
cloudflareTsconfig.compilerOptions.paths = tsconfig.compilerOptions.paths;
|
|
4200
|
-
cloudflareTsconfig.include.push("databases/**/schema.ts");
|
|
4201
|
-
await writeFile(cloudflareTsconfigPath, `${JSON.stringify(cloudflareTsconfig, null, 2)}\n`);
|
|
4202
|
-
await writeFile(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}\n`);
|
|
4203
|
-
const ui = await execa("pnpm", [
|
|
4204
|
-
"dlx",
|
|
4205
|
-
"shadcn@latest",
|
|
4206
|
-
"init",
|
|
4207
|
-
"--preset",
|
|
4208
|
-
"nova",
|
|
4209
|
-
"--base",
|
|
4210
|
-
"base",
|
|
4211
|
-
"--yes",
|
|
4212
|
-
"--no-monorepo"
|
|
4213
|
-
], {
|
|
4214
|
-
cwd: directory,
|
|
4215
|
-
reject: false,
|
|
4216
|
-
stdio: "inherit"
|
|
4217
|
-
});
|
|
4218
|
-
process.exitCode = ui.exitCode;
|
|
4219
|
-
if (ui.exitCode !== 0) return;
|
|
4220
|
-
await cp(new URL("./template/", import.meta.url), directory, { recursive: true });
|
|
4221
|
-
const configure = await execa("pnpm", [
|
|
4222
|
-
"config",
|
|
4223
|
-
"set",
|
|
4224
|
-
"--location=project",
|
|
4225
|
-
"--json",
|
|
4226
|
-
"minimumReleaseAgeExclude",
|
|
4227
|
-
"[\"@usecontextlayer/*\"]"
|
|
4228
|
-
], {
|
|
4229
|
-
cwd: directory,
|
|
4230
|
-
reject: false,
|
|
4231
|
-
stdio: "inherit"
|
|
4232
|
-
});
|
|
4233
|
-
process.exitCode = configure.exitCode;
|
|
4234
|
-
if (configure.exitCode !== 0) return;
|
|
4235
|
-
const install = await execa("pnpm", [
|
|
4236
|
-
"add",
|
|
4237
|
-
`@usecontextlayer/sdk@${version}`,
|
|
4238
|
-
"zod@^4.4.3",
|
|
4239
|
-
"drizzle-orm@0.45.3"
|
|
4240
|
-
], {
|
|
4241
|
-
cwd: directory,
|
|
4242
|
-
reject: false,
|
|
4243
|
-
stdio: "inherit"
|
|
4244
|
-
});
|
|
4245
|
-
process.exitCode = install.exitCode;
|
|
4246
|
-
if (install.exitCode !== 0) return;
|
|
4247
|
-
const migrationTool = await execa("pnpm", [
|
|
4248
|
-
"add",
|
|
4249
|
-
"-D",
|
|
4250
|
-
"drizzle-kit@0.31.11"
|
|
4251
|
-
], {
|
|
4252
|
-
cwd: directory,
|
|
4253
|
-
reject: false,
|
|
4254
|
-
stdio: "inherit"
|
|
4255
|
-
});
|
|
4256
|
-
process.exitCode = migrationTool.exitCode;
|
|
4257
|
-
if (migrationTool.exitCode !== 0) return;
|
|
4258
|
-
const packagePath = join(directory, "package.json");
|
|
4259
|
-
const checkoutPackage = looseObject({ scripts: record(string(), string()) }).parse(JSON.parse(await readFile(packagePath, "utf8")));
|
|
4260
|
-
checkoutPackage.scripts["db:migration"] = "drizzle-kit generate --custom";
|
|
4261
|
-
await writeFile(packagePath, `${JSON.stringify(checkoutPackage, null, 2)}\n`);
|
|
4262
4210
|
const response = await fetch(new URL("/api/slates", env.CTX_PLATFORM_URL), {
|
|
4263
4211
|
body: JSON.stringify(input),
|
|
4264
4212
|
headers: {
|
|
@@ -4295,11 +4243,11 @@ Start locally:
|
|
|
4295
4243
|
pnpm dev
|
|
4296
4244
|
Open the local URL printed by the development server.
|
|
4297
4245
|
|
|
4298
|
-
Deploy
|
|
4299
|
-
git add .
|
|
4300
|
-
git commit
|
|
4246
|
+
Deploy the committed starter:
|
|
4301
4247
|
git push -u origin main
|
|
4302
4248
|
|
|
4249
|
+
Commit your own changes before subsequent pushes.
|
|
4250
|
+
|
|
4303
4251
|
See README.md for the development and connection workflow.
|
|
4304
4252
|
`);
|
|
4305
4253
|
});
|
|
@@ -4311,36 +4259,37 @@ program.command("login").description("Sign in by approving a browser code and co
|
|
|
4311
4259
|
program.command("git-credential <operation>").description("Git credential helper using the saved login; invoked automatically by Git").hook("preAction", async (command) => {
|
|
4312
4260
|
if (command.args[0] === "get") await requireLogin(command);
|
|
4313
4261
|
}).action(gitCredential);
|
|
4314
|
-
program.command("whoami").description("Show your ContextLayer user ID verified by the auth server").action(async (_options, command) => {
|
|
4315
|
-
|
|
4316
|
-
});
|
|
4317
|
-
program.command("join").argument("<target>", "SlateID, public hostname, or local (run from the checkout root)").description("Join a private slate you can view using ctx login, enabling member-scoped unattended work; returns slate and user IDs").hook("preAction", requireLogin).action(async (target) => {
|
|
4318
|
-
await joinSlate(union([
|
|
4319
|
-
literal("local"),
|
|
4320
|
-
uuid(),
|
|
4321
|
-
hostname()
|
|
4322
|
-
]).parse(target));
|
|
4323
|
-
});
|
|
4324
|
-
const connections = program.command("connections").description("Manage Owner-owned connected accounts or list app and agent connections and assignments; local reads only the current checkout and its saved development assignments").option("--org <slug>", "Manage this organization's connected accounts; defaults to the signed-in user").argument("[target]", "SlateID or public hostname (pushed requirements), or local (current checkout; no platform request)").addArgument(new Argument("[operation]", "Slate connection operation").choices(["list"])).hook("preAction", async (command, actionCommand) => {
|
|
4325
|
-
if (actionCommand !== command || command.args[0] !== "local") await requireLogin(actionCommand);
|
|
4326
|
-
}).action(async (target, operation) => {
|
|
4327
|
-
if (!target || !operation) connections.error("Expected: ctx connections <target> list");
|
|
4328
|
-
await listSlateConnections(target);
|
|
4262
|
+
program.command("whoami").description("Show your ContextLayer user ID verified by the auth server, with the issuer and platform URL in use").action(async (_options, command) => {
|
|
4263
|
+
const { id } = await authenticate(command);
|
|
4264
|
+
console.log(`User: ${id}\nIssuer: ${env.CTX_AUTH_ISSUER}\nPlatform: ${env.CTX_PLATFORM_URL}`);
|
|
4329
4265
|
});
|
|
4330
|
-
|
|
4331
|
-
|
|
4266
|
+
const accounts = program.command("accounts").description("Connect and list the selected Owner's connected accounts").option("--org <slug>", "Manage this organization's connected accounts; defaults to the signed-in user").hook("preAction", requireLogin);
|
|
4267
|
+
accounts.command("list").description("List the selected Owner's connected accounts with their toolkit, identity, and status").action(async (_options, command) => {
|
|
4268
|
+
await listAccounts(ownerOptionsSchema.parse(command.optsWithGlobals()).org);
|
|
4332
4269
|
});
|
|
4333
|
-
|
|
4270
|
+
accounts.command("add <toolkit>").description("Connect the selected Owner's account in your browser (for example, gmail), then assign it with ctx connections <target> assign <slug> [connection_id]").action(async (toolkit, _options, command) => {
|
|
4334
4271
|
const options = ownerOptionsSchema.parse(command.optsWithGlobals());
|
|
4335
4272
|
await connectAccount(string().min(1).parse(toolkit), options.org);
|
|
4336
4273
|
});
|
|
4337
|
-
program.command("
|
|
4338
|
-
const
|
|
4274
|
+
program.command("connections").description("List declared app and agent connections or assign connected accounts; local reads and saves checkout configuration, SlateID/hostname uses pushed declarations and hosted assignments").argument("<target>", "SlateID, public hostname, or local (run from the checkout root)").addArgument(new Argument("<operation>").choices(["list", "assign"])).argument("[slug]", "Required for assign: connection slug declared in slate.json (for example, work-email)").argument("[connection_id]", "For assign: connected account ID; omit locally to choose interactively; required for hosted targets").action(async (target, operation, slug, connectionId, _options, command) => {
|
|
4275
|
+
const parsed = connectionsCommandSchema.safeParse({
|
|
4339
4276
|
connection_id: connectionId,
|
|
4277
|
+
operation,
|
|
4340
4278
|
slug,
|
|
4341
4279
|
target
|
|
4342
4280
|
});
|
|
4343
|
-
|
|
4281
|
+
if (!parsed.success) command.error(parsed.error.issues.map((issue) => issue.message).join("\n"));
|
|
4282
|
+
const input = parsed.data;
|
|
4283
|
+
if (input.operation !== "list" || input.target !== "local") await requireLogin(command);
|
|
4284
|
+
switch (input.operation) {
|
|
4285
|
+
case "list":
|
|
4286
|
+
await listSlateConnections(input.target);
|
|
4287
|
+
break;
|
|
4288
|
+
case "assign":
|
|
4289
|
+
await assignSlateConnection(input.target, input.slug, input.connection_id);
|
|
4290
|
+
break;
|
|
4291
|
+
default: throw new Error(`Unhandled connections operation: ${JSON.stringify(input)}`);
|
|
4292
|
+
}
|
|
4344
4293
|
});
|
|
4345
4294
|
program.command("agent").addArgument(new Argument("<target>", "Run from the checkout 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; Vite startup also requires ctx login when the app declares connections").action(async (_target, _operation, name, prompt) => {
|
|
4346
4295
|
const input = object({
|
|
@@ -4359,6 +4308,15 @@ secrets.command("set").argument("<name>", "Secret name: uppercase letters, digit
|
|
|
4359
4308
|
secrets.command("drop").argument("<name>", "Secret name: uppercase letters, digits, and underscores; cannot start with a digit").description("Delete the selected Owner's shared secret; returns only Owner and name").action(async (name, _options, command) => {
|
|
4360
4309
|
await dropSecret(secretNameSchema.parse(name), secretOptionsSchema.parse(command.optsWithGlobals()).org);
|
|
4361
4310
|
});
|
|
4311
|
+
program.command("db.codegen").argument("<slug>", "Database declared in public/slate.json or agents/<name>/slate.json").description("Generate databases/<slug>/types.ts from the migrated local database").addHelpText("after", "\nRun from the slate root with pnpm dev running.\nApply migrations with pnpm exec kysely before generating types.\n\nExample:\n pnpm db.codegen notes").action(async (slug, _options, command) => {
|
|
4312
|
+
const { generateDatabaseTypes } = await import("./database-codegen-C5TEhR5_.mjs");
|
|
4313
|
+
try {
|
|
4314
|
+
await generateDatabaseTypes(databaseSlugSchema.parse(slug));
|
|
4315
|
+
} catch (error) {
|
|
4316
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT" && "path" in error && error.path === resolve("public/slate.json")) command.error(`Missing ${error.path}. Run pnpm db.codegen from the slate root containing public/slate.json.`);
|
|
4317
|
+
throw error;
|
|
4318
|
+
}
|
|
4319
|
+
});
|
|
4362
4320
|
await program.parseAsync();
|
|
4363
4321
|
//#endregion
|
|
4364
4322
|
export {};
|