@usecontextlayer/cli 0.12.0 → 0.13.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/dist/cli.mjs CHANGED
@@ -1,12 +1,17 @@
1
1
  #!/usr/bin/env node
2
- import { a as env, c as hostname, d as url, f as uuid, i as whoami, l as object, n as getAccessToken, o as _enum, p as execa, r as login, s as array, t as getLocalAppId, u as string } from "./app-BqaczjqV.mjs";
3
- import { cp, readFile } from "node:fs/promises";
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";
3
+ import { cp, readFile, writeFile } from "node:fs/promises";
4
+ import path, { join } from "node:path";
4
5
  import { EventEmitter } from "node:events";
5
6
  import childProcess from "node:child_process";
6
- import path from "node:path";
7
7
  import fs from "node:fs";
8
- import process$1 from "node:process";
9
- import { stripVTControlCharacters } from "node:util";
8
+ import process$1, { stdin, stdout } from "node:process";
9
+ import { stripVTControlCharacters, styleText } from "node:util";
10
+ import { fileURLToPath } from "node:url";
11
+ import l__default, { createInterface } from "node:readline";
12
+ //#region \0rolldown/runtime.js
13
+ var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
14
+ //#endregion
10
15
  //#region ../../node_modules/.pnpm/commander@15.0.0/node_modules/commander/lib/error.js
