@fitlab-ai/agent-infra 0.11.7 → 0.11.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/dist/bin/internal-cli.js +8 -2
  4. package/dist/lib/agent-clients/adapters/codex.js +1 -1
  5. package/dist/lib/agent-clients/config.js +11 -3
  6. package/dist/lib/agent-clients/custom-tool-invocations.js +92 -0
  7. package/dist/lib/agent-clients/next-steps.js +1 -1
  8. package/dist/lib/agent-clients/reconcile.js +3 -3
  9. package/dist/lib/agent-clients/schema.js +18 -10
  10. package/dist/lib/defaults.json +6 -3
  11. package/dist/lib/init.js +2 -2
  12. package/dist/lib/internal/agent-client.js +3 -3
  13. package/dist/lib/internal/cli-route-inventory.js +3 -0
  14. package/dist/lib/internal/platform-pr-review.js +20 -3
  15. package/dist/lib/internal/task-operation-registry.js +3 -1
  16. package/dist/lib/internal/task-platform-recovery.js +56 -0
  17. package/dist/lib/merge.js +25 -5
  18. package/dist/lib/platform/completion-backfill.js +2 -1
  19. package/dist/lib/platform/in-label-sync.js +12 -1
  20. package/dist/lib/platform/issue-comments.js +58 -4
  21. package/dist/lib/platform/issues.js +105 -5
  22. package/dist/lib/platform/operation-coordinator.js +74 -0
  23. package/dist/lib/platform/pr-review.js +107 -1
  24. package/dist/lib/platform/pr-summary.js +79 -57
  25. package/dist/lib/platform/pull-requests.js +96 -4
  26. package/dist/lib/sandbox/commands/create.js +6 -3
  27. package/dist/lib/sandbox/commands/ls.js +4 -3
  28. package/dist/lib/sandbox/commands/rm.js +1 -1
  29. package/dist/lib/sandbox/config.js +22 -4
  30. package/dist/lib/sandbox/git-metadata.js +50 -0
  31. package/dist/lib/sandbox/index.js +1 -1
  32. package/dist/lib/sandbox/mounts.js +12 -0
  33. package/dist/lib/sandbox/recovery.js +12 -22
  34. package/dist/lib/sandbox/removal.js +58 -20
  35. package/dist/lib/sandbox/tools.js +31 -7
  36. package/dist/lib/task/activity-intent.js +4 -3
  37. package/dist/lib/task/create-service.js +5 -3
  38. package/dist/lib/task/create.js +22 -5
  39. package/dist/lib/task/finalization-artifacts.js +4 -1
  40. package/dist/lib/task/finalization.js +243 -113
  41. package/dist/lib/task/lifecycle.js +38 -2
  42. package/dist/lib/task/platform-operation-journal.js +152 -0
  43. package/dist/lib/task/platform-operation-recovery.js +459 -0
  44. package/dist/lib/task/verification.js +0 -1
  45. package/dist/lib/task/workflow-warning-intents.js +7 -1
  46. package/dist/lib/update.js +2 -2
  47. package/dist/lifecycle-build-manifest.json +3 -3
  48. package/lib/agent-clients/adapters/codex.ts +1 -1
  49. package/lib/agent-clients/config.ts +9 -3
  50. package/lib/agent-clients/custom-tool-invocations.ts +129 -0
  51. package/lib/agent-clients/next-steps.ts +3 -3
  52. package/lib/agent-clients/reconcile.ts +3 -3
  53. package/lib/agent-clients/schema.ts +18 -10
  54. package/lib/defaults.json +6 -3
  55. package/lib/init.ts +2 -2
  56. package/lib/internal/agent-client.ts +3 -3
  57. package/lib/internal/cli-route-inventory.ts +2 -0
  58. package/lib/internal/platform-pr-review.ts +14 -3
  59. package/lib/internal/task-operation-registry.ts +3 -1
  60. package/lib/internal/task-platform-recovery.ts +53 -0
  61. package/lib/merge.ts +26 -6
  62. package/lib/platform/completion-backfill.ts +2 -1
  63. package/lib/platform/in-label-sync.ts +12 -0
  64. package/lib/platform/issue-comments.ts +59 -3
  65. package/lib/platform/issues.ts +103 -5
  66. package/lib/platform/operation-coordinator.ts +96 -0
  67. package/lib/platform/pr-review.ts +113 -1
  68. package/lib/platform/pr-summary.ts +22 -1
  69. package/lib/platform/pull-requests.ts +105 -5
  70. package/lib/sandbox/commands/create.ts +7 -8
  71. package/lib/sandbox/commands/ls.ts +4 -3
  72. package/lib/sandbox/commands/rm.ts +1 -1
  73. package/lib/sandbox/config.ts +23 -5
  74. package/lib/sandbox/git-metadata.ts +66 -0
  75. package/lib/sandbox/index.ts +1 -1
  76. package/lib/sandbox/mounts.ts +14 -0
  77. package/lib/sandbox/recovery.ts +13 -25
  78. package/lib/sandbox/removal.ts +57 -19
  79. package/lib/sandbox/tool-types.ts +2 -1
  80. package/lib/sandbox/tools.ts +38 -7
  81. package/lib/task/activity-intent.ts +4 -3
  82. package/lib/task/create-service.ts +5 -3
  83. package/lib/task/create.ts +17 -5
  84. package/lib/task/finalization-artifacts.ts +4 -1
  85. package/lib/task/finalization.ts +242 -106
  86. package/lib/task/lifecycle.ts +35 -3
  87. package/lib/task/platform-operation-journal.ts +230 -0
  88. package/lib/task/platform-operation-recovery.ts +435 -0
  89. package/lib/task/verification.ts +1 -2
  90. package/lib/task/workflow-warning-intents.ts +9 -1
  91. package/lib/update.ts +2 -3
  92. package/package.json +1 -1
  93. package/templates/.agents/README.en.md +20 -66
  94. package/templates/.agents/README.zh-CN.md +19 -65
  95. package/templates/.agents/rules/README.en.md +1 -1
  96. package/templates/.agents/rules/README.zh-CN.md +1 -1
  97. package/templates/.agents/rules/next-step-output.en.md +1 -1
  98. package/templates/.agents/rules/next-step-output.zh-CN.md +1 -1
  99. package/templates/.agents/rules/task-management.en.md +12 -0
  100. package/templates/.agents/rules/task-management.zh-CN.md +12 -0
  101. package/templates/.agents/scripts/lib/agent-infra-package.js +0 -7
  102. package/templates/.agents/skills/cancel-task/SKILL.en.md +4 -2
  103. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +4 -2
  104. package/templates/.agents/skills/code-task/SKILL.en.md +2 -2
  105. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +2 -2
  106. package/templates/.agents/skills/commit/SKILL.en.md +1 -1
  107. package/templates/.agents/skills/commit/SKILL.zh-CN.md +1 -1
  108. package/templates/.agents/skills/complete-task/SKILL.en.md +2 -0
  109. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +2 -0
  110. package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +1 -1
  111. package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +1 -1
  112. package/templates/.agents/skills/plan-task/config/verify.en.json +1 -1
  113. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +1 -1
  114. package/templates/.agents/skills/review-code/SKILL.en.md +1 -1
  115. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +1 -1
  116. package/templates/.agents/skills/review-code/reference/output-templates.en.md +15 -6
  117. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +15 -6
  118. package/templates/.agents/skills/review-pr/SKILL.en.md +11 -11
  119. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +11 -11
  120. package/templates/.agents/skills/review-pr/reference/output-guidance.en.md +3 -3
  121. package/templates/.agents/skills/review-pr/reference/output-guidance.zh-CN.md +3 -3
  122. package/templates/.agents/skills/review-pr/reference/report-template.en.md +4 -0
  123. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +4 -0
  124. package/templates/.agents/skills/update-agent-infra/SKILL.en.md +1 -1
  125. package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +1 -1
  126. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +21 -274
  127. package/dist/lib/agent-clients/custom-tuis.js +0 -99
  128. package/lib/agent-clients/custom-tuis.ts +0 -149
