@cruxy/cli 0.20.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/approval/classify.js +24 -0
- package/dist/approval/policy.js +7 -0
- package/dist/approval/prompt.js +7 -0
- package/dist/approval/types.d.ts +6 -0
- package/dist/brand/voice.d.ts +1 -1
- package/dist/brand/voice.js +1 -1
- package/dist/cli/commands/mcp.d.ts +9 -0
- package/dist/cli/commands/mcp.js +87 -0
- package/dist/cli/commands/run.js +22 -5
- package/dist/cli/program.js +2 -0
- package/dist/cli/session-factory.d.ts +2 -2
- package/dist/cli/session-factory.js +20 -2
- package/dist/config/schema.d.ts +362 -38
- package/dist/config/schema.js +100 -5
- package/dist/constants.d.ts +8 -0
- package/dist/constants.js +8 -0
- package/dist/errors/constructors.d.ts +46 -0
- package/dist/errors/constructors.js +123 -0
- package/dist/errors/types.d.ts +26 -0
- package/dist/errors/types.js +41 -0
- package/dist/lsp/transport.d.ts +6 -15
- package/dist/lsp/transport.js +10 -66
- package/dist/mcp/adapter.d.ts +44 -0
- package/dist/mcp/adapter.js +70 -0
- package/dist/mcp/bounds.d.ts +35 -0
- package/dist/mcp/bounds.js +36 -0
- package/dist/mcp/client.d.ts +19 -0
- package/dist/mcp/client.js +93 -0
- package/dist/mcp/demarcate.d.ts +12 -0
- package/dist/mcp/demarcate.js +71 -0
- package/dist/mcp/index.d.ts +9 -0
- package/dist/mcp/index.js +8 -0
- package/dist/mcp/service.d.ts +54 -0
- package/dist/mcp/service.js +99 -0
- package/dist/mcp/transport.d.ts +30 -0
- package/dist/mcp/transport.js +188 -0
- package/dist/mcp/trust-gate.d.ts +35 -0
- package/dist/mcp/trust-gate.js +40 -0
- package/dist/mcp/trust.d.ts +52 -0
- package/dist/mcp/trust.js +111 -0
- package/dist/mcp/types.d.ts +52 -0
- package/dist/mcp/types.js +7 -0
- package/dist/tools/registry.js +3 -1
- package/dist/tools/types.d.ts +15 -1
- package/dist/utils/child-tree.d.ts +35 -0
- package/dist/utils/child-tree.js +76 -0
- package/dist/web/demarcate.d.ts +13 -0
- package/dist/web/demarcate.js +78 -0
- package/dist/web/fetch.d.ts +11 -0
- package/dist/web/fetch.js +174 -0
- package/dist/web/index.d.ts +7 -0
- package/dist/web/index.js +7 -0
- package/dist/web/provider.d.ts +29 -0
- package/dist/web/provider.js +77 -0
- package/dist/web/search.d.ts +17 -0
- package/dist/web/search.js +42 -0
- package/dist/web/ssrf.d.ts +55 -0
- package/dist/web/ssrf.js +223 -0
- package/dist/web/tools.d.ts +20 -0
- package/dist/web/tools.js +81 -0
- package/dist/web/types.d.ts +62 -0
- package/dist/web/types.js +1 -0
- package/package.json +2 -1
package/dist/config/schema.d.ts
CHANGED
|
@@ -44,15 +44,12 @@ export declare const AgentConfigSchema: z.ZodObject<{
|
|
|
44
44
|
export declare const ToolsConfigSchema: z.ZodObject<{
|
|
45
45
|
fileEdit: z.ZodDefault<z.ZodBoolean>;
|
|
46
46
|
shell: z.ZodDefault<z.ZodBoolean>;
|
|
47
|
-
webSearch: z.ZodDefault<z.ZodBoolean>;
|
|
48
47
|
}, "strict", z.ZodTypeAny, {
|
|
49
48
|
fileEdit: boolean;
|
|
50
49
|
shell: boolean;
|
|
51
|
-
webSearch: boolean;
|
|
52
50
|
}, {
|
|
53
51
|
fileEdit?: boolean | undefined;
|
|
54
52
|
shell?: boolean | undefined;
|
|
55
|
-
webSearch?: boolean | undefined;
|
|
56
53
|
}>;
|
|
57
54
|
export declare const GitConfigSchema: z.ZodObject<{
|
|
58
55
|
autoCommit: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -446,16 +443,16 @@ export declare const LspConfigSchema: z.ZodObject<{
|
|
|
446
443
|
}, "strict", z.ZodTypeAny, {
|
|
447
444
|
startupTimeout: number;
|
|
448
445
|
requestTimeout: number;
|
|
449
|
-
enabled: boolean;
|
|
450
446
|
servers: Record<string, string>;
|
|
447
|
+
enabled: boolean;
|
|
451
448
|
maxServers: number;
|
|
452
449
|
idleTimeout: number;
|
|
453
450
|
maxResults: number;
|
|
454
451
|
}, {
|
|
455
452
|
startupTimeout?: number | undefined;
|
|
456
453
|
requestTimeout?: number | undefined;
|
|
457
|
-
enabled?: boolean | undefined;
|
|
458
454
|
servers?: Record<string, string> | undefined;
|
|
455
|
+
enabled?: boolean | undefined;
|
|
459
456
|
maxServers?: number | undefined;
|
|
460
457
|
idleTimeout?: number | undefined;
|
|
461
458
|
maxResults?: number | undefined;
|
|
@@ -593,20 +590,198 @@ export declare const UsageConfigSchema: z.ZodObject<{
|
|
|
593
590
|
} | undefined;
|
|
594
591
|
}>;
|
|
595
592
|
export type UsageConfig = z.infer<typeof UsageConfigSchema>;
|
|
596
|
-
/**
|
|
597
|
-
|
|
593
|
+
/**
|
|
594
|
+
* One MCP server entry (C.27). A `command` (+ optional `args`/`env`) is a stdio
|
|
595
|
+
* server cruxy spawns as a child process; a `url` names a remote server. Exactly
|
|
596
|
+
* one transport must be given. Trusting a stdio server runs its code UNSANDBOXED
|
|
597
|
+
* with your privileges, which is why connection is gated by an explicit,
|
|
598
|
+
* fingerprinted trust decision (see `mcp/trust.ts`).
|
|
599
|
+
*/
|
|
600
|
+
export declare const McpServerSchema: z.ZodEffects<z.ZodObject<{
|
|
601
|
+
/** stdio transport: the server program to spawn. */
|
|
598
602
|
command: z.ZodOptional<z.ZodString>;
|
|
599
|
-
|
|
603
|
+
/** Arguments for `command`. */
|
|
604
|
+
args: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
605
|
+
/** Extra environment variables for the spawned server (stdio only). */
|
|
606
|
+
env: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
607
|
+
/** Remote transport: the server URL (mutually exclusive with `command`). */
|
|
600
608
|
url: z.ZodOptional<z.ZodString>;
|
|
601
609
|
}, "strict", z.ZodTypeAny, {
|
|
610
|
+
args: string[];
|
|
611
|
+
env: Record<string, string>;
|
|
612
|
+
command?: string | undefined;
|
|
613
|
+
url?: string | undefined;
|
|
614
|
+
}, {
|
|
602
615
|
command?: string | undefined;
|
|
603
616
|
url?: string | undefined;
|
|
604
617
|
args?: string[] | undefined;
|
|
618
|
+
env?: Record<string, string> | undefined;
|
|
619
|
+
}>, {
|
|
620
|
+
args: string[];
|
|
621
|
+
env: Record<string, string>;
|
|
622
|
+
command?: string | undefined;
|
|
623
|
+
url?: string | undefined;
|
|
605
624
|
}, {
|
|
606
625
|
command?: string | undefined;
|
|
607
626
|
url?: string | undefined;
|
|
608
627
|
args?: string[] | undefined;
|
|
628
|
+
env?: Record<string, string> | undefined;
|
|
609
629
|
}>;
|
|
630
|
+
export type McpServerConfig = z.infer<typeof McpServerSchema>;
|
|
631
|
+
/**
|
|
632
|
+
* MCP client integration (C.27): connect to trusted MCP servers and expose their
|
|
633
|
+
* tools to the agent. OFF by default — like the sandbox, LSP, and hooks, it runs
|
|
634
|
+
* EXTERNAL code (a stdio server executes UNSANDBOXED with your privileges), a
|
|
635
|
+
* real execution surface you opt into explicitly. When off, nothing connects or
|
|
636
|
+
* spawns and no MCP tool is ever registered. Every server-advertised tool is
|
|
637
|
+
* gated (destructive tier — a server can never self-declare a tool "safe"), its
|
|
638
|
+
* description and results are demarcated as untrusted external data with upstream
|
|
639
|
+
* model names scrubbed, and results are NEVER persisted. The tool list a server
|
|
640
|
+
* advertises is bounded (count + per-tool description/schema size) so a hostile
|
|
641
|
+
* server can't blow the context budget.
|
|
642
|
+
*/
|
|
643
|
+
export declare const McpConfigSchema: z.ZodObject<{
|
|
644
|
+
/** Master switch. When false, no server is connected/spawned and no MCP tool
|
|
645
|
+
* is registered (the feature stays fully inert). */
|
|
646
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
647
|
+
/** Named MCP servers, keyed by a short server id used as the tool prefix
|
|
648
|
+
* (`mcp__<server>__<tool>`) and in the trust prompt. */
|
|
649
|
+
servers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodEffects<z.ZodObject<{
|
|
650
|
+
/** stdio transport: the server program to spawn. */
|
|
651
|
+
command: z.ZodOptional<z.ZodString>;
|
|
652
|
+
/** Arguments for `command`. */
|
|
653
|
+
args: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
654
|
+
/** Extra environment variables for the spawned server (stdio only). */
|
|
655
|
+
env: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
656
|
+
/** Remote transport: the server URL (mutually exclusive with `command`). */
|
|
657
|
+
url: z.ZodOptional<z.ZodString>;
|
|
658
|
+
}, "strict", z.ZodTypeAny, {
|
|
659
|
+
args: string[];
|
|
660
|
+
env: Record<string, string>;
|
|
661
|
+
command?: string | undefined;
|
|
662
|
+
url?: string | undefined;
|
|
663
|
+
}, {
|
|
664
|
+
command?: string | undefined;
|
|
665
|
+
url?: string | undefined;
|
|
666
|
+
args?: string[] | undefined;
|
|
667
|
+
env?: Record<string, string> | undefined;
|
|
668
|
+
}>, {
|
|
669
|
+
args: string[];
|
|
670
|
+
env: Record<string, string>;
|
|
671
|
+
command?: string | undefined;
|
|
672
|
+
url?: string | undefined;
|
|
673
|
+
}, {
|
|
674
|
+
command?: string | undefined;
|
|
675
|
+
url?: string | undefined;
|
|
676
|
+
args?: string[] | undefined;
|
|
677
|
+
env?: Record<string, string> | undefined;
|
|
678
|
+
}>>>;
|
|
679
|
+
/** Fail a server's `initialize` handshake (its tools are skipped) if it does
|
|
680
|
+
* not complete within this many ms. */
|
|
681
|
+
startupTimeout: z.ZodDefault<z.ZodNumber>;
|
|
682
|
+
/** Fail a single `tools/call` if the server does not respond within this many
|
|
683
|
+
* ms — the connection is kept, only the one call errors. */
|
|
684
|
+
requestTimeout: z.ZodDefault<z.ZodNumber>;
|
|
685
|
+
/** Max tools accepted from ONE server; extras are dropped with a visible note
|
|
686
|
+
* (a hostile server can't advertise thousands of tools to flood context). */
|
|
687
|
+
maxToolsPerServer: z.ZodDefault<z.ZodNumber>;
|
|
688
|
+
/** Max characters kept from a single tool's description; the rest is truncated
|
|
689
|
+
* with a visible marker. */
|
|
690
|
+
maxDescriptionChars: z.ZodDefault<z.ZodNumber>;
|
|
691
|
+
/** Max bytes kept from a single tool's advertised JSON input schema; an
|
|
692
|
+
* over-cap schema is replaced with a permissive one and a visible note. */
|
|
693
|
+
maxSchemaBytes: z.ZodDefault<z.ZodNumber>;
|
|
694
|
+
}, "strict", z.ZodTypeAny, {
|
|
695
|
+
startupTimeout: number;
|
|
696
|
+
requestTimeout: number;
|
|
697
|
+
servers: Record<string, {
|
|
698
|
+
args: string[];
|
|
699
|
+
env: Record<string, string>;
|
|
700
|
+
command?: string | undefined;
|
|
701
|
+
url?: string | undefined;
|
|
702
|
+
}>;
|
|
703
|
+
enabled: boolean;
|
|
704
|
+
maxToolsPerServer: number;
|
|
705
|
+
maxDescriptionChars: number;
|
|
706
|
+
maxSchemaBytes: number;
|
|
707
|
+
}, {
|
|
708
|
+
startupTimeout?: number | undefined;
|
|
709
|
+
requestTimeout?: number | undefined;
|
|
710
|
+
servers?: Record<string, {
|
|
711
|
+
command?: string | undefined;
|
|
712
|
+
url?: string | undefined;
|
|
713
|
+
args?: string[] | undefined;
|
|
714
|
+
env?: Record<string, string> | undefined;
|
|
715
|
+
}> | undefined;
|
|
716
|
+
enabled?: boolean | undefined;
|
|
717
|
+
maxToolsPerServer?: number | undefined;
|
|
718
|
+
maxDescriptionChars?: number | undefined;
|
|
719
|
+
maxSchemaBytes?: number | undefined;
|
|
720
|
+
}>;
|
|
721
|
+
export type McpConfig = z.infer<typeof McpConfigSchema>;
|
|
722
|
+
/**
|
|
723
|
+
* Web-search + web-fetch subtool (C.20). OFF by default. When enabled, the agent
|
|
724
|
+
* gets a bounded `web_search` (query → ranked title/url/snippet) and a `web_fetch`
|
|
725
|
+
* (read one URL as text). Both surface EXTERNAL, attacker-controllable data:
|
|
726
|
+
* results and fetched pages are wrapped as untrusted data (do-not-follow-instructions
|
|
727
|
+
* envelope, fence-forgery neutralized) with upstream model names scrubbed, and
|
|
728
|
+
* are NEVER persisted to memory/index/checkpoint. `web_fetch` refuses non-http(s)
|
|
729
|
+
* schemes and any host that resolves into a private/loopback/link-local range
|
|
730
|
+
* (SSRF guard) — the request is never dispatched. No provider is constructed and
|
|
731
|
+
* no tool is registered while this is off. Search runs through a swappable
|
|
732
|
+
* `SearchProvider` seam; the direct provider's API key comes from the environment
|
|
733
|
+
* (`apiKeyEnv`), never from config-in-repo and never logged.
|
|
734
|
+
*/
|
|
735
|
+
export declare const WebConfigSchema: z.ZodObject<{
|
|
736
|
+
/** Master switch. When false, neither tool is registered and no provider is
|
|
737
|
+
* constructed (the feature stays fully inert). */
|
|
738
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
739
|
+
/** Which search backend to use behind the `SearchProvider` seam. A gateway
|
|
740
|
+
* provider slots in here first-class if the backend ever proxies search. */
|
|
741
|
+
provider: z.ZodDefault<z.ZodEnum<["tavily"]>>;
|
|
742
|
+
/** Environment variable holding the direct provider's API key. The key is
|
|
743
|
+
* read at call time, sent only in the provider's auth field, and never
|
|
744
|
+
* logged or written to the repo. */
|
|
745
|
+
apiKeyEnv: z.ZodDefault<z.ZodString>;
|
|
746
|
+
/** Max search results returned to the model (top-N; the rest are dropped). */
|
|
747
|
+
maxResults: z.ZodDefault<z.ZodNumber>;
|
|
748
|
+
/** Max characters kept from a single result's snippet; the rest is truncated
|
|
749
|
+
* with a visible marker. */
|
|
750
|
+
snippetMaxChars: z.ZodDefault<z.ZodNumber>;
|
|
751
|
+
/** Max bytes read from a single `web_fetch` page; the rest is truncated with
|
|
752
|
+
* a visible marker (a hostile/huge page can't blow the context budget). */
|
|
753
|
+
fetchMaxBytes: z.ZodDefault<z.ZodNumber>;
|
|
754
|
+
/** Per-request timeout (search and fetch) — a slow host errors, never hangs. */
|
|
755
|
+
timeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
756
|
+
/** Max HTTP redirects `web_fetch` follows; each hop is re-checked by the SSRF
|
|
757
|
+
* guard so a 3xx can't bounce the request into a private range. */
|
|
758
|
+
maxRedirects: z.ZodDefault<z.ZodNumber>;
|
|
759
|
+
/** Escape hatch: allow `web_fetch` to reach private/loopback/link-local hosts.
|
|
760
|
+
* OFF by default (SSRF-safe); only set true for a deliberate internal-network
|
|
761
|
+
* use case. */
|
|
762
|
+
allowPrivateHosts: z.ZodDefault<z.ZodBoolean>;
|
|
763
|
+
}, "strict", z.ZodTypeAny, {
|
|
764
|
+
provider: "tavily";
|
|
765
|
+
timeoutMs: number;
|
|
766
|
+
apiKeyEnv: string;
|
|
767
|
+
enabled: boolean;
|
|
768
|
+
maxResults: number;
|
|
769
|
+
snippetMaxChars: number;
|
|
770
|
+
fetchMaxBytes: number;
|
|
771
|
+
maxRedirects: number;
|
|
772
|
+
allowPrivateHosts: boolean;
|
|
773
|
+
}, {
|
|
774
|
+
provider?: "tavily" | undefined;
|
|
775
|
+
timeoutMs?: number | undefined;
|
|
776
|
+
apiKeyEnv?: string | undefined;
|
|
777
|
+
enabled?: boolean | undefined;
|
|
778
|
+
maxResults?: number | undefined;
|
|
779
|
+
snippetMaxChars?: number | undefined;
|
|
780
|
+
fetchMaxBytes?: number | undefined;
|
|
781
|
+
maxRedirects?: number | undefined;
|
|
782
|
+
allowPrivateHosts?: boolean | undefined;
|
|
783
|
+
}>;
|
|
784
|
+
export type WebConfig = z.infer<typeof WebConfigSchema>;
|
|
610
785
|
export declare const CruxyConfigSchema: z.ZodObject<{
|
|
611
786
|
model: z.ZodDefault<z.ZodObject<{
|
|
612
787
|
provider: z.ZodDefault<z.ZodEnum<["cruxy", "anthropic", "openai", "custom"]>>;
|
|
@@ -650,15 +825,12 @@ export declare const CruxyConfigSchema: z.ZodObject<{
|
|
|
650
825
|
tools: z.ZodDefault<z.ZodObject<{
|
|
651
826
|
fileEdit: z.ZodDefault<z.ZodBoolean>;
|
|
652
827
|
shell: z.ZodDefault<z.ZodBoolean>;
|
|
653
|
-
webSearch: z.ZodDefault<z.ZodBoolean>;
|
|
654
828
|
}, "strict", z.ZodTypeAny, {
|
|
655
829
|
fileEdit: boolean;
|
|
656
830
|
shell: boolean;
|
|
657
|
-
webSearch: boolean;
|
|
658
831
|
}, {
|
|
659
832
|
fileEdit?: boolean | undefined;
|
|
660
833
|
shell?: boolean | undefined;
|
|
661
|
-
webSearch?: boolean | undefined;
|
|
662
834
|
}>>;
|
|
663
835
|
git: z.ZodDefault<z.ZodObject<{
|
|
664
836
|
autoCommit: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -823,16 +995,16 @@ export declare const CruxyConfigSchema: z.ZodObject<{
|
|
|
823
995
|
}, "strict", z.ZodTypeAny, {
|
|
824
996
|
startupTimeout: number;
|
|
825
997
|
requestTimeout: number;
|
|
826
|
-
enabled: boolean;
|
|
827
998
|
servers: Record<string, string>;
|
|
999
|
+
enabled: boolean;
|
|
828
1000
|
maxServers: number;
|
|
829
1001
|
idleTimeout: number;
|
|
830
1002
|
maxResults: number;
|
|
831
1003
|
}, {
|
|
832
1004
|
startupTimeout?: number | undefined;
|
|
833
1005
|
requestTimeout?: number | undefined;
|
|
834
|
-
enabled?: boolean | undefined;
|
|
835
1006
|
servers?: Record<string, string> | undefined;
|
|
1007
|
+
enabled?: boolean | undefined;
|
|
836
1008
|
maxServers?: number | undefined;
|
|
837
1009
|
idleTimeout?: number | undefined;
|
|
838
1010
|
maxResults?: number | undefined;
|
|
@@ -1104,19 +1276,133 @@ export declare const CruxyConfigSchema: z.ZodObject<{
|
|
|
1104
1276
|
} | undefined;
|
|
1105
1277
|
} | undefined;
|
|
1106
1278
|
}>>;
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1279
|
+
mcp: z.ZodDefault<z.ZodObject<{
|
|
1280
|
+
/** Master switch. When false, no server is connected/spawned and no MCP tool
|
|
1281
|
+
* is registered (the feature stays fully inert). */
|
|
1282
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
1283
|
+
/** Named MCP servers, keyed by a short server id used as the tool prefix
|
|
1284
|
+
* (`mcp__<server>__<tool>`) and in the trust prompt. */
|
|
1285
|
+
servers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodEffects<z.ZodObject<{
|
|
1286
|
+
/** stdio transport: the server program to spawn. */
|
|
1287
|
+
command: z.ZodOptional<z.ZodString>;
|
|
1288
|
+
/** Arguments for `command`. */
|
|
1289
|
+
args: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
1290
|
+
/** Extra environment variables for the spawned server (stdio only). */
|
|
1291
|
+
env: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1292
|
+
/** Remote transport: the server URL (mutually exclusive with `command`). */
|
|
1293
|
+
url: z.ZodOptional<z.ZodString>;
|
|
1294
|
+
}, "strict", z.ZodTypeAny, {
|
|
1295
|
+
args: string[];
|
|
1296
|
+
env: Record<string, string>;
|
|
1297
|
+
command?: string | undefined;
|
|
1298
|
+
url?: string | undefined;
|
|
1299
|
+
}, {
|
|
1300
|
+
command?: string | undefined;
|
|
1301
|
+
url?: string | undefined;
|
|
1302
|
+
args?: string[] | undefined;
|
|
1303
|
+
env?: Record<string, string> | undefined;
|
|
1304
|
+
}>, {
|
|
1305
|
+
args: string[];
|
|
1306
|
+
env: Record<string, string>;
|
|
1307
|
+
command?: string | undefined;
|
|
1308
|
+
url?: string | undefined;
|
|
1309
|
+
}, {
|
|
1310
|
+
command?: string | undefined;
|
|
1311
|
+
url?: string | undefined;
|
|
1312
|
+
args?: string[] | undefined;
|
|
1313
|
+
env?: Record<string, string> | undefined;
|
|
1314
|
+
}>>>;
|
|
1315
|
+
/** Fail a server's `initialize` handshake (its tools are skipped) if it does
|
|
1316
|
+
* not complete within this many ms. */
|
|
1317
|
+
startupTimeout: z.ZodDefault<z.ZodNumber>;
|
|
1318
|
+
/** Fail a single `tools/call` if the server does not respond within this many
|
|
1319
|
+
* ms — the connection is kept, only the one call errors. */
|
|
1320
|
+
requestTimeout: z.ZodDefault<z.ZodNumber>;
|
|
1321
|
+
/** Max tools accepted from ONE server; extras are dropped with a visible note
|
|
1322
|
+
* (a hostile server can't advertise thousands of tools to flood context). */
|
|
1323
|
+
maxToolsPerServer: z.ZodDefault<z.ZodNumber>;
|
|
1324
|
+
/** Max characters kept from a single tool's description; the rest is truncated
|
|
1325
|
+
* with a visible marker. */
|
|
1326
|
+
maxDescriptionChars: z.ZodDefault<z.ZodNumber>;
|
|
1327
|
+
/** Max bytes kept from a single tool's advertised JSON input schema; an
|
|
1328
|
+
* over-cap schema is replaced with a permissive one and a visible note. */
|
|
1329
|
+
maxSchemaBytes: z.ZodDefault<z.ZodNumber>;
|
|
1111
1330
|
}, "strict", z.ZodTypeAny, {
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1331
|
+
startupTimeout: number;
|
|
1332
|
+
requestTimeout: number;
|
|
1333
|
+
servers: Record<string, {
|
|
1334
|
+
args: string[];
|
|
1335
|
+
env: Record<string, string>;
|
|
1336
|
+
command?: string | undefined;
|
|
1337
|
+
url?: string | undefined;
|
|
1338
|
+
}>;
|
|
1339
|
+
enabled: boolean;
|
|
1340
|
+
maxToolsPerServer: number;
|
|
1341
|
+
maxDescriptionChars: number;
|
|
1342
|
+
maxSchemaBytes: number;
|
|
1115
1343
|
}, {
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1344
|
+
startupTimeout?: number | undefined;
|
|
1345
|
+
requestTimeout?: number | undefined;
|
|
1346
|
+
servers?: Record<string, {
|
|
1347
|
+
command?: string | undefined;
|
|
1348
|
+
url?: string | undefined;
|
|
1349
|
+
args?: string[] | undefined;
|
|
1350
|
+
env?: Record<string, string> | undefined;
|
|
1351
|
+
}> | undefined;
|
|
1352
|
+
enabled?: boolean | undefined;
|
|
1353
|
+
maxToolsPerServer?: number | undefined;
|
|
1354
|
+
maxDescriptionChars?: number | undefined;
|
|
1355
|
+
maxSchemaBytes?: number | undefined;
|
|
1356
|
+
}>>;
|
|
1357
|
+
web: z.ZodDefault<z.ZodObject<{
|
|
1358
|
+
/** Master switch. When false, neither tool is registered and no provider is
|
|
1359
|
+
* constructed (the feature stays fully inert). */
|
|
1360
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
1361
|
+
/** Which search backend to use behind the `SearchProvider` seam. A gateway
|
|
1362
|
+
* provider slots in here first-class if the backend ever proxies search. */
|
|
1363
|
+
provider: z.ZodDefault<z.ZodEnum<["tavily"]>>;
|
|
1364
|
+
/** Environment variable holding the direct provider's API key. The key is
|
|
1365
|
+
* read at call time, sent only in the provider's auth field, and never
|
|
1366
|
+
* logged or written to the repo. */
|
|
1367
|
+
apiKeyEnv: z.ZodDefault<z.ZodString>;
|
|
1368
|
+
/** Max search results returned to the model (top-N; the rest are dropped). */
|
|
1369
|
+
maxResults: z.ZodDefault<z.ZodNumber>;
|
|
1370
|
+
/** Max characters kept from a single result's snippet; the rest is truncated
|
|
1371
|
+
* with a visible marker. */
|
|
1372
|
+
snippetMaxChars: z.ZodDefault<z.ZodNumber>;
|
|
1373
|
+
/** Max bytes read from a single `web_fetch` page; the rest is truncated with
|
|
1374
|
+
* a visible marker (a hostile/huge page can't blow the context budget). */
|
|
1375
|
+
fetchMaxBytes: z.ZodDefault<z.ZodNumber>;
|
|
1376
|
+
/** Per-request timeout (search and fetch) — a slow host errors, never hangs. */
|
|
1377
|
+
timeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
1378
|
+
/** Max HTTP redirects `web_fetch` follows; each hop is re-checked by the SSRF
|
|
1379
|
+
* guard so a 3xx can't bounce the request into a private range. */
|
|
1380
|
+
maxRedirects: z.ZodDefault<z.ZodNumber>;
|
|
1381
|
+
/** Escape hatch: allow `web_fetch` to reach private/loopback/link-local hosts.
|
|
1382
|
+
* OFF by default (SSRF-safe); only set true for a deliberate internal-network
|
|
1383
|
+
* use case. */
|
|
1384
|
+
allowPrivateHosts: z.ZodDefault<z.ZodBoolean>;
|
|
1385
|
+
}, "strict", z.ZodTypeAny, {
|
|
1386
|
+
provider: "tavily";
|
|
1387
|
+
timeoutMs: number;
|
|
1388
|
+
apiKeyEnv: string;
|
|
1389
|
+
enabled: boolean;
|
|
1390
|
+
maxResults: number;
|
|
1391
|
+
snippetMaxChars: number;
|
|
1392
|
+
fetchMaxBytes: number;
|
|
1393
|
+
maxRedirects: number;
|
|
1394
|
+
allowPrivateHosts: boolean;
|
|
1395
|
+
}, {
|
|
1396
|
+
provider?: "tavily" | undefined;
|
|
1397
|
+
timeoutMs?: number | undefined;
|
|
1398
|
+
apiKeyEnv?: string | undefined;
|
|
1399
|
+
enabled?: boolean | undefined;
|
|
1400
|
+
maxResults?: number | undefined;
|
|
1401
|
+
snippetMaxChars?: number | undefined;
|
|
1402
|
+
fetchMaxBytes?: number | undefined;
|
|
1403
|
+
maxRedirects?: number | undefined;
|
|
1404
|
+
allowPrivateHosts?: boolean | undefined;
|
|
1405
|
+
}>>;
|
|
1120
1406
|
logLevel: z.ZodDefault<z.ZodEnum<["debug", "info", "warn", "error", "silent"]>>;
|
|
1121
1407
|
}, "strict", z.ZodTypeAny, {
|
|
1122
1408
|
cruxy: {
|
|
@@ -1188,7 +1474,6 @@ export declare const CruxyConfigSchema: z.ZodObject<{
|
|
|
1188
1474
|
tools: {
|
|
1189
1475
|
fileEdit: boolean;
|
|
1190
1476
|
shell: boolean;
|
|
1191
|
-
webSearch: boolean;
|
|
1192
1477
|
};
|
|
1193
1478
|
git: {
|
|
1194
1479
|
autoCommit: boolean;
|
|
@@ -1218,8 +1503,8 @@ export declare const CruxyConfigSchema: z.ZodObject<{
|
|
|
1218
1503
|
lsp: {
|
|
1219
1504
|
startupTimeout: number;
|
|
1220
1505
|
requestTimeout: number;
|
|
1221
|
-
enabled: boolean;
|
|
1222
1506
|
servers: Record<string, string>;
|
|
1507
|
+
enabled: boolean;
|
|
1223
1508
|
maxServers: number;
|
|
1224
1509
|
idleTimeout: number;
|
|
1225
1510
|
maxResults: number;
|
|
@@ -1237,11 +1522,31 @@ export declare const CruxyConfigSchema: z.ZodObject<{
|
|
|
1237
1522
|
map: Partial<Record<"main-turn" | "subagent" | "plan" | "commit-msg" | "classify" | "summarize", "kavi" | "vaani" | "mira">>;
|
|
1238
1523
|
default?: "kavi" | "vaani" | "mira" | undefined;
|
|
1239
1524
|
};
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1525
|
+
mcp: {
|
|
1526
|
+
startupTimeout: number;
|
|
1527
|
+
requestTimeout: number;
|
|
1528
|
+
servers: Record<string, {
|
|
1529
|
+
args: string[];
|
|
1530
|
+
env: Record<string, string>;
|
|
1531
|
+
command?: string | undefined;
|
|
1532
|
+
url?: string | undefined;
|
|
1533
|
+
}>;
|
|
1534
|
+
enabled: boolean;
|
|
1535
|
+
maxToolsPerServer: number;
|
|
1536
|
+
maxDescriptionChars: number;
|
|
1537
|
+
maxSchemaBytes: number;
|
|
1538
|
+
};
|
|
1539
|
+
web: {
|
|
1540
|
+
provider: "tavily";
|
|
1541
|
+
timeoutMs: number;
|
|
1542
|
+
apiKeyEnv: string;
|
|
1543
|
+
enabled: boolean;
|
|
1544
|
+
maxResults: number;
|
|
1545
|
+
snippetMaxChars: number;
|
|
1546
|
+
fetchMaxBytes: number;
|
|
1547
|
+
maxRedirects: number;
|
|
1548
|
+
allowPrivateHosts: boolean;
|
|
1549
|
+
};
|
|
1245
1550
|
logLevel: "debug" | "info" | "warn" | "error" | "silent";
|
|
1246
1551
|
}, {
|
|
1247
1552
|
cruxy?: {
|
|
@@ -1313,7 +1618,6 @@ export declare const CruxyConfigSchema: z.ZodObject<{
|
|
|
1313
1618
|
tools?: {
|
|
1314
1619
|
fileEdit?: boolean | undefined;
|
|
1315
1620
|
shell?: boolean | undefined;
|
|
1316
|
-
webSearch?: boolean | undefined;
|
|
1317
1621
|
} | undefined;
|
|
1318
1622
|
git?: {
|
|
1319
1623
|
autoCommit?: boolean | undefined;
|
|
@@ -1343,8 +1647,8 @@ export declare const CruxyConfigSchema: z.ZodObject<{
|
|
|
1343
1647
|
lsp?: {
|
|
1344
1648
|
startupTimeout?: number | undefined;
|
|
1345
1649
|
requestTimeout?: number | undefined;
|
|
1346
|
-
enabled?: boolean | undefined;
|
|
1347
1650
|
servers?: Record<string, string> | undefined;
|
|
1651
|
+
enabled?: boolean | undefined;
|
|
1348
1652
|
maxServers?: number | undefined;
|
|
1349
1653
|
idleTimeout?: number | undefined;
|
|
1350
1654
|
maxResults?: number | undefined;
|
|
@@ -1362,11 +1666,31 @@ export declare const CruxyConfigSchema: z.ZodObject<{
|
|
|
1362
1666
|
map?: Partial<Record<"main-turn" | "subagent" | "plan" | "commit-msg" | "classify" | "summarize", "kavi" | "vaani" | "mira">> | undefined;
|
|
1363
1667
|
default?: "kavi" | "vaani" | "mira" | undefined;
|
|
1364
1668
|
} | undefined;
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1669
|
+
mcp?: {
|
|
1670
|
+
startupTimeout?: number | undefined;
|
|
1671
|
+
requestTimeout?: number | undefined;
|
|
1672
|
+
servers?: Record<string, {
|
|
1673
|
+
command?: string | undefined;
|
|
1674
|
+
url?: string | undefined;
|
|
1675
|
+
args?: string[] | undefined;
|
|
1676
|
+
env?: Record<string, string> | undefined;
|
|
1677
|
+
}> | undefined;
|
|
1678
|
+
enabled?: boolean | undefined;
|
|
1679
|
+
maxToolsPerServer?: number | undefined;
|
|
1680
|
+
maxDescriptionChars?: number | undefined;
|
|
1681
|
+
maxSchemaBytes?: number | undefined;
|
|
1682
|
+
} | undefined;
|
|
1683
|
+
web?: {
|
|
1684
|
+
provider?: "tavily" | undefined;
|
|
1685
|
+
timeoutMs?: number | undefined;
|
|
1686
|
+
apiKeyEnv?: string | undefined;
|
|
1687
|
+
enabled?: boolean | undefined;
|
|
1688
|
+
maxResults?: number | undefined;
|
|
1689
|
+
snippetMaxChars?: number | undefined;
|
|
1690
|
+
fetchMaxBytes?: number | undefined;
|
|
1691
|
+
maxRedirects?: number | undefined;
|
|
1692
|
+
allowPrivateHosts?: boolean | undefined;
|
|
1693
|
+
} | undefined;
|
|
1370
1694
|
logLevel?: "debug" | "info" | "warn" | "error" | "silent" | undefined;
|
|
1371
1695
|
}>;
|
|
1372
1696
|
export type CruxyConfig = z.infer<typeof CruxyConfigSchema>;
|
package/dist/config/schema.js
CHANGED
|
@@ -38,7 +38,6 @@ export const ToolsConfigSchema = z
|
|
|
38
38
|
.object({
|
|
39
39
|
fileEdit: z.boolean().default(true),
|
|
40
40
|
shell: z.boolean().default(true),
|
|
41
|
-
webSearch: z.boolean().default(false), // C.17
|
|
42
41
|
})
|
|
43
42
|
.strict();
|
|
44
43
|
export const GitConfigSchema = z
|
|
@@ -365,12 +364,107 @@ export const UsageConfigSchema = z
|
|
|
365
364
|
.default({}),
|
|
366
365
|
})
|
|
367
366
|
.strict();
|
|
368
|
-
/**
|
|
367
|
+
/**
|
|
368
|
+
* One MCP server entry (C.27). A `command` (+ optional `args`/`env`) is a stdio
|
|
369
|
+
* server cruxy spawns as a child process; a `url` names a remote server. Exactly
|
|
370
|
+
* one transport must be given. Trusting a stdio server runs its code UNSANDBOXED
|
|
371
|
+
* with your privileges, which is why connection is gated by an explicit,
|
|
372
|
+
* fingerprinted trust decision (see `mcp/trust.ts`).
|
|
373
|
+
*/
|
|
369
374
|
export const McpServerSchema = z
|
|
370
375
|
.object({
|
|
371
|
-
|
|
372
|
-
|
|
376
|
+
/** stdio transport: the server program to spawn. */
|
|
377
|
+
command: z.string().min(1).optional(),
|
|
378
|
+
/** Arguments for `command`. */
|
|
379
|
+
args: z.array(z.string()).default([]),
|
|
380
|
+
/** Extra environment variables for the spawned server (stdio only). */
|
|
381
|
+
env: z.record(z.string(), z.string()).default({}),
|
|
382
|
+
/** Remote transport: the server URL (mutually exclusive with `command`). */
|
|
373
383
|
url: z.string().url().optional(),
|
|
384
|
+
})
|
|
385
|
+
.strict()
|
|
386
|
+
.refine((s) => Boolean(s.command) !== Boolean(s.url), {
|
|
387
|
+
message: "an MCP server needs exactly one of `command` (stdio) or `url`",
|
|
388
|
+
});
|
|
389
|
+
/**
|
|
390
|
+
* MCP client integration (C.27): connect to trusted MCP servers and expose their
|
|
391
|
+
* tools to the agent. OFF by default — like the sandbox, LSP, and hooks, it runs
|
|
392
|
+
* EXTERNAL code (a stdio server executes UNSANDBOXED with your privileges), a
|
|
393
|
+
* real execution surface you opt into explicitly. When off, nothing connects or
|
|
394
|
+
* spawns and no MCP tool is ever registered. Every server-advertised tool is
|
|
395
|
+
* gated (destructive tier — a server can never self-declare a tool "safe"), its
|
|
396
|
+
* description and results are demarcated as untrusted external data with upstream
|
|
397
|
+
* model names scrubbed, and results are NEVER persisted. The tool list a server
|
|
398
|
+
* advertises is bounded (count + per-tool description/schema size) so a hostile
|
|
399
|
+
* server can't blow the context budget.
|
|
400
|
+
*/
|
|
401
|
+
export const McpConfigSchema = z
|
|
402
|
+
.object({
|
|
403
|
+
/** Master switch. When false, no server is connected/spawned and no MCP tool
|
|
404
|
+
* is registered (the feature stays fully inert). */
|
|
405
|
+
enabled: z.boolean().default(false),
|
|
406
|
+
/** Named MCP servers, keyed by a short server id used as the tool prefix
|
|
407
|
+
* (`mcp__<server>__<tool>`) and in the trust prompt. */
|
|
408
|
+
servers: z.record(z.string(), McpServerSchema).default({}),
|
|
409
|
+
/** Fail a server's `initialize` handshake (its tools are skipped) if it does
|
|
410
|
+
* not complete within this many ms. */
|
|
411
|
+
startupTimeout: z.number().int().positive().default(15000),
|
|
412
|
+
/** Fail a single `tools/call` if the server does not respond within this many
|
|
413
|
+
* ms — the connection is kept, only the one call errors. */
|
|
414
|
+
requestTimeout: z.number().int().positive().default(30000),
|
|
415
|
+
/** Max tools accepted from ONE server; extras are dropped with a visible note
|
|
416
|
+
* (a hostile server can't advertise thousands of tools to flood context). */
|
|
417
|
+
maxToolsPerServer: z.number().int().positive().default(32),
|
|
418
|
+
/** Max characters kept from a single tool's description; the rest is truncated
|
|
419
|
+
* with a visible marker. */
|
|
420
|
+
maxDescriptionChars: z.number().int().positive().default(1024),
|
|
421
|
+
/** Max bytes kept from a single tool's advertised JSON input schema; an
|
|
422
|
+
* over-cap schema is replaced with a permissive one and a visible note. */
|
|
423
|
+
maxSchemaBytes: z.number().int().positive().default(8192),
|
|
424
|
+
})
|
|
425
|
+
.strict();
|
|
426
|
+
/**
|
|
427
|
+
* Web-search + web-fetch subtool (C.20). OFF by default. When enabled, the agent
|
|
428
|
+
* gets a bounded `web_search` (query → ranked title/url/snippet) and a `web_fetch`
|
|
429
|
+
* (read one URL as text). Both surface EXTERNAL, attacker-controllable data:
|
|
430
|
+
* results and fetched pages are wrapped as untrusted data (do-not-follow-instructions
|
|
431
|
+
* envelope, fence-forgery neutralized) with upstream model names scrubbed, and
|
|
432
|
+
* are NEVER persisted to memory/index/checkpoint. `web_fetch` refuses non-http(s)
|
|
433
|
+
* schemes and any host that resolves into a private/loopback/link-local range
|
|
434
|
+
* (SSRF guard) — the request is never dispatched. No provider is constructed and
|
|
435
|
+
* no tool is registered while this is off. Search runs through a swappable
|
|
436
|
+
* `SearchProvider` seam; the direct provider's API key comes from the environment
|
|
437
|
+
* (`apiKeyEnv`), never from config-in-repo and never logged.
|
|
438
|
+
*/
|
|
439
|
+
export const WebConfigSchema = z
|
|
440
|
+
.object({
|
|
441
|
+
/** Master switch. When false, neither tool is registered and no provider is
|
|
442
|
+
* constructed (the feature stays fully inert). */
|
|
443
|
+
enabled: z.boolean().default(false),
|
|
444
|
+
/** Which search backend to use behind the `SearchProvider` seam. A gateway
|
|
445
|
+
* provider slots in here first-class if the backend ever proxies search. */
|
|
446
|
+
provider: z.enum(["tavily"]).default("tavily"),
|
|
447
|
+
/** Environment variable holding the direct provider's API key. The key is
|
|
448
|
+
* read at call time, sent only in the provider's auth field, and never
|
|
449
|
+
* logged or written to the repo. */
|
|
450
|
+
apiKeyEnv: z.string().min(1).default("TAVILY_API_KEY"),
|
|
451
|
+
/** Max search results returned to the model (top-N; the rest are dropped). */
|
|
452
|
+
maxResults: z.number().int().positive().max(20).default(5),
|
|
453
|
+
/** Max characters kept from a single result's snippet; the rest is truncated
|
|
454
|
+
* with a visible marker. */
|
|
455
|
+
snippetMaxChars: z.number().int().positive().default(500),
|
|
456
|
+
/** Max bytes read from a single `web_fetch` page; the rest is truncated with
|
|
457
|
+
* a visible marker (a hostile/huge page can't blow the context budget). */
|
|
458
|
+
fetchMaxBytes: z.number().int().positive().default(524288),
|
|
459
|
+
/** Per-request timeout (search and fetch) — a slow host errors, never hangs. */
|
|
460
|
+
timeoutMs: z.number().int().positive().default(15000),
|
|
461
|
+
/** Max HTTP redirects `web_fetch` follows; each hop is re-checked by the SSRF
|
|
462
|
+
* guard so a 3xx can't bounce the request into a private range. */
|
|
463
|
+
maxRedirects: z.number().int().min(0).default(3),
|
|
464
|
+
/** Escape hatch: allow `web_fetch` to reach private/loopback/link-local hosts.
|
|
465
|
+
* OFF by default (SSRF-safe); only set true for a deliberate internal-network
|
|
466
|
+
* use case. */
|
|
467
|
+
allowPrivateHosts: z.boolean().default(false),
|
|
374
468
|
})
|
|
375
469
|
.strict();
|
|
376
470
|
export const CruxyConfigSchema = z
|
|
@@ -393,7 +487,8 @@ export const CruxyConfigSchema = z
|
|
|
393
487
|
routing: RoutingConfigSchema.default({}),
|
|
394
488
|
memory: MemoryConfigSchema.default({}),
|
|
395
489
|
usage: UsageConfigSchema.default({}),
|
|
396
|
-
|
|
490
|
+
mcp: McpConfigSchema.default({}),
|
|
491
|
+
web: WebConfigSchema.default({}),
|
|
397
492
|
logLevel: z.enum(LOG_LEVELS).default("info"),
|
|
398
493
|
})
|
|
399
494
|
.strict();
|
package/dist/constants.d.ts
CHANGED
|
@@ -41,6 +41,14 @@ export declare const MEMORY_FILE_NAME = "entries.json";
|
|
|
41
41
|
* (`~/.cruxy/memory-trust.json`) — its own file, independent of hook trust, so
|
|
42
42
|
* cloning a repo carries zero memory trust (C.29 supply-chain safety). */
|
|
43
43
|
export declare const MEMORY_TRUST_FILE_NAME = "memory-trust.json";
|
|
44
|
+
/**
|
|
45
|
+
* MCP server integration (C.27). Per-repo trust for configured MCP servers, in
|
|
46
|
+
* the GLOBAL dir only (`~/.cruxy/mcp-trust.json`) — its own file, independent of
|
|
47
|
+
* hook and memory trust, so cloning a repo carries zero MCP trust. Trusting a
|
|
48
|
+
* server runs its code UNSANDBOXED with your privileges, so this decision is
|
|
49
|
+
* fingerprinted and re-checked on every run (C.27 supply-chain safety).
|
|
50
|
+
*/
|
|
51
|
+
export declare const MCP_TRUST_FILE_NAME = "mcp-trust.json";
|
|
44
52
|
/**
|
|
45
53
|
* Usage telemetry + cost tracking (C.22). Per-run/per-session usage records live
|
|
46
54
|
* in the GLOBAL dir only (`~/.cruxy/usage/runs.json`), `0600` — LOCAL accounting
|