@theokit/agents 13.0.0 → 13.2.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 (34) hide show
  1. package/CHANGELOG.md +213 -0
  2. package/dist/{agent-compiler-B0hb6HCo.d.ts → agent-compiler-BaOZzU7Q.d.ts} +26 -3
  3. package/dist/auth.d.ts +28 -1
  4. package/dist/auth.js +58 -0
  5. package/dist/auth.js.map +1 -1
  6. package/dist/{bridge-entry-DBkqwe6b.d.ts → bridge-entry-BgWauyLQ.d.ts} +4 -4
  7. package/dist/bridge.d.ts +5 -5
  8. package/dist/bridge.js +4 -4
  9. package/dist/{chunk-HGVT4VCE.js → chunk-2SP5BB6U.js} +39 -6
  10. package/dist/chunk-2SP5BB6U.js.map +1 -0
  11. package/dist/{chunk-KTQID5V3.js → chunk-CBP72LFM.js} +9 -3
  12. package/dist/chunk-CBP72LFM.js.map +1 -0
  13. package/dist/{chunk-PMMOOXR6.js → chunk-PYVLRSXZ.js} +22 -2
  14. package/dist/chunk-PYVLRSXZ.js.map +1 -0
  15. package/dist/{chunk-G7QBDGZ4.js → chunk-SL3QW5WZ.js} +32 -7
  16. package/dist/{chunk-G7QBDGZ4.js.map → chunk-SL3QW5WZ.js.map} +1 -1
  17. package/dist/config.d.ts +154 -4
  18. package/dist/config.js +312 -14
  19. package/dist/config.js.map +1 -1
  20. package/dist/{define-agent-DhwNmdej.d.ts → define-agent-DOZL_0uP.d.ts} +2 -2
  21. package/dist/{delegation-scoring-BzJEheml.d.ts → delegation-scoring-DLsMQ4BJ.d.ts} +14 -2
  22. package/dist/index.d.ts +9 -9
  23. package/dist/index.js +4 -4
  24. package/dist/{setting-sources-gate-DFu51i50.d.ts → setting-sources-gate-BXdZmY78.d.ts} +7 -1
  25. package/dist/testing.d.ts +3 -3
  26. package/dist/testing.js +2 -1
  27. package/dist/testing.js.map +1 -1
  28. package/dist/tools.d.ts +3 -3
  29. package/dist/tools.js +3 -2
  30. package/dist/tools.js.map +1 -1
  31. package/package.json +1 -1
  32. package/dist/chunk-HGVT4VCE.js.map +0 -1
  33. package/dist/chunk-KTQID5V3.js.map +0 -1
  34. package/dist/chunk-PMMOOXR6.js.map +0 -1
package/dist/config.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { TheokitAgentError } from '@theokit/sdk/errors';
2
2
  import { z } from 'zod';
3
- import { TrustPosture, LayerValues } from '@theokit/sdk';
4
- export { DeclaredLayer, LayerValues } from '@theokit/sdk';
5
- import { R as ResolvedCompatSource } from './setting-sources-gate-DFu51i50.js';
3
+ import { TrustPosture, LayerValues, PermissionRule } from '@theokit/sdk';
4
+ export { DeclaredLayer, LayerValues, PermissionAction, PermissionRule } from '@theokit/sdk';
5
+ import { R as ResolvedCompatSource } from './setting-sources-gate-BXdZmY78.js';
6
6
  export { resolveEffectiveContextWindow as effectiveContextWindow } from '@theokit/sdk/compaction';
7
7
 
8
8
  /**
@@ -683,6 +683,156 @@ declare function layerPrecedence(layer: SettingsLayer): number;
683
683
  */
684
684
  declare function settingsLayerChain(values: Partial<Record<SettingsLayer, Readonly<Record<string, unknown>>>>): LayerValues[];
685
685
 
