theokit 0.47.0 → 0.48.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.
Files changed (79) hide show
  1. package/dist/{actions-virtual-module-PUYSUA5O.js → actions-virtual-module-2VVLVXHY.js} +3 -3
  2. package/dist/{actions-virtual-module-Z76RNOJC.js → actions-virtual-module-Z5LXAX7E.js} +5 -4
  3. package/dist/actions-virtual-module-Z5LXAX7E.js.map +1 -0
  4. package/dist/{agent-3VDG5XK5.js → agent-Y3JKRROD.js} +2 -2
  5. package/dist/{app-typed-client-QYMZWXAW.js → app-typed-client-N4I4RBLT.js} +3 -3
  6. package/dist/{app-typed-client-VLT4FBKE.js → app-typed-client-NI3CM2FA.js} +5 -4
  7. package/dist/app-typed-client-NI3CM2FA.js.map +1 -0
  8. package/dist/boot/index.js +1 -1
  9. package/dist/{build-6KKFX33J.js → build-SJQDRD2B.js} +2 -2
  10. package/dist/chunk-6E5WKMDS.js +67 -0
  11. package/dist/chunk-6E5WKMDS.js.map +1 -0
  12. package/dist/{chunk-FZG3JYB3.js → chunk-7ZOQN7UH.js} +1 -1
  13. package/dist/{chunk-U3H53IIN.js → chunk-FO55VGMQ.js} +3 -3
  14. package/dist/{chunk-ELDTTO6P.js → chunk-GEHX6CAE.js} +2 -2
  15. package/dist/{chunk-7SABX4DJ.js → chunk-IZ3TIL6K.js} +28 -2
  16. package/dist/{chunk-7SABX4DJ.js.map → chunk-IZ3TIL6K.js.map} +1 -1
  17. package/dist/{chunk-B7XHGEDH.js → chunk-O5W7XSUX.js} +36 -36
  18. package/dist/chunk-O5W7XSUX.js.map +1 -0
  19. package/dist/{chunk-EIRQM55C.js → chunk-OJLL4YD6.js} +5 -46
  20. package/dist/chunk-OJLL4YD6.js.map +1 -0
  21. package/dist/{chunk-XTM32FF6.js → chunk-VQIUTCK2.js} +28 -2
  22. package/dist/{chunk-XTM32FF6.js.map → chunk-VQIUTCK2.js.map} +1 -1
  23. package/dist/{chunk-VPV7WABO.js → chunk-VTJMND23.js} +2 -2
  24. package/dist/{chunk-37ZO643S.js → chunk-XALU5LCU.js} +3 -3
  25. package/dist/{chunk-SEELKQUM.js → chunk-Y2KHTD2W.js} +6 -2
  26. package/dist/chunk-Y2KHTD2W.js.map +1 -0
  27. package/dist/{chunk-4TLLWXWH.js → chunk-YRRWQDKK.js} +11 -9
  28. package/dist/chunk-YRRWQDKK.js.map +1 -0
  29. package/dist/{chunk-OGU2MIHC.js → chunk-ZALJIZH2.js} +6 -6
  30. package/dist/cli/index.js +27 -5
  31. package/dist/cli/index.js.map +1 -1
  32. package/dist/{dev-4NLBCCLU.js → dev-6TWDBX6G.js} +5 -5
  33. package/dist/doctor-Y53QTUSP.js +56 -0
  34. package/dist/doctor-Y53QTUSP.js.map +1 -0
  35. package/dist/index.js +6 -5
  36. package/dist/index.js.map +1 -1
  37. package/dist/{internal-api-C5UJG3E2.js → internal-api-REGN3WMX.js} +8 -6
  38. package/dist/{internal-api-XAQ7H73N.js → internal-api-XQA2L663.js} +3 -3
  39. package/dist/{mcp-TJIUDFY2.js → mcp-CO4AGAXV.js} +2 -2
  40. package/dist/server/agent/index.d.ts +90 -1
  41. package/dist/server/agent/index.js +14 -2
  42. package/dist/server/cost/index.d.ts +1 -0
  43. package/dist/server/cost/index.js +3 -1
  44. package/dist/server/http/index.js +2 -2
  45. package/dist/server/index.d.ts +496 -3
  46. package/dist/server/index.js +486 -7
  47. package/dist/server/index.js.map +1 -1
  48. package/dist/{server-error-to-envelope-UM7DEVM4.js → server-error-to-envelope-2MQOME5Q.js} +2 -2
  49. package/dist/{server-error-to-envelope-J5NFZGCQ.js → server-error-to-envelope-4TGCDQ2S.js} +2 -2
  50. package/dist/sessions-gc-H4WC4IXB.js +38 -0
  51. package/dist/sessions-gc-H4WC4IXB.js.map +1 -0
  52. package/dist/{start-XPQ4EJ6J.js → start-IO3ZYGEX.js} +4 -4
  53. package/dist/vite-plugin/index.js +6 -5
  54. package/dist/{vite-plugin-CD67YAD5.js → vite-plugin-NQ6F7FGV.js} +5 -5
  55. package/package.json +5 -5
  56. package/dist/actions-virtual-module-Z76RNOJC.js.map +0 -1
  57. package/dist/app-typed-client-VLT4FBKE.js.map +0 -1
  58. package/dist/chunk-4TLLWXWH.js.map +0 -1
  59. package/dist/chunk-B7XHGEDH.js.map +0 -1
  60. package/dist/chunk-EIRQM55C.js.map +0 -1
  61. package/dist/chunk-SEELKQUM.js.map +0 -1
  62. /package/dist/{actions-virtual-module-PUYSUA5O.js.map → actions-virtual-module-2VVLVXHY.js.map} +0 -0
  63. /package/dist/{agent-3VDG5XK5.js.map → agent-Y3JKRROD.js.map} +0 -0
  64. /package/dist/{app-typed-client-QYMZWXAW.js.map → app-typed-client-N4I4RBLT.js.map} +0 -0
  65. /package/dist/{build-6KKFX33J.js.map → build-SJQDRD2B.js.map} +0 -0
  66. /package/dist/{chunk-FZG3JYB3.js.map → chunk-7ZOQN7UH.js.map} +0 -0
  67. /package/dist/{chunk-U3H53IIN.js.map → chunk-FO55VGMQ.js.map} +0 -0
  68. /package/dist/{chunk-ELDTTO6P.js.map → chunk-GEHX6CAE.js.map} +0 -0
  69. /package/dist/{chunk-VPV7WABO.js.map → chunk-VTJMND23.js.map} +0 -0
  70. /package/dist/{chunk-37ZO643S.js.map → chunk-XALU5LCU.js.map} +0 -0
  71. /package/dist/{chunk-OGU2MIHC.js.map → chunk-ZALJIZH2.js.map} +0 -0
  72. /package/dist/{dev-4NLBCCLU.js.map → dev-6TWDBX6G.js.map} +0 -0
  73. /package/dist/{internal-api-C5UJG3E2.js.map → internal-api-REGN3WMX.js.map} +0 -0
  74. /package/dist/{internal-api-XAQ7H73N.js.map → internal-api-XQA2L663.js.map} +0 -0
  75. /package/dist/{mcp-TJIUDFY2.js.map → mcp-CO4AGAXV.js.map} +0 -0
  76. /package/dist/{server-error-to-envelope-UM7DEVM4.js.map → server-error-to-envelope-2MQOME5Q.js.map} +0 -0
  77. /package/dist/{server-error-to-envelope-J5NFZGCQ.js.map → server-error-to-envelope-4TGCDQ2S.js.map} +0 -0
  78. /package/dist/{start-XPQ4EJ6J.js.map → start-IO3ZYGEX.js.map} +0 -0
  79. /package/dist/{vite-plugin-CD67YAD5.js.map → vite-plugin-NQ6F7FGV.js.map} +0 -0
