rulesync 16.30.2 → 16.31.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/README.md +3 -0
- package/dist/cli/index.cjs +74 -21
- package/dist/cli/index.js +74 -21
- package/dist/cli/index.js.map +1 -1
- package/dist/{import-auwKp4Mm.cjs → import-Cwe8RKJs.cjs} +3850 -283
- package/dist/{import-BknrMODR.js → import-D2GhBXJV.js} +3817 -268
- package/dist/import-D2GhBXJV.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +13 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/import-BknrMODR.js.map +0 -1
|
@@ -444,34 +444,36 @@ const isFeatureValueEnabled = (value) => {
|
|
|
444
444
|
const parseCommaSeparatedList = (value) => value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
445
445
|
//#endregion
|
|
446
446
|
//#region src/constants/rulesync-paths.ts
|
|
447
|
-
const { join: join$
|
|
447
|
+
const { join: join$332 } = node_path.posix;
|
|
448
448
|
const RULESYNC_CONFIG_RELATIVE_FILE_PATH = "rulesync.jsonc";
|
|
449
449
|
const RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH = "rulesync.local.jsonc";
|
|
450
|
+
const RULESYNC_USER_CONFIG_DIR_NAME = "rulesync";
|
|
451
|
+
const RULESYNC_XDG_CONFIG_HOME_DEFAULT_DIR_NAME = ".config";
|
|
450
452
|
const RULESYNC_RELATIVE_DIR_PATH = ".rulesync";
|
|
451
453
|
const RULES_FEATURE_SUBDIR = "rules";
|
|
452
|
-
const CURATED_RULES_FEATURE_SUBDIR = join$
|
|
454
|
+
const CURATED_RULES_FEATURE_SUBDIR = join$332(RULES_FEATURE_SUBDIR, ".curated");
|
|
453
455
|
const COMMANDS_FEATURE_SUBDIR = "commands";
|
|
454
456
|
const SUBAGENTS_FEATURE_SUBDIR = "subagents";
|
|
455
457
|
const CHECKS_FEATURE_SUBDIR = "checks";
|
|
456
458
|
const SKILLS_FEATURE_SUBDIR = "skills";
|
|
457
|
-
const CURATED_SKILLS_FEATURE_SUBDIR = join$
|
|
458
|
-
const RULESYNC_RULES_RELATIVE_DIR_PATH = join$
|
|
459
|
-
const RULESYNC_CURATED_RULES_RELATIVE_DIR_PATH = join$
|
|
460
|
-
const RULESYNC_COMMANDS_RELATIVE_DIR_PATH = join$
|
|
461
|
-
const RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH = join$
|
|
462
|
-
const RULESYNC_CHECKS_RELATIVE_DIR_PATH = join$
|
|
463
|
-
const RULESYNC_MCP_RELATIVE_FILE_PATH = join$
|
|
464
|
-
const RULESYNC_HOOKS_RELATIVE_FILE_PATH = join$
|
|
465
|
-
const RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH = join$
|
|
466
|
-
join$
|
|
467
|
-
const RULESYNC_HOOKS_LEGACY_RELATIVE_FILE_PATH = join$
|
|
468
|
-
const RULESYNC_PERMISSIONS_LEGACY_RELATIVE_FILE_PATH = join$
|
|
459
|
+
const CURATED_SKILLS_FEATURE_SUBDIR = join$332(SKILLS_FEATURE_SUBDIR, ".curated");
|
|
460
|
+
const RULESYNC_RULES_RELATIVE_DIR_PATH = join$332(RULESYNC_RELATIVE_DIR_PATH, RULES_FEATURE_SUBDIR);
|
|
461
|
+
const RULESYNC_CURATED_RULES_RELATIVE_DIR_PATH = join$332(RULESYNC_RELATIVE_DIR_PATH, CURATED_RULES_FEATURE_SUBDIR);
|
|
462
|
+
const RULESYNC_COMMANDS_RELATIVE_DIR_PATH = join$332(RULESYNC_RELATIVE_DIR_PATH, COMMANDS_FEATURE_SUBDIR);
|
|
463
|
+
const RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH = join$332(RULESYNC_RELATIVE_DIR_PATH, SUBAGENTS_FEATURE_SUBDIR);
|
|
464
|
+
const RULESYNC_CHECKS_RELATIVE_DIR_PATH = join$332(RULESYNC_RELATIVE_DIR_PATH, CHECKS_FEATURE_SUBDIR);
|
|
465
|
+
const RULESYNC_MCP_RELATIVE_FILE_PATH = join$332(RULESYNC_RELATIVE_DIR_PATH, "mcp.jsonc");
|
|
466
|
+
const RULESYNC_HOOKS_RELATIVE_FILE_PATH = join$332(RULESYNC_RELATIVE_DIR_PATH, "hooks.jsonc");
|
|
467
|
+
const RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH = join$332(RULESYNC_RELATIVE_DIR_PATH, "permissions.jsonc");
|
|
468
|
+
join$332(RULESYNC_RELATIVE_DIR_PATH, "mcp.json");
|
|
469
|
+
const RULESYNC_HOOKS_LEGACY_RELATIVE_FILE_PATH = join$332(RULESYNC_RELATIVE_DIR_PATH, "hooks.json");
|
|
470
|
+
const RULESYNC_PERMISSIONS_LEGACY_RELATIVE_FILE_PATH = join$332(RULESYNC_RELATIVE_DIR_PATH, "permissions.json");
|
|
469
471
|
const RULESYNC_AIIGNORE_FILE_NAME = ".aiignore";
|
|
470
|
-
const RULESYNC_AIIGNORE_RELATIVE_FILE_PATH = join$
|
|
472
|
+
const RULESYNC_AIIGNORE_RELATIVE_FILE_PATH = join$332(RULESYNC_RELATIVE_DIR_PATH, ".aiignore");
|
|
471
473
|
const RULESYNC_IGNORE_RELATIVE_FILE_PATH = ".rulesyncignore";
|
|
472
474
|
const RULESYNC_OVERVIEW_FILE_NAME = "overview.md";
|
|
473
|
-
const RULESYNC_SKILLS_RELATIVE_DIR_PATH = join$
|
|
474
|
-
const RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH = join$
|
|
475
|
+
const RULESYNC_SKILLS_RELATIVE_DIR_PATH = join$332(RULESYNC_RELATIVE_DIR_PATH, SKILLS_FEATURE_SUBDIR);
|
|
476
|
+
const RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH = join$332(RULESYNC_RELATIVE_DIR_PATH, CURATED_SKILLS_FEATURE_SUBDIR);
|
|
475
477
|
const RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH = "rulesync.lock";
|
|
476
478
|
const RULESYNC_NPM_SOURCES_LOCK_RELATIVE_FILE_PATH = "rulesync-npm.lock.json";
|
|
477
479
|
const RULESYNC_MCP_FILE_NAME = "mcp.jsonc";
|
|
@@ -495,6 +497,7 @@ const rulesProcessorToolTargetTuple = [
|
|
|
495
497
|
"antigravity-plugin",
|
|
496
498
|
"augmentcode",
|
|
497
499
|
"augmentcode-legacy",
|
|
500
|
+
"bob",
|
|
498
501
|
"claudecode",
|
|
499
502
|
"claudecode-legacy",
|
|
500
503
|
"cline",
|
|
@@ -502,6 +505,7 @@ const rulesProcessorToolTargetTuple = [
|
|
|
502
505
|
"codexcli",
|
|
503
506
|
"copilot",
|
|
504
507
|
"copilotcli",
|
|
508
|
+
"cortexcode",
|
|
505
509
|
"crush",
|
|
506
510
|
"cursor",
|
|
507
511
|
"deepagents",
|
|
@@ -523,6 +527,7 @@ const rulesProcessorToolTargetTuple = [
|
|
|
523
527
|
"replit",
|
|
524
528
|
"roo",
|
|
525
529
|
"rovodev",
|
|
530
|
+
"tabnine",
|
|
526
531
|
"takt",
|
|
527
532
|
"vibe",
|
|
528
533
|
"warp",
|
|
@@ -537,6 +542,7 @@ const ignoreProcessorToolTargetTuple = [
|
|
|
537
542
|
"aiassistant",
|
|
538
543
|
"antigravity-cli",
|
|
539
544
|
"augmentcode",
|
|
545
|
+
"bob",
|
|
540
546
|
"claudecode",
|
|
541
547
|
"claudecode-legacy",
|
|
542
548
|
"cline",
|
|
@@ -551,6 +557,7 @@ const ignoreProcessorToolTargetTuple = [
|
|
|
551
557
|
"qwencode",
|
|
552
558
|
"reasonix",
|
|
553
559
|
"roo",
|
|
560
|
+
"tabnine",
|
|
554
561
|
"devin",
|
|
555
562
|
"vibe",
|
|
556
563
|
"warp",
|
|
@@ -564,6 +571,7 @@ const mcpProcessorToolTargetTuple = [
|
|
|
564
571
|
"antigravity-ide",
|
|
565
572
|
"antigravity-plugin",
|
|
566
573
|
"augmentcode",
|
|
574
|
+
"bob",
|
|
567
575
|
"claudecode",
|
|
568
576
|
"claudecode-plugin",
|
|
569
577
|
"claudecode-legacy",
|
|
@@ -571,6 +579,7 @@ const mcpProcessorToolTargetTuple = [
|
|
|
571
579
|
"codexcli",
|
|
572
580
|
"copilot",
|
|
573
581
|
"copilotcli",
|
|
582
|
+
"cortexcode",
|
|
574
583
|
"cursor",
|
|
575
584
|
"deepagents",
|
|
576
585
|
"factorydroid",
|
|
@@ -589,6 +598,7 @@ const mcpProcessorToolTargetTuple = [
|
|
|
589
598
|
"reasonix",
|
|
590
599
|
"roo",
|
|
591
600
|
"rovodev",
|
|
601
|
+
"tabnine",
|
|
592
602
|
"takt",
|
|
593
603
|
"vibe",
|
|
594
604
|
"warp",
|
|
@@ -602,6 +612,7 @@ const commandsProcessorToolTargetTuple = [
|
|
|
602
612
|
"antigravity-cli",
|
|
603
613
|
"antigravity-ide",
|
|
604
614
|
"augmentcode",
|
|
615
|
+
"bob",
|
|
605
616
|
"claudecode",
|
|
606
617
|
"claudecode-plugin",
|
|
607
618
|
"claudecode-legacy",
|
|
@@ -625,6 +636,7 @@ const commandsProcessorToolTargetTuple = [
|
|
|
625
636
|
"roo",
|
|
626
637
|
"zoocode",
|
|
627
638
|
"rovodev",
|
|
639
|
+
"tabnine",
|
|
628
640
|
"takt",
|
|
629
641
|
"devin",
|
|
630
642
|
"warp",
|
|
@@ -644,6 +656,7 @@ const subagentsProcessorToolTargetTuple = [
|
|
|
644
656
|
"codexcli",
|
|
645
657
|
"copilot",
|
|
646
658
|
"copilotcli",
|
|
659
|
+
"cortexcode",
|
|
647
660
|
"cursor",
|
|
648
661
|
"deepagents",
|
|
649
662
|
"devin",
|
|
@@ -662,6 +675,7 @@ const subagentsProcessorToolTargetTuple = [
|
|
|
662
675
|
"roo",
|
|
663
676
|
"zoocode",
|
|
664
677
|
"rovodev",
|
|
678
|
+
"tabnine",
|
|
665
679
|
"takt",
|
|
666
680
|
"vibe",
|
|
667
681
|
"zcode"
|
|
@@ -675,6 +689,7 @@ const skillsProcessorToolTargetTuple = [
|
|
|
675
689
|
"antigravity-ide",
|
|
676
690
|
"antigravity-plugin",
|
|
677
691
|
"augmentcode",
|
|
692
|
+
"bob",
|
|
678
693
|
"claudecode",
|
|
679
694
|
"claudecode-plugin",
|
|
680
695
|
"claudecode-legacy",
|
|
@@ -682,6 +697,7 @@ const skillsProcessorToolTargetTuple = [
|
|
|
682
697
|
"codexcli",
|
|
683
698
|
"copilot",
|
|
684
699
|
"copilotcli",
|
|
700
|
+
"cortexcode",
|
|
685
701
|
"crush",
|
|
686
702
|
"cursor",
|
|
687
703
|
"deepagents",
|
|
@@ -703,6 +719,7 @@ const skillsProcessorToolTargetTuple = [
|
|
|
703
719
|
"replit",
|
|
704
720
|
"roo",
|
|
705
721
|
"rovodev",
|
|
722
|
+
"tabnine",
|
|
706
723
|
"takt",
|
|
707
724
|
"vibe",
|
|
708
725
|
"warp",
|
|
@@ -725,6 +742,7 @@ const hooksProcessorToolTargetTuple = [
|
|
|
725
742
|
"codexcli",
|
|
726
743
|
"copilot",
|
|
727
744
|
"copilotcli",
|
|
745
|
+
"cortexcode",
|
|
728
746
|
"opencode",
|
|
729
747
|
"pi",
|
|
730
748
|
"factorydroid",
|
|
@@ -737,10 +755,12 @@ const hooksProcessorToolTargetTuple = [
|
|
|
737
755
|
"kiro-ide",
|
|
738
756
|
"devin",
|
|
739
757
|
"augmentcode",
|
|
758
|
+
"bob",
|
|
740
759
|
"junie",
|
|
741
760
|
"vibe",
|
|
742
761
|
"qwencode",
|
|
743
762
|
"reasonix",
|
|
763
|
+
"tabnine",
|
|
744
764
|
"grokcli",
|
|
745
765
|
"zcode"
|
|
746
766
|
];
|
|
@@ -773,6 +793,7 @@ const permissionsProcessorToolTargetTuple = [
|
|
|
773
793
|
"reasonix",
|
|
774
794
|
"roo",
|
|
775
795
|
"rovodev",
|
|
796
|
+
"tabnine",
|
|
776
797
|
"takt",
|
|
777
798
|
"vibe",
|
|
778
799
|
"warp",
|
|
@@ -3258,16 +3279,21 @@ const SHARED_USER_MANAGED_CONFIG_PATHS = [
|
|
|
3258
3279
|
".amp/settings.json",
|
|
3259
3280
|
".amp/settings.jsonc",
|
|
3260
3281
|
".antigravity/settings.json",
|
|
3282
|
+
".bob/settings.json",
|
|
3283
|
+
".bob/settings/settings.json",
|
|
3261
3284
|
".claude/settings.json",
|
|
3262
3285
|
".claude/settings.local.json",
|
|
3263
3286
|
".codex/config.toml",
|
|
3264
3287
|
".copilot/settings.json",
|
|
3265
3288
|
".github/copilot/settings.json",
|
|
3289
|
+
".cortex/settings.json",
|
|
3290
|
+
".snowflake/cortex/hooks.json",
|
|
3266
3291
|
".devin/config.json",
|
|
3267
3292
|
".factory/settings.json",
|
|
3268
3293
|
".grok/config.toml",
|
|
3269
3294
|
".rovodev/config.yml",
|
|
3270
3295
|
".rovodev/mcp.json",
|
|
3296
|
+
".tabnine/agent/settings.json",
|
|
3271
3297
|
".vibe/config.toml",
|
|
3272
3298
|
".zcode/config.json",
|
|
3273
3299
|
".zcode/cli/config.json",
|
|
@@ -4778,6 +4804,110 @@ const CANONICAL_TO_ZCODE_EVENT_NAMES = {
|
|
|
4778
4804
|
};
|
|
4779
4805
|
const ZCODE_TO_CANONICAL_EVENT_NAMES = Object.fromEntries(Object.entries(CANONICAL_TO_ZCODE_EVENT_NAMES).map(([k, v]) => [v, k]));
|
|
4780
4806
|
/**
|
|
4807
|
+
* Hook events supported by IBM Bob's lifecycle hooks.
|
|
4808
|
+
*
|
|
4809
|
+
* Bob reads `hooks` from `.bob/settings.json` (project) and
|
|
4810
|
+
* `~/.bob/settings/settings.json` (user) in the Claude-Code shape and fires
|
|
4811
|
+
* five events: SessionStart, UserPromptSubmit, PreToolUse, PostToolUse and
|
|
4812
|
+
* Stop. Only `command` hooks exist, and `matcher` (a regex over the tool
|
|
4813
|
+
* name) applies to the two tool events.
|
|
4814
|
+
*
|
|
4815
|
+
* @see https://bob.ibm.com/docs/ide/configuration/lifecycle-hooks
|
|
4816
|
+
*/
|
|
4817
|
+
const BOB_HOOK_EVENTS = [
|
|
4818
|
+
"sessionStart",
|
|
4819
|
+
"beforeSubmitPrompt",
|
|
4820
|
+
"preToolUse",
|
|
4821
|
+
"postToolUse",
|
|
4822
|
+
"stop"
|
|
4823
|
+
];
|
|
4824
|
+
const CANONICAL_TO_BOB_EVENT_NAMES = {
|
|
4825
|
+
sessionStart: "SessionStart",
|
|
4826
|
+
beforeSubmitPrompt: "UserPromptSubmit",
|
|
4827
|
+
preToolUse: "PreToolUse",
|
|
4828
|
+
postToolUse: "PostToolUse",
|
|
4829
|
+
stop: "Stop"
|
|
4830
|
+
};
|
|
4831
|
+
const BOB_TO_CANONICAL_EVENT_NAMES = Object.fromEntries(Object.entries(CANONICAL_TO_BOB_EVENT_NAMES).map(([k, v]) => [v, k]));
|
|
4832
|
+
/**
|
|
4833
|
+
* Hook events supported by Tabnine CLI.
|
|
4834
|
+
*
|
|
4835
|
+
* Tabnine CLI reads `hooks` from `.tabnine/agent/settings.json` (project) and
|
|
4836
|
+
* `~/.tabnine/agent/settings.json` (user) and fires eleven events with
|
|
4837
|
+
* PascalCase names. Only `command` hooks exist; `matcher` is a regex over the
|
|
4838
|
+
* tool name for the two tool events and an exact string for the lifecycle
|
|
4839
|
+
* events, and `timeout` is expressed in milliseconds.
|
|
4840
|
+
*
|
|
4841
|
+
* @see https://docs.tabnine.com/main/getting-started/tabnine-cli/features/hooks
|
|
4842
|
+
* @see https://docs.tabnine.com/main/getting-started/tabnine-cli/features/hooks/configuration
|
|
4843
|
+
*/
|
|
4844
|
+
const TABNINE_HOOK_EVENTS = [
|
|
4845
|
+
"sessionStart",
|
|
4846
|
+
"sessionEnd",
|
|
4847
|
+
"beforeSubmitPrompt",
|
|
4848
|
+
"stop",
|
|
4849
|
+
"preModelInvocation",
|
|
4850
|
+
"postModelInvocation",
|
|
4851
|
+
"beforeToolSelection",
|
|
4852
|
+
"preToolUse",
|
|
4853
|
+
"postToolUse",
|
|
4854
|
+
"preCompact",
|
|
4855
|
+
"notification"
|
|
4856
|
+
];
|
|
4857
|
+
const CANONICAL_TO_TABNINE_EVENT_NAMES = {
|
|
4858
|
+
sessionStart: "SessionStart",
|
|
4859
|
+
sessionEnd: "SessionEnd",
|
|
4860
|
+
beforeSubmitPrompt: "BeforeAgent",
|
|
4861
|
+
stop: "AfterAgent",
|
|
4862
|
+
preModelInvocation: "BeforeModel",
|
|
4863
|
+
postModelInvocation: "AfterModel",
|
|
4864
|
+
beforeToolSelection: "BeforeToolSelection",
|
|
4865
|
+
preToolUse: "BeforeTool",
|
|
4866
|
+
postToolUse: "AfterTool",
|
|
4867
|
+
preCompact: "PreCompress",
|
|
4868
|
+
notification: "Notification"
|
|
4869
|
+
};
|
|
4870
|
+
const TABNINE_TO_CANONICAL_EVENT_NAMES = Object.fromEntries(Object.entries(CANONICAL_TO_TABNINE_EVENT_NAMES).map(([k, v]) => [v, k]));
|
|
4871
|
+
/**
|
|
4872
|
+
* Hook events supported by Snowflake Cortex Code.
|
|
4873
|
+
*
|
|
4874
|
+
* Cortex Code reads `hooks` from `.cortex/settings.json` (project) and
|
|
4875
|
+
* `~/.snowflake/cortex/hooks.json` (user) in the Claude-Code-shaped layout:
|
|
4876
|
+
* PascalCase event names, a regex `matcher` over the tool name, and `command`
|
|
4877
|
+
* or `prompt` hooks with a `timeout` in seconds and an optional `enabled`
|
|
4878
|
+
* flag. `$CORTEX_PROJECT_DIR` resolves to the project root inside commands.
|
|
4879
|
+
*
|
|
4880
|
+
* @see https://docs.snowflake.com/en/user-guide/cortex-code/extensibility
|
|
4881
|
+
* @see https://docs.snowflake.com/en/user-guide/cortex-code/settings
|
|
4882
|
+
*/
|
|
4883
|
+
const CORTEXCODE_HOOK_EVENTS = [
|
|
4884
|
+
"preToolUse",
|
|
4885
|
+
"postToolUse",
|
|
4886
|
+
"permissionRequest",
|
|
4887
|
+
"beforeSubmitPrompt",
|
|
4888
|
+
"sessionStart",
|
|
4889
|
+
"sessionEnd",
|
|
4890
|
+
"preCompact",
|
|
4891
|
+
"stop",
|
|
4892
|
+
"subagentStop",
|
|
4893
|
+
"notification",
|
|
4894
|
+
"setup"
|
|
4895
|
+
];
|
|
4896
|
+
const CANONICAL_TO_CORTEXCODE_EVENT_NAMES = {
|
|
4897
|
+
preToolUse: "PreToolUse",
|
|
4898
|
+
postToolUse: "PostToolUse",
|
|
4899
|
+
permissionRequest: "PermissionRequest",
|
|
4900
|
+
beforeSubmitPrompt: "UserPromptSubmit",
|
|
4901
|
+
sessionStart: "SessionStart",
|
|
4902
|
+
sessionEnd: "SessionEnd",
|
|
4903
|
+
preCompact: "PreCompact",
|
|
4904
|
+
stop: "Stop",
|
|
4905
|
+
subagentStop: "SubagentStop",
|
|
4906
|
+
notification: "Notification",
|
|
4907
|
+
setup: "Setup"
|
|
4908
|
+
};
|
|
4909
|
+
const CORTEXCODE_TO_CANONICAL_EVENT_NAMES = Object.fromEntries(Object.entries(CANONICAL_TO_CORTEXCODE_EVENT_NAMES).map(([k, v]) => [v, k]));
|
|
4910
|
+
/**
|
|
4781
4911
|
* Hook events supported by Hermes Agent's native Shell Hooks system.
|
|
4782
4912
|
*
|
|
4783
4913
|
* Hermes validates hook events against a fixed `VALID_HOOKS` set — 37 entries as
|
|
@@ -4930,6 +5060,9 @@ const HooksConfigSchema = zod_mini.z.looseObject({
|
|
|
4930
5060
|
grokcli: zod_mini.z.optional(zod_mini.z.looseObject({ hooks: zod_mini.z.optional(hooksRecordSchema) })),
|
|
4931
5061
|
"kimi-code": zod_mini.z.optional(zod_mini.z.looseObject({ hooks: zod_mini.z.optional(hooksRecordSchema) })),
|
|
4932
5062
|
zcode: zod_mini.z.optional(zod_mini.z.looseObject({ hooks: zod_mini.z.optional(hooksRecordSchema) })),
|
|
5063
|
+
bob: zod_mini.z.optional(zod_mini.z.looseObject({ hooks: zod_mini.z.optional(hooksRecordSchema) })),
|
|
5064
|
+
cortexcode: zod_mini.z.optional(zod_mini.z.looseObject({ hooks: zod_mini.z.optional(hooksRecordSchema) })),
|
|
5065
|
+
tabnine: zod_mini.z.optional(zod_mini.z.looseObject({ hooks: zod_mini.z.optional(hooksRecordSchema) })),
|
|
4933
5066
|
qwencode: zod_mini.z.optional(zod_mini.z.looseObject({
|
|
4934
5067
|
hooks: zod_mini.z.optional(hooksRecordSchema),
|
|
4935
5068
|
disableAllHooks: zod_mini.z.optional(zod_mini.z.boolean())
|
|
@@ -5931,6 +6064,7 @@ const RulesyncMcpFileSchema = zod_mini.z.looseObject({
|
|
|
5931
6064
|
"antigravity-ide": zod_mini.z.optional(toolScopedMcpSchema),
|
|
5932
6065
|
aiassistant: zod_mini.z.optional(toolScopedMcpSchema),
|
|
5933
6066
|
augmentcode: zod_mini.z.optional(toolScopedMcpSchema),
|
|
6067
|
+
bob: zod_mini.z.optional(toolScopedMcpSchema),
|
|
5934
6068
|
claudecode: zod_mini.z.optional(toolScopedMcpSchema),
|
|
5935
6069
|
cline: zod_mini.z.optional(toolScopedMcpSchema),
|
|
5936
6070
|
codexcli: zod_mini.z.optional(toolScopedMcpSchema),
|
|
@@ -5952,6 +6086,8 @@ const RulesyncMcpFileSchema = zod_mini.z.looseObject({
|
|
|
5952
6086
|
reasonix: zod_mini.z.optional(toolScopedMcpSchema),
|
|
5953
6087
|
roo: zod_mini.z.optional(toolScopedMcpSchema),
|
|
5954
6088
|
rovodev: zod_mini.z.optional(toolScopedMcpSchema),
|
|
6089
|
+
cortexcode: zod_mini.z.optional(toolScopedMcpSchema),
|
|
6090
|
+
tabnine: zod_mini.z.optional(toolScopedMcpSchema),
|
|
5955
6091
|
takt: zod_mini.z.optional(toolScopedMcpSchema),
|
|
5956
6092
|
vibe: zod_mini.z.optional(toolScopedMcpSchema),
|
|
5957
6093
|
warp: zod_mini.z.optional(toolScopedMcpSchema),
|
|
@@ -6773,6 +6909,27 @@ const QwencodePermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
|
6773
6909
|
autoMode: zod_mini.z.optional(zod_mini.z.looseObject({}))
|
|
6774
6910
|
});
|
|
6775
6911
|
/**
|
|
6912
|
+
* Tool-scoped override block for Tabnine CLI. The canonical `permission` block
|
|
6913
|
+
* drives only the `tools.allowed` / `tools.exclude` lists of
|
|
6914
|
+
* `.tabnine/agent/settings.json`; the other `tools.*` keys (`core`,
|
|
6915
|
+
* `enableCoaching`, `useRipgrep`, `shell.*`, `enableWebTools`, ...) and the
|
|
6916
|
+
* `general.defaultApprovalMode` switch have no canonical category, so they are
|
|
6917
|
+
* authored here, deep-merged into the settings file, and emitted only for
|
|
6918
|
+
* Tabnine. Import lifts the entries rulesync cannot map back onto a canonical
|
|
6919
|
+
* category into this block so a regenerate does not drop them. Kept
|
|
6920
|
+
* `looseObject` (verbatim passthrough). Both project and global scope are
|
|
6921
|
+
* supported.
|
|
6922
|
+
*
|
|
6923
|
+
* @example
|
|
6924
|
+
* { "tools": { "core": ["read_file", "run_shell_command(git)"] },
|
|
6925
|
+
* "general": { "defaultApprovalMode": "plan" } }
|
|
6926
|
+
*/
|
|
6927
|
+
const TabninePermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
6928
|
+
permission: zod_mini.z.optional(ToolScopedPermissionSchema),
|
|
6929
|
+
tools: zod_mini.z.optional(zod_mini.z.looseObject({})),
|
|
6930
|
+
general: zod_mini.z.optional(zod_mini.z.looseObject({}))
|
|
6931
|
+
});
|
|
6932
|
+
/**
|
|
6776
6933
|
* Tool-scoped override block for Reasonix. Reasonix has security axes orthogonal
|
|
6777
6934
|
* to per-tool allow/ask/deny with no canonical category — the `[sandbox]`
|
|
6778
6935
|
* enforcement table (`workspace_root`, `allow_write`, `forbid_read`, `bash`,
|
|
@@ -7533,6 +7690,7 @@ const PermissionsConfigSchema = zod_mini.z.looseObject({
|
|
|
7533
7690
|
factorydroid: zod_mini.z.optional(FactorydroidPermissionsOverrideSchema),
|
|
7534
7691
|
warp: zod_mini.z.optional(WarpPermissionsOverrideSchema),
|
|
7535
7692
|
junie: zod_mini.z.optional(JuniePermissionsOverrideSchema),
|
|
7693
|
+
tabnine: zod_mini.z.optional(TabninePermissionsOverrideSchema),
|
|
7536
7694
|
takt: zod_mini.z.optional(TaktPermissionsOverrideSchema),
|
|
7537
7695
|
amp: zod_mini.z.optional(AmpPermissionsOverrideSchema),
|
|
7538
7696
|
"antigravity-cli": zod_mini.z.optional(AntigravityCliPermissionsOverrideSchema),
|
|
@@ -9180,6 +9338,7 @@ const RulesyncSkillFrontmatterSchema = zod_mini.z.looseObject({
|
|
|
9180
9338
|
})),
|
|
9181
9339
|
cline: zod_mini.z.optional(zod_mini.z.looseObject({})),
|
|
9182
9340
|
roo: zod_mini.z.optional(zod_mini.z.looseObject({})),
|
|
9341
|
+
bob: zod_mini.z.optional(zod_mini.z.looseObject({})),
|
|
9183
9342
|
amp: zod_mini.z.optional(zod_mini.z.looseObject({})),
|
|
9184
9343
|
devin: zod_mini.z.optional(zod_mini.z.looseObject({
|
|
9185
9344
|
"argument-hint": zod_mini.z.optional(zod_mini.z.string()),
|
|
@@ -9257,6 +9416,8 @@ const RulesyncSkillFrontmatterSchema = zod_mini.z.looseObject({
|
|
|
9257
9416
|
"user-invocable": zod_mini.z.optional(zod_mini.z.boolean()),
|
|
9258
9417
|
"allowed-tools": zod_mini.z.optional(zod_mini.z.union([zod_mini.z.string(), zod_mini.z.array(zod_mini.z.string())]))
|
|
9259
9418
|
})),
|
|
9419
|
+
cortexcode: zod_mini.z.optional(zod_mini.z.looseObject({})),
|
|
9420
|
+
tabnine: zod_mini.z.optional(zod_mini.z.looseObject({})),
|
|
9260
9421
|
takt: zod_mini.z.optional(zod_mini.z.looseObject({
|
|
9261
9422
|
name: zod_mini.z.optional(zod_mini.z.string()),
|
|
9262
9423
|
extends: zod_mini.z.optional(zod_mini.z.string())
|
|
@@ -12819,6 +12980,53 @@ const SHARED_CONFIG_OWNERSHIP = {
|
|
|
12819
12980
|
},
|
|
12820
12981
|
".zcode/config.json": ZCODE_WORKSPACE_CONFIG_DECLARATION,
|
|
12821
12982
|
".zcode/cli/config.json": ZCODE_USER_CONFIG_DECLARATION,
|
|
12983
|
+
".bob/settings.json": {
|
|
12984
|
+
format: "json",
|
|
12985
|
+
invalidRootPolicy: "error",
|
|
12986
|
+
features: { hooks: {
|
|
12987
|
+
kind: "replace-owned-keys",
|
|
12988
|
+
ownedKeys: ["hooks"]
|
|
12989
|
+
} }
|
|
12990
|
+
},
|
|
12991
|
+
".bob/settings/settings.json": {
|
|
12992
|
+
format: "json",
|
|
12993
|
+
invalidRootPolicy: "error",
|
|
12994
|
+
features: { hooks: {
|
|
12995
|
+
kind: "replace-owned-keys",
|
|
12996
|
+
ownedKeys: ["hooks"]
|
|
12997
|
+
} }
|
|
12998
|
+
},
|
|
12999
|
+
".cortex/settings.json": {
|
|
13000
|
+
format: "json",
|
|
13001
|
+
invalidRootPolicy: "error",
|
|
13002
|
+
features: { hooks: {
|
|
13003
|
+
kind: "replace-owned-keys",
|
|
13004
|
+
ownedKeys: ["hooks"]
|
|
13005
|
+
} }
|
|
13006
|
+
},
|
|
13007
|
+
".snowflake/cortex/hooks.json": {
|
|
13008
|
+
format: "json",
|
|
13009
|
+
invalidRootPolicy: "error",
|
|
13010
|
+
features: { hooks: {
|
|
13011
|
+
kind: "replace-owned-keys",
|
|
13012
|
+
ownedKeys: ["hooks"]
|
|
13013
|
+
} }
|
|
13014
|
+
},
|
|
13015
|
+
".tabnine/agent/settings.json": {
|
|
13016
|
+
format: "json",
|
|
13017
|
+
invalidRootPolicy: "error",
|
|
13018
|
+
features: {
|
|
13019
|
+
mcp: {
|
|
13020
|
+
kind: "replace-owned-keys",
|
|
13021
|
+
ownedKeys: ["mcpServers"]
|
|
13022
|
+
},
|
|
13023
|
+
hooks: {
|
|
13024
|
+
kind: "replace-owned-keys",
|
|
13025
|
+
ownedKeys: ["hooks"]
|
|
13026
|
+
},
|
|
13027
|
+
permissions: { kind: "deep-merge" }
|
|
13028
|
+
}
|
|
13029
|
+
},
|
|
12822
13030
|
".kiro/agents/default.json": {
|
|
12823
13031
|
format: "json",
|
|
12824
13032
|
features: {
|
|
@@ -14511,6 +14719,140 @@ var AugmentcodeCommand = class AugmentcodeCommand extends ToolCommand {
|
|
|
14511
14719
|
}
|
|
14512
14720
|
};
|
|
14513
14721
|
//#endregion
|
|
14722
|
+
//#region src/constants/bob-paths.ts
|
|
14723
|
+
const BOB_DIR = ".bob";
|
|
14724
|
+
const BOB_RULE_FILE_NAME = "AGENTS.md";
|
|
14725
|
+
(0, node_path.join)(BOB_DIR, "rules");
|
|
14726
|
+
const BOB_IGNORE_FILE_NAME = ".bobignore";
|
|
14727
|
+
const BOB_MCP_FILE_NAME = "mcp.json";
|
|
14728
|
+
const BOB_COMMANDS_DIR_PATH = (0, node_path.join)(BOB_DIR, "commands");
|
|
14729
|
+
const BOB_SKILLS_DIR_PATH = (0, node_path.join)(BOB_DIR, "skills");
|
|
14730
|
+
const BOB_SETTINGS_FILE_NAME = "settings.json";
|
|
14731
|
+
const BOB_GLOBAL_SETTINGS_DIR_PATH = (0, node_path.join)(BOB_DIR, "settings");
|
|
14732
|
+
//#endregion
|
|
14733
|
+
//#region src/features/commands/bob-command.ts
|
|
14734
|
+
/**
|
|
14735
|
+
* IBM Bob slash commands are Markdown files under `<project>/.bob/commands/`
|
|
14736
|
+
* (project scope) and `~/.bob/commands/` (user scope), invoked from the chat
|
|
14737
|
+
* input with `/`. The file name is the command name; the optional
|
|
14738
|
+
* `description` / `argument-hint` frontmatter keys are the same ones the
|
|
14739
|
+
* Claude-Code-lineage tools use, and the body is the prompt Bob runs.
|
|
14740
|
+
*
|
|
14741
|
+
* @see https://bob.ibm.com/docs/ide/features/slash-commands
|
|
14742
|
+
* @see https://bob.ibm.com/docs/shell/features/slash-commands
|
|
14743
|
+
*/
|
|
14744
|
+
const BobCommandFrontmatterSchema = zod_mini.z.looseObject({
|
|
14745
|
+
description: zod_mini.z.optional(zod_mini.z.string()),
|
|
14746
|
+
"argument-hint": zod_mini.z.optional(zod_mini.z.string())
|
|
14747
|
+
});
|
|
14748
|
+
var BobCommand = class BobCommand extends ToolCommand {
|
|
14749
|
+
frontmatter;
|
|
14750
|
+
body;
|
|
14751
|
+
constructor({ frontmatter, body, ...rest }) {
|
|
14752
|
+
if (rest.validate) {
|
|
14753
|
+
const result = BobCommandFrontmatterSchema.safeParse(frontmatter);
|
|
14754
|
+
if (!result.success) throw new Error(`Invalid frontmatter in ${(0, node_path.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`);
|
|
14755
|
+
}
|
|
14756
|
+
super({
|
|
14757
|
+
...rest,
|
|
14758
|
+
fileContent: stringifyFrontmatter(body, frontmatter)
|
|
14759
|
+
});
|
|
14760
|
+
this.frontmatter = frontmatter;
|
|
14761
|
+
this.body = body;
|
|
14762
|
+
}
|
|
14763
|
+
static getSettablePaths(_options = {}) {
|
|
14764
|
+
return { relativeDirPath: BOB_COMMANDS_DIR_PATH };
|
|
14765
|
+
}
|
|
14766
|
+
getBody() {
|
|
14767
|
+
return this.body;
|
|
14768
|
+
}
|
|
14769
|
+
getFrontmatter() {
|
|
14770
|
+
return this.frontmatter;
|
|
14771
|
+
}
|
|
14772
|
+
toRulesyncCommand() {
|
|
14773
|
+
const { description, ...restFields } = this.frontmatter;
|
|
14774
|
+
const rulesyncFrontmatter = {
|
|
14775
|
+
targets: ["*"],
|
|
14776
|
+
description,
|
|
14777
|
+
...Object.keys(restFields).length > 0 && { bob: restFields }
|
|
14778
|
+
};
|
|
14779
|
+
const fileContent = stringifyFrontmatter(this.body, rulesyncFrontmatter);
|
|
14780
|
+
return new RulesyncCommand({
|
|
14781
|
+
outputRoot: ".",
|
|
14782
|
+
frontmatter: rulesyncFrontmatter,
|
|
14783
|
+
body: this.body,
|
|
14784
|
+
relativeDirPath: RulesyncCommand.getSettablePaths().relativeDirPath,
|
|
14785
|
+
relativeFilePath: this.relativeFilePath,
|
|
14786
|
+
fileContent,
|
|
14787
|
+
validate: true
|
|
14788
|
+
});
|
|
14789
|
+
}
|
|
14790
|
+
static fromRulesyncCommand({ outputRoot = process.cwd(), rulesyncCommand, validate = true, global = false }) {
|
|
14791
|
+
const rulesyncFrontmatter = rulesyncCommand.getFrontmatter();
|
|
14792
|
+
const bobFields = rulesyncFrontmatter.bob ?? {};
|
|
14793
|
+
const bobFrontmatter = {
|
|
14794
|
+
description: rulesyncFrontmatter.description,
|
|
14795
|
+
...bobFields
|
|
14796
|
+
};
|
|
14797
|
+
const body = rulesyncCommand.getBody();
|
|
14798
|
+
const paths = this.getSettablePaths({ global });
|
|
14799
|
+
return new BobCommand({
|
|
14800
|
+
outputRoot,
|
|
14801
|
+
frontmatter: bobFrontmatter,
|
|
14802
|
+
body,
|
|
14803
|
+
relativeDirPath: paths.relativeDirPath,
|
|
14804
|
+
relativeFilePath: rulesyncCommand.getRelativeFilePath(),
|
|
14805
|
+
validate
|
|
14806
|
+
});
|
|
14807
|
+
}
|
|
14808
|
+
validate() {
|
|
14809
|
+
if (!this.frontmatter) return {
|
|
14810
|
+
success: true,
|
|
14811
|
+
error: null
|
|
14812
|
+
};
|
|
14813
|
+
const result = BobCommandFrontmatterSchema.safeParse(this.frontmatter);
|
|
14814
|
+
if (result.success) return {
|
|
14815
|
+
success: true,
|
|
14816
|
+
error: null
|
|
14817
|
+
};
|
|
14818
|
+
return {
|
|
14819
|
+
success: false,
|
|
14820
|
+
error: /* @__PURE__ */ new Error(`Invalid frontmatter in ${(0, node_path.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`)
|
|
14821
|
+
};
|
|
14822
|
+
}
|
|
14823
|
+
static isTargetedByRulesyncCommand(rulesyncCommand) {
|
|
14824
|
+
return this.isTargetedByRulesyncCommandDefault({
|
|
14825
|
+
rulesyncCommand,
|
|
14826
|
+
toolTarget: "bob"
|
|
14827
|
+
});
|
|
14828
|
+
}
|
|
14829
|
+
static async fromFile({ outputRoot = process.cwd(), relativeFilePath, validate = true, global = false }) {
|
|
14830
|
+
const paths = this.getSettablePaths({ global });
|
|
14831
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, relativeFilePath);
|
|
14832
|
+
const { frontmatter, body: content } = parseFrontmatter(await readFileContent(filePath), filePath);
|
|
14833
|
+
const result = BobCommandFrontmatterSchema.safeParse(frontmatter);
|
|
14834
|
+
if (!result.success) throw new Error(`Invalid frontmatter in ${filePath}: ${formatError(result.error)}`);
|
|
14835
|
+
return new BobCommand({
|
|
14836
|
+
outputRoot,
|
|
14837
|
+
relativeDirPath: paths.relativeDirPath,
|
|
14838
|
+
relativeFilePath,
|
|
14839
|
+
frontmatter: result.data,
|
|
14840
|
+
body: content.trim(),
|
|
14841
|
+
validate
|
|
14842
|
+
});
|
|
14843
|
+
}
|
|
14844
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
|
|
14845
|
+
return new BobCommand({
|
|
14846
|
+
outputRoot,
|
|
14847
|
+
relativeDirPath,
|
|
14848
|
+
relativeFilePath,
|
|
14849
|
+
frontmatter: { description: "" },
|
|
14850
|
+
body: "",
|
|
14851
|
+
validate: false
|
|
14852
|
+
});
|
|
14853
|
+
}
|
|
14854
|
+
};
|
|
14855
|
+
//#endregion
|
|
14514
14856
|
//#region src/features/commands/claudecode-command.ts
|
|
14515
14857
|
const ClaudecodeCommandFrontmatterSchema = zod_mini.z.looseObject({
|
|
14516
14858
|
description: zod_mini.z.optional(zod_mini.z.string()),
|
|
@@ -18237,6 +18579,193 @@ var RovodevPromptsManifest = class extends ToolFile {
|
|
|
18237
18579
|
}
|
|
18238
18580
|
};
|
|
18239
18581
|
//#endregion
|
|
18582
|
+
//#region src/constants/tabnine-paths.ts
|
|
18583
|
+
const TABNINE_DIR = ".tabnine";
|
|
18584
|
+
const TABNINE_AGENT_DIR_PATH = (0, node_path.join)(TABNINE_DIR, "agent");
|
|
18585
|
+
const TABNINE_RULE_FILE_NAME = "TABNINE.md";
|
|
18586
|
+
(0, node_path.join)(TABNINE_DIR, "guidelines");
|
|
18587
|
+
const TABNINE_IGNORE_FILE_NAME = ".tabnineignore";
|
|
18588
|
+
const TABNINE_SETTINGS_FILE_NAME = "settings.json";
|
|
18589
|
+
const TABNINE_COMMANDS_DIR_PATH = (0, node_path.join)(TABNINE_AGENT_DIR_PATH, "commands");
|
|
18590
|
+
const TABNINE_AGENTS_DIR_PATH = (0, node_path.join)(TABNINE_AGENT_DIR_PATH, "agents");
|
|
18591
|
+
const TABNINE_SKILLS_DIR_PATH = (0, node_path.join)(TABNINE_AGENT_DIR_PATH, "skills");
|
|
18592
|
+
//#endregion
|
|
18593
|
+
//#region src/features/commands/tabnine-command.ts
|
|
18594
|
+
const TabnineCommandFrontmatterSchema = zod_mini.z.looseObject({
|
|
18595
|
+
description: zod_mini.z.optional(zod_mini.z.string()),
|
|
18596
|
+
prompt: zod_mini.z.string()
|
|
18597
|
+
});
|
|
18598
|
+
/**
|
|
18599
|
+
* Translate rulesync universal command syntax (Claude Code compatible) into
|
|
18600
|
+
* Tabnine CLI's native syntax. See docs/reference/command-syntax.md. Tabnine
|
|
18601
|
+
* CLI is a Gemini CLI derivative and documents the same placeholders:
|
|
18602
|
+
* `{{args}}` for the user's arguments and `!{cmd}` for shell injection. Its
|
|
18603
|
+
* `@{path}` file-injection form has no universal counterpart and passes
|
|
18604
|
+
* through untouched in both directions.
|
|
18605
|
+
* @see https://docs.tabnine.com/main/getting-started/tabnine-cli/features/commands
|
|
18606
|
+
*
|
|
18607
|
+
* Replacement order:
|
|
18608
|
+
* 1. `` !`cmd` `` → `!{cmd}` (backtick shell expansion → brace form)
|
|
18609
|
+
* 2. `$ARGUMENTS` → `{{args}}` (handled after step 1 so that
|
|
18610
|
+
* `` !`echo $ARGUMENTS` `` survives as `!{echo {{args}}}` rather than
|
|
18611
|
+
* requiring two passes).
|
|
18612
|
+
*
|
|
18613
|
+
* `$ARGUMENTS\b` uses a trailing word boundary so `$ARGUMENTSx` and
|
|
18614
|
+
* `$ARGUMENTS_FOO` are left alone, while `$ARGUMENTS-foo` (hyphen is not a
|
|
18615
|
+
* word char) is rewritten. There is no leading anchor, so `prefix$ARGUMENTS`
|
|
18616
|
+
* is rewritten to `prefix{{args}}`.
|
|
18617
|
+
*
|
|
18618
|
+
* Bodies that already contain Tabnine-native forms (`{{args}}` or `!{cmd}`)
|
|
18619
|
+
* are left untouched, which gives us the documented "we do not re-translate
|
|
18620
|
+
* already-Tabnine-native forms" property.
|
|
18621
|
+
*/
|
|
18622
|
+
function translateRulesyncBodyToTabnine(body) {
|
|
18623
|
+
return body.replace(/!`([^`\n]+)`/g, "!{$1}").replace(/\$ARGUMENTS\b/g, "{{args}}");
|
|
18624
|
+
}
|
|
18625
|
+
/**
|
|
18626
|
+
* Inverse of {@link translateRulesyncBodyToTabnine}, used when importing a
|
|
18627
|
+
* Tabnine CLI command file back into rulesync's universal syntax.
|
|
18628
|
+
*
|
|
18629
|
+
* Replacement order is intentionally inverted from the forward direction:
|
|
18630
|
+
* 1. `{{args}}` → `$ARGUMENTS` (handled first)
|
|
18631
|
+
* 2. `!{cmd}` → `` !`cmd` `` (handled second, with a non-greedy body
|
|
18632
|
+
* `[^}\n]+?`)
|
|
18633
|
+
*
|
|
18634
|
+
* Doing `{{args}}` first ensures that nested forms like
|
|
18635
|
+
* `!{echo {{args}}}` round-trip back to `` !`echo $ARGUMENTS` `` in a single
|
|
18636
|
+
* pass: the inner `{{args}}` is rewritten to `$ARGUMENTS`, and then the
|
|
18637
|
+
* non-greedy `!{...}` match consumes the smallest possible body.
|
|
18638
|
+
*/
|
|
18639
|
+
function translateTabnineBodyToRulesync(body) {
|
|
18640
|
+
return body.replace(/\{\{\s*args\s*\}\}/g, "$ARGUMENTS").replace(/!\{([^}\n]+?)\}/g, "!`$1`");
|
|
18641
|
+
}
|
|
18642
|
+
/**
|
|
18643
|
+
* Tabnine CLI custom slash commands: TOML files with `description` and
|
|
18644
|
+
* `prompt` under `<project>/.tabnine/agent/commands/` (project) and
|
|
18645
|
+
* `~/.tabnine/agent/commands/` (user). The relative path names the command:
|
|
18646
|
+
* `review.toml` → `/review`, `code/review.toml` → `/code:review`.
|
|
18647
|
+
* @see https://docs.tabnine.com/main/getting-started/tabnine-cli/features/commands
|
|
18648
|
+
*/
|
|
18649
|
+
var TabnineCommand = class TabnineCommand extends ToolCommand {
|
|
18650
|
+
frontmatter;
|
|
18651
|
+
body;
|
|
18652
|
+
constructor(params) {
|
|
18653
|
+
super(params);
|
|
18654
|
+
const parsed = this.parseTomlContent(this.fileContent);
|
|
18655
|
+
this.frontmatter = parsed;
|
|
18656
|
+
this.body = parsed.prompt;
|
|
18657
|
+
}
|
|
18658
|
+
static getSettablePaths(_options = {}) {
|
|
18659
|
+
return { relativeDirPath: TABNINE_COMMANDS_DIR_PATH };
|
|
18660
|
+
}
|
|
18661
|
+
parseTomlContent(content) {
|
|
18662
|
+
try {
|
|
18663
|
+
const parsed = (0, smol_toml.parse)(content);
|
|
18664
|
+
const result = TabnineCommandFrontmatterSchema.safeParse(parsed);
|
|
18665
|
+
if (!result.success) throw new Error(`Invalid frontmatter in ${(0, node_path.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`);
|
|
18666
|
+
return {
|
|
18667
|
+
...result.data,
|
|
18668
|
+
description: result.data.description
|
|
18669
|
+
};
|
|
18670
|
+
} catch (error) {
|
|
18671
|
+
throw new Error(`Failed to parse TOML command file (${(0, node_path.join)(this.relativeDirPath, this.relativeFilePath)}): ${formatError(error)}`, { cause: error });
|
|
18672
|
+
}
|
|
18673
|
+
}
|
|
18674
|
+
getBody() {
|
|
18675
|
+
return this.body;
|
|
18676
|
+
}
|
|
18677
|
+
getFrontmatter() {
|
|
18678
|
+
return {
|
|
18679
|
+
description: this.frontmatter.description,
|
|
18680
|
+
prompt: this.frontmatter.prompt
|
|
18681
|
+
};
|
|
18682
|
+
}
|
|
18683
|
+
toRulesyncCommand() {
|
|
18684
|
+
const { description, prompt: _prompt, ...restFields } = this.frontmatter;
|
|
18685
|
+
const rulesyncFrontmatter = {
|
|
18686
|
+
targets: ["tabnine"],
|
|
18687
|
+
description,
|
|
18688
|
+
...Object.keys(restFields).length > 0 && { tabnine: restFields }
|
|
18689
|
+
};
|
|
18690
|
+
const universalBody = translateTabnineBodyToRulesync(this.body);
|
|
18691
|
+
const fileContent = stringifyFrontmatter(universalBody, rulesyncFrontmatter);
|
|
18692
|
+
return new RulesyncCommand({
|
|
18693
|
+
outputRoot: process.cwd(),
|
|
18694
|
+
frontmatter: rulesyncFrontmatter,
|
|
18695
|
+
body: universalBody,
|
|
18696
|
+
relativeDirPath: RulesyncCommand.getSettablePaths().relativeDirPath,
|
|
18697
|
+
relativeFilePath: this.relativeFilePath.replace(/\.toml$/, ".md"),
|
|
18698
|
+
fileContent,
|
|
18699
|
+
validate: true
|
|
18700
|
+
});
|
|
18701
|
+
}
|
|
18702
|
+
static fromRulesyncCommand({ outputRoot = process.cwd(), rulesyncCommand, validate = true, global = false }) {
|
|
18703
|
+
const rulesyncFrontmatter = rulesyncCommand.getFrontmatter();
|
|
18704
|
+
const tabnineFields = rulesyncFrontmatter.tabnine ?? {};
|
|
18705
|
+
const translatedPrompt = typeof tabnineFields.prompt === "string" ? "" : translateRulesyncBodyToTabnine(rulesyncCommand.getBody());
|
|
18706
|
+
const tabnineFrontmatter = {
|
|
18707
|
+
description: rulesyncFrontmatter.description,
|
|
18708
|
+
prompt: translatedPrompt,
|
|
18709
|
+
...tabnineFields
|
|
18710
|
+
};
|
|
18711
|
+
const tomlObject = {};
|
|
18712
|
+
if (tabnineFrontmatter.description !== void 0) tomlObject.description = tabnineFrontmatter.description;
|
|
18713
|
+
tomlObject.prompt = tabnineFrontmatter.prompt.endsWith("\n") ? tabnineFrontmatter.prompt : `${tabnineFrontmatter.prompt}\n`;
|
|
18714
|
+
const { description: _description, prompt: _prompt, ...extraFields } = tabnineFrontmatter;
|
|
18715
|
+
for (const [key, value] of Object.entries(omitPrototypePollutionKeys(extraFields))) if (value !== void 0) tomlObject[key] = value;
|
|
18716
|
+
const tomlContent = (0, smol_toml.stringify)(tomlObject);
|
|
18717
|
+
const paths = this.getSettablePaths({ global });
|
|
18718
|
+
return new TabnineCommand({
|
|
18719
|
+
outputRoot,
|
|
18720
|
+
relativeDirPath: paths.relativeDirPath,
|
|
18721
|
+
relativeFilePath: rulesyncCommand.getRelativeFilePath().replace(/\.md$/, ".toml"),
|
|
18722
|
+
fileContent: tomlContent,
|
|
18723
|
+
validate
|
|
18724
|
+
});
|
|
18725
|
+
}
|
|
18726
|
+
static async fromFile({ outputRoot = process.cwd(), relativeFilePath, validate = true, global = false }) {
|
|
18727
|
+
const paths = this.getSettablePaths({ global });
|
|
18728
|
+
const fileContent = await readFileContent((0, node_path.join)(outputRoot, paths.relativeDirPath, relativeFilePath));
|
|
18729
|
+
return new TabnineCommand({
|
|
18730
|
+
outputRoot,
|
|
18731
|
+
relativeDirPath: paths.relativeDirPath,
|
|
18732
|
+
relativeFilePath,
|
|
18733
|
+
fileContent,
|
|
18734
|
+
validate
|
|
18735
|
+
});
|
|
18736
|
+
}
|
|
18737
|
+
validate() {
|
|
18738
|
+
try {
|
|
18739
|
+
this.parseTomlContent(this.fileContent);
|
|
18740
|
+
return {
|
|
18741
|
+
success: true,
|
|
18742
|
+
error: null
|
|
18743
|
+
};
|
|
18744
|
+
} catch (error) {
|
|
18745
|
+
return {
|
|
18746
|
+
success: false,
|
|
18747
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
18748
|
+
};
|
|
18749
|
+
}
|
|
18750
|
+
}
|
|
18751
|
+
static isTargetedByRulesyncCommand(rulesyncCommand) {
|
|
18752
|
+
return this.isTargetedByRulesyncCommandDefault({
|
|
18753
|
+
rulesyncCommand,
|
|
18754
|
+
toolTarget: "tabnine"
|
|
18755
|
+
});
|
|
18756
|
+
}
|
|
18757
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
|
|
18758
|
+
return new TabnineCommand({
|
|
18759
|
+
outputRoot,
|
|
18760
|
+
relativeDirPath,
|
|
18761
|
+
relativeFilePath,
|
|
18762
|
+
fileContent: `description = ""
|
|
18763
|
+
prompt = ""`,
|
|
18764
|
+
validate: false
|
|
18765
|
+
});
|
|
18766
|
+
}
|
|
18767
|
+
};
|
|
18768
|
+
//#endregion
|
|
18240
18769
|
//#region src/features/takt-shared.ts
|
|
18241
18770
|
/**
|
|
18242
18771
|
* Shared utilities for all TAKT-* tool file classes.
|
|
@@ -18708,6 +19237,16 @@ const toolCommandFactories = /* @__PURE__ */ new Map([
|
|
|
18708
19237
|
matchAdditionalImportsByBasename: true
|
|
18709
19238
|
}
|
|
18710
19239
|
}],
|
|
19240
|
+
["bob", {
|
|
19241
|
+
class: BobCommand,
|
|
19242
|
+
meta: {
|
|
19243
|
+
extension: "md",
|
|
19244
|
+
supportsProject: true,
|
|
19245
|
+
supportsGlobal: true,
|
|
19246
|
+
isSimulated: false,
|
|
19247
|
+
supportsSubdirectory: true
|
|
19248
|
+
}
|
|
19249
|
+
}],
|
|
18711
19250
|
["claudecode", {
|
|
18712
19251
|
class: ClaudecodeCommand,
|
|
18713
19252
|
meta: {
|
|
@@ -18939,6 +19478,16 @@ const toolCommandFactories = /* @__PURE__ */ new Map([
|
|
|
18939
19478
|
supportsSubdirectory: false
|
|
18940
19479
|
}
|
|
18941
19480
|
}],
|
|
19481
|
+
["tabnine", {
|
|
19482
|
+
class: TabnineCommand,
|
|
19483
|
+
meta: {
|
|
19484
|
+
extension: "toml",
|
|
19485
|
+
supportsProject: true,
|
|
19486
|
+
supportsGlobal: true,
|
|
19487
|
+
isSimulated: false,
|
|
19488
|
+
supportsSubdirectory: true
|
|
19489
|
+
}
|
|
19490
|
+
}],
|
|
18942
19491
|
["takt", {
|
|
18943
19492
|
class: TaktCommand,
|
|
18944
19493
|
meta: {
|
|
@@ -20978,6 +21527,135 @@ var AugmentcodeHooks = class AugmentcodeHooks extends ToolHooks {
|
|
|
20978
21527
|
}
|
|
20979
21528
|
};
|
|
20980
21529
|
//#endregion
|
|
21530
|
+
//#region src/features/hooks/bob-hooks.ts
|
|
21531
|
+
const BOB_CONVERTER_CONFIG = {
|
|
21532
|
+
supportedEvents: BOB_HOOK_EVENTS,
|
|
21533
|
+
canonicalToToolEventNames: CANONICAL_TO_BOB_EVENT_NAMES,
|
|
21534
|
+
toolToCanonicalEventNames: BOB_TO_CANONICAL_EVENT_NAMES,
|
|
21535
|
+
projectDirVar: "",
|
|
21536
|
+
noMatcherEvents: /* @__PURE__ */ new Set([
|
|
21537
|
+
"sessionStart",
|
|
21538
|
+
"beforeSubmitPrompt",
|
|
21539
|
+
"stop"
|
|
21540
|
+
]),
|
|
21541
|
+
supportedHookTypes: /* @__PURE__ */ new Set(["command"]),
|
|
21542
|
+
wildcardMatcherMeansAll: true
|
|
21543
|
+
};
|
|
21544
|
+
/**
|
|
21545
|
+
* Single spelling of the settings.json codec/policy: fail closed on an
|
|
21546
|
+
* unparseable root rather than replacing the user's Bob settings with
|
|
21547
|
+
* generated output.
|
|
21548
|
+
*/
|
|
21549
|
+
function parseBobSettings(fileContent, filePath) {
|
|
21550
|
+
return parseSharedConfig({
|
|
21551
|
+
format: "json",
|
|
21552
|
+
fileContent,
|
|
21553
|
+
filePath,
|
|
21554
|
+
invalidRootPolicy: "error"
|
|
21555
|
+
});
|
|
21556
|
+
}
|
|
21557
|
+
/**
|
|
21558
|
+
* IBM Bob lifecycle hooks.
|
|
21559
|
+
*
|
|
21560
|
+
* Hooks live under the top-level `hooks` key of Bob's settings file —
|
|
21561
|
+
* `<project>/.bob/settings.json` (project scope) and
|
|
21562
|
+
* `~/.bob/settings/settings.json` (user scope) — in the Claude-Code shape:
|
|
21563
|
+
* `{ "<Event>": [{ "matcher"?: "<regex>", "hooks": [{ "type": "command",
|
|
21564
|
+
* "command": "...", "timeout"?: <seconds> }] }] }`. The file also holds
|
|
21565
|
+
* settings rulesync does not own, so generation merges the `hooks` key into it
|
|
21566
|
+
* (see `SHARED_CONFIG_OWNERSHIP`) instead of overwriting the file.
|
|
21567
|
+
*
|
|
21568
|
+
* @see https://bob.ibm.com/docs/ide/configuration/lifecycle-hooks
|
|
21569
|
+
*/
|
|
21570
|
+
var BobHooks = class BobHooks extends ToolHooks {
|
|
21571
|
+
constructor(params) {
|
|
21572
|
+
super({
|
|
21573
|
+
...params,
|
|
21574
|
+
fileContent: params.fileContent ?? "{}"
|
|
21575
|
+
});
|
|
21576
|
+
}
|
|
21577
|
+
isDeletable() {
|
|
21578
|
+
return false;
|
|
21579
|
+
}
|
|
21580
|
+
static getSettablePaths({ global = false } = {}) {
|
|
21581
|
+
return {
|
|
21582
|
+
relativeDirPath: global ? BOB_GLOBAL_SETTINGS_DIR_PATH : BOB_DIR,
|
|
21583
|
+
relativeFilePath: BOB_SETTINGS_FILE_NAME
|
|
21584
|
+
};
|
|
21585
|
+
}
|
|
21586
|
+
static async fromFile({ outputRoot = process.cwd(), validate = true, global = false }) {
|
|
21587
|
+
const paths = BobHooks.getSettablePaths({ global });
|
|
21588
|
+
const fileContent = await readFileContentOrNull((0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath)) ?? "{\"hooks\":{}}";
|
|
21589
|
+
return new BobHooks({
|
|
21590
|
+
outputRoot,
|
|
21591
|
+
relativeDirPath: paths.relativeDirPath,
|
|
21592
|
+
relativeFilePath: paths.relativeFilePath,
|
|
21593
|
+
fileContent,
|
|
21594
|
+
validate
|
|
21595
|
+
});
|
|
21596
|
+
}
|
|
21597
|
+
static async fromRulesyncHooks({ outputRoot = process.cwd(), rulesyncHooks, validate = true, global = false, logger }) {
|
|
21598
|
+
const paths = BobHooks.getSettablePaths({ global });
|
|
21599
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
21600
|
+
const existingContent = await readFileContentOrNull(filePath) ?? JSON.stringify({}, null, 2);
|
|
21601
|
+
const config = rulesyncHooks.getJson();
|
|
21602
|
+
const hooks = canonicalToToolHooks({
|
|
21603
|
+
config,
|
|
21604
|
+
toolOverrideHooks: config.bob?.hooks,
|
|
21605
|
+
converterConfig: BOB_CONVERTER_CONFIG,
|
|
21606
|
+
logger
|
|
21607
|
+
});
|
|
21608
|
+
const fileContent = applySharedConfigPatch({
|
|
21609
|
+
fileKey: sharedConfigFileKey(paths),
|
|
21610
|
+
feature: "hooks",
|
|
21611
|
+
existingContent,
|
|
21612
|
+
patch: { hooks },
|
|
21613
|
+
filePath,
|
|
21614
|
+
logger
|
|
21615
|
+
});
|
|
21616
|
+
return new BobHooks({
|
|
21617
|
+
outputRoot,
|
|
21618
|
+
relativeDirPath: paths.relativeDirPath,
|
|
21619
|
+
relativeFilePath: paths.relativeFilePath,
|
|
21620
|
+
fileContent,
|
|
21621
|
+
validate
|
|
21622
|
+
});
|
|
21623
|
+
}
|
|
21624
|
+
toRulesyncHooks({ logger } = {}) {
|
|
21625
|
+
const configPath = (0, node_path.join)(this.getRelativeDirPath(), this.getRelativeFilePath());
|
|
21626
|
+
let settings;
|
|
21627
|
+
try {
|
|
21628
|
+
settings = parseBobSettings(this.getFileContent(), configPath);
|
|
21629
|
+
} catch (error) {
|
|
21630
|
+
throw new Error(`Failed to parse Bob hooks content in ${configPath}: ${formatError(error)}`, { cause: error });
|
|
21631
|
+
}
|
|
21632
|
+
const hooks = toolHooksToCanonical({
|
|
21633
|
+
logger,
|
|
21634
|
+
hooks: settings.hooks,
|
|
21635
|
+
converterConfig: BOB_CONVERTER_CONFIG
|
|
21636
|
+
});
|
|
21637
|
+
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
|
|
21638
|
+
hooks,
|
|
21639
|
+
overrideKey: "bob"
|
|
21640
|
+
}), null, 2) });
|
|
21641
|
+
}
|
|
21642
|
+
validate() {
|
|
21643
|
+
return {
|
|
21644
|
+
success: true,
|
|
21645
|
+
error: null
|
|
21646
|
+
};
|
|
21647
|
+
}
|
|
21648
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
|
|
21649
|
+
return new BobHooks({
|
|
21650
|
+
outputRoot,
|
|
21651
|
+
relativeDirPath,
|
|
21652
|
+
relativeFilePath,
|
|
21653
|
+
fileContent: JSON.stringify({ hooks: {} }, null, 2),
|
|
21654
|
+
validate: false
|
|
21655
|
+
});
|
|
21656
|
+
}
|
|
21657
|
+
};
|
|
21658
|
+
//#endregion
|
|
20981
21659
|
//#region src/features/hooks/preserve-unowned-hook-commands.ts
|
|
20982
21660
|
/**
|
|
20983
21661
|
* Read the `hooks` value from a destination JSON file.
|
|
@@ -22543,6 +23221,151 @@ var CopilotcliHooks = class CopilotcliHooks extends ToolHooks {
|
|
|
22543
23221
|
}
|
|
22544
23222
|
};
|
|
22545
23223
|
//#endregion
|
|
23224
|
+
//#region src/constants/cortexcode-paths.ts
|
|
23225
|
+
const CORTEXCODE_DIR = ".cortex";
|
|
23226
|
+
const CORTEXCODE_GLOBAL_DIR_PATH = (0, node_path.join)(".snowflake", "cortex");
|
|
23227
|
+
const CORTEXCODE_RULE_FILE_NAME = "AGENTS.md";
|
|
23228
|
+
const CORTEXCODE_SETTINGS_FILE_NAME = "settings.json";
|
|
23229
|
+
const CORTEXCODE_GLOBAL_HOOKS_FILE_NAME = "hooks.json";
|
|
23230
|
+
const CORTEXCODE_MCP_FILE_NAME = "mcp.json";
|
|
23231
|
+
const CORTEXCODE_AGENTS_DIR_PATH = (0, node_path.join)(CORTEXCODE_DIR, "agents");
|
|
23232
|
+
const CORTEXCODE_GLOBAL_AGENTS_DIR_PATH = (0, node_path.join)(CORTEXCODE_GLOBAL_DIR_PATH, "agents");
|
|
23233
|
+
const CORTEXCODE_SKILLS_DIR_PATH = (0, node_path.join)(CORTEXCODE_DIR, "skills");
|
|
23234
|
+
const CORTEXCODE_GLOBAL_SKILLS_DIR_PATH = (0, node_path.join)(CORTEXCODE_GLOBAL_DIR_PATH, "skills");
|
|
23235
|
+
//#endregion
|
|
23236
|
+
//#region src/features/hooks/cortexcode-hooks.ts
|
|
23237
|
+
const CORTEXCODE_CONVERTER_CONFIG = {
|
|
23238
|
+
supportedEvents: CORTEXCODE_HOOK_EVENTS,
|
|
23239
|
+
canonicalToToolEventNames: CANONICAL_TO_CORTEXCODE_EVENT_NAMES,
|
|
23240
|
+
toolToCanonicalEventNames: CORTEXCODE_TO_CANONICAL_EVENT_NAMES,
|
|
23241
|
+
projectDirVar: "$CORTEX_PROJECT_DIR",
|
|
23242
|
+
prefixDotRelativeCommandsOnly: true,
|
|
23243
|
+
noMatcherEvents: /* @__PURE__ */ new Set(["beforeSubmitPrompt", "stop"]),
|
|
23244
|
+
supportedHookTypes: /* @__PURE__ */ new Set(["command", "prompt"]),
|
|
23245
|
+
booleanPassthroughFields: [{
|
|
23246
|
+
canonical: "enabled",
|
|
23247
|
+
tool: "enabled"
|
|
23248
|
+
}]
|
|
23249
|
+
};
|
|
23250
|
+
/**
|
|
23251
|
+
* Single spelling of the settings/hooks codec/policy: fail closed on an
|
|
23252
|
+
* unparseable root rather than replacing the user's Cortex Code settings with
|
|
23253
|
+
* generated output.
|
|
23254
|
+
*/
|
|
23255
|
+
function parseCortexcodeSettings(fileContent, filePath) {
|
|
23256
|
+
return parseSharedConfig({
|
|
23257
|
+
format: "json",
|
|
23258
|
+
fileContent,
|
|
23259
|
+
filePath,
|
|
23260
|
+
invalidRootPolicy: "error"
|
|
23261
|
+
});
|
|
23262
|
+
}
|
|
23263
|
+
/**
|
|
23264
|
+
* Snowflake Cortex Code hooks.
|
|
23265
|
+
*
|
|
23266
|
+
* Hooks live under the top-level `hooks` key of `<project>/.cortex/settings.json`
|
|
23267
|
+
* (project scope) and of the dedicated `~/.snowflake/cortex/hooks.json` (user
|
|
23268
|
+
* scope), both in the Claude-Code shape: `{ "<Event>": [{ "matcher"?:
|
|
23269
|
+
* "<regex>", "hooks": [{ "type": "command" | "prompt", ..., "timeout"?:
|
|
23270
|
+
* <seconds>, "enabled"?: <boolean> }] }] }`. The project file also holds
|
|
23271
|
+
* settings rulesync does not own, so generation merges the `hooks` key into
|
|
23272
|
+
* either file (see `SHARED_CONFIG_OWNERSHIP`) instead of overwriting it.
|
|
23273
|
+
*
|
|
23274
|
+
* @see https://docs.snowflake.com/en/user-guide/cortex-code/extensibility
|
|
23275
|
+
* @see https://docs.snowflake.com/en/user-guide/cortex-code/settings
|
|
23276
|
+
*/
|
|
23277
|
+
var CortexcodeHooks = class CortexcodeHooks extends ToolHooks {
|
|
23278
|
+
constructor(params) {
|
|
23279
|
+
super({
|
|
23280
|
+
...params,
|
|
23281
|
+
fileContent: params.fileContent ?? "{}"
|
|
23282
|
+
});
|
|
23283
|
+
}
|
|
23284
|
+
isDeletable() {
|
|
23285
|
+
return false;
|
|
23286
|
+
}
|
|
23287
|
+
static getSettablePaths({ global = false } = {}) {
|
|
23288
|
+
return global ? {
|
|
23289
|
+
relativeDirPath: CORTEXCODE_GLOBAL_DIR_PATH,
|
|
23290
|
+
relativeFilePath: CORTEXCODE_GLOBAL_HOOKS_FILE_NAME
|
|
23291
|
+
} : {
|
|
23292
|
+
relativeDirPath: CORTEXCODE_DIR,
|
|
23293
|
+
relativeFilePath: CORTEXCODE_SETTINGS_FILE_NAME
|
|
23294
|
+
};
|
|
23295
|
+
}
|
|
23296
|
+
static async fromFile({ outputRoot = process.cwd(), validate = true, global = false }) {
|
|
23297
|
+
const paths = CortexcodeHooks.getSettablePaths({ global });
|
|
23298
|
+
const fileContent = await readFileContentOrNull((0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath)) ?? "{\"hooks\":{}}";
|
|
23299
|
+
return new CortexcodeHooks({
|
|
23300
|
+
outputRoot,
|
|
23301
|
+
relativeDirPath: paths.relativeDirPath,
|
|
23302
|
+
relativeFilePath: paths.relativeFilePath,
|
|
23303
|
+
fileContent,
|
|
23304
|
+
validate
|
|
23305
|
+
});
|
|
23306
|
+
}
|
|
23307
|
+
static async fromRulesyncHooks({ outputRoot = process.cwd(), rulesyncHooks, validate = true, global = false, logger }) {
|
|
23308
|
+
const paths = CortexcodeHooks.getSettablePaths({ global });
|
|
23309
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
23310
|
+
const existingContent = await readFileContentOrNull(filePath) ?? JSON.stringify({}, null, 2);
|
|
23311
|
+
const config = rulesyncHooks.getJson();
|
|
23312
|
+
const hooks = canonicalToToolHooks({
|
|
23313
|
+
config,
|
|
23314
|
+
toolOverrideHooks: config.cortexcode?.hooks,
|
|
23315
|
+
converterConfig: CORTEXCODE_CONVERTER_CONFIG,
|
|
23316
|
+
logger
|
|
23317
|
+
});
|
|
23318
|
+
const fileContent = applySharedConfigPatch({
|
|
23319
|
+
fileKey: sharedConfigFileKey(paths),
|
|
23320
|
+
feature: "hooks",
|
|
23321
|
+
existingContent,
|
|
23322
|
+
patch: { hooks },
|
|
23323
|
+
filePath,
|
|
23324
|
+
logger
|
|
23325
|
+
});
|
|
23326
|
+
return new CortexcodeHooks({
|
|
23327
|
+
outputRoot,
|
|
23328
|
+
relativeDirPath: paths.relativeDirPath,
|
|
23329
|
+
relativeFilePath: paths.relativeFilePath,
|
|
23330
|
+
fileContent,
|
|
23331
|
+
validate
|
|
23332
|
+
});
|
|
23333
|
+
}
|
|
23334
|
+
toRulesyncHooks({ logger } = {}) {
|
|
23335
|
+
const configPath = (0, node_path.join)(this.getRelativeDirPath(), this.getRelativeFilePath());
|
|
23336
|
+
let settings;
|
|
23337
|
+
try {
|
|
23338
|
+
settings = parseCortexcodeSettings(this.getFileContent(), configPath);
|
|
23339
|
+
} catch (error) {
|
|
23340
|
+
throw new Error(`Failed to parse Cortex Code hooks content in ${configPath}: ${formatError(error)}`, { cause: error });
|
|
23341
|
+
}
|
|
23342
|
+
const hooks = toolHooksToCanonical({
|
|
23343
|
+
logger,
|
|
23344
|
+
hooks: settings.hooks,
|
|
23345
|
+
converterConfig: CORTEXCODE_CONVERTER_CONFIG
|
|
23346
|
+
});
|
|
23347
|
+
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
|
|
23348
|
+
hooks,
|
|
23349
|
+
overrideKey: "cortexcode"
|
|
23350
|
+
}), null, 2) });
|
|
23351
|
+
}
|
|
23352
|
+
validate() {
|
|
23353
|
+
return {
|
|
23354
|
+
success: true,
|
|
23355
|
+
error: null
|
|
23356
|
+
};
|
|
23357
|
+
}
|
|
23358
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
|
|
23359
|
+
return new CortexcodeHooks({
|
|
23360
|
+
outputRoot,
|
|
23361
|
+
relativeDirPath,
|
|
23362
|
+
relativeFilePath,
|
|
23363
|
+
fileContent: JSON.stringify({ hooks: {} }, null, 2),
|
|
23364
|
+
validate: false
|
|
23365
|
+
});
|
|
23366
|
+
}
|
|
23367
|
+
};
|
|
23368
|
+
//#endregion
|
|
22546
23369
|
//#region src/features/hooks/cursor-hooks.ts
|
|
22547
23370
|
var CursorHooks = class CursorHooks extends ToolHooks {
|
|
22548
23371
|
constructor(params) {
|
|
@@ -25770,6 +26593,270 @@ var ReasonixHooks = class ReasonixHooks extends ToolHooks {
|
|
|
25770
26593
|
}
|
|
25771
26594
|
};
|
|
25772
26595
|
//#endregion
|
|
26596
|
+
//#region src/features/hooks/tabnine-hooks.ts
|
|
26597
|
+
/**
|
|
26598
|
+
* Environment block safe to hand Tabnine for a hook. A tool rebuilds each
|
|
26599
|
+
* entry into `KEY=VALUE` for the spawned process, so a key holding `=`, a
|
|
26600
|
+
* control character or nothing at all names a different variable than it
|
|
26601
|
+
* appears to; such entries are dropped in both directions (with a warning on
|
|
26602
|
+
* export, where the value came from an authored `.rulesync/hooks.*`).
|
|
26603
|
+
*/
|
|
26604
|
+
function sanitizeEnv({ env, warn }) {
|
|
26605
|
+
if (env === null || env === void 0 || typeof env !== "object" || Array.isArray(env)) return;
|
|
26606
|
+
const result = {};
|
|
26607
|
+
for (const [key, value] of Object.entries(env)) {
|
|
26608
|
+
const unsafeKey = key === "" || key.includes("=") || CONTROL_CHARS.some((char) => key.includes(char));
|
|
26609
|
+
const unsafeValue = typeof value !== "string" || CONTROL_CHARS.some((char) => value.includes(char));
|
|
26610
|
+
if (unsafeKey || unsafeValue) {
|
|
26611
|
+
warn?.(`Tabnine CLI hook env entry ${JSON.stringify(key)} is not a safe KEY=VALUE pair; skipping it.`);
|
|
26612
|
+
continue;
|
|
26613
|
+
}
|
|
26614
|
+
result[key] = value;
|
|
26615
|
+
}
|
|
26616
|
+
return Object.keys(result).length > 0 ? result : void 0;
|
|
26617
|
+
}
|
|
26618
|
+
/**
|
|
26619
|
+
* Build one Tabnine hook configuration from a canonical command definition.
|
|
26620
|
+
* Canonical `timeout` is seconds (docs/reference/file-formats.md); Tabnine's is
|
|
26621
|
+
* milliseconds.
|
|
26622
|
+
* @see https://docs.tabnine.com/main/getting-started/tabnine-cli/features/hooks/configuration
|
|
26623
|
+
*/
|
|
26624
|
+
function canonicalDefToTabnineHook({ def, warn }) {
|
|
26625
|
+
return {
|
|
26626
|
+
type: "command",
|
|
26627
|
+
...compact({
|
|
26628
|
+
command: def.command,
|
|
26629
|
+
name: def.name,
|
|
26630
|
+
description: def.description,
|
|
26631
|
+
timeout: typeof def.timeout === "number" && Number.isFinite(def.timeout) ? Math.round(def.timeout * 1e3) : void 0,
|
|
26632
|
+
env: sanitizeEnv({
|
|
26633
|
+
env: def.env,
|
|
26634
|
+
warn
|
|
26635
|
+
})
|
|
26636
|
+
})
|
|
26637
|
+
};
|
|
26638
|
+
}
|
|
26639
|
+
/**
|
|
26640
|
+
* Convert the canonical hooks config to Tabnine's `hooks` map: PascalCase
|
|
26641
|
+
* event names, matcher groups with an optional `sequential` flag, and
|
|
26642
|
+
* command-only hook entries. Tabnine treats an omitted `matcher` as match-all
|
|
26643
|
+
* and compiles tool-event matchers as regular expressions, so the canonical
|
|
26644
|
+
* catch-all `"*"` (not a valid regex) is emitted as no matcher. Commands are
|
|
26645
|
+
* passed through verbatim; Tabnine expands `$TABNINE_PROJECT_DIR` itself.
|
|
26646
|
+
*/
|
|
26647
|
+
function canonicalToTabnineHooks({ config, logger }) {
|
|
26648
|
+
const warn = (message) => logger?.warn(message);
|
|
26649
|
+
const supported = new Set(TABNINE_HOOK_EVENTS);
|
|
26650
|
+
const sharedHooks = {};
|
|
26651
|
+
for (const [event, defs] of Object.entries(config.hooks)) if (supported.has(event)) sharedHooks[event] = defs;
|
|
26652
|
+
const effectiveHooks = {
|
|
26653
|
+
...sharedHooks,
|
|
26654
|
+
...config.tabnine?.hooks
|
|
26655
|
+
};
|
|
26656
|
+
const tabnine = {};
|
|
26657
|
+
for (const [eventName, definitions] of Object.entries(effectiveHooks)) {
|
|
26658
|
+
const tabnineEventName = lookupOwn({
|
|
26659
|
+
record: CANONICAL_TO_TABNINE_EVENT_NAMES,
|
|
26660
|
+
key: eventName
|
|
26661
|
+
}) ?? eventName;
|
|
26662
|
+
const byMatcher = /* @__PURE__ */ new Map();
|
|
26663
|
+
for (const def of definitions) {
|
|
26664
|
+
if ((def.type ?? "command") !== "command") continue;
|
|
26665
|
+
if (typeof def.command !== "string" || def.command === "") {
|
|
26666
|
+
warn(`Tabnine CLI hook on '${eventName}' has no 'command'; Tabnine would discard it, so it is skipped.`);
|
|
26667
|
+
continue;
|
|
26668
|
+
}
|
|
26669
|
+
const key = def.matcher === void 0 || def.matcher === "*" ? "" : def.matcher;
|
|
26670
|
+
const list = byMatcher.get(key);
|
|
26671
|
+
if (list) list.push(def);
|
|
26672
|
+
else byMatcher.set(key, [def]);
|
|
26673
|
+
}
|
|
26674
|
+
const entries = [];
|
|
26675
|
+
for (const [matcherKey, defs] of byMatcher) {
|
|
26676
|
+
const hooks = defs.map((def) => canonicalDefToTabnineHook({
|
|
26677
|
+
def,
|
|
26678
|
+
warn
|
|
26679
|
+
}));
|
|
26680
|
+
const sequential = defs.some((def) => def.sequential === true);
|
|
26681
|
+
const group = matcherKey ? {
|
|
26682
|
+
matcher: matcherKey,
|
|
26683
|
+
hooks
|
|
26684
|
+
} : { hooks };
|
|
26685
|
+
if (sequential) group.sequential = true;
|
|
26686
|
+
entries.push(group);
|
|
26687
|
+
}
|
|
26688
|
+
if (entries.length > 0) tabnine[tabnineEventName] = entries;
|
|
26689
|
+
}
|
|
26690
|
+
return tabnine;
|
|
26691
|
+
}
|
|
26692
|
+
/**
|
|
26693
|
+
* Tabnine hook configuration as stored in each matcher group's `hooks` array.
|
|
26694
|
+
* `z.looseObject` keeps fields added by future Tabnine releases.
|
|
26695
|
+
*/
|
|
26696
|
+
const TabnineHookEntrySchema = zod_mini.z.looseObject({
|
|
26697
|
+
type: zod_mini.z.optional(zod_mini.z.string()),
|
|
26698
|
+
command: zod_mini.z.optional(zod_mini.z.string()),
|
|
26699
|
+
name: zod_mini.z.optional(zod_mini.z.string()),
|
|
26700
|
+
description: zod_mini.z.optional(zod_mini.z.string()),
|
|
26701
|
+
timeout: zod_mini.z.optional(zod_mini.z.number()),
|
|
26702
|
+
env: zod_mini.z.optional(zod_mini.z.record(zod_mini.z.string(), zod_mini.z.string()))
|
|
26703
|
+
});
|
|
26704
|
+
const TabnineMatcherEntrySchema = zod_mini.z.looseObject({
|
|
26705
|
+
matcher: zod_mini.z.optional(zod_mini.z.string()),
|
|
26706
|
+
sequential: zod_mini.z.optional(zod_mini.z.boolean()),
|
|
26707
|
+
hooks: zod_mini.z.optional(zod_mini.z.array(TabnineHookEntrySchema))
|
|
26708
|
+
});
|
|
26709
|
+
function tabnineMatcherEntryToCanonical(entry) {
|
|
26710
|
+
const sequential = entry.sequential === true;
|
|
26711
|
+
const matcher = entry.matcher !== void 0 && entry.matcher !== null && entry.matcher !== "" ? entry.matcher : void 0;
|
|
26712
|
+
const defs = [];
|
|
26713
|
+
for (const hook of entry.hooks ?? []) {
|
|
26714
|
+
if (hook.type !== "command" || typeof hook.command !== "string" || hook.command === "") continue;
|
|
26715
|
+
defs.push({
|
|
26716
|
+
type: "command",
|
|
26717
|
+
...compact({
|
|
26718
|
+
command: hook.command,
|
|
26719
|
+
name: hook.name,
|
|
26720
|
+
description: hook.description,
|
|
26721
|
+
timeout: typeof hook.timeout === "number" && Number.isFinite(hook.timeout) ? hook.timeout / 1e3 : void 0,
|
|
26722
|
+
env: sanitizeEnv({ env: hook.env }),
|
|
26723
|
+
sequential: sequential ? true : void 0,
|
|
26724
|
+
matcher
|
|
26725
|
+
})
|
|
26726
|
+
});
|
|
26727
|
+
}
|
|
26728
|
+
return defs;
|
|
26729
|
+
}
|
|
26730
|
+
/**
|
|
26731
|
+
* Extract the `hooks` map of a Tabnine settings file into canonical form.
|
|
26732
|
+
*/
|
|
26733
|
+
function tabnineHooksToCanonical(tabnineHooks) {
|
|
26734
|
+
if (tabnineHooks === null || tabnineHooks === void 0 || typeof tabnineHooks !== "object") return {};
|
|
26735
|
+
const canonical = {};
|
|
26736
|
+
for (const [tabnineEventName, matcherEntries] of Object.entries(tabnineHooks)) {
|
|
26737
|
+
const eventName = lookupOwn({
|
|
26738
|
+
record: TABNINE_TO_CANONICAL_EVENT_NAMES,
|
|
26739
|
+
key: tabnineEventName
|
|
26740
|
+
}) ?? tabnineEventName;
|
|
26741
|
+
if (!Array.isArray(matcherEntries)) continue;
|
|
26742
|
+
const defs = [];
|
|
26743
|
+
for (const rawEntry of matcherEntries) {
|
|
26744
|
+
const parseResult = TabnineMatcherEntrySchema.safeParse(rawEntry);
|
|
26745
|
+
if (!parseResult.success) continue;
|
|
26746
|
+
defs.push(...tabnineMatcherEntryToCanonical(parseResult.data));
|
|
26747
|
+
}
|
|
26748
|
+
if (defs.length > 0) canonical[eventName] = defs;
|
|
26749
|
+
}
|
|
26750
|
+
return canonical;
|
|
26751
|
+
}
|
|
26752
|
+
/**
|
|
26753
|
+
* Fail closed on an unparseable settings root rather than replacing the
|
|
26754
|
+
* user's Tabnine settings with generated output.
|
|
26755
|
+
*/
|
|
26756
|
+
function parseTabnineSettings(fileContent, filePath) {
|
|
26757
|
+
return parseSharedConfig({
|
|
26758
|
+
format: "json",
|
|
26759
|
+
fileContent,
|
|
26760
|
+
filePath,
|
|
26761
|
+
invalidRootPolicy: "error"
|
|
26762
|
+
});
|
|
26763
|
+
}
|
|
26764
|
+
/**
|
|
26765
|
+
* Tabnine CLI hooks.
|
|
26766
|
+
*
|
|
26767
|
+
* Hooks live under the top-level `hooks` key of Tabnine's settings file —
|
|
26768
|
+
* `<project>/.tabnine/agent/settings.json` (project scope) and
|
|
26769
|
+
* `~/.tabnine/agent/settings.json` (user scope). The file also carries
|
|
26770
|
+
* `mcpServers`, `tools` and other user-managed settings, so generation merges
|
|
26771
|
+
* the `hooks` key into it (see `SHARED_CONFIG_OWNERSHIP`) instead of
|
|
26772
|
+
* overwriting the file. The sibling `hooksConfig` block (master toggle,
|
|
26773
|
+
* disabled list, notifications) is left to the user.
|
|
26774
|
+
*
|
|
26775
|
+
* @see https://docs.tabnine.com/main/getting-started/tabnine-cli/features/hooks
|
|
26776
|
+
* @see https://docs.tabnine.com/main/getting-started/tabnine-cli/features/hooks/configuration
|
|
26777
|
+
*/
|
|
26778
|
+
var TabnineHooks = class TabnineHooks extends ToolHooks {
|
|
26779
|
+
constructor(params) {
|
|
26780
|
+
super({
|
|
26781
|
+
...params,
|
|
26782
|
+
fileContent: params.fileContent ?? "{}"
|
|
26783
|
+
});
|
|
26784
|
+
}
|
|
26785
|
+
isDeletable() {
|
|
26786
|
+
return false;
|
|
26787
|
+
}
|
|
26788
|
+
static getSettablePaths(_options = {}) {
|
|
26789
|
+
return {
|
|
26790
|
+
relativeDirPath: TABNINE_AGENT_DIR_PATH,
|
|
26791
|
+
relativeFilePath: TABNINE_SETTINGS_FILE_NAME
|
|
26792
|
+
};
|
|
26793
|
+
}
|
|
26794
|
+
static async fromFile({ outputRoot = process.cwd(), validate = true, global = false }) {
|
|
26795
|
+
const paths = TabnineHooks.getSettablePaths({ global });
|
|
26796
|
+
const fileContent = await readFileContentOrNull((0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath)) ?? "{\"hooks\":{}}";
|
|
26797
|
+
return new TabnineHooks({
|
|
26798
|
+
outputRoot,
|
|
26799
|
+
relativeDirPath: paths.relativeDirPath,
|
|
26800
|
+
relativeFilePath: paths.relativeFilePath,
|
|
26801
|
+
fileContent,
|
|
26802
|
+
validate
|
|
26803
|
+
});
|
|
26804
|
+
}
|
|
26805
|
+
static async fromRulesyncHooks({ outputRoot = process.cwd(), rulesyncHooks, validate = true, global = false, logger }) {
|
|
26806
|
+
const paths = TabnineHooks.getSettablePaths({ global });
|
|
26807
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
26808
|
+
const existingContent = await readFileContentOrNull(filePath) ?? JSON.stringify({}, null, 2);
|
|
26809
|
+
const hooks = canonicalToTabnineHooks({
|
|
26810
|
+
config: rulesyncHooks.getJson(),
|
|
26811
|
+
logger
|
|
26812
|
+
});
|
|
26813
|
+
const fileContent = applySharedConfigPatch({
|
|
26814
|
+
fileKey: sharedConfigFileKey(paths),
|
|
26815
|
+
feature: "hooks",
|
|
26816
|
+
existingContent,
|
|
26817
|
+
patch: { hooks },
|
|
26818
|
+
filePath,
|
|
26819
|
+
logger
|
|
26820
|
+
});
|
|
26821
|
+
return new TabnineHooks({
|
|
26822
|
+
outputRoot,
|
|
26823
|
+
relativeDirPath: paths.relativeDirPath,
|
|
26824
|
+
relativeFilePath: paths.relativeFilePath,
|
|
26825
|
+
fileContent,
|
|
26826
|
+
validate
|
|
26827
|
+
});
|
|
26828
|
+
}
|
|
26829
|
+
toRulesyncHooks() {
|
|
26830
|
+
const configPath = (0, node_path.join)(this.getRelativeDirPath(), this.getRelativeFilePath());
|
|
26831
|
+
let settings;
|
|
26832
|
+
try {
|
|
26833
|
+
settings = parseTabnineSettings(this.getFileContent(), configPath);
|
|
26834
|
+
} catch (error) {
|
|
26835
|
+
throw new Error(`Failed to parse Tabnine CLI hooks content in ${configPath}: ${formatError(error)}`, { cause: error });
|
|
26836
|
+
}
|
|
26837
|
+
const hooks = tabnineHooksToCanonical(settings.hooks);
|
|
26838
|
+
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify(buildImportedHooksConfig({
|
|
26839
|
+
hooks,
|
|
26840
|
+
overrideKey: "tabnine"
|
|
26841
|
+
}), null, 2) });
|
|
26842
|
+
}
|
|
26843
|
+
validate() {
|
|
26844
|
+
return {
|
|
26845
|
+
success: true,
|
|
26846
|
+
error: null
|
|
26847
|
+
};
|
|
26848
|
+
}
|
|
26849
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
|
|
26850
|
+
return new TabnineHooks({
|
|
26851
|
+
outputRoot,
|
|
26852
|
+
relativeDirPath,
|
|
26853
|
+
relativeFilePath,
|
|
26854
|
+
fileContent: JSON.stringify({ hooks: {} }, null, 2),
|
|
26855
|
+
validate: false
|
|
26856
|
+
});
|
|
26857
|
+
}
|
|
26858
|
+
};
|
|
26859
|
+
//#endregion
|
|
25773
26860
|
//#region src/features/hooks/vibe-hooks.ts
|
|
25774
26861
|
const VIBE_DIR = ".vibe";
|
|
25775
26862
|
const VIBE_HOOKS_FILE_NAME = "hooks.toml";
|
|
@@ -26529,6 +27616,40 @@ const toolHooksFactories = /* @__PURE__ */ new Map([
|
|
|
26529
27616
|
supportedHookTypes: ["command"],
|
|
26530
27617
|
supportsMatcher: true
|
|
26531
27618
|
}],
|
|
27619
|
+
["bob", {
|
|
27620
|
+
class: BobHooks,
|
|
27621
|
+
meta: {
|
|
27622
|
+
supportsProject: true,
|
|
27623
|
+
supportsGlobal: true,
|
|
27624
|
+
supportsImport: true
|
|
27625
|
+
},
|
|
27626
|
+
supportedEvents: BOB_HOOK_EVENTS,
|
|
27627
|
+
supportedHookTypes: ["command"],
|
|
27628
|
+
supportsMatcher: true,
|
|
27629
|
+
matcherEvents: ["preToolUse", "postToolUse"]
|
|
27630
|
+
}],
|
|
27631
|
+
["cortexcode", {
|
|
27632
|
+
class: CortexcodeHooks,
|
|
27633
|
+
meta: {
|
|
27634
|
+
supportsProject: true,
|
|
27635
|
+
supportsGlobal: true,
|
|
27636
|
+
supportsImport: true
|
|
27637
|
+
},
|
|
27638
|
+
supportedEvents: CORTEXCODE_HOOK_EVENTS,
|
|
27639
|
+
supportedHookTypes: ["command", "prompt"],
|
|
27640
|
+
supportsMatcher: true,
|
|
27641
|
+
matcherEvents: [
|
|
27642
|
+
"preToolUse",
|
|
27643
|
+
"postToolUse",
|
|
27644
|
+
"permissionRequest",
|
|
27645
|
+
"sessionStart",
|
|
27646
|
+
"sessionEnd",
|
|
27647
|
+
"preCompact",
|
|
27648
|
+
"subagentStop",
|
|
27649
|
+
"notification",
|
|
27650
|
+
"setup"
|
|
27651
|
+
]
|
|
27652
|
+
}],
|
|
26532
27653
|
["junie", {
|
|
26533
27654
|
class: JunieHooks,
|
|
26534
27655
|
meta: {
|
|
@@ -26540,6 +27661,17 @@ const toolHooksFactories = /* @__PURE__ */ new Map([
|
|
|
26540
27661
|
supportedHookTypes: ["command"],
|
|
26541
27662
|
supportsMatcher: true
|
|
26542
27663
|
}],
|
|
27664
|
+
["tabnine", {
|
|
27665
|
+
class: TabnineHooks,
|
|
27666
|
+
meta: {
|
|
27667
|
+
supportsProject: true,
|
|
27668
|
+
supportsGlobal: true,
|
|
27669
|
+
supportsImport: true
|
|
27670
|
+
},
|
|
27671
|
+
supportedEvents: TABNINE_HOOK_EVENTS,
|
|
27672
|
+
supportedHookTypes: ["command"],
|
|
27673
|
+
supportsMatcher: true
|
|
27674
|
+
}],
|
|
26543
27675
|
["vibe", {
|
|
26544
27676
|
class: VibeHooks,
|
|
26545
27677
|
meta: {
|
|
@@ -26986,6 +28118,58 @@ var AugmentcodeIgnore = class AugmentcodeIgnore extends ToolIgnore {
|
|
|
26986
28118
|
}
|
|
26987
28119
|
};
|
|
26988
28120
|
//#endregion
|
|
28121
|
+
//#region src/features/ignore/bob-ignore.ts
|
|
28122
|
+
/**
|
|
28123
|
+
* BobIgnore represents the `.bobignore` file of IBM Bob.
|
|
28124
|
+
*
|
|
28125
|
+
* - File location: workspace root only (`.bobignore`); no user-scope variant
|
|
28126
|
+
* is documented, so the feature is project-only.
|
|
28127
|
+
* - Syntax: the same as `.gitignore`.
|
|
28128
|
+
* - Matching files are hidden from Bob's file reads and listings.
|
|
28129
|
+
*
|
|
28130
|
+
* @see https://bob.ibm.com/docs/ide/configuration/bobignore
|
|
28131
|
+
*/
|
|
28132
|
+
var BobIgnore = class BobIgnore extends ToolIgnore {
|
|
28133
|
+
static getSettablePaths() {
|
|
28134
|
+
return {
|
|
28135
|
+
relativeDirPath: ".",
|
|
28136
|
+
relativeFilePath: BOB_IGNORE_FILE_NAME
|
|
28137
|
+
};
|
|
28138
|
+
}
|
|
28139
|
+
toRulesyncIgnore() {
|
|
28140
|
+
return this.toRulesyncIgnoreDefault();
|
|
28141
|
+
}
|
|
28142
|
+
static fromRulesyncIgnore({ outputRoot = process.cwd(), rulesyncIgnore }) {
|
|
28143
|
+
const paths = this.getSettablePaths();
|
|
28144
|
+
return new BobIgnore({
|
|
28145
|
+
outputRoot,
|
|
28146
|
+
relativeDirPath: paths.relativeDirPath,
|
|
28147
|
+
relativeFilePath: paths.relativeFilePath,
|
|
28148
|
+
fileContent: rulesyncIgnore.getFileContent()
|
|
28149
|
+
});
|
|
28150
|
+
}
|
|
28151
|
+
static async fromFile({ outputRoot = process.cwd(), validate = true }) {
|
|
28152
|
+
const paths = this.getSettablePaths();
|
|
28153
|
+
const fileContent = await readFileContent((0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath));
|
|
28154
|
+
return new BobIgnore({
|
|
28155
|
+
outputRoot,
|
|
28156
|
+
relativeDirPath: paths.relativeDirPath,
|
|
28157
|
+
relativeFilePath: paths.relativeFilePath,
|
|
28158
|
+
fileContent,
|
|
28159
|
+
validate
|
|
28160
|
+
});
|
|
28161
|
+
}
|
|
28162
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
|
|
28163
|
+
return new BobIgnore({
|
|
28164
|
+
outputRoot,
|
|
28165
|
+
relativeDirPath,
|
|
28166
|
+
relativeFilePath,
|
|
28167
|
+
fileContent: "",
|
|
28168
|
+
validate: false
|
|
28169
|
+
});
|
|
28170
|
+
}
|
|
28171
|
+
};
|
|
28172
|
+
//#endregion
|
|
26989
28173
|
//#region src/features/ignore/claudecode-ignore.ts
|
|
26990
28174
|
const DEFAULT_FILE_MODE = "shared";
|
|
26991
28175
|
/**
|
|
@@ -28015,6 +29199,60 @@ var RooIgnore = class RooIgnore extends ToolIgnore {
|
|
|
28015
29199
|
}
|
|
28016
29200
|
};
|
|
28017
29201
|
//#endregion
|
|
29202
|
+
//#region src/features/ignore/tabnine-ignore.ts
|
|
29203
|
+
/**
|
|
29204
|
+
* TabnineIgnore represents the `.tabnineignore` file of Tabnine CLI.
|
|
29205
|
+
*
|
|
29206
|
+
* - File location: project root only (`.tabnineignore`); no user-scope
|
|
29207
|
+
* variant is documented, so the feature is project-only.
|
|
29208
|
+
* - Syntax: the same as `.gitignore`.
|
|
29209
|
+
* - Matching files are excluded from the CLI's file searches and directory
|
|
29210
|
+
* listings while `context.fileFiltering.respectGeminiIgnore` (the default)
|
|
29211
|
+
* is enabled.
|
|
29212
|
+
*
|
|
29213
|
+
* @see https://docs.tabnine.com/main/getting-started/tabnine-cli/features/settings/settings-reference
|
|
29214
|
+
*/
|
|
29215
|
+
var TabnineIgnore = class TabnineIgnore extends ToolIgnore {
|
|
29216
|
+
static getSettablePaths() {
|
|
29217
|
+
return {
|
|
29218
|
+
relativeDirPath: ".",
|
|
29219
|
+
relativeFilePath: TABNINE_IGNORE_FILE_NAME
|
|
29220
|
+
};
|
|
29221
|
+
}
|
|
29222
|
+
toRulesyncIgnore() {
|
|
29223
|
+
return this.toRulesyncIgnoreDefault();
|
|
29224
|
+
}
|
|
29225
|
+
static fromRulesyncIgnore({ outputRoot = process.cwd(), rulesyncIgnore }) {
|
|
29226
|
+
const paths = this.getSettablePaths();
|
|
29227
|
+
return new TabnineIgnore({
|
|
29228
|
+
outputRoot,
|
|
29229
|
+
relativeDirPath: paths.relativeDirPath,
|
|
29230
|
+
relativeFilePath: paths.relativeFilePath,
|
|
29231
|
+
fileContent: rulesyncIgnore.getFileContent()
|
|
29232
|
+
});
|
|
29233
|
+
}
|
|
29234
|
+
static async fromFile({ outputRoot = process.cwd(), validate = true }) {
|
|
29235
|
+
const paths = this.getSettablePaths();
|
|
29236
|
+
const fileContent = await readFileContent((0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath));
|
|
29237
|
+
return new TabnineIgnore({
|
|
29238
|
+
outputRoot,
|
|
29239
|
+
relativeDirPath: paths.relativeDirPath,
|
|
29240
|
+
relativeFilePath: paths.relativeFilePath,
|
|
29241
|
+
fileContent,
|
|
29242
|
+
validate
|
|
29243
|
+
});
|
|
29244
|
+
}
|
|
29245
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
|
|
29246
|
+
return new TabnineIgnore({
|
|
29247
|
+
outputRoot,
|
|
29248
|
+
relativeDirPath,
|
|
29249
|
+
relativeFilePath,
|
|
29250
|
+
fileContent: "",
|
|
29251
|
+
validate: false
|
|
29252
|
+
});
|
|
29253
|
+
}
|
|
29254
|
+
};
|
|
29255
|
+
//#endregion
|
|
28018
29256
|
//#region src/features/ignore/vibe-ignore.ts
|
|
28019
29257
|
var VibeIgnore = class VibeIgnore extends ToolIgnore {
|
|
28020
29258
|
static getSettablePaths() {
|
|
@@ -28220,6 +29458,7 @@ const toolIgnoreFactories = /* @__PURE__ */ new Map([
|
|
|
28220
29458
|
["aiassistant", { class: AiassistantIgnore }],
|
|
28221
29459
|
["antigravity-cli", { class: AntigravityCliIgnore }],
|
|
28222
29460
|
["augmentcode", { class: AugmentcodeIgnore }],
|
|
29461
|
+
["bob", { class: BobIgnore }],
|
|
28223
29462
|
["claudecode", { class: ClaudecodeIgnore }],
|
|
28224
29463
|
["claudecode-legacy", { class: ClaudecodeIgnore }],
|
|
28225
29464
|
["cline", { class: ClineIgnore }],
|
|
@@ -28236,6 +29475,7 @@ const toolIgnoreFactories = /* @__PURE__ */ new Map([
|
|
|
28236
29475
|
["roo", { class: RooIgnore }],
|
|
28237
29476
|
["zoocode", { class: RooIgnore }],
|
|
28238
29477
|
["devin", { class: DevinIgnore }],
|
|
29478
|
+
["tabnine", { class: TabnineIgnore }],
|
|
28239
29479
|
["vibe", { class: VibeIgnore }],
|
|
28240
29480
|
["warp", { class: WarpIgnore }],
|
|
28241
29481
|
["zed", { class: ZedIgnore }]
|
|
@@ -28970,6 +30210,343 @@ var AugmentcodeMcp = class AugmentcodeMcp extends ToolMcp {
|
|
|
28970
30210
|
}
|
|
28971
30211
|
};
|
|
28972
30212
|
//#endregion
|
|
30213
|
+
//#region src/features/mcp/mcp-transport.ts
|
|
30214
|
+
/**
|
|
30215
|
+
* A server that names no way to be reached at all. It is what a Kilo bare
|
|
30216
|
+
* `{"enabled": <bool>}` entry imports as — a switch for a server another config
|
|
30217
|
+
* layer defines, which only Kilo's config spells this way. Every other tool's
|
|
30218
|
+
* config defines the servers it lists, so there the entry has no equivalent and
|
|
30219
|
+
* must be skipped rather than written as a server with an empty command.
|
|
30220
|
+
*/
|
|
30221
|
+
function declaresNoTransport(serverConfig) {
|
|
30222
|
+
return serverConfig.type === void 0 && serverConfig.transport === void 0 && serverConfig.command === void 0 && serverConfig.url === void 0 && serverConfig.httpUrl === void 0;
|
|
30223
|
+
}
|
|
30224
|
+
const REMOTE_TRANSPORTS = /* @__PURE__ */ new Set([
|
|
30225
|
+
"sse",
|
|
30226
|
+
"http",
|
|
30227
|
+
"streamable-http",
|
|
30228
|
+
"ws"
|
|
30229
|
+
]);
|
|
30230
|
+
/**
|
|
30231
|
+
* Whether the server speaks over the network rather than over a spawned
|
|
30232
|
+
* process. `httpUrl`, the Claude-specific alias several adapters accept, counts
|
|
30233
|
+
* as much as `url` does, and so does `transport`, the alias `type` has
|
|
30234
|
+
* everywhere in the canonical config.
|
|
30235
|
+
*/
|
|
30236
|
+
function isRemoteMcpServer(serverConfig) {
|
|
30237
|
+
return REMOTE_TRANSPORTS.has(serverConfig.type ?? "") || REMOTE_TRANSPORTS.has(serverConfig.transport ?? "") || serverConfig.url !== void 0 || serverConfig.httpUrl !== void 0;
|
|
30238
|
+
}
|
|
30239
|
+
/** The URL a remote server is reached at, or `undefined` if it states none. */
|
|
30240
|
+
function resolveRemoteMcpUrl(serverConfig) {
|
|
30241
|
+
return serverConfig.url || serverConfig.httpUrl || void 0;
|
|
30242
|
+
}
|
|
30243
|
+
/** The `command` array a `local` server is spawned with, `args` merged in. */
|
|
30244
|
+
function resolveLocalMcpCommand(serverConfig) {
|
|
30245
|
+
const commandArray = [];
|
|
30246
|
+
if (serverConfig.command) {
|
|
30247
|
+
if (Array.isArray(serverConfig.command)) commandArray.push(...serverConfig.command);
|
|
30248
|
+
else commandArray.push(serverConfig.command);
|
|
30249
|
+
}
|
|
30250
|
+
if (serverConfig.args) commandArray.push(...serverConfig.args);
|
|
30251
|
+
return commandArray;
|
|
30252
|
+
}
|
|
30253
|
+
/**
|
|
30254
|
+
* A server that names a transport but carries nothing to reach it — a `type`
|
|
30255
|
+
* with no `command`, an `http` with no `url` — has no form in a config that
|
|
30256
|
+
* spells the transport out. Writing `{type: "local", command: []}` for it would
|
|
30257
|
+
* give the tool a server it cannot start and the importer a file it cannot read
|
|
30258
|
+
* back, so it is skipped out loud instead.
|
|
30259
|
+
*/
|
|
30260
|
+
function warnAndSkipMcpServer({ toolName, serverName, reason, logger }) {
|
|
30261
|
+
logger?.warn(`${toolName} MCP: skipping "${serverName}" because it declares ${reason}.`);
|
|
30262
|
+
return null;
|
|
30263
|
+
}
|
|
30264
|
+
/**
|
|
30265
|
+
* The `tools` map Kilo and OpenCode keep beside `mcp` is keyed `<server>_<tool>`
|
|
30266
|
+
* and reaches servers `mcp` does not list — ones the global config or a
|
|
30267
|
+
* marketplace defines — so entries naming no listed
|
|
30268
|
+
* server are filters that would be dropped by a walk over `mcp` alone, and
|
|
30269
|
+
* deleted from the file on the next generate. They come back as transport-less
|
|
30270
|
+
* servers carrying nothing but the filters.
|
|
30271
|
+
*
|
|
30272
|
+
* The split is at the first `_`, which is where the write side joined them. A
|
|
30273
|
+
* server whose own name contains one is reconstructed under a shorter name, but
|
|
30274
|
+
* the key it is written back as is character-for-character the one that was
|
|
30275
|
+
* read, so Kilo sees exactly what it saw before.
|
|
30276
|
+
*/
|
|
30277
|
+
function orphanMcpToolFiltersToRulesync(servers, tools) {
|
|
30278
|
+
const orphans = {};
|
|
30279
|
+
for (const [toolName, enabled] of Object.entries(tools ?? {})) {
|
|
30280
|
+
if (Object.keys(servers).some((serverName) => toolName.startsWith(`${serverName}_`))) continue;
|
|
30281
|
+
const separator = toolName.indexOf("_");
|
|
30282
|
+
if (separator <= 0 || separator === toolName.length - 1) continue;
|
|
30283
|
+
const serverName = toolName.slice(0, separator);
|
|
30284
|
+
const toolSuffix = toolName.slice(separator + 1);
|
|
30285
|
+
if (!Object.hasOwn(orphans, serverName)) orphans[serverName] = {};
|
|
30286
|
+
const server = orphans[serverName];
|
|
30287
|
+
if (enabled) server.enabledTools = [...server.enabledTools ?? [], toolSuffix];
|
|
30288
|
+
else server.disabledTools = [...server.disabledTools ?? [], toolSuffix];
|
|
30289
|
+
}
|
|
30290
|
+
return orphans;
|
|
30291
|
+
}
|
|
30292
|
+
/**
|
|
30293
|
+
* Split imported servers into the ones every tool can use and the ones only the
|
|
30294
|
+
* importing tool can. A server with no transport is a Kilo/OpenCode idea — a
|
|
30295
|
+
* switch for a server another config layer defines, or a filter for one — and
|
|
30296
|
+
* nothing else knows what to do with it: written to `.mcp.json` and the rest,
|
|
30297
|
+
* it is an entry no tool can start. It goes into the tool-scoped
|
|
30298
|
+
* `{tool}.mcpServers` block instead, which only that tool reads.
|
|
30299
|
+
*/
|
|
30300
|
+
function splitMcpServersByTransport(servers) {
|
|
30301
|
+
const shared = {};
|
|
30302
|
+
const toolOnly = {};
|
|
30303
|
+
for (const [serverName, serverConfig] of Object.entries(servers)) if (declaresNoTransport(serverConfig)) toolOnly[serverName] = serverConfig;
|
|
30304
|
+
else shared[serverName] = serverConfig;
|
|
30305
|
+
return {
|
|
30306
|
+
shared,
|
|
30307
|
+
toolOnly
|
|
30308
|
+
};
|
|
30309
|
+
}
|
|
30310
|
+
//#endregion
|
|
30311
|
+
//#region src/features/mcp/bob-mcp.ts
|
|
30312
|
+
/**
|
|
30313
|
+
* Parse a Bob MCP file, failing closed on malformed JSON or a non-object root
|
|
30314
|
+
* (`null`, an array, a scalar) rather than spreading whatever came back into
|
|
30315
|
+
* the regenerated file.
|
|
30316
|
+
*/
|
|
30317
|
+
function parseBobMcpConfig({ fileContent, relativePath }) {
|
|
30318
|
+
let parsed;
|
|
30319
|
+
try {
|
|
30320
|
+
parsed = JSON.parse(fileContent);
|
|
30321
|
+
} catch (error) {
|
|
30322
|
+
throw new Error(`Failed to parse Bob MCP config at ${relativePath}: ${formatError(error)}`, { cause: error });
|
|
30323
|
+
}
|
|
30324
|
+
if (!isPlainObject$1(parsed)) throw new Error(`Failed to parse Bob MCP config at ${relativePath}: expected a JSON object at the root`);
|
|
30325
|
+
return parsed;
|
|
30326
|
+
}
|
|
30327
|
+
/** The `type` Bob IDE writes for a streamable HTTP server. */
|
|
30328
|
+
const BOB_STREAMABLE_HTTP_TYPE = "streamable-http";
|
|
30329
|
+
/**
|
|
30330
|
+
* The remote transport Bob IDE reads a server as, spelled the way it writes
|
|
30331
|
+
* it: `streamable-http` needs an explicit `type`, while SSE (legacy) is a bare
|
|
30332
|
+
* `url` with no `type`. `http` is the canonical rulesync alias for streamable
|
|
30333
|
+
* HTTP and a bare `url` defaults to it, streamable HTTP being the current MCP
|
|
30334
|
+
* transport. A `ws(s)://` URL or any other stated transport is something Bob
|
|
30335
|
+
* cannot reach, so `undefined` tells the caller to skip the server.
|
|
30336
|
+
* @see https://bob.ibm.com/docs/ide/configuration/mcp/mcp-in-bob
|
|
30337
|
+
*/
|
|
30338
|
+
function asBobRemoteType(stated, url) {
|
|
30339
|
+
if (stated === "sse") return "sse";
|
|
30340
|
+
if (stated === "http" || stated === BOB_STREAMABLE_HTTP_TYPE) return BOB_STREAMABLE_HTTP_TYPE;
|
|
30341
|
+
if (stated === void 0) return /^wss?:\/\//i.test(url) ? void 0 : BOB_STREAMABLE_HTTP_TYPE;
|
|
30342
|
+
}
|
|
30343
|
+
/**
|
|
30344
|
+
* Convert the canonical server map to the shape Bob IDE documents for
|
|
30345
|
+
* `.bob/mcp.json`: a stdio server carries `command` (plus `args`), a
|
|
30346
|
+
* streamable HTTP server carries `type: "streamable-http"` and `url`, and an
|
|
30347
|
+
* SSE server carries a bare `url`. The canonical `transport` alias and the
|
|
30348
|
+
* Claude-style `httpUrl` alias are folded into `type`/`url`; `env`, `cwd`,
|
|
30349
|
+
* `headers`, `timeout`, `alwaysAllow` and `disabled` pass through unchanged,
|
|
30350
|
+
* as Bob documents all of them.
|
|
30351
|
+
*
|
|
30352
|
+
* Bob Shell documents the same file with an `httpURL` key instead of
|
|
30353
|
+
* `type` + `url` for streamable HTTP. rulesync writes the IDE spelling (the two
|
|
30354
|
+
* products share the project file, and the IDE is the one whose global file
|
|
30355
|
+
* rulesync targets) and accepts the Shell spelling on import.
|
|
30356
|
+
*
|
|
30357
|
+
* A server Bob cannot start or reach — no transport at all, a remote transport
|
|
30358
|
+
* without a URL, a WebSocket URL, or a stdio entry without a command — is
|
|
30359
|
+
* skipped with a warning rather than written in a broken form.
|
|
30360
|
+
* @see https://bob.ibm.com/docs/ide/configuration/mcp/mcp-in-bob
|
|
30361
|
+
* @see https://bob.ibm.com/docs/shell/configuration/mcp/mcp-bobshell
|
|
30362
|
+
*/
|
|
30363
|
+
function convertToBobFormat(mcpServers, logger) {
|
|
30364
|
+
const result = {};
|
|
30365
|
+
for (const [serverName, serverConfig] of Object.entries(mcpServers)) {
|
|
30366
|
+
if (PROTOTYPE_POLLUTION_KEYS.has(serverName) || !isRecord$1(serverConfig)) continue;
|
|
30367
|
+
if (declaresNoTransport(serverConfig)) {
|
|
30368
|
+
warnAndSkipMcpServer({
|
|
30369
|
+
toolName: "Bob",
|
|
30370
|
+
serverName,
|
|
30371
|
+
reason: "no transport",
|
|
30372
|
+
logger
|
|
30373
|
+
});
|
|
30374
|
+
continue;
|
|
30375
|
+
}
|
|
30376
|
+
const { type, transport, url: _url, httpUrl: _httpUrl, command: _command, args: _args, ...rest } = serverConfig;
|
|
30377
|
+
const converted = {};
|
|
30378
|
+
if (isRemoteMcpServer(serverConfig)) {
|
|
30379
|
+
const url = resolveRemoteMcpUrl(serverConfig);
|
|
30380
|
+
if (!url) {
|
|
30381
|
+
warnAndSkipMcpServer({
|
|
30382
|
+
toolName: "Bob",
|
|
30383
|
+
serverName,
|
|
30384
|
+
reason: "a remote transport without a url",
|
|
30385
|
+
logger
|
|
30386
|
+
});
|
|
30387
|
+
continue;
|
|
30388
|
+
}
|
|
30389
|
+
const stated = type ?? transport;
|
|
30390
|
+
const remoteType = asBobRemoteType(stated, url);
|
|
30391
|
+
if (remoteType === void 0) {
|
|
30392
|
+
warnAndSkipMcpServer({
|
|
30393
|
+
toolName: "Bob",
|
|
30394
|
+
serverName,
|
|
30395
|
+
reason: stated === void 0 ? "a WebSocket url, which Bob's remote transports (streamable-http and sse) cannot reach" : `the "${stated}" transport, which Bob does not offer for remote servers (only streamable-http and sse)`,
|
|
30396
|
+
logger
|
|
30397
|
+
});
|
|
30398
|
+
continue;
|
|
30399
|
+
}
|
|
30400
|
+
if (remoteType === BOB_STREAMABLE_HTTP_TYPE) converted.type = BOB_STREAMABLE_HTTP_TYPE;
|
|
30401
|
+
converted.url = url;
|
|
30402
|
+
} else {
|
|
30403
|
+
const [command, ...args] = resolveLocalMcpCommand(serverConfig);
|
|
30404
|
+
if (!command) {
|
|
30405
|
+
warnAndSkipMcpServer({
|
|
30406
|
+
toolName: "Bob",
|
|
30407
|
+
serverName,
|
|
30408
|
+
reason: "a stdio transport without a command",
|
|
30409
|
+
logger
|
|
30410
|
+
});
|
|
30411
|
+
continue;
|
|
30412
|
+
}
|
|
30413
|
+
converted.command = command;
|
|
30414
|
+
if (args.length > 0) converted.args = args;
|
|
30415
|
+
}
|
|
30416
|
+
for (const [key, value] of Object.entries(rest)) {
|
|
30417
|
+
if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
|
|
30418
|
+
converted[key] = (key === "env" || key === "headers") && isRecord$1(value) ? omitPrototypePollutionKeys(value) : value;
|
|
30419
|
+
}
|
|
30420
|
+
result[serverName] = converted;
|
|
30421
|
+
}
|
|
30422
|
+
return result;
|
|
30423
|
+
}
|
|
30424
|
+
/**
|
|
30425
|
+
* Convert Bob's server map back to the canonical shape. The IDE spelling
|
|
30426
|
+
* (`type: "streamable-http"` + `url`) is already canonical and passes through;
|
|
30427
|
+
* the Bob Shell spelling `httpURL` becomes `url` with `type: "http"`; a bare
|
|
30428
|
+
* `url` is an SSE server in Bob, so it gains `type: "sse"` to keep that reading
|
|
30429
|
+
* on the next generate.
|
|
30430
|
+
*/
|
|
30431
|
+
function convertFromBobFormat(mcpServers) {
|
|
30432
|
+
if (!isMcpServers(mcpServers)) return {};
|
|
30433
|
+
const result = {};
|
|
30434
|
+
for (const [serverName, serverConfig] of Object.entries(mcpServers)) {
|
|
30435
|
+
if (PROTOTYPE_POLLUTION_KEYS.has(serverName) || !isRecord$1(serverConfig)) continue;
|
|
30436
|
+
const converted = {};
|
|
30437
|
+
let httpURL;
|
|
30438
|
+
for (const [key, value] of Object.entries(serverConfig)) {
|
|
30439
|
+
if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
|
|
30440
|
+
if (key === "httpURL") {
|
|
30441
|
+
if (typeof value === "string") httpURL = value;
|
|
30442
|
+
continue;
|
|
30443
|
+
}
|
|
30444
|
+
converted[key] = value;
|
|
30445
|
+
}
|
|
30446
|
+
if (httpURL !== void 0) {
|
|
30447
|
+
converted.url = httpURL;
|
|
30448
|
+
converted.type = "http";
|
|
30449
|
+
} else if (typeof converted.url === "string" && converted.type === void 0) converted.type = "sse";
|
|
30450
|
+
result[serverName] = converted;
|
|
30451
|
+
}
|
|
30452
|
+
return result;
|
|
30453
|
+
}
|
|
30454
|
+
/**
|
|
30455
|
+
* IBM Bob MCP configuration.
|
|
30456
|
+
*
|
|
30457
|
+
* Bob IDE reads `mcpServers` from `<project>/.bob/mcp.json` (project scope)
|
|
30458
|
+
* and `~/.bob/mcp.json` (user scope); the project entry wins when both define
|
|
30459
|
+
* the same server name. Both files are dedicated to MCP. The project one is
|
|
30460
|
+
* deletable; the user one is created and edited by Bob IDE's own MCP settings
|
|
30461
|
+
* UI, so `--delete` leaves it in place rather than removing a file the user
|
|
30462
|
+
* did not create through rulesync. (Bob Shell reads its user-scoped servers
|
|
30463
|
+
* from `~/.bob/mcp_settings.json` instead, which rulesync does not write.)
|
|
30464
|
+
*
|
|
30465
|
+
* @see https://bob.ibm.com/docs/ide/configuration/mcp/mcp-in-bob
|
|
30466
|
+
* @see https://bob.ibm.com/docs/shell/configuration/mcp/mcp-bobshell
|
|
30467
|
+
*/
|
|
30468
|
+
var BobMcp = class BobMcp extends ToolMcp {
|
|
30469
|
+
json;
|
|
30470
|
+
constructor(params) {
|
|
30471
|
+
super(params);
|
|
30472
|
+
this.json = this.fileContent === void 0 ? {} : parseBobMcpConfig({
|
|
30473
|
+
fileContent: this.fileContent,
|
|
30474
|
+
relativePath: (0, node_path.join)(this.relativeDirPath, this.relativeFilePath)
|
|
30475
|
+
});
|
|
30476
|
+
}
|
|
30477
|
+
getJson() {
|
|
30478
|
+
return this.json;
|
|
30479
|
+
}
|
|
30480
|
+
isDeletable() {
|
|
30481
|
+
return !this.global;
|
|
30482
|
+
}
|
|
30483
|
+
static getSettablePaths(_options = {}) {
|
|
30484
|
+
return {
|
|
30485
|
+
relativeDirPath: BOB_DIR,
|
|
30486
|
+
relativeFilePath: BOB_MCP_FILE_NAME
|
|
30487
|
+
};
|
|
30488
|
+
}
|
|
30489
|
+
static async fromFile({ outputRoot = process.cwd(), validate = true, global = false }) {
|
|
30490
|
+
const paths = this.getSettablePaths({ global });
|
|
30491
|
+
const json = parseBobMcpConfig({
|
|
30492
|
+
fileContent: await readFileContentOrNull((0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath)) ?? "{\"mcpServers\":{}}",
|
|
30493
|
+
relativePath: (0, node_path.join)(paths.relativeDirPath, paths.relativeFilePath)
|
|
30494
|
+
});
|
|
30495
|
+
const newJson = {
|
|
30496
|
+
...json,
|
|
30497
|
+
mcpServers: json.mcpServers ?? {}
|
|
30498
|
+
};
|
|
30499
|
+
return new BobMcp({
|
|
30500
|
+
outputRoot,
|
|
30501
|
+
relativeDirPath: paths.relativeDirPath,
|
|
30502
|
+
relativeFilePath: paths.relativeFilePath,
|
|
30503
|
+
fileContent: JSON.stringify(newJson, null, 2),
|
|
30504
|
+
validate,
|
|
30505
|
+
global
|
|
30506
|
+
});
|
|
30507
|
+
}
|
|
30508
|
+
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false, logger }) {
|
|
30509
|
+
const paths = this.getSettablePaths({ global });
|
|
30510
|
+
const json = parseBobMcpConfig({
|
|
30511
|
+
fileContent: await readFileContentOrNull((0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath)) ?? JSON.stringify({ mcpServers: {} }, null, 2),
|
|
30512
|
+
relativePath: (0, node_path.join)(paths.relativeDirPath, paths.relativeFilePath)
|
|
30513
|
+
});
|
|
30514
|
+
const mcpServers = convertToBobFormat(rulesyncMcp.getMcpServers(), logger);
|
|
30515
|
+
const bobConfig = {
|
|
30516
|
+
...json,
|
|
30517
|
+
mcpServers
|
|
30518
|
+
};
|
|
30519
|
+
return new BobMcp({
|
|
30520
|
+
outputRoot,
|
|
30521
|
+
relativeDirPath: paths.relativeDirPath,
|
|
30522
|
+
relativeFilePath: paths.relativeFilePath,
|
|
30523
|
+
fileContent: JSON.stringify(bobConfig, null, 2),
|
|
30524
|
+
validate,
|
|
30525
|
+
global
|
|
30526
|
+
});
|
|
30527
|
+
}
|
|
30528
|
+
toRulesyncMcp() {
|
|
30529
|
+
const mcpServers = convertFromBobFormat(this.json.mcpServers);
|
|
30530
|
+
return this.toRulesyncMcpDefault({ fileContent: JSON.stringify({ mcpServers }, null, 2) });
|
|
30531
|
+
}
|
|
30532
|
+
validate() {
|
|
30533
|
+
return {
|
|
30534
|
+
success: true,
|
|
30535
|
+
error: null
|
|
30536
|
+
};
|
|
30537
|
+
}
|
|
30538
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
|
|
30539
|
+
return new BobMcp({
|
|
30540
|
+
outputRoot,
|
|
30541
|
+
relativeDirPath,
|
|
30542
|
+
relativeFilePath,
|
|
30543
|
+
fileContent: "{}",
|
|
30544
|
+
validate: false,
|
|
30545
|
+
global
|
|
30546
|
+
});
|
|
30547
|
+
}
|
|
30548
|
+
};
|
|
30549
|
+
//#endregion
|
|
28973
30550
|
//#region src/features/mcp/claudecode-mcp.ts
|
|
28974
30551
|
var ClaudecodeMcp = class ClaudecodeMcp extends ToolMcp {
|
|
28975
30552
|
json;
|
|
@@ -29677,104 +31254,6 @@ var CopilotMcp = class CopilotMcp extends ToolMcp {
|
|
|
29677
31254
|
}
|
|
29678
31255
|
};
|
|
29679
31256
|
//#endregion
|
|
29680
|
-
//#region src/features/mcp/mcp-transport.ts
|
|
29681
|
-
/**
|
|
29682
|
-
* A server that names no way to be reached at all. It is what a Kilo bare
|
|
29683
|
-
* `{"enabled": <bool>}` entry imports as — a switch for a server another config
|
|
29684
|
-
* layer defines, which only Kilo's config spells this way. Every other tool's
|
|
29685
|
-
* config defines the servers it lists, so there the entry has no equivalent and
|
|
29686
|
-
* must be skipped rather than written as a server with an empty command.
|
|
29687
|
-
*/
|
|
29688
|
-
function declaresNoTransport(serverConfig) {
|
|
29689
|
-
return serverConfig.type === void 0 && serverConfig.transport === void 0 && serverConfig.command === void 0 && serverConfig.url === void 0 && serverConfig.httpUrl === void 0;
|
|
29690
|
-
}
|
|
29691
|
-
const REMOTE_TRANSPORTS = /* @__PURE__ */ new Set([
|
|
29692
|
-
"sse",
|
|
29693
|
-
"http",
|
|
29694
|
-
"streamable-http",
|
|
29695
|
-
"ws"
|
|
29696
|
-
]);
|
|
29697
|
-
/**
|
|
29698
|
-
* Whether the server speaks over the network rather than over a spawned
|
|
29699
|
-
* process. `httpUrl`, the Claude-specific alias several adapters accept, counts
|
|
29700
|
-
* as much as `url` does, and so does `transport`, the alias `type` has
|
|
29701
|
-
* everywhere in the canonical config.
|
|
29702
|
-
*/
|
|
29703
|
-
function isRemoteMcpServer(serverConfig) {
|
|
29704
|
-
return REMOTE_TRANSPORTS.has(serverConfig.type ?? "") || REMOTE_TRANSPORTS.has(serverConfig.transport ?? "") || serverConfig.url !== void 0 || serverConfig.httpUrl !== void 0;
|
|
29705
|
-
}
|
|
29706
|
-
/** The URL a remote server is reached at, or `undefined` if it states none. */
|
|
29707
|
-
function resolveRemoteMcpUrl(serverConfig) {
|
|
29708
|
-
return serverConfig.url || serverConfig.httpUrl || void 0;
|
|
29709
|
-
}
|
|
29710
|
-
/** The `command` array a `local` server is spawned with, `args` merged in. */
|
|
29711
|
-
function resolveLocalMcpCommand(serverConfig) {
|
|
29712
|
-
const commandArray = [];
|
|
29713
|
-
if (serverConfig.command) {
|
|
29714
|
-
if (Array.isArray(serverConfig.command)) commandArray.push(...serverConfig.command);
|
|
29715
|
-
else commandArray.push(serverConfig.command);
|
|
29716
|
-
}
|
|
29717
|
-
if (serverConfig.args) commandArray.push(...serverConfig.args);
|
|
29718
|
-
return commandArray;
|
|
29719
|
-
}
|
|
29720
|
-
/**
|
|
29721
|
-
* A server that names a transport but carries nothing to reach it — a `type`
|
|
29722
|
-
* with no `command`, an `http` with no `url` — has no form in a config that
|
|
29723
|
-
* spells the transport out. Writing `{type: "local", command: []}` for it would
|
|
29724
|
-
* give the tool a server it cannot start and the importer a file it cannot read
|
|
29725
|
-
* back, so it is skipped out loud instead.
|
|
29726
|
-
*/
|
|
29727
|
-
function warnAndSkipMcpServer({ toolName, serverName, reason, logger }) {
|
|
29728
|
-
logger?.warn(`${toolName} MCP: skipping "${serverName}" because it declares ${reason}.`);
|
|
29729
|
-
return null;
|
|
29730
|
-
}
|
|
29731
|
-
/**
|
|
29732
|
-
* The `tools` map Kilo and OpenCode keep beside `mcp` is keyed `<server>_<tool>`
|
|
29733
|
-
* and reaches servers `mcp` does not list — ones the global config or a
|
|
29734
|
-
* marketplace defines — so entries naming no listed
|
|
29735
|
-
* server are filters that would be dropped by a walk over `mcp` alone, and
|
|
29736
|
-
* deleted from the file on the next generate. They come back as transport-less
|
|
29737
|
-
* servers carrying nothing but the filters.
|
|
29738
|
-
*
|
|
29739
|
-
* The split is at the first `_`, which is where the write side joined them. A
|
|
29740
|
-
* server whose own name contains one is reconstructed under a shorter name, but
|
|
29741
|
-
* the key it is written back as is character-for-character the one that was
|
|
29742
|
-
* read, so Kilo sees exactly what it saw before.
|
|
29743
|
-
*/
|
|
29744
|
-
function orphanMcpToolFiltersToRulesync(servers, tools) {
|
|
29745
|
-
const orphans = {};
|
|
29746
|
-
for (const [toolName, enabled] of Object.entries(tools ?? {})) {
|
|
29747
|
-
if (Object.keys(servers).some((serverName) => toolName.startsWith(`${serverName}_`))) continue;
|
|
29748
|
-
const separator = toolName.indexOf("_");
|
|
29749
|
-
if (separator <= 0 || separator === toolName.length - 1) continue;
|
|
29750
|
-
const serverName = toolName.slice(0, separator);
|
|
29751
|
-
const toolSuffix = toolName.slice(separator + 1);
|
|
29752
|
-
if (!Object.hasOwn(orphans, serverName)) orphans[serverName] = {};
|
|
29753
|
-
const server = orphans[serverName];
|
|
29754
|
-
if (enabled) server.enabledTools = [...server.enabledTools ?? [], toolSuffix];
|
|
29755
|
-
else server.disabledTools = [...server.disabledTools ?? [], toolSuffix];
|
|
29756
|
-
}
|
|
29757
|
-
return orphans;
|
|
29758
|
-
}
|
|
29759
|
-
/**
|
|
29760
|
-
* Split imported servers into the ones every tool can use and the ones only the
|
|
29761
|
-
* importing tool can. A server with no transport is a Kilo/OpenCode idea — a
|
|
29762
|
-
* switch for a server another config layer defines, or a filter for one — and
|
|
29763
|
-
* nothing else knows what to do with it: written to `.mcp.json` and the rest,
|
|
29764
|
-
* it is an entry no tool can start. It goes into the tool-scoped
|
|
29765
|
-
* `{tool}.mcpServers` block instead, which only that tool reads.
|
|
29766
|
-
*/
|
|
29767
|
-
function splitMcpServersByTransport(servers) {
|
|
29768
|
-
const shared = {};
|
|
29769
|
-
const toolOnly = {};
|
|
29770
|
-
for (const [serverName, serverConfig] of Object.entries(servers)) if (declaresNoTransport(serverConfig)) toolOnly[serverName] = serverConfig;
|
|
29771
|
-
else shared[serverName] = serverConfig;
|
|
29772
|
-
return {
|
|
29773
|
-
shared,
|
|
29774
|
-
toolOnly
|
|
29775
|
-
};
|
|
29776
|
-
}
|
|
29777
|
-
//#endregion
|
|
29778
31257
|
//#region src/features/mcp/copilotcli-mcp.ts
|
|
29779
31258
|
/**
|
|
29780
31259
|
* Reached over WebSocket, which Copilot CLI has no transport for. The url is
|
|
@@ -30043,6 +31522,222 @@ var CopilotcliMcp = class CopilotcliMcp extends ToolMcp {
|
|
|
30043
31522
|
}
|
|
30044
31523
|
};
|
|
30045
31524
|
//#endregion
|
|
31525
|
+
//#region src/features/mcp/cortexcode-mcp.ts
|
|
31526
|
+
const CORTEXCODE_GLOBAL_ONLY_MESSAGE = "Snowflake Cortex Code MCP is global-only; use --global to sync ~/.snowflake/cortex/mcp.json";
|
|
31527
|
+
/**
|
|
31528
|
+
* Parse a Cortex Code MCP file, failing closed on malformed JSON or a
|
|
31529
|
+
* non-object root (`null`, an array, a scalar) rather than spreading whatever
|
|
31530
|
+
* came back into the regenerated file.
|
|
31531
|
+
*/
|
|
31532
|
+
function parseCortexcodeMcpConfig({ fileContent, relativePath }) {
|
|
31533
|
+
let parsed;
|
|
31534
|
+
try {
|
|
31535
|
+
parsed = JSON.parse(fileContent);
|
|
31536
|
+
} catch (error) {
|
|
31537
|
+
throw new Error(`Failed to parse Cortex Code MCP config at ${relativePath}: ${formatError(error)}`, { cause: error });
|
|
31538
|
+
}
|
|
31539
|
+
if (!isPlainObject$1(parsed)) throw new Error(`Failed to parse Cortex Code MCP config at ${relativePath}: expected a JSON object at the root`);
|
|
31540
|
+
return parsed;
|
|
31541
|
+
}
|
|
31542
|
+
/**
|
|
31543
|
+
* The remote transport Cortex Code reads a server as. Cortex Code documents
|
|
31544
|
+
* exactly three transports — `stdio`, `http` and `sse` — each spelled out in
|
|
31545
|
+
* an explicit `type` key. `http` is also the canonical rulesync spelling, and
|
|
31546
|
+
* a bare `url` defaults to it, streamable HTTP being the current MCP
|
|
31547
|
+
* transport. `streamable-http` is folded into `http`. A `ws(s)://` URL or any
|
|
31548
|
+
* other stated transport is something Cortex Code cannot reach, so
|
|
31549
|
+
* `undefined` tells the caller to skip the server.
|
|
31550
|
+
* @see https://docs.snowflake.com/en/user-guide/cortex-code/extensibility#transport-types
|
|
31551
|
+
*/
|
|
31552
|
+
function asCortexcodeRemoteType(stated, url) {
|
|
31553
|
+
if (stated === "sse") return "sse";
|
|
31554
|
+
if (stated === "http" || stated === "streamable-http") return "http";
|
|
31555
|
+
if (stated === void 0) return /^wss?:\/\//i.test(url) ? void 0 : "http";
|
|
31556
|
+
}
|
|
31557
|
+
/**
|
|
31558
|
+
* Convert the canonical server map to the shape Cortex Code documents for
|
|
31559
|
+
* `~/.snowflake/cortex/mcp.json`: every server carries an explicit `type`
|
|
31560
|
+
* (`stdio`, `http` or `sse`); a stdio server carries `command` (plus `args`)
|
|
31561
|
+
* and a remote server carries `url`. The canonical `transport` alias and the
|
|
31562
|
+
* Claude-style `httpUrl` alias are folded into `type`/`url`; `env`, `headers`,
|
|
31563
|
+
* `oauth` and `timeout` pass through, as Cortex Code documents all of them.
|
|
31564
|
+
*
|
|
31565
|
+
* A server Cortex Code cannot start or reach — no transport at all, a remote
|
|
31566
|
+
* transport without a URL, a WebSocket URL, or a stdio entry without a
|
|
31567
|
+
* command — is skipped with a warning rather than written in a broken form.
|
|
31568
|
+
* @see https://docs.snowflake.com/en/user-guide/cortex-code/extensibility#mcp-configuration
|
|
31569
|
+
*/
|
|
31570
|
+
function convertToCortexcodeFormat(mcpServers, logger) {
|
|
31571
|
+
const result = {};
|
|
31572
|
+
for (const [serverName, serverConfig] of Object.entries(mcpServers)) {
|
|
31573
|
+
if (PROTOTYPE_POLLUTION_KEYS.has(serverName) || !isRecord$1(serverConfig)) continue;
|
|
31574
|
+
if (declaresNoTransport(serverConfig)) {
|
|
31575
|
+
warnAndSkipMcpServer({
|
|
31576
|
+
toolName: "Cortex Code",
|
|
31577
|
+
serverName,
|
|
31578
|
+
reason: "no transport",
|
|
31579
|
+
logger
|
|
31580
|
+
});
|
|
31581
|
+
continue;
|
|
31582
|
+
}
|
|
31583
|
+
const { type, transport, url: _url, httpUrl: _httpUrl, command: _command, args: _args, ...rest } = serverConfig;
|
|
31584
|
+
const converted = {};
|
|
31585
|
+
if (isRemoteMcpServer(serverConfig)) {
|
|
31586
|
+
const url = resolveRemoteMcpUrl(serverConfig);
|
|
31587
|
+
if (!url) {
|
|
31588
|
+
warnAndSkipMcpServer({
|
|
31589
|
+
toolName: "Cortex Code",
|
|
31590
|
+
serverName,
|
|
31591
|
+
reason: "a remote transport without a url",
|
|
31592
|
+
logger
|
|
31593
|
+
});
|
|
31594
|
+
continue;
|
|
31595
|
+
}
|
|
31596
|
+
const stated = type ?? transport;
|
|
31597
|
+
const remoteType = asCortexcodeRemoteType(stated, url);
|
|
31598
|
+
if (remoteType === void 0) {
|
|
31599
|
+
warnAndSkipMcpServer({
|
|
31600
|
+
toolName: "Cortex Code",
|
|
31601
|
+
serverName,
|
|
31602
|
+
reason: stated === void 0 ? "a WebSocket url, which Cortex Code's remote transports (http and sse) cannot reach" : `the "${stated}" transport, which Cortex Code does not offer for remote servers (only http and sse)`,
|
|
31603
|
+
logger
|
|
31604
|
+
});
|
|
31605
|
+
continue;
|
|
31606
|
+
}
|
|
31607
|
+
converted.type = remoteType;
|
|
31608
|
+
converted.url = url;
|
|
31609
|
+
} else {
|
|
31610
|
+
const [command, ...args] = resolveLocalMcpCommand(serverConfig);
|
|
31611
|
+
if (!command) {
|
|
31612
|
+
warnAndSkipMcpServer({
|
|
31613
|
+
toolName: "Cortex Code",
|
|
31614
|
+
serverName,
|
|
31615
|
+
reason: "a stdio transport without a command",
|
|
31616
|
+
logger
|
|
31617
|
+
});
|
|
31618
|
+
continue;
|
|
31619
|
+
}
|
|
31620
|
+
converted.type = "stdio";
|
|
31621
|
+
converted.command = command;
|
|
31622
|
+
if (args.length > 0) converted.args = args;
|
|
31623
|
+
}
|
|
31624
|
+
for (const [key, value] of Object.entries(rest)) {
|
|
31625
|
+
if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
|
|
31626
|
+
converted[key] = (key === "env" || key === "headers") && isRecord$1(value) ? omitPrototypePollutionKeys(value) : value;
|
|
31627
|
+
}
|
|
31628
|
+
result[serverName] = converted;
|
|
31629
|
+
}
|
|
31630
|
+
return result;
|
|
31631
|
+
}
|
|
31632
|
+
/**
|
|
31633
|
+
* Convert Cortex Code's server map back to the canonical shape. The
|
|
31634
|
+
* documented spelling (`type` + `command`/`url`) is already canonical, so
|
|
31635
|
+
* entries pass through with only prototype-pollution keys dropped.
|
|
31636
|
+
*/
|
|
31637
|
+
function convertFromCortexcodeFormat(mcpServers) {
|
|
31638
|
+
if (!isMcpServers(mcpServers)) return {};
|
|
31639
|
+
const result = {};
|
|
31640
|
+
for (const [serverName, serverConfig] of Object.entries(mcpServers)) {
|
|
31641
|
+
if (PROTOTYPE_POLLUTION_KEYS.has(serverName) || !isRecord$1(serverConfig)) continue;
|
|
31642
|
+
result[serverName] = omitPrototypePollutionKeys(serverConfig);
|
|
31643
|
+
}
|
|
31644
|
+
return result;
|
|
31645
|
+
}
|
|
31646
|
+
/**
|
|
31647
|
+
* Snowflake Cortex Code MCP configuration.
|
|
31648
|
+
*
|
|
31649
|
+
* Cortex Code reads `mcpServers` only from the single user-scoped file
|
|
31650
|
+
* `~/.snowflake/cortex/mcp.json`; no project-scoped MCP location is
|
|
31651
|
+
* documented, so the target is global-only. The file is created and edited by
|
|
31652
|
+
* `cortex mcp add` as well, so `--delete` leaves it in place rather than
|
|
31653
|
+
* removing a file the user did not create through rulesync.
|
|
31654
|
+
*
|
|
31655
|
+
* @see https://docs.snowflake.com/en/user-guide/cortex-code/extensibility#mcp-configuration
|
|
31656
|
+
*/
|
|
31657
|
+
var CortexcodeMcp = class CortexcodeMcp extends ToolMcp {
|
|
31658
|
+
json;
|
|
31659
|
+
constructor(params) {
|
|
31660
|
+
super(params);
|
|
31661
|
+
this.json = this.fileContent === void 0 ? {} : parseCortexcodeMcpConfig({
|
|
31662
|
+
fileContent: this.fileContent,
|
|
31663
|
+
relativePath: (0, node_path.join)(this.relativeDirPath, this.relativeFilePath)
|
|
31664
|
+
});
|
|
31665
|
+
}
|
|
31666
|
+
getJson() {
|
|
31667
|
+
return this.json;
|
|
31668
|
+
}
|
|
31669
|
+
isDeletable() {
|
|
31670
|
+
return false;
|
|
31671
|
+
}
|
|
31672
|
+
static getSettablePaths(_options = {}) {
|
|
31673
|
+
return {
|
|
31674
|
+
relativeDirPath: CORTEXCODE_GLOBAL_DIR_PATH,
|
|
31675
|
+
relativeFilePath: CORTEXCODE_MCP_FILE_NAME
|
|
31676
|
+
};
|
|
31677
|
+
}
|
|
31678
|
+
static async fromFile({ outputRoot = process.cwd(), validate = true, global = false }) {
|
|
31679
|
+
if (!global) throw new Error(CORTEXCODE_GLOBAL_ONLY_MESSAGE);
|
|
31680
|
+
const paths = this.getSettablePaths({ global });
|
|
31681
|
+
const json = parseCortexcodeMcpConfig({
|
|
31682
|
+
fileContent: await readFileContentOrNull((0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath)) ?? "{\"mcpServers\":{}}",
|
|
31683
|
+
relativePath: (0, node_path.join)(paths.relativeDirPath, paths.relativeFilePath)
|
|
31684
|
+
});
|
|
31685
|
+
const newJson = {
|
|
31686
|
+
...json,
|
|
31687
|
+
mcpServers: json.mcpServers ?? {}
|
|
31688
|
+
};
|
|
31689
|
+
return new CortexcodeMcp({
|
|
31690
|
+
outputRoot,
|
|
31691
|
+
relativeDirPath: paths.relativeDirPath,
|
|
31692
|
+
relativeFilePath: paths.relativeFilePath,
|
|
31693
|
+
fileContent: JSON.stringify(newJson, null, 2),
|
|
31694
|
+
validate,
|
|
31695
|
+
global
|
|
31696
|
+
});
|
|
31697
|
+
}
|
|
31698
|
+
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false, logger }) {
|
|
31699
|
+
if (!global) throw new Error(CORTEXCODE_GLOBAL_ONLY_MESSAGE);
|
|
31700
|
+
const paths = this.getSettablePaths({ global });
|
|
31701
|
+
const json = parseCortexcodeMcpConfig({
|
|
31702
|
+
fileContent: await readFileContentOrNull((0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath)) ?? JSON.stringify({ mcpServers: {} }, null, 2),
|
|
31703
|
+
relativePath: (0, node_path.join)(paths.relativeDirPath, paths.relativeFilePath)
|
|
31704
|
+
});
|
|
31705
|
+
const mcpServers = convertToCortexcodeFormat(rulesyncMcp.getMcpServers(), logger);
|
|
31706
|
+
const cortexcodeConfig = {
|
|
31707
|
+
...json,
|
|
31708
|
+
mcpServers
|
|
31709
|
+
};
|
|
31710
|
+
return new CortexcodeMcp({
|
|
31711
|
+
outputRoot,
|
|
31712
|
+
relativeDirPath: paths.relativeDirPath,
|
|
31713
|
+
relativeFilePath: paths.relativeFilePath,
|
|
31714
|
+
fileContent: JSON.stringify(cortexcodeConfig, null, 2),
|
|
31715
|
+
validate,
|
|
31716
|
+
global
|
|
31717
|
+
});
|
|
31718
|
+
}
|
|
31719
|
+
toRulesyncMcp() {
|
|
31720
|
+
const mcpServers = convertFromCortexcodeFormat(this.json.mcpServers);
|
|
31721
|
+
return this.toRulesyncMcpDefault({ fileContent: JSON.stringify({ mcpServers }, null, 2) });
|
|
31722
|
+
}
|
|
31723
|
+
validate() {
|
|
31724
|
+
return {
|
|
31725
|
+
success: true,
|
|
31726
|
+
error: null
|
|
31727
|
+
};
|
|
31728
|
+
}
|
|
31729
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
|
|
31730
|
+
return new CortexcodeMcp({
|
|
31731
|
+
outputRoot,
|
|
31732
|
+
relativeDirPath,
|
|
31733
|
+
relativeFilePath,
|
|
31734
|
+
fileContent: "{}",
|
|
31735
|
+
validate: false,
|
|
31736
|
+
global
|
|
31737
|
+
});
|
|
31738
|
+
}
|
|
31739
|
+
};
|
|
31740
|
+
//#endregion
|
|
30046
31741
|
//#region src/features/mcp/mcp-env-var-format.ts
|
|
30047
31742
|
/**
|
|
30048
31743
|
* Canonical rulesync env var reference pattern: `${VAR}` (but not `${env:VAR}`,
|
|
@@ -34004,6 +35699,211 @@ var RovodevMcp = class RovodevMcp extends ToolMcp {
|
|
|
34004
35699
|
}
|
|
34005
35700
|
};
|
|
34006
35701
|
//#endregion
|
|
35702
|
+
//#region src/features/mcp/tabnine-mcp.ts
|
|
35703
|
+
/**
|
|
35704
|
+
* The remote `type` Tabnine CLI reads a server as. Tabnine documents `"http"`
|
|
35705
|
+
* (streamable HTTP, the default for a bare `url`) and `"sse"`; `streamable-http`
|
|
35706
|
+
* is the canonical alias for the former. A `ws(s)://` URL or any other stated
|
|
35707
|
+
* transport is something Tabnine cannot reach, so `undefined` tells the caller
|
|
35708
|
+
* to skip the server. `null` means "omit `type`": Tabnine then tries
|
|
35709
|
+
* streamable HTTP first and falls back to SSE on its own.
|
|
35710
|
+
* @see https://docs.tabnine.com/main/getting-started/tabnine-agent/mcp-intro-and-setup/mcp-server-config
|
|
35711
|
+
*/
|
|
35712
|
+
function asTabnineRemoteType(stated, url) {
|
|
35713
|
+
if (stated === "sse") return "sse";
|
|
35714
|
+
if (stated === "http" || stated === "streamable-http") return "http";
|
|
35715
|
+
if (stated === void 0) return /^wss?:\/\//i.test(url) ? void 0 : null;
|
|
35716
|
+
}
|
|
35717
|
+
/**
|
|
35718
|
+
* Convert the canonical server map to the shape Tabnine CLI documents for the
|
|
35719
|
+
* `mcpServers` block of `settings.json`: a stdio server carries `command` (plus
|
|
35720
|
+
* `args`), a remote one carries `url` and an optional `type` (`"http"` or
|
|
35721
|
+
* `"sse"`). The canonical `transport` alias and the Claude-style `httpUrl`
|
|
35722
|
+
* alias are folded into `type`/`url`; `enabledTools`/`disabledTools` become
|
|
35723
|
+
* Tabnine's `includeTools`/`excludeTools`; `env`, `cwd`, `headers`, `timeout`
|
|
35724
|
+
* and `trust` pass through as documented.
|
|
35725
|
+
*
|
|
35726
|
+
* A server Tabnine cannot start or reach — no transport at all, a remote
|
|
35727
|
+
* transport without a URL, a WebSocket URL, or a stdio entry without a command
|
|
35728
|
+
* — is skipped with a warning rather than written in a broken form.
|
|
35729
|
+
*/
|
|
35730
|
+
function convertToTabnineFormat(mcpServers, logger) {
|
|
35731
|
+
const result = {};
|
|
35732
|
+
for (const [serverName, serverConfig] of Object.entries(mcpServers)) {
|
|
35733
|
+
if (PROTOTYPE_POLLUTION_KEYS.has(serverName) || !isRecord$1(serverConfig)) continue;
|
|
35734
|
+
if (declaresNoTransport(serverConfig)) {
|
|
35735
|
+
warnAndSkipMcpServer({
|
|
35736
|
+
toolName: "Tabnine CLI",
|
|
35737
|
+
serverName,
|
|
35738
|
+
reason: "no transport",
|
|
35739
|
+
logger
|
|
35740
|
+
});
|
|
35741
|
+
continue;
|
|
35742
|
+
}
|
|
35743
|
+
const { type, transport, url: _url, httpUrl: _httpUrl, command: _command, args: _args, enabledTools, disabledTools, ...rest } = serverConfig;
|
|
35744
|
+
const converted = {};
|
|
35745
|
+
if (isRemoteMcpServer(serverConfig)) {
|
|
35746
|
+
const url = resolveRemoteMcpUrl(serverConfig);
|
|
35747
|
+
if (!url) {
|
|
35748
|
+
warnAndSkipMcpServer({
|
|
35749
|
+
toolName: "Tabnine CLI",
|
|
35750
|
+
serverName,
|
|
35751
|
+
reason: "a remote transport without a url",
|
|
35752
|
+
logger
|
|
35753
|
+
});
|
|
35754
|
+
continue;
|
|
35755
|
+
}
|
|
35756
|
+
const stated = type ?? transport;
|
|
35757
|
+
const remoteType = asTabnineRemoteType(stated, url);
|
|
35758
|
+
if (remoteType === void 0) {
|
|
35759
|
+
warnAndSkipMcpServer({
|
|
35760
|
+
toolName: "Tabnine CLI",
|
|
35761
|
+
serverName,
|
|
35762
|
+
reason: stated === void 0 ? "a WebSocket url, which Tabnine CLI's remote transports (http and sse) cannot reach" : `the "${stated}" transport, which Tabnine CLI does not offer for remote servers (only http and sse)`,
|
|
35763
|
+
logger
|
|
35764
|
+
});
|
|
35765
|
+
continue;
|
|
35766
|
+
}
|
|
35767
|
+
converted.url = url;
|
|
35768
|
+
if (remoteType !== null) converted.type = remoteType;
|
|
35769
|
+
} else {
|
|
35770
|
+
const [command, ...args] = resolveLocalMcpCommand(serverConfig);
|
|
35771
|
+
if (!command) {
|
|
35772
|
+
warnAndSkipMcpServer({
|
|
35773
|
+
toolName: "Tabnine CLI",
|
|
35774
|
+
serverName,
|
|
35775
|
+
reason: "a stdio transport without a command",
|
|
35776
|
+
logger
|
|
35777
|
+
});
|
|
35778
|
+
continue;
|
|
35779
|
+
}
|
|
35780
|
+
converted.command = command;
|
|
35781
|
+
if (args.length > 0) converted.args = args;
|
|
35782
|
+
}
|
|
35783
|
+
for (const [key, value] of Object.entries(rest)) {
|
|
35784
|
+
if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
|
|
35785
|
+
converted[key] = (key === "env" || key === "headers") && isRecord$1(value) ? omitPrototypePollutionKeys(value) : value;
|
|
35786
|
+
}
|
|
35787
|
+
if (enabledTools !== void 0) converted.includeTools = enabledTools;
|
|
35788
|
+
if (disabledTools !== void 0) converted.excludeTools = disabledTools;
|
|
35789
|
+
result[serverName] = converted;
|
|
35790
|
+
}
|
|
35791
|
+
return result;
|
|
35792
|
+
}
|
|
35793
|
+
/**
|
|
35794
|
+
* Convert Tabnine's server map back to the canonical shape: `includeTools` /
|
|
35795
|
+
* `excludeTools` become `enabledTools` / `disabledTools`; `type` (`stdio`,
|
|
35796
|
+
* `sse`, `http`) and every other documented field are already canonical.
|
|
35797
|
+
*/
|
|
35798
|
+
function convertFromTabnineFormat(mcpServers) {
|
|
35799
|
+
if (!isMcpServers(mcpServers)) return {};
|
|
35800
|
+
const result = {};
|
|
35801
|
+
for (const [serverName, serverConfig] of Object.entries(mcpServers)) {
|
|
35802
|
+
if (PROTOTYPE_POLLUTION_KEYS.has(serverName) || !isRecord$1(serverConfig)) continue;
|
|
35803
|
+
const converted = {};
|
|
35804
|
+
for (const [key, value] of Object.entries(serverConfig)) {
|
|
35805
|
+
if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
|
|
35806
|
+
if (key === "includeTools") converted.enabledTools = value;
|
|
35807
|
+
else if (key === "excludeTools") converted.disabledTools = value;
|
|
35808
|
+
else converted[key] = value;
|
|
35809
|
+
}
|
|
35810
|
+
result[serverName] = converted;
|
|
35811
|
+
}
|
|
35812
|
+
return result;
|
|
35813
|
+
}
|
|
35814
|
+
/**
|
|
35815
|
+
* Tabnine CLI MCP configuration.
|
|
35816
|
+
*
|
|
35817
|
+
* Tabnine CLI reads `mcpServers` from `<project>/.tabnine/agent/settings.json`
|
|
35818
|
+
* (project scope) and `~/.tabnine/agent/settings.json` (user scope); the
|
|
35819
|
+
* project entry wins when both define the same server name. Both files hold
|
|
35820
|
+
* the user's other settings (`general`, `tools`, `hooks`, ...), so writes go
|
|
35821
|
+
* through the shared-config gateway with `mcpServers` as the only owned key
|
|
35822
|
+
* and the file is never deleted.
|
|
35823
|
+
*
|
|
35824
|
+
* @see https://docs.tabnine.com/main/getting-started/tabnine-agent/mcp-intro-and-setup/mcp-server-config
|
|
35825
|
+
* @see https://docs.tabnine.com/main/getting-started/tabnine-cli/features/settings
|
|
35826
|
+
*/
|
|
35827
|
+
var TabnineMcp = class TabnineMcp extends ToolMcp {
|
|
35828
|
+
json;
|
|
35829
|
+
constructor(params) {
|
|
35830
|
+
super(params);
|
|
35831
|
+
this.json = parseSharedConfig({
|
|
35832
|
+
format: "json",
|
|
35833
|
+
fileContent: this.fileContent || "{}",
|
|
35834
|
+
filePath: (0, node_path.join)(this.relativeDirPath, this.relativeFilePath),
|
|
35835
|
+
invalidRootPolicy: "error"
|
|
35836
|
+
});
|
|
35837
|
+
}
|
|
35838
|
+
getJson() {
|
|
35839
|
+
return this.json;
|
|
35840
|
+
}
|
|
35841
|
+
/**
|
|
35842
|
+
* settings.json carries the user's other Tabnine settings, so it must not
|
|
35843
|
+
* be deleted.
|
|
35844
|
+
*/
|
|
35845
|
+
isDeletable() {
|
|
35846
|
+
return false;
|
|
35847
|
+
}
|
|
35848
|
+
static getSettablePaths(_options = {}) {
|
|
35849
|
+
return {
|
|
35850
|
+
relativeDirPath: TABNINE_AGENT_DIR_PATH,
|
|
35851
|
+
relativeFilePath: TABNINE_SETTINGS_FILE_NAME
|
|
35852
|
+
};
|
|
35853
|
+
}
|
|
35854
|
+
static async fromFile({ outputRoot = process.cwd(), validate = true, global = false }) {
|
|
35855
|
+
const paths = this.getSettablePaths({ global });
|
|
35856
|
+
const fileContent = await readFileContentOrNull((0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath)) ?? "{\"mcpServers\":{}}";
|
|
35857
|
+
return new TabnineMcp({
|
|
35858
|
+
outputRoot,
|
|
35859
|
+
relativeDirPath: paths.relativeDirPath,
|
|
35860
|
+
relativeFilePath: paths.relativeFilePath,
|
|
35861
|
+
fileContent,
|
|
35862
|
+
validate,
|
|
35863
|
+
global
|
|
35864
|
+
});
|
|
35865
|
+
}
|
|
35866
|
+
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false, logger }) {
|
|
35867
|
+
const paths = this.getSettablePaths({ global });
|
|
35868
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
35869
|
+
const existingContent = await readFileContentOrNull(filePath) ?? JSON.stringify({ mcpServers: {} }, null, 2);
|
|
35870
|
+
return new TabnineMcp({
|
|
35871
|
+
outputRoot,
|
|
35872
|
+
relativeDirPath: paths.relativeDirPath,
|
|
35873
|
+
relativeFilePath: paths.relativeFilePath,
|
|
35874
|
+
fileContent: applySharedConfigPatch({
|
|
35875
|
+
fileKey: sharedConfigFileKey(paths),
|
|
35876
|
+
feature: "mcp",
|
|
35877
|
+
existingContent,
|
|
35878
|
+
patch: { mcpServers: convertToTabnineFormat(rulesyncMcp.getMcpServers(), logger) },
|
|
35879
|
+
filePath
|
|
35880
|
+
}),
|
|
35881
|
+
validate,
|
|
35882
|
+
global
|
|
35883
|
+
});
|
|
35884
|
+
}
|
|
35885
|
+
toRulesyncMcp() {
|
|
35886
|
+
const mcpServers = convertFromTabnineFormat(this.json.mcpServers);
|
|
35887
|
+
return this.toRulesyncMcpDefault({ fileContent: JSON.stringify({ mcpServers }, null, 2) });
|
|
35888
|
+
}
|
|
35889
|
+
validate() {
|
|
35890
|
+
return {
|
|
35891
|
+
success: true,
|
|
35892
|
+
error: null
|
|
35893
|
+
};
|
|
35894
|
+
}
|
|
35895
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
|
|
35896
|
+
return new TabnineMcp({
|
|
35897
|
+
outputRoot,
|
|
35898
|
+
relativeDirPath,
|
|
35899
|
+
relativeFilePath,
|
|
35900
|
+
fileContent: "{}",
|
|
35901
|
+
validate: false,
|
|
35902
|
+
global
|
|
35903
|
+
});
|
|
35904
|
+
}
|
|
35905
|
+
};
|
|
35906
|
+
//#endregion
|
|
34007
35907
|
//#region src/features/mcp/takt-mcp.ts
|
|
34008
35908
|
/**
|
|
34009
35909
|
* MCP adapter for Takt (`.takt/config.yaml` project / `~/.takt/config.yaml`
|
|
@@ -34963,6 +36863,15 @@ const toolMcpFactories = /* @__PURE__ */ new Map([
|
|
|
34963
36863
|
supportsDisabledTools: false
|
|
34964
36864
|
}
|
|
34965
36865
|
}],
|
|
36866
|
+
["bob", {
|
|
36867
|
+
class: BobMcp,
|
|
36868
|
+
meta: {
|
|
36869
|
+
supportsProject: true,
|
|
36870
|
+
supportsGlobal: true,
|
|
36871
|
+
supportsEnabledTools: false,
|
|
36872
|
+
supportsDisabledTools: false
|
|
36873
|
+
}
|
|
36874
|
+
}],
|
|
34966
36875
|
["claudecode", {
|
|
34967
36876
|
class: ClaudecodeMcp,
|
|
34968
36877
|
meta: {
|
|
@@ -35026,6 +36935,15 @@ const toolMcpFactories = /* @__PURE__ */ new Map([
|
|
|
35026
36935
|
supportsDisabledTools: false
|
|
35027
36936
|
}
|
|
35028
36937
|
}],
|
|
36938
|
+
["cortexcode", {
|
|
36939
|
+
class: CortexcodeMcp,
|
|
36940
|
+
meta: {
|
|
36941
|
+
supportsProject: false,
|
|
36942
|
+
supportsGlobal: true,
|
|
36943
|
+
supportsEnabledTools: false,
|
|
36944
|
+
supportsDisabledTools: false
|
|
36945
|
+
}
|
|
36946
|
+
}],
|
|
35029
36947
|
["cursor", {
|
|
35030
36948
|
class: CursorMcp,
|
|
35031
36949
|
meta: {
|
|
@@ -35197,6 +37115,15 @@ const toolMcpFactories = /* @__PURE__ */ new Map([
|
|
|
35197
37115
|
supportsDisabledTools: false
|
|
35198
37116
|
}
|
|
35199
37117
|
}],
|
|
37118
|
+
["tabnine", {
|
|
37119
|
+
class: TabnineMcp,
|
|
37120
|
+
meta: {
|
|
37121
|
+
supportsProject: true,
|
|
37122
|
+
supportsGlobal: true,
|
|
37123
|
+
supportsEnabledTools: true,
|
|
37124
|
+
supportsDisabledTools: true
|
|
37125
|
+
}
|
|
37126
|
+
}],
|
|
35200
37127
|
["takt", {
|
|
35201
37128
|
class: TaktMcp,
|
|
35202
37129
|
meta: {
|
|
@@ -36401,7 +38328,7 @@ const ANTIGRAVITY_CLI_OVERRIDE_KEYS = [
|
|
|
36401
38328
|
"allowNonWorkspaceAccess",
|
|
36402
38329
|
"agentMode"
|
|
36403
38330
|
];
|
|
36404
|
-
const moduleLogger$
|
|
38331
|
+
const moduleLogger$4 = fallbackLogger;
|
|
36405
38332
|
/**
|
|
36406
38333
|
* Narrow an imported `settings.json` value to one of the documented values of
|
|
36407
38334
|
* an enum-typed override key. The override schema declares `toolPermission`,
|
|
@@ -36415,7 +38342,7 @@ const moduleLogger$3 = fallbackLogger;
|
|
|
36415
38342
|
function pickDocumentedValue({ key, value, documented }) {
|
|
36416
38343
|
if (typeof value !== "string") return void 0;
|
|
36417
38344
|
if (documented.includes(value)) return value;
|
|
36418
|
-
moduleLogger$
|
|
38345
|
+
moduleLogger$4.warn(`Antigravity CLI permissions: dropping '${key}: ${value}' on import — it is not one of the documented values (${documented.join(", ")}), and carrying it through would fail validation of the whole permissions file. Author it under the 'antigravity-cli' override by hand once rulesync supports it.`);
|
|
36419
38346
|
}
|
|
36420
38347
|
/**
|
|
36421
38348
|
* Deliberate mapping from rulesync canonical permission categories to the
|
|
@@ -36887,7 +38814,7 @@ function convertAntigravityIdeToRulesyncPermissions(params) {
|
|
|
36887
38814
|
}
|
|
36888
38815
|
//#endregion
|
|
36889
38816
|
//#region src/features/permissions/augmentcode-permissions.ts
|
|
36890
|
-
const moduleLogger$
|
|
38817
|
+
const moduleLogger$3 = fallbackLogger;
|
|
36891
38818
|
zod_mini.z.enum([
|
|
36892
38819
|
"allow",
|
|
36893
38820
|
"deny",
|
|
@@ -37186,7 +39113,7 @@ var AugmentcodePermissions = class AugmentcodePermissions extends ToolPermission
|
|
|
37186
39113
|
const specialEntries = allEntries.filter((entry) => isSpecialEntry(entry));
|
|
37187
39114
|
const result = { ...convertAugmentToRulesyncPermissions({
|
|
37188
39115
|
entries: allEntries.filter((entry) => !isSpecialEntry(entry)),
|
|
37189
|
-
logger: moduleLogger$
|
|
39116
|
+
logger: moduleLogger$3
|
|
37190
39117
|
}) };
|
|
37191
39118
|
if (specialEntries.length > 0) result.augmentcode = { toolPermissions: specialEntries };
|
|
37192
39119
|
return this.toRulesyncPermissionsDefault({ fileContent: JSON.stringify(result, null, 2) });
|
|
@@ -37560,6 +39487,14 @@ function collectRestrictionLosingSandboxEntries({ existing, merged, paths, toolL
|
|
|
37560
39487
|
return entries;
|
|
37561
39488
|
}
|
|
37562
39489
|
/**
|
|
39490
|
+
* The `'<label>' — <reason>` list a trust-affecting warning ends with, shared so
|
|
39491
|
+
* an adapter that phrases the rest of the sentence itself (an import that lifts
|
|
39492
|
+
* the settings rather than writes them) prints the entries the same way.
|
|
39493
|
+
*/
|
|
39494
|
+
function formatTrustAffectingEntries(entries) {
|
|
39495
|
+
return entries.map(({ label, reason }) => `'${label}' — ${reason}`).join("; ");
|
|
39496
|
+
}
|
|
39497
|
+
/**
|
|
37563
39498
|
* The one warning that names every trust-affecting setting this generate wrote
|
|
37564
39499
|
* to `relativeFilePath`. Emitted once per file: the individual reasons are what
|
|
37565
39500
|
* matter, but the "review this as you would a hook" framing only needs saying
|
|
@@ -37570,7 +39505,7 @@ function collectRestrictionLosingSandboxEntries({ existing, merged, paths, toolL
|
|
|
37570
39505
|
function warnOnTrustAffectingEntries({ toolLabel, noun = "setting", entries, relativeFilePath, logger }) {
|
|
37571
39506
|
if (entries.length === 0) return;
|
|
37572
39507
|
const one = entries.length === 1;
|
|
37573
|
-
const details = entries
|
|
39508
|
+
const details = formatTrustAffectingEntries(entries);
|
|
37574
39509
|
logger?.warn(`${toolLabel} permissions: writing ${entries.length} trust-affecting ${noun}${one ? "" : "s"} to ${relativeFilePath}; review ${one ? "it" : "them"} as you would a hook, especially if this permissions file came from 'rulesync fetch'. ${details}.`);
|
|
37575
39510
|
}
|
|
37576
39511
|
//#endregion
|
|
@@ -43692,7 +45627,7 @@ const QwenSettingsPermissionsSchema = zod_mini.z.looseObject({
|
|
|
43692
45627
|
deny: zod_mini.z.optional(zod_mini.z.array(zod_mini.z.string()))
|
|
43693
45628
|
});
|
|
43694
45629
|
const QwenSettingsSchema = zod_mini.z.looseObject({ permissions: zod_mini.z.optional(QwenSettingsPermissionsSchema) });
|
|
43695
|
-
const moduleLogger$
|
|
45630
|
+
const moduleLogger$2 = fallbackLogger;
|
|
43696
45631
|
/**
|
|
43697
45632
|
* Mapping from rulesync canonical tool category names (lowercase) to Qwen Code tool names (PascalCase).
|
|
43698
45633
|
* Unknown names pass through as-is (e.g., mcp__server__tool).
|
|
@@ -44055,7 +45990,7 @@ function warnAboutImportedScopedKeys(groups) {
|
|
|
44055
45990
|
if (!announceOnImport) continue;
|
|
44056
45991
|
if (announceOnlyGrants && !grantsSomething(value, scopedKey)) continue;
|
|
44057
45992
|
const globalNote = scopedKey.globalNote ?? QWEN_SCOPE_RULES[rule].globalNote;
|
|
44058
|
-
moduleLogger$
|
|
45993
|
+
moduleLogger$2.warn(`Qwen permissions: imported ${quoteQualifiedKey({
|
|
44059
45994
|
groupName,
|
|
44060
45995
|
key
|
|
44061
45996
|
})} = ${quoteValueForWarning(value)}. ${globalNote} Review it before generating with the global scope.`);
|
|
@@ -44248,7 +46183,7 @@ function convertRulesyncToQwenPermissions(config) {
|
|
|
44248
46183
|
}
|
|
44249
46184
|
function convertQwenToRulesyncPermissions(params) {
|
|
44250
46185
|
const permission = {};
|
|
44251
|
-
const logger = params.logger ?? moduleLogger$
|
|
46186
|
+
const logger = params.logger ?? moduleLogger$2;
|
|
44252
46187
|
const processEntries = (entries, action) => {
|
|
44253
46188
|
for (const entry of entries) {
|
|
44254
46189
|
const parsed = parseQwenPermissionEntry(entry, { logger });
|
|
@@ -45574,6 +47509,585 @@ function isPermissionAction(value) {
|
|
|
45574
47509
|
return PermissionActionSchema.safeParse(value).success;
|
|
45575
47510
|
}
|
|
45576
47511
|
//#endregion
|
|
47512
|
+
//#region src/features/permissions/tabnine-permissions.ts
|
|
47513
|
+
/** The `settings.json` key group that carries the two tool lists. */
|
|
47514
|
+
const TOOLS_KEY = "tools";
|
|
47515
|
+
/** `tools.allowed`: tool names (and `run_shell_command(<prefix>)`) that skip the confirmation prompt. */
|
|
47516
|
+
const ALLOWED_KEY = "allowed";
|
|
47517
|
+
/** `tools.exclude`: tool names removed from discovery entirely. */
|
|
47518
|
+
const EXCLUDE_KEY = "exclude";
|
|
47519
|
+
/** The `settings.json` key group whose keys the `tabnine` override may author. */
|
|
47520
|
+
const GENERAL_KEY = "general";
|
|
47521
|
+
/** The Tabnine CLI built-in that runs shell commands. */
|
|
47522
|
+
const SHELL_TOOL_NAME = "run_shell_command";
|
|
47523
|
+
/**
|
|
47524
|
+
* The paths of the `tabnine` override that are refused with a warning rather
|
|
47525
|
+
* than written — the line Claude Code's sandbox paths draw. Under `tools`, the
|
|
47526
|
+
* values Tabnine CLI spawns as a command (`discoveryCommand` and `callCommand`
|
|
47527
|
+
* at startup, `shell.pager` on every shell output, `sandbox.command` to start
|
|
47528
|
+
* the sandbox); under `general`, the host every login and API call goes to
|
|
47529
|
+
* (`tabnineHost`) and the editor executable (`preferredEditor`, "any editor
|
|
47530
|
+
* path"). A fetched `.rulesync/permissions.jsonc` must not be able to point
|
|
47531
|
+
* Tabnine CLI at an executable, or a server, of its choosing.
|
|
47532
|
+
* @see https://docs.tabnine.com/main/getting-started/tabnine-cli/features/settings/settings-reference
|
|
47533
|
+
*/
|
|
47534
|
+
const REFUSED_OVERRIDE_PATHS = {
|
|
47535
|
+
[TOOLS_KEY]: [
|
|
47536
|
+
["discoveryCommand"],
|
|
47537
|
+
["callCommand"],
|
|
47538
|
+
["shell", "pager"],
|
|
47539
|
+
["sandbox", "command"]
|
|
47540
|
+
],
|
|
47541
|
+
[GENERAL_KEY]: [["tabnineHost"], ["preferredEditor"]]
|
|
47542
|
+
};
|
|
47543
|
+
/** `tools.sandbox`: `true` keeps tool calls contained; anything else disables or picks the sandbox. */
|
|
47544
|
+
const SANDBOX_KEY = "sandbox";
|
|
47545
|
+
/** `general.defaultApprovalMode`: the modes that still ask before a tool call runs. */
|
|
47546
|
+
const DEFAULT_APPROVAL_MODE_KEY = "defaultApprovalMode";
|
|
47547
|
+
const PROMPTING_APPROVAL_MODES = /* @__PURE__ */ new Set(["default", "plan"]);
|
|
47548
|
+
/**
|
|
47549
|
+
* Canonical categories with a one-to-one Tabnine CLI built-in tool. `bash` is
|
|
47550
|
+
* handled separately because it is the only tool whose list entries carry a
|
|
47551
|
+
* command prefix.
|
|
47552
|
+
*
|
|
47553
|
+
* @see https://docs.tabnine.com/main/getting-started/tabnine-cli/features/built-in-tools
|
|
47554
|
+
*/
|
|
47555
|
+
const CANONICAL_TO_TABNINE_TOOL_NAMES = {
|
|
47556
|
+
read: "read_file",
|
|
47557
|
+
edit: "replace",
|
|
47558
|
+
write: "write_file",
|
|
47559
|
+
webfetch: "web_fetch",
|
|
47560
|
+
websearch: "google_web_search",
|
|
47561
|
+
grep: "grep_search",
|
|
47562
|
+
glob: "glob"
|
|
47563
|
+
};
|
|
47564
|
+
const TABNINE_TO_CANONICAL_TOOL_NAMES = Object.fromEntries(Object.entries(CANONICAL_TO_TABNINE_TOOL_NAMES).map(([canonical, tabnine]) => [tabnine, canonical]));
|
|
47565
|
+
const moduleLogger$1 = fallbackLogger;
|
|
47566
|
+
/**
|
|
47567
|
+
* Turn a canonical `bash` glob into the command prefix a
|
|
47568
|
+
* `run_shell_command(<prefix>)` entry carries. Tabnine matches the prefix
|
|
47569
|
+
* against the start of the command line, so only two glob shapes map cleanly:
|
|
47570
|
+
* `<prefix> *` and a bare `<prefix>` with no wildcard at all. Anything else
|
|
47571
|
+
* (`git * push`, `*.sh`, `npm run:*`) matches commands a prefix cannot name, so
|
|
47572
|
+
* it is reported and left out rather than approximated. `*` alone names the
|
|
47573
|
+
* tool itself and is returned as the empty prefix.
|
|
47574
|
+
*/
|
|
47575
|
+
function toShellPrefix(pattern) {
|
|
47576
|
+
if (pattern === "*") return "";
|
|
47577
|
+
const prefix = pattern.endsWith(" *") ? pattern.slice(0, -2) : pattern;
|
|
47578
|
+
if (prefix.length === 0 || /[*?[\]]/.test(prefix)) return;
|
|
47579
|
+
return prefix;
|
|
47580
|
+
}
|
|
47581
|
+
/**
|
|
47582
|
+
* The Tabnine tool a canonical category names. An unknown category is passed
|
|
47583
|
+
* through as a tool name (that is how an MCP tool is named); the read is an
|
|
47584
|
+
* own-property lookup so a category spelled `toString` does not pick up an
|
|
47585
|
+
* `Object.prototype` member.
|
|
47586
|
+
*/
|
|
47587
|
+
function toTabnineToolName(category) {
|
|
47588
|
+
return lookupOwn({
|
|
47589
|
+
record: CANONICAL_TO_TABNINE_TOOL_NAMES,
|
|
47590
|
+
key: category
|
|
47591
|
+
}) ?? category;
|
|
47592
|
+
}
|
|
47593
|
+
/**
|
|
47594
|
+
* The widest glob a `bash` pattern stands for once it is written as a
|
|
47595
|
+
* `run_shell_command(<prefix>)` entry: the prefix matches the start of the
|
|
47596
|
+
* command line, so a bare `pnpm` also covers `pnpm install`. Used only to
|
|
47597
|
+
* compare allows against the restrictions (`bash` deny and `ask` rules, and
|
|
47598
|
+
* the rules of `*`), where widening can only withhold more, never fail open.
|
|
47599
|
+
*/
|
|
47600
|
+
function widenToPrefixGlob(pattern) {
|
|
47601
|
+
const prefix = toShellPrefix(pattern);
|
|
47602
|
+
if (prefix === void 0) return pattern;
|
|
47603
|
+
return prefix === "" ? "*" : `${prefix}*`;
|
|
47604
|
+
}
|
|
47605
|
+
function toShellEntry(prefix) {
|
|
47606
|
+
return prefix === "" ? SHELL_TOOL_NAME : `${SHELL_TOOL_NAME}(${prefix})`;
|
|
47607
|
+
}
|
|
47608
|
+
/** The `bash` pattern a `run_shell_command(<prefix>)` entry stands for. */
|
|
47609
|
+
function toShellPattern(prefix) {
|
|
47610
|
+
return prefix === void 0 || prefix === "" ? "*" : `${prefix} *`;
|
|
47611
|
+
}
|
|
47612
|
+
/**
|
|
47613
|
+
* Split a `tools.allowed`/`tools.exclude` entry into its tool name and the
|
|
47614
|
+
* optional `(<prefix>)` suffix. An entry whose parenthesis never closes, or
|
|
47615
|
+
* that carries text after the closing one, is malformed and yields `undefined`.
|
|
47616
|
+
*/
|
|
47617
|
+
function parseTabnineEntry(entry) {
|
|
47618
|
+
const open = entry.indexOf("(");
|
|
47619
|
+
if (open === -1) return entry.length > 0 ? {
|
|
47620
|
+
toolName: entry,
|
|
47621
|
+
prefix: void 0
|
|
47622
|
+
} : void 0;
|
|
47623
|
+
if (open === 0 || !entry.endsWith(")")) return;
|
|
47624
|
+
return {
|
|
47625
|
+
toolName: entry.slice(0, open),
|
|
47626
|
+
prefix: entry.slice(open + 1, -1)
|
|
47627
|
+
};
|
|
47628
|
+
}
|
|
47629
|
+
/**
|
|
47630
|
+
* `record` without the value at `path`, when there is one, and without any
|
|
47631
|
+
* container the removal emptied. Containers on the way are copied, never
|
|
47632
|
+
* mutated, so the override the caller read stays intact.
|
|
47633
|
+
*/
|
|
47634
|
+
function omitPath({ record, path }) {
|
|
47635
|
+
const [head, ...rest] = path;
|
|
47636
|
+
if (head === void 0 || !Object.hasOwn(record, head)) return {
|
|
47637
|
+
record,
|
|
47638
|
+
removed: false
|
|
47639
|
+
};
|
|
47640
|
+
if (rest.length === 0) {
|
|
47641
|
+
const { [head]: _removed, ...others } = record;
|
|
47642
|
+
return {
|
|
47643
|
+
record: others,
|
|
47644
|
+
removed: true
|
|
47645
|
+
};
|
|
47646
|
+
}
|
|
47647
|
+
const child = record[head];
|
|
47648
|
+
if (!isRecord$1(child)) return {
|
|
47649
|
+
record,
|
|
47650
|
+
removed: false
|
|
47651
|
+
};
|
|
47652
|
+
const inner = omitPath({
|
|
47653
|
+
record: child,
|
|
47654
|
+
path: rest
|
|
47655
|
+
});
|
|
47656
|
+
if (!inner.removed) return {
|
|
47657
|
+
record,
|
|
47658
|
+
removed: false
|
|
47659
|
+
};
|
|
47660
|
+
if (Object.keys(inner.record).length === 0) {
|
|
47661
|
+
const { [head]: _emptied, ...others } = record;
|
|
47662
|
+
return {
|
|
47663
|
+
record: others,
|
|
47664
|
+
removed: true
|
|
47665
|
+
};
|
|
47666
|
+
}
|
|
47667
|
+
return {
|
|
47668
|
+
record: {
|
|
47669
|
+
...record,
|
|
47670
|
+
[head]: inner.record
|
|
47671
|
+
},
|
|
47672
|
+
removed: true
|
|
47673
|
+
};
|
|
47674
|
+
}
|
|
47675
|
+
/**
|
|
47676
|
+
* The `tabnine.<group>` record with every refused path removed, and the dotted
|
|
47677
|
+
* names of the paths that were there. Nothing else of the group is touched:
|
|
47678
|
+
* the rest is written verbatim (and announced where it widens trust).
|
|
47679
|
+
*/
|
|
47680
|
+
function stripRefusedPaths({ group, record }) {
|
|
47681
|
+
const refused = [];
|
|
47682
|
+
let stripped = record;
|
|
47683
|
+
for (const path of REFUSED_OVERRIDE_PATHS[group]) {
|
|
47684
|
+
const result = omitPath({
|
|
47685
|
+
record: stripped,
|
|
47686
|
+
path
|
|
47687
|
+
});
|
|
47688
|
+
if (result.removed) {
|
|
47689
|
+
refused.push(`${group}.${path.join(".")}`);
|
|
47690
|
+
stripped = result.record;
|
|
47691
|
+
}
|
|
47692
|
+
}
|
|
47693
|
+
return {
|
|
47694
|
+
record: stripped,
|
|
47695
|
+
refused
|
|
47696
|
+
};
|
|
47697
|
+
}
|
|
47698
|
+
/**
|
|
47699
|
+
* The `tools` and `general` groups of an override with the refused paths taken
|
|
47700
|
+
* out, and every refused path named. A `general` that is absent or that the
|
|
47701
|
+
* refusals emptied is reported as absent so no `general: {}` is written or
|
|
47702
|
+
* lifted. (The `TabninePermissionsOverrideSchema` already rejects a group that
|
|
47703
|
+
* is not an object; the `isRecord` guards only keep an unvalidated file from
|
|
47704
|
+
* throwing.)
|
|
47705
|
+
*/
|
|
47706
|
+
function stripRefusedOverridePaths(override) {
|
|
47707
|
+
const tools = stripRefusedPaths({
|
|
47708
|
+
group: TOOLS_KEY,
|
|
47709
|
+
record: isRecord$1(override[TOOLS_KEY]) ? override[TOOLS_KEY] : {}
|
|
47710
|
+
});
|
|
47711
|
+
const general = isRecord$1(override[GENERAL_KEY]) ? stripRefusedPaths({
|
|
47712
|
+
group: GENERAL_KEY,
|
|
47713
|
+
record: override[GENERAL_KEY]
|
|
47714
|
+
}) : void 0;
|
|
47715
|
+
return {
|
|
47716
|
+
tools: tools.record,
|
|
47717
|
+
general: general !== void 0 && Object.keys(general.record).length > 0 ? general.record : void 0,
|
|
47718
|
+
refused: [...tools.refused, ...general?.refused ?? []]
|
|
47719
|
+
};
|
|
47720
|
+
}
|
|
47721
|
+
/**
|
|
47722
|
+
* The settings of a `tabnine` override that widen what Tabnine CLI does without
|
|
47723
|
+
* asking, so the generate can name them. `tools.allowed` counts because an
|
|
47724
|
+
* override-authored entry skips the confirmation prompt on the strength of the
|
|
47725
|
+
* override alone (its `run_shell_command(...)` entries are not here: they are
|
|
47726
|
+
* compared as `bash` allows and withheld like them); `tools.sandbox` and
|
|
47727
|
+
* `general.defaultApprovalMode` decide whether tool calls are contained and
|
|
47728
|
+
* whether they are confirmed at all. Called on the override, not the file, so a
|
|
47729
|
+
* value the file already held is not reported as something rulesync opened.
|
|
47730
|
+
*/
|
|
47731
|
+
function collectTrustAffectingOverrideEntries({ tools, general }) {
|
|
47732
|
+
const entries = [];
|
|
47733
|
+
const allowed = isStringArray$2(tools[ALLOWED_KEY]) ? tools[ALLOWED_KEY] : [];
|
|
47734
|
+
if (allowed.length > 0) entries.push({
|
|
47735
|
+
label: `tools.allowed (${allowed.map(quoteValueForWarning).join(", ")})`,
|
|
47736
|
+
reason: "auto-approves what it names as the override spells it; a non-shell entry has no canonical rule to be checked against"
|
|
47737
|
+
});
|
|
47738
|
+
if (Object.hasOwn(tools, SANDBOX_KEY) && isNotTrue(tools[SANDBOX_KEY])) entries.push({
|
|
47739
|
+
label: `tools.sandbox = ${quoteValueForWarning(tools[SANDBOX_KEY])}`,
|
|
47740
|
+
reason: "is not the plain `true` that keeps tool calls contained, so it either disables the sandbox or picks the command, image, paths and network that contain them"
|
|
47741
|
+
});
|
|
47742
|
+
const approvalMode = general?.[DEFAULT_APPROVAL_MODE_KEY];
|
|
47743
|
+
if (general !== void 0 && Object.hasOwn(general, DEFAULT_APPROVAL_MODE_KEY) && !PROMPTING_APPROVAL_MODES.has(approvalMode)) entries.push({
|
|
47744
|
+
label: `general.defaultApprovalMode = ${quoteValueForWarning(approvalMode)}`,
|
|
47745
|
+
reason: "auto-approves tool calls instead of asking; only `default` and `plan` keep the prompt"
|
|
47746
|
+
});
|
|
47747
|
+
return entries;
|
|
47748
|
+
}
|
|
47749
|
+
/**
|
|
47750
|
+
* What a later generate would announce from the override an import builds,
|
|
47751
|
+
* said now, so the file the import writes into `.rulesync/` is read with the
|
|
47752
|
+
* same eyes as one that arrived with a clone. `refused` names the paths the
|
|
47753
|
+
* import left in `settings.json`, the ones generate refuses to write — an
|
|
47754
|
+
* override must not carry a value that only ever produces a warning.
|
|
47755
|
+
*/
|
|
47756
|
+
function announceLiftedOverride({ tools, general, refused }) {
|
|
47757
|
+
if (refused.length > 0) {
|
|
47758
|
+
const one = refused.length === 1;
|
|
47759
|
+
moduleLogger$1.info(`Tabnine CLI permissions: left ${refused.join(", ")} in settings.json rather than lifting ${one ? "it" : "them"} into the tabnine override; Tabnine CLI runs ${one ? "that value" : "those values"} as a command or sends its traffic there, and 'rulesync generate' refuses to write ${one ? "it" : "them"} from the override.`);
|
|
47760
|
+
}
|
|
47761
|
+
const trustAffecting = collectTrustAffectingOverrideEntries({
|
|
47762
|
+
tools,
|
|
47763
|
+
general
|
|
47764
|
+
});
|
|
47765
|
+
if (trustAffecting.length > 0) {
|
|
47766
|
+
const one = trustAffecting.length === 1;
|
|
47767
|
+
moduleLogger$1.warn(`Tabnine CLI permissions: the tabnine override now carries ${trustAffecting.length} trust-affecting setting${one ? "" : "s"} that 'rulesync generate' writes back as authored: ${formatTrustAffectingEntries(trustAffecting)}.`);
|
|
47768
|
+
}
|
|
47769
|
+
}
|
|
47770
|
+
/**
|
|
47771
|
+
* Build the two tool lists from the canonical block; the rules that could not
|
|
47772
|
+
* be carried are reported through `logger` here.
|
|
47773
|
+
*/
|
|
47774
|
+
function buildToolLists({ permission, overrideShellAllowPatterns, logger }) {
|
|
47775
|
+
const allowed = [];
|
|
47776
|
+
const exclude = [];
|
|
47777
|
+
const { rules: canonicalRules, ignoredAllToolsAllowPatterns } = collectShellCommandRules(permission);
|
|
47778
|
+
const { allow: shellAllow, deny: shellDeny, shadowedAllowPatterns, unwrittenDenyPatterns, unenforcedAllToolsAskPatterns, intersectionBudgetExhausted } = partitionCommandRules({
|
|
47779
|
+
rules: [...canonicalRules, ...overrideShellAllowPatterns.map((pattern) => ({
|
|
47780
|
+
pattern,
|
|
47781
|
+
action: "allow",
|
|
47782
|
+
fromAllToolsCategory: false
|
|
47783
|
+
}))],
|
|
47784
|
+
writesAllToolsDeny: false,
|
|
47785
|
+
normalizePattern: widenToPrefixGlob
|
|
47786
|
+
});
|
|
47787
|
+
warnAboutUnwrittenCommandRules({
|
|
47788
|
+
toolLabel: "Tabnine CLI",
|
|
47789
|
+
surfaceLabel: "tools.allowed/tools.exclude",
|
|
47790
|
+
foreignRestrictingCategories: [],
|
|
47791
|
+
shadowedAllowPatterns,
|
|
47792
|
+
unwrittenDenyPatterns,
|
|
47793
|
+
unwrittenDenyReason: "tools.exclude removes a tool from discovery, and a pattern written under '*' need not be a command at all.",
|
|
47794
|
+
unenforcedAllToolsAskPatterns,
|
|
47795
|
+
ignoredAllToolsAllowPatterns,
|
|
47796
|
+
intersectionBudgetExhausted,
|
|
47797
|
+
logger
|
|
47798
|
+
});
|
|
47799
|
+
const unmappedShellPatterns = [];
|
|
47800
|
+
for (const pattern of shellDeny) {
|
|
47801
|
+
const prefix = toShellPrefix(pattern);
|
|
47802
|
+
if (prefix === void 0) {
|
|
47803
|
+
unmappedShellPatterns.push(pattern);
|
|
47804
|
+
continue;
|
|
47805
|
+
}
|
|
47806
|
+
exclude.push(toShellEntry(prefix));
|
|
47807
|
+
}
|
|
47808
|
+
const shadowingShellDenies = createShadowingRestrictionsTest(shellDeny.map((pattern) => ({
|
|
47809
|
+
pattern,
|
|
47810
|
+
fromAllToolsCategory: false
|
|
47811
|
+
})), { normalizePattern: widenToPrefixGlob });
|
|
47812
|
+
const withheldAllowPatterns = [];
|
|
47813
|
+
for (const pattern of shellAllow) {
|
|
47814
|
+
const prefix = toShellPrefix(pattern);
|
|
47815
|
+
if (prefix === void 0) {
|
|
47816
|
+
unmappedShellPatterns.push(pattern);
|
|
47817
|
+
continue;
|
|
47818
|
+
}
|
|
47819
|
+
if (shadowingShellDenies(pattern).length > 0) {
|
|
47820
|
+
withheldAllowPatterns.push(pattern);
|
|
47821
|
+
continue;
|
|
47822
|
+
}
|
|
47823
|
+
allowed.push(toShellEntry(prefix));
|
|
47824
|
+
}
|
|
47825
|
+
if (unmappedShellPatterns.length > 0) warnWithFallback(logger, `Tabnine CLI permissions: skipped ${unmappedShellPatterns.length} 'bash' rule(s) whose pattern is not a command prefix (${unmappedShellPatterns.map(quoteValueForWarning).join(", ")}). run_shell_command(<prefix>) matches the start of the command line, so only '<prefix> *' and a bare '<prefix>' can be written.`);
|
|
47826
|
+
if (withheldAllowPatterns.length > 0) warnWithFallback(logger, `Tabnine CLI permissions: withheld ${withheldAllowPatterns.length} 'bash' allow rule(s) (${withheldAllowPatterns.map(quoteValueForWarning).join(", ")}) that overlap a 'bash' deny rule; writing them could auto-approve the denied commands, since tools.exclude is not documented to narrow run_shell_command to a prefix.`);
|
|
47827
|
+
const unmappedPatterns = [];
|
|
47828
|
+
for (const [category, categoryRules] of Object.entries(permission)) {
|
|
47829
|
+
if (category === "bash" || category === "*") continue;
|
|
47830
|
+
const toolName = toTabnineToolName(category);
|
|
47831
|
+
for (const [pattern, action] of Object.entries(categoryRules)) {
|
|
47832
|
+
if (pattern !== "*") {
|
|
47833
|
+
unmappedPatterns.push(`${category}: ${pattern}`);
|
|
47834
|
+
continue;
|
|
47835
|
+
}
|
|
47836
|
+
if (action === "allow") allowed.push(toolName);
|
|
47837
|
+
else if (action === "deny") exclude.push(toolName);
|
|
47838
|
+
}
|
|
47839
|
+
}
|
|
47840
|
+
if (unmappedPatterns.length > 0) warnWithFallback(logger, `Tabnine CLI permissions: skipped ${unmappedPatterns.length} rule(s) with a pattern other than '*' (${unmappedPatterns.map(quoteValueForWarning).join(", ")}). tools.allowed/tools.exclude name whole tools; only run_shell_command takes a prefix.`);
|
|
47841
|
+
return {
|
|
47842
|
+
allowed: (0, es_toolkit.uniq)(allowed),
|
|
47843
|
+
exclude: (0, es_toolkit.uniq)(exclude)
|
|
47844
|
+
};
|
|
47845
|
+
}
|
|
47846
|
+
/**
|
|
47847
|
+
* Permissions generator for the Tabnine CLI.
|
|
47848
|
+
*
|
|
47849
|
+
* Tabnine CLI keeps its tool policy in `.tabnine/agent/settings.json` (project)
|
|
47850
|
+
* and `~/.tabnine/agent/settings.json` (user), a shared file that also carries
|
|
47851
|
+
* `mcpServers`, `hooks`, `general.*`, `context.*` and more, so writes go through
|
|
47852
|
+
* the shared-config gateway as a deep merge and the file is never deleted.
|
|
47853
|
+
*
|
|
47854
|
+
* Two keys are driven by the canonical block:
|
|
47855
|
+
* - `tools.allowed` — `allow` rules. A tool name skips the confirmation prompt;
|
|
47856
|
+
* `run_shell_command(<prefix>)` narrows that to one command prefix.
|
|
47857
|
+
* - `tools.exclude` — `deny` rules. A tool name removes the tool from discovery.
|
|
47858
|
+
* A `bash` deny is written as `run_shell_command(<prefix>)` there, the form
|
|
47859
|
+
* Gemini CLI's `excludeTools` (which Tabnine derives from) honors, but Tabnine
|
|
47860
|
+
* documents the prefix for `tools.allowed` only — so the entry is not relied
|
|
47861
|
+
* on, and every allow the deny overlaps is withheld as well.
|
|
47862
|
+
*
|
|
47863
|
+
* `ask` writes nothing: a tool that is in neither list keeps Tabnine's default
|
|
47864
|
+
* prompt. Every other `tools.*` key (`core`, `shell.*`, `enableWebTools`, ...)
|
|
47865
|
+
* and the `general.*` group are authored through the `tabnine` override, which
|
|
47866
|
+
* is deep-merged beneath the two canonical lists; entries in the lists that
|
|
47867
|
+
* cannot be mapped back (a prefix on a non-shell tool, an MCP tool name) round
|
|
47868
|
+
* trip through the override too.
|
|
47869
|
+
*
|
|
47870
|
+
* @see https://docs.tabnine.com/main/getting-started/tabnine-cli/features/built-in-tools
|
|
47871
|
+
* @see https://docs.tabnine.com/main/getting-started/tabnine-cli/features/settings/settings-reference
|
|
47872
|
+
*/
|
|
47873
|
+
var TabninePermissions = class TabninePermissions extends ToolPermissions {
|
|
47874
|
+
constructor(params) {
|
|
47875
|
+
super({
|
|
47876
|
+
...params,
|
|
47877
|
+
fileContent: params.fileContent ?? "{}"
|
|
47878
|
+
});
|
|
47879
|
+
}
|
|
47880
|
+
/**
|
|
47881
|
+
* `settings.json` holds unrelated user settings (`mcpServers`, `hooks`,
|
|
47882
|
+
* `general`, ...), so it must not be deleted.
|
|
47883
|
+
*/
|
|
47884
|
+
isDeletable() {
|
|
47885
|
+
return false;
|
|
47886
|
+
}
|
|
47887
|
+
static getSettablePaths(_options = {}) {
|
|
47888
|
+
return {
|
|
47889
|
+
relativeDirPath: TABNINE_AGENT_DIR_PATH,
|
|
47890
|
+
relativeFilePath: TABNINE_SETTINGS_FILE_NAME
|
|
47891
|
+
};
|
|
47892
|
+
}
|
|
47893
|
+
static async fromFile({ outputRoot = process.cwd(), validate = true, global = false }) {
|
|
47894
|
+
const paths = TabninePermissions.getSettablePaths({ global });
|
|
47895
|
+
const fileContent = await readFileContentOrNull((0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath)) ?? "{}";
|
|
47896
|
+
return new TabninePermissions({
|
|
47897
|
+
outputRoot,
|
|
47898
|
+
relativeDirPath: paths.relativeDirPath,
|
|
47899
|
+
relativeFilePath: paths.relativeFilePath,
|
|
47900
|
+
fileContent,
|
|
47901
|
+
validate,
|
|
47902
|
+
global
|
|
47903
|
+
});
|
|
47904
|
+
}
|
|
47905
|
+
static async fromRulesyncPermissions({ outputRoot = process.cwd(), rulesyncPermissions, global = false, logger }) {
|
|
47906
|
+
const paths = TabninePermissions.getSettablePaths({ global });
|
|
47907
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
47908
|
+
const existingContent = await readFileContentOrNull(filePath) ?? "{}";
|
|
47909
|
+
const config = rulesyncPermissions.getJson();
|
|
47910
|
+
const override = isRecord$1(config.tabnine) ? config.tabnine : {};
|
|
47911
|
+
const { tools: overrideTools, general: overrideGeneral, refused: refusedPaths } = stripRefusedOverridePaths(override);
|
|
47912
|
+
if (refusedPaths.length > 0) warnWithFallback(logger, `Tabnine CLI permissions: refused to write ${refusedPaths.join(", ")} from the tabnine override; Tabnine CLI runs that value as a command or sends its traffic to it, and a permissions file (one that came from 'rulesync fetch' included) must not be able to point it at an executable or a server of its choosing. Set it by hand in ${(0, node_path.join)(paths.relativeDirPath, paths.relativeFilePath)} if you need it.`);
|
|
47913
|
+
const overrideList = (key) => {
|
|
47914
|
+
const value = overrideTools[key];
|
|
47915
|
+
if (value === void 0 || isStringArray$2(value)) return value ?? [];
|
|
47916
|
+
warnWithFallback(logger, `Tabnine CLI permissions: ignored tools.${key} of the tabnine override (${quoteValueForWarning(value)}); it must be a list of tool names.`);
|
|
47917
|
+
return [];
|
|
47918
|
+
};
|
|
47919
|
+
const overrideShellAllowPatterns = [];
|
|
47920
|
+
const overrideVerbatimAllowed = [];
|
|
47921
|
+
for (const entry of overrideList(ALLOWED_KEY)) {
|
|
47922
|
+
const parsed = parseTabnineEntry(entry);
|
|
47923
|
+
if (parsed?.toolName === SHELL_TOOL_NAME) overrideShellAllowPatterns.push(toShellPattern(parsed.prefix));
|
|
47924
|
+
else overrideVerbatimAllowed.push(entry);
|
|
47925
|
+
}
|
|
47926
|
+
const overrideExclude = overrideList(EXCLUDE_KEY);
|
|
47927
|
+
const { allowed, exclude } = buildToolLists({
|
|
47928
|
+
permission: config.permission,
|
|
47929
|
+
overrideShellAllowPatterns,
|
|
47930
|
+
logger
|
|
47931
|
+
});
|
|
47932
|
+
const ignoredOverrideKeys = Object.keys(override).filter((key) => key !== TOOLS_KEY && key !== GENERAL_KEY);
|
|
47933
|
+
if (ignoredOverrideKeys.length > 0) warnWithFallback(logger, `Tabnine CLI permissions: ignored ${ignoredOverrideKeys.length} key(s) of the tabnine override (${ignoredOverrideKeys.map(quoteValueForWarning).join(", ")}); only 'tools' and 'general' are written through the permissions feature.`);
|
|
47934
|
+
const existingTools = this.existingToolsGroup(existingContent);
|
|
47935
|
+
const managedToolNames = new Set(Object.keys(config.permission).map((category) => category === "bash" || category === "*" ? SHELL_TOOL_NAME : toTabnineToolName(category)));
|
|
47936
|
+
const preservedEntries = (key) => (isStringArray$2(existingTools?.[key]) ? existingTools[key] : []).filter((entry) => {
|
|
47937
|
+
const toolName = parseTabnineEntry(entry)?.toolName;
|
|
47938
|
+
return toolName === void 0 || !managedToolNames.has(toolName);
|
|
47939
|
+
});
|
|
47940
|
+
const allowedList = (0, es_toolkit.uniq)([
|
|
47941
|
+
...allowed,
|
|
47942
|
+
...overrideVerbatimAllowed,
|
|
47943
|
+
...preservedEntries(ALLOWED_KEY)
|
|
47944
|
+
]);
|
|
47945
|
+
const excludeList = (0, es_toolkit.uniq)([
|
|
47946
|
+
...exclude,
|
|
47947
|
+
...overrideExclude,
|
|
47948
|
+
...preservedEntries(EXCLUDE_KEY)
|
|
47949
|
+
]);
|
|
47950
|
+
const droppedExcludeEntries = (0, es_toolkit.uniq)(isStringArray$2(existingTools?.[EXCLUDE_KEY]) ? existingTools[EXCLUDE_KEY] : []).filter((entry) => {
|
|
47951
|
+
if (excludeList.includes(entry)) return false;
|
|
47952
|
+
const toolName = parseTabnineEntry(entry)?.toolName;
|
|
47953
|
+
return toolName === void 0 || !excludeList.includes(toolName);
|
|
47954
|
+
});
|
|
47955
|
+
if (droppedExcludeEntries.length > 0) warnWithFallback(logger, `Tabnine CLI permissions: removed ${droppedExcludeEntries.length} existing tools.exclude entry(ies) (${droppedExcludeEntries.map(quoteValueForWarning).join(", ")}) of a tool the canonical block manages; add a deny rule to .rulesync/permissions.jsonc to keep them.`);
|
|
47956
|
+
const tools = {
|
|
47957
|
+
...overrideTools,
|
|
47958
|
+
[ALLOWED_KEY]: allowedList.length > 0 ? allowedList : void 0,
|
|
47959
|
+
[EXCLUDE_KEY]: excludeList.length > 0 ? excludeList : void 0
|
|
47960
|
+
};
|
|
47961
|
+
const patch = {};
|
|
47962
|
+
if (overrideGeneral !== void 0) patch[GENERAL_KEY] = overrideGeneral;
|
|
47963
|
+
if (Object.values(tools).some((value) => value !== void 0) || existingTools !== void 0) patch[TOOLS_KEY] = tools;
|
|
47964
|
+
warnOnTrustAffectingEntries({
|
|
47965
|
+
toolLabel: "Tabnine CLI",
|
|
47966
|
+
entries: collectTrustAffectingOverrideEntries({
|
|
47967
|
+
tools: {
|
|
47968
|
+
...overrideTools,
|
|
47969
|
+
[ALLOWED_KEY]: overrideVerbatimAllowed
|
|
47970
|
+
},
|
|
47971
|
+
general: overrideGeneral
|
|
47972
|
+
}),
|
|
47973
|
+
relativeFilePath: (0, node_path.join)(paths.relativeDirPath, paths.relativeFilePath),
|
|
47974
|
+
logger
|
|
47975
|
+
});
|
|
47976
|
+
return new TabninePermissions({
|
|
47977
|
+
outputRoot,
|
|
47978
|
+
relativeDirPath: paths.relativeDirPath,
|
|
47979
|
+
relativeFilePath: paths.relativeFilePath,
|
|
47980
|
+
fileContent: applySharedConfigPatch({
|
|
47981
|
+
fileKey: sharedConfigFileKey(paths),
|
|
47982
|
+
feature: "permissions",
|
|
47983
|
+
existingContent,
|
|
47984
|
+
patch,
|
|
47985
|
+
filePath
|
|
47986
|
+
}),
|
|
47987
|
+
validate: true,
|
|
47988
|
+
global
|
|
47989
|
+
});
|
|
47990
|
+
}
|
|
47991
|
+
/** The `tools` group of the existing file, or `undefined` when it has none. */
|
|
47992
|
+
static existingToolsGroup(existingContent) {
|
|
47993
|
+
try {
|
|
47994
|
+
const existing = parseSharedConfig({
|
|
47995
|
+
format: "json",
|
|
47996
|
+
fileContent: existingContent || "{}",
|
|
47997
|
+
invalidRootPolicy: "error"
|
|
47998
|
+
});
|
|
47999
|
+
return isRecord$1(existing[TOOLS_KEY]) ? existing[TOOLS_KEY] : void 0;
|
|
48000
|
+
} catch {
|
|
48001
|
+
return;
|
|
48002
|
+
}
|
|
48003
|
+
}
|
|
48004
|
+
toRulesyncPermissions() {
|
|
48005
|
+
const settings = this.parseSettings();
|
|
48006
|
+
const tools = isRecord$1(settings[TOOLS_KEY]) ? settings[TOOLS_KEY] : {};
|
|
48007
|
+
const permission = {};
|
|
48008
|
+
const leftovers = {};
|
|
48009
|
+
const setRule = (category, pattern, action) => {
|
|
48010
|
+
const rules = Object.hasOwn(permission, category) ? permission[category] : permission[category] = {};
|
|
48011
|
+
if (rules !== void 0 && !Object.hasOwn(rules, pattern)) rules[pattern] = action;
|
|
48012
|
+
};
|
|
48013
|
+
for (const [key, action] of [[EXCLUDE_KEY, "deny"], [ALLOWED_KEY, "allow"]]) {
|
|
48014
|
+
const entries = isStringArray$2(tools[key]) ? tools[key] : [];
|
|
48015
|
+
for (const entry of entries) {
|
|
48016
|
+
const parsed = parseTabnineEntry(entry);
|
|
48017
|
+
if (parsed === void 0) {
|
|
48018
|
+
moduleLogger$1.warn(`Tabnine CLI permissions: kept malformed tools.${key} entry ${quoteValueForWarning(entry)} in the tabnine override.`);
|
|
48019
|
+
(leftovers[key] ??= []).push(entry);
|
|
48020
|
+
continue;
|
|
48021
|
+
}
|
|
48022
|
+
const { toolName, prefix } = parsed;
|
|
48023
|
+
if (toolName === SHELL_TOOL_NAME) {
|
|
48024
|
+
setRule(SHELL_PERMISSION_CATEGORY, toShellPattern(prefix), action);
|
|
48025
|
+
continue;
|
|
48026
|
+
}
|
|
48027
|
+
if (prefix !== void 0) {
|
|
48028
|
+
(leftovers[key] ??= []).push(entry);
|
|
48029
|
+
continue;
|
|
48030
|
+
}
|
|
48031
|
+
const category = lookupOwn({
|
|
48032
|
+
record: TABNINE_TO_CANONICAL_TOOL_NAMES,
|
|
48033
|
+
key: toolName
|
|
48034
|
+
}) ?? toolName;
|
|
48035
|
+
if (isPrototypePollutionKey(category)) {
|
|
48036
|
+
moduleLogger$1.warn(`Tabnine CLI permissions: kept tools.${key} entry ${quoteValueForWarning(entry)} in the tabnine override; its name cannot be a permission category.`);
|
|
48037
|
+
(leftovers[key] ??= []).push(entry);
|
|
48038
|
+
continue;
|
|
48039
|
+
}
|
|
48040
|
+
setRule(category, "*", action);
|
|
48041
|
+
}
|
|
48042
|
+
}
|
|
48043
|
+
const { tools: overrideTools, general, refused } = stripRefusedOverridePaths({
|
|
48044
|
+
[TOOLS_KEY]: Object.fromEntries(Object.entries(tools).filter(([key]) => key !== ALLOWED_KEY && key !== EXCLUDE_KEY)),
|
|
48045
|
+
[GENERAL_KEY]: settings[GENERAL_KEY]
|
|
48046
|
+
});
|
|
48047
|
+
for (const [key, entries] of Object.entries(leftovers)) overrideTools[key] = entries;
|
|
48048
|
+
const override = {};
|
|
48049
|
+
if (Object.keys(overrideTools).length > 0) override[TOOLS_KEY] = overrideTools;
|
|
48050
|
+
if (general !== void 0) override[GENERAL_KEY] = general;
|
|
48051
|
+
announceLiftedOverride({
|
|
48052
|
+
tools: overrideTools,
|
|
48053
|
+
general,
|
|
48054
|
+
refused
|
|
48055
|
+
});
|
|
48056
|
+
const imported = { permission };
|
|
48057
|
+
if (Object.keys(override).length > 0) imported.tabnine = override;
|
|
48058
|
+
return this.toRulesyncPermissionsDefault({ fileContent: JSON.stringify(imported, null, 2) });
|
|
48059
|
+
}
|
|
48060
|
+
parseSettings() {
|
|
48061
|
+
const relativePath = (0, node_path.join)(this.getRelativeDirPath(), this.getRelativeFilePath());
|
|
48062
|
+
try {
|
|
48063
|
+
return parseSharedConfig({
|
|
48064
|
+
format: "json",
|
|
48065
|
+
fileContent: this.getFileContent() || "{}",
|
|
48066
|
+
filePath: relativePath,
|
|
48067
|
+
invalidRootPolicy: "error"
|
|
48068
|
+
});
|
|
48069
|
+
} catch (error) {
|
|
48070
|
+
throw new Error(`Failed to parse Tabnine CLI settings in ${relativePath}: ${formatError(error)}`, { cause: error });
|
|
48071
|
+
}
|
|
48072
|
+
}
|
|
48073
|
+
validate() {
|
|
48074
|
+
return {
|
|
48075
|
+
success: true,
|
|
48076
|
+
error: null
|
|
48077
|
+
};
|
|
48078
|
+
}
|
|
48079
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
|
|
48080
|
+
return new TabninePermissions({
|
|
48081
|
+
outputRoot,
|
|
48082
|
+
relativeDirPath,
|
|
48083
|
+
relativeFilePath,
|
|
48084
|
+
fileContent: "{}",
|
|
48085
|
+
validate: false,
|
|
48086
|
+
global
|
|
48087
|
+
});
|
|
48088
|
+
}
|
|
48089
|
+
};
|
|
48090
|
+
//#endregion
|
|
45577
48091
|
//#region src/features/permissions/takt-permissions.ts
|
|
45578
48092
|
const TAKT_PROVIDER_KEY = "provider";
|
|
45579
48093
|
const TAKT_PROVIDER_PROFILES_KEY = "provider_profiles";
|
|
@@ -48953,6 +51467,14 @@ const toolPermissionsFactories = /* @__PURE__ */ new Map([
|
|
|
48953
51467
|
supportsImport: true
|
|
48954
51468
|
}
|
|
48955
51469
|
}],
|
|
51470
|
+
["tabnine", {
|
|
51471
|
+
class: TabninePermissions,
|
|
51472
|
+
meta: {
|
|
51473
|
+
supportsProject: true,
|
|
51474
|
+
supportsGlobal: true,
|
|
51475
|
+
supportsImport: true
|
|
51476
|
+
}
|
|
51477
|
+
}],
|
|
48956
51478
|
["takt", {
|
|
48957
51479
|
class: TaktPermissions,
|
|
48958
51480
|
meta: {
|
|
@@ -50250,16 +52772,198 @@ var AntigravitySharedSkill = class extends ToolSkill {
|
|
|
50250
52772
|
}
|
|
50251
52773
|
static fromRulesyncSkill({ outputRoot = process.cwd(), rulesyncSkill, validate = true, global = false }) {
|
|
50252
52774
|
const rulesyncFrontmatter = rulesyncSkill.getFrontmatter();
|
|
50253
|
-
const antigravityFrontmatter = {
|
|
52775
|
+
const antigravityFrontmatter = {
|
|
52776
|
+
name: rulesyncFrontmatter.name,
|
|
52777
|
+
description: rulesyncFrontmatter.description
|
|
52778
|
+
};
|
|
52779
|
+
const settablePaths = this.getSettablePaths({ global });
|
|
52780
|
+
return new this({
|
|
52781
|
+
outputRoot,
|
|
52782
|
+
relativeDirPath: settablePaths.relativeDirPath,
|
|
52783
|
+
dirName: rulesyncSkill.getDirName(),
|
|
52784
|
+
frontmatter: antigravityFrontmatter,
|
|
52785
|
+
body: rulesyncSkill.getBody(),
|
|
52786
|
+
otherFiles: rulesyncSkill.getOtherFiles(),
|
|
52787
|
+
validate,
|
|
52788
|
+
global
|
|
52789
|
+
});
|
|
52790
|
+
}
|
|
52791
|
+
static isTargetedByRulesyncSkill(rulesyncSkill) {
|
|
52792
|
+
const targets = rulesyncSkill.getFrontmatter().targets;
|
|
52793
|
+
return targets.includes("*") || targets.includes(this.getToolTarget());
|
|
52794
|
+
}
|
|
52795
|
+
static async fromDir(params) {
|
|
52796
|
+
const loaded = await this.loadSkillDirContent({
|
|
52797
|
+
...params,
|
|
52798
|
+
getSettablePaths: (options) => this.getSettablePaths(options)
|
|
52799
|
+
});
|
|
52800
|
+
const result = AntigravitySkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
52801
|
+
if (!result.success) {
|
|
52802
|
+
const skillDirPath = (0, node_path.join)(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
52803
|
+
throw new Error(`Invalid frontmatter in ${(0, node_path.join)(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
52804
|
+
}
|
|
52805
|
+
return new this({
|
|
52806
|
+
outputRoot: loaded.outputRoot,
|
|
52807
|
+
relativeDirPath: loaded.relativeDirPath,
|
|
52808
|
+
dirName: loaded.dirName,
|
|
52809
|
+
frontmatter: result.data,
|
|
52810
|
+
body: loaded.body,
|
|
52811
|
+
otherFiles: loaded.otherFiles,
|
|
52812
|
+
validate: true,
|
|
52813
|
+
global: loaded.global
|
|
52814
|
+
});
|
|
52815
|
+
}
|
|
52816
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, dirName, global = false }) {
|
|
52817
|
+
return new this({
|
|
52818
|
+
outputRoot,
|
|
52819
|
+
relativeDirPath,
|
|
52820
|
+
dirName,
|
|
52821
|
+
frontmatter: {
|
|
52822
|
+
name: "",
|
|
52823
|
+
description: ""
|
|
52824
|
+
},
|
|
52825
|
+
body: "",
|
|
52826
|
+
otherFiles: [],
|
|
52827
|
+
validate: false,
|
|
52828
|
+
global
|
|
52829
|
+
});
|
|
52830
|
+
}
|
|
52831
|
+
};
|
|
52832
|
+
//#endregion
|
|
52833
|
+
//#region src/features/skills/antigravity-cli-skill.ts
|
|
52834
|
+
/**
|
|
52835
|
+
* Represents a Google Antigravity CLI skill directory (Antigravity 2.0).
|
|
52836
|
+
*
|
|
52837
|
+
* Shares all behavior with {@link AntigravitySharedSkill}; the CLI keeps its
|
|
52838
|
+
* own global skills tree at `~/.gemini/antigravity-cli/skills/` and answers to
|
|
52839
|
+
* the `antigravity-cli` target.
|
|
52840
|
+
*/
|
|
52841
|
+
var AntigravityCliSkill = class extends AntigravitySharedSkill {
|
|
52842
|
+
static getGlobalSubdir() {
|
|
52843
|
+
return ANTIGRAVITY_CLI_PERMISSIONS_SUBDIR;
|
|
52844
|
+
}
|
|
52845
|
+
static getToolTarget() {
|
|
52846
|
+
return "antigravity-cli";
|
|
52847
|
+
}
|
|
52848
|
+
};
|
|
52849
|
+
//#endregion
|
|
52850
|
+
//#region src/features/skills/antigravity-ide-skill.ts
|
|
52851
|
+
/**
|
|
52852
|
+
* Represents a Google Antigravity IDE skill directory (Antigravity 2.0).
|
|
52853
|
+
*
|
|
52854
|
+
* Shares all behavior with {@link AntigravitySharedSkill}. As of Antigravity
|
|
52855
|
+
* 2.0 the IDE reads its global skills from the shared `~/.gemini/config/skills/`
|
|
52856
|
+
* location (the Skills doc lists `~/.gemini/config/skills/<skill-folder>/` as
|
|
52857
|
+
* the global scope); the legacy `~/.gemini/antigravity/skills/` path is no
|
|
52858
|
+
* longer used. It answers to the `antigravity-ide` target.
|
|
52859
|
+
*/
|
|
52860
|
+
var AntigravityIdeSkill = class extends AntigravitySharedSkill {
|
|
52861
|
+
static getGlobalSubdir() {
|
|
52862
|
+
return ANTIGRAVITY_IDE_GLOBAL_CONFIG_SUBDIR;
|
|
52863
|
+
}
|
|
52864
|
+
static getToolTarget() {
|
|
52865
|
+
return "antigravity-ide";
|
|
52866
|
+
}
|
|
52867
|
+
};
|
|
52868
|
+
//#endregion
|
|
52869
|
+
//#region src/features/skills/antigravity-plugin-skill.ts
|
|
52870
|
+
var AntigravityPluginSkill = class extends AntigravityIdeSkill {
|
|
52871
|
+
static isTargetedByRulesyncSkill(rulesyncSkill) {
|
|
52872
|
+
const targets = rulesyncSkill.getFrontmatter().targets;
|
|
52873
|
+
return targets.includes("*") || targets.includes("antigravity-plugin");
|
|
52874
|
+
}
|
|
52875
|
+
static getSettablePaths() {
|
|
52876
|
+
return { relativeDirPath: ANTIGRAVITY_PLUGIN_SKILLS_DIR };
|
|
52877
|
+
}
|
|
52878
|
+
};
|
|
52879
|
+
//#endregion
|
|
52880
|
+
//#region src/features/skills/augmentcode-skill.ts
|
|
52881
|
+
const AugmentcodeSkillFrontmatterSchema = zod_mini.z.looseObject({
|
|
52882
|
+
name: zod_mini.z.string(),
|
|
52883
|
+
description: zod_mini.z.string()
|
|
52884
|
+
});
|
|
52885
|
+
/**
|
|
52886
|
+
* Represents an AugmentCode (Auggie CLI) skill directory.
|
|
52887
|
+
* Auggie has native skill support — it reads `<name>/SKILL.md` directories under
|
|
52888
|
+
* `.augment/skills/` (project) and `~/.augment/skills/` (global).
|
|
52889
|
+
* See https://docs.augmentcode.com/cli/skills
|
|
52890
|
+
*/
|
|
52891
|
+
var AugmentcodeSkill = class AugmentcodeSkill extends ToolSkill {
|
|
52892
|
+
constructor({ outputRoot = process.cwd(), relativeDirPath = AugmentcodeSkill.getSettablePaths().relativeDirPath, dirName, frontmatter, body, otherFiles = [], validate = true, global = false }) {
|
|
52893
|
+
super({
|
|
52894
|
+
outputRoot,
|
|
52895
|
+
relativeDirPath,
|
|
52896
|
+
dirName,
|
|
52897
|
+
mainFile: {
|
|
52898
|
+
name: SKILL_FILE_NAME,
|
|
52899
|
+
body,
|
|
52900
|
+
frontmatter: { ...frontmatter }
|
|
52901
|
+
},
|
|
52902
|
+
otherFiles,
|
|
52903
|
+
global
|
|
52904
|
+
});
|
|
52905
|
+
if (validate) {
|
|
52906
|
+
const result = this.validate();
|
|
52907
|
+
if (!result.success) throw result.error;
|
|
52908
|
+
}
|
|
52909
|
+
}
|
|
52910
|
+
static getSettablePaths({ global: _global = false } = {}) {
|
|
52911
|
+
return {
|
|
52912
|
+
relativeDirPath: AUGMENTCODE_SKILLS_DIR_PATH,
|
|
52913
|
+
alternativeSkillRoots: [AUGMENTCODE_AGENTS_SKILLS_DIR_PATH]
|
|
52914
|
+
};
|
|
52915
|
+
}
|
|
52916
|
+
getFrontmatter() {
|
|
52917
|
+
return AugmentcodeSkillFrontmatterSchema.parse(this.requireMainFileFrontmatter());
|
|
52918
|
+
}
|
|
52919
|
+
getBody() {
|
|
52920
|
+
return this.mainFile?.body ?? "";
|
|
52921
|
+
}
|
|
52922
|
+
validate() {
|
|
52923
|
+
if (this.mainFile === void 0) return {
|
|
52924
|
+
success: false,
|
|
52925
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
52926
|
+
};
|
|
52927
|
+
const result = AugmentcodeSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
52928
|
+
if (!result.success) return {
|
|
52929
|
+
success: false,
|
|
52930
|
+
error: /* @__PURE__ */ new Error(`Invalid frontmatter in ${this.getDirPath()}: ${formatError(result.error)}`)
|
|
52931
|
+
};
|
|
52932
|
+
return {
|
|
52933
|
+
success: true,
|
|
52934
|
+
error: null
|
|
52935
|
+
};
|
|
52936
|
+
}
|
|
52937
|
+
toRulesyncSkill() {
|
|
52938
|
+
const frontmatter = this.getFrontmatter();
|
|
52939
|
+
const rulesyncFrontmatter = {
|
|
52940
|
+
name: frontmatter.name,
|
|
52941
|
+
description: frontmatter.description,
|
|
52942
|
+
targets: ["*"]
|
|
52943
|
+
};
|
|
52944
|
+
return new RulesyncSkill({
|
|
52945
|
+
outputRoot: this.outputRoot,
|
|
52946
|
+
relativeDirPath: RULESYNC_SKILLS_RELATIVE_DIR_PATH,
|
|
52947
|
+
dirName: this.getDirName(),
|
|
52948
|
+
frontmatter: rulesyncFrontmatter,
|
|
52949
|
+
body: this.getBody(),
|
|
52950
|
+
otherFiles: this.getOtherFiles(),
|
|
52951
|
+
validate: true,
|
|
52952
|
+
global: this.global
|
|
52953
|
+
});
|
|
52954
|
+
}
|
|
52955
|
+
static fromRulesyncSkill({ outputRoot = process.cwd(), rulesyncSkill, validate = true, global = false }) {
|
|
52956
|
+
const settablePaths = AugmentcodeSkill.getSettablePaths({ global });
|
|
52957
|
+
const rulesyncFrontmatter = rulesyncSkill.getFrontmatter();
|
|
52958
|
+
const augmentcodeFrontmatter = {
|
|
50254
52959
|
name: rulesyncFrontmatter.name,
|
|
50255
52960
|
description: rulesyncFrontmatter.description
|
|
50256
52961
|
};
|
|
50257
|
-
|
|
50258
|
-
return new this({
|
|
52962
|
+
return new AugmentcodeSkill({
|
|
50259
52963
|
outputRoot,
|
|
50260
52964
|
relativeDirPath: settablePaths.relativeDirPath,
|
|
50261
52965
|
dirName: rulesyncSkill.getDirName(),
|
|
50262
|
-
frontmatter:
|
|
52966
|
+
frontmatter: augmentcodeFrontmatter,
|
|
50263
52967
|
body: rulesyncSkill.getBody(),
|
|
50264
52968
|
otherFiles: rulesyncSkill.getOtherFiles(),
|
|
50265
52969
|
validate,
|
|
@@ -50268,19 +52972,19 @@ var AntigravitySharedSkill = class extends ToolSkill {
|
|
|
50268
52972
|
}
|
|
50269
52973
|
static isTargetedByRulesyncSkill(rulesyncSkill) {
|
|
50270
52974
|
const targets = rulesyncSkill.getFrontmatter().targets;
|
|
50271
|
-
return targets.includes("*") || targets.includes(
|
|
52975
|
+
return targets.includes("*") || targets.includes("augmentcode");
|
|
50272
52976
|
}
|
|
50273
52977
|
static async fromDir(params) {
|
|
50274
52978
|
const loaded = await this.loadSkillDirContent({
|
|
50275
52979
|
...params,
|
|
50276
|
-
getSettablePaths:
|
|
52980
|
+
getSettablePaths: AugmentcodeSkill.getSettablePaths
|
|
50277
52981
|
});
|
|
50278
|
-
const result =
|
|
52982
|
+
const result = AugmentcodeSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
50279
52983
|
if (!result.success) {
|
|
50280
52984
|
const skillDirPath = (0, node_path.join)(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
50281
52985
|
throw new Error(`Invalid frontmatter in ${(0, node_path.join)(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
50282
52986
|
}
|
|
50283
|
-
return new
|
|
52987
|
+
return new AugmentcodeSkill({
|
|
50284
52988
|
outputRoot: loaded.outputRoot,
|
|
50285
52989
|
relativeDirPath: loaded.relativeDirPath,
|
|
50286
52990
|
dirName: loaded.dirName,
|
|
@@ -50292,9 +52996,10 @@ var AntigravitySharedSkill = class extends ToolSkill {
|
|
|
50292
52996
|
});
|
|
50293
52997
|
}
|
|
50294
52998
|
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, dirName, global = false }) {
|
|
50295
|
-
|
|
52999
|
+
const settablePaths = AugmentcodeSkill.getSettablePaths({ global });
|
|
53000
|
+
return new AugmentcodeSkill({
|
|
50296
53001
|
outputRoot,
|
|
50297
|
-
relativeDirPath,
|
|
53002
|
+
relativeDirPath: relativeDirPath ?? settablePaths.relativeDirPath,
|
|
50298
53003
|
dirName,
|
|
50299
53004
|
frontmatter: {
|
|
50300
53005
|
name: "",
|
|
@@ -50308,66 +53013,24 @@ var AntigravitySharedSkill = class extends ToolSkill {
|
|
|
50308
53013
|
}
|
|
50309
53014
|
};
|
|
50310
53015
|
//#endregion
|
|
50311
|
-
//#region src/features/skills/
|
|
50312
|
-
|
|
50313
|
-
* Represents a Google Antigravity CLI skill directory (Antigravity 2.0).
|
|
50314
|
-
*
|
|
50315
|
-
* Shares all behavior with {@link AntigravitySharedSkill}; the CLI keeps its
|
|
50316
|
-
* own global skills tree at `~/.gemini/antigravity-cli/skills/` and answers to
|
|
50317
|
-
* the `antigravity-cli` target.
|
|
50318
|
-
*/
|
|
50319
|
-
var AntigravityCliSkill = class extends AntigravitySharedSkill {
|
|
50320
|
-
static getGlobalSubdir() {
|
|
50321
|
-
return ANTIGRAVITY_CLI_PERMISSIONS_SUBDIR;
|
|
50322
|
-
}
|
|
50323
|
-
static getToolTarget() {
|
|
50324
|
-
return "antigravity-cli";
|
|
50325
|
-
}
|
|
50326
|
-
};
|
|
50327
|
-
//#endregion
|
|
50328
|
-
//#region src/features/skills/antigravity-ide-skill.ts
|
|
50329
|
-
/**
|
|
50330
|
-
* Represents a Google Antigravity IDE skill directory (Antigravity 2.0).
|
|
50331
|
-
*
|
|
50332
|
-
* Shares all behavior with {@link AntigravitySharedSkill}. As of Antigravity
|
|
50333
|
-
* 2.0 the IDE reads its global skills from the shared `~/.gemini/config/skills/`
|
|
50334
|
-
* location (the Skills doc lists `~/.gemini/config/skills/<skill-folder>/` as
|
|
50335
|
-
* the global scope); the legacy `~/.gemini/antigravity/skills/` path is no
|
|
50336
|
-
* longer used. It answers to the `antigravity-ide` target.
|
|
50337
|
-
*/
|
|
50338
|
-
var AntigravityIdeSkill = class extends AntigravitySharedSkill {
|
|
50339
|
-
static getGlobalSubdir() {
|
|
50340
|
-
return ANTIGRAVITY_IDE_GLOBAL_CONFIG_SUBDIR;
|
|
50341
|
-
}
|
|
50342
|
-
static getToolTarget() {
|
|
50343
|
-
return "antigravity-ide";
|
|
50344
|
-
}
|
|
50345
|
-
};
|
|
50346
|
-
//#endregion
|
|
50347
|
-
//#region src/features/skills/antigravity-plugin-skill.ts
|
|
50348
|
-
var AntigravityPluginSkill = class extends AntigravityIdeSkill {
|
|
50349
|
-
static isTargetedByRulesyncSkill(rulesyncSkill) {
|
|
50350
|
-
const targets = rulesyncSkill.getFrontmatter().targets;
|
|
50351
|
-
return targets.includes("*") || targets.includes("antigravity-plugin");
|
|
50352
|
-
}
|
|
50353
|
-
static getSettablePaths() {
|
|
50354
|
-
return { relativeDirPath: ANTIGRAVITY_PLUGIN_SKILLS_DIR };
|
|
50355
|
-
}
|
|
50356
|
-
};
|
|
50357
|
-
//#endregion
|
|
50358
|
-
//#region src/features/skills/augmentcode-skill.ts
|
|
50359
|
-
const AugmentcodeSkillFrontmatterSchema = zod_mini.z.looseObject({
|
|
53016
|
+
//#region src/features/skills/bob-skill.ts
|
|
53017
|
+
const BobSkillFrontmatterSchema = zod_mini.z.looseObject({
|
|
50360
53018
|
name: zod_mini.z.string(),
|
|
50361
53019
|
description: zod_mini.z.string()
|
|
50362
53020
|
});
|
|
50363
53021
|
/**
|
|
50364
|
-
* Represents an
|
|
50365
|
-
*
|
|
50366
|
-
*
|
|
50367
|
-
*
|
|
53022
|
+
* Represents an IBM Bob skill directory.
|
|
53023
|
+
*
|
|
53024
|
+
* Bob discovers Anthropic-style `<name>/SKILL.md` directories under
|
|
53025
|
+
* `<project>/.bob/skills/` (project scope) and `~/.bob/skills/` (user scope);
|
|
53026
|
+
* the project copy wins on a name clash. The frontmatter requires `name`
|
|
53027
|
+
* (matching the directory name) and `description`; supporting files next to
|
|
53028
|
+
* `SKILL.md` are carried along.
|
|
53029
|
+
*
|
|
53030
|
+
* @see https://bob.ibm.com/docs/ide/features/skills
|
|
50368
53031
|
*/
|
|
50369
|
-
var
|
|
50370
|
-
constructor({ outputRoot = process.cwd(), relativeDirPath =
|
|
53032
|
+
var BobSkill = class BobSkill extends ToolSkill {
|
|
53033
|
+
constructor({ outputRoot = process.cwd(), relativeDirPath = BOB_SKILLS_DIR_PATH, dirName, frontmatter, body, otherFiles = [], validate = true, global = false }) {
|
|
50371
53034
|
super({
|
|
50372
53035
|
outputRoot,
|
|
50373
53036
|
relativeDirPath,
|
|
@@ -50386,38 +53049,40 @@ var AugmentcodeSkill = class AugmentcodeSkill extends ToolSkill {
|
|
|
50386
53049
|
}
|
|
50387
53050
|
}
|
|
50388
53051
|
static getSettablePaths({ global: _global = false } = {}) {
|
|
50389
|
-
return {
|
|
50390
|
-
relativeDirPath: AUGMENTCODE_SKILLS_DIR_PATH,
|
|
50391
|
-
alternativeSkillRoots: [AUGMENTCODE_AGENTS_SKILLS_DIR_PATH]
|
|
50392
|
-
};
|
|
53052
|
+
return { relativeDirPath: BOB_SKILLS_DIR_PATH };
|
|
50393
53053
|
}
|
|
50394
53054
|
getFrontmatter() {
|
|
50395
|
-
return
|
|
53055
|
+
return BobSkillFrontmatterSchema.parse(this.requireMainFileFrontmatter());
|
|
50396
53056
|
}
|
|
50397
53057
|
getBody() {
|
|
50398
53058
|
return this.mainFile?.body ?? "";
|
|
50399
53059
|
}
|
|
50400
53060
|
validate() {
|
|
50401
|
-
if (this.mainFile
|
|
53061
|
+
if (!this.mainFile) return {
|
|
50402
53062
|
success: false,
|
|
50403
53063
|
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
50404
53064
|
};
|
|
50405
|
-
const result =
|
|
53065
|
+
const result = BobSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
50406
53066
|
if (!result.success) return {
|
|
50407
53067
|
success: false,
|
|
50408
53068
|
error: /* @__PURE__ */ new Error(`Invalid frontmatter in ${this.getDirPath()}: ${formatError(result.error)}`)
|
|
50409
53069
|
};
|
|
53070
|
+
if (result.data.name !== this.getDirName()) return {
|
|
53071
|
+
success: false,
|
|
53072
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: frontmatter name (${result.data.name}) must match directory name (${this.getDirName()})`)
|
|
53073
|
+
};
|
|
50410
53074
|
return {
|
|
50411
53075
|
success: true,
|
|
50412
53076
|
error: null
|
|
50413
53077
|
};
|
|
50414
53078
|
}
|
|
50415
53079
|
toRulesyncSkill() {
|
|
50416
|
-
const
|
|
53080
|
+
const { name, description, ...bobSection } = this.getFrontmatter();
|
|
50417
53081
|
const rulesyncFrontmatter = {
|
|
50418
|
-
name
|
|
50419
|
-
description
|
|
50420
|
-
targets: ["*"]
|
|
53082
|
+
name,
|
|
53083
|
+
description,
|
|
53084
|
+
targets: ["*"],
|
|
53085
|
+
...Object.keys(bobSection).length > 0 && { bob: bobSection }
|
|
50421
53086
|
};
|
|
50422
53087
|
return new RulesyncSkill({
|
|
50423
53088
|
outputRoot: this.outputRoot,
|
|
@@ -50431,17 +53096,19 @@ var AugmentcodeSkill = class AugmentcodeSkill extends ToolSkill {
|
|
|
50431
53096
|
});
|
|
50432
53097
|
}
|
|
50433
53098
|
static fromRulesyncSkill({ outputRoot = process.cwd(), rulesyncSkill, validate = true, global = false }) {
|
|
50434
|
-
const settablePaths =
|
|
53099
|
+
const settablePaths = BobSkill.getSettablePaths({ global });
|
|
50435
53100
|
const rulesyncFrontmatter = rulesyncSkill.getFrontmatter();
|
|
50436
|
-
const
|
|
53101
|
+
const { name: _sectionName, description: _sectionDescription, ...bobSection } = rulesyncFrontmatter.bob ?? {};
|
|
53102
|
+
const bobFrontmatter = {
|
|
53103
|
+
...bobSection,
|
|
50437
53104
|
name: rulesyncFrontmatter.name,
|
|
50438
53105
|
description: rulesyncFrontmatter.description
|
|
50439
53106
|
};
|
|
50440
|
-
return new
|
|
53107
|
+
return new BobSkill({
|
|
50441
53108
|
outputRoot,
|
|
50442
53109
|
relativeDirPath: settablePaths.relativeDirPath,
|
|
50443
|
-
dirName:
|
|
50444
|
-
frontmatter:
|
|
53110
|
+
dirName: bobFrontmatter.name,
|
|
53111
|
+
frontmatter: bobFrontmatter,
|
|
50445
53112
|
body: rulesyncSkill.getBody(),
|
|
50446
53113
|
otherFiles: rulesyncSkill.getOtherFiles(),
|
|
50447
53114
|
validate,
|
|
@@ -50450,19 +53117,23 @@ var AugmentcodeSkill = class AugmentcodeSkill extends ToolSkill {
|
|
|
50450
53117
|
}
|
|
50451
53118
|
static isTargetedByRulesyncSkill(rulesyncSkill) {
|
|
50452
53119
|
const targets = rulesyncSkill.getFrontmatter().targets;
|
|
50453
|
-
return targets.includes("*") || targets.includes("
|
|
53120
|
+
return targets.includes("*") || targets.includes("bob");
|
|
50454
53121
|
}
|
|
50455
53122
|
static async fromDir(params) {
|
|
50456
53123
|
const loaded = await this.loadSkillDirContent({
|
|
50457
53124
|
...params,
|
|
50458
|
-
getSettablePaths:
|
|
53125
|
+
getSettablePaths: BobSkill.getSettablePaths
|
|
50459
53126
|
});
|
|
50460
|
-
const result =
|
|
53127
|
+
const result = BobSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
50461
53128
|
if (!result.success) {
|
|
50462
53129
|
const skillDirPath = (0, node_path.join)(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
50463
53130
|
throw new Error(`Invalid frontmatter in ${(0, node_path.join)(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
50464
53131
|
}
|
|
50465
|
-
|
|
53132
|
+
if (result.data.name !== loaded.dirName) {
|
|
53133
|
+
const skillFilePath = (0, node_path.join)(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME);
|
|
53134
|
+
throw new Error(`Frontmatter name (${result.data.name}) must match directory name (${loaded.dirName}) in ${skillFilePath}`);
|
|
53135
|
+
}
|
|
53136
|
+
return new BobSkill({
|
|
50466
53137
|
outputRoot: loaded.outputRoot,
|
|
50467
53138
|
relativeDirPath: loaded.relativeDirPath,
|
|
50468
53139
|
dirName: loaded.dirName,
|
|
@@ -50474,10 +53145,9 @@ var AugmentcodeSkill = class AugmentcodeSkill extends ToolSkill {
|
|
|
50474
53145
|
});
|
|
50475
53146
|
}
|
|
50476
53147
|
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, dirName, global = false }) {
|
|
50477
|
-
|
|
50478
|
-
return new AugmentcodeSkill({
|
|
53148
|
+
return new BobSkill({
|
|
50479
53149
|
outputRoot,
|
|
50480
|
-
relativeDirPath
|
|
53150
|
+
relativeDirPath,
|
|
50481
53151
|
dirName,
|
|
50482
53152
|
frontmatter: {
|
|
50483
53153
|
name: "",
|
|
@@ -51422,7 +54092,167 @@ var CopilotSkill = class CopilotSkill extends ToolSkill {
|
|
|
51422
54092
|
return { relativeDirPath: COPILOT_SKILLS_DIR_PATH };
|
|
51423
54093
|
}
|
|
51424
54094
|
getFrontmatter() {
|
|
51425
|
-
return CopilotSkillFrontmatterSchema.parse(this.requireMainFileFrontmatter());
|
|
54095
|
+
return CopilotSkillFrontmatterSchema.parse(this.requireMainFileFrontmatter());
|
|
54096
|
+
}
|
|
54097
|
+
getBody() {
|
|
54098
|
+
return this.mainFile?.body ?? "";
|
|
54099
|
+
}
|
|
54100
|
+
validate() {
|
|
54101
|
+
if (!this.mainFile) return {
|
|
54102
|
+
success: false,
|
|
54103
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
54104
|
+
};
|
|
54105
|
+
const result = CopilotSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
54106
|
+
if (!result.success) return {
|
|
54107
|
+
success: false,
|
|
54108
|
+
error: /* @__PURE__ */ new Error(`Invalid frontmatter in ${this.getDirPath()}: ${formatError(result.error)}`)
|
|
54109
|
+
};
|
|
54110
|
+
return {
|
|
54111
|
+
success: true,
|
|
54112
|
+
error: null
|
|
54113
|
+
};
|
|
54114
|
+
}
|
|
54115
|
+
toRulesyncSkill() {
|
|
54116
|
+
const { name, description, ...copilotSection } = this.getFrontmatter();
|
|
54117
|
+
const rulesyncFrontmatter = {
|
|
54118
|
+
name,
|
|
54119
|
+
description,
|
|
54120
|
+
targets: ["*"],
|
|
54121
|
+
...Object.keys(copilotSection).length > 0 && { copilot: copilotSection }
|
|
54122
|
+
};
|
|
54123
|
+
return new RulesyncSkill({
|
|
54124
|
+
outputRoot: this.outputRoot,
|
|
54125
|
+
relativeDirPath: RULESYNC_SKILLS_RELATIVE_DIR_PATH,
|
|
54126
|
+
dirName: this.getDirName(),
|
|
54127
|
+
frontmatter: rulesyncFrontmatter,
|
|
54128
|
+
body: this.getBody(),
|
|
54129
|
+
otherFiles: this.getOtherFiles(),
|
|
54130
|
+
validate: true,
|
|
54131
|
+
global: this.global
|
|
54132
|
+
});
|
|
54133
|
+
}
|
|
54134
|
+
static fromRulesyncSkill({ outputRoot = process.cwd(), rulesyncSkill, validate = true, global = false }) {
|
|
54135
|
+
const settablePaths = CopilotSkill.getSettablePaths({ global });
|
|
54136
|
+
const rulesyncFrontmatter = rulesyncSkill.getFrontmatter();
|
|
54137
|
+
const copilotSection = rulesyncFrontmatter.copilot;
|
|
54138
|
+
const resolvedUserInvocable = resolveUserInvocable({
|
|
54139
|
+
rootFrontmatter: rulesyncFrontmatter,
|
|
54140
|
+
section: copilotSection
|
|
54141
|
+
});
|
|
54142
|
+
const resolvedDisableModelInvocation = resolveDisableModelInvocation({
|
|
54143
|
+
rootFrontmatter: rulesyncFrontmatter,
|
|
54144
|
+
section: copilotSection
|
|
54145
|
+
});
|
|
54146
|
+
const license = resolveLicense({
|
|
54147
|
+
rootFrontmatter: rulesyncFrontmatter,
|
|
54148
|
+
section: copilotSection
|
|
54149
|
+
});
|
|
54150
|
+
const { "user-invocable": _userInvocable, "disable-model-invocation": _disableModelInvocation, license: _license, ...copilotFields } = copilotSection ?? {};
|
|
54151
|
+
const copilotFrontmatter = {
|
|
54152
|
+
...copilotFields,
|
|
54153
|
+
name: rulesyncFrontmatter.name,
|
|
54154
|
+
description: rulesyncFrontmatter.description,
|
|
54155
|
+
...license !== void 0 && { license },
|
|
54156
|
+
...resolvedUserInvocable !== void 0 && { "user-invocable": resolvedUserInvocable },
|
|
54157
|
+
...resolvedDisableModelInvocation !== void 0 && { "disable-model-invocation": resolvedDisableModelInvocation }
|
|
54158
|
+
};
|
|
54159
|
+
return new CopilotSkill({
|
|
54160
|
+
outputRoot,
|
|
54161
|
+
relativeDirPath: settablePaths.relativeDirPath,
|
|
54162
|
+
dirName: rulesyncSkill.getDirName(),
|
|
54163
|
+
frontmatter: copilotFrontmatter,
|
|
54164
|
+
body: rulesyncSkill.getBody(),
|
|
54165
|
+
otherFiles: rulesyncSkill.getOtherFiles(),
|
|
54166
|
+
validate,
|
|
54167
|
+
global
|
|
54168
|
+
});
|
|
54169
|
+
}
|
|
54170
|
+
static isTargetedByRulesyncSkill(rulesyncSkill) {
|
|
54171
|
+
const targets = rulesyncSkill.getFrontmatter().targets;
|
|
54172
|
+
return targets.includes("*") || targets.includes("copilot");
|
|
54173
|
+
}
|
|
54174
|
+
static async fromDir(params) {
|
|
54175
|
+
const loaded = await this.loadSkillDirContent({
|
|
54176
|
+
...params,
|
|
54177
|
+
getSettablePaths: CopilotSkill.getSettablePaths
|
|
54178
|
+
});
|
|
54179
|
+
const result = CopilotSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
54180
|
+
if (!result.success) {
|
|
54181
|
+
const skillDirPath = (0, node_path.join)(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
54182
|
+
throw new Error(`Invalid frontmatter in ${(0, node_path.join)(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
54183
|
+
}
|
|
54184
|
+
return new CopilotSkill({
|
|
54185
|
+
outputRoot: loaded.outputRoot,
|
|
54186
|
+
relativeDirPath: loaded.relativeDirPath,
|
|
54187
|
+
dirName: loaded.dirName,
|
|
54188
|
+
frontmatter: result.data,
|
|
54189
|
+
body: loaded.body,
|
|
54190
|
+
otherFiles: loaded.otherFiles,
|
|
54191
|
+
validate: true,
|
|
54192
|
+
global: loaded.global
|
|
54193
|
+
});
|
|
54194
|
+
}
|
|
54195
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, dirName, global = false }) {
|
|
54196
|
+
const settablePaths = CopilotSkill.getSettablePaths({ global });
|
|
54197
|
+
return new CopilotSkill({
|
|
54198
|
+
outputRoot,
|
|
54199
|
+
relativeDirPath: relativeDirPath ?? settablePaths.relativeDirPath,
|
|
54200
|
+
dirName,
|
|
54201
|
+
frontmatter: {
|
|
54202
|
+
name: "",
|
|
54203
|
+
description: ""
|
|
54204
|
+
},
|
|
54205
|
+
body: "",
|
|
54206
|
+
otherFiles: [],
|
|
54207
|
+
validate: false,
|
|
54208
|
+
global
|
|
54209
|
+
});
|
|
54210
|
+
}
|
|
54211
|
+
};
|
|
54212
|
+
//#endregion
|
|
54213
|
+
//#region src/features/skills/copilotcli-skill.ts
|
|
54214
|
+
const CopilotcliSkillFrontmatterSchema = zod_mini.z.looseObject({
|
|
54215
|
+
name: zod_mini.z.string(),
|
|
54216
|
+
description: zod_mini.z.string(),
|
|
54217
|
+
license: zod_mini.z.optional(zod_mini.z.string()),
|
|
54218
|
+
"allowed-tools": zod_mini.z.optional(zod_mini.z.union([zod_mini.z.string(), zod_mini.z.array(zod_mini.z.string())])),
|
|
54219
|
+
"argument-hint": zod_mini.z.optional(zod_mini.z.string()),
|
|
54220
|
+
"user-invocable": zod_mini.z.optional(zod_mini.z.boolean()),
|
|
54221
|
+
"disable-model-invocation": zod_mini.z.optional(zod_mini.z.boolean())
|
|
54222
|
+
});
|
|
54223
|
+
/**
|
|
54224
|
+
* Represents a GitHub Copilot CLI skill directory.
|
|
54225
|
+
*
|
|
54226
|
+
* Copilot CLI discovers project skills from `.github/skills/` (shared with the
|
|
54227
|
+
* Copilot IDE target) and personal/global skills from `~/.copilot/skills/`. Each
|
|
54228
|
+
* skill is a directory containing a `SKILL.md` file with `name`/`description`
|
|
54229
|
+
* frontmatter. https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-skills
|
|
54230
|
+
*/
|
|
54231
|
+
var CopilotcliSkill = class CopilotcliSkill extends ToolSkill {
|
|
54232
|
+
constructor({ outputRoot = process.cwd(), relativeDirPath = COPILOT_SKILLS_DIR_PATH, dirName, frontmatter, body, otherFiles = [], validate = true, global = false }) {
|
|
54233
|
+
super({
|
|
54234
|
+
outputRoot,
|
|
54235
|
+
relativeDirPath,
|
|
54236
|
+
dirName,
|
|
54237
|
+
mainFile: {
|
|
54238
|
+
name: SKILL_FILE_NAME,
|
|
54239
|
+
body,
|
|
54240
|
+
frontmatter: { ...frontmatter }
|
|
54241
|
+
},
|
|
54242
|
+
otherFiles,
|
|
54243
|
+
global
|
|
54244
|
+
});
|
|
54245
|
+
if (validate) {
|
|
54246
|
+
const result = this.validate();
|
|
54247
|
+
if (!result.success) throw result.error;
|
|
54248
|
+
}
|
|
54249
|
+
}
|
|
54250
|
+
static getSettablePaths(options) {
|
|
54251
|
+
if (options?.global) return { relativeDirPath: COPILOT_SKILLS_GLOBAL_DIR_PATH };
|
|
54252
|
+
return { relativeDirPath: COPILOT_SKILLS_DIR_PATH };
|
|
54253
|
+
}
|
|
54254
|
+
getFrontmatter() {
|
|
54255
|
+
return CopilotcliSkillFrontmatterSchema.parse(this.requireMainFileFrontmatter());
|
|
51426
54256
|
}
|
|
51427
54257
|
getBody() {
|
|
51428
54258
|
return this.mainFile?.body ?? "";
|
|
@@ -51432,7 +54262,7 @@ var CopilotSkill = class CopilotSkill extends ToolSkill {
|
|
|
51432
54262
|
success: false,
|
|
51433
54263
|
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
51434
54264
|
};
|
|
51435
|
-
const result =
|
|
54265
|
+
const result = CopilotcliSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
51436
54266
|
if (!result.success) return {
|
|
51437
54267
|
success: false,
|
|
51438
54268
|
error: /* @__PURE__ */ new Error(`Invalid frontmatter in ${this.getDirPath()}: ${formatError(result.error)}`)
|
|
@@ -51443,12 +54273,12 @@ var CopilotSkill = class CopilotSkill extends ToolSkill {
|
|
|
51443
54273
|
};
|
|
51444
54274
|
}
|
|
51445
54275
|
toRulesyncSkill() {
|
|
51446
|
-
const { name, description, ...
|
|
54276
|
+
const { name, description, ...copilotcliSection } = this.getFrontmatter();
|
|
51447
54277
|
const rulesyncFrontmatter = {
|
|
51448
54278
|
name,
|
|
51449
54279
|
description,
|
|
51450
54280
|
targets: ["*"],
|
|
51451
|
-
...Object.keys(
|
|
54281
|
+
...Object.keys(copilotcliSection).length > 0 && { copilotcli: copilotcliSection }
|
|
51452
54282
|
};
|
|
51453
54283
|
return new RulesyncSkill({
|
|
51454
54284
|
outputRoot: this.outputRoot,
|
|
@@ -51462,35 +54292,35 @@ var CopilotSkill = class CopilotSkill extends ToolSkill {
|
|
|
51462
54292
|
});
|
|
51463
54293
|
}
|
|
51464
54294
|
static fromRulesyncSkill({ outputRoot = process.cwd(), rulesyncSkill, validate = true, global = false }) {
|
|
51465
|
-
const settablePaths =
|
|
54295
|
+
const settablePaths = CopilotcliSkill.getSettablePaths({ global });
|
|
51466
54296
|
const rulesyncFrontmatter = rulesyncSkill.getFrontmatter();
|
|
51467
|
-
const
|
|
54297
|
+
const copilotcliSection = rulesyncFrontmatter.copilotcli;
|
|
51468
54298
|
const resolvedUserInvocable = resolveUserInvocable({
|
|
51469
54299
|
rootFrontmatter: rulesyncFrontmatter,
|
|
51470
|
-
section:
|
|
54300
|
+
section: copilotcliSection
|
|
51471
54301
|
});
|
|
51472
54302
|
const resolvedDisableModelInvocation = resolveDisableModelInvocation({
|
|
51473
54303
|
rootFrontmatter: rulesyncFrontmatter,
|
|
51474
|
-
section:
|
|
54304
|
+
section: copilotcliSection
|
|
51475
54305
|
});
|
|
51476
54306
|
const license = resolveLicense({
|
|
51477
54307
|
rootFrontmatter: rulesyncFrontmatter,
|
|
51478
|
-
section:
|
|
54308
|
+
section: copilotcliSection
|
|
51479
54309
|
});
|
|
51480
|
-
const { "user-invocable": _userInvocable, "disable-model-invocation": _disableModelInvocation, license: _license, ...
|
|
51481
|
-
const
|
|
51482
|
-
...
|
|
54310
|
+
const { "user-invocable": _userInvocable, "disable-model-invocation": _disableModelInvocation, license: _license, ...copilotcliFields } = copilotcliSection ?? {};
|
|
54311
|
+
const copilotcliFrontmatter = {
|
|
54312
|
+
...copilotcliFields,
|
|
51483
54313
|
name: rulesyncFrontmatter.name,
|
|
51484
54314
|
description: rulesyncFrontmatter.description,
|
|
51485
54315
|
...license !== void 0 && { license },
|
|
51486
54316
|
...resolvedUserInvocable !== void 0 && { "user-invocable": resolvedUserInvocable },
|
|
51487
54317
|
...resolvedDisableModelInvocation !== void 0 && { "disable-model-invocation": resolvedDisableModelInvocation }
|
|
51488
54318
|
};
|
|
51489
|
-
return new
|
|
54319
|
+
return new CopilotcliSkill({
|
|
51490
54320
|
outputRoot,
|
|
51491
54321
|
relativeDirPath: settablePaths.relativeDirPath,
|
|
51492
54322
|
dirName: rulesyncSkill.getDirName(),
|
|
51493
|
-
frontmatter:
|
|
54323
|
+
frontmatter: copilotcliFrontmatter,
|
|
51494
54324
|
body: rulesyncSkill.getBody(),
|
|
51495
54325
|
otherFiles: rulesyncSkill.getOtherFiles(),
|
|
51496
54326
|
validate,
|
|
@@ -51499,19 +54329,19 @@ var CopilotSkill = class CopilotSkill extends ToolSkill {
|
|
|
51499
54329
|
}
|
|
51500
54330
|
static isTargetedByRulesyncSkill(rulesyncSkill) {
|
|
51501
54331
|
const targets = rulesyncSkill.getFrontmatter().targets;
|
|
51502
|
-
return targets.includes("*") || targets.includes("
|
|
54332
|
+
return targets.includes("*") || targets.includes("copilotcli");
|
|
51503
54333
|
}
|
|
51504
54334
|
static async fromDir(params) {
|
|
51505
54335
|
const loaded = await this.loadSkillDirContent({
|
|
51506
54336
|
...params,
|
|
51507
|
-
getSettablePaths:
|
|
54337
|
+
getSettablePaths: CopilotcliSkill.getSettablePaths
|
|
51508
54338
|
});
|
|
51509
|
-
const result =
|
|
54339
|
+
const result = CopilotcliSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
51510
54340
|
if (!result.success) {
|
|
51511
54341
|
const skillDirPath = (0, node_path.join)(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
51512
54342
|
throw new Error(`Invalid frontmatter in ${(0, node_path.join)(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
51513
54343
|
}
|
|
51514
|
-
return new
|
|
54344
|
+
return new CopilotcliSkill({
|
|
51515
54345
|
outputRoot: loaded.outputRoot,
|
|
51516
54346
|
relativeDirPath: loaded.relativeDirPath,
|
|
51517
54347
|
dirName: loaded.dirName,
|
|
@@ -51523,8 +54353,8 @@ var CopilotSkill = class CopilotSkill extends ToolSkill {
|
|
|
51523
54353
|
});
|
|
51524
54354
|
}
|
|
51525
54355
|
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, dirName, global = false }) {
|
|
51526
|
-
const settablePaths =
|
|
51527
|
-
return new
|
|
54356
|
+
const settablePaths = CopilotcliSkill.getSettablePaths({ global });
|
|
54357
|
+
return new CopilotcliSkill({
|
|
51528
54358
|
outputRoot,
|
|
51529
54359
|
relativeDirPath: relativeDirPath ?? settablePaths.relativeDirPath,
|
|
51530
54360
|
dirName,
|
|
@@ -51540,26 +54370,25 @@ var CopilotSkill = class CopilotSkill extends ToolSkill {
|
|
|
51540
54370
|
}
|
|
51541
54371
|
};
|
|
51542
54372
|
//#endregion
|
|
51543
|
-
//#region src/features/skills/
|
|
51544
|
-
const
|
|
54373
|
+
//#region src/features/skills/cortexcode-skill.ts
|
|
54374
|
+
const CortexcodeSkillFrontmatterSchema = zod_mini.z.looseObject({
|
|
51545
54375
|
name: zod_mini.z.string(),
|
|
51546
54376
|
description: zod_mini.z.string(),
|
|
51547
|
-
|
|
51548
|
-
|
|
51549
|
-
"argument-hint": zod_mini.z.optional(zod_mini.z.string()),
|
|
51550
|
-
"user-invocable": zod_mini.z.optional(zod_mini.z.boolean()),
|
|
51551
|
-
"disable-model-invocation": zod_mini.z.optional(zod_mini.z.boolean())
|
|
54377
|
+
/** Tool names the skill may use; omitted = every tool. */
|
|
54378
|
+
tools: zod_mini.z.optional(zod_mini.z.array(zod_mini.z.string()))
|
|
51552
54379
|
});
|
|
51553
54380
|
/**
|
|
51554
|
-
* Represents a
|
|
54381
|
+
* Represents a Snowflake Cortex Code skill directory.
|
|
51555
54382
|
*
|
|
51556
|
-
*
|
|
51557
|
-
*
|
|
51558
|
-
*
|
|
51559
|
-
*
|
|
54383
|
+
* Cortex Code discovers Anthropic-style `<name>/SKILL.md` directories under
|
|
54384
|
+
* `<project>/.cortex/skills/` (project scope) and `~/.snowflake/cortex/skills/`
|
|
54385
|
+
* (user scope). The frontmatter requires `name` (matching the directory name)
|
|
54386
|
+
* and `description`; supporting files next to `SKILL.md` are carried along.
|
|
54387
|
+
*
|
|
54388
|
+
* @see https://docs.snowflake.com/en/user-guide/cortex-code/extensibility
|
|
51560
54389
|
*/
|
|
51561
|
-
var
|
|
51562
|
-
constructor({ outputRoot = process.cwd(), relativeDirPath =
|
|
54390
|
+
var CortexcodeSkill = class CortexcodeSkill extends ToolSkill {
|
|
54391
|
+
constructor({ outputRoot = process.cwd(), relativeDirPath = CORTEXCODE_SKILLS_DIR_PATH, dirName, frontmatter, body, otherFiles = [], validate = true, global = false }) {
|
|
51563
54392
|
super({
|
|
51564
54393
|
outputRoot,
|
|
51565
54394
|
relativeDirPath,
|
|
@@ -51577,12 +54406,11 @@ var CopilotcliSkill = class CopilotcliSkill extends ToolSkill {
|
|
|
51577
54406
|
if (!result.success) throw result.error;
|
|
51578
54407
|
}
|
|
51579
54408
|
}
|
|
51580
|
-
static getSettablePaths(
|
|
51581
|
-
|
|
51582
|
-
return { relativeDirPath: COPILOT_SKILLS_DIR_PATH };
|
|
54409
|
+
static getSettablePaths({ global = false } = {}) {
|
|
54410
|
+
return { relativeDirPath: global ? CORTEXCODE_GLOBAL_SKILLS_DIR_PATH : CORTEXCODE_SKILLS_DIR_PATH };
|
|
51583
54411
|
}
|
|
51584
54412
|
getFrontmatter() {
|
|
51585
|
-
return
|
|
54413
|
+
return CortexcodeSkillFrontmatterSchema.parse(this.requireMainFileFrontmatter());
|
|
51586
54414
|
}
|
|
51587
54415
|
getBody() {
|
|
51588
54416
|
return this.mainFile?.body ?? "";
|
|
@@ -51592,23 +54420,27 @@ var CopilotcliSkill = class CopilotcliSkill extends ToolSkill {
|
|
|
51592
54420
|
success: false,
|
|
51593
54421
|
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
51594
54422
|
};
|
|
51595
|
-
const result =
|
|
54423
|
+
const result = CortexcodeSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
51596
54424
|
if (!result.success) return {
|
|
51597
54425
|
success: false,
|
|
51598
54426
|
error: /* @__PURE__ */ new Error(`Invalid frontmatter in ${this.getDirPath()}: ${formatError(result.error)}`)
|
|
51599
54427
|
};
|
|
54428
|
+
if (result.data.name !== this.getDirName()) return {
|
|
54429
|
+
success: false,
|
|
54430
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: frontmatter name (${result.data.name}) must match directory name (${this.getDirName()})`)
|
|
54431
|
+
};
|
|
51600
54432
|
return {
|
|
51601
54433
|
success: true,
|
|
51602
54434
|
error: null
|
|
51603
54435
|
};
|
|
51604
54436
|
}
|
|
51605
54437
|
toRulesyncSkill() {
|
|
51606
|
-
const { name, description, ...
|
|
54438
|
+
const { name, description, ...cortexcodeSection } = this.getFrontmatter();
|
|
51607
54439
|
const rulesyncFrontmatter = {
|
|
51608
54440
|
name,
|
|
51609
54441
|
description,
|
|
51610
54442
|
targets: ["*"],
|
|
51611
|
-
...Object.keys(
|
|
54443
|
+
...Object.keys(cortexcodeSection).length > 0 && { cortexcode: cortexcodeSection }
|
|
51612
54444
|
};
|
|
51613
54445
|
return new RulesyncSkill({
|
|
51614
54446
|
outputRoot: this.outputRoot,
|
|
@@ -51622,35 +54454,19 @@ var CopilotcliSkill = class CopilotcliSkill extends ToolSkill {
|
|
|
51622
54454
|
});
|
|
51623
54455
|
}
|
|
51624
54456
|
static fromRulesyncSkill({ outputRoot = process.cwd(), rulesyncSkill, validate = true, global = false }) {
|
|
51625
|
-
const settablePaths =
|
|
54457
|
+
const settablePaths = CortexcodeSkill.getSettablePaths({ global });
|
|
51626
54458
|
const rulesyncFrontmatter = rulesyncSkill.getFrontmatter();
|
|
51627
|
-
const
|
|
51628
|
-
const
|
|
51629
|
-
|
|
51630
|
-
section: copilotcliSection
|
|
51631
|
-
});
|
|
51632
|
-
const resolvedDisableModelInvocation = resolveDisableModelInvocation({
|
|
51633
|
-
rootFrontmatter: rulesyncFrontmatter,
|
|
51634
|
-
section: copilotcliSection
|
|
51635
|
-
});
|
|
51636
|
-
const license = resolveLicense({
|
|
51637
|
-
rootFrontmatter: rulesyncFrontmatter,
|
|
51638
|
-
section: copilotcliSection
|
|
51639
|
-
});
|
|
51640
|
-
const { "user-invocable": _userInvocable, "disable-model-invocation": _disableModelInvocation, license: _license, ...copilotcliFields } = copilotcliSection ?? {};
|
|
51641
|
-
const copilotcliFrontmatter = {
|
|
51642
|
-
...copilotcliFields,
|
|
54459
|
+
const { name: _sectionName, description: _sectionDescription, ...cortexcodeSection } = rulesyncFrontmatter.cortexcode ?? {};
|
|
54460
|
+
const cortexcodeFrontmatter = {
|
|
54461
|
+
...cortexcodeSection,
|
|
51643
54462
|
name: rulesyncFrontmatter.name,
|
|
51644
|
-
description: rulesyncFrontmatter.description
|
|
51645
|
-
...license !== void 0 && { license },
|
|
51646
|
-
...resolvedUserInvocable !== void 0 && { "user-invocable": resolvedUserInvocable },
|
|
51647
|
-
...resolvedDisableModelInvocation !== void 0 && { "disable-model-invocation": resolvedDisableModelInvocation }
|
|
54463
|
+
description: rulesyncFrontmatter.description
|
|
51648
54464
|
};
|
|
51649
|
-
return new
|
|
54465
|
+
return new CortexcodeSkill({
|
|
51650
54466
|
outputRoot,
|
|
51651
54467
|
relativeDirPath: settablePaths.relativeDirPath,
|
|
51652
|
-
dirName:
|
|
51653
|
-
frontmatter:
|
|
54468
|
+
dirName: cortexcodeFrontmatter.name,
|
|
54469
|
+
frontmatter: cortexcodeFrontmatter,
|
|
51654
54470
|
body: rulesyncSkill.getBody(),
|
|
51655
54471
|
otherFiles: rulesyncSkill.getOtherFiles(),
|
|
51656
54472
|
validate,
|
|
@@ -51659,19 +54475,23 @@ var CopilotcliSkill = class CopilotcliSkill extends ToolSkill {
|
|
|
51659
54475
|
}
|
|
51660
54476
|
static isTargetedByRulesyncSkill(rulesyncSkill) {
|
|
51661
54477
|
const targets = rulesyncSkill.getFrontmatter().targets;
|
|
51662
|
-
return targets.includes("*") || targets.includes("
|
|
54478
|
+
return targets.includes("*") || targets.includes("cortexcode");
|
|
51663
54479
|
}
|
|
51664
54480
|
static async fromDir(params) {
|
|
51665
54481
|
const loaded = await this.loadSkillDirContent({
|
|
51666
54482
|
...params,
|
|
51667
|
-
getSettablePaths:
|
|
54483
|
+
getSettablePaths: CortexcodeSkill.getSettablePaths
|
|
51668
54484
|
});
|
|
51669
|
-
const result =
|
|
54485
|
+
const result = CortexcodeSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
51670
54486
|
if (!result.success) {
|
|
51671
54487
|
const skillDirPath = (0, node_path.join)(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
51672
54488
|
throw new Error(`Invalid frontmatter in ${(0, node_path.join)(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
51673
54489
|
}
|
|
51674
|
-
|
|
54490
|
+
if (result.data.name !== loaded.dirName) {
|
|
54491
|
+
const skillFilePath = (0, node_path.join)(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME);
|
|
54492
|
+
throw new Error(`Frontmatter name (${result.data.name}) must match directory name (${loaded.dirName}) in ${skillFilePath}`);
|
|
54493
|
+
}
|
|
54494
|
+
return new CortexcodeSkill({
|
|
51675
54495
|
outputRoot: loaded.outputRoot,
|
|
51676
54496
|
relativeDirPath: loaded.relativeDirPath,
|
|
51677
54497
|
dirName: loaded.dirName,
|
|
@@ -51683,10 +54503,9 @@ var CopilotcliSkill = class CopilotcliSkill extends ToolSkill {
|
|
|
51683
54503
|
});
|
|
51684
54504
|
}
|
|
51685
54505
|
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, dirName, global = false }) {
|
|
51686
|
-
|
|
51687
|
-
return new CopilotcliSkill({
|
|
54506
|
+
return new CortexcodeSkill({
|
|
51688
54507
|
outputRoot,
|
|
51689
|
-
relativeDirPath
|
|
54508
|
+
relativeDirPath,
|
|
51690
54509
|
dirName,
|
|
51691
54510
|
frontmatter: {
|
|
51692
54511
|
name: "",
|
|
@@ -55010,6 +57829,154 @@ var RooSkill = class RooSkill extends ToolSkill {
|
|
|
55010
57829
|
}
|
|
55011
57830
|
};
|
|
55012
57831
|
//#endregion
|
|
57832
|
+
//#region src/features/skills/tabnine-skill.ts
|
|
57833
|
+
const TabnineSkillFrontmatterSchema = zod_mini.z.looseObject({
|
|
57834
|
+
name: zod_mini.z.string(),
|
|
57835
|
+
description: zod_mini.z.string()
|
|
57836
|
+
});
|
|
57837
|
+
/**
|
|
57838
|
+
* Represents a Tabnine CLI skill directory.
|
|
57839
|
+
*
|
|
57840
|
+
* Tabnine CLI discovers Anthropic-style `<name>/SKILL.md` directories under
|
|
57841
|
+
* `<project>/.tabnine/agent/skills/` (workspace scope) and
|
|
57842
|
+
* `~/.tabnine/agent/skills/` (user scope); the workspace copy wins on a name
|
|
57843
|
+
* clash. The frontmatter requires `name` (matching the directory name) and
|
|
57844
|
+
* `description`; supporting files next to `SKILL.md` are carried along.
|
|
57845
|
+
*
|
|
57846
|
+
* @see https://docs.tabnine.com/main/getting-started/tabnine-cli/features/agent-skills
|
|
57847
|
+
*/
|
|
57848
|
+
var TabnineSkill = class TabnineSkill extends ToolSkill {
|
|
57849
|
+
constructor({ outputRoot = process.cwd(), relativeDirPath = TABNINE_SKILLS_DIR_PATH, dirName, frontmatter, body, otherFiles = [], validate = true, global = false }) {
|
|
57850
|
+
super({
|
|
57851
|
+
outputRoot,
|
|
57852
|
+
relativeDirPath,
|
|
57853
|
+
dirName,
|
|
57854
|
+
mainFile: {
|
|
57855
|
+
name: SKILL_FILE_NAME,
|
|
57856
|
+
body,
|
|
57857
|
+
frontmatter: { ...frontmatter }
|
|
57858
|
+
},
|
|
57859
|
+
otherFiles,
|
|
57860
|
+
global
|
|
57861
|
+
});
|
|
57862
|
+
if (validate) {
|
|
57863
|
+
const result = this.validate();
|
|
57864
|
+
if (!result.success) throw result.error;
|
|
57865
|
+
}
|
|
57866
|
+
}
|
|
57867
|
+
static getSettablePaths({ global: _global = false } = {}) {
|
|
57868
|
+
return { relativeDirPath: TABNINE_SKILLS_DIR_PATH };
|
|
57869
|
+
}
|
|
57870
|
+
getFrontmatter() {
|
|
57871
|
+
return TabnineSkillFrontmatterSchema.parse(this.requireMainFileFrontmatter());
|
|
57872
|
+
}
|
|
57873
|
+
getBody() {
|
|
57874
|
+
return this.mainFile?.body ?? "";
|
|
57875
|
+
}
|
|
57876
|
+
validate() {
|
|
57877
|
+
if (!this.mainFile) return {
|
|
57878
|
+
success: false,
|
|
57879
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: ${SKILL_FILE_NAME} file does not exist`)
|
|
57880
|
+
};
|
|
57881
|
+
const result = TabnineSkillFrontmatterSchema.safeParse(this.mainFile.frontmatter);
|
|
57882
|
+
if (!result.success) return {
|
|
57883
|
+
success: false,
|
|
57884
|
+
error: /* @__PURE__ */ new Error(`Invalid frontmatter in ${this.getDirPath()}: ${formatError(result.error)}`)
|
|
57885
|
+
};
|
|
57886
|
+
if (result.data.name !== this.getDirName()) return {
|
|
57887
|
+
success: false,
|
|
57888
|
+
error: /* @__PURE__ */ new Error(`${this.getDirPath()}: frontmatter name (${result.data.name}) must match directory name (${this.getDirName()})`)
|
|
57889
|
+
};
|
|
57890
|
+
return {
|
|
57891
|
+
success: true,
|
|
57892
|
+
error: null
|
|
57893
|
+
};
|
|
57894
|
+
}
|
|
57895
|
+
toRulesyncSkill() {
|
|
57896
|
+
const { name, description, ...tabnineSection } = this.getFrontmatter();
|
|
57897
|
+
const rulesyncFrontmatter = {
|
|
57898
|
+
name,
|
|
57899
|
+
description,
|
|
57900
|
+
targets: ["*"],
|
|
57901
|
+
...Object.keys(tabnineSection).length > 0 && { tabnine: tabnineSection }
|
|
57902
|
+
};
|
|
57903
|
+
return new RulesyncSkill({
|
|
57904
|
+
outputRoot: this.outputRoot,
|
|
57905
|
+
relativeDirPath: RULESYNC_SKILLS_RELATIVE_DIR_PATH,
|
|
57906
|
+
dirName: this.getDirName(),
|
|
57907
|
+
frontmatter: rulesyncFrontmatter,
|
|
57908
|
+
body: this.getBody(),
|
|
57909
|
+
otherFiles: this.getOtherFiles(),
|
|
57910
|
+
validate: true,
|
|
57911
|
+
global: this.global
|
|
57912
|
+
});
|
|
57913
|
+
}
|
|
57914
|
+
static fromRulesyncSkill({ outputRoot = process.cwd(), rulesyncSkill, validate = true, global = false }) {
|
|
57915
|
+
const settablePaths = TabnineSkill.getSettablePaths({ global });
|
|
57916
|
+
const rulesyncFrontmatter = rulesyncSkill.getFrontmatter();
|
|
57917
|
+
const { name: _sectionName, description: _sectionDescription, ...tabnineSection } = rulesyncFrontmatter.tabnine ?? {};
|
|
57918
|
+
const tabnineFrontmatter = {
|
|
57919
|
+
...tabnineSection,
|
|
57920
|
+
name: rulesyncFrontmatter.name,
|
|
57921
|
+
description: rulesyncFrontmatter.description
|
|
57922
|
+
};
|
|
57923
|
+
return new TabnineSkill({
|
|
57924
|
+
outputRoot,
|
|
57925
|
+
relativeDirPath: settablePaths.relativeDirPath,
|
|
57926
|
+
dirName: tabnineFrontmatter.name,
|
|
57927
|
+
frontmatter: tabnineFrontmatter,
|
|
57928
|
+
body: rulesyncSkill.getBody(),
|
|
57929
|
+
otherFiles: rulesyncSkill.getOtherFiles(),
|
|
57930
|
+
validate,
|
|
57931
|
+
global
|
|
57932
|
+
});
|
|
57933
|
+
}
|
|
57934
|
+
static isTargetedByRulesyncSkill(rulesyncSkill) {
|
|
57935
|
+
const targets = rulesyncSkill.getFrontmatter().targets;
|
|
57936
|
+
return targets.includes("*") || targets.includes("tabnine");
|
|
57937
|
+
}
|
|
57938
|
+
static async fromDir(params) {
|
|
57939
|
+
const loaded = await this.loadSkillDirContent({
|
|
57940
|
+
...params,
|
|
57941
|
+
getSettablePaths: TabnineSkill.getSettablePaths
|
|
57942
|
+
});
|
|
57943
|
+
const result = TabnineSkillFrontmatterSchema.safeParse(loaded.frontmatter);
|
|
57944
|
+
if (!result.success) {
|
|
57945
|
+
const skillDirPath = (0, node_path.join)(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName);
|
|
57946
|
+
throw new Error(`Invalid frontmatter in ${(0, node_path.join)(skillDirPath, SKILL_FILE_NAME)}: ${formatError(result.error)}`);
|
|
57947
|
+
}
|
|
57948
|
+
if (result.data.name !== loaded.dirName) {
|
|
57949
|
+
const skillFilePath = (0, node_path.join)(loaded.outputRoot, loaded.relativeDirPath, loaded.dirName, SKILL_FILE_NAME);
|
|
57950
|
+
throw new Error(`Frontmatter name (${result.data.name}) must match directory name (${loaded.dirName}) in ${skillFilePath}`);
|
|
57951
|
+
}
|
|
57952
|
+
return new TabnineSkill({
|
|
57953
|
+
outputRoot: loaded.outputRoot,
|
|
57954
|
+
relativeDirPath: loaded.relativeDirPath,
|
|
57955
|
+
dirName: loaded.dirName,
|
|
57956
|
+
frontmatter: result.data,
|
|
57957
|
+
body: loaded.body,
|
|
57958
|
+
otherFiles: loaded.otherFiles,
|
|
57959
|
+
validate: true,
|
|
57960
|
+
global: loaded.global
|
|
57961
|
+
});
|
|
57962
|
+
}
|
|
57963
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, dirName, global = false }) {
|
|
57964
|
+
return new TabnineSkill({
|
|
57965
|
+
outputRoot,
|
|
57966
|
+
relativeDirPath,
|
|
57967
|
+
dirName,
|
|
57968
|
+
frontmatter: {
|
|
57969
|
+
name: "",
|
|
57970
|
+
description: ""
|
|
57971
|
+
},
|
|
57972
|
+
body: "",
|
|
57973
|
+
otherFiles: [],
|
|
57974
|
+
validate: false,
|
|
57975
|
+
global
|
|
57976
|
+
});
|
|
57977
|
+
}
|
|
57978
|
+
};
|
|
57979
|
+
//#endregion
|
|
55013
57980
|
//#region src/features/skills/takt-skill.ts
|
|
55014
57981
|
/**
|
|
55015
57982
|
* Skill generator for TAKT.
|
|
@@ -55898,6 +58865,14 @@ const toolSkillFactories = /* @__PURE__ */ new Map([
|
|
|
55898
58865
|
supportsGlobal: true
|
|
55899
58866
|
}
|
|
55900
58867
|
}],
|
|
58868
|
+
["bob", {
|
|
58869
|
+
class: BobSkill,
|
|
58870
|
+
meta: {
|
|
58871
|
+
supportsProject: true,
|
|
58872
|
+
supportsSimulated: false,
|
|
58873
|
+
supportsGlobal: true
|
|
58874
|
+
}
|
|
58875
|
+
}],
|
|
55901
58876
|
["claudecode", {
|
|
55902
58877
|
class: ClaudecodeSkill,
|
|
55903
58878
|
meta: {
|
|
@@ -55954,6 +58929,14 @@ const toolSkillFactories = /* @__PURE__ */ new Map([
|
|
|
55954
58929
|
supportsGlobal: true
|
|
55955
58930
|
}
|
|
55956
58931
|
}],
|
|
58932
|
+
["cortexcode", {
|
|
58933
|
+
class: CortexcodeSkill,
|
|
58934
|
+
meta: {
|
|
58935
|
+
supportsProject: true,
|
|
58936
|
+
supportsSimulated: false,
|
|
58937
|
+
supportsGlobal: true
|
|
58938
|
+
}
|
|
58939
|
+
}],
|
|
55957
58940
|
["crush", {
|
|
55958
58941
|
class: CrushSkill,
|
|
55959
58942
|
meta: {
|
|
@@ -56131,6 +59114,14 @@ const toolSkillFactories = /* @__PURE__ */ new Map([
|
|
|
56131
59114
|
supportsGlobal: true
|
|
56132
59115
|
}
|
|
56133
59116
|
}],
|
|
59117
|
+
["tabnine", {
|
|
59118
|
+
class: TabnineSkill,
|
|
59119
|
+
meta: {
|
|
59120
|
+
supportsProject: true,
|
|
59121
|
+
supportsSimulated: false,
|
|
59122
|
+
supportsGlobal: true
|
|
59123
|
+
}
|
|
59124
|
+
}],
|
|
56134
59125
|
["takt", {
|
|
56135
59126
|
class: TaktSkill,
|
|
56136
59127
|
meta: {
|
|
@@ -58325,6 +61316,135 @@ var CopilotcliSubagent = class CopilotcliSubagent extends ToolSubagent {
|
|
|
58325
61316
|
}
|
|
58326
61317
|
};
|
|
58327
61318
|
//#endregion
|
|
61319
|
+
//#region src/features/subagents/cortexcode-subagent.ts
|
|
61320
|
+
const CortexcodeSubagentFrontmatterSchema = zod_mini.z.looseObject({
|
|
61321
|
+
name: zod_mini.z.string(),
|
|
61322
|
+
description: zod_mini.z.optional(zod_mini.z.string()),
|
|
61323
|
+
/** Tool names the subagent may use; omitted = every tool. */
|
|
61324
|
+
tools: zod_mini.z.optional(zod_mini.z.array(zod_mini.z.string())),
|
|
61325
|
+
model: zod_mini.z.optional(zod_mini.z.string())
|
|
61326
|
+
});
|
|
61327
|
+
/**
|
|
61328
|
+
* Snowflake Cortex Code subagent: a Markdown file with YAML frontmatter under
|
|
61329
|
+
* `.cortex/agents/` (project) or `~/.snowflake/cortex/agents/` (user).
|
|
61330
|
+
*/
|
|
61331
|
+
var CortexcodeSubagent = class CortexcodeSubagent extends ToolSubagent {
|
|
61332
|
+
frontmatter;
|
|
61333
|
+
body;
|
|
61334
|
+
constructor({ frontmatter, body, fileContent, ...rest }) {
|
|
61335
|
+
if (rest.validate !== false) {
|
|
61336
|
+
const result = CortexcodeSubagentFrontmatterSchema.safeParse(frontmatter);
|
|
61337
|
+
if (!result.success) throw new Error(`Invalid frontmatter in ${(0, node_path.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`);
|
|
61338
|
+
}
|
|
61339
|
+
super({
|
|
61340
|
+
...rest,
|
|
61341
|
+
fileContent: fileContent ?? stringifyFrontmatter(body, frontmatter)
|
|
61342
|
+
});
|
|
61343
|
+
this.frontmatter = frontmatter;
|
|
61344
|
+
this.body = body;
|
|
61345
|
+
}
|
|
61346
|
+
static getSettablePaths({ global = false } = {}) {
|
|
61347
|
+
return { relativeDirPath: global ? CORTEXCODE_GLOBAL_AGENTS_DIR_PATH : CORTEXCODE_AGENTS_DIR_PATH };
|
|
61348
|
+
}
|
|
61349
|
+
getFrontmatter() {
|
|
61350
|
+
return this.frontmatter;
|
|
61351
|
+
}
|
|
61352
|
+
getBody() {
|
|
61353
|
+
return this.body;
|
|
61354
|
+
}
|
|
61355
|
+
toRulesyncSubagent() {
|
|
61356
|
+
const { name, description, ...rest } = this.frontmatter;
|
|
61357
|
+
return new RulesyncSubagent({
|
|
61358
|
+
outputRoot: ".",
|
|
61359
|
+
frontmatter: {
|
|
61360
|
+
targets: ["*"],
|
|
61361
|
+
name,
|
|
61362
|
+
description,
|
|
61363
|
+
cortexcode: { ...rest }
|
|
61364
|
+
},
|
|
61365
|
+
body: this.body,
|
|
61366
|
+
relativeDirPath: RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH,
|
|
61367
|
+
relativeFilePath: this.getRelativeFilePath(),
|
|
61368
|
+
validate: true
|
|
61369
|
+
});
|
|
61370
|
+
}
|
|
61371
|
+
static fromRulesyncSubagent({ outputRoot = process.cwd(), rulesyncSubagent, validate = true, global = false }) {
|
|
61372
|
+
const rulesyncFrontmatter = rulesyncSubagent.getFrontmatter();
|
|
61373
|
+
const cortexcodeSection = rulesyncFrontmatter.cortexcode ?? {};
|
|
61374
|
+
const cortexcodeSubagentFrontmatter = {
|
|
61375
|
+
name: rulesyncFrontmatter.name,
|
|
61376
|
+
description: rulesyncFrontmatter.description,
|
|
61377
|
+
...cortexcodeSection
|
|
61378
|
+
};
|
|
61379
|
+
const body = rulesyncSubagent.getBody();
|
|
61380
|
+
const fileContent = stringifyFrontmatter(body, cortexcodeSubagentFrontmatter, { avoidBlockScalars: true });
|
|
61381
|
+
const paths = this.getSettablePaths({ global });
|
|
61382
|
+
return new CortexcodeSubagent({
|
|
61383
|
+
outputRoot,
|
|
61384
|
+
frontmatter: cortexcodeSubagentFrontmatter,
|
|
61385
|
+
body,
|
|
61386
|
+
relativeDirPath: paths.relativeDirPath,
|
|
61387
|
+
relativeFilePath: rulesyncSubagent.getRelativeFilePath(),
|
|
61388
|
+
fileContent,
|
|
61389
|
+
validate,
|
|
61390
|
+
global
|
|
61391
|
+
});
|
|
61392
|
+
}
|
|
61393
|
+
validate() {
|
|
61394
|
+
if (!this.frontmatter) return {
|
|
61395
|
+
success: true,
|
|
61396
|
+
error: null
|
|
61397
|
+
};
|
|
61398
|
+
const result = CortexcodeSubagentFrontmatterSchema.safeParse(this.frontmatter);
|
|
61399
|
+
if (result.success) return {
|
|
61400
|
+
success: true,
|
|
61401
|
+
error: null
|
|
61402
|
+
};
|
|
61403
|
+
else return {
|
|
61404
|
+
success: false,
|
|
61405
|
+
error: /* @__PURE__ */ new Error(`Invalid frontmatter in ${(0, node_path.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`)
|
|
61406
|
+
};
|
|
61407
|
+
}
|
|
61408
|
+
static isTargetedByRulesyncSubagent(rulesyncSubagent) {
|
|
61409
|
+
return this.isTargetedByRulesyncSubagentDefault({
|
|
61410
|
+
rulesyncSubagent,
|
|
61411
|
+
toolTarget: "cortexcode"
|
|
61412
|
+
});
|
|
61413
|
+
}
|
|
61414
|
+
static async fromFile({ outputRoot = process.cwd(), relativeFilePath, validate = true, global = false }) {
|
|
61415
|
+
const paths = this.getSettablePaths({ global });
|
|
61416
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, relativeFilePath);
|
|
61417
|
+
const fileContent = await readFileContent(filePath);
|
|
61418
|
+
const { frontmatter, body: content } = parseFrontmatter(fileContent, filePath);
|
|
61419
|
+
const result = CortexcodeSubagentFrontmatterSchema.safeParse(frontmatter);
|
|
61420
|
+
if (!result.success) throw new Error(`Invalid frontmatter in ${filePath}: ${formatError(result.error)}`);
|
|
61421
|
+
return new CortexcodeSubagent({
|
|
61422
|
+
outputRoot,
|
|
61423
|
+
relativeDirPath: paths.relativeDirPath,
|
|
61424
|
+
relativeFilePath,
|
|
61425
|
+
frontmatter: result.data,
|
|
61426
|
+
body: content.trim(),
|
|
61427
|
+
fileContent,
|
|
61428
|
+
validate,
|
|
61429
|
+
global
|
|
61430
|
+
});
|
|
61431
|
+
}
|
|
61432
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
|
|
61433
|
+
return new CortexcodeSubagent({
|
|
61434
|
+
outputRoot,
|
|
61435
|
+
relativeDirPath,
|
|
61436
|
+
relativeFilePath,
|
|
61437
|
+
frontmatter: {
|
|
61438
|
+
name: "",
|
|
61439
|
+
description: ""
|
|
61440
|
+
},
|
|
61441
|
+
body: "",
|
|
61442
|
+
fileContent: "",
|
|
61443
|
+
validate: false
|
|
61444
|
+
});
|
|
61445
|
+
}
|
|
61446
|
+
};
|
|
61447
|
+
//#endregion
|
|
58328
61448
|
//#region src/features/subagents/cursor-subagent.ts
|
|
58329
61449
|
const CursorSubagentFrontmatterSchema = zod_mini.z.looseObject({
|
|
58330
61450
|
name: zod_mini.z.string(),
|
|
@@ -60777,6 +63897,145 @@ var RooSubagent = class extends ToolSubagent {
|
|
|
60777
63897
|
}
|
|
60778
63898
|
};
|
|
60779
63899
|
//#endregion
|
|
63900
|
+
//#region src/features/subagents/tabnine-subagent.ts
|
|
63901
|
+
const TabnineSubagentFrontmatterSchema = zod_mini.z.looseObject({
|
|
63902
|
+
name: zod_mini.z.string(),
|
|
63903
|
+
description: zod_mini.z.optional(zod_mini.z.string()),
|
|
63904
|
+
/** "local" (default) runs inside the CLI; "remote" delegates to a Tabnine cloud agent. */
|
|
63905
|
+
kind: zod_mini.z.optional(zod_mini.z.string()),
|
|
63906
|
+
/** Built-in tool names the subagent may use; omitted = every tool. */
|
|
63907
|
+
tools: zod_mini.z.optional(zod_mini.z.array(zod_mini.z.string())),
|
|
63908
|
+
model: zod_mini.z.optional(zod_mini.z.string()),
|
|
63909
|
+
/** Sampling temperature, 0.0-2.0. */
|
|
63910
|
+
temperature: zod_mini.z.optional(zod_mini.z.number()),
|
|
63911
|
+
/** Maximum agent turns (Tabnine default: 15). */
|
|
63912
|
+
max_turns: zod_mini.z.optional(zod_mini.z.number()),
|
|
63913
|
+
/** Wall-clock budget in minutes (Tabnine default: 5). */
|
|
63914
|
+
timeout_mins: zod_mini.z.optional(zod_mini.z.number())
|
|
63915
|
+
});
|
|
63916
|
+
/**
|
|
63917
|
+
* Tabnine CLI subagent: a Markdown file with YAML frontmatter under
|
|
63918
|
+
* `.tabnine/agent/agents/` (project) or `~/.tabnine/agent/agents/` (user).
|
|
63919
|
+
* Tabnine only loads these when `experimental.enableAgents` is `true` in its
|
|
63920
|
+
* settings; rulesync writes the files and leaves that flag to the user.
|
|
63921
|
+
*/
|
|
63922
|
+
var TabnineSubagent = class TabnineSubagent extends ToolSubagent {
|
|
63923
|
+
frontmatter;
|
|
63924
|
+
body;
|
|
63925
|
+
constructor({ frontmatter, body, fileContent, ...rest }) {
|
|
63926
|
+
if (rest.validate !== false) {
|
|
63927
|
+
const result = TabnineSubagentFrontmatterSchema.safeParse(frontmatter);
|
|
63928
|
+
if (!result.success) throw new Error(`Invalid frontmatter in ${(0, node_path.join)(rest.relativeDirPath, rest.relativeFilePath)}: ${formatError(result.error)}`);
|
|
63929
|
+
}
|
|
63930
|
+
super({
|
|
63931
|
+
...rest,
|
|
63932
|
+
fileContent: fileContent ?? stringifyFrontmatter(body, frontmatter)
|
|
63933
|
+
});
|
|
63934
|
+
this.frontmatter = frontmatter;
|
|
63935
|
+
this.body = body;
|
|
63936
|
+
}
|
|
63937
|
+
static getSettablePaths(_options = {}) {
|
|
63938
|
+
return { relativeDirPath: TABNINE_AGENTS_DIR_PATH };
|
|
63939
|
+
}
|
|
63940
|
+
getFrontmatter() {
|
|
63941
|
+
return this.frontmatter;
|
|
63942
|
+
}
|
|
63943
|
+
getBody() {
|
|
63944
|
+
return this.body;
|
|
63945
|
+
}
|
|
63946
|
+
toRulesyncSubagent() {
|
|
63947
|
+
const { name, description, ...rest } = this.frontmatter;
|
|
63948
|
+
return new RulesyncSubagent({
|
|
63949
|
+
outputRoot: ".",
|
|
63950
|
+
frontmatter: {
|
|
63951
|
+
targets: ["*"],
|
|
63952
|
+
name,
|
|
63953
|
+
description,
|
|
63954
|
+
tabnine: { ...rest }
|
|
63955
|
+
},
|
|
63956
|
+
body: this.body,
|
|
63957
|
+
relativeDirPath: RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH,
|
|
63958
|
+
relativeFilePath: this.getRelativeFilePath(),
|
|
63959
|
+
validate: true
|
|
63960
|
+
});
|
|
63961
|
+
}
|
|
63962
|
+
static fromRulesyncSubagent({ outputRoot = process.cwd(), rulesyncSubagent, validate = true, global = false }) {
|
|
63963
|
+
const rulesyncFrontmatter = rulesyncSubagent.getFrontmatter();
|
|
63964
|
+
const tabnineSection = rulesyncFrontmatter.tabnine ?? {};
|
|
63965
|
+
const tabnineSubagentFrontmatter = {
|
|
63966
|
+
name: rulesyncFrontmatter.name,
|
|
63967
|
+
description: rulesyncFrontmatter.description,
|
|
63968
|
+
...tabnineSection
|
|
63969
|
+
};
|
|
63970
|
+
const body = rulesyncSubagent.getBody();
|
|
63971
|
+
const fileContent = stringifyFrontmatter(body, tabnineSubagentFrontmatter, { avoidBlockScalars: true });
|
|
63972
|
+
const paths = this.getSettablePaths({ global });
|
|
63973
|
+
return new TabnineSubagent({
|
|
63974
|
+
outputRoot,
|
|
63975
|
+
frontmatter: tabnineSubagentFrontmatter,
|
|
63976
|
+
body,
|
|
63977
|
+
relativeDirPath: paths.relativeDirPath,
|
|
63978
|
+
relativeFilePath: rulesyncSubagent.getRelativeFilePath(),
|
|
63979
|
+
fileContent,
|
|
63980
|
+
validate,
|
|
63981
|
+
global
|
|
63982
|
+
});
|
|
63983
|
+
}
|
|
63984
|
+
validate() {
|
|
63985
|
+
if (!this.frontmatter) return {
|
|
63986
|
+
success: true,
|
|
63987
|
+
error: null
|
|
63988
|
+
};
|
|
63989
|
+
const result = TabnineSubagentFrontmatterSchema.safeParse(this.frontmatter);
|
|
63990
|
+
if (result.success) return {
|
|
63991
|
+
success: true,
|
|
63992
|
+
error: null
|
|
63993
|
+
};
|
|
63994
|
+
else return {
|
|
63995
|
+
success: false,
|
|
63996
|
+
error: /* @__PURE__ */ new Error(`Invalid frontmatter in ${(0, node_path.join)(this.relativeDirPath, this.relativeFilePath)}: ${formatError(result.error)}`)
|
|
63997
|
+
};
|
|
63998
|
+
}
|
|
63999
|
+
static isTargetedByRulesyncSubagent(rulesyncSubagent) {
|
|
64000
|
+
return this.isTargetedByRulesyncSubagentDefault({
|
|
64001
|
+
rulesyncSubagent,
|
|
64002
|
+
toolTarget: "tabnine"
|
|
64003
|
+
});
|
|
64004
|
+
}
|
|
64005
|
+
static async fromFile({ outputRoot = process.cwd(), relativeFilePath, validate = true, global = false }) {
|
|
64006
|
+
const paths = this.getSettablePaths({ global });
|
|
64007
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, relativeFilePath);
|
|
64008
|
+
const fileContent = await readFileContent(filePath);
|
|
64009
|
+
const { frontmatter, body: content } = parseFrontmatter(fileContent, filePath);
|
|
64010
|
+
const result = TabnineSubagentFrontmatterSchema.safeParse(frontmatter);
|
|
64011
|
+
if (!result.success) throw new Error(`Invalid frontmatter in ${filePath}: ${formatError(result.error)}`);
|
|
64012
|
+
return new TabnineSubagent({
|
|
64013
|
+
outputRoot,
|
|
64014
|
+
relativeDirPath: paths.relativeDirPath,
|
|
64015
|
+
relativeFilePath,
|
|
64016
|
+
frontmatter: result.data,
|
|
64017
|
+
body: content.trim(),
|
|
64018
|
+
fileContent,
|
|
64019
|
+
validate,
|
|
64020
|
+
global
|
|
64021
|
+
});
|
|
64022
|
+
}
|
|
64023
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
|
|
64024
|
+
return new TabnineSubagent({
|
|
64025
|
+
outputRoot,
|
|
64026
|
+
relativeDirPath,
|
|
64027
|
+
relativeFilePath,
|
|
64028
|
+
frontmatter: {
|
|
64029
|
+
name: "",
|
|
64030
|
+
description: ""
|
|
64031
|
+
},
|
|
64032
|
+
body: "",
|
|
64033
|
+
fileContent: "",
|
|
64034
|
+
validate: false
|
|
64035
|
+
});
|
|
64036
|
+
}
|
|
64037
|
+
};
|
|
64038
|
+
//#endregion
|
|
60780
64039
|
//#region src/features/subagents/takt-subagent.ts
|
|
60781
64040
|
/**
|
|
60782
64041
|
* Subagent generator for TAKT.
|
|
@@ -61408,6 +64667,15 @@ const toolSubagentFactories = /* @__PURE__ */ new Map([
|
|
|
61408
64667
|
filePattern: "*.agent.md"
|
|
61409
64668
|
}
|
|
61410
64669
|
}],
|
|
64670
|
+
["cortexcode", {
|
|
64671
|
+
class: CortexcodeSubagent,
|
|
64672
|
+
meta: {
|
|
64673
|
+
supportsProject: true,
|
|
64674
|
+
supportsSimulated: false,
|
|
64675
|
+
supportsGlobal: true,
|
|
64676
|
+
filePattern: "*.md"
|
|
64677
|
+
}
|
|
64678
|
+
}],
|
|
61411
64679
|
["cursor", {
|
|
61412
64680
|
class: CursorSubagent,
|
|
61413
64681
|
meta: {
|
|
@@ -61579,6 +64847,15 @@ const toolSubagentFactories = /* @__PURE__ */ new Map([
|
|
|
61579
64847
|
filePattern: "*.md"
|
|
61580
64848
|
}
|
|
61581
64849
|
}],
|
|
64850
|
+
["tabnine", {
|
|
64851
|
+
class: TabnineSubagent,
|
|
64852
|
+
meta: {
|
|
64853
|
+
supportsProject: true,
|
|
64854
|
+
supportsSimulated: false,
|
|
64855
|
+
supportsGlobal: true,
|
|
64856
|
+
filePattern: "*.md"
|
|
64857
|
+
}
|
|
64858
|
+
}],
|
|
61582
64859
|
["takt", {
|
|
61583
64860
|
class: TaktSubagent,
|
|
61584
64861
|
meta: {
|
|
@@ -63130,6 +66407,95 @@ var AugmentcodeRule = class AugmentcodeRule extends ToolRule {
|
|
|
63130
66407
|
}
|
|
63131
66408
|
};
|
|
63132
66409
|
//#endregion
|
|
66410
|
+
//#region src/features/rules/bob-rule.ts
|
|
66411
|
+
/**
|
|
66412
|
+
* Rule generator for IBM Bob (Bob IDE and Bob Shell).
|
|
66413
|
+
*
|
|
66414
|
+
* Bob auto-loads plain-markdown instruction files with no frontmatter:
|
|
66415
|
+
*
|
|
66416
|
+
* - Project scope: the cross-tool `AGENTS.md` at the project root plus every
|
|
66417
|
+
* `.bob/rules/*.md` file (read recursively in alphabetical order).
|
|
66418
|
+
* - Global scope: `~/.bob/AGENTS.md` plus `~/.bob/rules/*.md`.
|
|
66419
|
+
*
|
|
66420
|
+
* The workspace files override the user files. Bob's mode-specific
|
|
66421
|
+
* `.bob/rules-{mode}/` directories are left alone: rulesync has no notion of
|
|
66422
|
+
* Bob's modes, and a rule that should apply everywhere belongs in `.bob/rules/`.
|
|
66423
|
+
*
|
|
66424
|
+
* @see https://bob.ibm.com/docs/ide/configuration/rules
|
|
66425
|
+
* @see https://bob.ibm.com/docs/shell/configuration/configuring (user-scoped `~/.bob/AGENTS.md`)
|
|
66426
|
+
*/
|
|
66427
|
+
var BobRule = class BobRule extends ToolRule {
|
|
66428
|
+
static getSettablePaths({ global, excludeToolDir } = {}) {
|
|
66429
|
+
return {
|
|
66430
|
+
root: {
|
|
66431
|
+
relativeDirPath: global ? buildToolPath(BOB_DIR, ".", excludeToolDir) : ".",
|
|
66432
|
+
relativeFilePath: BOB_RULE_FILE_NAME
|
|
66433
|
+
},
|
|
66434
|
+
nonRoot: { relativeDirPath: buildToolPath(BOB_DIR, "rules", excludeToolDir) }
|
|
66435
|
+
};
|
|
66436
|
+
}
|
|
66437
|
+
static async fromFile({ outputRoot = process.cwd(), relativeFilePath, validate = true, global = false }) {
|
|
66438
|
+
const paths = this.getSettablePaths({ global });
|
|
66439
|
+
if (relativeFilePath === paths.root.relativeFilePath) {
|
|
66440
|
+
const fileContent = await readFileContent((0, node_path.join)(outputRoot, paths.root.relativeDirPath, paths.root.relativeFilePath));
|
|
66441
|
+
return new BobRule({
|
|
66442
|
+
outputRoot,
|
|
66443
|
+
relativeDirPath: paths.root.relativeDirPath,
|
|
66444
|
+
relativeFilePath: paths.root.relativeFilePath,
|
|
66445
|
+
fileContent,
|
|
66446
|
+
validate,
|
|
66447
|
+
root: true
|
|
66448
|
+
});
|
|
66449
|
+
}
|
|
66450
|
+
const fileContent = await readFileContent((0, node_path.join)(outputRoot, paths.nonRoot.relativeDirPath, relativeFilePath));
|
|
66451
|
+
return new BobRule({
|
|
66452
|
+
outputRoot,
|
|
66453
|
+
relativeDirPath: paths.nonRoot.relativeDirPath,
|
|
66454
|
+
relativeFilePath,
|
|
66455
|
+
fileContent,
|
|
66456
|
+
validate,
|
|
66457
|
+
root: false
|
|
66458
|
+
});
|
|
66459
|
+
}
|
|
66460
|
+
static fromRulesyncRule({ outputRoot = process.cwd(), rulesyncRule, validate = true, global = false }) {
|
|
66461
|
+
const paths = this.getSettablePaths({ global });
|
|
66462
|
+
return new BobRule(this.buildToolRuleParamsDefault({
|
|
66463
|
+
outputRoot,
|
|
66464
|
+
rulesyncRule,
|
|
66465
|
+
validate,
|
|
66466
|
+
rootPath: paths.root,
|
|
66467
|
+
nonRootPath: paths.nonRoot
|
|
66468
|
+
}));
|
|
66469
|
+
}
|
|
66470
|
+
toRulesyncRule() {
|
|
66471
|
+
return this.toRulesyncRuleDefault();
|
|
66472
|
+
}
|
|
66473
|
+
validate() {
|
|
66474
|
+
return {
|
|
66475
|
+
success: true,
|
|
66476
|
+
error: null
|
|
66477
|
+
};
|
|
66478
|
+
}
|
|
66479
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
|
|
66480
|
+
const paths = this.getSettablePaths({ global });
|
|
66481
|
+
const isRoot = relativeFilePath === paths.root.relativeFilePath && relativeDirPath !== paths.nonRoot.relativeDirPath;
|
|
66482
|
+
return new BobRule({
|
|
66483
|
+
outputRoot,
|
|
66484
|
+
relativeDirPath,
|
|
66485
|
+
relativeFilePath,
|
|
66486
|
+
fileContent: "",
|
|
66487
|
+
validate: false,
|
|
66488
|
+
root: isRoot
|
|
66489
|
+
});
|
|
66490
|
+
}
|
|
66491
|
+
static isTargetedByRulesyncRule(rulesyncRule) {
|
|
66492
|
+
return this.isTargetedByRulesyncRuleDefault({
|
|
66493
|
+
rulesyncRule,
|
|
66494
|
+
toolTarget: "bob"
|
|
66495
|
+
});
|
|
66496
|
+
}
|
|
66497
|
+
};
|
|
66498
|
+
//#endregion
|
|
63133
66499
|
//#region src/features/rules/claudecode-language-settings.ts
|
|
63134
66500
|
/**
|
|
63135
66501
|
* Claude Code's native home for the root `language` key of `rulesync.jsonc`.
|
|
@@ -64344,6 +67710,73 @@ var CopilotcliRule = class CopilotcliRule extends CopilotRule {
|
|
|
64344
67710
|
}
|
|
64345
67711
|
};
|
|
64346
67712
|
//#endregion
|
|
67713
|
+
//#region src/features/rules/cortexcode-rule.ts
|
|
67714
|
+
var CortexcodeRule = class CortexcodeRule extends ToolRule {
|
|
67715
|
+
constructor({ fileContent, root, ...rest }) {
|
|
67716
|
+
super({
|
|
67717
|
+
...rest,
|
|
67718
|
+
fileContent,
|
|
67719
|
+
root: root ?? false
|
|
67720
|
+
});
|
|
67721
|
+
}
|
|
67722
|
+
static getSettablePaths(_options = {}) {
|
|
67723
|
+
return { root: {
|
|
67724
|
+
relativeDirPath: ".",
|
|
67725
|
+
relativeFilePath: CORTEXCODE_RULE_FILE_NAME
|
|
67726
|
+
} };
|
|
67727
|
+
}
|
|
67728
|
+
static async fromFile({ outputRoot = process.cwd(), relativeFilePath: _relativeFilePath, validate = true, global = false }) {
|
|
67729
|
+
const { root } = this.getSettablePaths({ global });
|
|
67730
|
+
const relativePath = (0, node_path.join)(root.relativeDirPath, root.relativeFilePath);
|
|
67731
|
+
const fileContent = await readFileContent((0, node_path.join)(outputRoot, relativePath));
|
|
67732
|
+
return new CortexcodeRule({
|
|
67733
|
+
outputRoot,
|
|
67734
|
+
relativeDirPath: root.relativeDirPath,
|
|
67735
|
+
relativeFilePath: root.relativeFilePath,
|
|
67736
|
+
fileContent,
|
|
67737
|
+
validate,
|
|
67738
|
+
root: true
|
|
67739
|
+
});
|
|
67740
|
+
}
|
|
67741
|
+
static fromRulesyncRule({ outputRoot = process.cwd(), rulesyncRule, validate = true, global = false }) {
|
|
67742
|
+
const { root } = this.getSettablePaths({ global });
|
|
67743
|
+
const isRoot = rulesyncRule.getFrontmatter().root ?? false;
|
|
67744
|
+
return new CortexcodeRule({
|
|
67745
|
+
outputRoot,
|
|
67746
|
+
relativeDirPath: root.relativeDirPath,
|
|
67747
|
+
relativeFilePath: root.relativeFilePath,
|
|
67748
|
+
fileContent: rulesyncRule.getBody(),
|
|
67749
|
+
validate,
|
|
67750
|
+
root: isRoot
|
|
67751
|
+
});
|
|
67752
|
+
}
|
|
67753
|
+
toRulesyncRule() {
|
|
67754
|
+
return this.toRulesyncRuleDefault();
|
|
67755
|
+
}
|
|
67756
|
+
validate() {
|
|
67757
|
+
return {
|
|
67758
|
+
success: true,
|
|
67759
|
+
error: null
|
|
67760
|
+
};
|
|
67761
|
+
}
|
|
67762
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
|
|
67763
|
+
return new CortexcodeRule({
|
|
67764
|
+
outputRoot,
|
|
67765
|
+
relativeDirPath,
|
|
67766
|
+
relativeFilePath,
|
|
67767
|
+
fileContent: "",
|
|
67768
|
+
validate: false,
|
|
67769
|
+
root: relativeFilePath === "AGENTS.md" && relativeDirPath === "."
|
|
67770
|
+
});
|
|
67771
|
+
}
|
|
67772
|
+
static isTargetedByRulesyncRule(rulesyncRule) {
|
|
67773
|
+
return this.isTargetedByRulesyncRuleDefault({
|
|
67774
|
+
rulesyncRule,
|
|
67775
|
+
toolTarget: "cortexcode"
|
|
67776
|
+
});
|
|
67777
|
+
}
|
|
67778
|
+
};
|
|
67779
|
+
//#endregion
|
|
64347
67780
|
//#region src/features/rules/crush-rule.ts
|
|
64348
67781
|
var CrushRule = class CrushRule extends ToolRule {
|
|
64349
67782
|
constructor({ fileContent, root, ...rest }) {
|
|
@@ -67421,6 +70854,97 @@ var RovodevRule = class RovodevRule extends ToolRule {
|
|
|
67421
70854
|
}
|
|
67422
70855
|
};
|
|
67423
70856
|
//#endregion
|
|
70857
|
+
//#region src/features/rules/tabnine-rule.ts
|
|
70858
|
+
/**
|
|
70859
|
+
* Rule generator for Tabnine CLI.
|
|
70860
|
+
*
|
|
70861
|
+
* - Project scope: `TABNINE.md` at the project root is the CLI's memory file
|
|
70862
|
+
* (loaded on every session, refreshed with `/memory reload`). Non-root
|
|
70863
|
+
* rules go to `.tabnine/guidelines/*.md`, the guideline directory the
|
|
70864
|
+
* Tabnine IDE agent reads; the CLI does not auto-load that directory, so
|
|
70865
|
+
* the processor lists the files from `TABNINE.md` (toon mode).
|
|
70866
|
+
* - Global scope: `~/.tabnine/agent/TABNINE.md` next to the other user-scoped
|
|
70867
|
+
* agent assets (the CLI documents no user-level memory file, so this path
|
|
70868
|
+
* mirrors the `~/.gemini/GEMINI.md` convention of the Gemini CLI it is
|
|
70869
|
+
* derived from) plus `~/.tabnine/guidelines/*.md`.
|
|
70870
|
+
*
|
|
70871
|
+
* Rule files are plain Markdown without frontmatter.
|
|
70872
|
+
*
|
|
70873
|
+
* @see https://docs.tabnine.com/main/getting-started/tabnine-cli/features/settings/settings-reference (`context.fileName`, `/memory`)
|
|
70874
|
+
* @see https://docs.tabnine.com/main/getting-started/tabnine-agent/guidelines (`.tabnine/guidelines/`)
|
|
70875
|
+
*/
|
|
70876
|
+
var TabnineRule = class TabnineRule extends ToolRule {
|
|
70877
|
+
static getSettablePaths({ global, excludeToolDir } = {}) {
|
|
70878
|
+
return {
|
|
70879
|
+
root: {
|
|
70880
|
+
relativeDirPath: global ? buildToolPath(TABNINE_AGENT_DIR_PATH, ".", excludeToolDir) : ".",
|
|
70881
|
+
relativeFilePath: TABNINE_RULE_FILE_NAME
|
|
70882
|
+
},
|
|
70883
|
+
nonRoot: { relativeDirPath: buildToolPath(TABNINE_DIR, "guidelines", excludeToolDir) }
|
|
70884
|
+
};
|
|
70885
|
+
}
|
|
70886
|
+
static async fromFile({ outputRoot = process.cwd(), relativeFilePath, validate = true, global = false }) {
|
|
70887
|
+
const paths = this.getSettablePaths({ global });
|
|
70888
|
+
if (relativeFilePath === paths.root.relativeFilePath) {
|
|
70889
|
+
const fileContent = await readFileContent((0, node_path.join)(outputRoot, paths.root.relativeDirPath, paths.root.relativeFilePath));
|
|
70890
|
+
return new TabnineRule({
|
|
70891
|
+
outputRoot,
|
|
70892
|
+
relativeDirPath: paths.root.relativeDirPath,
|
|
70893
|
+
relativeFilePath: paths.root.relativeFilePath,
|
|
70894
|
+
fileContent,
|
|
70895
|
+
validate,
|
|
70896
|
+
root: true
|
|
70897
|
+
});
|
|
70898
|
+
}
|
|
70899
|
+
const fileContent = await readFileContent((0, node_path.join)(outputRoot, paths.nonRoot.relativeDirPath, relativeFilePath));
|
|
70900
|
+
return new TabnineRule({
|
|
70901
|
+
outputRoot,
|
|
70902
|
+
relativeDirPath: paths.nonRoot.relativeDirPath,
|
|
70903
|
+
relativeFilePath,
|
|
70904
|
+
fileContent,
|
|
70905
|
+
validate,
|
|
70906
|
+
root: false
|
|
70907
|
+
});
|
|
70908
|
+
}
|
|
70909
|
+
static fromRulesyncRule({ outputRoot = process.cwd(), rulesyncRule, validate = true, global = false }) {
|
|
70910
|
+
const paths = this.getSettablePaths({ global });
|
|
70911
|
+
return new TabnineRule(this.buildToolRuleParamsDefault({
|
|
70912
|
+
outputRoot,
|
|
70913
|
+
rulesyncRule,
|
|
70914
|
+
validate,
|
|
70915
|
+
rootPath: paths.root,
|
|
70916
|
+
nonRootPath: paths.nonRoot
|
|
70917
|
+
}));
|
|
70918
|
+
}
|
|
70919
|
+
toRulesyncRule() {
|
|
70920
|
+
return this.toRulesyncRuleDefault();
|
|
70921
|
+
}
|
|
70922
|
+
validate() {
|
|
70923
|
+
return {
|
|
70924
|
+
success: true,
|
|
70925
|
+
error: null
|
|
70926
|
+
};
|
|
70927
|
+
}
|
|
70928
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
|
|
70929
|
+
const paths = this.getSettablePaths({ global });
|
|
70930
|
+
const isRoot = relativeFilePath === paths.root.relativeFilePath && relativeDirPath !== paths.nonRoot.relativeDirPath;
|
|
70931
|
+
return new TabnineRule({
|
|
70932
|
+
outputRoot,
|
|
70933
|
+
relativeDirPath,
|
|
70934
|
+
relativeFilePath,
|
|
70935
|
+
fileContent: "",
|
|
70936
|
+
validate: false,
|
|
70937
|
+
root: isRoot
|
|
70938
|
+
});
|
|
70939
|
+
}
|
|
70940
|
+
static isTargetedByRulesyncRule(rulesyncRule) {
|
|
70941
|
+
return this.isTargetedByRulesyncRuleDefault({
|
|
70942
|
+
rulesyncRule,
|
|
70943
|
+
toolTarget: "tabnine"
|
|
70944
|
+
});
|
|
70945
|
+
}
|
|
70946
|
+
};
|
|
70947
|
+
//#endregion
|
|
67424
70948
|
//#region src/features/rules/takt-rule.ts
|
|
67425
70949
|
/**
|
|
67426
70950
|
* Default facet directory for TAKT rule files.
|
|
@@ -67983,6 +71507,14 @@ const toolRuleFactories = /* @__PURE__ */ new Map([
|
|
|
67983
71507
|
ruleDiscoveryMode: "toon"
|
|
67984
71508
|
}
|
|
67985
71509
|
}],
|
|
71510
|
+
["bob", {
|
|
71511
|
+
class: BobRule,
|
|
71512
|
+
meta: {
|
|
71513
|
+
extension: "md",
|
|
71514
|
+
supportsGlobal: true,
|
|
71515
|
+
ruleDiscoveryMode: "auto"
|
|
71516
|
+
}
|
|
71517
|
+
}],
|
|
67986
71518
|
["claudecode", {
|
|
67987
71519
|
class: ClaudecodeRule,
|
|
67988
71520
|
meta: {
|
|
@@ -68046,6 +71578,15 @@ const toolRuleFactories = /* @__PURE__ */ new Map([
|
|
|
68046
71578
|
ruleDiscoveryMode: "auto"
|
|
68047
71579
|
}
|
|
68048
71580
|
}],
|
|
71581
|
+
["cortexcode", {
|
|
71582
|
+
class: CortexcodeRule,
|
|
71583
|
+
meta: {
|
|
71584
|
+
extension: "md",
|
|
71585
|
+
supportsGlobal: false,
|
|
71586
|
+
ruleDiscoveryMode: "auto",
|
|
71587
|
+
collisionPolicy: "fold"
|
|
71588
|
+
}
|
|
71589
|
+
}],
|
|
68049
71590
|
["crush", {
|
|
68050
71591
|
class: CrushRule,
|
|
68051
71592
|
meta: {
|
|
@@ -68252,6 +71793,14 @@ const toolRuleFactories = /* @__PURE__ */ new Map([
|
|
|
68252
71793
|
localRootFileName: "AGENTS.local.md"
|
|
68253
71794
|
}
|
|
68254
71795
|
}],
|
|
71796
|
+
["tabnine", {
|
|
71797
|
+
class: TabnineRule,
|
|
71798
|
+
meta: {
|
|
71799
|
+
extension: "md",
|
|
71800
|
+
supportsGlobal: true,
|
|
71801
|
+
ruleDiscoveryMode: "toon"
|
|
71802
|
+
}
|
|
71803
|
+
}],
|
|
68255
71804
|
["takt", {
|
|
68256
71805
|
class: TaktRule,
|
|
68257
71806
|
meta: {
|
|
@@ -71889,6 +75438,18 @@ Object.defineProperty(exports, "RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH", {
|
|
|
71889
75438
|
return RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH;
|
|
71890
75439
|
}
|
|
71891
75440
|
});
|
|
75441
|
+
Object.defineProperty(exports, "RULESYNC_USER_CONFIG_DIR_NAME", {
|
|
75442
|
+
enumerable: true,
|
|
75443
|
+
get: function() {
|
|
75444
|
+
return RULESYNC_USER_CONFIG_DIR_NAME;
|
|
75445
|
+
}
|
|
75446
|
+
});
|
|
75447
|
+
Object.defineProperty(exports, "RULESYNC_XDG_CONFIG_HOME_DEFAULT_DIR_NAME", {
|
|
75448
|
+
enumerable: true,
|
|
75449
|
+
get: function() {
|
|
75450
|
+
return RULESYNC_XDG_CONFIG_HOME_DEFAULT_DIR_NAME;
|
|
75451
|
+
}
|
|
75452
|
+
});
|
|
71892
75453
|
Object.defineProperty(exports, "RulesProcessor", {
|
|
71893
75454
|
enumerable: true,
|
|
71894
75455
|
get: function() {
|
|
@@ -72039,6 +75600,12 @@ Object.defineProperty(exports, "assertDirectoryIfExists", {
|
|
|
72039
75600
|
return assertDirectoryIfExists;
|
|
72040
75601
|
}
|
|
72041
75602
|
});
|
|
75603
|
+
Object.defineProperty(exports, "assertTargetsFeaturesExclusive", {
|
|
75604
|
+
enumerable: true,
|
|
75605
|
+
get: function() {
|
|
75606
|
+
return assertTargetsFeaturesExclusive;
|
|
75607
|
+
}
|
|
75608
|
+
});
|
|
72042
75609
|
Object.defineProperty(exports, "assertTreeContainsNoSymlinks", {
|
|
72043
75610
|
enumerable: true,
|
|
72044
75611
|
get: function() {
|