686
+ /**
687
+ * A style was named and could not be read.
688
+ *
689
+ * Typed, and carrying the directories it searched, because the whole point of the refusal is that
690
+ * the author learns WHICH lookup failed. `error-handling.md` § 2: fail fast, fail clear.
691
+ */
692
+ declare class OutputStyleError extends TheokitAgentError {
693
+ readonly name = "OutputStyleError";
694
+ constructor(message: string);
695
+ }
696
+ interface OutputStyle {
697
+ /** The filename without `.md` — what `outputStyle` in settings refers to. */
698
+ readonly name: string;
699
+ /** The body, which becomes a section of the system prompt. */
700
+ readonly content: string;
701
+ /** The `description` frontmatter key, when present. */
702
+ readonly description?: string;
703
+ /**
704
+ * `keep-coding-instructions: true` in frontmatter.
705
+ *
706
+ * The field with teeth. A style REPLACES the built-in software-engineering instructions by
707
+ * default, so a consumer who does not know that loses them without being told. Carried here so
708
+ * the decision belongs to the caller rather than to whoever wrote the style file.
709
+ */
710
+ readonly keepCodingInstructions: boolean;
711
+ }
712
+ interface LoadOutputStyleInput {
713
+ /** The style to load, from `settings.json`'s `outputStyle`. `undefined` means none was asked for. */
714
+ readonly name: string | undefined;
715
+ /** Project root. Its `.claude/output-styles/` wins over the home directory's. */
716
+ readonly cwd: string;
717
+ /** Home directory, for styles that apply across every project. Omit to search the project only. */
718
+ readonly homeDir?: string;
719
+ }
720
+ /**
721
+ * The named style, or `undefined` when none was requested.
722
+ *
723
+ * @throws OutputStyleError when a style IS named and no file backs it, listing the directories that
724
+ * were searched.
725
+ */
726
+ declare function loadOutputStyle(input: LoadOutputStyleInput): OutputStyle | undefined;
727
+ /**
728
+ * The style the project's settings name, read from the project's style files.
729
+ *
730
+ * The two halves of the documented mechanism, joined. `loadSettings` reads the `outputStyle` key and
731
+ * {@link loadOutputStyle} reads the file; until this existed nothing connected them, so a consumer
732
+ * had to find both modules and know that one feeds the other. Two halves each individually correct
733
+ * and jointly unreachable is the same defect as a capability with no caller — it just takes two
734
+ * files to make.
735
+ *
736
+ * Deliberately does NOT soften the loader: a style named in settings with no file behind it still
737
+ * throws {@link OutputStyleError}. Returning `undefined` there would restore the exact silence this
738
+ * work removed — configured, not applied, and no way to tell which.
739
+ *
740
+ * @throws OutputStyleError when settings name a style and no file backs it.
741
+ */
742
+ declare function resolveOutputStyle(input: {
743
+ readonly cwd: string;
744
+ readonly homeDir?: string;
745
+ readonly onWarn?: (message: string) => void;
746
+ }): OutputStyle | undefined;
747
+
748
+ /**
749
+ * Translate a settings `permissions` block into rules the SDK's engine evaluates.
750
+ *
751
+ * The SDK ships `PermissionEngine(rules, { defaultAction })` and it is a CODE surface: you construct
752
+ * it with `PermissionRule[]`. What was missing was the path from the FILE to those rules. Measured
753
+ * 2026-09-11: `permissions` appears in 13 SDK files, and the SDK reads `settings.json` in three, of
754
+ * which two are sourcemaps and the third describes the hooks shape. An operator writing
755
+ * `{ "permissions": { "deny": ["Bash(curl:*)"] } }` got a file nothing translated.
756
+ *
757
+ * ## Partial fidelity would be worse than absence
758
+ *
759
+ * A `deny` that silently fails to match is a control the operator believes is in force — strictly
760
+ * more dangerous than no rule, because without one they would have written the guard themselves. So
761
+ * every entry this module cannot render faithfully is RETURNED as unsupported, with a reason, and
762
+ * excluded from the rules. Nothing is quietly turned into a matcher that does not bite.
763
+ *
764
+ * ## What it deliberately does not attempt
765
+ *
766
+ * The reference's specifier language is larger than this: path globs with `~` expansion, per-tool
767
+ * argument names, and matching semantics that differ by tool. Implementing a lookalike would produce
768
+ * rules that match *almost* the right calls, which is the failure above. Two forms are translated —
769
+ * a bare tool name, and `Tool(prefix:*)` / `Tool(exact)` — and everything else is reported.
770
+ */
771
+
772
+ /** An entry that was understood well enough to refuse, but not well enough to translate. */
773
+ interface UnsupportedPermissionEntry {
774
+ /** The entry as written, so the operator can find it in their file. */
775
+ readonly entry: string;
776
+ /** Why it was not translated. */
777
+ readonly reason: string;
778
+ }
779
+ interface PermissionTranslation {
780
+ readonly rules: readonly PermissionRule[];
781
+ readonly unsupported: readonly UnsupportedPermissionEntry[];
782
+ }
783
+ /** The `permissions` block as a settings file may carry it. */
784
+ interface PermissionsBlock {
785
+ readonly allow?: readonly string[];
786
+ readonly deny?: readonly string[];
787
+ readonly ask?: readonly string[];
788
+ }
789
+ /**
790
+ * The rules a `permissions` block means, and the entries that could not be rendered.
791
+ *
792
+ * An absent or empty block yields nothing and reports nothing: most projects declare no permissions,
793
+ * and a translator that warned there would be noise in every one of them.
794
+ */
795
+ declare function permissionRulesFromSettings(block: PermissionsBlock | undefined): PermissionTranslation;
796
+
797
+ /**
798
+ * The keys this layer can act on today, plus everything else untouched.
799
+ *
800
+ * Typed narrowly on purpose: a key is listed here when something in this package reads it, not
801
+ * because the reference documents it. Declaring a field the code ignores would publish a control
802
+ * that does nothing, which is the shape every item in this batch had.
803
+ */
804
+ declare const SETTINGS_SCHEMA: z.ZodObject<{
805
+ outputStyle: z.ZodOptional<z.ZodString>;
806
+ env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
807
+ permissions: z.ZodOptional<z.ZodObject<{
808
+ allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
809
+ deny: z.ZodOptional<z.ZodArray<z.ZodString>>;
810
+ ask: z.ZodOptional<z.ZodArray<z.ZodString>>;
811
+ }, z.core.$loose>>;
812
+ }, z.core.$loose>;
813
+ type Settings = z.infer<typeof SETTINGS_SCHEMA>;
814
+ interface LoadSettingsInput {
815
+ /** Project root. Its `.claude/settings.json` and `.claude/settings.local.json` are read. */
816
+ readonly cwd: string;
817
+ /** Home directory, for the user-level file. Omit to read the project only. */
818
+ readonly homeDir?: string;
819
+ /** Where a file that exists and cannot be parsed is reported. */
820
+ readonly onWarn?: (message: string) => void;
821
+ }
822
+ interface LoadSettingsResult {
823
+ readonly values: Settings;
824
+ /** Which layer each resolved key came from. */
825
+ readonly provenancePerKey: Readonly<Record<string, string>>;
826
+ /** Which declared layers contributed nothing — a file nobody is reading is named, not hidden. */
827
+ readonly precedenceReport: PrecedenceReport;
828
+ }
829
+ /**
830
+ * The settings as the declared layers resolve them.
831
+ *
832
+ * Never throws for a missing or malformed file; see {@link readLayer}.
833
+ */
834
+ declare function loadSettings(input: LoadSettingsInput): LoadSettingsResult;
835
+
686
836
  /**
687
837
  * Split a markdown file into frontmatter lines and body.
688
838
  *
@@ -772,4 +922,4 @@ declare class ContextPressureThresholdError extends TheokitAgentError {
772
922
  */