@@ -61,7 +61,7 @@ import {
61
61
  resolveTransformer,
62
62
  superjsonTransformer,
63
63
  validateRouteInput
64
- } from "../chunk-U3H53IIN.js";
64
+ } from "../chunk-FO55VGMQ.js";
65
65
  import {
66
66
  ActionError,
67
67
  ActionInputError,
@@ -88,7 +88,7 @@ import {
88
88
  runMiddlewareAndContext,
89
89
  sendError,
90
90
  sendJson
91
- } from "../chunk-37ZO643S.js";
91
+ } from "../chunk-XALU5LCU.js";
92
92
  import {
93
93
  DuplicateContextKeyError,
94
94
  createOutbox,
@@ -176,7 +176,7 @@ import {
176
176
  TheoError,
177
177
  fromUnknown,
178
178
  serverErrorToEnvelope
179
- } from "../chunk-7SABX4DJ.js";
179
+ } from "../chunk-IZ3TIL6K.js";
180
180
  import {
181
181
  CodeModePermissionDeniedError,
182
182
  InProcessApprovalRequiredError,
@@ -191,13 +191,20 @@ import {
191
191
  parseChannelPath,
192
192
  serveMcpStdio,
193
193
  streamAgentTurnInProcess
194
- } from "../chunk-FZG3JYB3.js";
194
+ } from "../chunk-7ZOQN7UH.js";
195
195
  import {
196
196
  buildResourceDescriptors,
197
197
  defineAppResource,
198
198
  extractAppResources,
199
199
  readAppResource
200
200
  } from "../chunk-YOIVCCZT.js";