@@ -60,9 +60,12 @@ const DEFAULTS = {
60
60
  "runtimes": [
61
61
  "node22"
62
62
  ],
63
- "tools": [
64
- "agent-infra"
65
- ],
63
+ "tools": {
64
+ "ids": [
65
+ "agent-infra"
66
+ ],
67
+ "definitions": {}
68
+ },
66
69
  "refreshIntervalDays": 7,
67
70
  "dockerfile": null,
68
71
  "vm": {
@@ -222,17 +225,6 @@ const AGENT_CLIENT_MANIFEST = [
222
225
  }
223
226
  }
224
227
  ];
225
- const CUSTOM_TUI_CONTRACT = {
226
- "requiredFields": [
227
- "name",
228
- "dir",
229
- "invoke"
230
- ],
231
- "allowedPlaceholders": [
232
- "skillName",
233
- "projectName"
234
- ]
235
- };
236
228
  // Add a new identifier here only after shipping matching .{platform}. template variants.
237
229
  const KNOWN_PLATFORMS = new Set(['github', 'none']);
238
230
  const KNOWN_LANGUAGES = new Set(['en', 'zh-CN']);
@@ -334,10 +326,20 @@ function normalizeAgentClientConfig(cfg) {
334
326
  const sandbox = cfg.sandbox && typeof cfg.sandbox === 'object' && !Array.isArray(cfg.sandbox)
335
327
  ? cfg.sandbox
336
328
  : undefined;
337
- if (Array.isArray(sandbox?.tools)) {
338
- for (const [index, tool] of sandbox.tools.entries()) {
329
+ if (sandbox && own(sandbox, 'customTools')) {
330
+ return failure('INVALID_AGENT_CLIENTS', 'sandbox.customTools');
331
+ }
332
+ if (sandbox && own(sandbox, 'tools')) {
333
+ const tools = sandbox.tools;
334
+ if (!tools || typeof tools !== 'object' || Array.isArray(tools)) {
335
+ return failure('INVALID_AGENT_CLIENTS', 'sandbox.tools');
336
+ }
337
+ if (!Array.isArray(tools.ids)) {
338
+ return failure('INVALID_AGENT_CLIENTS', 'sandbox.tools.ids');
339
+ }
340
+ for (const [index, tool] of tools.ids.entries()) {
339
341
  if (AGENT_CLIENT_IDS.includes(tool)) {
340
- return failure('INVALID_AGENT_CLIENTS', `sandbox.tools[${index}]`);
342
+ return failure('INVALID_AGENT_CLIENTS', `sandbox.tools.ids[${index}]`);
341
343
  }
342
344
  }
343
345
  }
@@ -431,10 +433,6 @@ function trustedBaseline(value) {
431
433
  return typeof value === 'string' && /^sha256:[a-f0-9]{64}$/.test(value) ? value : null;
432
434
  }
433
435
 
434
- function normDir(p) {
435
- return norm(p).replace(/^\.\//, '').replace(/\/+$/, '');
436
- }
437
-
438
436
  function isInsideProject(projectRoot, relativePath) {
439
437
  if (typeof relativePath !== 'string' || relativePath.trim() === '' || path.isAbsolute(relativePath)) {
440
438
  return false;
@@ -594,14 +592,6 @@ function isCustomProtected(targetPath, customSkills, customCommandTargets) {
594
592
  )) || customCommandTargets.has(normalized);
595
593
  }
596
594
 
597
- function recordCustomTUISkipped(report, entry) {
598
- report?.custom?.customTUIs?.skipped?.push(entry);
599
- }
600
-
601
- function recordCustomTUISkippedRef(report, entry) {
602
- report?.custom?.customTUIs?.skippedRefs?.push(entry);
603
- }
604
-
605
595
  function expandHome(inputPath) {
606
596
  if (inputPath === '~') return os.homedir();
607
597
  if (inputPath.startsWith('~/')) {
@@ -843,204 +833,6 @@ function generateAgentClientCommand(skill, lang, descriptor) {
843
833
  return `${lines.join('\n')}\n`;
844
834
  }
845
835
 
846
- function validateCustomTUIs(projectRoot, customTUIs, report) {
847
- if (customTUIs === undefined) return [];
848
- if (!Array.isArray(customTUIs)) {
849
- recordCustomTUISkipped(report, {
850
- index: -1,
851
- name: '',
852
- dir: '',
853
- reason: 'customTUIs must be an array'
854
- });
855
- return [];
856
- }
857
- const tools = customTUIs;
858
- return tools
859
- .map((tool, index) => {
860
- if (
861
- typeof tool !== 'object'
862
- || tool === null
863
- || Array.isArray(tool)
864
- ) {
865
- recordCustomTUISkipped(report, {
866
- index,
867
- name: '',
868
- dir: '',
869
- reason: 'invalid custom TUI'
870
- });
871
- return null;
872
- }
873
-
874
- for (const field of CUSTOM_TUI_CONTRACT.requiredFields) {
875
- if (
876
- typeof tool[field] !== 'string'
877
- || tool[field].trim() === ''
878
- || /[\r\n]/.test(tool[field])
879
- ) {
880
- recordCustomTUISkipped(report, {
881
- index,
882
- name: String(tool.name || ''),
883
- dir: String(tool.dir || ''),
884
- reason: `invalid ${field}`
885
- });
886
- return null;
887
- }
888
- }
889
-
890
- if (typeof tool?.dir !== 'string' || tool.dir.trim() === '') {
891
- recordCustomTUISkipped(report, {
892
- index,
893
- name: String(tool?.name || ''),
894
- dir: String(tool?.dir || ''),
895
- reason: 'invalid dir'
896
- });
897
- return null;
898
- }
899
-
900
- if (tool.dir.includes('\\')) {
901
- recordCustomTUISkipped(report, {
902
- index,
903
- name: tool.name,
904
- dir: tool.dir,
905
- reason: 'dir must use POSIX separators'
906
- });
907
- return null;
908
- }
909
-
910
- if (!isInsideProject(projectRoot, tool.dir)) {
911
- recordCustomTUISkipped(report, {
912
- index,
913
- name: String(tool?.name || ''),
914
- dir: tool.dir,
915
- reason: 'dir must be a relative path inside the project root'
916
- });
917
- return null;
918
- }
919
-
920
- const placeholders = [...tool.invoke.matchAll(/\$\{([^}]+)\}/g)]
921
- .map((match) => match[1]);
922
- if (
923
- !placeholders.includes('skillName')
924
- || placeholders.some((placeholder) =>
925
- !CUSTOM_TUI_CONTRACT.allowedPlaceholders.includes(placeholder)
926
- )
927
- || tool.invoke
928
- .replaceAll('${skillName}', '')
929
- .replaceAll('${projectName}', '')
930
- .includes('${')
931
- ) {
932
- recordCustomTUISkipped(report, {
933
- index,
934
- name: tool.name,
935
- dir: tool.dir,
936
- reason: 'invalid invoke placeholders'
937
- });
938
- return null;
939
- }
940
-
941
- return { ...tool, index, dir: normDir(tool.dir) };
942
- })
943
- .filter(Boolean);
944
- }
945
-
946
- function customTUITargetPath(tool, refFile, refSkillName, skillName) {
947
- const targetFile = refFile.includes(refSkillName)
948
- ? refFile.replaceAll(refSkillName, skillName)
949
- : `${skillName}${path.extname(refFile)}`;
950
- return norm(path.join(tool.dir, targetFile));
951
- }
952
-
953
- function findCustomTUIReference(projectRoot, tool, templateSkillNames, report, logSkipped = false) {
954
- const cmdDir = path.join(projectRoot, tool.dir);
955
- if (!fs.existsSync(cmdDir) || !fs.statSync(cmdDir).isDirectory()) {
956
- if (logSkipped) {
957
- recordCustomTUISkipped(report, {
958
- index: tool.index,
959
- name: String(tool.name || ''),
960
- dir: tool.dir,
961
- reason: 'directory not found'
962
- });
963
- }
964
- return null;
965
- }
966
-
967
- const cmdFiles = fs.readdirSync(cmdDir)
968
- .filter((file) => fs.statSync(path.join(cmdDir, file)).isFile())
969
- .sort((left, right) => left.localeCompare(right));
970
- if (cmdFiles.length === 0) {
971
- if (logSkipped) {
972
- recordCustomTUISkipped(report, {
973
- index: tool.index,
974
- name: String(tool.name || ''),
975
- dir: tool.dir,
976
- reason: 'no command files'
977
- });
978
- }
979
- return null;
980
- }
981
-
982
- let sawKnownSkillReference = false;
983
-
984
- for (const file of cmdFiles) {
985
- const content = fs.readFileSync(path.join(cmdDir, file), 'utf8');
986
- const match = content.match(/\.agents\/skills\/([^/]+)\/SKILL\.md/);
987
- if (!match) continue;
988
-
989
- const skillName = match[1];
990
- if (!templateSkillNames.has(skillName)) continue;
991
-
992
- const skillMd = path.join(projectRoot, '.agents/skills', skillName, 'SKILL.md');
993
- if (!fs.existsSync(skillMd)) continue;
994
-
995
- const meta = parseSkillFrontmatter(skillMd);
996
- if (!meta.description) continue;
997
-
998
- sawKnownSkillReference = true;
999
- if (!content.includes(meta.description)) {
1000
- if (logSkipped) {
1001
- recordCustomTUISkippedRef(report, {
1002
- index: tool.index,
1003
- name: String(tool.name || ''),
1004
- dir: tool.dir,
1005
- file,
1006
- skill: skillName,
1007
- reason: 'description not found in reference command file'
1008
- });
1009
- }
1010
- continue;
1011
- }
1012
-
1013
- return { content, file, skillName, skillDesc: meta.description };
1014
- }
1015
-
1016
- if (logSkipped) {
1017
- recordCustomTUISkipped(report, {
1018
- index: tool.index,
1019
- name: String(tool.name || ''),
1020
- dir: tool.dir,
1021
- reason: sawKnownSkillReference
1022
- ? 'no reference command file with matching description'
1023
- : 'no usable reference command file'
1024
- });
1025
- }
1026
-
1027
- return null;
1028
- }
1029
-
1030
- function buildCustomTUICommandTargets(projectRoot, customSkills, customTUIs, templateSkillNames) {
1031
- const targets = new Set();
1032
- for (const tool of customTUIs) {
1033
- const ref = findCustomTUIReference(projectRoot, tool, templateSkillNames, null, false);
1034
- if (!ref) continue;
1035
-
1036
- for (const skill of customSkills) {
1037
- targets.add(customTUITargetPath(tool, ref.file, ref.skillName, skill.dirName));
1038
- }
1039
- }
1040
-
1041
- return targets;
1042
- }
1043
-
1044
836
  function buildBuiltinCustomCommandTargets(customSkills, enabledTUIs) {
1045
837
  return new Set(AGENT_CLIENT_MANIFEST.flatMap((adapter) => {
1046
838
  if (!enabledTUIs.has(adapter.id) || !adapter.customCommand) return [];
@@ -1050,33 +842,10 @@ function buildBuiltinCustomCommandTargets(customSkills, enabledTUIs) {
1050
842
  }));
1051
843
  }
1052
844
 
1053
- function learnAndGenerateCommands(projectRoot, customSkills, tool, templateSkillNames, report) {
1054
- const ref = findCustomTUIReference(projectRoot, tool, templateSkillNames, report, true);
1055
- if (!ref) return;
1056
-
1057
- for (const skill of customSkills) {
1058
- const descToken = '__AGENT_INFRA_CUSTOM_SKILL_DESCRIPTION__';
1059
- const generated = ref.content
1060
- .replaceAll(ref.skillDesc, descToken)
1061
- .replaceAll(ref.skillName, skill.dirName)
1062
- .replaceAll(descToken, skill.description);
1063
-
1064
- writeIfChanged(
1065
- projectRoot,
1066
- customTUITargetPath(tool, ref.file, ref.skillName, skill.dirName),
1067
- generated,
1068
- report.custom.commands
1069
- );
1070
- }
1071
- }
1072
-
1073
845
  function generateCustomCommands(
1074
- projectRoot,
1075
846
  customSkills,
1076
847
  lang,
1077
848
  report,
1078
- customTUIs,
1079
- templateSkillNames,
1080
849
  enabledTUIs,
1081
850
  managedWriter
1082
851
  ) {
@@ -1094,11 +863,6 @@ function generateCustomCommands(
1094
863
  );
1095
864
  }
1096
865
  }
1097
-
1098
- const tools = Array.isArray(customTUIs) ? customTUIs : [];
1099
- for (const tool of tools) {
1100
- learnAndGenerateCommands(projectRoot, customSkills, tool, templateSkillNames, report);
1101
- }
1102
866
  }
1103
867
 
1104
868
  function matchesAny(rel, patterns) {
@@ -1264,9 +1028,7 @@ function syncTemplates(projectRoot, templateRootOverride) {
1264
1028
  const configPathRel = norm(path.relative(projectRoot, cfgPath));
1265
1029
  let templateRoot = templateRootOverride;
1266
1030
  if (!templateRoot) {
1267
- const packageResolution = resolveAgentInfraPackage({
1268
- startPath: path.join(projectRoot, '.agents', 'scripts', 'lib', 'agent-infra-package.js')
1269
- });
1031
+ const packageResolution = resolveAgentInfraPackage();
1270
1032
  if (packageResolution.templateRoot && fs.existsSync(packageResolution.templateRoot)) {
1271
1033
  templateRoot = packageResolution.templateRoot;
1272
1034
  } else {
@@ -1290,7 +1052,6 @@ function syncTemplates(projectRoot, templateRootOverride) {
1290
1052
  AGENT_CLIENT_IDS.filter((id) => enabledResolution.state[id].enabled)
1291
1053
  );
1292
1054
  materializeAgentClientConfig(cfg, enabledResolution);
1293
- const customTUIsConfig = Array.isArray(cfg.customTUIs) ? cfg.customTUIs : [];
1294
1055
  const vars = { project, org };
1295
1056
  const templateSkillNames = listTemplateSkillNames(templateRoot);
1296
1057
  const protectedCustomSkills = detectCustomSkills(projectRoot, templateSkillNames);
@@ -1377,24 +1138,13 @@ function syncTemplates(projectRoot, templateRootOverride) {
1377
1138
  unchanged: [],
1378
1139
  removed: [],
1379
1140
  sourceErrors: [],
1380
- customTUIs: { skipped: [], skippedRefs: [] },
1381
1141
  commands: { generated: [], updated: [], unchanged: [] }
1382
1142
  },
1383
1143
  ejected: { created: [], skipped: [] },
1384
1144
  merged: { pending: [] },
1385
1145
  configUpdated: false
1386
1146
  };
1387
- const customTUIs = validateCustomTUIs(projectRoot, customTUIsConfig, report);
1388
- const customTUICommandTargets = buildCustomTUICommandTargets(
1389
- projectRoot,
1390
- protectedCustomSkills,
1391
- customTUIs,
1392
- templateSkillNames
1393
- );
1394
- const customCommandTargets = new Set([
1395
- ...buildBuiltinCustomCommandTargets(protectedCustomSkills, enabledTUIs),
1396
- ...customTUICommandTargets
1397
- ]);
1147
+ const customCommandTargets = buildBuiltinCustomCommandTargets(protectedCustomSkills, enabledTUIs);
1398
1148
 
1399
1149
  for (const category of ['managed', 'merged', 'ejected']) {
1400
1150
  const before = currentRegistry[category];
@@ -1883,12 +1633,9 @@ function syncTemplates(projectRoot, templateRootOverride) {
1883
1633
  const customSkills = detectCustomSkills(projectRoot, templateSkillNames);
1884
1634
  report.custom.detected = customSkills.map((skill) => skill.dirName);
1885
1635
  generateCustomCommands(
1886
- projectRoot,
1887
1636
  customSkills,
1888
1637
  lang,
1889
1638
  report,
1890
- customTUIs,
1891
- templateSkillNames,
1892
1639
  enabledTUIs,
1893
1640
  writeProtectedManaged
1894
1641
  );
@@ -1,99 +0,0 @@
1
- import path from 'node:path';
2
- const CUSTOM_TUI_CONTRACT = Object.freeze({
3
- requiredFields: Object.freeze(['name', 'dir', 'invoke']),
4
- allowedPlaceholders: Object.freeze(['skillName', 'projectName'])
5
- });
6
- function isRecord(value) {
7
- return typeof value === 'object' && value !== null && !Array.isArray(value);
8
- }
9
- function isNonEmptySingleLine(value) {
10
- return typeof value === 'string'
11
- && value.trim() !== ''
12
- && !/[\r\n]/.test(value);
13
- }
14
- function normalizeDir(projectRoot, value) {
15
- if (!isNonEmptySingleLine(value)
16
- || value.includes('\\')
17
- || path.isAbsolute(value)
18
- || /^[a-zA-Z]:/.test(value)) {
19
- return null;
20
- }
21
- const normalized = path.posix.normalize(value);
22
- if (normalized === '.'
23
- || normalized === '..'
24
- || normalized.startsWith('../')
25
- || normalized.split('/').includes('..')) {
26
- return null;
27
- }
28
- const relative = path.relative(path.resolve(projectRoot), path.resolve(projectRoot, normalized));
29
- return relative === ''
30
- || path.isAbsolute(relative)
31
- || relative === '..'
32
- || relative.startsWith(`..${path.sep}`)
33
- ? null
34
- : normalized;
35
- }
36
- function hasValidPlaceholders(invocation) {
37
- const placeholders = [
38
- ...invocation.matchAll(/\$\{([^}]+)\}/g)
39
- ].map((match) => match[1]);
40
- return placeholders.includes('skillName')
41
- && placeholders.every((placeholder) => CUSTOM_TUI_CONTRACT.allowedPlaceholders.includes(placeholder))
42
- && !invocation
43
- .replaceAll('${skillName}', '')
44
- .replaceAll('${projectName}', '')
45
- .includes('${');
46
- }
47
- function normalizeCustomTUIs(projectRoot, input) {
48
- const items = [];
49
- const diagnostics = [];
50
- if (!Array.isArray(input)) {
51
- return Object.freeze({
52
- items: Object.freeze([]),
53
- diagnostics: Object.freeze([
54
- Object.freeze({
55
- code: 'INVALID_CUSTOM_TUIS',
56
- path: 'customTUIs'
57
- })
58
- ])
59
- });
60
- }
61
- for (const [index, candidate] of input.entries()) {
62
- const base = `customTUIs[${index}]`;
63
- if (!isRecord(candidate)) {
64
- diagnostics.push({ code: 'INVALID_CUSTOM_TUI', path: base });
65
- continue;
66
- }
67
- if (!isNonEmptySingleLine(candidate.name)) {
68
- diagnostics.push({ code: 'INVALID_CUSTOM_TUI', path: `${base}.name` });
69
- continue;
70
- }
71
- const dir = normalizeDir(projectRoot, candidate.dir);
72
- if (!dir) {
73
- diagnostics.push({ code: 'INVALID_CUSTOM_TUI', path: `${base}.dir` });
74
- continue;
75
- }
76
- if (!isNonEmptySingleLine(candidate.invoke)) {
77
- diagnostics.push({ code: 'INVALID_CUSTOM_TUI', path: `${base}.invoke` });
78
- continue;
79
- }
80
- if (!hasValidPlaceholders(candidate.invoke)) {
81
- diagnostics.push({
82
- code: 'INVALID_CUSTOM_TUI_PLACEHOLDER',
83
- path: `${base}.invoke`
84
- });
85
- continue;
86
- }
87
- items.push(Object.freeze({
88
- name: candidate.name,
89
- dir,
90
- invocation: candidate.invoke
91
- }));
92
- }
93
- return Object.freeze({
94
- items: Object.freeze(items),
95
- diagnostics: Object.freeze(diagnostics.map((diagnostic) => Object.freeze(diagnostic)))
96
- });
97
- }
98
- export { CUSTOM_TUI_CONTRACT, normalizeCustomTUIs };
99
- //# sourceMappingURL=custom-tuis.js.map
@@ -1,149 +0,0 @@
1
- import path from 'node:path';
2
-
3
- type CustomTUI = Readonly<{
4
- name: string;
5
- dir: string;
6
- invocation: string;
7
- }>;
8
-
9
- type CustomTUIDiagnosticCode =
10
- | 'INVALID_CUSTOM_TUIS'
11
- | 'INVALID_CUSTOM_TUI'
12
- | 'INVALID_CUSTOM_TUI_PLACEHOLDER';
13
-
14
- type CustomTUIDiagnostic = Readonly<{
15
- code: CustomTUIDiagnosticCode;
16
- path: string;
17
- }>;
18
-
19
- type NormalizeCustomTUIsResult = Readonly<{
20
- items: readonly CustomTUI[];
21
- diagnostics: readonly CustomTUIDiagnostic[];
22
- }>;
23
-
24
- const CUSTOM_TUI_CONTRACT = Object.freeze({
25
- requiredFields: Object.freeze(['name', 'dir', 'invoke']),
26
- allowedPlaceholders: Object.freeze(['skillName', 'projectName'])
27
- });
28
-
29
- function isRecord(value: unknown): value is Record<string, unknown> {
30
- return typeof value === 'object' && value !== null && !Array.isArray(value);
31
- }
32
-
33
- function isNonEmptySingleLine(value: unknown): value is string {
34
- return typeof value === 'string'
35
- && value.trim() !== ''
36
- && !/[\r\n]/.test(value);
37
- }
38
-
39
- function normalizeDir(projectRoot: string, value: unknown): string | null {
40
- if (
41
- !isNonEmptySingleLine(value)
42
- || value.includes('\\')
43
- || path.isAbsolute(value)
44
- || /^[a-zA-Z]:/.test(value)
45
- ) {
46
- return null;
47
- }
48
- const normalized = path.posix.normalize(value);
49
- if (
50
- normalized === '.'
51
- || normalized === '..'
52
- || normalized.startsWith('../')
53
- || normalized.split('/').includes('..')
54
- ) {
55
- return null;
56
- }
57
- const relative = path.relative(
58
- path.resolve(projectRoot),
59
- path.resolve(projectRoot, normalized)
60
- );
61
- return relative === ''
62
- || path.isAbsolute(relative)
63
- || relative === '..'
64
- || relative.startsWith(`..${path.sep}`)
65
- ? null
66
- : normalized;
67
- }
68
-
69
- function hasValidPlaceholders(invocation: string): boolean {
70
- const placeholders = [
71
- ...invocation.matchAll(/\$\{([^}]+)\}/g)
72
- ].map((match) => match[1]!);
73
- return placeholders.includes('skillName')
74
- && placeholders.every((placeholder) =>
75
- CUSTOM_TUI_CONTRACT.allowedPlaceholders.includes(placeholder)
76
- )
77
- && !invocation
78
- .replaceAll('${skillName}', '')
79
- .replaceAll('${projectName}', '')
80
- .includes('${');
81
- }
82
-
83
- function normalizeCustomTUIs(
84
- projectRoot: string,
85
- input: unknown
86
- ): NormalizeCustomTUIsResult {
87
- const items: CustomTUI[] = [];
88
- const diagnostics: CustomTUIDiagnostic[] = [];
89
-
90
- if (!Array.isArray(input)) {
91
- return Object.freeze({
92
- items: Object.freeze([]),
93
- diagnostics: Object.freeze([
94
- Object.freeze({
95
- code: 'INVALID_CUSTOM_TUIS' as const,
96
- path: 'customTUIs'
97
- })
98
- ])
99
- });
100
- }
101
-
102
- for (const [index, candidate] of input.entries()) {
103
- const base = `customTUIs[${index}]`;
104
- if (!isRecord(candidate)) {
105
- diagnostics.push({ code: 'INVALID_CUSTOM_TUI', path: base });
106
- continue;
107
- }
108
- if (!isNonEmptySingleLine(candidate.name)) {
109
- diagnostics.push({ code: 'INVALID_CUSTOM_TUI', path: `${base}.name` });
110
- continue;
111
- }
112
- const dir = normalizeDir(projectRoot, candidate.dir);
113
- if (!dir) {
114
- diagnostics.push({ code: 'INVALID_CUSTOM_TUI', path: `${base}.dir` });
115
- continue;
116
- }
117
- if (!isNonEmptySingleLine(candidate.invoke)) {
118
- diagnostics.push({ code: 'INVALID_CUSTOM_TUI', path: `${base}.invoke` });
119
- continue;
120
- }
121
- if (!hasValidPlaceholders(candidate.invoke)) {
122
- diagnostics.push({
123
- code: 'INVALID_CUSTOM_TUI_PLACEHOLDER',
124
- path: `${base}.invoke`
125
- });
126
- continue;
127
- }
128
- items.push(Object.freeze({
129
- name: candidate.name,
130
- dir,
131
- invocation: candidate.invoke
132
- }));
133
- }
134
-
135
- return Object.freeze({
136
- items: Object.freeze(items),
137
- diagnostics: Object.freeze(
138
- diagnostics.map((diagnostic) => Object.freeze(diagnostic))
139
- )
140
- });
141
- }
142
-
143
- export { CUSTOM_TUI_CONTRACT, normalizeCustomTUIs };
144
- export type {
145
- CustomTUI,
146
- CustomTUIDiagnostic,
147
- CustomTUIDiagnosticCode,
148
- NormalizeCustomTUIsResult
149
- };