@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.
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/bin/internal-cli.js +8 -2
- package/dist/lib/agent-clients/adapters/codex.js +1 -1
- package/dist/lib/agent-clients/config.js +11 -3
- package/dist/lib/agent-clients/custom-tool-invocations.js +92 -0
- package/dist/lib/agent-clients/next-steps.js +1 -1
- package/dist/lib/agent-clients/reconcile.js +3 -3
- package/dist/lib/agent-clients/schema.js +18 -10
- package/dist/lib/defaults.json +6 -3
- package/dist/lib/init.js +2 -2
- package/dist/lib/internal/agent-client.js +3 -3
- package/dist/lib/internal/cli-route-inventory.js +3 -0
- package/dist/lib/internal/platform-pr-review.js +20 -3
- package/dist/lib/internal/task-operation-registry.js +3 -1
- package/dist/lib/internal/task-platform-recovery.js +56 -0
- package/dist/lib/merge.js +25 -5
- package/dist/lib/platform/completion-backfill.js +2 -1
- package/dist/lib/platform/in-label-sync.js +12 -1
- package/dist/lib/platform/issue-comments.js +58 -4
- package/dist/lib/platform/issues.js +105 -5
- package/dist/lib/platform/operation-coordinator.js +74 -0
- package/dist/lib/platform/pr-review.js +107 -1
- package/dist/lib/platform/pr-summary.js +79 -57
- package/dist/lib/platform/pull-requests.js +96 -4
- package/dist/lib/sandbox/commands/create.js +6 -3
- package/dist/lib/sandbox/commands/ls.js +4 -3
- package/dist/lib/sandbox/commands/rm.js +1 -1
- package/dist/lib/sandbox/config.js +22 -4
- package/dist/lib/sandbox/git-metadata.js +50 -0
- package/dist/lib/sandbox/index.js +1 -1
- package/dist/lib/sandbox/mounts.js +12 -0
- package/dist/lib/sandbox/recovery.js +12 -22
- package/dist/lib/sandbox/removal.js +58 -20
- package/dist/lib/sandbox/tools.js +31 -7
- package/dist/lib/task/activity-intent.js +4 -3
- package/dist/lib/task/create-service.js +5 -3
- package/dist/lib/task/create.js +22 -5
- package/dist/lib/task/finalization-artifacts.js +4 -1
- package/dist/lib/task/finalization.js +243 -113
- package/dist/lib/task/lifecycle.js +38 -2
- package/dist/lib/task/platform-operation-journal.js +152 -0
- package/dist/lib/task/platform-operation-recovery.js +459 -0
- package/dist/lib/task/verification.js +0 -1
- package/dist/lib/task/workflow-warning-intents.js +7 -1
- package/dist/lib/update.js +2 -2
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-clients/adapters/codex.ts +1 -1
- package/lib/agent-clients/config.ts +9 -3
- package/lib/agent-clients/custom-tool-invocations.ts +129 -0
- package/lib/agent-clients/next-steps.ts +3 -3
- package/lib/agent-clients/reconcile.ts +3 -3
- package/lib/agent-clients/schema.ts +18 -10
- package/lib/defaults.json +6 -3
- package/lib/init.ts +2 -2
- package/lib/internal/agent-client.ts +3 -3
- package/lib/internal/cli-route-inventory.ts +2 -0
- package/lib/internal/platform-pr-review.ts +14 -3
- package/lib/internal/task-operation-registry.ts +3 -1
- package/lib/internal/task-platform-recovery.ts +53 -0
- package/lib/merge.ts +26 -6
- package/lib/platform/completion-backfill.ts +2 -1
- package/lib/platform/in-label-sync.ts +12 -0
- package/lib/platform/issue-comments.ts +59 -3
- package/lib/platform/issues.ts +103 -5
- package/lib/platform/operation-coordinator.ts +96 -0
- package/lib/platform/pr-review.ts +113 -1
- package/lib/platform/pr-summary.ts +22 -1
- package/lib/platform/pull-requests.ts +105 -5
- package/lib/sandbox/commands/create.ts +7 -8
- package/lib/sandbox/commands/ls.ts +4 -3
- package/lib/sandbox/commands/rm.ts +1 -1
- package/lib/sandbox/config.ts +23 -5
- package/lib/sandbox/git-metadata.ts +66 -0
- package/lib/sandbox/index.ts +1 -1
- package/lib/sandbox/mounts.ts +14 -0
- package/lib/sandbox/recovery.ts +13 -25
- package/lib/sandbox/removal.ts +57 -19
- package/lib/sandbox/tool-types.ts +2 -1
- package/lib/sandbox/tools.ts +38 -7
- package/lib/task/activity-intent.ts +4 -3
- package/lib/task/create-service.ts +5 -3
- package/lib/task/create.ts +17 -5
- package/lib/task/finalization-artifacts.ts +4 -1
- package/lib/task/finalization.ts +242 -106
- package/lib/task/lifecycle.ts +35 -3
- package/lib/task/platform-operation-journal.ts +230 -0
- package/lib/task/platform-operation-recovery.ts +435 -0
- package/lib/task/verification.ts +1 -2
- package/lib/task/workflow-warning-intents.ts +9 -1
- package/lib/update.ts +2 -3
- package/package.json +1 -1
- package/templates/.agents/README.en.md +20 -66
- package/templates/.agents/README.zh-CN.md +19 -65
- package/templates/.agents/rules/README.en.md +1 -1
- package/templates/.agents/rules/README.zh-CN.md +1 -1
- package/templates/.agents/rules/next-step-output.en.md +1 -1
- package/templates/.agents/rules/next-step-output.zh-CN.md +1 -1
- package/templates/.agents/rules/task-management.en.md +12 -0
- package/templates/.agents/rules/task-management.zh-CN.md +12 -0
- package/templates/.agents/scripts/lib/agent-infra-package.js +0 -7
- package/templates/.agents/skills/cancel-task/SKILL.en.md +4 -2
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +4 -2
- package/templates/.agents/skills/code-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/commit/SKILL.en.md +1 -1
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-task/SKILL.en.md +2 -0
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +2 -0
- package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +1 -1
- package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +1 -1
- package/templates/.agents/skills/plan-task/config/verify.en.json +1 -1
- package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/review-code/SKILL.en.md +1 -1
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/review-code/reference/output-templates.en.md +15 -6
- package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +15 -6
- package/templates/.agents/skills/review-pr/SKILL.en.md +11 -11
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +11 -11
- package/templates/.agents/skills/review-pr/reference/output-guidance.en.md +3 -3
- package/templates/.agents/skills/review-pr/reference/output-guidance.zh-CN.md +3 -3
- package/templates/.agents/skills/review-pr/reference/report-template.en.md +4 -0
- package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +4 -0
- package/templates/.agents/skills/update-agent-infra/SKILL.en.md +1 -1
- package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +21 -274
- package/dist/lib/agent-clients/custom-tuis.js +0 -99
- 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
|
-
"
|
|
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 (
|
|
338
|
-
|
|
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
|
|
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
|
-
};
|