agentsmesh 0.19.1 → 0.21.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 +87 -0
- package/README.md +31 -1
- package/dist/canonical.js +66 -13
- package/dist/canonical.js.map +1 -1
- package/dist/cli.js +165 -160
- package/dist/engine.js +66 -13
- package/dist/engine.js.map +1 -1
- package/dist/index.js +66 -13
- package/dist/index.js.map +1 -1
- package/dist/targets.js +7 -2
- package/dist/targets.js.map +1 -1
- package/package.json +2 -2
- package/schemas/installs.json +7 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,92 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.21.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- b1efca1: Harden install pipeline against third-party supply-chain attacks.
|
|
8
|
+
- **Strip elevated artifacts from non-local sources by default.** `hooks.yaml`, `permissions.yaml`, and `mcp.json` are now removed from any pack installed from a `github:`, `gitlab:`, or `git+...` source unless you opt in. These three files control your agent's tool settings (shell hooks, granted permissions, MCP launch specs) and a malicious pack shipping any of them could otherwise execute arbitrary local commands the next time the matching event fires. Opt in per-artifact with `--accept-hooks`, `--accept-permissions`, `--accept-mcp`, or all three with `--accept-elevated`. Local sources remain trusted as before.
|
|
9
|
+
- **Skill supporting-file traversal no longer follows symlinks.** A pack containing `skills/foo/keys -> /Users/victim/.ssh` previously pulled external bytes (private keys, etc.) into the canonical skill content. Skill traversal now uses the existing `readDirRecursiveNoSymlinks` helper, mirroring the hardening already applied to install-manifest hashing.
|
|
10
|
+
- **Redact credentials from remote-fetch error output.** `oauth2:<token>@`, `x-access-token:<token>@`, and any other userinfo-bearing URLs are now masked (`https://***@host/...`) in console warnings and thrown error messages so GitHub PATs and GitLab tokens never leak into CI logs, terminal scrollback, or log shippers.
|
|
11
|
+
- **Gate `git+file://` sources behind `AGENTSMESH_ALLOW_LOCAL_GIT=1`.** On shared/multi-tenant hosts a `git+file:///tmp/world-writable-repo` `extends:` clause could silently consume a repo planted by another user; combined with downstream elevated-artifact emission this was a local priv-esc vector. Set `AGENTSMESH_ALLOW_LOCAL_GIT=1` to enable for closed-network development.
|
|
12
|
+
- **Allowlist tar entry types on GitHub tarball extraction.** Previously only `Link` and `SymbolicLink` were rejected (denylist). Now only `File` and `Directory` entries extract; FIFOs, devices, hardlinks, and any future/exotic tar variant are rejected by default.
|
|
13
|
+
|
|
14
|
+
These changes apply to `agentsmesh install`, `agentsmesh refresh`, and any `extends:` resolution against a non-local source. They are behavior changes for users who were silently inheriting hooks/permissions/mcp from a remote pack — re-run with the matching `--accept-*` flag (or `--accept-elevated`) to preserve previous behavior intentionally.
|
|
15
|
+
|
|
16
|
+
## 0.20.0
|
|
17
|
+
|
|
18
|
+
### Minor Changes
|
|
19
|
+
|
|
20
|
+
- 6739c63: feat(refresh): add `agentsmesh refresh` to re-fetch and re-apply installed packs
|
|
21
|
+
|
|
22
|
+
A new top-level CLI command and MCP tool for keeping installed packs in
|
|
23
|
+
sync with their declared sources. Branch pins re-resolve to the current
|
|
24
|
+
tip; tag pins re-resolve in case the tag moved; SHA pins stay put. Per-pack
|
|
25
|
+
atomic via the existing `materializePack` swap — a failure or interruption
|
|
26
|
+
leaves the affected pack at its pre-refresh state.
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
agentsmesh refresh # refresh every installed pack
|
|
30
|
+
agentsmesh refresh my-pack,other-pack # refresh just these
|
|
31
|
+
agentsmesh refresh --dry-run # preview without writing
|
|
32
|
+
agentsmesh refresh --force # skip the drift consent prompt
|
|
33
|
+
agentsmesh refresh --json # JSON output (implies --force)
|
|
34
|
+
agentsmesh refresh --global # global scope
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**MCP parity:** new `mcp__agentsmesh__refresh` tool with the same
|
|
38
|
+
`{ names?, dry_run?, global? }` input shape MCP install/uninstall use.
|
|
39
|
+
`force: true` is implicit (no TTY). Errors map to two new codes —
|
|
40
|
+
`REFRESH_RESOLVE_FAILED` and `REFRESH_APPLY_FAILED` — plus the existing
|
|
41
|
+
`LOCK_HELD` and `IO_ERROR`.
|
|
42
|
+
|
|
43
|
+
**Drift handling:** modified pack files trigger a consolidated consent
|
|
44
|
+
prompt with a 5-minute timeout (default no). `--force` bypasses the prompt
|
|
45
|
+
and overwrites local edits. The prompt is collapsed across packs so a bulk
|
|
46
|
+
refresh asks once, not N times.
|
|
47
|
+
|
|
48
|
+
**Schema additions** (`installs.yaml`, all optional, backwards-compatible):
|
|
49
|
+
- `original_ref?: string` — the user's original ref expression (e.g.
|
|
50
|
+
`main`, `v1.2.3`) captured at install time. Used by refresh to
|
|
51
|
+
re-resolve branch pins. Absent on installs predating this release;
|
|
52
|
+
refresh becomes a deterministic no-op for those rows.
|
|
53
|
+
- `refreshed_at?: string` — ISO-8601 timestamp of the last successful
|
|
54
|
+
refresh. Surfaces in `installs list` under the "LAST TOUCHED" column
|
|
55
|
+
(falls back to `installed_at` when absent).
|
|
56
|
+
|
|
57
|
+
**Behavior changes that could affect existing consumers:**
|
|
58
|
+
- `installs.yaml` rows written by this release include `original_ref`.
|
|
59
|
+
Pre-existing rows continue to parse and behave identically.
|
|
60
|
+
- `--json` on `agentsmesh refresh` implies `--force` (CI/MCP can't
|
|
61
|
+
answer the consent prompt). Documented on the website CLI reference.
|
|
62
|
+
- `installs list` column header was "INSTALLED AT", now "LAST TOUCHED",
|
|
63
|
+
showing `refreshed_at` when present and `installed_at` otherwise.
|
|
64
|
+
|
|
65
|
+
**Architecture notes:**
|
|
66
|
+
- `installAsPack` gains an optional `forceFreshMaterialize` flag,
|
|
67
|
+
threaded through five layers (`install-flags → run-install →
|
|
68
|
+
run-install-locked → single-pack-install → run-install-execute →
|
|
69
|
+
installAsPack`). Default is false; install's existing flow is
|
|
70
|
+
untouched. Refresh sets the flag to bypass the
|
|
71
|
+
merge-into-existing-pack branch and force atomic replacement via
|
|
72
|
+
`materializePack`.
|
|
73
|
+
- Source-URL parsing is now shared between install and refresh via the
|
|
74
|
+
new pure `parseSourceUrl` helper (`src/install/source/parse-source-url.ts`).
|
|
75
|
+
|
|
76
|
+
**Refresh does NOT switch refs.** To move a pack to a different ref,
|
|
77
|
+
re-run `agentsmesh install <source>@<new-ref>` — install silently
|
|
78
|
+
overwrites an existing pack of the same name.
|
|
79
|
+
|
|
80
|
+
**Refresh vs `install --sync`** are orthogonal. `--sync` replays missing
|
|
81
|
+
installs from `installs.yaml` (fresh clone). `refresh` updates existing
|
|
82
|
+
installs against their declared sources.
|
|
83
|
+
|
|
84
|
+
Verified end-to-end against 64 community packs from the install
|
|
85
|
+
compatibility log spanning Anthropic skill-packs, marketplaces (`--all`),
|
|
86
|
+
canonical mixed packs, flat collections, root SKILL.md, root CLAUDE.md,
|
|
87
|
+
manual `--path`/`--as`/`--target` combinations, and packs using `pick`
|
|
88
|
+
selectors. Full unit/integration/e2e suite green (7700+ tests).
|
|
89
|
+
|
|
3
90
|
## 0.19.1
|
|
4
91
|
|
|
5
92
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -233,8 +233,10 @@ agentsmesh check [--global]
|
|
|
233
233
|
agentsmesh merge [--global]
|
|
234
234
|
agentsmesh matrix [--global] [--targets <csv>] [--verbose]
|
|
235
235
|
agentsmesh install <source> [--sync] [--path <dir>] [--target <id>] [--as <kind>] [--name <id>] [--extends] [--all] [--dry-run] [--global] [--force]
|
|
236
|
+
[--accept-hooks|--accept-permissions|--accept-mcp|--accept-elevated]
|
|
236
237
|
agentsmesh uninstall <name>[,<name>...] [--all] [--keep-pack] [--keep-generated] [--dry-run] [--global] [--force]
|
|
237
238
|
agentsmesh installs list [--global]
|
|
239
|
+
agentsmesh refresh [<name>[,<name>...]] [--dry-run] [--force] [--json] [--global]
|
|
238
240
|
agentsmesh plugin add|list|remove|info [--version <v>] [--id <id>]
|
|
239
241
|
agentsmesh target scaffold <id> [--name <displayName>] [--force]
|
|
240
242
|
```
|
|
@@ -314,6 +316,34 @@ agentsmesh uninstall <name> --dry-run # preview; no writes
|
|
|
314
316
|
|
|
315
317
|
Each install writes `.agentsmesh-install-manifest.json` next to the pack with per-file sha256 hashes; uninstall compares current contents against that manifest and prompts before deleting locally-modified files. `--force` accepts the documented defaults (bulk = accept all, broken-link = leave-with-warnings, modified = delete-anyway). `.agentsmesh/.install.lock` serialises install/uninstall so concurrent runs on the same project fail fast rather than racing on disk.
|
|
316
318
|
|
|
319
|
+
### Refreshing packs
|
|
320
|
+
|
|
321
|
+
`agentsmesh refresh` re-fetches every installed pack from its recorded source/ref
|
|
322
|
+
and re-applies it. Branch pins (`@main`) advance to the current tip; tag pins
|
|
323
|
+
re-resolve in case the tag moved; SHA pins stay put (re-fetch with the same content).
|
|
324
|
+
|
|
325
|
+
```bash
|
|
326
|
+
agentsmesh refresh # refresh every installed pack
|
|
327
|
+
agentsmesh refresh my-pack,other-pack # refresh just these
|
|
328
|
+
agentsmesh refresh --dry-run # preview without writing
|
|
329
|
+
agentsmesh refresh --force # skip the drift prompt
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
Each pack is refreshed atomically — a failure or interruption leaves the
|
|
333
|
+
affected pack at its pre-refresh state. Local edits to pack files trigger
|
|
334
|
+
a consolidated consent prompt (5-minute timeout) unless `--force` is set.
|
|
335
|
+
|
|
336
|
+
**refresh does NOT switch refs.** To move a pack to a different ref, just install
|
|
337
|
+
with the new ref — install silently overwrites an existing pack of the same name:
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
agentsmesh install github:org/repo@v2.0.0
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
**refresh vs `install --sync`.** `--sync` replays missing installs from
|
|
344
|
+
`installs.yaml` (e.g. after a fresh clone). `refresh` updates existing
|
|
345
|
+
installs against their declared sources. They are orthogonal.
|
|
346
|
+
|
|
317
347
|
### What to commit and what to gitignore
|
|
318
348
|
|
|
319
349
|
`agentsmesh init` writes a `.gitignore` that follows the recommended convention. The defaults are deliberate:
|
|
@@ -457,7 +487,7 @@ See the [full feature matrix docs](https://samplexbro.github.io/agentsmesh/refer
|
|
|
457
487
|
|
|
458
488
|
- **[Getting Started](https://samplexbro.github.io/agentsmesh/getting-started/installation/)** — installation, quick start
|
|
459
489
|
- **[Canonical Config](https://samplexbro.github.io/agentsmesh/canonical-config/)** — rules, commands, agents, skills, MCP, hooks, ignore, permissions
|
|
460
|
-
- **[CLI Reference](https://samplexbro.github.io/agentsmesh/cli/)** — `init`, `generate`, `import`, `convert`, `install`, `uninstall`, `installs`, `diff`, `lint`, `watch`, `check`, `merge`, `matrix`, `plugin`, `target`
|
|
490
|
+
- **[CLI Reference](https://samplexbro.github.io/agentsmesh/cli/)** — `init`, `generate`, `import`, `convert`, `install`, `uninstall`, `installs`, `refresh`, `diff`, `lint`, `watch`, `check`, `merge`, `matrix`, `plugin`, `target`
|
|
461
491
|
- **[Configuration](https://samplexbro.github.io/agentsmesh/configuration/agentsmesh-yaml/)** — `agentsmesh.yaml`, local overrides, extends, collaboration, conversions
|
|
462
492
|
- **[Guides](https://samplexbro.github.io/agentsmesh/guides/existing-project/)** — adopting in existing projects · multi-tool teams · sharing config · CI drift detection · community packs · **building plugins**
|
|
463
493
|
- **[Reference](https://samplexbro.github.io/agentsmesh/reference/generation-pipeline/)** — supported tools matrix · generation pipeline · managed embedding
|
package/dist/canonical.js
CHANGED
|
@@ -185,6 +185,33 @@ async function readDirRecursive(dir, visited, branchSegments) {
|
|
|
185
185
|
);
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
|
+
async function readDirRecursiveNoSymlinks(dir, branchSegments) {
|
|
189
|
+
const currentBranchSegments = branchSegments ?? [basename(dir)];
|
|
190
|
+
try {
|
|
191
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
192
|
+
const files = [];
|
|
193
|
+
for (const ent of entries) {
|
|
194
|
+
if (ent.isSymbolicLink()) continue;
|
|
195
|
+
const full = join(dir, ent.name);
|
|
196
|
+
if (ent.isDirectory()) {
|
|
197
|
+
const nextSegments = [...currentBranchSegments, ent.name];
|
|
198
|
+
if (shouldSkipRecursiveBranch(nextSegments)) continue;
|
|
199
|
+
files.push(...await readDirRecursiveNoSymlinks(full, nextSegments));
|
|
200
|
+
} else if (ent.isFile()) {
|
|
201
|
+
files.push(full);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return files;
|
|
205
|
+
} catch (err) {
|
|
206
|
+
const e = err;
|
|
207
|
+
if (e.code === "ENOENT" || e.code === "ENOTDIR" || e.code === "EACCES") return [];
|
|
208
|
+
throw new FileSystemError(
|
|
209
|
+
dir,
|
|
210
|
+
`Failed to read directory ${dir}: ${e.message}. Check permissions.`,
|
|
211
|
+
{ cause: err, errnoCode: e.code }
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
188
215
|
var MAX_RECURSIVE_DEPTH, MAX_SEGMENT_REPETITIONS;
|
|
189
216
|
var init_fs_traverse = __esm({
|
|
190
217
|
"src/utils/filesystem/fs-traverse.ts"() {
|
|
@@ -1023,7 +1050,7 @@ ${legacy}`, "");
|
|
|
1023
1050
|
}
|
|
1024
1051
|
return result.trim();
|
|
1025
1052
|
}
|
|
1026
|
-
var ROOT_INSTRUCTION_BODY_V1, ROOT_INSTRUCTION_BODY_V2, ROOT_INSTRUCTION_BODY_V3, ROOT_INSTRUCTION_BODY_V4, ROOT_INSTRUCTION_BODY_V5, ROOT_INSTRUCTION_BODY_V6, ROOT_INSTRUCTION_BODY_V7, ROOT_INSTRUCTION_BODY, LEGACY_AGENTSMESH_ROOT_INSTRUCTION_PARAGRAPH, LEGACY_AGENTSMESH_ROOT_INSTRUCTION_SECTION, AGENTSMESH_CONTRACT_WITH_V1_BODY, AGENTSMESH_CONTRACT_WITH_V2_BODY, AGENTSMESH_CONTRACT_WITH_V3_BODY, AGENTSMESH_CONTRACT_WITH_V4_BODY, AGENTSMESH_CONTRACT_WITH_V5_BODY, AGENTSMESH_CONTRACT_WITH_V6_BODY, AGENTSMESH_CONTRACT_WITH_V7_BODY, AGENTSMESH_ROOT_INSTRUCTION_PARAGRAPH, LEGACY_FORMS;
|
|
1053
|
+
var ROOT_INSTRUCTION_BODY_V1, ROOT_INSTRUCTION_BODY_V2, ROOT_INSTRUCTION_BODY_V3, ROOT_INSTRUCTION_BODY_V4, ROOT_INSTRUCTION_BODY_V5, ROOT_INSTRUCTION_BODY_V6, ROOT_INSTRUCTION_BODY_V7, ROOT_INSTRUCTION_BODY_V8, ROOT_INSTRUCTION_BODY, LEGACY_AGENTSMESH_ROOT_INSTRUCTION_PARAGRAPH, LEGACY_AGENTSMESH_ROOT_INSTRUCTION_SECTION, AGENTSMESH_CONTRACT_WITH_V1_BODY, AGENTSMESH_CONTRACT_WITH_V2_BODY, AGENTSMESH_CONTRACT_WITH_V3_BODY, AGENTSMESH_CONTRACT_WITH_V4_BODY, AGENTSMESH_CONTRACT_WITH_V5_BODY, AGENTSMESH_CONTRACT_WITH_V6_BODY, AGENTSMESH_CONTRACT_WITH_V7_BODY, AGENTSMESH_CONTRACT_WITH_V8_BODY, AGENTSMESH_ROOT_INSTRUCTION_PARAGRAPH, LEGACY_FORMS;
|
|
1027
1054
|
var init_root_instruction_paragraph = __esm({
|
|
1028
1055
|
"src/targets/projection/root-instruction-paragraph.ts"() {
|
|
1029
1056
|
init_managed_blocks();
|
|
@@ -1034,7 +1061,8 @@ var init_root_instruction_paragraph = __esm({
|
|
|
1034
1061
|
ROOT_INSTRUCTION_BODY_V5 = "Use Claude-style Markdown in `.agentsmesh`: `agents/*.md`, `commands/*.md`, and `skills/*/SKILL.md`; keep rules in `rules/*.md`, hooks in `hooks.yaml`, MCP in `mcp.json`, permissions in `permissions.yaml`, and ignore patterns in `ignore`, then run `agentsmesh generate`.";
|
|
1035
1062
|
ROOT_INSTRUCTION_BODY_V6 = "Create canonical files in `.agentsmesh`: `rules/_root.md` and `rules/*.md` are Markdown rules; `commands/*.md`, `agents/*.md`, and `skills/*/SKILL.md` plus supporting files use Claude-style frontmatter Markdown; `mcp.json` is MCP JSON; `hooks.yaml` and `permissions.yaml` are YAML; `ignore` is gitignore-style text. Then run `agentsmesh generate`.";
|
|
1036
1063
|
ROOT_INSTRUCTION_BODY_V7 = "`.agentsmesh` is the only folder you edit or add these files in: `rules/_root.md` and `rules/*.md` are Markdown rules; `commands/*.md`, `agents/*.md`, and `skills/*/SKILL.md` plus supporting files use Claude-style frontmatter Markdown; `mcp.json` is MCP JSON; `hooks.yaml` and `permissions.yaml` are YAML; `ignore` is gitignore-style text. Do not edit generated tool files; run `agentsmesh generate`.";
|
|
1037
|
-
|
|
1064
|
+
ROOT_INSTRUCTION_BODY_V8 = "`agentsmesh.yaml` selects targets/features (`agentsmesh.local.yaml` overrides locally), and `.agentsmesh` is the only place to add or edit canonical items: `rules/_root.md`, `rules/*.md`, `commands/*.md`, `agents/*.md`, `skills/*/SKILL.md` plus supporting files, `mcp.json`, `hooks.yaml`, `permissions.yaml`, and `ignore`; if missing run `agentsmesh init`, use `agentsmesh import --from <tool>` for native configs, `agentsmesh install <source>` or `install --sync` for reusable packs, then run `agentsmesh generate`. Use `diff`, `lint`, `check`, `watch`, `matrix`, and `merge` as needed; never edit generated tool files.";
|
|
1065
|
+
ROOT_INSTRUCTION_BODY = "`agentsmesh.yaml` selects targets/features (`agentsmesh.local.yaml` overrides locally), and `.agentsmesh` is the only place to add or edit canonical items: `rules/_root.md`, `rules/*.md`, `commands/*.md`, `agents/*.md`, `skills/*/SKILL.md` plus supporting files, `mcp.json`, `hooks.yaml`, `permissions.yaml`, and `ignore`; if missing run `agentsmesh init`, use `agentsmesh import --from <tool>` for native configs, `agentsmesh install <source>` or `install --sync` for reusable packs, then run `agentsmesh generate`. Use `diff`, `lint`, `check`, `watch`, `matrix`, `merge`, and `refresh` as needed; never edit generated tool files.";
|
|
1038
1066
|
LEGACY_AGENTSMESH_ROOT_INSTRUCTION_PARAGRAPH = ROOT_INSTRUCTION_BODY_V1;
|
|
1039
1067
|
LEGACY_AGENTSMESH_ROOT_INSTRUCTION_SECTION = `## Project-Specific Rules
|
|
1040
1068
|
|
|
@@ -1060,12 +1088,16 @@ ${ROOT_INSTRUCTION_BODY_V6}`;
|
|
|
1060
1088
|
AGENTSMESH_CONTRACT_WITH_V7_BODY = `## AgentsMesh Generation Contract
|
|
1061
1089
|
|
|
1062
1090
|
${ROOT_INSTRUCTION_BODY_V7}`;
|
|
1091
|
+
AGENTSMESH_CONTRACT_WITH_V8_BODY = `## AgentsMesh Generation Contract
|
|
1092
|
+
|
|
1093
|
+
${ROOT_INSTRUCTION_BODY_V8}`;
|
|
1063
1094
|
AGENTSMESH_ROOT_INSTRUCTION_PARAGRAPH = `${ROOT_CONTRACT_START}
|
|
1064
1095
|
## AgentsMesh Generation Contract
|
|
1065
1096
|
|
|
1066
1097
|
${ROOT_INSTRUCTION_BODY}
|
|
1067
1098
|
${ROOT_CONTRACT_END}`;
|
|
1068
1099
|
LEGACY_FORMS = [
|
|
1100
|
+
AGENTSMESH_CONTRACT_WITH_V8_BODY,
|
|
1069
1101
|
AGENTSMESH_CONTRACT_WITH_V7_BODY,
|
|
1070
1102
|
AGENTSMESH_CONTRACT_WITH_V6_BODY,
|
|
1071
1103
|
AGENTSMESH_CONTRACT_WITH_V5_BODY,
|
|
@@ -18726,6 +18758,19 @@ init_fs();
|
|
|
18726
18758
|
|
|
18727
18759
|
// src/config/remote/git-remote.ts
|
|
18728
18760
|
init_fs();
|
|
18761
|
+
|
|
18762
|
+
// src/utils/output/redact-url-secrets.ts
|
|
18763
|
+
var URL_WITH_CREDENTIALS = /([a-zA-Z][a-zA-Z0-9+.-]*:\/\/)([^/@\s"'<>]+)@([^\s"'<>]+)/g;
|
|
18764
|
+
function redactUrlSecrets(message) {
|
|
18765
|
+
return message.replace(
|
|
18766
|
+
URL_WITH_CREDENTIALS,
|
|
18767
|
+
(_full, scheme, _userinfo, rest) => {
|
|
18768
|
+
return `${scheme}***@${rest}`;
|
|
18769
|
+
}
|
|
18770
|
+
);
|
|
18771
|
+
}
|
|
18772
|
+
|
|
18773
|
+
// src/config/remote/git-remote.ts
|
|
18729
18774
|
var execFileAsync = promisify(execFile);
|
|
18730
18775
|
var REPO_DIRNAME = "repo";
|
|
18731
18776
|
function ensureNotFlag(value, kind) {
|
|
@@ -18759,12 +18804,13 @@ async function fetchGitRemoteExtend(parsed, extendName, options, cacheDir, build
|
|
|
18759
18804
|
await rm(stagedRoot, { recursive: true, force: true });
|
|
18760
18805
|
const allowFallback = options.allowOfflineFallback !== false;
|
|
18761
18806
|
if (allowFallback && await hasCachedRepo(cacheRepoDir)) {
|
|
18807
|
+
const rawMsg = err instanceof Error ? err.message : String(err);
|
|
18762
18808
|
console.warn(
|
|
18763
|
-
`[agentsmesh] Remote fetch failed for ${extendName}; using cached version. Error: ${
|
|
18809
|
+
`[agentsmesh] Remote fetch failed for ${extendName}; using cached version. Error: ${redactUrlSecrets(rawMsg)}`
|
|
18764
18810
|
);
|
|
18765
18811
|
return readCachedRepo(cacheRepoDir);
|
|
18766
18812
|
}
|
|
18767
|
-
throw err;
|
|
18813
|
+
throw err instanceof Error ? Object.assign(new Error(redactUrlSecrets(err.message)), { cause: err.cause }) : err;
|
|
18768
18814
|
}
|
|
18769
18815
|
}
|
|
18770
18816
|
async function readCachedRepo(repoDir) {
|
|
@@ -18925,13 +18971,14 @@ async function fetchGithubRemoteExtend(parsed, extendName, options, cacheDir, bu
|
|
|
18925
18971
|
if (allowFallback && await exists(extractDir)) {
|
|
18926
18972
|
const topDir2 = await findExtractTopDir(extractDir);
|
|
18927
18973
|
if (topDir2) {
|
|
18974
|
+
const rawMsg = err instanceof Error ? err.message : String(err);
|
|
18928
18975
|
console.warn(
|
|
18929
|
-
`[agentsmesh] Network failed for ${extendName}; using cached version. Error: ${
|
|
18976
|
+
`[agentsmesh] Network failed for ${extendName}; using cached version. Error: ${redactUrlSecrets(rawMsg)}`
|
|
18930
18977
|
);
|
|
18931
18978
|
return { resolvedPath: join(extractDir, topDir2), version: tag };
|
|
18932
18979
|
}
|
|
18933
18980
|
}
|
|
18934
|
-
throw err;
|
|
18981
|
+
throw err instanceof Error ? Object.assign(new Error(redactUrlSecrets(err.message)), { cause: err.cause }) : err;
|
|
18935
18982
|
}
|
|
18936
18983
|
await rm(extractDir, { recursive: true, force: true });
|
|
18937
18984
|
await mkdir(extractDir, { recursive: true });
|
|
@@ -18942,12 +18989,14 @@ async function fetchGithubRemoteExtend(parsed, extendName, options, cacheDir, bu
|
|
|
18942
18989
|
file: tarPath,
|
|
18943
18990
|
cwd: extractDir,
|
|
18944
18991
|
strict: true,
|
|
18992
|
+
// Allowlist entry types instead of denylist: only `File` and `Directory`
|
|
18993
|
+
// can be extracted. Hardlinks (`Link`), symlinks (`SymbolicLink`), FIFOs,
|
|
18994
|
+
// character/block devices, and any future/exotic tar entry type are
|
|
18995
|
+
// rejected. A denylist would silently let an unknown variant through.
|
|
18945
18996
|
filter: (entryPath, entry) => {
|
|
18946
18997
|
if (isZipSlipPath(entryPath)) return false;
|
|
18947
|
-
|
|
18948
|
-
|
|
18949
|
-
}
|
|
18950
|
-
return true;
|
|
18998
|
+
const type = entry && "type" in entry ? entry.type : void 0;
|
|
18999
|
+
return type === "File" || type === "Directory";
|
|
18951
19000
|
}
|
|
18952
19001
|
});
|
|
18953
19002
|
} finally {
|
|
@@ -19045,8 +19094,11 @@ function parseGitSource(source) {
|
|
|
19045
19094
|
return null;
|
|
19046
19095
|
}
|
|
19047
19096
|
const allowInsecure = process.env.AGENTSMESH_ALLOW_INSECURE_GIT === "1" || process.env.AGENTSMESH_ALLOW_INSECURE_GIT === "true";
|
|
19048
|
-
const
|
|
19049
|
-
|
|
19097
|
+
const allowLocalGit = process.env.AGENTSMESH_ALLOW_LOCAL_GIT === "1" || process.env.AGENTSMESH_ALLOW_LOCAL_GIT === "true";
|
|
19098
|
+
const allowed = ["https:", "ssh:"];
|
|
19099
|
+
if (allowInsecure) allowed.push("http:");
|
|
19100
|
+
if (allowLocalGit) allowed.push("file:");
|
|
19101
|
+
if (!allowed.includes(parsedUrl.protocol)) {
|
|
19050
19102
|
return null;
|
|
19051
19103
|
}
|
|
19052
19104
|
return { url, ref };
|
|
@@ -19571,6 +19623,7 @@ async function parseAgents(agentsDir, opts = {}) {
|
|
|
19571
19623
|
|
|
19572
19624
|
// src/canonical/features/skills.ts
|
|
19573
19625
|
init_fs();
|
|
19626
|
+
init_fs_traverse();
|
|
19574
19627
|
init_markdown();
|
|
19575
19628
|
init_boilerplate_filter();
|
|
19576
19629
|
async function readContent(path) {
|
|
@@ -19589,7 +19642,7 @@ function sanitizeSkillName(raw) {
|
|
|
19589
19642
|
return raw.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
19590
19643
|
}
|
|
19591
19644
|
async function listSupportingFiles(skillDir) {
|
|
19592
|
-
const files = await
|
|
19645
|
+
const files = await readDirRecursiveNoSymlinks(skillDir);
|
|
19593
19646
|
const result = [];
|
|
19594
19647
|
for (const absPath of files) {
|
|
19595
19648
|
const raw = absPath.slice(skillDir.length + 1);
|