@usecontextlayer/cli 0.12.1 → 0.14.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 { S as execa, _ as record, a as getAccessToken, b as url, c as whoami, d as boolean, f as discriminatedUnion, g as object, h as looseObject, i as secretNameSchema, l as env, m as literal, n as readLocalManifest, o as getCurrentUser, p as hostname, r as credentialModeSchema, s as login, t as getLocalAppId, u as array, v as string, x as uuid, y as unknown } from "./app-DUUpiXEm.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,7 +2967,71 @@ 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
3007
+ //#region owner.ts
3008
+ const ownerOptionsSchema = object({ org: string().min(1).optional() });
3009
+ async function resolveOwner(org, headers) {
3010
+ if (!org) return {
3011
+ id: (await getCurrentUser(headers)).id,
3012
+ type: "user"
3013
+ };
3014
+ const response = await fetch(new URL("/api/platform/organizations", env.CTX_AUTH_ISSUER), { headers });
3015
+ if (!response.ok) throw new Error(`Organization lookup failed: HTTP ${response.status}`);
3016
+ const { organizations } = object({ organizations: array(object({
3017
+ id: string().min(1),
3018
+ slug: string()
3019
+ })) }).parse(await response.json());
3020
+ const organization = organizations.find((organization) => organization.slug === org);
3021
+ if (!organization) throw new Error("Organization is not in your memberships");
3022
+ return {
3023
+ id: organization.id,
3024
+ type: "organization"
3025
+ };
3026
+ }
3027
+ function ownerPath(owner) {
3028
+ return `${owner.type === "organization" ? "org" : "user"}/${encodeURIComponent(owner.id)}`;
3029
+ }
3030
+ //#endregion
2965
3031
  //#region connections.ts