773
923
  declare function contextPressure(usedTokens: number, effectiveWindow: number, thresholds?: ContextPressureThresholds): ContextPressure;
774
924
 
775
- export { type ComposeInstructionsOptions, type ComposedInstructions, type ConfigLayer, type ContextPressure, ContextPressureThresholdError, type ContextPressureThresholds, type CustomCommand, type CustomCommandsResult, DEFAULT_CONTEXT_PRESSURE_THRESHOLDS, type ExpandImportsInput, FILE_INLINE_CAP, type InstructionBlock, type InstructionSource, type InstructionTree, type InstructionTreeBudget, LAYERS_ARE_POSITIONED, LayerOutOfOrderError, LayeredConfig, type LayeredConfigInput, type LayeredConfigResult, type LoadCustomCommandsInput, type LoadInstructionTreeInput, type ParsedFrontmatter, type PrecedenceReport, type ProvenancePerKey, SETTINGS_LAYERS, type SettingsLayer, type ShellResult, type TemplateDeps, type TrustRecord, TrustStore, TrustStorePermissionsError, blockAppliesTo, composeInstructions, contextPressure, expandCommandTemplate, expandInstructionImports, frontmatterValue, layerPrecedence, loadCustomCommands, loadInstructionTree, settingsLayerChain, splitFrontmatter, templateHints };
925
+ export { type ComposeInstructionsOptions, type ComposedInstructions, type ConfigLayer, type ContextPressure, ContextPressureThresholdError, type ContextPressureThresholds, type CustomCommand, type CustomCommandsResult, DEFAULT_CONTEXT_PRESSURE_THRESHOLDS, type ExpandImportsInput, FILE_INLINE_CAP, type InstructionBlock, type InstructionSource, type InstructionTree, type InstructionTreeBudget, LAYERS_ARE_POSITIONED, LayerOutOfOrderError, LayeredConfig, type LayeredConfigInput, type LayeredConfigResult, type LoadCustomCommandsInput, type LoadInstructionTreeInput, type LoadOutputStyleInput, type LoadSettingsInput, type LoadSettingsResult, type OutputStyle, OutputStyleError, type ParsedFrontmatter, type PermissionTranslation, type PermissionsBlock, type PrecedenceReport, type ProvenancePerKey, SETTINGS_LAYERS, type Settings, type SettingsLayer, type ShellResult, type TemplateDeps, type TrustRecord, TrustStore, TrustStorePermissionsError, type UnsupportedPermissionEntry, blockAppliesTo, composeInstructions, contextPressure, expandCommandTemplate, expandInstructionImports, frontmatterValue, layerPrecedence, loadCustomCommands, loadInstructionTree, loadOutputStyle, loadSettings, permissionRulesFromSettings, resolveOutputStyle, settingsLayerChain, splitFrontmatter, templateHints };
package/dist/config.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  ensureSecureDir
3
3
  } from "./chunk-D2EFYZBV.js";
