agentsmesh 0.14.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/README.md +27 -2
- package/dist/canonical.d.ts +2 -2
- package/dist/canonical.js +305 -104
- package/dist/canonical.js.map +1 -1
- package/dist/cli.js +190 -188
- package/dist/engine.d.ts +2 -2
- package/dist/engine.js +343 -111
- package/dist/engine.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +343 -111
- package/dist/index.js.map +1 -1
- package/dist/{schema-o4oXUVBP.d.ts → schema-CD2qcmDL.d.ts} +1 -0
- package/dist/{target-descriptor--Nw5i4v3.d.ts → target-descriptor-CvB1qzPn.d.ts} +1 -1
- package/dist/targets.d.ts +3 -3
- package/dist/targets.js +129 -98
- package/dist/targets.js.map +1 -1
- package/package.json +1 -1
- package/schemas/agentsmesh.json +3 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { AgentsMeshError, AgentsMeshErrorCode, CheckLockSyncOptions, ComputeDiffResult, ConfigNotFoundError, ConfigValidationError, DiffEntry, DiffSummary, FileSystemError, GenerateContext, GenerationError, ImportError, LintOptions, LintResult, LoadProjectContextOptions, LockAcquisitionError, LockSyncReport, ProjectContext, RemoteFetchError, TargetNotFoundError, check, computeDiff, diff, formatDiffSummary, generate, importFrom, lint, loadConfig, loadConfigFromDirectory, loadProjectContext, resolveOutputCollisions } from './engine.js';
|
|
2
2
|
export { LoadCanonicalOptions, loadCanonical, loadCanonicalFiles } from './canonical.js';
|
|
3
3
|
export { getAllDescriptors, getDescriptor, getTargetCatalog, registerTargetDescriptor } from './targets.js';
|
|
4
|
-
export { C as CanonicalAgent, a as CanonicalCommand, b as CanonicalFiles, c as CanonicalRule, d as CanonicalSkill, H as HookEntry, e as Hooks, I as IgnorePatterns, M as McpConfig, f as McpServer, P as Permissions, S as SkillSupportingFile, g as StdioMcpServer, U as UrlMcpServer, V as ValidatedConfig } from './schema-
|
|
5
|
-
export { E as ExtraRuleOutputContext, a as ExtraRuleOutputResolver, F as FeatureLinter, G as GenerateResult, b as GeneratedOutputMerger, c as GlobalTargetSupport, I as ImportPathBuilder, d as ImportResult, L as LintDiagnostic, R as RuleLinter, S as ScopeExtrasFn, T as TargetCapabilities, e as TargetDescriptor, f as TargetGenerators, g as TargetLayout, h as TargetLayoutScope, i as TargetLintHooks, j as TargetManagedOutputs, k as TargetOutputFamily, l as TargetPathResolvers } from './target-descriptor
|
|
4
|
+
export { C as CanonicalAgent, a as CanonicalCommand, b as CanonicalFiles, c as CanonicalRule, d as CanonicalSkill, H as HookEntry, e as Hooks, I as IgnorePatterns, M as McpConfig, f as McpServer, P as Permissions, S as SkillSupportingFile, g as StdioMcpServer, U as UrlMcpServer, V as ValidatedConfig } from './schema-CD2qcmDL.js';
|
|
5
|
+
export { E as ExtraRuleOutputContext, a as ExtraRuleOutputResolver, F as FeatureLinter, G as GenerateResult, b as GeneratedOutputMerger, c as GlobalTargetSupport, I as ImportPathBuilder, d as ImportResult, L as LintDiagnostic, R as RuleLinter, S as ScopeExtrasFn, T as TargetCapabilities, e as TargetDescriptor, f as TargetGenerators, g as TargetLayout, h as TargetLayoutScope, i as TargetLintHooks, j as TargetManagedOutputs, k as TargetOutputFamily, l as TargetPathResolvers } from './target-descriptor-CvB1qzPn.js';
|
|
6
6
|
import 'zod';
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { stringify, parse } from 'yaml';
|
|
3
|
-
import { access, readdir, readFile, realpath, stat, rm, mkdir, lstat, unlink, writeFile, rename } from 'fs/promises';
|
|
4
3
|
import { join, basename, dirname, relative, win32, posix, resolve, extname } from 'path';
|
|
5
|
-
import {
|
|
4
|
+
import { access, readdir, readFile, realpath, stat, rm, mkdir, lstat, unlink, writeFile, rename, chmod } from 'fs/promises';
|
|
5
|
+
import { constants, existsSync, realpathSync, statSync, readFileSync } from 'fs';
|
|
6
6
|
import { parse as parse$1 } from 'smol-toml';
|
|
7
7
|
import { Buffer } from 'buffer';
|
|
8
8
|
import { homedir } from 'os';
|
|
@@ -619,6 +619,104 @@ function shouldNormalizeLineEndings(path) {
|
|
|
619
619
|
function normalizeLineEndings(content) {
|
|
620
620
|
return content.replace(/\r\n?/g, "\n");
|
|
621
621
|
}
|
|
622
|
+
function executableModeFor(path) {
|
|
623
|
+
return EXECUTABLE_SCRIPT_EXTENSIONS.has(extname(path).toLowerCase()) ? 493 : void 0;
|
|
624
|
+
}
|
|
625
|
+
var UTF8_BOM, TEXT_EXTENSIONS, TEXT_DOTFILES, EXECUTABLE_SCRIPT_EXTENSIONS;
|
|
626
|
+
var init_fs_text_encoding = __esm({
|
|
627
|
+
"src/utils/filesystem/fs-text-encoding.ts"() {
|
|
628
|
+
UTF8_BOM = "\uFEFF";
|
|
629
|
+
TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
630
|
+
".md",
|
|
631
|
+
".mdc",
|
|
632
|
+
".mdx",
|
|
633
|
+
".markdown",
|
|
634
|
+
".txt",
|
|
635
|
+
".json",
|
|
636
|
+
".jsonc",
|
|
637
|
+
".yaml",
|
|
638
|
+
".yml",
|
|
639
|
+
".toml",
|
|
640
|
+
".ini",
|
|
641
|
+
".sh",
|
|
642
|
+
".bash",
|
|
643
|
+
".zsh",
|
|
644
|
+
".ps1",
|
|
645
|
+
".js",
|
|
646
|
+
".mjs",
|
|
647
|
+
".cjs",
|
|
648
|
+
".ts",
|
|
649
|
+
".tsx",
|
|
650
|
+
".html",
|
|
651
|
+
".css"
|
|
652
|
+
]);
|
|
653
|
+
TEXT_DOTFILES = /* @__PURE__ */ new Set([
|
|
654
|
+
".gitignore",
|
|
655
|
+
".cursorignore",
|
|
656
|
+
".cursorindexingignore",
|
|
657
|
+
".aiignore",
|
|
658
|
+
".agentignore",
|
|
659
|
+
".clineignore",
|
|
660
|
+
".geminiignore",
|
|
661
|
+
".codeiumignore",
|
|
662
|
+
".continueignore",
|
|
663
|
+
".copilotignore",
|
|
664
|
+
".windsurfignore",
|
|
665
|
+
".junieignore",
|
|
666
|
+
".kiroignore",
|
|
667
|
+
".rooignore",
|
|
668
|
+
".antigravityignore"
|
|
669
|
+
]);
|
|
670
|
+
EXECUTABLE_SCRIPT_EXTENSIONS = /* @__PURE__ */ new Set([".sh", ".bash", ".zsh"]);
|
|
671
|
+
}
|
|
672
|
+
});
|
|
673
|
+
async function readDirRecursive(dir, visited) {
|
|
674
|
+
let canonicalDir;
|
|
675
|
+
try {
|
|
676
|
+
canonicalDir = await realpath(dir);
|
|
677
|
+
} catch (err) {
|
|
678
|
+
const e = err;
|
|
679
|
+
if (e.code === "ENOENT" || e.code === "ENOTDIR" || e.code === "ELOOP") return [];
|
|
680
|
+
throw new FileSystemError(
|
|
681
|
+
dir,
|
|
682
|
+
`Failed to read directory ${dir}: ${e.message}. Check permissions.`,
|
|
683
|
+
{ cause: err, errnoCode: e.code }
|
|
684
|
+
);
|
|
685
|
+
}
|
|
686
|
+
const seen = visited ?? /* @__PURE__ */ new Set();
|
|
687
|
+
if (seen.has(canonicalDir)) return [];
|
|
688
|
+
seen.add(canonicalDir);
|
|
689
|
+
try {
|
|
690
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
691
|
+
const files = [];
|
|
692
|
+
for (const ent of entries) {
|
|
693
|
+
const full = join(dir, ent.name);
|
|
694
|
+
const walkChild = ent.isDirectory() || ent.isSymbolicLink() && await stat(full).then(
|
|
695
|
+
(s) => s.isDirectory(),
|
|
696
|
+
() => false
|
|
697
|
+
);
|
|
698
|
+
if (walkChild) {
|
|
699
|
+
files.push(...await readDirRecursive(full, seen));
|
|
700
|
+
} else {
|
|
701
|
+
files.push(full);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
return files;
|
|
705
|
+
} catch (err) {
|
|
706
|
+
const e = err;
|
|
707
|
+
if (e.code === "ENOENT" || e.code === "ENOTDIR" || e.code === "EACCES") return [];
|
|
708
|
+
throw new FileSystemError(
|
|
709
|
+
dir,
|
|
710
|
+
`Failed to read directory ${dir}: ${e.message}. Check permissions.`,
|
|
711
|
+
{ cause: err, errnoCode: e.code }
|
|
712
|
+
);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
var init_fs_traverse = __esm({
|
|
716
|
+
"src/utils/filesystem/fs-traverse.ts"() {
|
|
717
|
+
init_errors();
|
|
718
|
+
}
|
|
719
|
+
});
|
|
622
720
|
async function readFileSafe(path) {
|
|
623
721
|
try {
|
|
624
722
|
const data = await readFile(path, "utf-8");
|
|
@@ -633,7 +731,7 @@ async function readFileSafe(path) {
|
|
|
633
731
|
);
|
|
634
732
|
}
|
|
635
733
|
}
|
|
636
|
-
async function writeFileAtomic(path, content) {
|
|
734
|
+
async function writeFileAtomic(path, content, options) {
|
|
637
735
|
const dir = dirname(path);
|
|
638
736
|
await mkdir(dir, { recursive: true });
|
|
639
737
|
try {
|
|
@@ -657,6 +755,7 @@ async function writeFileAtomic(path, content) {
|
|
|
657
755
|
}
|
|
658
756
|
const tmpPath = `${path}.tmp`;
|
|
659
757
|
const payload = shouldNormalizeLineEndings(path) ? normalizeLineEndings(content) : content;
|
|
758
|
+
const mode = executableModeFor(path);
|
|
660
759
|
try {
|
|
661
760
|
try {
|
|
662
761
|
const tmpInfo = await lstat(tmpPath);
|
|
@@ -666,8 +765,16 @@ async function writeFileAtomic(path, content) {
|
|
|
666
765
|
} catch (tmpErr) {
|
|
667
766
|
if (tmpErr.code !== "ENOENT") throw tmpErr;
|
|
668
767
|
}
|
|
669
|
-
|
|
768
|
+
const writeOpts = {
|
|
769
|
+
encoding: "utf-8",
|
|
770
|
+
flag: "w"
|
|
771
|
+
};
|
|
772
|
+
if (mode !== void 0) writeOpts.mode = mode;
|
|
773
|
+
await writeFile(tmpPath, payload, writeOpts);
|
|
670
774
|
await rename(tmpPath, path);
|
|
775
|
+
if (mode !== void 0) {
|
|
776
|
+
await chmod(path, mode);
|
|
777
|
+
}
|
|
671
778
|
} catch (err) {
|
|
672
779
|
await rm(tmpPath, { force: true }).catch(() => {
|
|
673
780
|
});
|
|
@@ -690,94 +797,12 @@ async function exists(path) {
|
|
|
690
797
|
async function mkdirp(path) {
|
|
691
798
|
await mkdir(path, { recursive: true });
|
|
692
799
|
}
|
|
693
|
-
async function readDirRecursive(dir, visited) {
|
|
694
|
-
let canonicalDir;
|
|
695
|
-
try {
|
|
696
|
-
canonicalDir = await realpath(dir);
|
|
697
|
-
} catch (err) {
|
|
698
|
-
const e = err;
|
|
699
|
-
if (e.code === "ENOENT" || e.code === "ENOTDIR" || e.code === "ELOOP") return [];
|
|
700
|
-
throw new FileSystemError(
|
|
701
|
-
dir,
|
|
702
|
-
`Failed to read directory ${dir}: ${e.message}. Check permissions.`,
|
|
703
|
-
{ cause: err, errnoCode: e.code }
|
|
704
|
-
);
|
|
705
|
-
}
|
|
706
|
-
const seen = visited ?? /* @__PURE__ */ new Set();
|
|
707
|
-
if (seen.has(canonicalDir)) return [];
|
|
708
|
-
seen.add(canonicalDir);
|
|
709
|
-
try {
|
|
710
|
-
const entries = await readdir(dir, { withFileTypes: true });
|
|
711
|
-
const files = [];
|
|
712
|
-
for (const ent of entries) {
|
|
713
|
-
const full = join(dir, ent.name);
|
|
714
|
-
const walkChild = ent.isDirectory() || ent.isSymbolicLink() && await stat(full).then(
|
|
715
|
-
(s) => s.isDirectory(),
|
|
716
|
-
() => false
|
|
717
|
-
);
|
|
718
|
-
if (walkChild) {
|
|
719
|
-
files.push(...await readDirRecursive(full, seen));
|
|
720
|
-
} else {
|
|
721
|
-
files.push(full);
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
return files;
|
|
725
|
-
} catch (err) {
|
|
726
|
-
const e = err;
|
|
727
|
-
if (e.code === "ENOENT" || e.code === "ENOTDIR" || e.code === "EACCES") return [];
|
|
728
|
-
throw new FileSystemError(
|
|
729
|
-
dir,
|
|
730
|
-
`Failed to read directory ${dir}: ${e.message}. Check permissions.`,
|
|
731
|
-
{ cause: err, errnoCode: e.code }
|
|
732
|
-
);
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
var UTF8_BOM, TEXT_EXTENSIONS, TEXT_DOTFILES;
|
|
736
800
|
var init_fs = __esm({
|
|
737
801
|
"src/utils/filesystem/fs.ts"() {
|
|
738
802
|
init_errors();
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
".mdc",
|
|
743
|
-
".mdx",
|
|
744
|
-
".markdown",
|
|
745
|
-
".txt",
|
|
746
|
-
".json",
|
|
747
|
-
".jsonc",
|
|
748
|
-
".yaml",
|
|
749
|
-
".yml",
|
|
750
|
-
".toml",
|
|
751
|
-
".ini",
|
|
752
|
-
".sh",
|
|
753
|
-
".bash",
|
|
754
|
-
".zsh",
|
|
755
|
-
".ps1",
|
|
756
|
-
".js",
|
|
757
|
-
".mjs",
|
|
758
|
-
".cjs",
|
|
759
|
-
".ts",
|
|
760
|
-
".tsx",
|
|
761
|
-
".html",
|
|
762
|
-
".css"
|
|
763
|
-
]);
|
|
764
|
-
TEXT_DOTFILES = /* @__PURE__ */ new Set([
|
|
765
|
-
".gitignore",
|
|
766
|
-
".cursorignore",
|
|
767
|
-
".cursorindexingignore",
|
|
768
|
-
".aiignore",
|
|
769
|
-
".agentignore",
|
|
770
|
-
".clineignore",
|
|
771
|
-
".geminiignore",
|
|
772
|
-
".codeiumignore",
|
|
773
|
-
".continueignore",
|
|
774
|
-
".copilotignore",
|
|
775
|
-
".windsurfignore",
|
|
776
|
-
".junieignore",
|
|
777
|
-
".kiroignore",
|
|
778
|
-
".rooignore",
|
|
779
|
-
".antigravityignore"
|
|
780
|
-
]);
|
|
803
|
+
init_fs_text_encoding();
|
|
804
|
+
init_fs_traverse();
|
|
805
|
+
init_fs_text_encoding();
|
|
781
806
|
}
|
|
782
807
|
});
|
|
783
808
|
function escapeRegExp(value) {
|
|
@@ -5173,13 +5198,16 @@ function generateAgents4(canonical) {
|
|
|
5173
5198
|
function safeEventName(event) {
|
|
5174
5199
|
return event.replace(/[^a-zA-Z0-9]/g, "-").toLowerCase();
|
|
5175
5200
|
}
|
|
5201
|
+
function safeShellLine(value) {
|
|
5202
|
+
return value.replace(/[\r\n]+/g, " ");
|
|
5203
|
+
}
|
|
5176
5204
|
function buildHookScript(event, command, matcher) {
|
|
5177
5205
|
return [
|
|
5178
5206
|
"#!/usr/bin/env bash",
|
|
5179
|
-
`# agentsmesh-event: ${event}`,
|
|
5180
|
-
`# agentsmesh-matcher: ${matcher}`,
|
|
5181
|
-
`# agentsmesh-command: ${command}`,
|
|
5182
|
-
"set -
|
|
5207
|
+
`# agentsmesh-event: ${safeShellLine(event)}`,
|
|
5208
|
+
`# agentsmesh-matcher: ${safeShellLine(matcher)}`,
|
|
5209
|
+
`# agentsmesh-command: ${safeShellLine(command)}`,
|
|
5210
|
+
"set -eu",
|
|
5183
5211
|
command,
|
|
5184
5212
|
""
|
|
5185
5213
|
].join("\n");
|
|
@@ -7636,7 +7664,7 @@ function extractMatcher(comment) {
|
|
|
7636
7664
|
function extractWrapperCommand(content) {
|
|
7637
7665
|
const metadataMatch = content.match(/^# agentsmesh-command:\s*(.+)$/m);
|
|
7638
7666
|
if (metadataMatch?.[1]) return metadataMatch[1].trim();
|
|
7639
|
-
return content.replace(/^#!.*\n/, "").replace(/^#.*\n/gm, "").replace(/^HOOK_DIR=.*\n/gm, "").replace(/^set -e
|
|
7667
|
+
return content.replace(/^#!.*\n/, "").replace(/^#.*\n/gm, "").replace(/^HOOK_DIR=.*\n/gm, "").replace(/^set -e[u]?\n?/m, "").trim();
|
|
7640
7668
|
}
|
|
7641
7669
|
async function importHooks(projectRoot, results) {
|
|
7642
7670
|
const hooksDir = join(projectRoot, COPILOT_HOOKS_DIR);
|
|
@@ -7958,12 +7986,15 @@ async function buildAssetOutput(projectRoot, command) {
|
|
|
7958
7986
|
function wrapperPath(event, index) {
|
|
7959
7987
|
return `${COPILOT_HOOKS_DIR}/scripts/${safePhaseName(event)}-${index}.sh`;
|
|
7960
7988
|
}
|
|
7989
|
+
function safeShellLine2(value) {
|
|
7990
|
+
return value.replace(/[\r\n]+/g, " ");
|
|
7991
|
+
}
|
|
7961
7992
|
function buildWrapper(command, matcher) {
|
|
7962
7993
|
return [
|
|
7963
7994
|
"#!/usr/bin/env bash",
|
|
7964
|
-
`# agentsmesh-matcher: ${matcher}`,
|
|
7965
|
-
`# agentsmesh-command: ${command}`,
|
|
7966
|
-
"set -
|
|
7995
|
+
`# agentsmesh-matcher: ${safeShellLine2(matcher)}`,
|
|
7996
|
+
`# agentsmesh-command: ${safeShellLine2(command)}`,
|
|
7997
|
+
"set -eu",
|
|
7967
7998
|
command,
|
|
7968
7999
|
""
|
|
7969
8000
|
].join("\n");
|
|
@@ -7987,8 +8018,8 @@ async function addHookScriptAssets(projectRoot, canonical, outputs) {
|
|
|
7987
8018
|
}
|
|
7988
8019
|
}
|
|
7989
8020
|
const wrapper = buildWrapper(command, entry.matcher).replace(
|
|
7990
|
-
"set -
|
|
7991
|
-
'set -
|
|
8021
|
+
"set -eu\n",
|
|
8022
|
+
'set -eu\nHOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"\n'
|
|
7992
8023
|
);
|
|
7993
8024
|
wrapperOutputs.push({ path: scriptPath, content: wrapper });
|
|
7994
8025
|
index++;
|
|
@@ -15590,7 +15621,15 @@ var conversionsSchema = z.object({
|
|
|
15590
15621
|
var pluginEntrySchema = z.object({
|
|
15591
15622
|
id: z.string().regex(/^[a-z][a-z0-9-]*$/),
|
|
15592
15623
|
source: z.string(),
|
|
15593
|
-
version: z.string().optional()
|
|
15624
|
+
version: z.string().optional(),
|
|
15625
|
+
/**
|
|
15626
|
+
* When true, a failure to import or validate this plugin throws and
|
|
15627
|
+
* aborts the run. Default `false` keeps the lenient behavior of logging
|
|
15628
|
+
* a warning and continuing. Use strict mode in CI when missing
|
|
15629
|
+
* descriptors should fail the build instead of silently shrinking the
|
|
15630
|
+
* generation matrix.
|
|
15631
|
+
*/
|
|
15632
|
+
strict: z.boolean().optional()
|
|
15594
15633
|
}).strict();
|
|
15595
15634
|
var configSchema = z.object({
|
|
15596
15635
|
version: z.literal(1),
|
|
@@ -15758,6 +15797,13 @@ init_fs();
|
|
|
15758
15797
|
init_fs();
|
|
15759
15798
|
var execFileAsync = promisify(execFile);
|
|
15760
15799
|
var REPO_DIRNAME = "repo";
|
|
15800
|
+
function ensureNotFlag(value, kind) {
|
|
15801
|
+
if (value.startsWith("-")) {
|
|
15802
|
+
throw new Error(
|
|
15803
|
+
`agentsmesh refuses ${kind} starting with "-" (option-injection guard): ${value}`
|
|
15804
|
+
);
|
|
15805
|
+
}
|
|
15806
|
+
}
|
|
15761
15807
|
async function fetchGitRemoteExtend(parsed, extendName, options, cacheDir, buildCacheKey2) {
|
|
15762
15808
|
const provider = "cloneUrl" in parsed ? "gitlab" : "git";
|
|
15763
15809
|
const identifier = "cloneUrl" in parsed ? `${parsed.namespace}/${parsed.project}` : parsed.url;
|
|
@@ -15815,9 +15861,11 @@ function resolveCloneUrl(parsed) {
|
|
|
15815
15861
|
return parsed.url;
|
|
15816
15862
|
}
|
|
15817
15863
|
async function cloneRepo(cloneUrl, repoDir) {
|
|
15864
|
+
ensureNotFlag(cloneUrl, "clone-url");
|
|
15818
15865
|
await runGit(["clone", cloneUrl, repoDir]);
|
|
15819
15866
|
}
|
|
15820
15867
|
async function checkoutRef(repoDir, ref) {
|
|
15868
|
+
ensureNotFlag(ref, "ref");
|
|
15821
15869
|
await runGit(["checkout", ref], repoDir);
|
|
15822
15870
|
}
|
|
15823
15871
|
async function getHeadSha(repoDir) {
|
|
@@ -15836,6 +15884,46 @@ async function runGit(args, cwd) {
|
|
|
15836
15884
|
|
|
15837
15885
|
// src/config/remote/github-remote.ts
|
|
15838
15886
|
init_fs();
|
|
15887
|
+
var MAX_TARBALL_BYTES = 500 * 1024 * 1024;
|
|
15888
|
+
async function readBoundedResponse(res, maxBytes) {
|
|
15889
|
+
const lenHeader = typeof res.headers?.get === "function" ? res.headers.get("content-length") : null;
|
|
15890
|
+
if (lenHeader !== null) {
|
|
15891
|
+
const declared = Number(lenHeader);
|
|
15892
|
+
if (Number.isFinite(declared) && declared > maxBytes) {
|
|
15893
|
+
throw new Error(`remote response declared ${declared} bytes; exceeds cap of ${maxBytes}`);
|
|
15894
|
+
}
|
|
15895
|
+
}
|
|
15896
|
+
const stream = res.body;
|
|
15897
|
+
if (!stream) {
|
|
15898
|
+
const buf = await res.arrayBuffer();
|
|
15899
|
+
if (buf.byteLength > maxBytes) {
|
|
15900
|
+
throw new Error(`remote response is ${buf.byteLength} bytes; exceeds cap of ${maxBytes}`);
|
|
15901
|
+
}
|
|
15902
|
+
return new Uint8Array(buf);
|
|
15903
|
+
}
|
|
15904
|
+
const reader = stream.getReader();
|
|
15905
|
+
const chunks = [];
|
|
15906
|
+
let total = 0;
|
|
15907
|
+
for (; ; ) {
|
|
15908
|
+
const { done, value } = await reader.read();
|
|
15909
|
+
if (done) break;
|
|
15910
|
+
if (!value) continue;
|
|
15911
|
+
total += value.byteLength;
|
|
15912
|
+
if (total > maxBytes) {
|
|
15913
|
+
await reader.cancel().catch(() => {
|
|
15914
|
+
});
|
|
15915
|
+
throw new Error(`remote response exceeded cap of ${maxBytes} bytes during streaming`);
|
|
15916
|
+
}
|
|
15917
|
+
chunks.push(value);
|
|
15918
|
+
}
|
|
15919
|
+
const out2 = new Uint8Array(total);
|
|
15920
|
+
let offset = 0;
|
|
15921
|
+
for (const c2 of chunks) {
|
|
15922
|
+
out2.set(c2, offset);
|
|
15923
|
+
offset += c2.byteLength;
|
|
15924
|
+
}
|
|
15925
|
+
return out2;
|
|
15926
|
+
}
|
|
15839
15927
|
async function resolveLatestTag(org, repo, token) {
|
|
15840
15928
|
const url = `https://api.github.com/repos/${org}/${repo}/releases/latest`;
|
|
15841
15929
|
const headers = {
|
|
@@ -15875,11 +15963,11 @@ async function fetchGithubRemoteExtend(parsed, extendName, options, cacheDir, bu
|
|
|
15875
15963
|
const tarballUrl = `https://github.com/${parsed.org}/${parsed.repo}/tarball/${tag}`;
|
|
15876
15964
|
const headers = {};
|
|
15877
15965
|
if (token) headers.Authorization = `Bearer ${token}`;
|
|
15878
|
-
let
|
|
15966
|
+
let tarballBytes;
|
|
15879
15967
|
try {
|
|
15880
15968
|
const res = await globalThis.fetch(tarballUrl, { headers, redirect: "follow" });
|
|
15881
15969
|
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
|
|
15882
|
-
|
|
15970
|
+
tarballBytes = await readBoundedResponse(res, MAX_TARBALL_BYTES);
|
|
15883
15971
|
} catch (err) {
|
|
15884
15972
|
const allowFallback = options.allowOfflineFallback !== false;
|
|
15885
15973
|
if (allowFallback && await exists(extractDir)) {
|
|
@@ -15896,7 +15984,7 @@ async function fetchGithubRemoteExtend(parsed, extendName, options, cacheDir, bu
|
|
|
15896
15984
|
await rm(extractDir, { recursive: true, force: true });
|
|
15897
15985
|
await mkdir(extractDir, { recursive: true });
|
|
15898
15986
|
const tarPath = join(extractDir, "archive.tar.gz");
|
|
15899
|
-
await writeFile(tarPath,
|
|
15987
|
+
await writeFile(tarPath, tarballBytes);
|
|
15900
15988
|
try {
|
|
15901
15989
|
await tar.extract({
|
|
15902
15990
|
file: tarPath,
|
|
@@ -16068,7 +16156,20 @@ function buildCacheKey(provider, identifier, ref) {
|
|
|
16068
16156
|
}
|
|
16069
16157
|
function getCacheDir() {
|
|
16070
16158
|
const env = process.env.AGENTSMESH_CACHE;
|
|
16071
|
-
if (env)
|
|
16159
|
+
if (env) {
|
|
16160
|
+
const trimmed = env.trim();
|
|
16161
|
+
if (!trimmed) {
|
|
16162
|
+
return join(homedir(), ".agentsmesh", "cache");
|
|
16163
|
+
}
|
|
16164
|
+
const isAbs = /^([A-Za-z]:[\\/]|\/)/.test(trimmed);
|
|
16165
|
+
if (!isAbs) {
|
|
16166
|
+
throw new Error(`AGENTSMESH_CACHE must be an absolute path (got: "${trimmed}").`);
|
|
16167
|
+
}
|
|
16168
|
+
if (trimmed === "/" || /^[A-Za-z]:[\\/]?$/.test(trimmed)) {
|
|
16169
|
+
throw new Error(`AGENTSMESH_CACHE must not be the filesystem root (got: "${trimmed}").`);
|
|
16170
|
+
}
|
|
16171
|
+
return trimmed;
|
|
16172
|
+
}
|
|
16072
16173
|
return join(homedir(), ".agentsmesh", "cache");
|
|
16073
16174
|
}
|
|
16074
16175
|
async function fetchRemoteExtend(source, extendName, options = {}) {
|
|
@@ -16160,6 +16261,98 @@ async function resolveExtendPaths(config, configDir, options = {}) {
|
|
|
16160
16261
|
// src/canonical/features/rules.ts
|
|
16161
16262
|
init_fs();
|
|
16162
16263
|
init_markdown();
|
|
16264
|
+
|
|
16265
|
+
// src/utils/filesystem/windows-path-safety.ts
|
|
16266
|
+
var WINDOWS_RESERVED_NAMES = /* @__PURE__ */ new Set([
|
|
16267
|
+
"CON",
|
|
16268
|
+
"PRN",
|
|
16269
|
+
"AUX",
|
|
16270
|
+
"NUL",
|
|
16271
|
+
"COM1",
|
|
16272
|
+
"COM2",
|
|
16273
|
+
"COM3",
|
|
16274
|
+
"COM4",
|
|
16275
|
+
"COM5",
|
|
16276
|
+
"COM6",
|
|
16277
|
+
"COM7",
|
|
16278
|
+
"COM8",
|
|
16279
|
+
"COM9",
|
|
16280
|
+
"LPT1",
|
|
16281
|
+
"LPT2",
|
|
16282
|
+
"LPT3",
|
|
16283
|
+
"LPT4",
|
|
16284
|
+
"LPT5",
|
|
16285
|
+
"LPT6",
|
|
16286
|
+
"LPT7",
|
|
16287
|
+
"LPT8",
|
|
16288
|
+
"LPT9"
|
|
16289
|
+
]);
|
|
16290
|
+
var WINDOWS_ILLEGAL_CHARS = new RegExp('[<>:"|?*\\u0000-\\u001F]');
|
|
16291
|
+
function segmentReservedName(segment) {
|
|
16292
|
+
const stem = segment.replace(/\.[^.]*$/, "").toUpperCase();
|
|
16293
|
+
return WINDOWS_RESERVED_NAMES.has(stem);
|
|
16294
|
+
}
|
|
16295
|
+
function findWindowsPathIssues(path) {
|
|
16296
|
+
const issues = [];
|
|
16297
|
+
const segments = path.split(/[\\/]/);
|
|
16298
|
+
for (const segment of segments) {
|
|
16299
|
+
if (segment === "" || segment === "." || segment === "..") continue;
|
|
16300
|
+
if (WINDOWS_ILLEGAL_CHARS.test(segment)) {
|
|
16301
|
+
issues.push({ segment, reason: "illegal-character" });
|
|
16302
|
+
continue;
|
|
16303
|
+
}
|
|
16304
|
+
if (/[. ]$/.test(segment)) {
|
|
16305
|
+
issues.push({ segment, reason: "trailing-dot-or-space" });
|
|
16306
|
+
continue;
|
|
16307
|
+
}
|
|
16308
|
+
if (segmentReservedName(segment)) {
|
|
16309
|
+
issues.push({ segment, reason: "reserved-name" });
|
|
16310
|
+
}
|
|
16311
|
+
}
|
|
16312
|
+
return issues;
|
|
16313
|
+
}
|
|
16314
|
+
|
|
16315
|
+
// src/canonical/features/validate-name.ts
|
|
16316
|
+
var CanonicalNameError = class extends Error {
|
|
16317
|
+
feature;
|
|
16318
|
+
name;
|
|
16319
|
+
constructor(feature, name, message) {
|
|
16320
|
+
super(message);
|
|
16321
|
+
this.feature = feature;
|
|
16322
|
+
this.name = name;
|
|
16323
|
+
}
|
|
16324
|
+
};
|
|
16325
|
+
function assertCanonicalName(feature, name) {
|
|
16326
|
+
const issues = findWindowsPathIssues(name);
|
|
16327
|
+
if (issues.length === 0) return;
|
|
16328
|
+
const reasons = issues.map((i) => `${i.segment} (${i.reason})`).join(", ");
|
|
16329
|
+
throw new CanonicalNameError(
|
|
16330
|
+
feature,
|
|
16331
|
+
name,
|
|
16332
|
+
`canonical ${feature} name "${name}" is not portable to Windows: ${reasons}. Rename the file.`
|
|
16333
|
+
);
|
|
16334
|
+
}
|
|
16335
|
+
function assertNoBasenameCollisions(feature, paths, stripExt) {
|
|
16336
|
+
const seen = /* @__PURE__ */ new Map();
|
|
16337
|
+
for (const p of paths) {
|
|
16338
|
+
const fwdIdx = p.lastIndexOf("/");
|
|
16339
|
+
const bckIdx = p.lastIndexOf("\\");
|
|
16340
|
+
const idx = Math.max(fwdIdx, bckIdx);
|
|
16341
|
+
const base = idx === -1 ? p : p.slice(idx + 1);
|
|
16342
|
+
const slug = base.endsWith(stripExt) ? base.slice(0, -stripExt.length) : base;
|
|
16343
|
+
const prior = seen.get(slug);
|
|
16344
|
+
if (prior !== void 0 && prior !== p) {
|
|
16345
|
+
throw new CanonicalNameError(
|
|
16346
|
+
feature,
|
|
16347
|
+
slug,
|
|
16348
|
+
`canonical ${feature} files collide on slug "${slug}": ${prior} vs ${p}. Rename one.`
|
|
16349
|
+
);
|
|
16350
|
+
}
|
|
16351
|
+
seen.set(slug, p);
|
|
16352
|
+
}
|
|
16353
|
+
}
|
|
16354
|
+
|
|
16355
|
+
// src/canonical/features/rules.ts
|
|
16163
16356
|
var VALID_TRIGGERS = ["always_on", "model_decision", "glob", "manual"];
|
|
16164
16357
|
function toStrArray(v) {
|
|
16165
16358
|
if (Array.isArray(v)) return v.filter((x) => typeof x === "string");
|
|
@@ -16179,6 +16372,7 @@ async function parseRules(rulesDir) {
|
|
|
16179
16372
|
if (!content) continue;
|
|
16180
16373
|
const { frontmatter, body } = parseFrontmatter(content);
|
|
16181
16374
|
const name = basename(path, ".md");
|
|
16375
|
+
assertCanonicalName("rule", name);
|
|
16182
16376
|
const rootFromFilename = name === "_root";
|
|
16183
16377
|
const rootFromFm = frontmatter.root === true;
|
|
16184
16378
|
const triggerRaw = frontmatter.trigger;
|
|
@@ -16220,12 +16414,14 @@ function toToolsArray2(v) {
|
|
|
16220
16414
|
async function parseCommands(commandsDir) {
|
|
16221
16415
|
const files = await readDirRecursive(commandsDir);
|
|
16222
16416
|
const mdFiles = files.filter((f) => f.endsWith(".md") && !basename(f).startsWith("_"));
|
|
16417
|
+
assertNoBasenameCollisions("command", mdFiles, ".md");
|
|
16223
16418
|
const commands = [];
|
|
16224
16419
|
for (const path of mdFiles) {
|
|
16225
16420
|
const content = await readFileSafe(path);
|
|
16226
16421
|
if (!content) continue;
|
|
16227
16422
|
const { frontmatter, body } = parseFrontmatter(content);
|
|
16228
16423
|
const name = basename(path, ".md");
|
|
16424
|
+
assertCanonicalName("command", name);
|
|
16229
16425
|
const fromCamel = toToolsArray2(frontmatter.allowedTools);
|
|
16230
16426
|
const fromKebab = toToolsArray2(frontmatter["allowed-tools"]);
|
|
16231
16427
|
const allowedTools = fromCamel.length > 0 ? fromCamel : fromKebab;
|
|
@@ -16273,12 +16469,14 @@ function toHooks2(v) {
|
|
|
16273
16469
|
async function parseAgents(agentsDir) {
|
|
16274
16470
|
const files = await readDirRecursive(agentsDir);
|
|
16275
16471
|
const mdFiles = files.filter((f) => f.endsWith(".md") && !basename(f).startsWith("_"));
|
|
16472
|
+
assertNoBasenameCollisions("agent", mdFiles, ".md");
|
|
16276
16473
|
const agents = [];
|
|
16277
16474
|
for (const path of mdFiles) {
|
|
16278
16475
|
const content = await readFileSafe(path);
|
|
16279
16476
|
if (!content) continue;
|
|
16280
16477
|
const { frontmatter, body } = parseFrontmatter(content);
|
|
16281
16478
|
const name = basename(path, ".md");
|
|
16479
|
+
assertCanonicalName("agent", name);
|
|
16282
16480
|
const toolsCamel = toStrArray2(frontmatter.tools);
|
|
16283
16481
|
const toolsKebab = toStrArray2(frontmatter["tools"]);
|
|
16284
16482
|
const tools = toolsCamel.length > 0 ? toolsCamel : toolsKebab;
|
|
@@ -16346,9 +16544,11 @@ async function parseSkillDirectory(skillDir) {
|
|
|
16346
16544
|
const { frontmatter, body } = parseFrontmatter(content);
|
|
16347
16545
|
const supportingFiles = await listSupportingFiles(skillDir);
|
|
16348
16546
|
const fmName = typeof frontmatter.name === "string" ? sanitizeSkillName(frontmatter.name) : "";
|
|
16547
|
+
const name = fmName || basename(skillDir);
|
|
16548
|
+
assertCanonicalName("skill", name);
|
|
16349
16549
|
return {
|
|
16350
16550
|
source: skillPath,
|
|
16351
|
-
name
|
|
16551
|
+
name,
|
|
16352
16552
|
description: typeof frontmatter.description === "string" ? frontmatter.description : "",
|
|
16353
16553
|
body,
|
|
16354
16554
|
supportingFiles
|
|
@@ -16365,6 +16565,7 @@ async function parseSkills(skillsDir) {
|
|
|
16365
16565
|
for (const ent of entries) {
|
|
16366
16566
|
if (!ent.isDirectory()) continue;
|
|
16367
16567
|
if (ent.name.startsWith("_")) continue;
|
|
16568
|
+
assertCanonicalName("skill", ent.name);
|
|
16368
16569
|
const skillDir = join(skillsDir, ent.name);
|
|
16369
16570
|
const skillPath = join(skillDir, SKILL_FILE);
|
|
16370
16571
|
const content = await readFileSafe(skillPath);
|
|
@@ -17218,15 +17419,35 @@ async function loadCanonicalWithExtends(config, configDir, options = {}, canonic
|
|
|
17218
17419
|
// src/plugins/load-plugin.ts
|
|
17219
17420
|
init_target_descriptor_schema();
|
|
17220
17421
|
init_registry();
|
|
17422
|
+
function resolveNpmSpecifier(source, projectRoot) {
|
|
17423
|
+
const pkgDir = join(projectRoot, "node_modules", source);
|
|
17424
|
+
const pkgJsonPath = join(pkgDir, "package.json");
|
|
17425
|
+
if (!existsSync(pkgJsonPath)) {
|
|
17426
|
+
throw new Error(`Cannot find package '${source}' in ${join(projectRoot, "node_modules")}`);
|
|
17427
|
+
}
|
|
17428
|
+
const pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
|
|
17429
|
+
const entry = (typeof pkgJson.exports === "string" ? pkgJson.exports : null) ?? (typeof pkgJson.main === "string" ? pkgJson.main : null) ?? "index.js";
|
|
17430
|
+
const resolved = resolve(pkgDir, entry);
|
|
17431
|
+
if (!existsSync(resolved)) {
|
|
17432
|
+
throw new Error(`Package '${source}' entry '${entry}' does not exist at ${resolved}`);
|
|
17433
|
+
}
|
|
17434
|
+
return resolved;
|
|
17435
|
+
}
|
|
17436
|
+
function isLocalSource(source) {
|
|
17437
|
+
return source.startsWith("file:") || source.startsWith("./") || source.startsWith("../") || source.startsWith("/") || // Windows absolute paths: `D:\foo`, `C:/bar`, etc. `node:path`'s `resolve()` produces
|
|
17438
|
+
// these on win32, and they must not be misinterpreted as bare npm package names.
|
|
17439
|
+
/^[A-Za-z]:[/\\]/.test(source);
|
|
17440
|
+
}
|
|
17221
17441
|
async function importPluginModule(entry, projectRoot) {
|
|
17222
17442
|
const { source } = entry;
|
|
17223
17443
|
let importTarget;
|
|
17224
|
-
if (
|
|
17444
|
+
if (isLocalSource(source)) {
|
|
17225
17445
|
const raw = source.startsWith("file:") ? fileURLToPath(source) : source;
|
|
17226
17446
|
const resolved = resolve(projectRoot, raw);
|
|
17227
17447
|
importTarget = pathToFileURL(resolved).href;
|
|
17228
17448
|
} else {
|
|
17229
|
-
|
|
17449
|
+
const resolved = resolveNpmSpecifier(source, projectRoot);
|
|
17450
|
+
importTarget = pathToFileURL(resolved).href;
|
|
17230
17451
|
}
|
|
17231
17452
|
const mod = await import(importTarget);
|
|
17232
17453
|
return mod;
|
|
@@ -17265,18 +17486,29 @@ async function loadPlugin(entry, projectRoot) {
|
|
|
17265
17486
|
}
|
|
17266
17487
|
async function loadAllPlugins(entries, projectRoot) {
|
|
17267
17488
|
const results = [];
|
|
17268
|
-
|
|
17489
|
+
const envStrict = process.env.AGENTSMESH_STRICT_PLUGINS === "1" || process.env.AGENTSMESH_STRICT_PLUGINS === "true";
|
|
17490
|
+
const settled = await Promise.all(
|
|
17269
17491
|
entries.map(async (entry) => {
|
|
17270
17492
|
try {
|
|
17271
17493
|
const loaded = await loadPlugin(entry, projectRoot);
|
|
17272
17494
|
results.push(loaded);
|
|
17495
|
+
return null;
|
|
17273
17496
|
} catch (err) {
|
|
17274
|
-
|
|
17275
|
-
|
|
17276
|
-
|
|
17497
|
+
const message = `Plugin '${entry.source}' failed to load: ${err instanceof Error ? err.message : String(err)}`;
|
|
17498
|
+
if (entry.strict === true || envStrict) {
|
|
17499
|
+
return new Error(message);
|
|
17500
|
+
}
|
|
17501
|
+
logger.warn(message);
|
|
17502
|
+
return null;
|
|
17277
17503
|
}
|
|
17278
17504
|
})
|
|
17279
17505
|
);
|
|
17506
|
+
const fatal = settled.filter((e) => e !== null);
|
|
17507
|
+
if (fatal.length > 0) {
|
|
17508
|
+
const summary = fatal.map((e) => ` - ${e.message}`).join("\n");
|
|
17509
|
+
throw new Error(`agentsmesh: ${fatal.length} plugin(s) failed strict load:
|
|
17510
|
+
${summary}`);
|
|
17511
|
+
}
|
|
17280
17512
|
return results;
|
|
17281
17513
|
}
|
|
17282
17514
|
|