3032
+ async function getLocalManifest(target) {
3033
+ return target === "local" ? readLocalManifest() : void 0;
3034
+ }
2966
3035
  async function resolveAppTarget(target) {
2967
3036
  if (target !== "local") return target;
2968
3037
  return getLocalAppId();
@@ -2972,6 +3041,7 @@ async function assignAppConnection(target, slug, connectionId) {
2972
3041
  const response = await fetch(new URL(`/api/apps/${encodeURIComponent(appTarget)}/connections/assign`, env.CTX_PLATFORM_URL), {
2973
3042
  body: JSON.stringify({
2974
3043
  connection_id: connectionId,
3044
+ manifest: await getLocalManifest(target),
2975
3045
  slug
2976
3046
  }),
2977
3047
  headers: {
@@ -2989,7 +3059,7 @@ async function assignAppConnection(target, slug, connectionId) {
2989
3059
  }
2990
3060
  async function listAppConnections(target) {
2991
3061
  const appTarget = await resolveAppTarget(target);
2992
- const manifest = target === "local" ? JSON.parse(await readFile("public/slate.json", "utf8")) : void 0;
3062
+ const manifest = await getLocalManifest(target);
2993
3063
  const response = await fetch(new URL(`/api/apps/${encodeURIComponent(appTarget)}/connections/list`, env.CTX_PLATFORM_URL), {
2994
3064
  body: JSON.stringify({ manifest }),
2995
3065
  headers: {
@@ -3001,7 +3071,7 @@ async function listAppConnections(target) {
3001
3071
  if (!response.ok) throw new Error(`App connections request failed: HTTP ${response.status}`);
3002
3072
  const { connections } = object({ connections: array(object({
3003
3073
  connection_id: string().nullable(),
3004
- mode: _enum(["individual", "shared"]),
3074
+ mode: credentialModeSchema,
3005
3075
  slug: string(),
3006
3076
  toolkit: string()
3007
3077
  })) }).parse(await response.json());
@@ -3014,22 +3084,26 @@ async function listAppConnections(target) {
3014
3084
  connection: connection_id ?? "unassigned"
3015
3085
  })));
3016
3086
  }
3017
- async function addConnection(toolkit) {
3018
- const response = await fetch(new URL("/api/connections", env.CTX_PLATFORM_URL), {
3087
+ async function addConnection(toolkit, org) {
3088
+ const headers = { authorization: `Bearer ${await getAccessToken()}` };
3089
+ const owner = await resolveOwner(org, headers);
3090
+ const response = await fetch(new URL(`/api/connections/${ownerPath(owner)}`, env.CTX_PLATFORM_URL), {
3019
3091
  body: JSON.stringify({ toolkit }),
3020
3092
  headers: {
3021
- authorization: `Bearer ${await getAccessToken()}`,
3093
+ ...headers,
3022
3094
  "content-type": "application/json"
3023
3095
  },
3024
3096
  method: "POST"
3025
3097
  });
3026
3098
  if (!response.ok) throw new Error(`Connection authorization failed: HTTP ${response.status}`);
3027
3099
  const { redirect_url } = object({ redirect_url: url() }).parse(await response.json());
3028
- console.log(`Open this link to connect your account:\n${redirect_url}`);
3029
- console.log("After authorization, run ctx connections list to see your account.");
3100
+ console.log(`Open this link to authorize the Owner's account:\n${redirect_url}`);
3101
+ console.log(`After authorization, run ctx connections${org ? ` --org ${org}` : ""} list to see the Owner's account.`);
3030
3102
  }
3031
- async function listConnections() {
3032
- const response = await fetch(new URL("/api/connections", env.CTX_PLATFORM_URL), { headers: { authorization: `Bearer ${await getAccessToken()}` } });
3103
+ async function listConnections(org) {
3104
+ const headers = { authorization: `Bearer ${await getAccessToken()}` };
3105
+ const owner = await resolveOwner(org, headers);
3106
+ const response = await fetch(new URL(`/api/connections/${ownerPath(owner)}`, env.CTX_PLATFORM_URL), { headers });
3033
3107
  if (!response.ok) throw new Error(`Connection list failed: HTTP ${response.status}`);
3034
3108
  const { connections } = object({ connections: array(object({
3035
3109
  alias: string().nullable(),
@@ -3045,12 +3119,809 @@ async function listConnections() {
3045
3119
  console.table(connections);
3046
3120
  }
3047
3121
  //#endregion
3122
+ //#region git-credential.ts
3123
+ async function setupGit(cli) {
3124
+ const key = `credential.${new URL("/git", env.CTX_PLATFORM_URL).href}.helper`;
3125
+ const command = [
3126
+ process.execPath,
3127
+ fileURLToPath(cli),
3128
+ "git-credential"
3129
+ ].map((argument) => `'${argument.replaceAll("'", "'\\''")}'`).join(" ");
3130
+ await execa("git", [
3131
+ "config",
3132
+ "--global",
3133
+ "--replace-all",
3134
+ key,
3135
+ ""
3136
+ ]);
3137
+ await execa("git", [
3138
+ "config",
3139
+ "--global",
3140
+ "--add",
3141
+ key,
3142
+ `!${command}`
3143
+ ]);
3144
+ }
3145
+ async function gitCredential(operation) {
3146
+ if (operation === "capability") {
3147
+ process.stdout.write("version 0\ncapability authtype\n");
3148
+ return;
3149
+ }
3150
+ if (operation !== "get") return;
3151
+ const attributes = new URLSearchParams();
3152
+ const lines = createInterface({ input: process.stdin });
3153
+ for await (const line of lines) {
3154
+ if (line === "") break;
3155
+ const separator = line.indexOf("=");
3156
+ attributes.append(line.slice(0, separator), line.slice(separator + 1));
3157
+ }
3158
+ literal("authtype").parse(attributes.getAll("capability[]").find((c) => c === "authtype"));
3159
+ process.stdout.write(`capability[]=authtype\nauthtype=Bearer\ncredential=${await getAccessToken()}\n\n`);
3160
+ }
3161
+ //#endregion
3048
3162
  //#region package.json
3049
- var version = "0.12.1";
3163
+ var version = "0.14.0";
3164
+ //#endregion
3165
+ //#region ../../node_modules/.pnpm/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/utils.js
3166
+ const getCodePointsLength = (() => {
3167
+ const SURROGATE_PAIR_RE = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
3168
+ return (input) => {
3169
+ let surrogatePairsNr = 0;
3170
+ SURROGATE_PAIR_RE.lastIndex = 0;
3171
+ while (SURROGATE_PAIR_RE.test(input)) surrogatePairsNr += 1;
3172
+ return input.length - surrogatePairsNr;
3173
+ };
3174
+ })();
3175
+ const isFullWidth = (x) => {
3176
+ return x === 12288 || x >= 65281 && x <= 65376 || x >= 65504 && x <= 65510;
3177
+ };
3178
+ const isWideNotCJKTNotEmoji = (x) => {
3179
+ 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;
3180
+ };
3181
+ //#endregion
3182
+ //#region ../../node_modules/.pnpm/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/index.js
3183
+ const ANSI_RE = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
3184
+ const CONTROL_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
3185
+ 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;
3186
+ const TAB_RE = /\t{1,1000}/y;
3187
+ 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;
3188
+ const LATIN_RE = /(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y;
3189
+ const MODIFIER_RE = /\p{M}+/gu;
3190
+ const NO_TRUNCATION$1 = {
3191
+ limit: Infinity,
3192
+ ellipsis: ""
3193
+ };
3194
+ const getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {}) => {
3195
+ const LIMIT = truncationOptions.limit ?? Infinity;
3196
+ const ELLIPSIS = truncationOptions.ellipsis ?? "";
3197
+ const ELLIPSIS_WIDTH = truncationOptions?.ellipsisWidth ?? (ELLIPSIS ? getStringTruncatedWidth(ELLIPSIS, NO_TRUNCATION$1, widthOptions).width : 0);
3198
+ const ANSI_WIDTH = 0;
3199
+ const CONTROL_WIDTH = widthOptions.controlWidth ?? 0;
3200
+ const TAB_WIDTH = widthOptions.tabWidth ?? 8;
3201
+ const EMOJI_WIDTH = widthOptions.emojiWidth ?? 2;
3202
+ const FULL_WIDTH_WIDTH = 2;
3203
+ const REGULAR_WIDTH = widthOptions.regularWidth ?? 1;
3204
+ const WIDE_WIDTH = widthOptions.wideWidth ?? FULL_WIDTH_WIDTH;
3205
+ const PARSE_BLOCKS = [
3206
+ [LATIN_RE, REGULAR_WIDTH],
3207
+ [ANSI_RE, ANSI_WIDTH],
3208
+ [CONTROL_RE, CONTROL_WIDTH],
3209
+ [TAB_RE, TAB_WIDTH],
3210
+ [EMOJI_RE, EMOJI_WIDTH],
3211
+ [CJKT_WIDE_RE, WIDE_WIDTH]
3212
+ ];
3213
+ let indexPrev = 0;
3214
+ let index = 0;
3215
+ let length = input.length;
3216
+ let lengthExtra = 0;
3217
+ let truncationEnabled = false;
3218
+ let truncationIndex = length;
3219
+ let truncationLimit = Math.max(0, LIMIT - ELLIPSIS_WIDTH);
3220
+ let unmatchedStart = 0;
3221
+ let unmatchedEnd = 0;
3222
+ let width = 0;
3223
+ let widthExtra = 0;
3224
+ outer: while (true) {
3225
+ if (unmatchedEnd > unmatchedStart || index >= length && index > indexPrev) {
3226
+ const unmatched = input.slice(unmatchedStart, unmatchedEnd) || input.slice(indexPrev, index);
3227
+ lengthExtra = 0;
3228
+ for (const char of unmatched.replaceAll(MODIFIER_RE, "")) {
3229
+ const codePoint = char.codePointAt(0) || 0;
3230
+ if (isFullWidth(codePoint)) widthExtra = FULL_WIDTH_WIDTH;
3231
+ else if (isWideNotCJKTNotEmoji(codePoint)) widthExtra = WIDE_WIDTH;
3232
+ else widthExtra = REGULAR_WIDTH;
3233
+ if (width + widthExtra > truncationLimit) truncationIndex = Math.min(truncationIndex, Math.max(unmatchedStart, indexPrev) + lengthExtra);
3234
+ if (width + widthExtra > LIMIT) {
3235
+ truncationEnabled = true;
3236
+ break outer;
3237
+ }
3238
+ lengthExtra += char.length;
3239
+ width += widthExtra;
3240
+ }
3241
+ unmatchedStart = unmatchedEnd = 0;
3242
+ }
3243
+ if (index >= length) break outer;
3244
+ for (let i = 0, l = PARSE_BLOCKS.length; i < l; i++) {
3245
+ const [BLOCK_RE, BLOCK_WIDTH] = PARSE_BLOCKS[i];
3246
+ BLOCK_RE.lastIndex = index;
3247
+ if (BLOCK_RE.test(input)) {
3248
+ lengthExtra = BLOCK_RE === CJKT_WIDE_RE ? getCodePointsLength(input.slice(index, BLOCK_RE.lastIndex)) : BLOCK_RE === EMOJI_RE ? 1 : BLOCK_RE.lastIndex - index;
3249
+ widthExtra = lengthExtra * BLOCK_WIDTH;
3250
+ if (width + widthExtra > truncationLimit) truncationIndex = Math.min(truncationIndex, index + Math.floor((truncationLimit - width) / BLOCK_WIDTH));
3251
+ if (width + widthExtra > LIMIT) {
3252
+ truncationEnabled = true;
3253
+ break outer;
3254
+ }
3255
+ width += widthExtra;
3256
+ unmatchedStart = indexPrev;
3257
+ unmatchedEnd = index;
3258
+ index = indexPrev = BLOCK_RE.lastIndex;
3259
+ continue outer;
3260
+ }
3261
+ }
3262
+ index += 1;
3263
+ }
3264
+ return {
3265
+ width: truncationEnabled ? truncationLimit : width,
3266
+ index: truncationEnabled ? truncationIndex : length,
3267
+ truncated: truncationEnabled,
3268
+ ellipsed: truncationEnabled && LIMIT >= ELLIPSIS_WIDTH
3269
+ };
3270
+ };
3271
+ //#endregion
3272
+ //#region ../../node_modules/.pnpm/fast-string-width@3.0.2/node_modules/fast-string-width/dist/index.js
3273
+ const NO_TRUNCATION = {
3274
+ limit: Infinity,
3275
+ ellipsis: "",
3276
+ ellipsisWidth: 0
3277
+ };
3278
+ const fastStringWidth = (input, options = {}) => {
3279
+ return getStringTruncatedWidth(input, NO_TRUNCATION, options).width;
3280
+ };
3281
+ //#endregion
3282
+ //#region ../../node_modules/.pnpm/fast-wrap-ansi@0.2.2/node_modules/fast-wrap-ansi/lib/main.js
3283
+ const ESC = "\x1B";
3284
+ const CSI = "›";
3285
+ const END_CODE = 39;
3286
+ const ANSI_ESCAPE_BELL = "\x07";
3287
+ const ANSI_CSI = "[";
3288
+ const ANSI_OSC = "]";
3289
+ const ANSI_SGR_TERMINATOR = "m";
3290
+ const ANSI_ESCAPE_LINK = `${ANSI_OSC}8;;`;
3291
+ const GROUP_REGEX = new RegExp(`(?:\\${ANSI_CSI}(?<code>\\d+)m|\\${ANSI_ESCAPE_LINK}(?<uri>.*)${ANSI_ESCAPE_BELL})`, "y");
3292
+ const getClosingCode = (openingCode) => {
3293
+ if (openingCode >= 30 && openingCode <= 37) return 39;
3294
+ if (openingCode >= 90 && openingCode <= 97) return 39;
3295
+ if (openingCode >= 40 && openingCode <= 47) return 49;
3296
+ if (openingCode >= 100 && openingCode <= 107) return 49;
3297
+ if (openingCode === 1 || openingCode === 2) return 22;
3298
+ if (openingCode === 3) return 23;
3299
+ if (openingCode === 4) return 24;
3300
+ if (openingCode === 7) return 27;
3301
+ if (openingCode === 8) return 28;
3302
+ if (openingCode === 9) return 29;
3303
+ if (openingCode === 0) return 0;
3304
+ };
3305
+ const wrapAnsiCode = (code) => `${ESC}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
3306
+ const wrapAnsiHyperlink = (url) => `${ESC}${ANSI_ESCAPE_LINK}${url}${ANSI_ESCAPE_BELL}`;
3307
+ const wrapWord = (rows, word, columns) => {
3308
+ const characters = word[Symbol.iterator]();
3309
+ let isInsideEscape = false;
3310
+ let isInsideLinkEscape = false;
3311
+ let lastRow = rows.at(-1);
3312
+ let visible = lastRow === void 0 ? 0 : fastStringWidth(lastRow);
3313
+ let currentCharacter = characters.next();
3314
+ let nextCharacter = characters.next();
3315
+ let rawCharacterIndex = 0;
3316
+ while (!currentCharacter.done) {
3317
+ const character = currentCharacter.value;
3318
+ const characterLength = fastStringWidth(character);
3319
+ if (visible + characterLength <= columns) rows[rows.length - 1] += character;
3320
+ else {
3321
+ rows.push(character);
3322
+ visible = 0;
3323
+ }
3324
+ if (character === ESC || character === CSI) {
3325
+ isInsideEscape = true;
3326
+ isInsideLinkEscape = word.startsWith(ANSI_ESCAPE_LINK, rawCharacterIndex + 1);
3327
+ }
3328
+ if (isInsideEscape) {
3329
+ if (isInsideLinkEscape) {
3330
+ if (character === ANSI_ESCAPE_BELL) {
3331
+ isInsideEscape = false;
3332
+ isInsideLinkEscape = false;
3333
+ }
3334
+ } else if (character === ANSI_SGR_TERMINATOR) isInsideEscape = false;
3335
+ } else {
3336
+ visible += characterLength;
3337
+ if (visible === columns && !nextCharacter.done) {
3338
+ rows.push("");
3339
+ visible = 0;
3340
+ }
3341
+ }
3342
+ currentCharacter = nextCharacter;
3343
+ nextCharacter = characters.next();
3344
+ rawCharacterIndex += character.length;
3345
+ }
3346
+ lastRow = rows.at(-1);
3347
+ if (!visible && lastRow !== void 0 && lastRow.length && rows.length > 1) rows[rows.length - 2] += rows.pop();
3348
+ };
3349
+ const stringVisibleTrimSpacesRight = (string) => {
3350
+ const words = string.split(" ");
3351
+ let last = words.length;
3352
+ while (last) {
3353
+ if (fastStringWidth(words[last - 1])) break;
3354
+ last--;
3355
+ }
3356
+ if (last === words.length) return string;
3357
+ return words.slice(0, last).join(" ") + words.slice(last).join("");
3358
+ };
3359
+ const exec = (string, columns, options = {}) => {
3360
+ if (options.trim !== false && string.trim() === "") return "";
3361
+ let returnValue = "";
3362
+ let escapeCode;
3363
+ let escapeUrl;
3364
+ const words = string.split(" ");
3365
+ let rows = [""];
3366
+ let rowLength = 0;
3367
+ for (let index = 0; index < words.length; index++) {
3368
+ const word = words[index];
3369
+ if (options.trim !== false) {
3370
+ const row = rows.at(-1) ?? "";
3371
+ const trimmed = row.trimStart();
3372
+ if (row.length !== trimmed.length) {
3373
+ rows[rows.length - 1] = trimmed;
3374
+ rowLength = fastStringWidth(trimmed);
3375
+ }
3376
+ }
3377
+ if (index !== 0) {
3378
+ if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
3379
+ rows.push("");
3380
+ rowLength = 0;
3381
+ }
3382
+ if (rowLength || options.trim === false) {
3383
+ rows[rows.length - 1] += " ";
3384
+ rowLength++;
3385
+ }
3386
+ }
3387
+ const wordLength = fastStringWidth(word);
3388
+ if (options.hard && wordLength > columns) {
3389
+ const remainingColumns = columns - rowLength;
3390
+ const breaksStartingThisLine = 1 + Math.floor((wordLength - remainingColumns - 1) / columns);
3391
+ if (Math.floor((wordLength - 1) / columns) < breaksStartingThisLine) rows.push("");
3392
+ wrapWord(rows, word, columns);
3393
+ rowLength = fastStringWidth(rows.at(-1) ?? "");
3394
+ continue;
3395
+ }
3396
+ if (rowLength + wordLength > columns && rowLength && wordLength) {
3397
+ if (options.wordWrap === false && rowLength < columns) {
3398
+ wrapWord(rows, word, columns);
3399
+ rowLength = fastStringWidth(rows.at(-1) ?? "");
3400
+ continue;
3401
+ }
3402
+ rows.push("");
3403
+ rowLength = 0;
3404
+ }
3405
+ if (rowLength + wordLength > columns && options.wordWrap === false) {
3406
+ wrapWord(rows, word, columns);
3407
+ rowLength = fastStringWidth(rows.at(-1) ?? "");
3408
+ continue;
3409
+ }
3410
+ rows[rows.length - 1] += word;
3411
+ rowLength += wordLength;
3412
+ }
3413
+ if (options.trim !== false) rows = rows.map((row) => stringVisibleTrimSpacesRight(row));
3414
+ const preString = rows.join("\n");
3415
+ let inSurrogate = false;
3416
+ for (let i = 0; i < preString.length; i++) {
3417
+ const character = preString[i];
3418
+ returnValue += character;
3419
+ if (!inSurrogate) {
3420
+ inSurrogate = character >= "\ud800" && character <= "\udbff";
3421
+ if (inSurrogate) continue;
3422
+ } else inSurrogate = false;
3423
+ if (character === ESC || character === CSI) {
3424
+ GROUP_REGEX.lastIndex = i + 1;
3425
+ const groups = GROUP_REGEX.exec(preString)?.groups;
3426
+ if (groups?.code !== void 0) {
3427
+ const code = Number.parseFloat(groups.code);
3428
+ escapeCode = code === END_CODE ? void 0 : code;
3429
+ } else if (groups?.uri !== void 0) escapeUrl = groups.uri.length === 0 ? void 0 : groups.uri;
3430
+ }
3431
+ if (preString[i + 1] === "\n") {
3432
+ if (escapeUrl) returnValue += wrapAnsiHyperlink("");
3433
+ const closingCode = escapeCode ? getClosingCode(escapeCode) : void 0;
3434
+ if (escapeCode && closingCode) returnValue += wrapAnsiCode(closingCode);
3435
+ } else if (character === "\n") {
3436
+ if (escapeCode && getClosingCode(escapeCode)) returnValue += wrapAnsiCode(escapeCode);
3437
+ if (escapeUrl) returnValue += wrapAnsiHyperlink(escapeUrl);
3438
+ }
3439
+ }
3440
+ return returnValue;
3441
+ };
3442
+ const CRLF_OR_LF = /\r?\n/;
3443
+ function wrapAnsi(string, columns, options) {
3444
+ return String(string).normalize().split(CRLF_OR_LF).map((line) => exec(line, columns, options)).join("\n");
3445
+ }
3446
+ //#endregion
3447
+ //#region ../../node_modules/.pnpm/@clack+core@1.5.1/node_modules/@clack/core/dist/index.mjs
3448
+ var import_src = (/* @__PURE__ */ __commonJSMin(((exports, module) => {
3449
+ const ESC = "\x1B";
3450
+ const CSI = `${ESC}[`;
3451
+ const beep = "\x07";
3452
+ const cursor = {
3453
+ to(x, y) {
3454
+ if (!y) return `${CSI}${x + 1}G`;
3455
+ return `${CSI}${y + 1};${x + 1}H`;
3456
+ },
3457
+ move(x, y) {
3458
+ let ret = "";
3459
+ if (x < 0) ret += `${CSI}${-x}D`;
3460
+ else if (x > 0) ret += `${CSI}${x}C`;
3461
+ if (y < 0) ret += `${CSI}${-y}A`;
3462
+ else if (y > 0) ret += `${CSI}${y}B`;
3463
+ return ret;
3464
+ },
3465
+ up: (count = 1) => `${CSI}${count}A`,
3466
+ down: (count = 1) => `${CSI}${count}B`,
3467
+ forward: (count = 1) => `${CSI}${count}C`,
3468
+ backward: (count = 1) => `${CSI}${count}D`,
3469
+ nextLine: (count = 1) => `${CSI}E`.repeat(count),
3470
+ prevLine: (count = 1) => `${CSI}F`.repeat(count),
3471
+ left: `${CSI}G`,
3472
+ hide: `${CSI}?25l`,
3473
+ show: `${CSI}?25h`,
3474
+ save: `${ESC}7`,
3475
+ restore: `${ESC}8`
3476
+ };
3477
+ module.exports = {
3478
+ cursor,
3479
+ scroll: {
3480
+ up: (count = 1) => `${CSI}S`.repeat(count),
3481
+ down: (count = 1) => `${CSI}T`.repeat(count)
3482
+ },
3483
+ erase: {
3484
+ screen: `${CSI}2J`,
3485
+ up: (count = 1) => `${CSI}1J`.repeat(count),
3486
+ down: (count = 1) => `${CSI}J`.repeat(count),
3487
+ line: `${CSI}2K`,
3488
+ lineEnd: `${CSI}K`,
3489
+ lineStart: `${CSI}1K`,
3490
+ lines(count) {
3491
+ let clear = "";
3492
+ for (let i = 0; i < count; i++) clear += this.line + (i < count - 1 ? cursor.up() : "");
3493
+ if (count) clear += cursor.left;
3494
+ return clear;
3495
+ }
3496
+ },
3497
+ beep
3498
+ };
3499
+ })))();
3500
+ const settings = {
3501
+ actions: /* @__PURE__ */ new Set([
3502
+ "up",
3503
+ "down",
3504
+ "left",
3505
+ "right",
3506
+ "space",
3507
+ "enter",
3508
+ "cancel"
3509
+ ]),
3510
+ aliases: /* @__PURE__ */ new Map([
3511
+ ["k", "up"],
3512
+ ["j", "down"],
3513
+ ["h", "left"],
3514
+ ["l", "right"],
3515
+ ["", "cancel"],
3516
+ ["escape", "cancel"]
3517
+ ]),
3518
+ messages: {
3519
+ cancel: "Canceled",
3520
+ error: "Something went wrong"
3521
+ },
3522
+ withGuide: true,
3523
+ accessible: void 0,
3524
+ date: {
3525
+ monthNames: [...[
3526
+ "January",
3527
+ "February",
3528
+ "March",
3529
+ "April",
3530
+ "May",
3531
+ "June",
3532
+ "July",
3533
+ "August",
3534
+ "September",
3535
+ "October",
3536
+ "November",
3537
+ "December"
3538
+ ]],
3539
+ messages: {
3540
+ required: "Please enter a valid date",
3541
+ invalidMonth: "There are only 12 months in a year",
3542
+ invalidDay: (n, e) => `There are only ${n} days in ${e}`,
3543
+ afterMin: (n) => `Date must be on or after ${n.toISOString().slice(0, 10)}`,
3544
+ beforeMax: (n) => `Date must be on or before ${n.toISOString().slice(0, 10)}`
3545
+ }
3546
+ }
3547
+ };
3548
+ function isAccessible(n) {
3549
+ if (n !== void 0) return n;
3550
+ if (settings.accessible !== void 0) return settings.accessible;
3551
+ const e = process.env.ACCESSIBLE;
3552
+ return e !== void 0 && e !== "" && e !== "0" && e !== "false";
3553
+ }
3554
+ function isActionKey(n, e) {
3555
+ if (typeof n == "string") return settings.aliases.get(n) === e;
3556
+ for (const s of n) if (s !== void 0 && isActionKey(s, e)) return true;
3557
+ return false;
3558
+ }
3559
+ function diffLines(i, s) {
3560
+ if (i === s) return;
3561
+ const e = i.split(`
3562
+ `), t = s.split(`
3563
+ `), r = Math.max(e.length, t.length), f = [];
3564
+ for (let n = 0; n < r; n++) e[n] !== t[n] && f.push(n);
3565
+ return {
3566
+ lines: f,
3567
+ numLinesBefore: e.length,
3568
+ numLinesAfter: t.length,
3569
+ numLines: r
3570
+ };
3571
+ }
3572
+ globalThis.process.platform.startsWith("win");
3573
+ const CANCEL_SYMBOL = Symbol("clack:cancel");
3574
+ function isCancel(e) {
3575
+ return e === CANCEL_SYMBOL;
3576
+ }
3577
+ function setRawMode(e, r) {
3578
+ const o = e;
3579
+ o.isTTY && o.setRawMode(r);
3580
+ }
3581
+ const getRows = (e) => "rows" in e && typeof e.rows == "number" ? e.rows : 20;
3582
+ function runValidation(e, a) {
3583
+ if ("~standard" in e) {
3584
+ const n = e["~standard"].validate(a);
3585
+ return n instanceof Promise ? n.then((r) => r.issues?.at(0)?.message) : n.issues?.at(0)?.message;
3586
+ }
3587
+ return e(a);
3588
+ }
3589
+ var y = class {
3590
+ input;
3591
+ output;
3592
+ _abortSignal;
3593
+ rl;
3594
+ opts;
3595
+ _render;
3596
+ _track = false;
3597
+ _prevFrame = "";
3598
+ _subscribers = /* @__PURE__ */ new Map();
3599
+ _cursor = 0;
3600
+ state = "initial";
3601
+ error = "";
3602
+ value;
3603
+ userInput = "";
3604
+ /**
3605
+ * Whether accessible (static, screen-reader friendly) output is enabled for
3606
+ * this prompt, resolved from the `accessible` option, the global setting,
3607
+ * and the `ACCESSIBLE` env var.
3608
+ */
3609
+ get accessible() {
3610
+ return isAccessible(this.opts.accessible);
3611
+ }
3612
+ constructor(t, e = true) {
3613
+ const { input: i = stdin, output: s = stdout, render: r, signal: n, ...o } = t;
3614
+ 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;
3615
+ }
3616
+ /**
3617
+ * Unsubscribe all listeners
3618
+ */
3619
+ unsubscribe() {
3620
+ this._subscribers.clear();
3621
+ }
3622
+ /**
3623
+ * Set a subscriber with opts
3624
+ * @param event - The event name
3625
+ */
3626
+ setSubscriber(t, e) {
3627
+ const i = this._subscribers.get(t) ?? [];
3628
+ i.push(e), this._subscribers.set(t, i);
3629
+ }
3630
+ /**
3631
+ * Subscribe to an event
3632
+ * @param event - The event name
3633
+ * @param cb - The callback
3634
+ */
3635
+ on(t, e) {
3636
+ this.setSubscriber(t, { cb: e });
3637
+ }
3638
+ /**
3639
+ * Subscribe to an event once
3640
+ * @param event - The event name
3641
+ * @param cb - The callback
3642
+ */
3643
+ once(t, e) {
3644
+ this.setSubscriber(t, {
3645
+ cb: e,
3646
+ once: true
3647
+ });
3648
+ }
3649
+ /**
3650
+ * Emit an event with data
3651
+ * @param event - The event name
3652
+ * @param data - The data to pass to the callback
3653
+ */
3654
+ emit(t, ...e) {
3655
+ const i = this._subscribers.get(t) ?? [], s = [];
3656
+ for (const r of i) r.cb(...e), r.once && s.push(() => i.splice(i.indexOf(r), 1));
3657
+ for (const r of s) r();
3658
+ }
3659
+ prompt() {
3660
+ return new Promise((t) => {
3661
+ if (this._abortSignal) {
3662
+ if (this._abortSignal.aborted) return this.state = "cancel", this.close(), t(CANCEL_SYMBOL);
3663
+ this._abortSignal.addEventListener("abort", () => {
3664
+ this.state = "cancel", this.close();
3665
+ }, { once: true });
3666
+ }
3667
+ this.rl = l__default.createInterface({
3668
+ input: this.input,
3669
+ tabSize: 2,
3670
+ prompt: "",
3671
+ escapeCodeTimeout: 50,
3672
+ terminal: true
3673
+ }), 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", () => {
3674
+ this.output.write(import_src.cursor.show), this.output.off("resize", this.render), setRawMode(this.input, false), t(this.value);
3675
+ }), this.once("cancel", () => {
3676
+ this.output.write(import_src.cursor.show), this.output.off("resize", this.render), setRawMode(this.input, false), t(CANCEL_SYMBOL);
3677
+ });
3678
+ });
3679
+ }
3680
+ _isActionKey(t, e) {
3681
+ return t === " ";
3682
+ }
3683
+ _shouldSubmit(t, e) {
3684
+ return true;
3685
+ }
3686
+ _setValue(t) {
3687
+ this.value = t, this.emit("value", this.value);
3688
+ }
3689
+ _setUserInput(t, e) {
3690
+ this.userInput = t ?? "", this.emit("userInput", this.userInput), e && this._track && this.rl && (this.rl.write(this.userInput), this._cursor = this.rl.cursor);
3691
+ }
3692
+ _clearUserInput() {
3693
+ this.rl?.write(null, {
3694
+ ctrl: true,
3695
+ name: "u"
3696
+ }), this._setUserInput("");
3697
+ }
3698
+ async onKeypress(t, e) {
3699
+ if (this.state !== "validating") {
3700
+ if (this._track && e.name !== "return" && (e.name && this._isActionKey(t, e) && this.rl?.write(null, {
3701
+ ctrl: true,
3702
+ name: "h"
3703
+ }), 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)) {
3704
+ if (this.opts.validate) {
3705
+ const i = runValidation(this.opts.validate, this.value);
3706
+ let s;
3707
+ 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));
3708
+ }
3709
+ this.state !== "error" && (this.state = "submit");
3710
+ }
3711
+ isActionKey([
3712
+ t,
3713
+ e?.name,
3714
+ e?.sequence
3715
+ ], "cancel") && (this.state = "cancel"), (this.state === "submit" || this.state === "cancel") && this.emit("finalize"), this.render(), (this.state === "submit" || this.state === "cancel") && this.close();
3716
+ }
3717
+ }
3718
+ close() {
3719
+ this.input.unpipe(), this.input.removeListener("keypress", this.onKeypress), this.output.write(`
3720
+ `), setRawMode(this.input, false), this.rl?.close(), this.rl = void 0, this.emit(`${this.state}`, this.value), this.unsubscribe();
3721
+ }
3722
+ restoreCursor() {
3723
+ const t = wrapAnsi(this._prevFrame, process.stdout.columns, {
3724
+ hard: true,
3725
+ trim: false
3726
+ }).split(`
3727
+ `).length - 1;
3728
+ this.output.write(import_src.cursor.move(-999, t * -1));
3729
+ }
3730
+ render() {
3731
+ const t = wrapAnsi(this._render(this) ?? "", process.stdout.columns, {
3732
+ hard: true,
3733
+ trim: false
3734
+ });
3735
+ if (t !== this._prevFrame) {
3736
+ if (this.state === "initial") this.output.write(import_src.cursor.hide);
3737
+ else {
3738
+ const e = diffLines(this._prevFrame, t), i = getRows(this.output);
3739
+ if (this.restoreCursor(), e) {
3740
+ const s = Math.max(0, e.numLinesAfter - i), r = Math.max(0, e.numLinesBefore - i);
3741
+ let n = e.lines.find((o) => o >= s);
3742
+ if (n === void 0) {
3743
+ this._prevFrame = t;
3744
+ return;
3745
+ }
3746
+ if (e.lines.length === 1) {
3747
+ this.output.write(import_src.cursor.move(0, n - r)), this.output.write(import_src.erase.lines(1));
3748
+ const o = t.split(`
3749
+ `);
3750
+ this.output.write(o[n]), this._prevFrame = t, this.output.write(import_src.cursor.move(0, o.length - n - 1));
3751
+ return;
3752
+ } else if (e.lines.length > 1) {
3753
+ if (s < r) n = s;
3754
+ else {
3755
+ const h = n - r;
3756
+ h > 0 && this.output.write(import_src.cursor.move(0, h));
3757
+ }
3758
+ this.output.write(import_src.erase.down());
3759
+ const f = t.split(`
3760
+ `).slice(n);
3761
+ this.output.write(f.join(`
3762
+ `)), this._prevFrame = t;
3763
+ return;
3764
+ }
3765
+ }
3766
+ this.output.write(import_src.erase.down());
3767
+ }
3768
+ this.output.write(t), this.state === "initial" && (this.state = "active"), this._prevFrame = t;
3769
+ }
3770
+ }
3771
+ };
3772
+ let u$1 = class u extends y {
3773
+ _mask = "•";
3774
+ get cursor() {
3775
+ return this._cursor;
3776
+ }
3777
+ get masked() {
3778
+ return this.userInput.replaceAll(/./g, this._mask);
3779
+ }
3780
+ get userInputWithCursor() {
3781
+ if (this.state === "submit" || this.state === "cancel") return this.masked;
3782
+ const t = this.userInput;
3783
+ if (this.cursor >= t.length) return `${this.masked}${styleText(["inverse", "hidden"], "_")}`;
3784
+ const s = this.masked, r = s.slice(0, this.cursor), i = s.slice(this.cursor, this.cursor + 1), o = s.slice(this.cursor + 1);
3785
+ return `${r}${styleText("inverse", i)}${o}`;
3786
+ }
3787
+ clear() {
3788
+ this._clearUserInput();
3789
+ }
3790
+ constructor({ mask: t, ...s }) {
3791
+ super(s), this._mask = t ?? "•", this.on("userInput", (r) => {
3792
+ this._setValue(r);
3793
+ }), this.on("finalize", () => {
3794
+ this.value === void 0 && (this.value = "");
3795
+ });
3796
+ }
3797
+ };
3798
+ //#endregion
3799
+ //#region ../../node_modules/.pnpm/@clack+prompts@1.8.1/node_modules/@clack/prompts/dist/index.mjs
3800
+ function isUnicodeSupported() {
3801
+ if (process$1.platform !== "win32") return process$1.env.TERM !== "linux";
3802
+ 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";
3803
+ }
3804
+ const unicode = isUnicodeSupported();
3805
+ const unicodeOr = (o, e) => unicode ? o : e;
3806
+ const S_STEP_ACTIVE = unicodeOr("◆", "*");
3807
+ const S_STEP_CANCEL = unicodeOr("■", "x");
3808
+ const S_STEP_ERROR = unicodeOr("▲", "x");
3809
+ const S_STEP_SUBMIT = unicodeOr("◇", "o");
3810
+ const S_BAR = unicodeOr("│", "|");
3811
+ const S_BAR_END = unicodeOr("└", "—");
3812
+ const S_PASSWORD_MASK = unicodeOr("▪", "•");
3813
+ const symbol = (o) => {
3814
+ switch (o) {
3815
+ case "initial":
3816
+ case "active": return styleText("cyan", S_STEP_ACTIVE);
3817
+ case "cancel": return styleText("red", S_STEP_CANCEL);
3818
+ case "error": return styleText("yellow", S_STEP_ERROR);
3819
+ case "submit": return styleText("green", S_STEP_SUBMIT);
3820
+ case "validating": return styleText("dim", S_STEP_ACTIVE);
3821
+ }
3822
+ };
3823
+ `${styleText("dim", "↑/↓")}`, `${styleText("dim", "Space:")}`, `${styleText("dim", "Enter:")}`;
3824
+ const password = (e) => new u$1({
3825
+ validate: e.validate,
3826
+ mask: e.mask ?? S_PASSWORD_MASK,
3827
+ signal: e.signal,
3828
+ input: e.input,
3829
+ output: e.output,
3830
+ render() {
3831
+ const r = e.withGuide ?? settings.withGuide, o = `${r ? `${styleText("gray", S_BAR)}
3832
+ ` : ""}${symbol(this.state)} ${e.message}
3833
+ `, m = this.userInputWithCursor, i = this.masked;
3834
+ switch (this.state) {
3835
+ case "error": {
3836
+ const s = r ? `${styleText("yellow", S_BAR)} ` : "", n = r ? `${styleText("yellow", S_BAR_END)} ` : "", d = i ?? "";
3837
+ return e.clearOnError && this.clear(), `${o.trim()}
3838
+ ${s}${d}
3839
+ ${n}${styleText("yellow", this.error)}
3840
+ `;
3841
+ }
3842
+ case "submit": return `${o}${r ? `${styleText("gray", S_BAR)} ` : ""}${i ? styleText("dim", i) : ""}`;
3843
+ case "cancel": return `${o}${r ? `${styleText("gray", S_BAR)} ` : ""}${i ? styleText(["strikethrough", "dim"], i) : ""}${i && r ? `
3844
+ ${styleText("gray", S_BAR)}` : ""}`;
3845
+ default: return `${o}${r ? `${styleText("cyan", S_BAR)} ` : ""}${m}
3846
+ ${r ? styleText("cyan", S_BAR_END) : ""}
3847
+ `;
3848
+ }
3849
+ }
3850
+ }).prompt();
3851
+ `${styleText("dim", "↑/↓")}`, `${styleText("dim", "Enter:")}`;
3852
+ `${styleText("gray", S_BAR)}`;
3853
+ //#endregion
3854
+ //#region ../shared/dist/app-usage.mjs
3855
+ const ownerSchema = discriminatedUnion("type", [object({
3856
+ id: string().min(1),
3857
+ type: literal("user")
3858
+ }), object({
3859
+ id: string().min(1),
3860
+ type: literal("organization")
3861
+ })]);
3862
+ object({
3863
+ id: uuid(),
3864
+ owner: ownerSchema
3865
+ });
3866
+ //#endregion
3867
+ //#region secrets.ts
3868
+ const secretOptionsSchema = ownerOptionsSchema.extend({ stdin: boolean().default(false) });
3869
+ const valueSchema = string().min(1);
3870
+ const confirmationSchema = object({
3871
+ name: secretNameSchema,
3872
+ owner: ownerSchema
3873
+ });
3874
+ async function resolveSecretUrl(name, org, headers) {
3875
+ const owner = await resolveOwner(org, headers);
3876
+ return new URL(`/api/secrets/${ownerPath(owner)}/${encodeURIComponent(name)}`, env.CTX_PLATFORM_URL);
3877
+ }
3878
+ async function setSecret(name, options) {
3879
+ const headers = { authorization: `Bearer ${await getAccessToken()}` };
3880
+ const url = await resolveSecretUrl(name, options.org, headers);
3881
+ let value;
3882
+ if (options.stdin) {
3883
+ process.stdin.setEncoding("utf8");
3884
+ value = "";
3885
+ for await (const chunk of process.stdin) value += chunk;
3886
+ } else {
3887
+ if (!process.stdin.isTTY) throw new Error("Use --stdin to read a secret without a terminal");
3888
+ const entered = await password({
3889
+ message: `Value for ${name}`,
3890
+ output: process.stderr,
3891
+ validate: valueSchema
3892
+ });
3893
+ if (isCancel(entered)) {
3894
+ process.exitCode = 130;
3895
+ return;
3896
+ }
3897
+ value = entered;
3898
+ }
3899
+ const response = await fetch(url, {
3900
+ body: JSON.stringify({ value: valueSchema.parse(value) }),
3901
+ headers: {
3902
+ ...headers,
3903
+ "content-type": "application/json"
3904
+ },
3905
+ method: "PUT"
3906
+ });
3907
+ if (!response.ok) throw new Error(`Secret save failed: HTTP ${response.status}`);
3908
+ console.log(JSON.stringify(confirmationSchema.parse(await response.json())));
3909
+ }
3910
+ async function dropSecret(name, org) {
3911
+ const headers = { authorization: `Bearer ${await getAccessToken()}` };
3912
+ const response = await fetch(await resolveSecretUrl(name, org, headers), {
3913
+ headers,
3914
+ method: "DELETE"
3915
+ });
3916
+ if (!response.ok) throw new Error(`Secret drop failed: HTTP ${response.status}`);
3917
+ console.log(JSON.stringify(confirmationSchema.parse(await response.json())));
3918
+ }
3050
3919
  //#endregion
3051
3920
  //#region cli.ts
3052
3921
  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) => {
3922
+ 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) => {
3923
+ const input = object({ organization_slug: string().min(1).optional() }).parse({ organization_slug: options.org });
3924
+ const accessToken = await getAccessToken();
3054
3925
  const result = await execa("pnpm", [
3055
3926
  "create",
3056
3927
  "cloudflare@latest",
@@ -3067,6 +3938,27 @@ program.command("init <directory>").description("Create a Cloudflare React Route
3067
3938
  });
3068
3939
  process.exitCode = result.exitCode;
3069
3940
  if (result.exitCode !== 0) return;
3941
+ const tsconfigPath = join(directory, "tsconfig.json");
3942
+ const tsconfig = looseObject({ compilerOptions: record(string(), unknown()) }).parse(JSON.parse(await readFile(tsconfigPath, "utf8")));
3943
+ tsconfig.compilerOptions.paths = { "~/*": ["./app/*"] };
3944
+ await writeFile(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}\n`);
3945
+ const ui = await execa("pnpm", [
3946
+ "dlx",
3947
+ "shadcn@latest",
3948
+ "init",
3949
+ "--preset",
3950
+ "nova",
3951
+ "--base",
3952
+ "base",
3953
+ "--yes",
3954
+ "--no-monorepo"
3955
+ ], {
3956
+ cwd: directory,
3957
+ reject: false,
3958
+ stdio: "inherit"
3959
+ });
3960
+ process.exitCode = ui.exitCode;
3961
+ if (ui.exitCode !== 0) return;
3070
3962
  await cp(new URL("./template/", import.meta.url), directory, { recursive: true });
3071
3963
  const configure = await execa("pnpm", [
3072
3964
  "config",
@@ -3093,7 +3985,14 @@ program.command("init <directory>").description("Create a Cloudflare React Route
3093
3985
  });
3094
3986
  process.exitCode = install.exitCode;
3095
3987
  if (install.exitCode !== 0) return;
3096
- const response = await fetch(new URL("/api/apps", env.CTX_PLATFORM_URL), { method: "POST" });
3988
+ const response = await fetch(new URL("/api/apps", env.CTX_PLATFORM_URL), {
3989
+ body: JSON.stringify(input),
3990
+ headers: {
3991
+ authorization: `Bearer ${accessToken}`,
3992
+ "content-type": "application/json"
3993
+ },
3994
+ method: "POST"
3995
+ });
3097
3996
  if (!response.ok) throw new Error(`App creation failed: HTTP ${response.status}`);
3098
3997
  const app = object({
3099
3998
  id: uuid(),
@@ -3112,17 +4011,44 @@ program.command("init <directory>").description("Create a Cloudflare React Route
3112
4011
  });
3113
4012
  process.exitCode = git.exitCode;
3114
4013
  });
3115
- program.command("login").description("Sign in to ContextLayer by approving a code in your browser").action(login);
4014
+ program.command("login").description("Sign in by approving a browser code and configure Git credentials for ContextLayer repositories").action(async () => {
4015
+ await login();
4016
+ await setupGit(new URL(import.meta.url));
4017
+ console.log("Git credentials configured for ContextLayer.");
4018
+ });
4019
+ program.command("git-credential <operation>").description("Git credential helper using the saved login; invoked automatically by Git").action(gitCredential);
3116
4020
  program.command("whoami").description("Show your ContextLayer user ID using the saved login").action(whoami);
3117
- 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) => {
4021
+ const connections = program.command("connections").description("Manage Owner-owned connected accounts or list an app's requirements").option("--org <org_slug>", "Manage this organization's connections; defaults to the signed-in user").argument("[target]", "AppID, public hostname, or local (run from the app root)").addArgument(new Argument("[operation]", "App connection operation").choices(["list"])).action(async (target, operation) => {
3118
4022
  if (!target || !operation) connections.error("Expected: ctx connections <target> list");
3119
4023
  await listAppConnections(target);
3120
4024
  });
3121
- connections.command("list").description("List your Composio accounts with their toolkit, identity, and status").action(listConnections);
3122
- connections.command("add <toolset>").description("Print a Composio authorization link to connect an account (for example, gmail)").action(addConnection);
3123
- 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) => {
4025
+ connections.command("list").description("List the selected Owner's Composio accounts with their toolkit, identity, and status").action(async (_options, command) => {
4026
+ await listConnections(ownerOptionsSchema.parse(command.optsWithGlobals()).org);
4027
+ });
4028
+ connections.command("add <toolkit>").description("Print a Composio authorization link for the selected Owner's account (for example, gmail)").action(async (toolkit, _options, command) => {
4029
+ const options = ownerOptionsSchema.parse(command.optsWithGlobals());
4030
+ await addConnection(string().min(1).parse(toolkit), options.org);
4031
+ });
4032
+ program.command("connection").description("Assign a connection using the requirement’s viewer or owner mode; owner mode requires app management").argument("<target>", "AppID, public hostname, or local (run from the app root)").addArgument(new Argument("<operation>").choices(["assign"])).argument("<slug>", "Connection requirement slug").argument("<connection_id>", "Composio connected-account ID").action(async (target, _operation, slug, connectionId) => {
3124
4033
  await assignAppConnection(target, slug, connectionId);
3125
4034
  });
4035
+ 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) => {
4036
+ const input = object({
4037
+ name: string().min(1),
4038
+ prompt: string().min(1)
4039
+ }).parse({
4040
+ name,
4041
+ prompt
4042
+ });
4043
+ console.log(await runLocalAgent(input.name, input.prompt));
4044
+ });
4045
+ 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");
4046
+ 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) => {
4047
+ await setSecret(secretNameSchema.parse(name), secretOptionsSchema.parse(command.optsWithGlobals()));
4048
+ });
4049
+ 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) => {
4050
+ await dropSecret(secretNameSchema.parse(name), secretOptionsSchema.parse(command.optsWithGlobals()).org);
4051
+ });
3126
4052
  await program.parseAsync();
3127
4053
  //#endregion
3128
4054
  export {};