diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index bd7fb18..f05108d 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -12,7 +12,7 @@ "name": "deploygate", "source": "./plugin", "description": "Upload apps, manage distribution pages, add team members, and set up CI/CD integration with DeployGate", - "version": "1.3.1" + "version": "1.4.0" } ] } diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 9049e2f..4c313f9 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.3.1" + ".": "1.4.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 03430d6..4f0111a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## [1.4.0](https://github.com/DeployGate/deploygate-agent-plugin/compare/deploygate--v1.3.1...deploygate--v1.4.0) (2026-05-15) + + +### Features + +* send User-Agent header on DeployGate API requests ([#17](https://github.com/DeployGate/deploygate-agent-plugin/issues/17)) ([0756a9f](https://github.com/DeployGate/deploygate-agent-plugin/commit/0756a9fd0079c87be184737022f877e7bd6e3982)) + + +### Bug Fixes + +* **ci:** avoid fromJSON in step env so the bundle-commit step skips cleanly ([#19](https://github.com/DeployGate/deploygate-agent-plugin/issues/19)) ([de3df07](https://github.com/DeployGate/deploygate-agent-plugin/commit/de3df0736c3d67647bb85c474de172d97223ca0b)) + ## [1.3.1](https://github.com/DeployGate/deploygate-agent-plugin/compare/deploygate--v1.3.0...deploygate--v1.3.1) (2026-05-15) diff --git a/package-lock.json b/package-lock.json index 895ac94..0f8f543 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "deploygate-agent-plugin", - "version": "1.3.1", + "version": "1.4.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "deploygate-agent-plugin", - "version": "1.3.1", + "version": "1.4.0", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.29.0", diff --git a/package.json b/package.json index cfffa4e..63dd81c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "deploygate-agent-plugin", - "version": "1.3.1", + "version": "1.4.0", "description": "DeployGate agent integration: upload mobile apps, manage distribution pages, set up CI/CD, and onboard your team. Supports iOS (IPA) and Android (APK/AAB).", "type": "module", "main": "dist/index.js", diff --git a/plugin/.claude-plugin/plugin.json b/plugin/.claude-plugin/plugin.json index 438530e..75f860e 100644 --- a/plugin/.claude-plugin/plugin.json +++ b/plugin/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "deploygate", - "version": "1.3.1", + "version": "1.4.0", "description": "DeployGate agent integration: upload mobile apps, manage distribution pages, set up CI/CD, and onboard your team. Supports iOS (IPA) and Android (APK/AAB).", "author": { "name": "DeployGate", diff --git a/plugin/.codex-plugin/plugin.json b/plugin/.codex-plugin/plugin.json index ff69c17..6487f27 100644 --- a/plugin/.codex-plugin/plugin.json +++ b/plugin/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "deploygate", - "version": "1.3.1", + "version": "1.4.0", "description": "DeployGate agent integration: upload mobile apps, manage distribution pages, set up CI/CD, and onboard your team. Supports iOS (IPA) and Android (APK/AAB).", "author": { "name": "DeployGate", diff --git a/plugin/scripts/bundle.js b/plugin/scripts/bundle.js index bcc4892..a13a2a6 100755 --- a/plugin/scripts/bundle.js +++ b/plugin/scripts/bundle.js @@ -3105,6 +3105,9 @@ var require_utils = __commonJS({ "use strict"; var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu); var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u); + var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu); + var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu); + var isPathCharacter = RegExp.prototype.test.bind(/^[\da-z\-._~!$&'()*+,;=:@/]$/iu); function stringArrayToHexStripped(input) { let acc = ""; let code = 0; @@ -3297,27 +3300,77 @@ var require_utils = __commonJS({ } return output.join(""); } - function normalizeComponentEncoding(component, esc2) { - const func = esc2 !== true ? escape : unescape; - if (component.scheme !== void 0) { - component.scheme = func(component.scheme); - } - if (component.userinfo !== void 0) { - component.userinfo = func(component.userinfo); - } - if (component.host !== void 0) { - component.host = func(component.host); + var HOST_DELIMS = { "@": "%40", "/": "%2F", "?": "%3F", "#": "%23", ":": "%3A" }; + var HOST_DELIM_RE = /[@/?#:]/g; + var HOST_DELIM_NO_COLON_RE = /[@/?#]/g; + function reescapeHostDelimiters(host, isIP) { + const re = isIP ? HOST_DELIM_NO_COLON_RE : HOST_DELIM_RE; + re.lastIndex = 0; + return host.replace(re, (ch) => HOST_DELIMS[ch]); + } + function normalizePercentEncoding(input, decodeUnreserved = false) { + if (input.indexOf("%") === -1) { + return input; } - if (component.path !== void 0) { - component.path = func(component.path); + let output = ""; + for (let i = 0; i < input.length; i++) { + if (input[i] === "%" && i + 2 < input.length) { + const hex3 = input.slice(i + 1, i + 3); + if (isHexPair(hex3)) { + const normalizedHex = hex3.toUpperCase(); + const decoded = String.fromCharCode(parseInt(normalizedHex, 16)); + if (decodeUnreserved && isUnreserved(decoded)) { + output += decoded; + } else { + output += "%" + normalizedHex; + } + i += 2; + continue; + } + } + output += input[i]; } - if (component.query !== void 0) { - component.query = func(component.query); + return output; + } + function normalizePathEncoding(input) { + let output = ""; + for (let i = 0; i < input.length; i++) { + if (input[i] === "%" && i + 2 < input.length) { + const hex3 = input.slice(i + 1, i + 3); + if (isHexPair(hex3)) { + const normalizedHex = hex3.toUpperCase(); + const decoded = String.fromCharCode(parseInt(normalizedHex, 16)); + if (decoded !== "." && isUnreserved(decoded)) { + output += decoded; + } else { + output += "%" + normalizedHex; + } + i += 2; + continue; + } + } + if (isPathCharacter(input[i])) { + output += input[i]; + } else { + output += escape(input[i]); + } } - if (component.fragment !== void 0) { - component.fragment = func(component.fragment); + return output; + } + function escapePreservingEscapes(input) { + let output = ""; + for (let i = 0; i < input.length; i++) { + if (input[i] === "%" && i + 2 < input.length) { + const hex3 = input.slice(i + 1, i + 3); + if (isHexPair(hex3)) { + output += "%" + hex3.toUpperCase(); + i += 2; + continue; + } + } + output += escape(input[i]); } - return component; + return output; } function recomposeAuthority(component) { const uriTokens = []; @@ -3332,7 +3385,7 @@ var require_utils = __commonJS({ if (ipV6res.isIPV6 === true) { host = `[${ipV6res.escapedHost}]`; } else { - host = component.host; + host = reescapeHostDelimiters(host, false); } } uriTokens.push(host); @@ -3346,7 +3399,10 @@ var require_utils = __commonJS({ module.exports = { nonSimpleDomain, recomposeAuthority, - normalizeComponentEncoding, + reescapeHostDelimiters, + normalizePercentEncoding, + normalizePathEncoding, + escapePreservingEscapes, removeDotSegments, isIPv4, isUUID, @@ -3570,12 +3626,12 @@ var require_schemes = __commonJS({ var require_fast_uri = __commonJS({ "node_modules/fast-uri/index.js"(exports, module) { "use strict"; - var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizeComponentEncoding, isIPv4, nonSimpleDomain } = require_utils(); + var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils(); var { SCHEMES, getSchemeHandler } = require_schemes(); function normalize(uri, options) { if (typeof uri === "string") { uri = /** @type {T} */ - serialize(parse3(uri, options), options); + normalizeString(uri, options); } else if (typeof uri === "object") { uri = /** @type {T} */ parse3(serialize(uri, options), options); @@ -3642,19 +3698,9 @@ var require_fast_uri = __commonJS({ return target; } function equal(uriA, uriB, options) { - if (typeof uriA === "string") { - uriA = unescape(uriA); - uriA = serialize(normalizeComponentEncoding(parse3(uriA, options), true), { ...options, skipEscape: true }); - } else if (typeof uriA === "object") { - uriA = serialize(normalizeComponentEncoding(uriA, true), { ...options, skipEscape: true }); - } - if (typeof uriB === "string") { - uriB = unescape(uriB); - uriB = serialize(normalizeComponentEncoding(parse3(uriB, options), true), { ...options, skipEscape: true }); - } else if (typeof uriB === "object") { - uriB = serialize(normalizeComponentEncoding(uriB, true), { ...options, skipEscape: true }); - } - return uriA.toLowerCase() === uriB.toLowerCase(); + const normalizedA = normalizeComparableURI(uriA, options); + const normalizedB = normalizeComparableURI(uriB, options); + return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA.toLowerCase() === normalizedB.toLowerCase(); } function serialize(cmpts, opts) { const component = { @@ -3679,12 +3725,12 @@ var require_fast_uri = __commonJS({ if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options); if (component.path !== void 0) { if (!options.skipEscape) { - component.path = escape(component.path); + component.path = escapePreservingEscapes(component.path); if (component.scheme !== void 0) { component.path = component.path.split("%3A").join(":"); } } else { - component.path = unescape(component.path); + component.path = normalizePercentEncoding(component.path); } } if (options.reference !== "suffix" && component.scheme) { @@ -3719,7 +3765,16 @@ var require_fast_uri = __commonJS({ return uriTokens.join(""); } var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u; - function parse3(uri, opts) { + function getParseError(parsed, matches) { + if (matches[2] !== void 0 && parsed.path && parsed.path[0] !== "/") { + return 'URI path must start with "/" when authority is present.'; + } + if (typeof parsed.port === "number" && (parsed.port < 0 || parsed.port > 65535)) { + return "URI port is malformed."; + } + return void 0; + } + function parseWithStatus(uri, opts) { const options = Object.assign({}, opts); const parsed = { scheme: void 0, @@ -3730,6 +3785,7 @@ var require_fast_uri = __commonJS({ query: void 0, fragment: void 0 }; + let malformedAuthorityOrPort = false; let isIP = false; if (options.reference === "suffix") { if (options.scheme) { @@ -3750,6 +3806,11 @@ var require_fast_uri = __commonJS({ if (isNaN(parsed.port)) { parsed.port = matches[5]; } + const parseError = getParseError(parsed, matches); + if (parseError !== void 0) { + parsed.error = parsed.error || parseError; + malformedAuthorityOrPort = true; + } if (parsed.host) { const ipv4result = isIPv4(parsed.host); if (ipv4result === false) { @@ -3788,14 +3849,18 @@ var require_fast_uri = __commonJS({ parsed.scheme = unescape(parsed.scheme); } if (parsed.host !== void 0) { - parsed.host = unescape(parsed.host); + parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP); } } if (parsed.path) { - parsed.path = escape(unescape(parsed.path)); + parsed.path = normalizePathEncoding(parsed.path); } if (parsed.fragment) { - parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment)); + try { + parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment)); + } catch { + parsed.error = parsed.error || "URI malformed"; + } } } if (schemeHandler && schemeHandler.parse) { @@ -3804,7 +3869,29 @@ var require_fast_uri = __commonJS({ } else { parsed.error = parsed.error || "URI can not be parsed."; } - return parsed; + return { parsed, malformedAuthorityOrPort }; + } + function parse3(uri, opts) { + return parseWithStatus(uri, opts).parsed; + } + function normalizeString(uri, opts) { + return normalizeStringWithStatus(uri, opts).normalized; + } + function normalizeStringWithStatus(uri, opts) { + const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts); + return { + normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts), + malformedAuthorityOrPort + }; + } + function normalizeComparableURI(uri, opts) { + if (typeof uri === "string") { + const { normalized, malformedAuthorityOrPort } = normalizeStringWithStatus(uri, opts); + return malformedAuthorityOrPort ? void 0 : normalized; + } + if (typeof uri === "object") { + return serialize(uri, opts); + } } var fastUri = { SCHEMES, @@ -30864,7 +30951,13 @@ var StdioServerTransport = class { // dist/client.js import { readFile } from "node:fs/promises"; import { basename } from "node:path"; + +// dist/version.js +var VERSION = true ? "1.4.0" : "dev"; + +// dist/client.js var BASE_URL = "https://deploygate.com"; +var USER_AGENT = `deploygate-agent-plugin/${VERSION}`; var DeployGateApiError = class extends Error { errorType; because; @@ -30890,7 +30983,10 @@ var DeployGateClient = class { } async requestRaw(method, path, options) { const url2 = `${BASE_URL}${path}`; - const headers = { ...options.headers ?? {} }; + const headers = { + "User-Agent": USER_AGENT, + ...options.headers ?? {} + }; if (options.authenticated) { if (!this.token) { throw new Error("API token is not set. Run the `login_start` tool to obtain one."); @@ -30915,6 +31011,7 @@ var DeployGateClient = class { } const url2 = `${BASE_URL}${path}`; const headers = { + "User-Agent": USER_AGENT, Authorization: `Bearer ${this.token}` }; const fetchOptions = { method, headers }; @@ -31675,7 +31772,7 @@ var stored = await tokenStore.load(); var client = new DeployGateClient(stored?.token); var server = new McpServer({ name: "deploygate", - version: "1.3.0" + version: VERSION }); registerAuthTools(server, client, tokenStore); registerUploadTools(server, client);