11
16
  /**
12
17
  * CommanderError class
@@ -2962,6 +2967,43 @@ function useColor() {
2962
2967
  }
2963
2968
  new Command();
2964
2969
  //#endregion
2970
+ //#region agents.ts
2971
+ const platformInstructions = "You are a ContextLayer app agent. The user message is the task for this run. Work in the app directory and return the task's result.";
2972
+ async function runLocalAgent(name, prompt) {
2973
+ const instructions = await readFile(join("agents", name, "instructions.md"), "utf8");
2974
+ const { query } = await import("@anthropic-ai/claude-agent-sdk");
2975
+ const run = query({
2976
+ options: {
2977
+ cwd: process.cwd(),
2978
+ settingSources: [],
2979
+ systemPrompt: {
2980
+ append: `${platformInstructions}\n\n${instructions}`,
2981
+ preset: "claude_code",
2982
+ type: "preset"
2983
+ }
2984
+ },
2985
+ prompt
2986
+ });
2987
+ try {
2988
+ for await (const message of run) {
2989
+ if (message.type !== "result") continue;
2990
+ switch (message.subtype) {
2991
+ case "success":
2992
+ if (message.is_error) throw new Error(message.result);
2993
+ return message.result;
2994
+ case "error_during_execution":
2995
+ case "error_max_turns":
2996
+ case "error_max_budget_usd":
2997
+ case "error_max_structured_output_retries": throw new Error(message.errors.join("\n"));
2998
+ default: throw new Error(`Unhandled Claude result: ${JSON.stringify(message)}`);
2999
+ }
3000
+ }
3001
+ throw new Error("Claude ended without a result");
3002
+ } finally {
3003
+ run.close();
3004
+ }
3005
+ }
3006
+ //#endregion
2965
3007
  //#region connections.ts
2966
3008
  async function resolveAppTarget(target) {
2967
3009
  if (target !== "local") return target;
@@ -3045,12 +3087,820 @@ async function listConnections() {
3045
3087
  console.table(connections);
3046
3088
  }
3047
3089
  //#endregion
3090
+ //#region git-credential.ts
3091
+ async function setupGit(cli) {
3092
+ const key = `credential.${new URL("/git", env.CTX_PLATFORM_URL).href}.helper`;
3093
+ const command = [
3094
+ process.execPath,
3095
+ fileURLToPath(cli),
3096
+ "git-credential"
3097
+ ].map((argument) => `'${argument.replaceAll("'", "'\\''")}'`).join(" ");
3098
+ await execa("git", [
3099
+ "config",
3100
+ "--global",
3101
+ "--replace-all",
3102
+ key,
3103
+ ""
3104
+ ]);
3105
+ await execa("git", [
3106
+ "config",
3107
+ "--global",
3108
+ "--add",
3109
+ key,
3110
+ `!${command}`
3111
+ ]);
3112
+ }
3113
+ async function gitCredential(operation) {
3114
+ if (operation === "capability") {
3115
+ process.stdout.write("version 0\ncapability authtype\n");
3116
+ return;
3117
+ }
3118
+ if (operation !== "get") return;
3119
+ const attributes = new URLSearchParams();
3120
+ const lines = createInterface({ input: process.stdin });
3121
+ for await (const line of lines) {
3122
+ if (line === "") break;
3123
+ const separator = line.indexOf("=");
3124
+ attributes.append(line.slice(0, separator), line.slice(separator + 1));
3125
+ }
3126
+ literal("authtype").parse(attributes.getAll("capability[]").find((c) => c === "authtype"));
3127
+ process.stdout.write(`capability[]=authtype\nauthtype=Bearer\ncredential=${await getAccessToken()}\n\n`);
3128
+ }
3129
+ //#endregion
3048
3130
  //#region package.json
3049
- var version = "0.12.0";
3131
+ var version = "0.13.0";
3132
+ //#endregion
3133
+ //#region ../../node_modules/.pnpm/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/utils.js
3134
+ const getCodePointsLength = (() => {
3135
+ const SURROGATE_PAIR_RE = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
3136
+ return (input) => {
3137
+ let surrogatePairsNr = 0;
3138
+ SURROGATE_PAIR_RE.lastIndex = 0;
3139
+ while (SURROGATE_PAIR_RE.test(input)) surrogatePairsNr += 1;
3140
+ return input.length - surrogatePairsNr;
3141
+ };
3142
+ })();
3143
+ const isFullWidth = (x) => {
3144
+ return x === 12288 || x >= 65281 && x <= 65376 || x >= 65504 && x <= 65510;
3145
+ };
3146
+ const isWideNotCJKTNotEmoji = (x) => {
3147
+ return x === 8987 || x === 9001 || x >= 12272 && x <= 12287 || x >= 12289 && x <= 12350 || x >= 12441 && x <= 12543 || x >= 12549 && x <= 12591 || x >= 12593 && x <= 12686 || x >= 12688 && x <= 12771 || x >= 12783 && x <= 12830 || x >= 12832 && x <= 12871 || x >= 12880 && x <= 19903 || x >= 65040 && x <= 65049 || x >= 65072 && x <= 65106 || x >= 65108 && x <= 65126 || x >= 65128 && x <= 65131 || x >= 127488 && x <= 127490 || x >= 127504 && x <= 127547 || x >= 127552 && x <= 127560 || x >= 131072 && x <= 196605 || x >= 196608 && x <= 262141;
3148
+ };
3149
+ //#endregion
3150
+ //#region ../../node_modules/.pnpm/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/index.js
3151
+ const ANSI_RE = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
3152
+ const CONTROL_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
3153
+ const CJKT_WIDE_RE = /(?:(?![\uFF61-\uFF9F\uFF00-\uFFEF])[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Tangut}]){1,1000}/uy;
3154
+ const TAB_RE = /\t{1,1000}/y;
3155
+ const EMOJI_RE = /[\u{1F1E6}-\u{1F1FF}]{2}|\u{1F3F4}[\u{E0061}-\u{E007A}]{2}[\u{E0030}-\u{E0039}\u{E0061}-\u{E007A}]{1,3}\u{E007F}|(?:\p{Emoji}\uFE0F\u20E3?|\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation})(?:\u200D(?:\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F\u20E3?))*/uy;
3156
+ const LATIN_RE = /(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y;
3157
+ const MODIFIER_RE = /\p{M}+/gu;
3158
+ const NO_TRUNCATION$1 = {
3159
+ limit: Infinity,
3160
+ ellipsis: ""
3161
+ };
3162
+ const getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {}) => {
3163
+ const LIMIT = truncationOptions.limit ?? Infinity;
3164
+ const ELLIPSIS = truncationOptions.ellipsis ?? "";
3165
+ const ELLIPSIS_WIDTH = truncationOptions?.ellipsisWidth ?? (ELLIPSIS ? getStringTruncatedWidth(ELLIPSIS, NO_TRUNCATION$1, widthOptions).width : 0);
3166
+ const ANSI_WIDTH = 0;
3167
+ const CONTROL_WIDTH = widthOptions.controlWidth ?? 0;
3168
+ const TAB_WIDTH = widthOptions.tabWidth ?? 8;
3169
+ const EMOJI_WIDTH = widthOptions.emojiWidth ?? 2;
3170
+ const FULL_WIDTH_WIDTH = 2;
3171
+ const REGULAR_WIDTH = widthOptions.regularWidth ?? 1;
3172
+ const WIDE_WIDTH = widthOptions.wideWidth ?? FULL_WIDTH_WIDTH;
3173
+ const PARSE_BLOCKS = [
3174
+ [LATIN_RE, REGULAR_WIDTH],
3175
+ [ANSI_RE, ANSI_WIDTH],
3176
+ [CONTROL_RE, CONTROL_WIDTH],
3177
+ [TAB_RE, TAB_WIDTH],
3178
+ [EMOJI_RE, EMOJI_WIDTH],
3179
+ [CJKT_WIDE_RE, WIDE_WIDTH]
3180
+ ];
3181
+ let indexPrev = 0;
3182
+ let index = 0;
3183
+ let length = input.length;
3184
+ let lengthExtra = 0;
3185
+ let truncationEnabled = false;
3186
+ let truncationIndex = length;
3187
+ let truncationLimit = Math.max(0, LIMIT - ELLIPSIS_WIDTH);
3188
+ let unmatchedStart = 0;
3189
+ let unmatchedEnd = 0;
3190
+ let width = 0;
3191
+ let widthExtra = 0;
3192
+ outer: while (true) {
3193
+ if (unmatchedEnd > unmatchedStart || index >= length && index > indexPrev) {
3194
+ const unmatched = input.slice(unmatchedStart, unmatchedEnd) || input.slice(indexPrev, index);
3195
+ lengthExtra = 0;
3196
+ for (const char of unmatched.replaceAll(MODIFIER_RE, "")) {
3197
+ const codePoint = char.codePointAt(0) || 0;
3198
+ if (isFullWidth(codePoint)) widthExtra = FULL_WIDTH_WIDTH;
3199
+ else if (isWideNotCJKTNotEmoji(codePoint)) widthExtra = WIDE_WIDTH;
3200
+ else widthExtra = REGULAR_WIDTH;
3201
+ if (width + widthExtra > truncationLimit) truncationIndex = Math.min(truncationIndex, Math.max(unmatchedStart, indexPrev) + lengthExtra);
3202
+ if (width + widthExtra > LIMIT) {
3203
+ truncationEnabled = true;
3204
+ break outer;
3205
+ }
3206
+ lengthExtra += char.length;
3207
+ width += widthExtra;
3208
+ }
3209
+ unmatchedStart = unmatchedEnd = 0;
3210
+ }
3211
+ if (index >= length) break outer;
3212
+ for (let i = 0, l = PARSE_BLOCKS.length; i < l; i++) {
3213
+ const [BLOCK_RE, BLOCK_WIDTH] = PARSE_BLOCKS[i];
3214
+ BLOCK_RE.lastIndex = index;
3215
+ if (BLOCK_RE.test(input)) {
3216
+ lengthExtra = BLOCK_RE === CJKT_WIDE_RE ? getCodePointsLength(input.slice(index, BLOCK_RE.lastIndex)) : BLOCK_RE === EMOJI_RE ? 1 : BLOCK_RE.lastIndex - index;
3217
+ widthExtra = lengthExtra * BLOCK_WIDTH;
3218
+ if (width + widthExtra > truncationLimit) truncationIndex = Math.min(truncationIndex, index + Math.floor((truncationLimit - width) / BLOCK_WIDTH));
3219
+ if (width + widthExtra > LIMIT) {
3220
+ truncationEnabled = true;
3221
+ break outer;
3222
+ }
3223
+ width += widthExtra;
3224
+ unmatchedStart = indexPrev;
3225
+ unmatchedEnd = index;
3226
+ index = indexPrev = BLOCK_RE.lastIndex;
3227
+ continue outer;
3228
+ }
3229
+ }
3230
+ index += 1;
3231
+ }
3232
+ return {
3233
+ width: truncationEnabled ? truncationLimit : width,
3234
+ index: truncationEnabled ? truncationIndex : length,
3235
+ truncated: truncationEnabled,
3236
+ ellipsed: truncationEnabled && LIMIT >= ELLIPSIS_WIDTH
3237
+ };
3238
+ };
3239
+ //#endregion
3240
+ //#region ../../node_modules/.pnpm/fast-string-width@3.0.2/node_modules/fast-string-width/dist/index.js
3241
+ const NO_TRUNCATION = {
3242
+ limit: Infinity,
3243
+ ellipsis: "",
3244
+ ellipsisWidth: 0
3245
+ };
3246
+ const fastStringWidth = (input, options = {}) => {
3247
+ return getStringTruncatedWidth(input, NO_TRUNCATION, options).width;
3248
+ };
3249
+ //#endregion
3250
+ //#region ../../node_modules/.pnpm/fast-wrap-ansi@0.2.2/node_modules/fast-wrap-ansi/lib/main.js
3251
+ const ESC = "\x1B";
3252
+ const CSI = "›";
3253
+ const END_CODE = 39;
3254
+ const ANSI_ESCAPE_BELL = "\x07";
3255
+ const ANSI_CSI = "[";
3256
+ const ANSI_OSC = "]";
3257
+ const ANSI_SGR_TERMINATOR = "m";
3258
+ const ANSI_ESCAPE_LINK = `${ANSI_OSC}8;;`;
3259
+ const GROUP_REGEX = new RegExp(`(?:\\${ANSI_CSI}(?<code>\\d+)m|\\${ANSI_ESCAPE_LINK}(?<uri>.*)${ANSI_ESCAPE_BELL})`, "y");
3260
+ const getClosingCode = (openingCode) => {
3261
+ if (openingCode >= 30 && openingCode <= 37) return 39;
3262
+ if (openingCode >= 90 && openingCode <= 97) return 39;
3263
+ if (openingCode >= 40 && openingCode <= 47) return 49;
3264
+ if (openingCode >= 100 && openingCode <= 107) return 49;
3265
+ if (openingCode === 1 || openingCode === 2) return 22;
3266
+ if (openingCode === 3) return 23;
3267
+ if (openingCode === 4) return 24;
3268
+ if (openingCode === 7) return 27;
3269
+ if (openingCode === 8) return 28;
3270
+ if (openingCode === 9) return 29;
3271
+ if (openingCode === 0) return 0;
3272
+ };
3273
+ const wrapAnsiCode = (code) => `${ESC}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
3274
+ const wrapAnsiHyperlink = (url) => `${ESC}${ANSI_ESCAPE_LINK}${url}${ANSI_ESCAPE_BELL}`;
3275
+ const wrapWord = (rows, word, columns) => {
3276
+ const characters = word[Symbol.iterator]();
3277
+ let isInsideEscape = false;
3278
+ let isInsideLinkEscape = false;
3279
+ let lastRow = rows.at(-1);
3280
+ let visible = lastRow === void 0 ? 0 : fastStringWidth(lastRow);
3281
+ let currentCharacter = characters.next();
3282
+ let nextCharacter = characters.next();
3283
+ let rawCharacterIndex = 0;
3284
+ while (!currentCharacter.done) {
3285
+ const character = currentCharacter.value;
3286
+ const characterLength = fastStringWidth(character);
3287
+ if (visible + characterLength <= columns) rows[rows.length - 1] += character;
3288
+ else {
3289
+ rows.push(character);
3290
+ visible = 0;
3291
+ }
3292
+ if (character === ESC || character === CSI) {
3293
+ isInsideEscape = true;
3294
+ isInsideLinkEscape = word.startsWith(ANSI_ESCAPE_LINK, rawCharacterIndex + 1);
3295
+ }
3296
+ if (isInsideEscape) {
3297
+ if (isInsideLinkEscape) {
3298
+ if (character === ANSI_ESCAPE_BELL) {
3299
+ isInsideEscape = false;
3300
+ isInsideLinkEscape = false;
3301
+ }
3302
+ } else if (character === ANSI_SGR_TERMINATOR) isInsideEscape = false;
3303
+ } else {
3304
+ visible += characterLength;
3305
+ if (visible === columns && !nextCharacter.done) {
3306
+ rows.push("");
3307
+ visible = 0;
3308
+ }
3309
+ }
3310
+ currentCharacter = nextCharacter;
3311
+ nextCharacter = characters.next();
3312
+ rawCharacterIndex += character.length;
3313
+ }
3314
+ lastRow = rows.at(-1);
3315
+ if (!visible && lastRow !== void 0 && lastRow.length && rows.length > 1) rows[rows.length - 2] += rows.pop();
3316
+ };
3317
+ const stringVisibleTrimSpacesRight = (string) => {
3318
+ const words = string.split(" ");
3319
+ let last = words.length;
3320
+ while (last) {
3321
+ if (fastStringWidth(words[last - 1])) break;
3322
+ last--;
3323
+ }
3324
+ if (last === words.length) return string;
3325
+ return words.slice(0, last).join(" ") + words.slice(last).join("");
3326
+ };
3327
+ const exec = (string, columns, options = {}) => {
3328
+ if (options.trim !== false && string.trim() === "") return "";
3329
+ let returnValue = "";
3330
+ let escapeCode;
3331
+ let escapeUrl;
3332
+ const words = string.split(" ");
3333
+ let rows = [""];
3334
+ let rowLength = 0;
3335
+ for (let index = 0; index < words.length; index++) {
3336
+ const word = words[index];
3337
+ if (options.trim !== false) {
3338
+ const row = rows.at(-1) ?? "";
3339
+ const trimmed = row.trimStart();
3340
+ if (row.length !== trimmed.length) {
3341
+ rows[rows.length - 1] = trimmed;
3342
+ rowLength = fastStringWidth(trimmed);
3343
+ }
3344
+ }
3345
+ if (index !== 0) {
3346
+ if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
3347
+ rows.push("");
3348
+ rowLength = 0;
3349
+ }
3350
+ if (rowLength || options.trim === false) {
3351
+ rows[rows.length - 1] += " ";
3352
+ rowLength++;
3353
+ }
3354
+ }
3355
+ const wordLength = fastStringWidth(word);
3356
+ if (options.hard && wordLength > columns) {
3357
+ const remainingColumns = columns - rowLength;
3358
+ const breaksStartingThisLine = 1 + Math.floor((wordLength - remainingColumns - 1) / columns);
3359
+ if (Math.floor((wordLength - 1) / columns) < breaksStartingThisLine) rows.push("");
3360
+ wrapWord(rows, word, columns);
3361
+ rowLength = fastStringWidth(rows.at(-1) ?? "");
3362
+ continue;
3363
+ }
3364
+ if (rowLength + wordLength > columns && rowLength && wordLength) {
3365
+ if (options.wordWrap === false && rowLength < columns) {
3366
+ wrapWord(rows, word, columns);
3367
+ rowLength = fastStringWidth(rows.at(-1) ?? "");
3368
+ continue;
3369
+ }
3370
+ rows.push("");
3371
+ rowLength = 0;
3372
+ }
3373
+ if (rowLength + wordLength > columns && options.wordWrap === false) {
3374
+ wrapWord(rows, word, columns);
3375
+ rowLength = fastStringWidth(rows.at(-1) ?? "");
3376
+ continue;
3377
+ }
3378
+ rows[rows.length - 1] += word;
3379
+ rowLength += wordLength;
3380
+ }
3381
+ if (options.trim !== false) rows = rows.map((row) => stringVisibleTrimSpacesRight(row));
3382
+ const preString = rows.join("\n");
3383
+ let inSurrogate = false;
3384
+ for (let i = 0; i < preString.length; i++) {
3385
+ const character = preString[i];
3386
+ returnValue += character;
3387
+ if (!inSurrogate) {
3388
+ inSurrogate = character >= "\ud800" && character <= "\udbff";
3389
+ if (inSurrogate) continue;
3390
+ } else inSurrogate = false;
3391
+ if (character === ESC || character === CSI) {
3392
+ GROUP_REGEX.lastIndex = i + 1;
3393
+ const groups = GROUP_REGEX.exec(preString)?.groups;
3394
+ if (groups?.code !== void 0) {
3395
+ const code = Number.parseFloat(groups.code);
3396
+ escapeCode = code === END_CODE ? void 0 : code;
3397
+ } else if (groups?.uri !== void 0) escapeUrl = groups.uri.length === 0 ? void 0 : groups.uri;
3398
+ }
3399
+ if (preString[i + 1] === "\n") {
3400
+ if (escapeUrl) returnValue += wrapAnsiHyperlink("");
3401
+ const closingCode = escapeCode ? getClosingCode(escapeCode) : void 0;
3402
+ if (escapeCode && closingCode) returnValue += wrapAnsiCode(closingCode);
3403
+ } else if (character === "\n") {
3404
+ if (escapeCode && getClosingCode(escapeCode)) returnValue += wrapAnsiCode(escapeCode);
3405
+ if (escapeUrl) returnValue += wrapAnsiHyperlink(escapeUrl);
3406
+ }
3407
+ }
3408
+ return returnValue;
3409
+ };
3410
+ const CRLF_OR_LF = /\r?\n/;
3411
+ function wrapAnsi(string, columns, options) {
3412
+ return String(string).normalize().split(CRLF_OR_LF).map((line) => exec(line, columns, options)).join("\n");
3413
+ }
3414
+ //#endregion
3415
+ //#region ../../node_modules/.pnpm/@clack+core@1.5.1/node_modules/@clack/core/dist/index.mjs
3416
+ var import_src = (/* @__PURE__ */ __commonJSMin(((exports, module) => {
3417
+ const ESC = "\x1B";
3418
+ const CSI = `${ESC}[`;
3419
+ const beep = "\x07";
3420
+ const cursor = {
3421
+ to(x, y) {
3422
+ if (!y) return `${CSI}${x + 1}G`;
3423
+ return `${CSI}${y + 1};${x + 1}H`;
3424
+ },
3425
+ move(x, y) {
3426
+ let ret = "";
3427
+ if (x < 0) ret += `${CSI}${-x}D`;
3428
+ else if (x > 0) ret += `${CSI}${x}C`;
3429
+ if (y < 0) ret += `${CSI}${-y}A`;
3430
+ else if (y > 0) ret += `${CSI}${y}B`;
3431
+ return ret;
3432
+ },
3433
+ up: (count = 1) => `${CSI}${count}A`,
3434
+ down: (count = 1) => `${CSI}${count}B`,
3435
+ forward: (count = 1) => `${CSI}${count}C`,
3436
+ backward: (count = 1) => `${CSI}${count}D`,
3437
+ nextLine: (count = 1) => `${CSI}E`.repeat(count),
3438
+ prevLine: (count = 1) => `${CSI}F`.repeat(count),
3439
+ left: `${CSI}G`,
3440
+ hide: `${CSI}?25l`,
3441
+ show: `${CSI}?25h`,
3442
+ save: `${ESC}7`,
3443
+ restore: `${ESC}8`
3444
+ };
3445
+ module.exports = {
3446
+ cursor,
3447
+ scroll: {
3448
+ up: (count = 1) => `${CSI}S`.repeat(count),
3449
+ down: (count = 1) => `${CSI}T`.repeat(count)
3450
+ },
3451
+ erase: {
3452
+ screen: `${CSI}2J`,
3453
+ up: (count = 1) => `${CSI}1J`.repeat(count),
3454
+ down: (count = 1) => `${CSI}J`.repeat(count),
3455
+ line: `${CSI}2K`,
3456
+ lineEnd: `${CSI}K`,
3457
+ lineStart: `${CSI}1K`,
3458
+ lines(count) {
3459
+ let clear = "";
3460
+ for (let i = 0; i < count; i++) clear += this.line + (i < count - 1 ? cursor.up() : "");
3461
+ if (count) clear += cursor.left;
3462
+ return clear;
3463
+ }
3464
+ },
3465
+ beep
3466
+ };
3467
+ })))();
3468
+ const settings = {
3469
+ actions: /* @__PURE__ */ new Set([
3470
+ "up",
3471
+ "down",
3472
+ "left",
3473
+ "right",
3474
+ "space",
3475
+ "enter",
3476
+ "cancel"
3477
+ ]),
3478
+ aliases: /* @__PURE__ */ new Map([
3479
+ ["k", "up"],
3480
+ ["j", "down"],
3481
+ ["h", "left"],
3482
+ ["l", "right"],
3483
+ ["", "cancel"],
3484
+ ["escape", "cancel"]
3485
+ ]),
3486
+ messages: {
3487
+ cancel: "Canceled",
3488
+ error: "Something went wrong"
3489
+ },
3490
+ withGuide: true,
3491
+ accessible: void 0,
3492
+ date: {
3493
+ monthNames: [...[
3494
+ "January",
3495
+ "February",
3496
+ "March",
3497
+ "April",
3498
+ "May",
3499
+ "June",
3500
+ "July",
3501
+ "August",
3502
+ "September",
3503
+ "October",
3504
+ "November",
3505
+ "December"
3506
+ ]],
3507
+ messages: {
3508
+ required: "Please enter a valid date",
3509
+ invalidMonth: "There are only 12 months in a year",
3510
+ invalidDay: (n, e) => `There are only ${n} days in ${e}`,
3511
+ afterMin: (n) => `Date must be on or after ${n.toISOString().slice(0, 10)}`,
3512
+ beforeMax: (n) => `Date must be on or before ${n.toISOString().slice(0, 10)}`
3513
+ }
3514
+ }
3515
+ };
3516
+ function isAccessible(n) {
3517
+ if (n !== void 0) return n;
3518
+ if (settings.accessible !== void 0) return settings.accessible;
3519
+ const e = process.env.ACCESSIBLE;
3520
+ return e !== void 0 && e !== "" && e !== "0" && e !== "false";
3521
+ }
3522
+ function isActionKey(n, e) {
3523
+ if (typeof n == "string") return settings.aliases.get(n) === e;
3524
+ for (const s of n) if (s !== void 0 && isActionKey(s, e)) return true;
3525
+ return false;
3526
+ }
3527
+ function diffLines(i, s) {
3528
+ if (i === s) return;
3529
+ const e = i.split(`
3530
+ `), t = s.split(`
3531
+ `), r = Math.max(e.length, t.length), f = [];
3532
+ for (let n = 0; n < r; n++) e[n] !== t[n] && f.push(n);
3533
+ return {
3534
+ lines: f,
3535
+ numLinesBefore: e.length,
3536
+ numLinesAfter: t.length,
3537
+ numLines: r
3538
+ };
3539
+ }
3540
+ globalThis.process.platform.startsWith("win");
3541
+ const CANCEL_SYMBOL = Symbol("clack:cancel");
3542
+ function isCancel(e) {
3543
+ return e === CANCEL_SYMBOL;
3544
+ }
3545
+ function setRawMode(e, r) {
3546
+ const o = e;
3547
+ o.isTTY && o.setRawMode(r);
3548
+ }
3549
+ const getRows = (e) => "rows" in e && typeof e.rows == "number" ? e.rows : 20;
3550
+ function runValidation(e, a) {
3551
+ if ("~standard" in e) {
3552
+ const n = e["~standard"].validate(a);
3553
+ return n instanceof Promise ? n.then((r) => r.issues?.at(0)?.message) : n.issues?.at(0)?.message;
3554
+ }
3555
+ return e(a);
3556
+ }
3557
+ var y = class {
3558
+ input;
3559
+ output;
3560
+ _abortSignal;
3561
+ rl;
3562
+ opts;
3563
+ _render;
3564
+ _track = false;
3565
+ _prevFrame = "";
3566
+ _subscribers = /* @__PURE__ */ new Map();
3567
+ _cursor = 0;
3568
+ state = "initial";
3569
+ error = "";
3570
+ value;
3571
+ userInput = "";
3572
+ /**
3573
+ * Whether accessible (static, screen-reader friendly) output is enabled for
3574
+ * this prompt, resolved from the `accessible` option, the global setting,
3575
+ * and the `ACCESSIBLE` env var.
3576
+ */
3577
+ get accessible() {
3578
+ return isAccessible(this.opts.accessible);
3579
+ }
3580
+ constructor(t, e = true) {
3581
+ const { input: i = stdin, output: s = stdout, render: r, signal: n, ...o } = t;
3582
+ this.opts = o, this.onKeypress = this.onKeypress.bind(this), this.close = this.close.bind(this), this.render = this.render.bind(this), this._render = r.bind(this), this._track = e, this._abortSignal = n, this.input = i, this.output = s;
3583
+ }
3584
+ /**
3585
+ * Unsubscribe all listeners
3586
+ */
3587
+ unsubscribe() {
3588
+ this._subscribers.clear();
3589
+ }
3590
+ /**
3591
+ * Set a subscriber with opts
3592
+ * @param event - The event name
3593
+ */
3594
+ setSubscriber(t, e) {
3595
+ const i = this._subscribers.get(t) ?? [];
3596
+ i.push(e), this._subscribers.set(t, i);
3597
+ }
3598
+ /**
3599
+ * Subscribe to an event
3600
+ * @param event - The event name
3601
+ * @param cb - The callback
3602
+ */
3603
+ on(t, e) {
3604
+ this.setSubscriber(t, { cb: e });
3605
+ }
3606
+ /**
3607
+ * Subscribe to an event once
3608
+ * @param event - The event name
3609
+ * @param cb - The callback
3610
+ */
3611
+ once(t, e) {
3612
+ this.setSubscriber(t, {
3613
+ cb: e,
3614
+ once: true
3615
+ });
3616
+ }
3617
+ /**
3618
+ * Emit an event with data
3619
+ * @param event - The event name
3620
+ * @param data - The data to pass to the callback
3621
+ */
3622
+ emit(t, ...e) {
3623
+ const i = this._subscribers.get(t) ?? [], s = [];
3624
+ for (const r of i) r.cb(...e), r.once && s.push(() => i.splice(i.indexOf(r), 1));
3625
+ for (const r of s) r();
3626
+ }
3627
+ prompt() {
3628
+ return new Promise((t) => {
3629
+ if (this._abortSignal) {
3630
+ if (this._abortSignal.aborted) return this.state = "cancel", this.close(), t(CANCEL_SYMBOL);
3631
+ this._abortSignal.addEventListener("abort", () => {
3632
+ this.state = "cancel", this.close();
3633
+ }, { once: true });
3634
+ }
3635
+ this.rl = l__default.createInterface({
3636
+ input: this.input,
3637
+ tabSize: 2,
3638
+ prompt: "",
3639
+ escapeCodeTimeout: 50,
3640
+ terminal: true
3641
+ }), this.rl.prompt(), this.opts.initialUserInput !== void 0 && this._setUserInput(this.opts.initialUserInput, true), this.input.on("keypress", this.onKeypress), setRawMode(this.input, true), this.output.on("resize", this.render), this.render(), this.once("submit", () => {
3642
+ this.output.write(import_src.cursor.show), this.output.off("resize", this.render), setRawMode(this.input, false), t(this.value);
3643
+ }), this.once("cancel", () => {
3644
+ this.output.write(import_src.cursor.show), this.output.off("resize", this.render), setRawMode(this.input, false), t(CANCEL_SYMBOL);
3645
+ });
3646
+ });
3647
+ }
3648
+ _isActionKey(t, e) {
3649
+ return t === " ";
3650
+ }
3651
+ _shouldSubmit(t, e) {
3652
+ return true;
3653
+ }
3654
+ _setValue(t) {
3655
+ this.value = t, this.emit("value", this.value);
3656
+ }
3657
+ _setUserInput(t, e) {
3658
+ this.userInput = t ?? "", this.emit("userInput", this.userInput), e && this._track && this.rl && (this.rl.write(this.userInput), this._cursor = this.rl.cursor);
3659
+ }
3660
+ _clearUserInput() {
3661
+ this.rl?.write(null, {
3662
+ ctrl: true,
3663
+ name: "u"
3664
+ }), this._setUserInput("");
3665
+ }
3666
+ async onKeypress(t, e) {
3667
+ if (this.state !== "validating") {
3668
+ if (this._track && e.name !== "return" && (e.name && this._isActionKey(t, e) && this.rl?.write(null, {
3669
+ ctrl: true,
3670
+ name: "h"
3671
+ }), this._cursor = this.rl?.cursor ?? 0, this._setUserInput(this.rl?.line)), this.state === "error" && (this.state = "active"), e?.name && (!this._track && settings.aliases.has(e.name) && this.emit("cursor", settings.aliases.get(e.name)), settings.actions.has(e.name) && this.emit("cursor", e.name)), t && (t.toLowerCase() === "y" || t.toLowerCase() === "n") && this.emit("confirm", t.toLowerCase() === "y"), this.emit("key", t, e), e?.name === "return" && this._shouldSubmit(t, e)) {
3672
+ if (this.opts.validate) {
3673
+ const i = runValidation(this.opts.validate, this.value);
3674
+ let s;
3675
+ i instanceof Promise ? (this.state = "validating", this.render(), s = await i) : s = i, s && (this.error = s instanceof Error ? s.message : s, this.state = "error", this.rl?.write(this.userInput));
3676
+ }
3677
+ this.state !== "error" && (this.state = "submit");
3678
+ }
3679
+ isActionKey([
3680
+ t,
3681
+ e?.name,
3682
+ e?.sequence
3683
+ ], "cancel") && (this.state = "cancel"), (this.state === "submit" || this.state === "cancel") && this.emit("finalize"), this.render(), (this.state === "submit" || this.state === "cancel") && this.close();
3684
+ }
3685
+ }
3686
+ close() {
3687
+ this.input.unpipe(), this.input.removeListener("keypress", this.onKeypress), this.output.write(`
3688
+ `), setRawMode(this.input, false), this.rl?.close(), this.rl = void 0, this.emit(`${this.state}`, this.value), this.unsubscribe();
3689
+ }
3690
+ restoreCursor() {
3691
+ const t = wrapAnsi(this._prevFrame, process.stdout.columns, {
3692
+ hard: true,
3693
+ trim: false
3694
+ }).split(`
3695
+ `).length - 1;
3696
+ this.output.write(import_src.cursor.move(-999, t * -1));
3697
+ }
3698
+ render() {
3699
+ const t = wrapAnsi(this._render(this) ?? "", process.stdout.columns, {
3700
+ hard: true,
3701
+ trim: false
3702
+ });
3703
+ if (t !== this._prevFrame) {
3704
+ if (this.state === "initial") this.output.write(import_src.cursor.hide);
3705
+ else {
3706
+ const e = diffLines(this._prevFrame, t), i = getRows(this.output);
3707
+ if (this.restoreCursor(), e) {
3708
+ const s = Math.max(0, e.numLinesAfter - i), r = Math.max(0, e.numLinesBefore - i);
3709
+ let n = e.lines.find((o) => o >= s);
3710
+ if (n === void 0) {
3711
+ this._prevFrame = t;
3712
+ return;
3713
+ }
3714
+ if (e.lines.length === 1) {
3715
+ this.output.write(import_src.cursor.move(0, n - r)), this.output.write(import_src.erase.lines(1));
3716
+ const o = t.split(`
3717
+ `);
3718
+ this.output.write(o[n]), this._prevFrame = t, this.output.write(import_src.cursor.move(0, o.length - n - 1));
3719
+ return;
3720
+ } else if (e.lines.length > 1) {
3721
+ if (s < r) n = s;
3722
+ else {
3723
+ const h = n - r;
3724
+ h > 0 && this.output.write(import_src.cursor.move(0, h));
3725
+ }
3726
+ this.output.write(import_src.erase.down());
3727
+ const f = t.split(`
3728
+ `).slice(n);
3729
+ this.output.write(f.join(`
3730
+ `)), this._prevFrame = t;
3731
+ return;
3732
+ }
3733
+ }
3734
+ this.output.write(import_src.erase.down());
3735
+ }
3736
+ this.output.write(t), this.state === "initial" && (this.state = "active"), this._prevFrame = t;
3737
+ }
3738
+ }
3739
+ };
3740
+ let u$1 = class u extends y {
3741
+ _mask = "•";
3742
+ get cursor() {
3743
+ return this._cursor;
3744
+ }
3745
+ get masked() {
3746
+ return this.userInput.replaceAll(/./g, this._mask);
3747
+ }
3748
+ get userInputWithCursor() {
3749
+ if (this.state === "submit" || this.state === "cancel") return this.masked;
3750
+ const t = this.userInput;
3751
+ if (this.cursor >= t.length) return `${this.masked}${styleText(["inverse", "hidden"], "_")}`;
3752
+ const s = this.masked, r = s.slice(0, this.cursor), i = s.slice(this.cursor, this.cursor + 1), o = s.slice(this.cursor + 1);
3753
+ return `${r}${styleText("inverse", i)}${o}`;
3754
+ }
3755
+ clear() {
3756
+ this._clearUserInput();
3757
+ }
3758
+ constructor({ mask: t, ...s }) {
3759
+ super(s), this._mask = t ?? "•", this.on("userInput", (r) => {
3760
+ this._setValue(r);
3761
+ }), this.on("finalize", () => {
3762
+ this.value === void 0 && (this.value = "");
3763
+ });
3764
+ }
3765
+ };
3766
+ //#endregion
3767
+ //#region ../../node_modules/.pnpm/@clack+prompts@1.8.1/node_modules/@clack/prompts/dist/index.mjs
3768
+ function isUnicodeSupported() {
3769
+ if (process$1.platform !== "win32") return process$1.env.TERM !== "linux";
3770
+ return Boolean(process$1.env.CI) || Boolean(process$1.env.WT_SESSION) || Boolean(process$1.env.TERMINUS_SUBLIME) || process$1.env.ConEmuTask === "{cmd::Cmder}" || process$1.env.TERM_PROGRAM === "Terminus-Sublime" || process$1.env.TERM_PROGRAM === "vscode" || process$1.env.TERM === "xterm-256color" || process$1.env.TERM === "alacritty" || process$1.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
3771
+ }
3772
+ const unicode = isUnicodeSupported();
3773
+ const unicodeOr = (o, e) => unicode ? o : e;
3774
+ const S_STEP_ACTIVE = unicodeOr("◆", "*");
3775
+ const S_STEP_CANCEL = unicodeOr("■", "x");
3776
+ const S_STEP_ERROR = unicodeOr("▲", "x");
3777
+ const S_STEP_SUBMIT = unicodeOr("◇", "o");
3778
+ const S_BAR = unicodeOr("│", "|");
3779
+ const S_BAR_END = unicodeOr("└", "—");
3780
+ const S_PASSWORD_MASK = unicodeOr("▪", "•");
3781
+ const symbol = (o) => {
3782
+ switch (o) {
3783
+ case "initial":
3784
+ case "active": return styleText("cyan", S_STEP_ACTIVE);
3785
+ case "cancel": return styleText("red", S_STEP_CANCEL);
3786
+ case "error": return styleText("yellow", S_STEP_ERROR);
3787
+ case "submit": return styleText("green", S_STEP_SUBMIT);
3788
+ case "validating": return styleText("dim", S_STEP_ACTIVE);
3789
+ }
3790
+ };
3791
+ `${styleText("dim", "↑/↓")}`, `${styleText("dim", "Space:")}`, `${styleText("dim", "Enter:")}`;
3792
+ const password = (e) => new u$1({
3793
+ validate: e.validate,
3794
+ mask: e.mask ?? S_PASSWORD_MASK,
3795
+ signal: e.signal,
3796
+ input: e.input,
3797
+ output: e.output,
3798
+ render() {
3799
+ const r = e.withGuide ?? settings.withGuide, o = `${r ? `${styleText("gray", S_BAR)}
3800
+ ` : ""}${symbol(this.state)} ${e.message}
3801
+ `, m = this.userInputWithCursor, i = this.masked;
3802
+ switch (this.state) {
3803
+ case "error": {
3804
+ const s = r ? `${styleText("yellow", S_BAR)} ` : "", n = r ? `${styleText("yellow", S_BAR_END)} ` : "", d = i ?? "";
3805
+ return e.clearOnError && this.clear(), `${o.trim()}
3806
+ ${s}${d}
3807
+ ${n}${styleText("yellow", this.error)}
3808
+ `;
3809
+ }
3810
+ case "submit": return `${o}${r ? `${styleText("gray", S_BAR)} ` : ""}${i ? styleText("dim", i) : ""}`;
3811
+ case "cancel": return `${o}${r ? `${styleText("gray", S_BAR)} ` : ""}${i ? styleText(["strikethrough", "dim"], i) : ""}${i && r ? `
3812
+ ${styleText("gray", S_BAR)}` : ""}`;
3813
+ default: return `${o}${r ? `${styleText("cyan", S_BAR)} ` : ""}${m}
3814
+ ${r ? styleText("cyan", S_BAR_END) : ""}
3815
+ `;
3816
+ }
3817
+ }
3818
+ }).prompt();
3819
+ `${styleText("dim", "↑/↓")}`, `${styleText("dim", "Enter:")}`;
3820
+ `${styleText("gray", S_BAR)}`;
3821
+ //#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)
3827
+ });
3828
+ const valueSchema = string().min(1);
3829
+ const confirmationSchema = object({
3830
+ name: secretNameSchema,
3831
+ owner: object({
3832
+ id: string().min(1),
3833
+ type: _enum(["organization", "user"])
3834
+ })
3835
+ });
3836
+ 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);
3856
+ }
3857
+ async function setSecret(name, options) {
3858
+ const headers = { authorization: `Bearer ${await getAccessToken()}` };
3859
+ const url = await resolveSecretUrl(name, options.org, headers);
3860
+ let value;
3861
+ if (options.stdin) {
3862
+ process.stdin.setEncoding("utf8");
3863
+ value = "";
3864
+ for await (const chunk of process.stdin) value += chunk;
3865
+ } else {
3866
+ if (!process.stdin.isTTY) throw new Error("Use --stdin to read a secret without a terminal");
3867
+ const entered = await password({
3868
+ message: `Value for ${name}`,
3869
+ output: process.stderr,
3870
+ validate: valueSchema
3871
+ });
3872
+ if (isCancel(entered)) {
3873
+ process.exitCode = 130;
3874
+ return;
3875
+ }
3876
+ value = entered;
3877
+ }
3878
+ const response = await fetch(url, {
3879
+ body: JSON.stringify({ value: valueSchema.parse(value) }),
3880
+ headers: {
3881
+ ...headers,
3882
+ "content-type": "application/json"
3883
+ },
3884
+ method: "PUT"
3885
+ });
3886
+ if (!response.ok) throw new Error(`Secret save failed: HTTP ${response.status}`);
3887
+ console.log(JSON.stringify(confirmationSchema.parse(await response.json())));
3888
+ }
3889
+ async function dropSecret(name, org) {
3890
+ const headers = { authorization: `Bearer ${await getAccessToken()}` };
3891
+ const response = await fetch(await resolveSecretUrl(name, org, headers), {
3892
+ headers,
3893
+ method: "DELETE"
3894
+ });
3895
+ if (!response.ok) throw new Error(`Secret drop failed: HTTP ${response.status}`);
3896
+ console.log(JSON.stringify(confirmationSchema.parse(await response.json())));
3897
+ }
3050
3898
  //#endregion
3051
3899
  //#region cli.ts
3052
3900
  const program = new Command().name("ctx").description("ContextLayer CLI").version(version);
3053
- program.command("init <directory>").description("Create a Cloudflare React Router project with local Composio tools, register an app, and set its immutable Git remote").action(async (directory) => {
3901
+ program.command("init <directory>").description("Create a Cloudflare React Router project with Tailwind and shadcn Base UI, register an app owned by you or an organization (ctx login), and set its immutable Git remote").option("--org <slug>", "Create the app under an organization you belong to").action(async (directory, options) => {
3902
+ const input = object({ organization_slug: string().min(1).optional() }).parse({ organization_slug: options.org });
3903
+ const accessToken = await getAccessToken();
3054
3904
  const result = await execa("pnpm", [
3055
3905
  "create",
3056
3906
  "cloudflare@latest",
@@ -3067,6 +3917,27 @@ program.command("init <directory>").description("Create a Cloudflare React Route
3067
3917
  });
3068
3918
  process.exitCode = result.exitCode;
3069
3919
  if (result.exitCode !== 0) return;
3920
+ const tsconfigPath = join(directory, "tsconfig.json");
3921
+ const tsconfig = looseObject({ compilerOptions: record(string(), unknown()) }).parse(JSON.parse(await readFile(tsconfigPath, "utf8")));
3922
+ tsconfig.compilerOptions.paths = { "~/*": ["./app/*"] };
3923
+ await writeFile(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}\n`);
3924
+ const ui = await execa("pnpm", [
3925
+ "dlx",
3926
+ "shadcn@latest",
3927
+ "init",
3928
+ "--preset",
3929
+ "nova",
3930
+ "--base",
3931
+ "base",
3932
+ "--yes",
3933
+ "--no-monorepo"
3934
+ ], {
3935
+ cwd: directory,
3936
+ reject: false,
3937
+ stdio: "inherit"
3938
+ });
3939
+ process.exitCode = ui.exitCode;
3940
+ if (ui.exitCode !== 0) return;
3070
3941
  await cp(new URL("./template/", import.meta.url), directory, { recursive: true });