201
+ import {
202
+ listProviders,
203
+ registerProvider,
204
+ resetProviderRegistry,
205
+ resolveProvider,
206
+ tryResolveProvider
207
+ } from "../chunk-6E5WKMDS.js";
201
208
  import {
202
209
  AuthRequiredError,
203
210
  _resetKeyCacheForTests,
@@ -239,9 +246,10 @@ import {
239
246
  } from "../chunk-JA2ZAT5Q.js";
240
247
  import {
241
248
  InMemoryUsageStorage,
249
+ InMemoryUsageStorage2,
242
250
  trackAgentRun,
243
251
  trackAgentTools
244
- } from "../chunk-SEELKQUM.js";
252
+ } from "../chunk-Y2KHTD2W.js";
245
253
  import {
246
254
  CRON_MANIFEST_SCHEMA_VERSION,
247
255
  DuplicateCronNameError,
@@ -788,8 +796,8 @@ function createCacheEngine(opts) {
788
796
  function claimAndRun(key, fn, options, skipWrite) {
789
797
  let resolveOuter;
790
798
  let rejectOuter;
791
- const outerPromise = new Promise((resolve2, reject) => {
792
- resolveOuter = resolve2;
799
+ const outerPromise = new Promise((resolve3, reject) => {
800
+ resolveOuter = resolve3;
793
801
  rejectOuter = reject;
794
802
  });
795
803
  void outerPromise.catch(() => {
@@ -1178,6 +1186,458 @@ var CTX_WRITERS = {
1178
1186
  jobsQueue: "jobBackend"
1179
1187
  };
1180
1188
 
1189
+ // src/config/layered-config.ts
1190
+ import { foldLayers, verifyLayerOrdering } from "@theokit/agents";
1191
+ var LayerOutOfOrderError = class extends Error {
1192
+ name = "LayerOutOfOrderError";
1193
+ };
1194
+ var LayeredConfig = {
1195
+ /**
1196
+ * Fold the chain, validate the result, and report where everything came from.
1197
+ *
1198
+ * The schema is applied AFTER folding, never per layer. Validating each layer separately would
1199
+ * force every file to be complete, which defeats layering: a project override that sets one key
1200
+ * would have to restate the whole config.
1201
+ *
1202
+ * @throws {LayerOutOfOrderError} when a layer does not outrank the one before it.
1203
+ */
1204
+ resolve(input) {
1205
+ assertOrdering(input.layers);
1206
+ const accumulating = input.accumulatingKeys ?? [];
1207
+ const folded = foldLayers(input.layers, accumulating);
1208
+ const value = input.schema.parse(folded);
1209
+ return {
1210
+ value,
1211
+ provenancePerKey: buildProvenance(input.layers, accumulating),
1212
+ precedenceReport: buildReport(input.layers)
1213
+ };
1214
+ }
1215
+ };
1216
+ function assertOrdering(layers) {
1217
+ try {
1218
+ verifyLayerOrdering(layers);
1219
+ } catch (error) {
1220
+ throw new LayerOutOfOrderError(error.message);
1221
+ }
1222
+ }
1223
+ function contributorsOf(layers, key) {
1224
+ return layers.filter((layer) => key in layer.values).map((layer) => layer.layer);
1225
+ }
1226
+ function buildProvenance(layers, accumulating) {
1227
+ const keys = new Set(layers.flatMap((layer) => Object.keys(layer.values)));
1228
+ const provenance = {};
1229
+ for (const key of keys) {
1230
+ const contributors = contributorsOf(layers, key);
1231
+ const winner = contributors.at(-1);
1232
+ if (winner === void 0) continue;
1233
+ provenance[key] = accumulating.includes(key) ? contributors.join(", ") : winner;
1234
+ }
1235
+ return provenance;
1236
+ }
1237
+ function buildReport(layers) {
1238
+ const declared = layers.map((layer) => layer.layer);
1239
+ const contributed = new Set(
1240
+ layers.filter((layer) => Object.keys(layer.values).length > 0).map((layer) => layer.layer)
1241
+ );
1242
+ const measured = declared.filter((name) => contributed.has(name));
1243
+ const declaredButSilent = declared.filter((name) => !contributed.has(name));
1244
+ return {
1245
+ declared,
1246
+ measured,
1247
+ declaredButSilent,
1248
+ diverges: declaredButSilent.length > 0
1249
+ };
1250
+ }
1251
+
1252
+ // src/config/trust-store.ts
1253
+ import { chmodSync, existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
1254
+ import { dirname } from "path";
1255
+ import { resolveTrustPosture } from "@theokit/agents";
1256
+ import { atomicWriteJson, withFileLock } from "@theokit/agents/persistence";
1257
+ var TrustStorePermissionsError = class extends Error {
1258
+ constructor(file, mode) {
1259
+ super(
1260
+ `trust store ${file} is mode ${mode.toString(8)} \u2014 group or world writable. This file decides which directories may run shell hooks, so a writable store is a way to grant that to yourself. Refused rather than repaired: tightening it silently would hide that something changed the mode. Fix with \`chmod 600 ${file}\`.`
1261
+ );
1262
+ this.file = file;
1263
+ this.mode = mode;
1264
+ }
1265
+ file;
1266
+ mode;
1267
+ name = "TrustStorePermissionsError";
1268
+ };
1269
+ var FORBIDDEN_WRITE_BITS = 18;
1270
+ var TrustStore = class {
1271
+ constructor(file) {
1272
+ this.file = file;
1273
+ }
1274
+ file;
1275
+ /**
1276
+ * Read the store, refusing a file other users can write.
1277
+ *
1278
+ * A missing store is not an error — it is a machine that has trusted nothing yet, which is the
1279
+ * correct starting state and the safe one.
1280
+ */
1281
+ read() {
1282
+ if (!existsSync2(this.file)) return [];
1283
+ this.assertSafePermissions();
1284
+ const parsed = JSON.parse(readFileSync2(this.file, "utf8"));
1285
+ return parsed.records;
1286
+ }
1287
+ /**
1288
+ * Record a decision about `path`, replacing any previous one for it.
1289
+ *
1290
+ * `decidedAt` and `decidedBy` are ARGUMENTS, not derived here (DIP): the clock and the identity
1291
+ * belong to the caller, and baking `new Date()` in would make every assertion about the record
1292
+ * depend on when the test ran.
1293
+ *
1294
+ * ASYNC because both `withFileLock` and `atomicWriteJson` are. Measured, not assumed: the first
1295
+ * draft called them synchronously and `trust()` returned before the bytes landed, so an immediate
1296
+ * `read()` saw an empty store. Same shape as the M71 pointer bug, and same cause — the SDK's
1297
+ * `.d.ts` does not declare these, so nothing at compile time says they return a Promise
1298
+ * (usetheodev/theokit-sdk#280).
1299
+ */
1300
+ async trust(record) {
1301
+ mkdirSync(dirname(this.file), { recursive: true });
1302
+ await withFileLock(
1303
+ this.file,
1304
+ async () => {
1305
+ const existing = existsSync2(this.file) ? this.read() : [];
1306
+ const records = [...existing.filter((r) => r.path !== record.path), record];
1307
+ await atomicWriteJson(this.file, {
1308
+ version: 1,
1309
+ records
1310
+ });
1311
+ chmodSync(this.file, 384);
1312
+ }
1313
+ );
1314
+ }
1315
+ /**
1316
+ * The recorded posture for `path`, or an UNTRUSTED posture when nothing was recorded.
1317
+ *
1318
+ * Absence resolves to untrusted, never to "unknown, proceed". A store that answered "I do not
1319
+ * know" would push the decision back to the caller, and the caller asking is what the store
1320
+ * exists to answer.
1321
+ */
1322
+ postureFor(path, capabilities) {
1323
+ const record = this.read().find((r) => r.path === path);
1324
+ return resolveTrustPosture({
1325
+ capabilities: [...capabilities],
1326
+ isTrusted: () => record?.trusted === true
1327
+ });
1328
+ }
1329
+ assertSafePermissions() {
1330
+ const mode = statSync2(this.file).mode & 511;
1331
+ if ((mode & FORBIDDEN_WRITE_BITS) !== 0) {
1332
+ throw new TrustStorePermissionsError(this.file, mode);
1333
+ }
1334
+ }
1335
+ };
1336
+
1337
+ // src/config/custom-commands.ts
1338
+ import { readFileSync as readFileSync3, readdirSync, statSync as statSync3 } from "fs";
1339
+ import { basename, extname, join } from "path";
1340
+
1341
+ // src/config/frontmatter.ts
1342
+ var FENCE = "---";
1343
+ function splitFrontmatter(raw) {
1344
+ const lines = raw.split("\n");
1345
+ if (lines[0]?.trim() !== FENCE) return { frontmatter: [], body: raw };
1346
+ const closing = lines.indexOf(FENCE, 1);
1347
+ if (closing === -1) return void 0;
1348
+ return { frontmatter: lines.slice(1, closing), body: lines.slice(closing + 1).join("\n") };
1349
+ }
1350
+ function frontmatterValue(frontmatter, key) {
1351
+ const prefix = `${key}:`;
1352
+ for (const line of frontmatter) {
1353
+ if (!line.startsWith(prefix)) continue;
1354
+ const value = line.slice(prefix.length).trim();
1355
+ const unquoted = /^(["'])(.*)\1$/.exec(value);
1356
+ return unquoted?.[2] ?? value;
1357
+ }
1358
+ return void 0;
1359
+ }
1360
+
1361
+ // src/config/custom-commands.ts
1362
+ var COMMANDS_DIR = join(".theokit", "commands");
1363
+ var IGNORE_WARNING = () => void 0;
1364
+ function loadCustomCommands(input) {
1365
+ const warn = input.onWarn ?? IGNORE_WARNING;
1366
+ const loaded = /* @__PURE__ */ new Map();
1367
+ if (input.homeDir !== void 0) {
1368
+ for (const command of readCommandsDir(join(input.homeDir, COMMANDS_DIR), "user", warn)) {
1369
+ loaded.set(command.name, command);
1370
+ }
1371
+ }
1372
+ if (input.projectDir !== void 0) {
1373
+ if (!input.projectTrusted) {
1374
+ const pending = readCommandsDir(
1375
+ join(input.projectDir, COMMANDS_DIR),
1376
+ "project",
1377
+ IGNORE_WARNING
1378
+ );
1379
+ if (pending.length > 0) {
1380
+ warn(
1381
+ `${String(pending.length)} project command(s) found but the directory is not trusted \u2014 none were loaded. A command is a prompt that runs on your behalf.`
1382
+ );
1383
+ }
1384
+ } else {
1385
+ for (const command of readCommandsDir(
1386
+ join(input.projectDir, COMMANDS_DIR),
1387
+ "project",
1388
+ warn
1389
+ )) {
1390
+ const shadowed = loaded.get(command.name);
1391
+ if (shadowed !== void 0) {
1392
+ warn(
1393
+ `project command "${command.name}" overrides the user-level one at ${shadowed.path}.`
1394
+ );
1395
+ }
1396
+ loaded.set(command.name, command);
1397
+ }
1398
+ }
1399
+ }
1400
+ const builtins = new Set(input.builtinNames ?? []);
1401
+ const shadowedBuiltins = [...loaded.keys()].filter((name) => builtins.has(name));
1402
+ for (const name of shadowedBuiltins) {
1403
+ warn(
1404
+ `custom command "${name}" has the same name as a builtin. This loader does not choose between them \u2014 the router decides, because only it knows what its builtins do.`
1405
+ );
1406
+ }
1407
+ return {
1408
+ // Project first in the returned order, matching the precedence a reader would expect.
1409
+ commands: [...loaded.values()].sort(byProjectThenName),
1410
+ shadowedBuiltins
1411
+ };
1412
+ }
1413
+ function byProjectThenName(a, b) {
1414
+ if (a.source !== b.source) return a.source === "project" ? -1 : 1;
1415
+ return a.name.localeCompare(b.name);
1416
+ }
1417
+ function readCommandsDir(dir, source, warn) {
1418
+ let entries;
1419
+ try {
1420
+ entries = readdirSync(dir);
1421
+ } catch {
1422
+ return [];
1423
+ }
1424
+ entries.sort((a, b) => a.localeCompare(b));
1425
+ const commands = [];
1426
+ for (const entry of entries) {
1427
+ if (extname(entry) !== ".md") continue;
1428
+ const path = join(dir, entry);
1429
+ try {
1430
+ if (!statSync3(path).isFile()) continue;
1431
+ } catch {
1432
+ continue;
1433
+ }
1434
+ const command = parseCommandFile(path, entry, source, warn);
1435
+ if (command !== void 0) commands.push(command);
1436
+ }
1437
+ return commands;
1438
+ }
1439
+ function parseCommandFile(path, entry, source, warn) {
1440
+ let raw;
1441
+ try {
1442
+ raw = readFileSync3(path, "utf8");
1443
+ } catch {
1444
+ return void 0;
1445
+ }
1446
+ const parsed = splitFrontmatter(raw);
1447
+ if (parsed === void 0) {
1448
+ warn(`command frontmatter never closes, file skipped: ${path}`);
1449
+ return void 0;
1450
+ }
1451
+ const description = frontmatterValue(parsed.frontmatter, "description");
1452
+ return {
1453
+ name: basename(entry, ".md"),
1454
+ ...description !== void 0 && { description },
1455
+ body: parsed.body,
1456
+ source,
1457
+ path
1458
+ };
1459
+ }
1460
+
1461
+ // src/config/instruction-tree.ts
1462
+ import { readFileSync as readFileSync4, readdirSync as readdirSync2, statSync as statSync4 } from "fs";
1463
+ import { join as join2, relative, resolve as resolve2 } from "path";
1464
+ import { assertNoSymlinkEscape } from "@theokit/agents";
1465
+ var DEFAULT_FILE_NAMES = ["THEO.md", "AGENTS.md"];
1466
+ var IGNORE_WARNING2 = () => void 0;
1467
+ function loadInstructionTree(input) {
1468
+ const warn = input.onWarn ?? IGNORE_WARNING2;
1469
+ const fileNames = input.fileNames ?? DEFAULT_FILE_NAMES;
1470
+ const cwd = resolve2(input.cwd);
1471
+ const blocks = [];
1472
+ const seenInodes = /* @__PURE__ */ new Set();
1473
+ let chars = 0;
1474
+ const visit = (dir, depth) => {
1475
+ if (depth > input.budget.maxDepth) return false;
1476
+ let entries;
1477
+ try {
1478
+ entries = readdirSync2(dir);
1479
+ } catch {
1480
+ return false;
1481
+ }
1482
+ for (const { entry, path, stats } of filesBeforeDirectories(dir, entries)) {
1483
+ const inode = `${String(stats.dev)}:${String(stats.ino)}`;
1484
+ if (seenInodes.has(inode)) continue;
1485
+ seenInodes.add(inode);
1486
+ if (stats.isDirectory()) {
1487
+ if (visit(path, depth + 1)) return true;
1488
+ continue;
1489
+ }
1490
+ if (!fileNames.includes(entry)) continue;
1491
+ try {
1492
+ ;
1493
+ assertNoSymlinkEscape(path, cwd);
1494
+ } catch {
1495
+ warn(`instruction file escapes the project root and was skipped: ${relative(cwd, path)}`);
1496
+ continue;
1497
+ }
1498
+ if (blocks.length >= input.budget.maxFiles) {
1499
+ warn(`instruction budget: stopped at ${String(input.budget.maxFiles)} files`);
1500
+ return true;
1501
+ }
1502
+ const parsed = parseInstructionFile(path, cwd, warn);
1503
+ if (parsed === void 0) continue;
1504
+ if (chars + parsed.content.length > input.budget.maxChars) {
1505
+ warn(`instruction budget: stopped at ${String(input.budget.maxChars)} characters`);
1506
+ return true;
1507
+ }
1508
+ chars += parsed.content.length;
1509
+ blocks.push(parsed);
1510
+ }
1511
+ return false;
1512
+ };
1513
+ let truncated = false;
1514
+ for (const root of input.roots) {
1515
+ truncated = visit(resolve2(cwd, root), 0);
1516
+ if (truncated) break;
1517
+ }
1518
+ return { blocks, truncated, count: blocks.length };
1519
+ }
1520
+ function filesBeforeDirectories(dir, entries) {
1521
+ const found = [];
1522
+ for (const entry of [...entries].sort((a, b) => a.localeCompare(b))) {
1523
+ const path = join2(dir, entry);
1524
+ try {
1525
+ found.push({ entry, path, stats: statSync4(path) });
1526
+ } catch {
1527
+ continue;
1528
+ }
1529
+ }
1530
+ return [
1531
+ ...found.filter((item) => !item.stats.isDirectory()),
1532
+ ...found.filter((item) => item.stats.isDirectory())
1533
+ ];
1534
+ }
1535
+ function parseInstructionFile(path, cwd, warn) {
1536
+ let raw;
1537
+ try {
1538
+ raw = readFileSync4(path, "utf8");
1539
+ } catch {
1540
+ return void 0;
1541
+ }
1542
+ const rel = relative(cwd, path);
1543
+ const parsed = splitFrontmatter(raw);
1544
+ if (parsed === void 0) {
1545
+ warn(`instruction frontmatter never closes, file skipped: ${rel}`);
1546
+ return void 0;
1547
+ }
1548
+ return {
1549
+ path: rel,
1550
+ content: parsed.body,
1551
+ scopes: parsePathsScope(parsed.frontmatter)
1552
+ };
1553
+ }
1554
+ function parsePathsScope(frontmatter) {
1555
+ const scopes = [];
1556
+ let inPaths = false;
1557
+ for (const line of frontmatter) {
1558
+ if (/^paths\s*:/.test(line)) {
1559
+ inPaths = true;
1560
+ const inline = line.slice(line.indexOf(":") + 1).trim();
1561
+ if (inline.startsWith("[")) {
1562
+ return inline.slice(1, inline.lastIndexOf("]")).split(",").map((item2) => item2.trim().replaceAll(/^["']|["']$/g, "")).filter((item2) => item2.length > 0);
1563
+ }
1564
+ continue;
1565
+ }
1566
+ if (!inPaths) continue;
1567
+ const item = /^ {0,32}- {0,32}(\S.*)$/.exec(line);
1568
+ if (item?.[1] === void 0) break;
1569
+ scopes.push(item[1].trim().replaceAll(/^["']|["']$/g, ""));
1570
+ }
1571
+ return scopes;
1572
+ }
1573
+
1574
+ // src/config/compose-instructions.ts
1575
+ var DEFAULT_SEPARATOR = "\n\n";
1576
+ var IGNORE_WARNING3 = () => void 0;
1577
+ function composeInstructions(base, sources, options) {
1578
+ const warn = options.onWarn ?? IGNORE_WARNING3;
1579
+ const separator = options.separator ?? DEFAULT_SEPARATOR;
1580
+ if (base.length >= options.maxChars) {
1581
+ warn(
1582
+ `instruction budget: the base prompt alone is ${String(base.length)} characters against a ceiling of ${String(options.maxChars)}. It was truncated and every source was dropped.`
1583
+ );
1584
+ return {
1585
+ text: base.slice(0, options.maxChars),
1586
+ dropped: sources.map((source) => source.name),
1587
+ trimmed: "base"
1588
+ };
1589
+ }
1590
+ const kept = [...sources];
1591
+ const dropped = [];
1592
+ let trimmed;
1593
+ const lengthOf = (list) => [base, ...list.map((source) => source.content)].join(separator).length;
1594
+ while (kept.length > 0 && lengthOf(kept) > options.maxChars) {
1595
+ const last = kept.at(-1);
1596
+ if (last === void 0) break;
1597
+ const withoutLast = kept.slice(0, -1);
1598
+ const room = options.maxChars - lengthOf(withoutLast) - separator.length;
1599
+ if (room > 0 && trimmed === void 0) {
1600
+ kept[kept.length - 1] = { ...last, content: last.content.slice(0, room) };
1601
+ trimmed = last.name;
1602
+ warn(
1603
+ `instruction budget: "${last.name}" was trimmed to ${String(room)} characters to fit the ${String(options.maxChars)}-character ceiling.`
1604
+ );
1605
+ break;
1606
+ }
1607
+ kept.pop();
1608
+ dropped.push(last.name);
1609
+ warn(`instruction budget: "${last.name}" was dropped to fit the ceiling.`);
1610
+ }
1611
+ return {
1612
+ text: [base, ...kept.map((source) => source.content)].join(separator),
1613
+ dropped,
1614
+ ...trimmed !== void 0 && { trimmed }
1615
+ };
1616
+ }
1617
+
1618
+ // src/config/context-pressure.ts
1619
+ import { resolveEffectiveContextWindow } from "@theokit/agents";
1620
+ var DEFAULT_CONTEXT_PRESSURE_THRESHOLDS = {
1621
+ warn: 0.75,
1622
+ critical: 0.9
1623
+ };
1624
+ var ContextPressureThresholdError = class extends Error {
1625
+ name = "ContextPressureThresholdError";
1626
+ };
1627
+ function contextPressure(usedTokens, effectiveWindow, thresholds = DEFAULT_CONTEXT_PRESSURE_THRESHOLDS) {
1628
+ if (thresholds.warn >= thresholds.critical) {
1629
+ throw new ContextPressureThresholdError(
1630
+ `context pressure: \`warn\` (${String(thresholds.warn)}) must be below \`critical\` (${String(thresholds.critical)}), otherwise one of the two levels can never be reached.`
1631
+ );
1632
+ }
1633
+ if (!Number.isFinite(effectiveWindow) || effectiveWindow <= 0) return "ok";
1634
+ if (!Number.isFinite(usedTokens) || usedTokens <= 0) return "ok";
1635
+ const ratio = usedTokens / effectiveWindow;
1636
+ if (ratio >= thresholds.critical) return "critical";
1637
+ if (ratio >= thresholds.warn) return "warn";
1638
+ return "ok";
1639
+ }
1640
+
1181
1641
  // src/server/index.ts
1182
1642
  if (typeof globalThis !== "undefined") {
1183
1643
  const WARN_KEY = "__theokit_server_umbrella_warn_emitted__";
@@ -1212,7 +1672,9 @@ export {
1212
1672
  ChannelManager,
1213
1673
  CodeModePermissionDeniedError,
1214
1674
  ConsoleObservabilityAdapter,
1675
+ ContextPressureThresholdError,
1215
1676
  CsrfReadinessStore,
1677
+ DEFAULT_CONTEXT_PRESSURE_THRESHOLDS,
1216
1678
  DEFAULT_CSP,
1217
1679
  DEFAULT_EXCLUDED_QUERY_PARAMS,
1218
1680
  DEFAULT_MAX_BODY_BYTES,
@@ -1233,7 +1695,10 @@ export {
1233
1695
  InvalidPluginShapeError,
1234
1696
  JOB_MANIFEST_SCHEMA_VERSION,
1235
1697
  JsonStdoutSink,
1698
+ LayerOutOfOrderError,
1699
+ LayeredConfig,
1236
1700
  MAX_ERROR_HTML_BYTES,
1701
+ InMemoryUsageStorage2 as NeutralUsageStorage,
1237
1702
  NodeAcpTransport,
1238
1703
  NonRetryableError,
1239
1704
  NoopObservabilityAdapter,
@@ -1252,6 +1717,8 @@ export {
1252
1717
  TRACE_PARENT_HEADER,
1253
1718
  TheoCloudObservabilityAdapter,
1254
1719
  TheoError,
1720
+ TrustStore,
1721
+ TrustStorePermissionsError,
1255
1722
  _resetCacheEngine,
1256
1723
  _resetEnvCache,
1257
1724
  _resetKeyCacheForTests,
@@ -1272,6 +1739,8 @@ export {
1272
1739
  clearOidcCache,
1273
1740
  compilePattern,
1274
1741
  compileRouteRules,
1742
+ composeInstructions,
1743
+ contextPressure,
1275
1744
  convertToAwsCron,
1276
1745
  createACPTool,
1277
1746
  createCacheEngine,
@@ -1317,6 +1786,7 @@ export {
1317
1786
  deserializeResponse,
1318
1787
  discoverOidcProvider,
1319
1788
  dispatchWebhook,
1789
+ resolveEffectiveContextWindow as effectiveContextWindow,
1320
1790
  encrypt,
1321
1791
  enforceCsrf,
1322
1792
  envelopeCodeToStatus,
@@ -1329,6 +1799,7 @@ export {
1329
1799
  extractUniversalIssues,
1330
1800
  findSuggestion,
1331
1801
  fromUnknown,
1802
+ frontmatterValue,
1332
1803
  generateBackupCodes,
1333
1804
  generateManifest,
1334
1805
  generateNonce,
@@ -1356,8 +1827,11 @@ export {
1356
1827
  isInputError,
1357
1828
  jsonTransformer,
1358
1829
  levenshtein,
1830
+ listProviders,
1831
+ loadCustomCommands,
1359
1832
  loadCustomErrorPages,
1360
1833
  loadEnv,
1834
+ loadInstructionTree,
1361
1835
  loadManifest,
1362
1836
  logRequest,
1363
1837
  matchDisallowed,
@@ -1376,8 +1850,11 @@ export {
1376
1850
  readAppResource,
1377
1851
  readRawBody,
1378
1852
  recordAttempt,
1853
+ registerProvider,
1379
1854
  requireAuth,
1855
+ resetProviderRegistry,
1380
1856
  resolveAdapter,
1857
+ resolveProvider,
1381
1858
  resolveRouteRule,
1382
1859
  resolveTransformer,
1383
1860
  revalidatePath,
@@ -1405,6 +1882,7 @@ export {
1405
1882
  serveStaticFile,
1406
1883
  serverErrorToEnvelope,
1407
1884
  setCookie,
1885
+ splitFrontmatter,
1408
1886
  streamAgentTurnInProcess,
1409
1887
  superjsonTransformer,
1410
1888
  timingSafeEqual,
@@ -1416,6 +1894,7 @@ export {
1416
1894
  translateCronToCloudflare,
1417
1895
  translateCronToDeno,
1418
1896
  translateCronToVercel,
1897
+ tryResolveProvider,
1419
1898
  uiMessageStreamResponse,
1420
1899
  updateTag,
1421
1900
  useDatabase,