4
- import {
5
- currentOperatorPolicy
6
- } from "./chunk-HGVT4VCE.js";
7
4
  import {
8
5
  ConfigurationError
9
6
  } from "./chunk-U72XTMYB.js";
7
+ import {
8
+ currentOperatorPolicy
9
+ } from "./chunk-2SP5BB6U.js";
10
10
  import {
11
11
  __name
12
12
  } from "./chunk-Z4QWC7IK.js";
@@ -564,23 +564,61 @@ function composeInstructions(base, sources, options) {
564
564
  __name(composeInstructions, "composeInstructions");
565
565
 
566
566
  // src/config/custom-commands.ts
567
- import { readFileSync as readFileSync4, readdirSync as readdirSync2, statSync as statSync3 } from "fs";
568
- import { extname, join as join2, relative as relative2 } from "path";
569
- var COMMANDS_DIR = join2(".theokit", "commands");
570
- var COMPAT_COMMANDS_DIR = join2(".claude", "commands");
567
+ import { readFileSync as readFileSync4, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
568
+ import { extname, join as join3, relative as relative2 } from "path";
569
+
570
+ // src/bridge/unloaded-surfaces.ts
571
+ import { existsSync as existsSync3, readdirSync as readdirSync2 } from "fs";
572
+ import { join as join2 } from "path";
573
+ var WORKFLOWS_DIR = join2(".claude", "workflows");
574
+ var SCRIPT_SUFFIXES = [
575
+ ".js",
576
+ ".mjs",
577
+ ".cjs"
578
+ ];
579
+ function reportUnloadedSurfaces(input) {
580
+ const dir = join2(input.cwd, WORKFLOWS_DIR);
581
+ if (!existsSync3(dir)) return;
582
+ let scripts;
583
+ try {
584
+ scripts = readdirSync2(dir).filter((f) => SCRIPT_SUFFIXES.some((s) => f.endsWith(s)));
585
+ } catch {
586
+ return;
587
+ }
588
+ if (scripts.length === 0) return;
589
+ input.onWarn(`${WORKFLOWS_DIR}: found ${String(scripts.length)} workflow script(s) \u2014 ${[
590
+ ...scripts
591
+ ].sort((a, b) => a.localeCompare(b)).join(", ")} \u2014 which this runtime does NOT execute. Every configuration surface it loads is data (commands, hooks, plugins, skills, subagents); a workflow file is code, and executing JavaScript found under a caller-supplied directory is a trust decision that belongs to you rather than to this library. The orchestration itself is supported: build the same pipeline with Workflow / agentStep / createSquad from @theokit/sdk, which you import explicitly.`);
592
+ }
593
+ __name(reportUnloadedSurfaces, "reportUnloadedSurfaces");
594
+
595
+ // src/config/custom-commands.ts
596
+ var COMMANDS_DIR = join3(".theokit", "commands");
597
+ var COMPAT_COMMANDS_DIR = join3(".claude", "commands");
571
598
  var CLAUDE_CODE_SOURCE = "claude-code";
572
599
  var IGNORE_WARNING3 = /* @__PURE__ */ __name(() => void 0, "IGNORE_WARNING");
573
600
  function declaresCommands(sources) {
574
601
  return sources?.some((source) => typeof source === "string" ? source === CLAUDE_CODE_SOURCE : source.import.includes("commands")) === true;
575
602
  }
576
603
  __name(declaresCommands, "declaresCommands");
604
+ function declaresClaudeCode(sources) {
605
+ return sources?.some((source) => (
606
+ // The narrowed form IS a declaration of this dialect by construction — its `kind` is the one
607
+ // literal, which is why `declaresCommands` does not re-check it either and why the
608
+ // `NarrowedCompatSource` docblock says a second dialect must revisit both. Comparing it here
609
+ // would be a runtime check the type already makes, and `no-unnecessary-condition` is right
610
+ // about that: the type is not lying, there is exactly one dialect.
611
+ typeof source !== "string" || source === CLAUDE_CODE_SOURCE
612
+ )) === true;
613
+ }
614
+ __name(declaresClaudeCode, "declaresClaudeCode");
577
615
  function projectCommandDirs(input) {
578
616
  if (input.projectDir === void 0) return [];
579
617
  const dirs = [];
580
618
  if (declaresCommands(input.compatSources)) {
581
- dirs.push(join2(input.projectDir, COMPAT_COMMANDS_DIR));
619
+ dirs.push(join3(input.projectDir, COMPAT_COMMANDS_DIR));
582
620
  }
583
- dirs.push(join2(input.projectDir, COMMANDS_DIR));
621
+ dirs.push(join3(input.projectDir, COMMANDS_DIR));
584
622
  return dirs;
585
623
  }
586
624
  __name(projectCommandDirs, "projectCommandDirs");
@@ -606,8 +644,14 @@ __name(mergeProjectCommands, "mergeProjectCommands");
606
644
  function loadCustomCommands(input) {
607
645
  const warn = input.onWarn ?? IGNORE_WARNING3;
608
646
  const loaded = /* @__PURE__ */ new Map();
647
+ if (input.projectDir !== void 0 && declaresClaudeCode(input.compatSources)) {
648
+ reportUnloadedSurfaces({
649
+ cwd: input.projectDir,
650
+ onWarn: warn
651
+ });
652
+ }
609
653
  if (input.homeDir !== void 0) {
610
- for (const command of readCommandsDir(join2(input.homeDir, COMMANDS_DIR), "user", warn)) {
654
+ for (const command of readCommandsDir(join3(input.homeDir, COMMANDS_DIR), "user", warn)) {
611
655
  loaded.set(command.name, command);
612
656
  }
613
657
  }
@@ -636,14 +680,14 @@ __name(byProjectThenName, "byProjectThenName");
636
680
  function readCommandsDir(dir, source, warn, root = dir) {
637
681
  let entries;
638
682
  try {
639
- entries = readdirSync2(dir);
683
+ entries = readdirSync3(dir);
640
684
  } catch {
641
685
  return [];
642
686
  }
643
687
  entries.sort((a, b) => a.localeCompare(b));
644
688
  const commands = [];
645
689
  for (const entry of entries) {
646
- const path = join2(dir, entry);
690
+ const path = join3(dir, entry);
647
691
  let stats;
648
692
  try {
649
693
  stats = statSync3(path);
@@ -824,14 +868,263 @@ function settingsLayerChain(values) {
824
868
  }
825
869
  __name(settingsLayerChain, "settingsLayerChain");
826
870
 
871
+ // src/config/output-styles.ts
872
+ import { existsSync as existsSync5, readFileSync as readFileSync6 } from "fs";
873
+ import { join as join5 } from "path";
874
+ import { TheokitAgentError as TheokitAgentError3 } from "@theokit/sdk/errors";
875
+
876
+ // src/config/settings-file.ts
877
+ import { existsSync as existsSync4, readFileSync as readFileSync5 } from "fs";
878
+ import { join as join4 } from "path";
879
+ import { z } from "zod";
880
+ var SETTINGS_SCHEMA = z.looseObject({
881
+ /** Selects a file under `.claude/output-styles/`. Consumed by `loadOutputStyle`. */
882
+ outputStyle: z.string().optional(),
883
+ /** Environment variables for the session. */
884
+ env: z.record(z.string(), z.string()).optional(),
885
+ /**
886
+ * Tool permissions, as `settings-permissions.ts` translates them into `PermissionRule[]`.
887
+ *
888
+ * Typed here rather than left to the passthrough because the passthrough yields `unknown`, and a
889
+ * consumer would have to cast to reach it — a cast is where a wrong shape stops being checked. The
890
+ * SAFETY of this key depends on the translator seeing what the operator actually wrote.
891
+ */
892
+ permissions: z.object({
893
+ allow: z.array(z.string()).optional(),
894
+ deny: z.array(z.string()).optional(),
895
+ ask: z.array(z.string()).optional()
896
+ }).loose().optional()
897
+ });
898
+ var IGNORE_WARNING4 = /* @__PURE__ */ __name(() => void 0, "IGNORE_WARNING");
899
+ var FILE_LAYERS = [
900
+ {
901
+ layer: "user",
902
+ dir: "home",
903
+ file: "settings.json"
904
+ },
905
+ {
906
+ layer: "project-shared",
907
+ dir: "cwd",
908
+ file: "settings.json"
909
+ },
910
+ {
911
+ layer: "project-local",
912
+ dir: "cwd",
913
+ file: "settings.local.json"
914
+ }
915
+ ];
916
+ function readLayer(path, warn) {
917
+ if (!existsSync4(path)) return {};
918
+ try {
919
+ const parsed = JSON.parse(readFileSync5(path, "utf8"));
920
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
921
+ warn(`${path} is not a JSON object \u2014 it is NOT being applied.`);
922
+ return {};
923
+ }
924
+ return parsed;
925
+ } catch (error) {
926
+ warn(`${path} could not be parsed (${error.message}) \u2014 it is NOT being applied.`);
927
+ return {};
928
+ }
929
+ }
930
+ __name(readLayer, "readLayer");
931
+ function loadSettings(input) {
932
+ const warn = input.onWarn ?? IGNORE_WARNING4;
933
+ const layers = FILE_LAYERS.flatMap((entry) => {
934
+ const root = entry.dir === "home" ? input.homeDir : input.cwd;
935
+ if (root === void 0) return [];
936
+ const declared = SETTINGS_LAYERS.find((l) => l.layer === entry.layer);
937
+ if (declared === void 0) return [];
938
+ return [
939
+ {
940
+ layer: entry.layer,
941
+ precedence: declared.precedence,
942
+ values: readLayer(join4(root, ".claude", entry.file), warn)
943
+ }
944
+ ];
945
+ });
946
+ const ordered = [
947
+ ...layers
948
+ ].sort((a, b) => (a.precedence ?? 0) - (b.precedence ?? 0));
949
+ const resolved = LayeredConfig.resolve({
950
+ layers: ordered,
951
+ schema: SETTINGS_SCHEMA
952
+ });
953
+ return {
954
+ values: resolved.value,
955
+ provenancePerKey: resolved.provenancePerKey,
956
+ precedenceReport: resolved.precedenceReport
957
+ };
958
+ }
959
+ __name(loadSettings, "loadSettings");
960
+
961
+ // src/config/output-styles.ts
962
+ var OUTPUT_STYLES_DIR = join5(".claude", "output-styles");
963
+ var OutputStyleError = class extends TheokitAgentError3 {
964
+ static {
965
+ __name(this, "OutputStyleError");
966
+ }
967
+ name = "OutputStyleError";
968
+ constructor(message) {
969
+ super(`[@theokit/agents] ${message}`, {
970
+ code: "output_style_not_found",
971
+ isRetryable: false
972
+ });
973
+ }
974
+ };
975
+ function loadOutputStyle(input) {
976
+ if (input.name === void 0) return void 0;
977
+ const searched = [
978
+ join5(input.cwd, OUTPUT_STYLES_DIR),
979
+ ...input.homeDir === void 0 ? [] : [
980
+ join5(input.homeDir, OUTPUT_STYLES_DIR)
981
+ ]
982
+ ];
983
+ for (const dir of searched) {
984
+ const path = join5(dir, `${input.name}.md`);
985
+ if (!existsSync5(path)) continue;
986
+ const raw = readFileSync6(path, "utf8");
987
+ const parsed = splitFrontmatter(raw);
988
+ const body = parsed === void 0 ? raw : parsed.body;
989
+ const description = parsed === void 0 ? void 0 : frontmatterValue(parsed.frontmatter, "description");
990
+ return {
991
+ name: input.name,
992
+ content: body.trim(),
993
+ ...description === void 0 ? {} : {
994
+ description
995
+ },
996
+ keepCodingInstructions: parsed !== void 0 && frontmatterValue(parsed.frontmatter, "keep-coding-instructions") === "true"
997
+ };
998
+ }
999
+ throw new OutputStyleError(`output style "${input.name}" is configured and no file backs it. Looked for ${input.name}.md in: ${searched.join(", ")}. A style that cannot be read is not applied, and a silent fallback would be indistinguishable from a style that had no effect.`);
1000
+ }
1001
+ __name(loadOutputStyle, "loadOutputStyle");
1002
+ function resolveOutputStyle(input) {
1003
+ const settings = loadSettings(input);
1004
+ return loadOutputStyle({
1005
+ ...input,
1006
+ name: settings.values.outputStyle
1007
+ });
1008
+ }
1009
+ __name(resolveOutputStyle, "resolveOutputStyle");
1010
+
1011
+ // src/config/settings-permissions.ts
1012
+ var ACTIONS = [
1013
+ "deny",
1014
+ "ask",
1015
+ "allow"
1016
+ ];
1017
+ var MAX_TOOL = 64;
1018
+ var MAX_SPEC = 512;
1019
+ function splitEntry(entry) {
1020
+ const open = entry.indexOf("(");
1021
+ if (open === -1) return isToolName(entry) ? {
1022
+ tool: entry
1023
+ } : void 0;
1024
+ if (!entry.endsWith(")")) return void 0;
1025
+ const tool = entry.slice(0, open);
1026
+ const spec = entry.slice(open + 1, -1);
1027
+ if (!isToolName(tool) || spec.length > MAX_SPEC || spec.includes(")")) return void 0;
1028
+ return {
1029
+ tool,
1030
+ spec
1031
+ };
1032
+ }
1033
+ __name(splitEntry, "splitEntry");
1034
+ function isToolName(value) {
1035
+ if (value.length === 0 || value.length > MAX_TOOL) return false;
1036
+ return /^[A-Za-z_][\w-]*$/.test(value);
1037
+ }
1038
+ __name(isToolName, "isToolName");
1039
+ var UNTRANSLATABLE = /[*?[\]{}~]/;
1040
+ function escapeRegExp(literal) {
1041
+ return literal.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
1042
+ }
1043
+ __name(escapeRegExp, "escapeRegExp");
1044
+ function translate(entry, action) {
1045
+ const parsed = splitEntry(entry.trim());
1046
+ if (parsed === void 0) {
1047
+ return {
1048
+ entry,
1049
+ reason: "not of the form `Tool` or `Tool(specifier)`."
1050
+ };
1051
+ }
1052
+ const { tool, spec } = parsed;
1053
+ if (spec === void 0) return {
1054
+ tool,
1055
+ action
1056
+ };
1057
+ if (spec.length === 0) {
1058
+ return {
1059
+ entry,
1060
+ reason: "has an empty specifier \u2014 write `Tool` if you meant the whole tool."
1061
+ };
1062
+ }
1063
+ const prefix = spec.endsWith(":*") ? spec.slice(0, -2) : void 0;
1064
+ const literal = prefix ?? spec;
1065
+ if (UNTRANSLATABLE.test(literal)) {
1066
+ return {
1067
+ entry,
1068
+ reason: "uses glob or path syntax this runtime does not translate. It is NOT being applied \u2014 a rule that matched almost the right calls would be worse than none, because you would believe a control is in force. Express it in code with `PermissionRule` instead."
1069
+ };
1070
+ }
1071
+ return {
1072
+ tool,
1073
+ // Anchored at the start either way: unanchored, `Bash(ls)` would also deny `please ls`. The
1074
+ // prefix form stays open at the end, which is what `:*` means; the exact form closes with `$`
1075
+ // so `Bash(ls)` does not deny `ls-everything`.
1076
+ args: {
1077
+ // Built from the operator's own specifier, and escaped before it gets here so no metacharacter
1078
+ // of theirs survives into the pattern. `splitEntry` has already bounded its length, so the compiled
1079
+ // pattern is linear in a value this module controls the size of.
1080
+ // eslint-disable-next-line security/detect-non-literal-regexp -- the literal is escaped by `escapeRegExp` and length-bounded by `splitEntry`; the whole point of the module is to turn operator text into a matcher
1081
+ command: new RegExp(`^${escapeRegExp(literal)}${prefix === void 0 ? "$" : ""}`)
1082
+ },
1083
+ action
1084
+ };
1085
+ }
1086
+ __name(translate, "translate");
1087
+ function isRule(value) {
1088
+ return "tool" in value;
1089
+ }
1090
+ __name(isRule, "isRule");
1091
+ function permissionRulesFromSettings(block) {
1092
+ if (block === void 0) return {
1093
+ rules: [],
1094
+ unsupported: []
1095
+ };
1096
+ const rules = [];
1097
+ const unsupported = [];
1098
+ for (const key of Object.keys(block)) {
1099
+ if (!ACTIONS.includes(key)) {
1100
+ unsupported.push({
1101
+ entry: key,
1102
+ reason: `is not a permission action. Expected one of: ${ACTIONS.join(", ")}.`
1103
+ });
1104
+ }
1105
+ }
1106
+ for (const action of ACTIONS) {
1107
+ for (const entry of block[action] ?? []) {
1108
+ const translated = translate(entry, action);
1109
+ if (isRule(translated)) rules.push(translated);
1110
+ else unsupported.push(translated);
1111
+ }
1112
+ }
1113
+ return {
1114
+ rules,
1115
+ unsupported
1116
+ };
1117
+ }
1118
+ __name(permissionRulesFromSettings, "permissionRulesFromSettings");
1119
+
827
1120
  // src/config/context-pressure.ts
828
1121
  import { resolveEffectiveContextWindow } from "@theokit/sdk/compaction";
829
- import { TheokitAgentError as TheokitAgentError3 } from "@theokit/sdk/errors";
1122
+ import { TheokitAgentError as TheokitAgentError4 } from "@theokit/sdk/errors";
830
1123
  var DEFAULT_CONTEXT_PRESSURE_THRESHOLDS = {
831
1124
  warn: 0.75,
832
1125
  critical: 0.9
833
1126
  };
834
- var ContextPressureThresholdError = class extends TheokitAgentError3 {
1127
+ var ContextPressureThresholdError = class extends TheokitAgentError4 {
835
1128
  static {
836
1129
  __name(this, "ContextPressureThresholdError");
837
1130
  }
@@ -862,6 +1155,7 @@ export {
862
1155
  LAYERS_ARE_POSITIONED,
863
1156
  LayerOutOfOrderError,
864
1157
  LayeredConfig,
1158
+ OutputStyleError,
865
1159
  SETTINGS_LAYERS,
866
1160
  TrustStore,
867
1161
  TrustStorePermissionsError,
@@ -875,6 +1169,10 @@ export {
875
1169
  layerPrecedence,
876
1170
  loadCustomCommands,
877
1171
  loadInstructionTree,
1172
+ loadOutputStyle,
1173
+ loadSettings,
1174
+ permissionRulesFromSettings,
1175
+ resolveOutputStyle,
878
1176
  settingsLayerChain,
879
1177
  splitFrontmatter,
880
1178
  templateHints