3071
3942
  const configure = await execa("pnpm", [
3072
3943
  "config",
@@ -3074,7 +3945,7 @@ program.command("init <directory>").description("Create a Cloudflare React Route
3074
3945
  "--location=project",
3075
3946
  "--json",
3076
3947
  "minimumReleaseAgeExclude",
3077
- "[\"@usecontextlayer/*\", \"@contextlayer/*\"]"
3948
+ "[\"@usecontextlayer/*\"]"
3078
3949
  ], {
3079
3950
  cwd: directory,
3080
3951
  reject: false,
@@ -3084,7 +3955,7 @@ program.command("init <directory>").description("Create a Cloudflare React Route
3084
3955
  if (configure.exitCode !== 0) return;
3085
3956
  const install = await execa("pnpm", [
3086
3957
  "add",
3087
- `@contextlayer/sdk@${version}`,
3958
+ `@usecontextlayer/sdk@${version}`,
3088
3959
  "zod@^4.4.3"
3089
3960
  ], {
3090
3961
  cwd: directory,
@@ -3093,7 +3964,14 @@ program.command("init <directory>").description("Create a Cloudflare React Route
3093
3964
  });
3094
3965
  process.exitCode = install.exitCode;
3095
3966
  if (install.exitCode !== 0) return;
3096
- const response = await fetch(new URL("/api/apps", env.CTX_PLATFORM_URL), { method: "POST" });
3967
+ const response = await fetch(new URL("/api/apps", env.CTX_PLATFORM_URL), {
3968
+ body: JSON.stringify(input),
3969
+ headers: {
3970
+ authorization: `Bearer ${accessToken}`,
3971
+ "content-type": "application/json"
3972
+ },
3973
+ method: "POST"
3974
+ });
3097
3975
  if (!response.ok) throw new Error(`App creation failed: HTTP ${response.status}`);
3098
3976
  const app = object({
3099
3977
  id: uuid(),
@@ -3112,7 +3990,12 @@ program.command("init <directory>").description("Create a Cloudflare React Route
3112
3990
  });
3113
3991
  process.exitCode = git.exitCode;
3114
3992
  });
3115
- program.command("login").description("Sign in to ContextLayer by approving a code in your browser").action(login);
3993
+ program.command("login").description("Sign in by approving a browser code and configure Git credentials for ContextLayer repositories").action(async () => {
3994
+ await login();
3995
+ await setupGit(new URL(import.meta.url));
3996
+ console.log("Git credentials configured for ContextLayer.");
3997
+ });
3998
+ program.command("git-credential <operation>").description("Git credential helper using the saved login; invoked automatically by Git").action(gitCredential);
3116
3999
  program.command("whoami").description("Show your ContextLayer user ID using the saved login").action(whoami);
3117
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) => {
3118
4001
  if (!target || !operation) connections.error("Expected: ctx connections <target> list");
@@ -3123,6 +4006,23 @@ connections.command("add <toolset>").description("Print a Composio authorization
3123
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) => {
3124
4007
  await assignAppConnection(target, slug, connectionId);
3125
4008
  });
4009
+ 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) => {
4010
+ const input = object({
4011
+ name: string().min(1),
4012
+ prompt: string().min(1)
4013
+ }).parse({
4014
+ name,
4015
+ prompt
4016
+ });
4017
+ console.log(await runLocalAgent(input.name, input.prompt));
4018
+ });
4019
+ const secrets = program.command("secrets").description("Save or drop Owner-owned shared secrets through the authenticated platform").option("--org <org_slug>", "Use this organization's Owner; defaults to the signed-in user");
4020
+ secrets.command("set").argument("<name>", "Secret name: uppercase letters, digits, and underscores; cannot start with a digit").description("Save a secret with a masked password prompt; returns only Owner and name").option("--stdin", "Read the exact UTF-8 value from stdin instead of prompting; preserves whitespace and newlines").action(async (name, _options, command) => {
4021
+ await setSecret(secretNameSchema.parse(name), secretOptionsSchema.parse(command.optsWithGlobals()));
4022
+ });
4023
+ 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) => {
4024
+ await dropSecret(secretNameSchema.parse(name), secretOptionsSchema.parse(command.optsWithGlobals()).org);
4025
+ });
3126
4026
  await program.parseAsync();
3127
4027
  //#endregion
3128
4028
  export {};