@usecontextlayer/cli 0.16.2 → 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 +151 -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--XCCMeP6.mjs → resources-BhJbHzU0.mjs} +23 -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--XCCMeP6.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}`,
|
|
@@ -3976,21 +4020,13 @@ async function assignSlateConnection(target, slug, connectionId) {
|
|
|
3976
4020
|
}).parse(await response.json());
|
|
3977
4021
|
console.log(`${assignment.slug} → ${assignment.connection_id}`);
|
|
3978
4022
|
}
|
|
3979
|
-
async function
|
|
4023
|
+
async function prepareSlateConnections(target) {
|
|
3980
4024
|
if (target === "local") {
|
|
3981
4025
|
const { connections } = await prepareLocalResourceConfiguration();
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
}
|
|
3986
|
-
console.table(Object.entries(connections).map(([slug, { connection_id, consumers, mode, toolkit }]) => ({
|
|
3987
|
-
connected_account: connection_id ?? "unassigned",
|
|
3988
|
-
consumers: consumers.map((consumer) => consumer.type === "app" ? "app" : `agent:${consumer.name}`).join(", "),
|
|
3989
|
-
mode,
|
|
3990
|
-
slug,
|
|
3991
|
-
toolkit
|
|
3992
|
-
})));
|
|
3993
|
-
return;
|
|
4026
|
+
return Object.entries(connections).map(([slug, connection]) => ({
|
|
4027
|
+
...connection,
|
|
4028
|
+
slug
|
|
4029
|
+
}));
|
|
3994
4030
|
}
|
|
3995
4031
|
const response = await fetch(new URL(`/api/slates/${encodeURIComponent(target)}/connections/list`, env.CTX_PLATFORM_URL), {
|
|
3996
4032
|
body: JSON.stringify({}),
|
|
@@ -4002,46 +4038,20 @@ async function listSlateConnections(target) {
|
|
|
4002
4038
|
});
|
|
4003
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.");
|
|
4004
4040
|
if (!response.ok) throw new Error(`Slate connections request failed: HTTP ${response.status}`);
|
|
4005
|
-
|
|
4041
|
+
return slateConnectionsSchema.parse(await response.json()).connections;
|
|
4042
|
+
}
|
|
4043
|
+
async function listSlateConnections(target) {
|
|
4044
|
+
const connections = await prepareSlateConnections(target);
|
|
4006
4045
|
if (!connections.length) {
|
|
4007
4046
|
console.log("No connection requirements.");
|
|
4008
4047
|
return;
|
|
4009
4048
|
}
|
|
4010
|
-
console.table(connections.map(({ connection_id, ...requirement }) => ({
|
|
4049
|
+
console.table(connections.map(({ connection_id, consumers, ...requirement }) => ({
|
|
4011
4050
|
...requirement,
|
|
4012
|
-
connected_account: connection_id ?? "unassigned"
|
|
4051
|
+
connected_account: connection_id ?? "unassigned",
|
|
4052
|
+
consumers: consumers.map((consumer) => consumer.type === "app" ? "app" : `agent:${consumer.name}`).join(", ")
|
|
4013
4053
|
})));
|
|
4014
4054
|
}
|
|
4015
|
-
async function connectAccount(toolkit, org) {
|
|
4016
|
-
const headers = { authorization: `Bearer ${await getAccessToken(env)}` };
|
|
4017
|
-
const owner = await resolveOwner(org, headers);
|
|
4018
|
-
const response = await fetch(new URL(`/api/connections/${ownerPath(owner)}`, env.CTX_PLATFORM_URL), {
|
|
4019
|
-
body: JSON.stringify({ toolkit }),
|
|
4020
|
-
headers: {
|
|
4021
|
-
...headers,
|
|
4022
|
-
"content-type": "application/json"
|
|
4023
|
-
},
|
|
4024
|
-
method: "POST"
|
|
4025
|
-
});
|
|
4026
|
-
if (!response.ok) throw new Error(`Connecting account failed: HTTP ${response.status}`);
|
|
4027
|
-
const { redirect_url } = object({ redirect_url: url() }).parse(await response.json());
|
|
4028
|
-
console.log(`Open this link to connect the Owner's account:\n${redirect_url}`);
|
|
4029
|
-
console.log("After connecting in your browser, assign the connected account to a slate's declared connection.");
|
|
4030
|
-
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>");
|
|
4031
|
-
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>`);
|
|
4032
|
-
}
|
|
4033
|
-
async function listConnections(org) {
|
|
4034
|
-
const headers = { authorization: `Bearer ${await getAccessToken(env)}` };
|
|
4035
|
-
const owner = await resolveOwner(org, headers);
|
|
4036
|
-
const response = await fetch(new URL(`/api/connections/${ownerPath(owner)}`, env.CTX_PLATFORM_URL), { headers });
|
|
4037
|
-
if (!response.ok) throw new Error(`Connected account list failed: HTTP ${response.status}`);
|
|
4038
|
-
const { connections } = connectionsSchema.parse(await response.json());
|
|
4039
|
-
if (connections.length === 0) {
|
|
4040
|
-
console.log("No connected accounts.");
|
|
4041
|
-
return;
|
|
4042
|
-
}
|
|
4043
|
-
console.table(connections);
|
|
4044
|
-
}
|
|
4045
4055
|
//#endregion
|
|
4046
4056
|
//#region git-credential.ts
|
|
4047
4057
|
async function configureGit(cli) {
|
|
@@ -4084,7 +4094,7 @@ async function gitCredential(operation) {
|
|
|
4084
4094
|
}
|
|
4085
4095
|
//#endregion
|
|
4086
4096
|
//#region package.json
|
|
4087
|
-
var version = "0.
|
|
4097
|
+
var version = "0.17.0";
|
|
4088
4098
|
//#endregion
|
|
4089
4099
|
//#region secrets.ts
|
|
4090
4100
|
const secretOptionsSchema = ownerOptionsSchema.extend({ stdin: boolean().default(false) });
|
|
@@ -4141,19 +4151,29 @@ async function dropSecret(name, org) {
|
|
|
4141
4151
|
//#endregion
|
|
4142
4152
|
//#region cli.ts
|
|
4143
4153
|
const program = new Command().name("ctx").description("ContextLayer CLI").version(version);
|
|
4144
|
-
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>`);
|
|
4145
4155
|
async function authenticate(command) {
|
|
4146
4156
|
try {
|
|
4147
4157
|
return await getCurrentUser(env, { authorization: `Bearer ${await getAccessToken(env)}` });
|
|
4148
4158
|
} catch (error) {
|
|
4149
|
-
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
|
+
}
|
|
4150
4170
|
throw error;
|
|
4151
4171
|
}
|
|
4152
4172
|
}
|
|
4153
4173
|
async function requireLogin(command) {
|
|
4154
4174
|
await authenticate(command);
|
|
4155
4175
|
}
|
|
4156
|
-
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) => {
|
|
4157
4177
|
const input = object({ organization_slug: string().min(1).optional() }).parse({ organization_slug: options.org });
|
|
4158
4178
|
const accessToken = await getAccessToken(env);
|
|
4159
4179
|
const gitIdentity = await execa("git", ["var", "GIT_AUTHOR_IDENT"], {
|
|
@@ -4166,15 +4186,15 @@ program.command("init <directory>").description("Create a private ContextLayer s
|
|
|
4166
4186
|
});
|
|
4167
4187
|
process.exitCode = gitIdentity.exitCode;
|
|
4168
4188
|
if (gitIdentity.exitCode !== 0) return;
|
|
4169
|
-
const result = await execa(
|
|
4170
|
-
"create",
|
|
4171
|
-
"cloudflare@latest",
|
|
4189
|
+
const result = await execa(process.execPath, [
|
|
4190
|
+
fileURLToPath(new URL("./dist/cli.js", import.meta.resolve("create-react-router/package.json"))),
|
|
4172
4191
|
directory,
|
|
4173
|
-
"--
|
|
4174
|
-
"
|
|
4175
|
-
"--
|
|
4176
|
-
"
|
|
4177
|
-
"--",
|
|
4192
|
+
"--template",
|
|
4193
|
+
fileURLToPath(new URL("./template.tar.gz", import.meta.url)),
|
|
4194
|
+
"--package-manager",
|
|
4195
|
+
"pnpm",
|
|
4196
|
+
"--install",
|
|
4197
|
+
"--git-init",
|
|
4178
4198
|
"--yes"
|
|
4179
4199
|
], {
|
|
4180
4200
|
env: {
|
|
@@ -4187,80 +4207,6 @@ program.command("init <directory>").description("Create a private ContextLayer s
|
|
|
4187
4207
|
});
|
|
4188
4208
|
process.exitCode = result.exitCode;
|
|
4189
4209
|
if (result.exitCode !== 0) return;
|
|
4190
|
-
const tsconfigPath = join(directory, "tsconfig.json");
|
|
4191
|
-
const tsconfig = looseObject({ compilerOptions: record(string(), unknown()) }).parse(JSON.parse(await readFile(tsconfigPath, "utf8")));
|
|
4192
|
-
tsconfig.compilerOptions.paths = {
|
|
4193
|
-
"@/*": ["./*"],
|
|
4194
|
-
"~/*": ["./app/*"]
|
|
4195
|
-
};
|
|
4196
|
-
const cloudflareTsconfigPath = join(directory, "tsconfig.cloudflare.json");
|
|
4197
|
-
const cloudflareTsconfig = looseObject({
|
|
4198
|
-
compilerOptions: record(string(), unknown()),
|
|
4199
|
-
include: array(string())
|
|
4200
|
-
}).parse(JSON.parse(await readFile(cloudflareTsconfigPath, "utf8")));
|
|
4201
|
-
cloudflareTsconfig.compilerOptions.paths = tsconfig.compilerOptions.paths;
|
|
4202
|
-
cloudflareTsconfig.include.push("databases/**/schema.ts");
|
|
4203
|
-
await writeFile(cloudflareTsconfigPath, `${JSON.stringify(cloudflareTsconfig, null, 2)}\n`);
|
|
4204
|
-
await writeFile(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}\n`);
|
|
4205
|
-
const ui = await execa("pnpm", [
|
|
4206
|
-
"dlx",
|
|
4207
|
-
"shadcn@latest",
|
|
4208
|
-
"init",
|
|
4209
|
-
"--preset",
|
|
4210
|
-
"nova",
|
|
4211
|
-
"--base",
|
|
4212
|
-
"base",
|
|
4213
|
-
"--yes",
|
|
4214
|
-
"--no-monorepo"
|
|
4215
|
-
], {
|
|
4216
|
-
cwd: directory,
|
|
4217
|
-
reject: false,
|
|
4218
|
-
stdio: "inherit"
|
|
4219
|
-
});
|
|
4220
|
-
process.exitCode = ui.exitCode;
|
|
4221
|
-
if (ui.exitCode !== 0) return;
|
|
4222
|
-
await cp(new URL("./template/", import.meta.url), directory, { recursive: true });
|
|
4223
|
-
const configure = await execa("pnpm", [
|
|
4224
|
-
"config",
|
|
4225
|
-
"set",
|
|
4226
|
-
"--location=project",
|
|
4227
|
-
"--json",
|
|
4228
|
-
"minimumReleaseAgeExclude",
|
|
4229
|
-
"[\"@usecontextlayer/*\"]"
|
|
4230
|
-
], {
|
|
4231
|
-
cwd: directory,
|
|
4232
|
-
reject: false,
|
|
4233
|
-
stdio: "inherit"
|
|
4234
|
-
});
|
|
4235
|
-
process.exitCode = configure.exitCode;
|
|
4236
|
-
if (configure.exitCode !== 0) return;
|
|
4237
|
-
const install = await execa("pnpm", [
|
|
4238
|
-
"add",
|
|
4239
|
-
`@usecontextlayer/sdk@${version}`,
|
|
4240
|
-
"zod@^4.4.3",
|
|
4241
|
-
"drizzle-orm@0.45.3"
|
|
4242
|
-
], {
|
|
4243
|
-
cwd: directory,
|
|
4244
|
-
reject: false,
|
|
4245
|
-
stdio: "inherit"
|
|
4246
|
-
});
|
|
4247
|
-
process.exitCode = install.exitCode;
|
|
4248
|
-
if (install.exitCode !== 0) return;
|
|
4249
|
-
const migrationTool = await execa("pnpm", [
|
|
4250
|
-
"add",
|
|
4251
|
-
"-D",
|
|
4252
|
-
"drizzle-kit@0.31.11"
|
|
4253
|
-
], {
|
|
4254
|
-
cwd: directory,
|
|
4255
|
-
reject: false,
|
|
4256
|
-
stdio: "inherit"
|
|
4257
|
-
});
|
|
4258
|
-
process.exitCode = migrationTool.exitCode;
|
|
4259
|
-
if (migrationTool.exitCode !== 0) return;
|
|
4260
|
-
const packagePath = join(directory, "package.json");
|
|
4261
|
-
const checkoutPackage = looseObject({ scripts: record(string(), string()) }).parse(JSON.parse(await readFile(packagePath, "utf8")));
|
|
4262
|
-
checkoutPackage.scripts["db:migration"] = "drizzle-kit generate --custom";
|
|
4263
|
-
await writeFile(packagePath, `${JSON.stringify(checkoutPackage, null, 2)}\n`);
|
|
4264
4210
|
const response = await fetch(new URL("/api/slates", env.CTX_PLATFORM_URL), {
|
|
4265
4211
|
body: JSON.stringify(input),
|
|
4266
4212
|
headers: {
|
|
@@ -4297,11 +4243,11 @@ Start locally:
|
|
|
4297
4243
|
pnpm dev
|
|
4298
4244
|
Open the local URL printed by the development server.
|
|
4299
4245
|
|
|
4300
|
-
Deploy
|
|
4301
|
-
git add .
|
|
4302
|
-
git commit
|
|
4246
|
+
Deploy the committed starter:
|
|
4303
4247
|
git push -u origin main
|
|
4304
4248
|
|
|
4249
|
+
Commit your own changes before subsequent pushes.
|
|
4250
|
+
|
|
4305
4251
|
See README.md for the development and connection workflow.
|
|
4306
4252
|
`);
|
|
4307
4253
|
});
|
|
@@ -4313,36 +4259,37 @@ program.command("login").description("Sign in by approving a browser code and co
|
|
|
4313
4259
|
program.command("git-credential <operation>").description("Git credential helper using the saved login; invoked automatically by Git").hook("preAction", async (command) => {
|
|
4314
4260
|
if (command.args[0] === "get") await requireLogin(command);
|
|
4315
4261
|
}).action(gitCredential);
|
|
4316
|
-
program.command("whoami").description("Show your ContextLayer user ID verified by the auth server").action(async (_options, command) => {
|
|
4317
|
-
|
|
4318
|
-
});
|
|
4319
|
-
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) => {
|
|
4320
|
-
await joinSlate(union([
|
|
4321
|
-
literal("local"),
|
|
4322
|
-
uuid(),
|
|
4323
|
-
hostname()
|
|
4324
|
-
]).parse(target));
|
|
4325
|
-
});
|
|
4326
|
-
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) => {
|
|
4327
|
-
if (actionCommand !== command || command.args[0] !== "local") await requireLogin(actionCommand);
|
|
4328
|
-
}).action(async (target, operation) => {
|
|
4329
|
-
if (!target || !operation) connections.error("Expected: ctx connections <target> list");
|
|
4330
|
-
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}`);
|
|
4331
4265
|
});
|
|
4332
|
-
|
|
4333
|
-
|
|
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);
|
|
4334
4269
|
});
|
|
4335
|
-
|
|
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) => {
|
|
4336
4271
|
const options = ownerOptionsSchema.parse(command.optsWithGlobals());
|
|
4337
4272
|
await connectAccount(string().min(1).parse(toolkit), options.org);
|
|
4338
4273
|
});
|
|
4339
|
-
program.command("
|
|
4340
|
-
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({
|
|
4341
4276
|
connection_id: connectionId,
|
|
4277
|
+
operation,
|
|
4342
4278
|
slug,
|
|
4343
4279
|
target
|
|
4344
4280
|
});
|
|
4345
|
-
|
|
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
|
+
}
|
|
4346
4293
|
});
|
|
4347
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) => {
|
|
4348
4295
|
const input = object({
|
|
@@ -4361,6 +4308,15 @@ secrets.command("set").argument("<name>", "Secret name: uppercase letters, digit
|
|
|
4361
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) => {
|
|
4362
4309
|
await dropSecret(secretNameSchema.parse(name), secretOptionsSchema.parse(command.optsWithGlobals()).org);
|
|
4363
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
|
+
});
|
|
4364
4320
|
await program.parseAsync();
|
|
4365
4321
|
//#endregion
|
|
4366
4322
|
export {};
|