@yanlinglabs/winter-agent-sdk 0.0.40 → 0.0.43
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/dist/index.js
CHANGED
|
@@ -430,7 +430,8 @@ function toWireMcpServers(servers) {
|
|
|
430
430
|
...cfg.timeout !== undefined ? { timeout: cfg.timeout } : {},
|
|
431
431
|
...isWinterMcpServerInstance(cfg.instance) ? { tools: cfg.instance.listTools() } : {},
|
|
432
432
|
...cfg.toolNames !== undefined ? { toolNames: { ...cfg.toolNames } } : {},
|
|
433
|
-
...cfg.toolLanes !== undefined ? { toolLanes: { ...cfg.toolLanes } } : {}
|
|
433
|
+
...cfg.toolLanes !== undefined ? { toolLanes: { ...cfg.toolLanes } } : {},
|
|
434
|
+
...Array.isArray(cfg.concurrentTools) ? { concurrentTools: [...cfg.concurrentTools] } : {}
|
|
434
435
|
} : cfg;
|
|
435
436
|
}
|
|
436
437
|
return out;
|
|
@@ -1270,32 +1271,38 @@ function withTestKeychainRedirect(env) {
|
|
|
1270
1271
|
return { ...env, [TEST_KEYCHAIN_ENV]: redirect };
|
|
1271
1272
|
}
|
|
1272
1273
|
// src/version.ts
|
|
1273
|
-
var SDK_VERSION = "0.0.
|
|
1274
|
+
var SDK_VERSION = "0.0.43";
|
|
1274
1275
|
// src/paths/project-key.ts
|
|
1275
1276
|
var TRANSCRIPT_PROJECT_KEY_MAX_LENGTH = 64;
|
|
1276
1277
|
var VENDOR_PROJECT_KEY_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;
|
|
1277
1278
|
function isVendorCompliantProjectKey(key) {
|
|
1278
1279
|
return VENDOR_PROJECT_KEY_PATTERN.test(key);
|
|
1279
1280
|
}
|
|
1280
|
-
function
|
|
1281
|
-
return
|
|
1281
|
+
function isAsciiAlphanumeric(code) {
|
|
1282
|
+
return code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 97 && code <= 122;
|
|
1282
1283
|
}
|
|
1283
|
-
function
|
|
1284
|
-
let
|
|
1285
|
-
for (let i = 0;i <
|
|
1286
|
-
|
|
1284
|
+
function sanitizeForKey(text) {
|
|
1285
|
+
let out = "";
|
|
1286
|
+
for (let i = 0;i < text.length; i++) {
|
|
1287
|
+
const code = text.charCodeAt(i);
|
|
1288
|
+
out += isAsciiAlphanumeric(code) ? text[i] : "-";
|
|
1287
1289
|
}
|
|
1288
|
-
return
|
|
1290
|
+
return out;
|
|
1289
1291
|
}
|
|
1290
|
-
function
|
|
1291
|
-
|
|
1292
|
+
function hashSuffix(text) {
|
|
1293
|
+
let hash = 0;
|
|
1294
|
+
for (let i = 0;i < text.length; i++) {
|
|
1295
|
+
hash = Math.imul(hash, 31) + text.charCodeAt(i) | 0;
|
|
1296
|
+
}
|
|
1297
|
+
return Math.abs(hash).toString(36);
|
|
1292
1298
|
}
|
|
1293
1299
|
function transcriptProjectKey(absPath) {
|
|
1294
|
-
const sanitized =
|
|
1300
|
+
const sanitized = sanitizeForKey(absPath);
|
|
1295
1301
|
if (sanitized.length <= TRANSCRIPT_PROJECT_KEY_MAX_LENGTH)
|
|
1296
1302
|
return sanitized;
|
|
1297
|
-
const suffix =
|
|
1298
|
-
|
|
1303
|
+
const suffix = hashSuffix(absPath);
|
|
1304
|
+
const prefixLength = TRANSCRIPT_PROJECT_KEY_MAX_LENGTH - 1 - suffix.length;
|
|
1305
|
+
return `${sanitized.slice(0, prefixLength)}-${suffix}`;
|
|
1299
1306
|
}
|
|
1300
1307
|
// src/paths/keys.ts
|
|
1301
1308
|
import { realpathSync } from "node:fs";
|
|
@@ -2052,52 +2059,52 @@ import { CATALOG_TAG_RENAMES } from "@yanlinglabs/winter-provider-catalog";
|
|
|
2052
2059
|
|
|
2053
2060
|
// src/plugins/manage.ts
|
|
2054
2061
|
import { mkdir, open, readFile as readFile2, rename, rmdir, unlink, writeFile } from "node:fs/promises";
|
|
2055
|
-
import { dirname as dirname3, isAbsolute as isAbsolute2, join as join3, resolve
|
|
2062
|
+
import { dirname as dirname3, isAbsolute as isAbsolute2, join as join3, resolve } from "node:path";
|
|
2056
2063
|
import { randomBytes } from "node:crypto";
|
|
2057
2064
|
|
|
2058
2065
|
// src/plugins/marketplace-path.ts
|
|
2059
|
-
import
|
|
2060
|
-
var
|
|
2061
|
-
function
|
|
2062
|
-
|
|
2063
|
-
}
|
|
2064
|
-
function normalizePluginRoot(pluginRoot) {
|
|
2065
|
-
if (typeof pluginRoot !== "string" || pluginRoot === "" || pluginRoot.startsWith("/") || pluginRoot.includes("\\") || pluginRoot.includes(":"))
|
|
2066
|
+
import path from "node:path";
|
|
2067
|
+
var MARKETPLACE_DIR = Symbol("marketplace-dir");
|
|
2068
|
+
function usableRoot(pluginRoot) {
|
|
2069
|
+
if (typeof pluginRoot !== "string")
|
|
2066
2070
|
return;
|
|
2067
|
-
|
|
2068
|
-
if (stripped === "" || stripped === ".")
|
|
2069
|
-
return ".";
|
|
2070
|
-
if (stripped.split("/").some((segment) => segment === "" || segment === "." || segment === ".."))
|
|
2071
|
+
if (pluginRoot === "" || pluginRoot.startsWith("/"))
|
|
2071
2072
|
return;
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
return normalized.startsWith("./") ? normalized : undefined;
|
|
2082
|
-
}
|
|
2083
|
-
function resolveWithinBase(base, relativePath) {
|
|
2084
|
-
const normalizedBase = resolve(base);
|
|
2085
|
-
const resolved = resolve(base, relativePath);
|
|
2086
|
-
if (resolved !== normalizedBase && !resolved.startsWith(normalizedBase + sep)) {
|
|
2087
|
-
throw new Error(`Path traversal detected: "${relativePath}" would escape the base directory`);
|
|
2073
|
+
if (pluginRoot.includes("\\") || pluginRoot.includes(":"))
|
|
2074
|
+
return;
|
|
2075
|
+
let rest = pluginRoot.startsWith("./") ? pluginRoot.slice(2) : pluginRoot;
|
|
2076
|
+
rest = rest.replace(/\/+$/, "");
|
|
2077
|
+
if (rest === "" || rest === ".")
|
|
2078
|
+
return MARKETPLACE_DIR;
|
|
2079
|
+
for (const piece of rest.split("/")) {
|
|
2080
|
+
if (piece === "" || piece === "." || piece === "..")
|
|
2081
|
+
return;
|
|
2088
2082
|
}
|
|
2089
|
-
return
|
|
2083
|
+
return rest;
|
|
2084
|
+
}
|
|
2085
|
+
function isBareName(source) {
|
|
2086
|
+
return /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(source) && !source.includes("..");
|
|
2090
2087
|
}
|
|
2091
2088
|
function resolveMarketplacePluginPath(installLocation, pluginRoot, source) {
|
|
2092
|
-
if (typeof source !== "string" || source === "")
|
|
2093
|
-
return;
|
|
2094
|
-
const normalizedRoot = normalizePluginRoot(pluginRoot);
|
|
2095
|
-
const prefixed = withPluginRootPrefix(source, normalizedRoot);
|
|
2096
|
-
const sourcePath = schemaSourcePath(prefixed);
|
|
2097
|
-
if (sourcePath === undefined)
|
|
2098
|
-
return;
|
|
2099
2089
|
try {
|
|
2100
|
-
|
|
2090
|
+
if (typeof source !== "string" || source === "")
|
|
2091
|
+
return;
|
|
2092
|
+
let relativePath = source;
|
|
2093
|
+
if (isBareName(source)) {
|
|
2094
|
+
const root = usableRoot(pluginRoot);
|
|
2095
|
+
if (root !== undefined) {
|
|
2096
|
+
relativePath = root === MARKETPLACE_DIR ? `./${source}` : `./${root}/${source}`;
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
2099
|
+
if (relativePath === ".")
|
|
2100
|
+
relativePath = "./";
|
|
2101
|
+
if (!relativePath.startsWith("./"))
|
|
2102
|
+
return;
|
|
2103
|
+
const base = path.resolve(installLocation);
|
|
2104
|
+
const candidate = path.resolve(installLocation, relativePath);
|
|
2105
|
+
if (candidate === base || candidate.startsWith(base + path.sep))
|
|
2106
|
+
return candidate;
|
|
2107
|
+
return;
|
|
2101
2108
|
} catch {
|
|
2102
2109
|
return;
|
|
2103
2110
|
}
|
|
@@ -2243,7 +2250,7 @@ function classifySource(source) {
|
|
|
2243
2250
|
if (/^[a-zA-Z0-9](?:[a-zA-Z0-9._-]*[a-zA-Z0-9])?\/[a-zA-Z0-9](?:[a-zA-Z0-9._-]*[a-zA-Z0-9])?$/.test(source) && !source.includes("..")) {
|
|
2244
2251
|
return { kind: "github", locator: source };
|
|
2245
2252
|
}
|
|
2246
|
-
return { kind: "directory", locator: isAbsolute2(source) ? source :
|
|
2253
|
+
return { kind: "directory", locator: isAbsolute2(source) ? source : resolve(source) };
|
|
2247
2254
|
}
|
|
2248
2255
|
function marketplaceInfoOf(name, record) {
|
|
2249
2256
|
const kind = record.source.source;
|
|
@@ -1,10 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Resolve one marketplace manifest plugin entry's install path -- the ONE function
|
|
3
|
-
* `packages/runtime/src/plugins/installed.ts` (the daemon's own directory-marketplace fallback,
|
|
4
|
-
* SV-4) and `packages/sdk/src/plugins/manage.ts` (`resolvePluginSourcePath`, the CLI-facing install
|
|
5
|
-
* command) both call, so the two can never resolve the identical manifest entry to two different
|
|
6
|
-
* paths. `undefined` for anything invalid or refused -- a bare name with no usable `pluginRoot`, an
|
|
7
|
-
* absolute/malformed source, or a path that would escape `installLocation` -- NEVER a throw a
|
|
8
|
-
* caller must remember to catch; each caller renders its own typed rejection from `undefined`.
|
|
9
|
-
*/
|
|
10
1
|
export declare function resolveMarketplacePluginPath(installLocation: string, pluginRoot: unknown, source: unknown): string | undefined;
|
|
@@ -406,6 +406,23 @@ export interface McpSdkServerConfig {
|
|
|
406
406
|
* ignored. Only an in-process (`sdk`) server may declare lanes; the host vouches for its own tools.
|
|
407
407
|
*/
|
|
408
408
|
toolLanes?: Record<string, string>;
|
|
409
|
+
/**
|
|
410
|
+
* SDK 0.0.41, a Winter extension: some of this server's tools, by the server's own tool name, that are
|
|
411
|
+
* SAFE TO RUN CONCURRENTLY without being read-only (`["session_spawn"]`). A round's calls normally run
|
|
412
|
+
* one at a time unless the tool is read-only (`readOnlyHint: true`); a tool listed here runs BESIDE the
|
|
413
|
+
* round's other concurrent calls (up to 10 at once), exactly like a read-only one -- several calls of it
|
|
414
|
+
* in one round run at the same time (claude runs several `Agent` calls of a round at once; this is the
|
|
415
|
+
* same thing for a host tool that starts work elsewhere).
|
|
416
|
+
*
|
|
417
|
+
* It is a SCHEDULING statement only. It never makes the tool read-only anywhere else: the tool's
|
|
418
|
+
* `annotations` are not touched, plan mode, permission evaluation, the hook input's `winter_mcp_server`
|
|
419
|
+
* and `canUseTool`'s `mcpServer` read the server's own `readOnlyHint` exactly as before. Use it only for a
|
|
420
|
+
* tool whose concurrent calls cannot interfere with each other (each call's work is its own); a tool
|
|
421
|
+
* that holds one exclusive resource belongs in a lane (`toolLanes`) instead. A tool named in BOTH is in
|
|
422
|
+
* its lane (the stricter answer). An entry that is not a string, or names no tool of this server, is
|
|
423
|
+
* ignored. Only an in-process (`sdk`) server may declare it; the host vouches for its own tools.
|
|
424
|
+
*/
|
|
425
|
+
concurrentTools?: string[];
|
|
409
426
|
}
|
|
410
427
|
export type McpServerConfigForProcessTransport = McpStdioServerConfig | McpHttpServerConfig | McpSSEServerConfig | McpSdkServerConfig;
|
|
411
428
|
export type AgentMcpServerSpec = string | Record<string, McpServerConfigForProcessTransport>;
|
package/dist/settings/types.d.ts
CHANGED
|
@@ -69,12 +69,10 @@ export interface Settings {
|
|
|
69
69
|
* `permissions.deny`'s own union exists to prevent; see `unionSandboxFilesystemDenyArrays` below).
|
|
70
70
|
* CORRECTED in fix round 10, item C: round 9 reasoned `allowWrite` should NOT union (a widening
|
|
71
71
|
* key should never accumulate) and used the ordinary replace-by-higher-tier merge for it instead
|
|
72
|
-
* -- the controller's round-10 ruling reverses this
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* round) is claude's own read carve-out (`getFsReadConfig`'s `allowWithinDeny`) -- carried and
|
|
77
|
-
* unioned identically for merge-parity, though `packages/runtime/src/sandbox/profile.ts`'s own
|
|
72
|
+
* -- the controller's round-10 ruling reverses this: Claude Code accumulates allowWrite entries
|
|
73
|
+
* from every source rather than letting one replace another, so Winter unions the widening array
|
|
74
|
+
* too. `allowRead` (also new this round) is the settings key for re-permitting reads inside a
|
|
75
|
+
* denied region -- carried and unioned identically for merge-parity, though `packages/runtime/src/sandbox/profile.ts`'s own
|
|
78
76
|
* `buildSeatbeltProfile` does not yet enforce it (a disclosed, fails-CLOSED gap: see that file's
|
|
79
77
|
* own `SandboxFilesystemSettings.allowRead` doc comment).
|
|
80
78
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yanlinglabs/winter-agent-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.43",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -45,15 +45,15 @@
|
|
|
45
45
|
}
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@yanlinglabs/winter-provider-catalog": "0.0.
|
|
48
|
+
"@yanlinglabs/winter-provider-catalog": "0.0.43"
|
|
49
49
|
},
|
|
50
50
|
"optionalDependencies": {
|
|
51
|
-
"@yanlinglabs/winter-agent-sdk-darwin-arm64": "0.0.
|
|
51
|
+
"@yanlinglabs/winter-agent-sdk-darwin-arm64": "0.0.43"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@types/node": "^26.4.0",
|
|
55
|
-
"@yanlinglabs/winter-agent-runtime": "0.0.
|
|
56
|
-
"@yanlinglabs/winter-conformance": "0.0.
|
|
55
|
+
"@yanlinglabs/winter-agent-runtime": "0.0.43",
|
|
56
|
+
"@yanlinglabs/winter-conformance": "0.0.43"
|
|
57
57
|
},
|
|
58
58
|
"scripts": {}
|
|
59
59
|
}
|