@cnwenf/occ 2.1.329 → 2.1.331

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.
Files changed (2) hide show
  1. package/dist/cli.js +1088 -184
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bun
2
- globalThis.MACRO={"VERSION":"2.1.329","BINARY_NAME":"occ","BUILD_TIME":"2026-09-11T03:55:52.872Z","FEEDBACK_CHANNEL":"","ISSUES_EXPLAINER":"","NATIVE_PACKAGE_URL":"","PACKAGE_URL":"@cnwenf/occ","VERSION_CHANGELOG":""};
2
+ globalThis.MACRO={"VERSION":"2.1.331","BINARY_NAME":"occ","BUILD_TIME":"2026-09-12T07:54:49.967Z","FEEDBACK_CHANNEL":"","ISSUES_EXPLAINER":"","NATIVE_PACKAGE_URL":"","PACKAGE_URL":"@cnwenf/occ","VERSION_CHANGELOG":""};
3
3
  // @bun
4
4
  var __create = Object.create;
5
5
  var __getProtoOf = Object.getPrototypeOf;
@@ -203596,12 +203596,15 @@ function isPathInSandboxWriteAllowlist(resolvedPath) {
203596
203596
  }
203597
203597
  function isPathAllowed(resolvedPath, context4, operationType, precomputedPathsToCheck) {
203598
203598
  const permissionType = operationType === "read" ? "read" : "edit";
203599
- const denyRule = matchingRuleForInput(resolvedPath, context4, permissionType, "deny");
203600
- if (denyRule !== null) {
203601
- return {
203602
- allowed: false,
203603
- decisionReason: { type: "rule", rule: denyRule }
203604
- };
203599
+ const pathsToCheck = precomputedPathsToCheck ?? getPathsForPermissionCheck(resolvedPath);
203600
+ for (const pathToCheck of pathsToCheck) {
203601
+ const denyRule = matchingRuleForInput(pathToCheck, context4, permissionType, "deny");
203602
+ if (denyRule !== null) {
203603
+ return {
203604
+ allowed: false,
203605
+ decisionReason: { type: "rule", rule: denyRule }
203606
+ };
203607
+ }
203605
203608
  }
203606
203609
  if (operationType !== "read") {
203607
203610
  const internalEditResult = checkEditableInternalPath(resolvedPath, {});
@@ -377483,43 +377486,40 @@ function getMaxBashTimeoutMs(env6 = process.env) {
377483
377486
  var DEFAULT_TIMEOUT_MS = 120000, MAX_TIMEOUT_MS = 600000;
377484
377487
 
377485
377488
  // src/utils/todoToolsAvailability.ts
377486
- function isModelAtOrAboveRestrictedThreshold(modelId, restricted) {
377487
- const match = /^claude-([a-z]+)-(\d+(?:-\d+)*)$/.exec(modelId);
377488
- const family = match?.[1];
377489
- const version5 = match?.[2];
377490
- if (!family || !version5) {
377491
- return false;
377492
- }
377493
- const threshold = restricted.find(([f4]) => f4 === family)?.[1];
377494
- if (!threshold) {
377495
- return false;
377496
- }
377497
- const segments = version5.split("-").map(Number);
377498
- for (let i6 = 0;i6 < Math.max(segments.length, threshold.length); i6++) {
377499
- const diff2 = (segments[i6] ?? 0) - (threshold[i6] ?? 0);
377500
- if (diff2 !== 0) {
377501
- return diff2 > 0;
377502
- }
377503
- }
377504
- return true;
377505
- }
377506
377489
  function areTodoToolsAvailable() {
377507
377490
  const model = getMainLoopModel();
377508
- if (!isModelAtOrAboveRestrictedThreshold(model, TODO_TOOL_RESTRICTED_MODELS)) {
377491
+ if (model === undefined) {
377492
+ return true;
377493
+ }
377494
+ if (model.includes("application-inference-profile")) {
377495
+ return true;
377496
+ }
377497
+ if (TODO_TOOL_ALLOWED_MODELS.has(model)) {
377509
377498
  return true;
377510
377499
  }
377511
377500
  return isEnvTruthy(process.env.CLAUDE_CODE_ENABLE_TODO_TOOLS);
377512
377501
  }
377513
- var TODO_TOOL_RESTRICTED_MODELS;
377502
+ var TODO_TOOL_ALLOWED_MODELS;
377514
377503
  var init_todoToolsAvailability = __esm(() => {
377515
377504
  init_envUtils();
377516
377505
  init_model();
377517
- TODO_TOOL_RESTRICTED_MODELS = [
377518
- ["opus", [4, 8]],
377519
- ["sonnet", [5]],
377520
- ["fable", [5]],
377521
- ["mythos", [5]]
377522
- ];
377506
+ TODO_TOOL_ALLOWED_MODELS = new Set([
377507
+ "claude-3-opus",
377508
+ "claude-3-sonnet",
377509
+ "claude-3-haiku",
377510
+ "claude-3-5-sonnet",
377511
+ "claude-3-5-haiku",
377512
+ "claude-3-7-sonnet",
377513
+ "claude-opus-4-0",
377514
+ "claude-opus-4-1",
377515
+ "claude-opus-4-5",
377516
+ "claude-opus-4-6",
377517
+ "claude-opus-4-7",
377518
+ "claude-sonnet-4-0",
377519
+ "claude-sonnet-4-5",
377520
+ "claude-sonnet-4-6",
377521
+ "claude-haiku-4-5"
377522
+ ]);
377523
377523
  });
377524
377524
 
377525
377525
  // src/utils/todo/types.ts
@@ -387726,6 +387726,518 @@ var init_common4 = __esm(() => {
387726
387726
  trackedTabIds = new Set;
387727
387727
  });
387728
387728
 
387729
+ // src/services/mcp/redaction.ts
387730
+ function splitEnvVarSegments(template) {
387731
+ const segments = [];
387732
+ let cursor = 0;
387733
+ for (const match of template.matchAll(new RegExp(ENV_VAR_PATTERN, "g"))) {
387734
+ segments.push(template.slice(cursor, match.index));
387735
+ cursor = match.index + match[0].length;
387736
+ }
387737
+ segments.push(template.slice(cursor));
387738
+ return segments;
387739
+ }
387740
+ function redactEnvVarPlaceholders(value) {
387741
+ return value.replace(new RegExp(ENV_VAR_PATTERN, "g"), (match) => "x".repeat(match.length));
387742
+ }
387743
+ function normalizeEnvVarRefs(value) {
387744
+ return value.replace(new RegExp(ENV_VAR_PATTERN, "g"), (_match, name3) => `\${${name3}}`);
387745
+ }
387746
+ function escapeRegExp2(value) {
387747
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
387748
+ }
387749
+ function recoverExpandedSecrets(template, expanded) {
387750
+ if (!template || !expanded || !template.includes("${"))
387751
+ return [];
387752
+ const segments = splitEnvVarSegments(template);
387753
+ if (segments.length < 2)
387754
+ return [];
387755
+ if (expanded.length > MAX_RECOVER_EXPANDED_LENGTH || segments.length > MAX_RECOVER_SEGMENTS)
387756
+ return [];
387757
+ const escapedSegments = segments.map(escapeRegExp2);
387758
+ const secrets = [];
387759
+ if (segments.length === 2) {
387760
+ const [prefix = "", suffix = ""] = segments;
387761
+ if (expanded.length >= prefix.length + suffix.length && expanded.startsWith(prefix) && expanded.endsWith(suffix))
387762
+ secrets.push(expanded.slice(prefix.length, expanded.length - suffix.length));
387763
+ } else if (segments.length === 3) {
387764
+ const [prefix = "", middle = "", suffix = ""] = segments;
387765
+ if (expanded.startsWith(prefix) && expanded.endsWith(suffix)) {
387766
+ const inner = expanded.slice(prefix.length, expanded.length - suffix.length);
387767
+ if (middle === "")
387768
+ secrets.push(inner);
387769
+ else {
387770
+ const positions = [];
387771
+ for (let idx = inner.indexOf(middle);idx !== -1 && positions.length <= MAX_MIDDLE_OCCURRENCES; idx = inner.indexOf(middle, idx + 1))
387772
+ positions.push(idx);
387773
+ const chosen = positions.length > MAX_MIDDLE_OCCURRENCES ? [positions[0] ?? 0, inner.lastIndexOf(middle)] : positions;
387774
+ for (const position2 of chosen)
387775
+ secrets.push(inner.slice(0, position2), inner.slice(position2 + middle.length));
387776
+ }
387777
+ }
387778
+ } else {
387779
+ for (let i6 = 1;i6 < segments.length - 1; i6++)
387780
+ if (segments[i6] === "")
387781
+ return [];
387782
+ let pattern = "^";
387783
+ for (let i6 = 0;i6 < escapedSegments.length; i6++) {
387784
+ pattern += escapedSegments[i6];
387785
+ if (i6 < escapedSegments.length - 1) {
387786
+ const next = segments[i6 + 1] ?? "";
387787
+ if (next === "")
387788
+ pattern += "([\\s\\S]*)";
387789
+ else {
387790
+ const firstChar = next.charAt(0).replace(/[.*+?^${}()|[\]-]/g, "\\$&");
387791
+ pattern += `([^${firstChar}]*)`;
387792
+ }
387793
+ }
387794
+ }
387795
+ const match = expanded.match(new RegExp(`${pattern}$`));
387796
+ if (match)
387797
+ secrets.push(...match.slice(1).filter((secret) => secret !== ""));
387798
+ }
387799
+ return [...new Set(secrets)];
387800
+ }
387801
+ function collectConfigSecrets(authored, resolved) {
387802
+ if (!authored)
387803
+ return [];
387804
+ const secrets = [];
387805
+ const collect = (template, expanded) => {
387806
+ if (typeof template === "string" && typeof expanded === "string")
387807
+ secrets.push(...recoverExpandedSecrets(template, expanded));
387808
+ };
387809
+ if ("url" in authored && "url" in resolved)
387810
+ collect(authored.url, resolved.url);
387811
+ if ("command" in authored && "command" in resolved) {
387812
+ collect(authored.command, resolved.command);
387813
+ const authoredArgs = Array.isArray(authored.args) ? authored.args : [];
387814
+ const resolvedArgs = Array.isArray(resolved.args) ? resolved.args : [];
387815
+ for (let i6 = 0;i6 < Math.min(authoredArgs.length, resolvedArgs.length); i6++)
387816
+ collect(authoredArgs[i6], resolvedArgs[i6]);
387817
+ }
387818
+ for (const field of ["headers", "env"]) {
387819
+ const authoredRecord = field in authored ? authored[field] : undefined;
387820
+ const resolvedRecord = field in resolved ? resolved[field] : undefined;
387821
+ if (authoredRecord && resolvedRecord && typeof authoredRecord === "object" && typeof resolvedRecord === "object")
387822
+ for (const [key2, value] of Object.entries(authoredRecord))
387823
+ collect(value, resolvedRecord[key2]);
387824
+ }
387825
+ return secrets;
387826
+ }
387827
+ function matchesEnvVarTemplate(template, expanded) {
387828
+ const segments = splitEnvVarSegments(template);
387829
+ if (segments.length === 1)
387830
+ return template === expanded;
387831
+ const prefix = segments[0] ?? "";
387832
+ const suffix = segments.at(-1) ?? "";
387833
+ if (!expanded.startsWith(prefix) || !expanded.endsWith(suffix))
387834
+ return false;
387835
+ let cursor = prefix.length;
387836
+ const limit = expanded.length - suffix.length;
387837
+ for (let i6 = 1;i6 < segments.length - 1; i6++) {
387838
+ const segment2 = segments[i6] ?? "";
387839
+ const idx = expanded.indexOf(segment2, cursor);
387840
+ if (idx === -1 || idx + segment2.length > limit)
387841
+ return false;
387842
+ cursor = idx + segment2.length;
387843
+ }
387844
+ return cursor <= limit;
387845
+ }
387846
+ function recordField(config6, field) {
387847
+ const value = config6[field];
387848
+ return value && typeof value === "object" ? value : undefined;
387849
+ }
387850
+ function recordFieldsMatch(authored, expanded) {
387851
+ const authoredEntries = Object.entries(authored ?? {});
387852
+ const expandedRecord = expanded ?? {};
387853
+ if (authoredEntries.length !== Object.keys(expandedRecord).length)
387854
+ return false;
387855
+ return authoredEntries.every(([key2, value]) => typeof expandedRecord[key2] === "string" && matchesEnvVarTemplate(value, expandedRecord[key2]));
387856
+ }
387857
+ function isWebUrl(url3) {
387858
+ if (!URL.canParse(url3))
387859
+ return false;
387860
+ const { protocol } = new URL(url3);
387861
+ return protocol === "http:" || protocol === "https:" || protocol === "ws:" || protocol === "wss:";
387862
+ }
387863
+ function getServerUrl(config6) {
387864
+ return "url" in config6 ? config6.url : null;
387865
+ }
387866
+ function getStdioCommandParts(config6) {
387867
+ if (config6.type !== undefined && config6.type !== "stdio")
387868
+ return null;
387869
+ if (!("command" in config6))
387870
+ return null;
387871
+ return [config6.command, ...config6.args ?? []];
387872
+ }
387873
+ function getServerTypeLabel(config6) {
387874
+ return config6.type ?? ("command" in config6 ? "stdio" : "unknown");
387875
+ }
387876
+ function splitUrlParts(url3, maskedUrl = url3) {
387877
+ const findSplit = (from) => {
387878
+ let end2 = url3.length;
387879
+ for (const delimiter2 of ["/", "?", "#", "\\"]) {
387880
+ const idx = maskedUrl.indexOf(delimiter2, from);
387881
+ if (idx !== -1 && idx < end2)
387882
+ end2 = idx;
387883
+ }
387884
+ return end2;
387885
+ };
387886
+ const schemeSeparator = maskedUrl.indexOf("://");
387887
+ const start = schemeSeparator !== -1 && schemeSeparator < findSplit(0) && /^[A-Za-z][A-Za-z0-9+.-]*$/.test(maskedUrl.slice(0, schemeSeparator)) ? schemeSeparator + 3 : 0;
387888
+ const end = findSplit(start);
387889
+ return {
387890
+ scheme: url3.slice(0, start),
387891
+ authority: url3.slice(start, end),
387892
+ rest: url3.slice(end)
387893
+ };
387894
+ }
387895
+ function authorityHasEnvVarRef(url3) {
387896
+ return splitUrlParts(url3, redactEnvVarPlaceholders(url3)).authority.includes("${");
387897
+ }
387898
+ function authoredMatchesExpanded(authored, expanded) {
387899
+ if ((authored.type ?? "stdio") !== (expanded.type ?? "stdio"))
387900
+ return false;
387901
+ const authoredUrl = getServerUrl(authored);
387902
+ const expandedUrl = getServerUrl(expanded);
387903
+ if (authoredUrl !== null || expandedUrl !== null) {
387904
+ const urlsMatchTemplate = (a5, r4) => {
387905
+ const masked = redactEnvVarPlaceholders(a5);
387906
+ const authoredParts = splitUrlParts(a5, masked);
387907
+ const expandedParts = splitUrlParts(r4);
387908
+ const isAllPlaceholder = (value) => splitEnvVarSegments(value).every((segment2) => segment2 === "");
387909
+ if (isAllPlaceholder(a5))
387910
+ return true;
387911
+ if (authoredParts.scheme === "" && isAllPlaceholder(authoredParts.authority))
387912
+ return matchesEnvVarTemplate(a5, r4);
387913
+ const maskedAt = splitUrlParts(masked).authority.lastIndexOf("@");
387914
+ const expandedAt = expandedParts.authority.lastIndexOf("@");
387915
+ if (maskedAt === -1 !== (expandedAt === -1))
387916
+ return false;
387917
+ if (authoredParts.scheme === "")
387918
+ return expandedParts.scheme === "" && !isWebUrl(r4) && matchesEnvVarTemplate(a5, r4);
387919
+ if (expandedParts.scheme === "")
387920
+ return false;
387921
+ return matchesEnvVarTemplate(authoredParts.scheme.toLowerCase(), expandedParts.scheme.toLowerCase()) && (maskedAt === -1 || matchesEnvVarTemplate(authoredParts.authority.slice(0, maskedAt), expandedParts.authority.slice(0, expandedAt))) && matchesEnvVarTemplate(authoredParts.authority.slice(maskedAt + 1), expandedParts.authority.slice(expandedAt + 1)) && matchesEnvVarTemplate(authoredParts.rest, expandedParts.rest);
387922
+ };
387923
+ if (authoredUrl === null || expandedUrl === null)
387924
+ return false;
387925
+ if (!urlsMatchTemplate(authoredUrl, expandedUrl))
387926
+ return false;
387927
+ }
387928
+ const authoredCommand = getStdioCommandParts(authored);
387929
+ const expandedCommand = getStdioCommandParts(expanded);
387930
+ if (authoredCommand !== null || expandedCommand !== null) {
387931
+ if (authoredCommand === null || expandedCommand === null || authoredCommand.length !== expandedCommand.length || !authoredCommand.every((part, i6) => matchesEnvVarTemplate(part, expandedCommand[i6] ?? "")))
387932
+ return false;
387933
+ }
387934
+ return recordFieldsMatch(recordField(authored, "headers"), recordField(expanded, "headers")) && recordFieldsMatch(recordField(authored, "env"), recordField(expanded, "env"));
387935
+ }
387936
+ function getUrlOrigin(url3) {
387937
+ try {
387938
+ const origin2 = new URL(url3).origin;
387939
+ return origin2 === "null" ? undefined : origin2;
387940
+ } catch {
387941
+ return;
387942
+ }
387943
+ }
387944
+ function maskUrlUserinfo(url3) {
387945
+ const masked = redactEnvVarPlaceholders(url3);
387946
+ const { scheme, authority } = splitUrlParts(masked);
387947
+ const schemeLength = scheme.length;
387948
+ const authorityEnd = schemeLength + authority.length;
387949
+ if (masked.includes("@", authorityEnd))
387950
+ return `${normalizeEnvVarRefs(url3.slice(0, schemeLength))}[unparseable-authority]`;
387951
+ const at = authority.lastIndexOf("@");
387952
+ const userinfo = url3.slice(at === -1 ? schemeLength : schemeLength + at + 1, authorityEnd);
387953
+ if (userinfo === "")
387954
+ return;
387955
+ return normalizeEnvVarRefs(url3.slice(0, schemeLength) + userinfo);
387956
+ }
387957
+ function getEndpointForDisplay(params) {
387958
+ const { authoredUnexpanded: authored, expanded } = params;
387959
+ const detail = params.detail ?? "endpoint";
387960
+ if (authored) {
387961
+ const url3 = getServerUrl(authored);
387962
+ if (url3) {
387963
+ if (detail === "endpoint")
387964
+ return normalizeEnvVarRefs(url3);
387965
+ if (authorityHasEnvVarRef(url3))
387966
+ return maskUrlUserinfo(url3);
387967
+ return getUrlOrigin(url3) ?? maskUrlUserinfo(url3);
387968
+ }
387969
+ const commandParts = getStdioCommandParts(authored);
387970
+ if (commandParts)
387971
+ return detail === "endpoint" ? normalizeEnvVarRefs(commandParts.join(" ")) : undefined;
387972
+ return detail === "endpoint" ? getServerTypeLabel(authored) : undefined;
387973
+ }
387974
+ const expandedUrl = getServerUrl(expanded);
387975
+ if (expandedUrl) {
387976
+ const origin2 = getUrlOrigin(expandedUrl);
387977
+ if (origin2 !== undefined)
387978
+ return origin2;
387979
+ }
387980
+ return detail === "endpoint" ? getServerTypeLabel(expanded) : undefined;
387981
+ }
387982
+ function deepNormalizeEnvVarRefs(value) {
387983
+ const walk = (current) => typeof current === "string" ? normalizeEnvVarRefs(current) : Array.isArray(current) ? current.map(walk) : current && typeof current === "object" ? Object.fromEntries(Object.entries(current).map(([key2, child]) => [key2, walk(child)])) : current;
387984
+ return walk(value);
387985
+ }
387986
+ function sanitizeConfigForDisplay(config6) {
387987
+ const typeLabel = getServerTypeLabel(config6);
387988
+ if ("url" in config6) {
387989
+ return {
387990
+ ...config6,
387991
+ url: typeLabel,
387992
+ ..."headers" in config6 && config6.headers && {
387993
+ headers: Object.fromEntries(Object.keys(config6.headers).map((key2) => [key2, "[REDACTED]"]))
387994
+ }
387995
+ };
387996
+ }
387997
+ if ("command" in config6) {
387998
+ return {
387999
+ ...config6,
388000
+ command: typeLabel,
388001
+ ..."args" in config6 && config6.args && { args: [] },
388002
+ ..."env" in config6 && config6.env && {
388003
+ env: Object.fromEntries(Object.keys(config6.env).map((key2) => [key2, "[REDACTED]"]))
388004
+ }
388005
+ };
388006
+ }
388007
+ return config6;
388008
+ }
388009
+ function getKnownScope(config6) {
388010
+ if (!("scope" in config6))
388011
+ return;
388012
+ const scope = config6.scope;
388013
+ return ConfigScopeSchema().options.find((known) => known === scope);
388014
+ }
388015
+ function getDisplayServers(servers, resolveUnexpanded) {
388016
+ const resolverCache = new Map;
388017
+ const display = {};
388018
+ for (const [name3, config6] of Object.entries(servers)) {
388019
+ const scope = getKnownScope(config6);
388020
+ if (scope === undefined) {
388021
+ display[name3] = config6;
388022
+ continue;
388023
+ }
388024
+ if (scope === "claudeai") {
388025
+ display[name3] = deepNormalizeEnvVarRefs(config6);
388026
+ continue;
388027
+ }
388028
+ if (!resolverCache.has(scope))
388029
+ resolverCache.set(scope, resolveUnexpanded(scope));
388030
+ const authored = resolverCache.get(scope)?.[name3];
388031
+ display[name3] = authored && authoredMatchesExpanded(authored, config6) ? deepNormalizeEnvVarRefs(authored) : sanitizeConfigForDisplay(config6);
388032
+ }
388033
+ return display;
388034
+ }
388035
+ function getDisplayConfig(name3, config6, resolveUnexpanded) {
388036
+ return getDisplayServers({ [name3]: config6 }, resolveUnexpanded)[name3] ?? sanitizeConfigForDisplay(config6);
388037
+ }
388038
+ function registerAuthoredUnexpandedConfig(name3, config6) {
388039
+ authoredUnexpandedRegistry.set(name3, config6);
388040
+ }
388041
+ function getAuthoredUnexpandedRegistry() {
388042
+ return authoredUnexpandedRegistry;
388043
+ }
388044
+ function getAuthoredUnexpanded(name3, config6, resolveUnexpanded) {
388045
+ const scope = getKnownScope(config6);
388046
+ if (scope === undefined)
388047
+ return;
388048
+ try {
388049
+ const authored = resolveUnexpanded(scope)?.[name3];
388050
+ return authored && authoredMatchesExpanded(authored, config6) ? authored : undefined;
388051
+ } catch {
388052
+ return;
388053
+ }
388054
+ }
388055
+ function getMcpErrorEndpoint(name3, config6, options, resolveUnexpanded) {
388056
+ const authored = getAuthoredUnexpanded(name3, config6, resolveUnexpanded);
388057
+ if (authored === undefined && getKnownScope(config6) !== undefined)
388058
+ return options?.detail === "origin" ? undefined : getServerTypeLabel(config6);
388059
+ return getEndpointForDisplay({
388060
+ authoredUnexpanded: authored,
388061
+ expanded: config6,
388062
+ cliOwned: false,
388063
+ detail: options?.detail
388064
+ });
388065
+ }
388066
+ function isLabelLikeSecret(candidate) {
388067
+ const parts = candidate.split(/[:=\uFF1A\uFF1D]+/).map((part) => part.trim());
388068
+ let matched = 0;
388069
+ for (const [index2, part] of parts.entries()) {
388070
+ if (part === "")
388071
+ continue;
388072
+ const isNonFinalOrFlag = index2 < parts.length - 1 || part.startsWith("-");
388073
+ if (!LABEL_EXACT_PATTERN.test(part) && !(isNonFinalOrFlag && LABEL_SUFFIX_PATTERN.test(part)))
388074
+ return false;
388075
+ matched++;
388076
+ }
388077
+ return matched > 0;
388078
+ }
388079
+ function redactMcpErrorText(errorText, expanded, endpoint3, authored) {
388080
+ const endpointDisplay = endpoint3 ?? MCP_ENDPOINT_PLACEHOLDER;
388081
+ const registrations = [];
388082
+ const registerSecret = (secret, replacement, options) => {
388083
+ if (secret === undefined)
388084
+ return;
388085
+ if (secret.length < 4)
388086
+ return;
388087
+ if (replacement !== "[redacted]" && replacement.includes(secret))
388088
+ return;
388089
+ registrations.push([secret, replacement, options?.wordBoundary === true]);
388090
+ };
388091
+ const registerRedacted = (secret, replacement = endpointDisplay) => {
388092
+ if (secret === undefined)
388093
+ return;
388094
+ if (replacement.includes(secret) || isLabelLikeSecret(secret.trim()))
388095
+ return;
388096
+ registerSecret(secret, "[redacted]");
388097
+ };
388098
+ const registerWithVariants = (secret, replacement = endpointDisplay) => {
388099
+ if (!secret)
388100
+ return;
388101
+ registerRedacted(secret, replacement);
388102
+ if (secret.includes("+"))
388103
+ registerRedacted(secret.replaceAll("+", " "), replacement);
388104
+ if (secret.includes(" "))
388105
+ registerRedacted(secret.replaceAll(" ", "+"), replacement);
388106
+ for (const variant of [secret, secret.replaceAll("+", " ")]) {
388107
+ const words = variant.split(/\s+/);
388108
+ if (words.length > 1)
388109
+ for (const word of words)
388110
+ registerRedacted(word, replacement);
388111
+ }
388112
+ };
388113
+ const registerUrl = (url3, replacement) => {
388114
+ if (url3 === undefined)
388115
+ return;
388116
+ registerSecret(url3, replacement);
388117
+ try {
388118
+ const parsed = new URL(url3);
388119
+ registerSecret(parsed.href, replacement);
388120
+ if (parsed.origin !== "null")
388121
+ registerSecret(parsed.origin, replacement);
388122
+ registerSecret(parsed.host, replacement);
388123
+ registerSecret(parsed.hostname, replacement);
388124
+ const bareHostname = parsed.hostname.replace(/^\[|\]$/g, "");
388125
+ if (bareHostname !== parsed.hostname)
388126
+ registerSecret(bareHostname, replacement);
388127
+ registerWithVariants(parsed.username, replacement);
388128
+ registerWithVariants(parsed.password, replacement);
388129
+ registerRedacted(parsed.pathname !== "/" ? parsed.pathname : undefined, replacement);
388130
+ for (const segment2 of parsed.pathname.split("/"))
388131
+ registerWithVariants(segment2, replacement);
388132
+ registerRedacted(parsed.search, replacement);
388133
+ for (const [key2, value] of parsed.searchParams.entries()) {
388134
+ registerWithVariants(key2, replacement);
388135
+ registerWithVariants(value, replacement);
388136
+ }
388137
+ for (const pair of parsed.search.replace(/^\?/, "").split("&")) {
388138
+ const eq2 = pair.indexOf("=");
388139
+ if (eq2 === -1)
388140
+ registerWithVariants(pair, replacement);
388141
+ else {
388142
+ registerWithVariants(pair.slice(0, eq2), replacement);
388143
+ registerWithVariants(pair.slice(eq2 + 1), replacement);
388144
+ }
388145
+ }
388146
+ } catch {}
388147
+ };
388148
+ for (const secret of collectConfigSecrets(authored, expanded))
388149
+ registerWithVariants(secret);
388150
+ if ("url" in expanded && typeof expanded.url === "string")
388151
+ registerUrl(expanded.url, endpointDisplay);
388152
+ if ("oauth" in expanded && typeof expanded.oauth?.authServerMetadataUrl === "string") {
388153
+ const metadataUrl = expanded.oauth.authServerMetadataUrl;
388154
+ let replacement = "[redacted]";
388155
+ try {
388156
+ const origin2 = new URL(metadataUrl).origin;
388157
+ if (origin2 !== "null")
388158
+ replacement = origin2;
388159
+ } catch {}
388160
+ registerUrl(metadataUrl, replacement);
388161
+ }
388162
+ if ("command" in expanded && typeof expanded.command === "string") {
388163
+ const authoredCommand = authored && "command" in authored && typeof authored.command === "string" ? normalizeEnvVarRefs(authored.command) : undefined;
388164
+ registerSecret(expanded.command, authoredCommand ?? endpointDisplay, {
388165
+ wordBoundary: true
388166
+ });
388167
+ if (Array.isArray(expanded.args))
388168
+ for (const arg of expanded.args)
388169
+ registerWithVariants(arg);
388170
+ }
388171
+ if ("headers" in expanded && expanded.headers)
388172
+ for (const value of Object.values(expanded.headers))
388173
+ registerWithVariants(value);
388174
+ if ("env" in expanded && expanded.env)
388175
+ for (const value of Object.values(expanded.env))
388176
+ registerWithVariants(value);
388177
+ if ("authToken" in expanded && typeof expanded.authToken === "string")
388178
+ registerWithVariants(expanded.authToken);
388179
+ if (registrations.length === 0)
388180
+ return errorText;
388181
+ registrations.sort((a5, b5) => b5[0].length - a5[0].length);
388182
+ const deduped = new Map;
388183
+ for (const [secret, replacement, wordBoundary] of registrations) {
388184
+ const existing = deduped.get(secret);
388185
+ if (!existing)
388186
+ deduped.set(secret, { replacement, wordBoundary });
388187
+ else if (existing.replacement === "[redacted]" && replacement !== "[redacted]")
388188
+ deduped.set(secret, {
388189
+ replacement,
388190
+ wordBoundary: existing.wordBoundary && wordBoundary
388191
+ });
388192
+ }
388193
+ const spans = [];
388194
+ for (const [secret, entry] of deduped) {
388195
+ const escaped = escapeRegExp2(secret);
388196
+ const pattern = entry.wordBoundary && /^[\w-]+$/.test(secret) ? `(?<![\\w:.-])${escaped}(?![\\w:.-])` : escaped;
388197
+ const regex2 = new RegExp(pattern, "gi");
388198
+ for (let match = regex2.exec(errorText);match !== null; match = regex2.exec(errorText)) {
388199
+ spans.push({
388200
+ start: match.index,
388201
+ end: match.index + match[0].length,
388202
+ replacement: entry.replacement
388203
+ });
388204
+ regex2.lastIndex = match.index + 1;
388205
+ }
388206
+ }
388207
+ spans.sort((a5, b5) => a5.start - b5.start || b5.end - a5.end);
388208
+ const merged = [];
388209
+ for (const span of spans) {
388210
+ const last2 = merged.at(-1);
388211
+ if (last2 && span.start < last2.end)
388212
+ last2.end = Math.max(last2.end, span.end);
388213
+ else
388214
+ merged.push({ ...span });
388215
+ }
388216
+ let result = "";
388217
+ let cursor = 0;
388218
+ for (const span of merged) {
388219
+ result += errorText.slice(cursor, span.start) + span.replacement;
388220
+ cursor = span.end;
388221
+ }
388222
+ result += errorText.slice(cursor);
388223
+ return result;
388224
+ }
388225
+ function redactMcpErrorDetail(name3, config6, errorText, resolveUnexpanded) {
388226
+ try {
388227
+ return redactMcpErrorText(errorText, config6, getMcpErrorEndpoint(name3, config6, { detail: "origin" }, resolveUnexpanded) ?? getServerTypeLabel(config6), getAuthoredUnexpanded(name3, config6, resolveUnexpanded));
388228
+ } catch {
388229
+ return MCP_ERROR_REDACTION_FAILED;
388230
+ }
388231
+ }
388232
+ var MCP_ENDPOINT_PLACEHOLDER = "[mcp-endpoint]", MCP_ERROR_REDACTION_FAILED = "[mcp error detail unavailable: redaction failed]", MAX_RECOVER_EXPANDED_LENGTH = 2000, MAX_RECOVER_SEGMENTS = 9, MAX_MIDDLE_OCCURRENCES = 64, ENV_VAR_PATTERN, authoredUnexpandedRegistry, LABEL_EXACT_PATTERN, LABEL_SUFFIX_PATTERN;
388233
+ var init_redaction = __esm(() => {
388234
+ init_types();
388235
+ ENV_VAR_PATTERN = String.raw`\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-[^}]*)?\}`;
388236
+ authoredUnexpandedRegistry = new Map;
388237
+ LABEL_EXACT_PATTERN = /^(?:bearer|basic|(?:access|refresh|id|client|api|x[-_]api|session|auth)?[-_ ]?(?:token|key|secret|password|authorization|credential)s?)$/i;
388238
+ LABEL_SUFFIX_PATTERN = /(?:^|[^A-Za-z0-9_\s])(?:bearer|basic|token|key|secret|password|authorization|credential)s?$/i;
388239
+ });
388240
+
387729
388241
  // src/utils/plugins/mcpPluginIntegration.ts
387730
388242
  import { join as join78 } from "path";
387731
388243
  async function loadMcpServersFromMcpb(plugin, mcpbPath, errors8) {
@@ -387909,6 +388421,20 @@ function buildMcpUserConfig(plugin, serverName) {
387909
388421
  return;
387910
388422
  return { ...topLevel, ...channelSpecific };
387911
388423
  }
388424
+ function buildAuthoredPluginConfig(config6, plugin) {
388425
+ if (config6.type === undefined || config6.type === "stdio") {
388426
+ return {
388427
+ ...config6,
388428
+ env: {
388429
+ CLAUDE_PLUGIN_ROOT: plugin.path,
388430
+ CLAUDE_PLUGIN_DATA: getPluginDataDir(plugin.source),
388431
+ ...config6.env || {}
388432
+ },
388433
+ scope: "dynamic"
388434
+ };
388435
+ }
388436
+ return { ...config6, scope: "dynamic" };
388437
+ }
387912
388438
  function resolvePluginMcpEnvironment(config6, plugin, userConfig, errors8, pluginName, serverName) {
387913
388439
  const allMissingVars = [];
387914
388440
  const resolveValue2 = (value) => {
@@ -387998,6 +388524,7 @@ async function getPluginMcpServers(plugin, errors8 = []) {
387998
388524
  const userConfig = buildMcpUserConfig(plugin, name3);
387999
388525
  try {
388000
388526
  resolvedServers[name3] = resolvePluginMcpEnvironment(config6, plugin, userConfig, errors8, plugin.name, name3);
388527
+ registerAuthoredUnexpandedConfig(`plugin:${plugin.name}:${name3}`, buildAuthoredPluginConfig(config6, plugin));
388001
388528
  } catch (err2) {
388002
388529
  errors8?.push({
388003
388530
  type: "generic-error",
@@ -388010,6 +388537,7 @@ async function getPluginMcpServers(plugin, errors8 = []) {
388010
388537
  return addPluginScopeToServers(resolvedServers, plugin.name, plugin.source);
388011
388538
  }
388012
388539
  var init_mcpPluginIntegration = __esm(() => {
388540
+ init_redaction();
388013
388541
  init_types();
388014
388542
  init_debug();
388015
388543
  init_errors();
@@ -388040,25 +388568,6 @@ function markClaudeAiMcpConnected(name3) {
388040
388568
  function isClaudeAiMcpCurrentlyConnected(name3) {
388041
388569
  return currentlyConnectedClaudeAiMcps.has(name3);
388042
388570
  }
388043
- function shouldCountClaudeAiNeedsAuth(client8) {
388044
- if (client8.config.type !== "claudeai-proxy")
388045
- return false;
388046
- const eligible2 = client8.config.eligible;
388047
- if (eligible2 === false && !isClaudeAiMcpCurrentlyConnected(client8.name)) {
388048
- return false;
388049
- }
388050
- return hasClaudeAiMcpEverConnected(client8.name);
388051
- }
388052
- function getMcpNeedsAuthCount(clients) {
388053
- return clients.filter((client8) => {
388054
- if (client8.type !== "needs-auth")
388055
- return false;
388056
- if (client8.config.type === "claudeai-proxy") {
388057
- return shouldCountClaudeAiNeedsAuth(client8);
388058
- }
388059
- return client8.config.type !== "sse-ide" && client8.config.type !== "ws-ide";
388060
- }).length;
388061
- }
388062
388571
  var FETCH_TIMEOUT_MS = 5000, MCP_SERVERS_BETA_HEADER = "mcp-servers-2025-12-04", fetchClaudeAIMcpConfigsIfEligible, currentlyConnectedClaudeAiMcps;
388063
388572
  var init_claudeai = __esm(() => {
388064
388573
  init_axios2();
@@ -388323,18 +388832,22 @@ function mcpServerHealthStatusLabel(result) {
388323
388832
  function isUnconfiguredMcpServer(result) {
388324
388833
  return result.type === "failed" && result.errorCode === "UNCONFIGURED";
388325
388834
  }
388835
+ function formatErrorCode(errorCode) {
388836
+ const numeric = Number(errorCode);
388837
+ return errorCode === "23" ? "request timed out" : Number.isInteger(numeric) && numeric >= 100 && numeric <= 599 ? `HTTP ${errorCode}` : errorCode;
388838
+ }
388326
388839
  function getMcpServerFailureMessage(result) {
388840
+ const endpoint3 = getMcpErrorEndpoint(result.name, result.config, { detail: "origin" }, resolveUnexpandedMcpServers);
388327
388841
  const errorCode = result.errorCode;
388328
- if (errorCode && NAMED_FAILURE_ERROR_CODES.has(errorCode)) {
388329
- return result.error ?? errorCode;
388842
+ const redact = (errorText) => redactMcpErrorDetail(result.name, result.config, errorText, resolveUnexpandedMcpServers);
388843
+ if (errorCode !== undefined && NAMED_FAILURE_ERROR_CODES.has(errorCode)) {
388844
+ return result.error !== undefined ? redact(result.error) : errorCode;
388330
388845
  }
388331
388846
  if (errorCode) {
388332
- const numeric = Number(errorCode);
388333
- const message = errorCode === "23" ? "request timed out" : Number.isInteger(numeric) && numeric >= 100 && numeric <= 599 ? `HTTP ${errorCode}` : errorCode;
388334
- const url3 = "url" in result.config && typeof result.config.url === "string" ? result.config.url : null;
388335
- return url3 ? `${message} at ${url3}` : message;
388847
+ const message = formatErrorCode(errorCode);
388848
+ return endpoint3 ? `${message} at ${endpoint3}` : message;
388336
388849
  }
388337
- return result.error ?? "";
388850
+ return result.error !== undefined ? redact(result.error) : "";
388338
388851
  }
388339
388852
  function getMcpServerScopeFromToolName(toolName) {
388340
388853
  if (!isMcpTool({ name: toolName })) {
@@ -388437,7 +388950,15 @@ function getLoggingSafeMcpBaseUrl(config6) {
388437
388950
  return;
388438
388951
  }
388439
388952
  }
388440
- var NAMED_FAILURE_ERROR_CODES;
388953
+ var NAMED_FAILURE_ERROR_CODES, resolveUnexpandedMcpServers = (scope) => {
388954
+ if (scope === "dynamic") {
388955
+ const registry2 = getAuthoredUnexpandedRegistry();
388956
+ return registry2.size === 0 ? undefined : Object.fromEntries(registry2);
388957
+ }
388958
+ if (scope !== "local" && scope !== "user" && scope !== "project" && scope !== "enterprise")
388959
+ return;
388960
+ return getMcpConfigsByScope(scope, { expandVars: false }).servers;
388961
+ };
388441
388962
  var init_utils9 = __esm(() => {
388442
388963
  init_state();
388443
388964
  init_cwd2();
@@ -388447,6 +388968,7 @@ var init_utils9 = __esm(() => {
388447
388968
  init_slowOperations();
388448
388969
  init_config6();
388449
388970
  init_mcpStringUtils();
388971
+ init_redaction();
388450
388972
  init_normalization();
388451
388973
  init_types();
388452
388974
  NAMED_FAILURE_ERROR_CODES = new Set([
@@ -388522,7 +389044,7 @@ function commandArraysMatch(a5, b5) {
388522
389044
  }
388523
389045
  return a5.every((val, idx) => val === b5[idx]);
388524
389046
  }
388525
- function getServerUrl(config6) {
389047
+ function getServerUrl2(config6) {
388526
389048
  return "url" in config6 ? config6.url : null;
388527
389049
  }
388528
389050
  function unwrapCcrProxyUrl(url3) {
@@ -388542,7 +389064,7 @@ function getMcpServerSignature(config6) {
388542
389064
  if (cmd) {
388543
389065
  return `stdio:${jsonStringify(cmd)}`;
388544
389066
  }
388545
- const url3 = getServerUrl(config6);
389067
+ const url3 = getServerUrl2(config6);
388546
389068
  if (url3) {
388547
389069
  return `url:${unwrapCcrProxyUrl(url3)}`;
388548
389070
  }
@@ -388641,7 +389163,7 @@ function isMcpServerDenied(serverName, config6) {
388641
389163
  }
388642
389164
  }
388643
389165
  }
388644
- const serverUrl = getServerUrl(config6);
389166
+ const serverUrl = getServerUrl2(config6);
388645
389167
  if (serverUrl) {
388646
389168
  for (const entry of settings.deniedMcpServers) {
388647
389169
  if (isMcpServerUrlEntry(entry) && urlMatchesPattern(serverUrl, entry.serverUrl)) {
@@ -388667,7 +389189,7 @@ function isMcpServerAllowedByPolicy(serverName, config6) {
388667
389189
  const hasUrlEntries = settings.allowedMcpServers.some(isMcpServerUrlEntry);
388668
389190
  if (config6) {
388669
389191
  const serverCommand = getServerCommandArray(config6);
388670
- const serverUrl = getServerUrl(config6);
389192
+ const serverUrl = getServerUrl2(config6);
388671
389193
  if (serverCommand) {
388672
389194
  if (hasCommandEntries) {
388673
389195
  for (const entry of settings.allowedMcpServers) {
@@ -388964,7 +389486,7 @@ function getProjectMcpConfigsFromCwd() {
388964
389486
  errors: errors8 || []
388965
389487
  };
388966
389488
  }
388967
- function getMcpConfigsByScope(scope) {
389489
+ function getMcpConfigsByScope(scope, options) {
388968
389490
  const sourceMap = {
388969
389491
  project: "projectSettings",
388970
389492
  user: "userSettings",
@@ -388987,7 +389509,7 @@ function getMcpConfigsByScope(scope) {
388987
389509
  const mcpJsonPath = join80(dir, ".mcp.json");
388988
389510
  const { config: config6, errors: errors8 } = parseMcpConfigFromFilePath({
388989
389511
  filePath: mcpJsonPath,
388990
- expandVars: true,
389512
+ expandVars: options?.expandVars ?? true,
388991
389513
  scope: "project"
388992
389514
  });
388993
389515
  if (!config6) {
@@ -389017,7 +389539,7 @@ function getMcpConfigsByScope(scope) {
389017
389539
  }
389018
389540
  const { config: config6, errors: errors8 } = parseMcpConfig({
389019
389541
  configObject: { mcpServers },
389020
- expandVars: true,
389542
+ expandVars: options?.expandVars ?? true,
389021
389543
  scope: "user"
389022
389544
  });
389023
389545
  return {
@@ -389032,7 +389554,7 @@ function getMcpConfigsByScope(scope) {
389032
389554
  }
389033
389555
  const { config: config6, errors: errors8 } = parseMcpConfig({
389034
389556
  configObject: { mcpServers },
389035
- expandVars: true,
389557
+ expandVars: options?.expandVars ?? true,
389036
389558
  scope: "local"
389037
389559
  });
389038
389560
  return {
@@ -389044,7 +389566,7 @@ function getMcpConfigsByScope(scope) {
389044
389566
  const enterpriseMcpPath = getEnterpriseMcpFilePath();
389045
389567
  const { config: config6, errors: errors8 } = parseMcpConfigFromFilePath({
389046
389568
  filePath: enterpriseMcpPath,
389047
- expandVars: true,
389569
+ expandVars: options?.expandVars ?? true,
389048
389570
  scope: "enterprise"
389049
389571
  });
389050
389572
  if (!config6) {
@@ -389432,6 +389954,10 @@ function parseDynamicMcpConfig(params) {
389432
389954
  }
389433
389955
  let serverConfig = validated;
389434
389956
  if (expandVars) {
389957
+ registerAuthoredUnexpandedConfig(name3, {
389958
+ ...validated,
389959
+ scope
389960
+ });
389435
389961
  const { expanded, missingVars, urlExpandedToEmpty } = expandEnvVars(validated);
389436
389962
  if (missingVars.length > 0) {
389437
389963
  pushEntryError(name3, `Missing environment variables: ${missingVars.join(", ")}`, `Set the following environment variables: ${missingVars.join(", ")}`, undefined);
@@ -389537,6 +390063,7 @@ var init_config6 = __esm(() => {
389537
390063
  init_slowOperations();
389538
390064
  init_analytics();
389539
390065
  init_claudeai();
390066
+ init_redaction();
389540
390067
  init_types();
389541
390068
  init_utils9();
389542
390069
  init_normalization();
@@ -395001,14 +395528,19 @@ async function gracefulShutdown(exitCode = 0, reason = "other", options) {
395001
395528
  return;
395002
395529
  }
395003
395530
  shutdownInProgress = true;
395004
- const { executeSessionEndHooks, getSessionEndHookTimeoutMs } = await Promise.resolve().then(() => (init_hooks5(), exports_hooks2));
395531
+ const {
395532
+ executeSessionEndHooks,
395533
+ getSessionEndHookTimeoutMs,
395534
+ getSessionEndHooksBudgetMs
395535
+ } = await Promise.resolve().then(() => (init_hooks5(), exports_hooks2));
395005
395536
  const sessionEndTimeoutMs = getSessionEndHookTimeoutMs();
395537
+ const sessionEndBudgetMs = getSessionEndHooksBudgetMs();
395006
395538
  failsafeTimer = setTimeout(async (code) => {
395007
395539
  cleanupTerminalModes();
395008
395540
  printResumeHint();
395009
395541
  await drainStdoutBeforeExit(500);
395010
395542
  forceExit(code);
395011
- }, Math.max(5000, sessionEndTimeoutMs + 3500), exitCode);
395543
+ }, Math.max(5000, sessionEndBudgetMs + 3500), exitCode);
395012
395544
  failsafeTimer.unref();
395013
395545
  process.exitCode = exitCode;
395014
395546
  cleanupTerminalModes();
@@ -395033,7 +395565,7 @@ async function gracefulShutdown(exitCode = 0, reason = "other", options) {
395033
395565
  try {
395034
395566
  await executeSessionEndHooks(reason, {
395035
395567
  ...options,
395036
- signal: AbortSignal.timeout(sessionEndTimeoutMs),
395568
+ signal: AbortSignal.timeout(sessionEndBudgetMs),
395037
395569
  timeoutMs: sessionEndTimeoutMs
395038
395570
  });
395039
395571
  } catch {}
@@ -439044,7 +439576,8 @@ async function authStatus(opts) {
439044
439576
  const output = {
439045
439577
  loggedIn,
439046
439578
  authMethod,
439047
- apiProvider
439579
+ apiProvider,
439580
+ configDirectory: getClaudeConfigHomeDir()
439048
439581
  };
439049
439582
  if (resolvedApiKeySource) {
439050
439583
  output.apiKeySource = resolvedApiKeySource;
@@ -453078,6 +453611,15 @@ function parseRGB(colorStr) {
453078
453611
  RGB_CACHE.set(colorStr, result);
453079
453612
  return result;
453080
453613
  }
453614
+ function collapseWhitespace(value) {
453615
+ return value.replace(/\s+/g, " ").trim();
453616
+ }
453617
+ function computeTodoLabel(todo) {
453618
+ return [todo.activeForm, todo.subject].map((value) => value === undefined ? undefined : collapseWhitespace(value)).find(Boolean);
453619
+ }
453620
+ function computeSpinnerVerbWidth(columns) {
453621
+ return Math.max(40, columns - 8);
453622
+ }
453081
453623
  var THINKING_AMBER_DELAY_MS = 1e4, THINKING_AMBER_RAMP_MS = 1e4, RGB_CACHE;
453082
453624
  var init_utils10 = __esm(() => {
453083
453625
  RGB_CACHE = new Map;
@@ -459880,7 +460422,8 @@ function SpinnerWithVerbInner({
459880
460422
  const currentTodo = tasksV2?.find((task) => task.status !== "pending" && task.status !== "completed");
459881
460423
  const nextTask = findNextPendingTask(tasksV2);
459882
460424
  const [randomVerb] = import_react64.useState(() => sample_default(getSpinnerVerbs()));
459883
- const leaderVerb = overrideMessage ?? currentTodo?.activeForm ?? currentTodo?.subject ?? randomVerb;
460425
+ const leaderTodoLabel = currentTodo ? computeTodoLabel(currentTodo) : undefined;
460426
+ const leaderVerb = overrideMessage ?? (leaderTodoLabel === undefined ? undefined : truncateToWidthNoEllipsis(leaderTodoLabel, computeSpinnerVerbWidth(columns))) ?? randomVerb;
459884
460427
  const effectiveVerb = foregroundedTeammate && !foregroundedTeammate.isIdle ? foregroundedTeammate.spinnerVerb ?? randomVerb : leaderVerb;
459885
460428
  const message = effectiveVerb + "\u2026";
459886
460429
  import_react64.useEffect(() => {
@@ -460052,7 +460595,8 @@ function SpinnerWithVerbInner({
460052
460595
  (nextTask || effectiveTip) && /* @__PURE__ */ jsx_runtime82.jsx(MessageResponse, {
460053
460596
  children: /* @__PURE__ */ jsx_runtime82.jsx(ThemedText, {
460054
460597
  dimColor: true,
460055
- children: nextTask ? `Next: ${nextTask.subject}` : `Tip: ${effectiveTip}`
460598
+ wrap: nextTask ? "truncate-end" : "wrap",
460599
+ children: nextTask ? `Next: ${collapseWhitespace(nextTask.subject)}` : `Tip: ${effectiveTip}`
460056
460600
  })
460057
460601
  })
460058
460602
  ]
@@ -460402,6 +460946,7 @@ var init_Spinner2 = __esm(() => {
460402
460946
  init_useTerminalSize();
460403
460947
  init_stringWidth();
460404
460948
  init_Spinner();
460949
+ init_utils10();
460405
460950
  init_SpinnerAnimationRow();
460406
460951
  init_useSettings();
460407
460952
  init_InProcessTeammateTask();
@@ -481225,6 +481770,38 @@ var init_UI10 = __esm(() => {
481225
481770
  jsx_runtime137 = __toESM(require_jsx_runtime(), 1);
481226
481771
  });
481227
481772
 
481773
+ // src/utils/combinedAbortSignal.ts
481774
+ function createCombinedAbortSignal(signal, opts) {
481775
+ const { signalB, timeoutMs } = opts ?? {};
481776
+ const combined = createAbortController();
481777
+ if (signal?.aborted || signalB?.aborted) {
481778
+ combined.abort();
481779
+ return { signal: combined.signal, cleanup: () => {} };
481780
+ }
481781
+ let timer;
481782
+ const abortCombined = () => {
481783
+ if (timer !== undefined)
481784
+ clearTimeout(timer);
481785
+ combined.abort();
481786
+ };
481787
+ if (timeoutMs !== undefined) {
481788
+ timer = setTimeout(abortCombined, timeoutMs);
481789
+ timer.unref?.();
481790
+ }
481791
+ signal?.addEventListener("abort", abortCombined);
481792
+ signalB?.addEventListener("abort", abortCombined);
481793
+ const cleanup = () => {
481794
+ if (timer !== undefined)
481795
+ clearTimeout(timer);
481796
+ signal?.removeEventListener("abort", abortCombined);
481797
+ signalB?.removeEventListener("abort", abortCombined);
481798
+ };
481799
+ return { signal: combined.signal, cleanup };
481800
+ }
481801
+ var init_combinedAbortSignal = __esm(() => {
481802
+ init_abortController();
481803
+ });
481804
+
481228
481805
  // src/utils/mcpOutputStorage.ts
481229
481806
  import { writeFile as writeFile27 } from "fs/promises";
481230
481807
  import { join as join100 } from "path";
@@ -497292,7 +497869,7 @@ function filterValue(rule, node, options) {
497292
497869
  throw new TypeError("`filter` needs to be a string, array, or function");
497293
497870
  }
497294
497871
  }
497295
- function collapseWhitespace(options) {
497872
+ function collapseWhitespace2(options) {
497296
497873
  var element = options.element;
497297
497874
  var isBlock2 = options.isBlock;
497298
497875
  var isVoid2 = options.isVoid;
@@ -497384,7 +497961,7 @@ function RootNode(input, options) {
497384
497961
  } else {
497385
497962
  root3 = input.cloneNode(true);
497386
497963
  }
497387
- collapseWhitespace({
497964
+ collapseWhitespace2({
497388
497965
  element: root3,
497389
497966
  isBlock,
497390
497967
  isVoid,
@@ -497957,12 +498534,15 @@ __export(exports_utils2, {
497957
498534
  validateURL: () => validateURL,
497958
498535
  isPreapprovedUrl: () => isPreapprovedUrl,
497959
498536
  isPermittedRedirect: () => isPermittedRedirect,
498537
+ invalidUrlErrorMessage: () => invalidUrlErrorMessage,
497960
498538
  getWithPermittedRedirects: () => getWithPermittedRedirects,
498539
+ getWebFetchDeadlineMs: () => getWebFetchDeadlineMs,
497961
498540
  getURLMarkdownContent: () => getURLMarkdownContent,
497962
498541
  getTurndownService: () => getTurndownService,
497963
498542
  clearWebFetchCache: () => clearWebFetchCache,
497964
498543
  checkDomainBlocklist: () => checkDomainBlocklist,
497965
498544
  applyPromptToMarkdown: () => applyPromptToMarkdown,
498545
+ WebFetchTransportError: () => WebFetchTransportError,
497966
498546
  MAX_MARKDOWN_LENGTH: () => MAX_MARKDOWN_LENGTH
497967
498547
  });
497968
498548
  function clearWebFetchCache() {
@@ -497982,6 +498562,13 @@ function getTurndownService() {
497982
498562
  return service;
497983
498563
  });
497984
498564
  }
498565
+ function getWebFetchDeadlineMs() {
498566
+ const fromEnv5 = parseEnvInt(process.env.CLAUDE_CODE_WEBFETCH_DEADLINE_MS);
498567
+ if (fromEnv5 !== undefined) {
498568
+ return Math.min(fromEnv5, MAX_DEADLINE_MS);
498569
+ }
498570
+ return WEBFETCH_DEADLINE_MS_DEFAULT;
498571
+ }
497985
498572
  function isPreapprovedUrl(url3) {
497986
498573
  try {
497987
498574
  const parsedUrl = new URL(url3);
@@ -498010,6 +498597,18 @@ function validateURL(url3) {
498010
498597
  }
498011
498598
  return true;
498012
498599
  }
498600
+ function invalidUrlErrorMessage(url3) {
498601
+ let hostname4;
498602
+ try {
498603
+ hostname4 = new URL(url3).hostname;
498604
+ } catch {
498605
+ hostname4 = undefined;
498606
+ }
498607
+ if (hostname4 && !hostname4.includes(".")) {
498608
+ return "WebFetch cannot fetch localhost or other hostnames without a dot. To reach a local server, use Bash with curl instead.";
498609
+ }
498610
+ return "Invalid URL";
498611
+ }
498013
498612
  async function checkDomainBlocklist(domain2) {
498014
498613
  if (DOMAIN_CHECK_CACHE.has(domain2)) {
498015
498614
  return { status: "allowed" };
@@ -498053,13 +498652,30 @@ function isPermittedRedirect(originalUrl, redirectUrl) {
498053
498652
  return false;
498054
498653
  }
498055
498654
  }
498056
- async function getWithPermittedRedirects(url3, signal, redirectChecker, depth = 0) {
498655
+ async function getWithPermittedRedirects(url3, signal, redirectChecker, depth = 0, deadlineSignal) {
498656
+ if (deadlineSignal !== undefined) {
498657
+ return fetchWithRedirectChain(url3, signal, redirectChecker, depth, deadlineSignal);
498658
+ }
498659
+ const deadlineMs = getWebFetchDeadlineMs();
498660
+ if (deadlineMs === 0) {
498661
+ return fetchWithRedirectChain(url3, signal, redirectChecker, depth, new AbortController().signal);
498662
+ }
498663
+ const deadline = createCombinedAbortSignal(undefined, {
498664
+ timeoutMs: deadlineMs
498665
+ });
498666
+ try {
498667
+ return await fetchWithRedirectChain(url3, signal, redirectChecker, depth, deadline.signal);
498668
+ } finally {
498669
+ deadline.cleanup();
498670
+ }
498671
+ }
498672
+ async function fetchWithRedirectChain(url3, signal, redirectChecker, depth, deadlineSignal) {
498057
498673
  if (depth > MAX_REDIRECTS) {
498058
498674
  throw new Error(`Too many redirects (exceeded ${MAX_REDIRECTS})`);
498059
498675
  }
498060
498676
  try {
498061
498677
  return await axios_default.get(url3, {
498062
- signal,
498678
+ signal: AbortSignal.any([signal, deadlineSignal]),
498063
498679
  timeout: FETCH_TIMEOUT_MS3,
498064
498680
  maxRedirects: 0,
498065
498681
  responseType: "arraybuffer",
@@ -498070,14 +498686,17 @@ async function getWithPermittedRedirects(url3, signal, redirectChecker, depth =
498070
498686
  }
498071
498687
  });
498072
498688
  } catch (error52) {
498073
- if (axios_default.isAxiosError(error52) && error52.response && [301, 302, 307, 308].includes(error52.response.status)) {
498689
+ if (axios_default.isCancel(error52) && deadlineSignal.aborted && !signal.aborted) {
498690
+ throw new WebFetchTransportError(`Fetch did not complete within the ${getWebFetchDeadlineMs() / 1000}s deadline`, "EDEADLINE");
498691
+ }
498692
+ if (axios_default.isAxiosError(error52) && error52.response && REDIRECT_STATUS_CODES.has(error52.response.status)) {
498074
498693
  const redirectLocation = error52.response.headers.location;
498075
498694
  if (!redirectLocation) {
498076
498695
  throw new Error("Redirect missing Location header");
498077
498696
  }
498078
498697
  const redirectUrl = new URL(redirectLocation, url3).toString();
498079
498698
  if (redirectChecker(url3, redirectUrl)) {
498080
- return getWithPermittedRedirects(redirectUrl, signal, redirectChecker, depth + 1);
498699
+ return fetchWithRedirectChain(redirectUrl, signal, redirectChecker, depth + 1, deadlineSignal);
498081
498700
  } else {
498082
498701
  return {
498083
498702
  type: "redirect",
@@ -498099,7 +498718,7 @@ function isRedirectInfo(response3) {
498099
498718
  }
498100
498719
  async function getURLMarkdownContent(url3, abortController) {
498101
498720
  if (!validateURL(url3)) {
498102
- throw new Error("Invalid URL");
498721
+ throw new Error(invalidUrlErrorMessage(url3));
498103
498722
  }
498104
498723
  const cachedEntry = URL_CACHE.get(url3);
498105
498724
  if (cachedEntry) {
@@ -498131,7 +498750,7 @@ async function getURLMarkdownContent(url3, abortController) {
498131
498750
  case "blocked":
498132
498751
  throw new DomainBlockedError(hostname4);
498133
498752
  case "check_failed":
498134
- throw new DomainCheckFailedError(hostname4);
498753
+ throw new DomainCheckFailedError(hostname4, axios_default.isCancel(checkResult.error) ? "EDEADLINE_PREFLIGHT" : undefined);
498135
498754
  }
498136
498755
  }
498137
498756
  if (process.env.USER_TYPE === "ant") {
@@ -498215,12 +498834,14 @@ async function applyPromptToMarkdown(prompt, markdownContent, signal, isNonInter
498215
498834
  }
498216
498835
  return "No response from model";
498217
498836
  }
498218
- var DomainBlockedError, DomainCheckFailedError, EgressBlockedError, MAX_CACHE_SIZE_BYTES, URL_CACHE, DOMAIN_CHECK_CACHE, turndownServicePromise, MAX_URL_LENGTH = 2000, MAX_HTTP_CONTENT_LENGTH = 10485760, FETCH_TIMEOUT_MS3 = 60000, DOMAIN_CHECK_TIMEOUT_MS = 1e4, MAX_REDIRECTS = 10, MAX_MARKDOWN_LENGTH = 1e5;
498837
+ var DomainBlockedError, DomainCheckFailedError, WebFetchTransportError, EgressBlockedError, MAX_CACHE_SIZE_BYTES, URL_CACHE, DOMAIN_CHECK_CACHE, turndownServicePromise, MAX_URL_LENGTH = 2000, MAX_HTTP_CONTENT_LENGTH = 10485760, FETCH_TIMEOUT_MS3 = 60000, DOMAIN_CHECK_TIMEOUT_MS = 1e4, MAX_REDIRECTS = 10, REDIRECT_STATUS_CODES, WEBFETCH_DEADLINE_MS_DEFAULT = 300000, MAX_DEADLINE_MS = 2147483647, MAX_MARKDOWN_LENGTH = 1e5;
498219
498838
  var init_utils12 = __esm(() => {
498220
498839
  init_axios2();
498221
498840
  init_index_min();
498222
498841
  init_analytics();
498223
498842
  init_claude();
498843
+ init_combinedAbortSignal();
498844
+ init_envValidation();
498224
498845
  init_errors();
498225
498846
  init_http4();
498226
498847
  init_log3();
@@ -498236,9 +498857,19 @@ var init_utils12 = __esm(() => {
498236
498857
  }
498237
498858
  };
498238
498859
  DomainCheckFailedError = class DomainCheckFailedError extends Error {
498239
- constructor(domain2) {
498860
+ code;
498861
+ constructor(domain2, code) {
498240
498862
  super(`Unable to verify if domain ${domain2} is safe to fetch. This may be due to network restrictions or enterprise security policies blocking claude.ai.`);
498241
498863
  this.name = "DomainCheckFailedError";
498864
+ this.code = code;
498865
+ }
498866
+ };
498867
+ WebFetchTransportError = class WebFetchTransportError extends Error {
498868
+ code;
498869
+ constructor(message, code) {
498870
+ super(message);
498871
+ this.name = "WebFetchTransportError";
498872
+ this.code = code;
498242
498873
  }
498243
498874
  };
498244
498875
  EgressBlockedError = class EgressBlockedError extends Error {
@@ -498262,6 +498893,13 @@ var init_utils12 = __esm(() => {
498262
498893
  max: 128,
498263
498894
  ttl: 5 * 60 * 1000
498264
498895
  });
498896
+ REDIRECT_STATUS_CODES = new Set([
498897
+ 301,
498898
+ 302,
498899
+ 303,
498900
+ 307,
498901
+ 308
498902
+ ]);
498265
498903
  });
498266
498904
 
498267
498905
  // src/tools/WebFetchTool/WebFetchTool.ts
@@ -605131,12 +605769,8 @@ ${customInstructions}`;
605131
605769
  function formatCompactSummary(summary) {
605132
605770
  let formattedSummary = summary;
605133
605771
  formattedSummary = formattedSummary.replace(/<analysis>[\s\S]*?<\/analysis>/, "");
605134
- const summaryMatch = formattedSummary.match(/<summary>([\s\S]*?)<\/summary>/);
605135
- if (summaryMatch) {
605136
- const content = summaryMatch[1] || "";
605137
- formattedSummary = formattedSummary.replace(/<summary>[\s\S]*?<\/summary>/, `Summary:
605138
- ${content.trim()}`);
605139
- }
605772
+ formattedSummary = formattedSummary.replace(/<summary>([\s\S]*?)<\/summary>/, (_m4, g5) => `Summary:
605773
+ ${(g5 ?? "").trim()}`);
605140
605774
  formattedSummary = formattedSummary.replace(/\n\n+/g, `
605141
605775
 
605142
605776
  `);
@@ -614927,7 +615561,7 @@ function isClassifierDenial(content) {
614927
615561
  function buildYoloRejectionMessage(reason) {
614928
615562
  const prefix = AUTO_MODE_REJECTION_PREFIX;
614929
615563
  const ruleHint = feature("BASH_CLASSIFIER") ? `To allow this type of action in the future, the user can add a permission rule like ` + `Bash(prompt: <description of allowed action>) to their settings. ` + `At the end of your session, recommend what permission rules to add so you don't get blocked again.` : `To allow this type of action in the future, the user can add a Bash permission rule to their settings.`;
614930
- return `${prefix}${reason}. ` + `If you have other tasks that don't depend on this action, continue working on those. ` + `${DENIAL_WORKAROUND_GUIDANCE} ` + ruleHint;
615564
+ return `${prefix}${reason}. ` + `If you have other tasks that don't depend on this action, continue working on those. ` + `${DENIAL_WORKAROUND_GUIDANCE_BASE}${AUTO_MODE_STOP_SUFFIX} ` + ruleHint;
614931
615565
  }
614932
615566
  function buildClassifierUnavailableMessage(toolName, classifierModel) {
614933
615567
  return `${classifierModel} is temporarily unavailable, so auto mode cannot determine the safety of ${toolName} right now. ` + `Wait briefly and then try this action again. ` + `If it keeps failing, continue with other tasks that don't require this action and come back to it later. ` + `Note: reading files, searching code, and other read-only operations do not require the classifier and can still be used.`;
@@ -618328,7 +618962,7 @@ Note: The user's next message may contain a correction or preference. Pay close
618328
618962
  `, PLAN_REJECTION_PREFIX = `The agent proposed a plan that was rejected by the user. The user chose to stay in plan mode rather than proceed with implementation.
618329
618963
 
618330
618964
  Rejected plan:
618331
- `, DENIAL_WORKAROUND_GUIDANCE, NO_RESPONSE_REQUESTED = "No response requested.", SYNTHETIC_TOOL_RESULT_PLACEHOLDER = "[Tool result missing due to internal error]", AUTO_MODE_REJECTION_PREFIX = "Permission for this action was denied by the Claude Code auto mode classifier. Reason: ", CLASSIFIER_UNAVAILABLE_REASON = "Classifier unavailable", CLASSIFIER_PARSING_ERROR_REASON_PREFIX = "Auto mode could not evaluate this action and is blocking it for safety", CLASSIFIER_TRANSCRIPT_TOO_LONG_REASON = "Auto mode classifier transcript exceeded context window \u2014 falling back to manual approval (try /compact to reduce conversation size)", SYNTHETIC_MODEL = "<synthetic>", SYNTHETIC_MESSAGES, EMPTY_LOOKUPS, EMPTY_STRING_SET, _normalizationCache, STRIPPED_TAGS_RE, PLAN_PHASE4_CONTROL = `### Phase 4: Final Plan
618965
+ `, DENIAL_WORKAROUND_GUIDANCE_BASE, LEGACY_STOP_SUFFIX, AUTO_MODE_STOP_SUFFIX, DENIAL_WORKAROUND_GUIDANCE, NO_RESPONSE_REQUESTED = "No response requested.", SYNTHETIC_TOOL_RESULT_PLACEHOLDER = "[Tool result missing due to internal error]", AUTO_MODE_REJECTION_PREFIX = "Permission for this action was denied by the Claude Code auto mode classifier. Reason: ", CLASSIFIER_UNAVAILABLE_REASON = "Classifier unavailable", CLASSIFIER_PARSING_ERROR_REASON_PREFIX = "Auto mode could not evaluate this action and is blocking it for safety", CLASSIFIER_TRANSCRIPT_TOO_LONG_REASON = "Auto mode classifier transcript exceeded context window \u2014 falling back to manual approval (try /compact to reduce conversation size)", SYNTHETIC_MODEL = "<synthetic>", SYNTHETIC_MESSAGES, EMPTY_LOOKUPS, EMPTY_STRING_SET, _normalizationCache, STRIPPED_TAGS_RE, PLAN_PHASE4_CONTROL = `### Phase 4: Final Plan
618332
618966
  Goal: Write your final plan to the plan file (the only file you can edit).
618333
618967
  - Begin with a **Context** section: explain why this change is being made \u2014 the problem or need it addresses, what prompted it, and the intended outcome
618334
618968
  - Include only your recommended approach, not all alternatives
@@ -618403,7 +619037,10 @@ var init_messages3 = __esm(() => {
618403
619037
  init_stringUtils();
618404
619038
  init_tasks();
618405
619039
  init_toolSearch();
618406
- DENIAL_WORKAROUND_GUIDANCE = `IMPORTANT: You *may* attempt to accomplish this action using other tools that might naturally be used to accomplish this goal, ` + `e.g. using head instead of cat. But you *should not* attempt to work around this denial in malicious ways, ` + `e.g. do not use your ability to run tests to execute non-test actions. ` + `You should only try to work around this restriction in reasonable ways that do not attempt to bypass the intent behind this denial. ` + `If you believe this capability is essential to complete the user's request, STOP and explain to the user ` + `what you were trying to do and why you need this permission. Let the user decide how to proceed.`;
619040
+ DENIAL_WORKAROUND_GUIDANCE_BASE = `IMPORTANT: You *may* attempt to accomplish this action using other tools that might naturally be used to accomplish this goal, ` + `e.g. using head instead of cat. But you *should not* attempt to work around this denial in malicious ways, ` + `e.g. do not use your ability to run tests to execute non-test actions. ` + `You should only try to work around this restriction in reasonable ways that do not attempt to bypass the intent behind this denial. `;
619041
+ LEGACY_STOP_SUFFIX = `If you believe this capability is essential to complete the user's request, STOP and explain to the user ` + `what you were trying to do and why you need this permission. Let the user decide how to proceed.`;
619042
+ AUTO_MODE_STOP_SUFFIX = `If you believe this capability is essential to complete the user's request, first try a safer method. ` + `Get as much of the rest of the task done as you can, then STOP and explain to the user ` + `what you were trying to do and why you need this permission. Let the user decide how to proceed.`;
619043
+ DENIAL_WORKAROUND_GUIDANCE = `${DENIAL_WORKAROUND_GUIDANCE_BASE}${LEGACY_STOP_SUFFIX}`;
618407
619044
  SYNTHETIC_MESSAGES = new Set([
618408
619045
  INTERRUPT_MESSAGE,
618409
619046
  INTERRUPT_MESSAGE_FOR_TOOL_USE,
@@ -625176,9 +625813,28 @@ async function findAvailablePort() {
625176
625813
  });
625177
625814
  return REDIRECT_PORT_FALLBACK;
625178
625815
  } catch {
625816
+ const ephemeralPort = await tryAssignEphemeralPort();
625817
+ if (ephemeralPort !== undefined) {
625818
+ return ephemeralPort;
625819
+ }
625179
625820
  throw new Error(`No available ports for OAuth redirect`);
625180
625821
  }
625181
625822
  }
625823
+ async function tryAssignEphemeralPort() {
625824
+ try {
625825
+ return await new Promise((resolve53) => {
625826
+ const testServer = createServer4();
625827
+ testServer.once("error", () => resolve53(undefined));
625828
+ testServer.listen(0, "127.0.0.1", () => {
625829
+ const address = testServer.address();
625830
+ const port2 = typeof address === "object" && address !== null ? address.port : undefined;
625831
+ testServer.close(() => resolve53(port2));
625832
+ });
625833
+ });
625834
+ } catch {
625835
+ return;
625836
+ }
625837
+ }
625182
625838
  var REDIRECT_PORT_RANGE, REDIRECT_PORT_FALLBACK = 3118;
625183
625839
  var init_oauthPort = __esm(() => {
625184
625840
  init_platform2();
@@ -646389,6 +647045,86 @@ var init_magicDocs = __esm(() => {
646389
647045
  });
646390
647046
  });
646391
647047
 
647048
+ // src/utils/mcpNeedsAuthNotice.ts
647049
+ function clearNeedsAuthNoticedThisSession() {
647050
+ needsAuthNoticedThisSession.clear();
647051
+ }
647052
+ function isFailedUnconfigured(client8) {
647053
+ return client8.type === "failed" && client8.errorCode === "UNCONFIGURED";
647054
+ }
647055
+ function isEligibleForNeedsAuthNotice(client8, { hasEverConnected, connectedThisSession }) {
647056
+ if (isFailedUnconfigured(client8))
647057
+ return false;
647058
+ if (client8.config.type === "claudeai-proxy") {
647059
+ const eligible2 = client8.config.eligible;
647060
+ if (eligible2 === false && !connectedThisSession(client8.name))
647061
+ return false;
647062
+ return hasEverConnected(client8.name);
647063
+ }
647064
+ return client8.config.type !== "sse-ide" && client8.config.type !== "ws-ide";
647065
+ }
647066
+ function shouldAnnounceNeedsAuth(client8, deps) {
647067
+ if (client8.type !== "needs-auth" || !isEligibleForNeedsAuthNotice(client8, deps)) {
647068
+ return false;
647069
+ }
647070
+ return needsAuthNoticedThisSession.has(client8.name) || !(getGlobalConfig().mcpNeedsAuthNoticed ?? []).includes(client8.name);
647071
+ }
647072
+ function countNeedsAuthToAnnounce(clients, deps) {
647073
+ let count4 = 0;
647074
+ for (const client8 of clients) {
647075
+ count4 += +!!shouldAnnounceNeedsAuth(client8, deps);
647076
+ }
647077
+ return count4;
647078
+ }
647079
+ function markNeedsAuthNoticed(clients, deps) {
647080
+ const newlyNoticed = [];
647081
+ for (const client8 of clients) {
647082
+ if (shouldAnnounceNeedsAuth(client8, deps) && !needsAuthNoticedThisSession.has(client8.name)) {
647083
+ needsAuthNoticedThisSession.add(client8.name);
647084
+ newlyNoticed.push(client8.name);
647085
+ }
647086
+ }
647087
+ if (newlyNoticed.length === 0)
647088
+ return;
647089
+ saveGlobalConfig((current) => {
647090
+ const noticed = current.mcpNeedsAuthNoticed ?? [];
647091
+ const fresh = newlyNoticed.filter((name3) => !noticed.includes(name3));
647092
+ if (fresh.length === 0)
647093
+ return current;
647094
+ const merged = [...noticed, ...fresh];
647095
+ return {
647096
+ ...current,
647097
+ mcpNeedsAuthNoticed: merged.slice(-MCP_NEEDS_AUTH_NOTICED_CAP)
647098
+ };
647099
+ });
647100
+ }
647101
+ function countNoticedServersNowConnected(clients) {
647102
+ const noticed = getGlobalConfig().mcpNeedsAuthNoticed;
647103
+ if (noticed === undefined || noticed.length === 0)
647104
+ return 0;
647105
+ let count4 = 0;
647106
+ for (const client8 of clients) {
647107
+ count4 += +!!(client8.type === "connected" && noticed.includes(client8.name));
647108
+ }
647109
+ return count4;
647110
+ }
647111
+ function pruneNoticedServersNowConnected(clients) {
647112
+ saveGlobalConfig((current) => {
647113
+ const noticed = current.mcpNeedsAuthNoticed;
647114
+ if (noticed === undefined || noticed.length === 0)
647115
+ return current;
647116
+ const remaining = noticed.filter((name3) => !clients.some((client8) => client8.name === name3 && client8.type === "connected"));
647117
+ if (remaining.length === noticed.length)
647118
+ return current;
647119
+ return { ...current, mcpNeedsAuthNoticed: remaining };
647120
+ });
647121
+ }
647122
+ var MCP_NEEDS_AUTH_NOTICED_CAP = 128, needsAuthNoticedThisSession;
647123
+ var init_mcpNeedsAuthNotice = __esm(() => {
647124
+ init_config4();
647125
+ needsAuthNoticedThisSession = new Set;
647126
+ });
647127
+
646392
647128
  // src/commands/clear/caches.ts
646393
647129
  var exports_caches = {};
646394
647130
  __export(exports_caches, {
@@ -646411,6 +647147,7 @@ function clearSessionCaches(preservedAgentIds = new Set) {
646411
647147
  resetGetMemoryFilesCache("session_start");
646412
647148
  clearStoredImagePaths();
646413
647149
  clearAllSessions();
647150
+ clearNeedsAuthNoticedThisSession();
646414
647151
  if (!hasPreserved)
646415
647152
  clearAllPendingCallbacks();
646416
647153
  if (process.env.USER_TYPE === "ant") {
@@ -646458,6 +647195,7 @@ var init_caches = __esm(() => {
646458
647195
  init_detectRepository();
646459
647196
  init_gitFilesystem();
646460
647197
  init_imageStore();
647198
+ init_mcpNeedsAuthNotice();
646461
647199
  init_sessionEnvVars();
646462
647200
  });
646463
647201
 
@@ -646477,10 +647215,11 @@ async function clearConversation({
646477
647215
  setConversationId
646478
647216
  }) {
646479
647217
  const sessionEndTimeoutMs = getSessionEndHookTimeoutMs();
647218
+ const sessionEndBudgetMs = getSessionEndHooksBudgetMs();
646480
647219
  await executeSessionEndHooks("clear", {
646481
647220
  getAppState,
646482
647221
  setAppState,
646483
- signal: AbortSignal.timeout(sessionEndTimeoutMs),
647222
+ signal: AbortSignal.timeout(sessionEndBudgetMs),
646484
647223
  timeoutMs: sessionEndTimeoutMs
646485
647224
  });
646486
647225
  const lastRequestId = getLastMainRequestId();
@@ -668772,6 +669511,12 @@ function MCPRemoteServerMenu({
668772
669511
  } = useTerminalSize();
668773
669512
  const [isAuthenticating, setIsAuthenticating] = import_react131.default.useState(false);
668774
669513
  const [error52, setError] = import_react131.default.useState(null);
669514
+ const scopedConfig = import_react131.default.useMemo(() => ({
669515
+ ...server.config,
669516
+ scope: server.scope ?? server.config.scope
669517
+ }), [server.config, server.scope]);
669518
+ const displayConfig = import_react131.default.useMemo(() => getDisplayConfig(server.name, scopedConfig, resolveUnexpandedMcpServers), [server.name, scopedConfig]);
669519
+ const displayUrl = "url" in displayConfig ? displayConfig.url : "";
668775
669520
  const mcp = useAppState((s4) => s4.mcp);
668776
669521
  const setAppState = useSetAppState();
668777
669522
  const [authorizationUrl, setAuthorizationUrl] = import_react131.default.useState(null);
@@ -668984,7 +669729,7 @@ function MCPRemoteServerMenu({
668984
669729
  }
668985
669730
  } catch (err_1) {
668986
669731
  if (err_1 instanceof Error && !(err_1 instanceof AuthenticationCancelledError)) {
668987
- setError(err_1.message);
669732
+ setError(redactMcpErrorDetail(server.name, scopedConfig, err_1.message, resolveUnexpandedMcpServers));
668988
669733
  }
668989
669734
  } finally {
668990
669735
  setIsAuthenticating(false);
@@ -669502,7 +670247,7 @@ function MCPRemoteServerMenu({
669502
670247
  }),
669503
670248
  /* @__PURE__ */ jsx_runtime238.jsx(ThemedText, {
669504
670249
  dimColor: true,
669505
- children: server.config.url
670250
+ children: displayUrl
669506
670251
  })
669507
670252
  ]
669508
670253
  }),
@@ -669656,6 +670401,7 @@ var init_MCPRemoteServerMenu = __esm(() => {
669656
670401
  init_auth11();
669657
670402
  init_client12();
669658
670403
  init_MCPConnectionManager();
670404
+ init_redaction();
669659
670405
  init_utils9();
669660
670406
  init_AppState();
669661
670407
  init_auth6();
@@ -669689,6 +670435,12 @@ function MCPStdioServerMenu({
669689
670435
  const reconnectMcpServer = useMcpReconnect();
669690
670436
  const toggleMcpServer = useMcpToggleEnabled();
669691
670437
  const [isReconnecting, setIsReconnecting] = import_react132.useState(false);
670438
+ const displayConfig = import_react132.default.useMemo(() => getDisplayConfig(server.name, {
670439
+ ...server.config,
670440
+ scope: server.config.scope ?? "dynamic"
670441
+ }, resolveUnexpandedMcpServers), [server.name, server.config]);
670442
+ const displayCommand = "command" in displayConfig ? displayConfig.command : "";
670443
+ const displayArgs = "command" in displayConfig && Array.isArray(displayConfig.args) ? displayConfig.args : [];
669692
670444
  const handleToggleEnabled = import_react132.default.useCallback(async () => {
669693
670445
  const wasEnabled = server.client.type !== "disabled";
669694
670446
  try {
@@ -669824,11 +670576,11 @@ function MCPStdioServerMenu({
669824
670576
  }),
669825
670577
  /* @__PURE__ */ jsx_runtime239.jsx(ThemedText, {
669826
670578
  dimColor: true,
669827
- children: server.config.command
670579
+ children: displayCommand
669828
670580
  })
669829
670581
  ]
669830
670582
  }),
669831
- server.config.args && server.config.args.length > 0 && /* @__PURE__ */ jsx_runtime239.jsxs(ThemedBox_default, {
670583
+ displayArgs.length > 0 && /* @__PURE__ */ jsx_runtime239.jsxs(ThemedBox_default, {
669832
670584
  children: [
669833
670585
  /* @__PURE__ */ jsx_runtime239.jsx(ThemedText, {
669834
670586
  bold: true,
@@ -669836,7 +670588,7 @@ function MCPStdioServerMenu({
669836
670588
  }),
669837
670589
  /* @__PURE__ */ jsx_runtime239.jsx(ThemedText, {
669838
670590
  dimColor: true,
669839
- children: server.config.args.join(" ")
670591
+ children: displayArgs.join(" ")
669840
670592
  })
669841
670593
  ]
669842
670594
  }),
@@ -669946,6 +670698,7 @@ var init_MCPStdioServerMenu = __esm(() => {
669946
670698
  init_ink2();
669947
670699
  init_config6();
669948
670700
  init_MCPConnectionManager();
670701
+ init_redaction();
669949
670702
  init_utils9();
669950
670703
  init_AppState();
669951
670704
  init_errors();
@@ -679149,7 +679902,7 @@ function formatZodErrors(zodError) {
679149
679902
  }));
679150
679903
  }
679151
679904
  function checkPathTraversal(p4, field, errors8, hint) {
679152
- if (p4.includes("..")) {
679905
+ if (p4.split(/[\\/]/).some((segment2) => segment2 === "..")) {
679153
679906
  errors8.push({
679154
679907
  path: field,
679155
679908
  message: hint ? `Path contains "..": ${p4}. ${hint}` : `Path contains ".." which could be a path traversal attempt: ${p4}`
@@ -726154,7 +726907,15 @@ function stripNonLoadedContent(raw) {
726154
726907
  }
726155
726908
  return result;
726156
726909
  }
726157
- function truncateEntrypointContent(raw) {
726910
+ function truncatePreviewAtWordBoundary(value, max2) {
726911
+ if (value.length <= max2)
726912
+ return value;
726913
+ const head = sliceHead(value, max2 - 1);
726914
+ const lastWordStart = head.search(/\s\S*$/);
726915
+ const beforeLastWord = lastWordStart === -1 ? "" : head.slice(0, lastWordStart).trimEnd();
726916
+ return `${beforeLastWord.length > max2 / 2 ? beforeLastWord : head.trimEnd()}\u2026`;
726917
+ }
726918
+ function truncateEntrypointContent(raw, kind = "index") {
726158
726919
  const trimmed = raw.trim();
726159
726920
  const contentLines = trimmed.split(`
726160
726921
  `);
@@ -726178,11 +726939,20 @@ function truncateEntrypointContent(raw) {
726178
726939
  `, MAX_ENTRYPOINT_BYTES);
726179
726940
  truncated = truncated.slice(0, cutAt > 0 ? cutAt : MAX_ENTRYPOINT_BYTES);
726180
726941
  }
726181
- const reason = wasByteTruncated && !wasLineTruncated ? `${formatFileSize(byteCount)} (limit: ${formatFileSize(MAX_ENTRYPOINT_BYTES)}) \u2014 index entries are too long` : wasLineTruncated && !wasByteTruncated ? `${lineCount} lines (limit: ${MAX_ENTRYPOINT_LINES})` : `${lineCount} lines and ${formatFileSize(byteCount)}`;
726942
+ const fullLinesKept = trimmed[truncated.length] === `
726943
+ ` ? countCharInString(truncated, `
726944
+ `) + 1 : 0;
726945
+ const previewStart = truncated.length + 1;
726946
+ const previewEnd = trimmed.indexOf(`
726947
+ `, previewStart);
726948
+ const firstCutLine = trimmed.slice(previewStart, previewEnd < 0 ? undefined : previewEnd).trim();
726949
+ const cutDetail = fullLinesKept === 0 ? `everything after the first ${truncated.length} characters of line 1 was cut off` : `${lineCount - fullLinesKept} of ${lineCount} lines were cut off, starting at line ${fullLinesKept + 1}${firstCutLine ? ` ("${truncatePreviewAtWordBoundary(firstCutLine, CUT_LINE_PREVIEW_MAX)}")` : ""}`;
726950
+ const reason = wasByteTruncated && !wasLineTruncated ? `${formatFileSize(byteCount)} (limit: ${formatFileSize(MAX_ENTRYPOINT_BYTES)}) \u2014 ${kind === "index" ? "index entries are too long" : "its lines are too long"}` : wasLineTruncated && !wasByteTruncated ? `${lineCount} lines (limit: ${MAX_ENTRYPOINT_LINES})` : `${lineCount} lines and ${formatFileSize(byteCount)}`;
726951
+ const warning = kind === "index" ? `${ENTRYPOINT_NAME} is ${reason}. Only part of it was loaded: ${cutDetail}. Keep index entries to one line under ~200 chars; move detail into topic files.` : `this memory file is ${reason}. Only part of it was loaded: ${cutDetail}. Keep each memory file focused on one topic.`;
726182
726952
  return {
726183
726953
  content: truncated + `
726184
726954
 
726185
- > WARNING: ${ENTRYPOINT_NAME} is ${reason}. Only part of it was loaded. Keep index entries to one line under ~200 chars; move detail into topic files.`,
726955
+ > WARNING: ${warning}`,
726186
726956
  lineCount,
726187
726957
  byteCount,
726188
726958
  wasLineTruncated,
@@ -726499,7 +727269,7 @@ async function loadMemoryPrompt() {
726499
727269
  }
726500
727270
  return null;
726501
727271
  }
726502
- var teamMemPaths7, ENTRYPOINT_NAME = "MEMORY.md", MAX_ENTRYPOINT_LINES = 200, MAX_ENTRYPOINT_BYTES = 25000, AUTO_MEM_DISPLAY_NAME = "auto memory", HTML_COMMENT_REGEX, MEMORY_INDEX_APPROACHING_THRESHOLD = 0.8, MEMORY_INDEX_TARGET_FRACTION = 0.7, WRITE_GUARD_READ_LIMIT, teamMemPrompts, DIR_EXISTS_GUIDANCE = "This directory already exists \u2014 write to it directly with the Write tool (do not run mkdir or check for its existence).", DIRS_EXIST_GUIDANCE = "Both directories already exist \u2014 write to them directly with the Write tool (do not run mkdir or check for their existence).";
727272
+ var teamMemPaths7, ENTRYPOINT_NAME = "MEMORY.md", MAX_ENTRYPOINT_LINES = 200, MAX_ENTRYPOINT_BYTES = 25000, AUTO_MEM_DISPLAY_NAME = "auto memory", HTML_COMMENT_REGEX, CUT_LINE_PREVIEW_MAX = 80, MEMORY_INDEX_APPROACHING_THRESHOLD = 0.8, MEMORY_INDEX_TARGET_FRACTION = 0.7, WRITE_GUARD_READ_LIMIT, teamMemPrompts, DIR_EXISTS_GUIDANCE = "This directory already exists \u2014 write to it directly with the Write tool (do not run mkdir or check for its existence).", DIRS_EXIST_GUIDANCE = "Both directories already exist \u2014 write to them directly with the Write tool (do not run mkdir or check for their existence).";
726503
727273
  var init_memdir = __esm(() => {
726504
727274
  init_featureFlags();
726505
727275
  init_marked_esm();
@@ -726517,6 +727287,8 @@ var init_memdir = __esm(() => {
726517
727287
  init_format();
726518
727288
  init_sessionStorage();
726519
727289
  init_settings2();
727290
+ init_stringUtils();
727291
+ init_truncateMiddle();
726520
727292
  init_memoryTypes();
726521
727293
  teamMemPaths7 = feature("TEAMMEM") ? (init_teamMemPaths(), __toCommonJS(exports_teamMemPaths)) : null;
726522
727294
  HTML_COMMENT_REGEX = /<!--[\s\S]*?-->/g;
@@ -726595,10 +727367,108 @@ var init_agentMemory = __esm(() => {
726595
727367
  init_path2();
726596
727368
  });
726597
727369
 
727370
+ // src/utils/permissions/symlinkEquivalences.ts
727371
+ import { posix as posix8 } from "path";
727372
+ function unescapePatternSegment(segment2) {
727373
+ return segment2.replace(/\\([\s\S])/g, (match, char) => ESCAPABLE_PATTERN_CHAR.test(char) ? char : match);
727374
+ }
727375
+ function escapePatternPath(path39) {
727376
+ let escaped = path39.replaceAll("\\", "\\\\").replace(/[[\]()|+^$]/g, (char) => `\\${char}`);
727377
+ escaped = escaped.replaceAll("*", "\\*");
727378
+ if (escaped.startsWith("!") || escaped.startsWith("#")) {
727379
+ escaped = `\\${escaped}`;
727380
+ }
727381
+ return escaped.replace(/\s+$/, (whitespace) => Array.from(whitespace, (char) => `\\${char}`).join(""));
727382
+ }
727383
+ function collapsePatternSlashes(pattern) {
727384
+ const collapsed = pattern.replace(/\/{2,}/g, "/");
727385
+ if (/^\s*(?:\/\*\*)?$/.test(collapsed)) {
727386
+ return collapsed;
727387
+ }
727388
+ return collapsed.replace(/^\uFEFF([!#]?)/, (_match, marker) => marker ? `\\${marker}` : "").replace(/^\uFEFF/, "[\uFEFF]");
727389
+ }
727390
+ function normalizeTrailingGlobstar(pattern, isAllow) {
727391
+ if (pattern.endsWith("/**")) {
727392
+ const withoutSuffix = pattern.slice(0, -3);
727393
+ if (/[^/]/.test(withoutSuffix)) {
727394
+ return withoutSuffix.includes("/") || !isAllow || /^[!#]/.test(withoutSuffix) ? withoutSuffix : `/${withoutSuffix}`;
727395
+ }
727396
+ return "/**";
727397
+ }
727398
+ return pattern;
727399
+ }
727400
+ function unusablePatternReason(pattern) {
727401
+ if (UNUSABLE_IGNORE_PATTERN.test(pattern)) {
727402
+ return "skipped by the ignore library (blank, comment, or trailing backslash)";
727403
+ }
727404
+ return validateIgnorePattern(pattern);
727405
+ }
727406
+ function makePhysicalTwinsKey(root3, pattern) {
727407
+ return `${root3}\x00${pattern}`;
727408
+ }
727409
+ function getOrInitPhysicalTwins(key4) {
727410
+ let twins = physicalTwinsByPattern.get(key4);
727411
+ if (twins === undefined) {
727412
+ twins = new Set;
727413
+ physicalTwinsByPattern.set(key4, twins);
727414
+ }
727415
+ return twins;
727416
+ }
727417
+ function resolvePhysicalTwinPattern(root3, rawPattern) {
727418
+ if (getPlatform() === "windows") {
727419
+ return null;
727420
+ }
727421
+ const pattern = collapsePatternSlashes(rawPattern);
727422
+ if (!pattern.startsWith("/")) {
727423
+ return null;
727424
+ }
727425
+ const segments = pattern.slice(1).split("/");
727426
+ let prefixEnd = 0;
727427
+ while (prefixEnd < segments.length && segments[prefixEnd] !== "" && !UNESCAPED_GLOB_CHAR.test(segments[prefixEnd])) {
727428
+ prefixEnd++;
727429
+ }
727430
+ if (prefixEnd === 0) {
727431
+ return null;
727432
+ }
727433
+ const prefixPath = posix8.join(root3, ...segments.slice(0, prefixEnd).map(unescapePatternSegment));
727434
+ let physicalPrefix;
727435
+ try {
727436
+ physicalPrefix = resolveDeepestExistingAncestorSync(getFsImplementation(), prefixPath);
727437
+ } catch (error52) {
727438
+ logForDebugging(`Could not resolve the physical twin of rule prefix ${prefixPath}: ${error52}`);
727439
+ return null;
727440
+ }
727441
+ if (physicalPrefix === undefined || physicalPrefix === prefixPath || physicalPrefix === DIR_SEP) {
727442
+ return null;
727443
+ }
727444
+ const rest = segments.slice(prefixEnd);
727445
+ const twin = collapsePatternSlashes(escapePatternPath(physicalPrefix) + (rest.length > 0 ? `/${rest.join("/")}` : ""));
727446
+ const normalized = normalizeTrailingGlobstar(twin, false);
727447
+ if (unusablePatternReason(normalized) !== null) {
727448
+ return null;
727449
+ }
727450
+ if (normalized !== twin && `${normalized}/**` !== twin) {
727451
+ return null;
727452
+ }
727453
+ return twin;
727454
+ }
727455
+ var DIR_SEP, UNESCAPED_GLOB_CHAR, ESCAPABLE_PATTERN_CHAR, UNUSABLE_IGNORE_PATTERN, physicalTwinsByPattern;
727456
+ var init_symlinkEquivalences = __esm(() => {
727457
+ init_debug();
727458
+ init_fsOperations();
727459
+ init_globPatternValidation();
727460
+ init_platform2();
727461
+ DIR_SEP = posix8.sep;
727462
+ UNESCAPED_GLOB_CHAR = /(?:^|[^\\])(?:\\\\)*[*?[]/;
727463
+ ESCAPABLE_PATTERN_CHAR = /^[\\[\]!#()|+^$*?\s]$/;
727464
+ UNUSABLE_IGNORE_PATTERN = /^\s*$|^#|(?:^|[^\\])\\$/;
727465
+ physicalTwinsByPattern = new Map;
727466
+ });
727467
+
726598
727468
  // src/utils/permissions/filesystem.ts
726599
727469
  import { randomBytes as randomBytes19 } from "crypto";
726600
727470
  import { homedir as homedir44, tmpdir as tmpdir15 } from "os";
726601
- import { join as join164, normalize as normalize18, posix as posix8, sep as sep47 } from "path";
727471
+ import { join as join164, normalize as normalize18, posix as posix9, sep as sep47 } from "path";
726602
727472
  function normalizeCaseForComparison2(path39) {
726603
727473
  return path39.toLowerCase();
726604
727474
  }
@@ -726641,9 +727511,9 @@ function relativePath(from2, to) {
726641
727511
  if (getPlatform() === "windows") {
726642
727512
  const posixFrom = windowsPathToPosixPath(from2);
726643
727513
  const posixTo = windowsPathToPosixPath(to);
726644
- return posix8.relative(posixFrom, posixTo);
727514
+ return posix9.relative(posixFrom, posixTo);
726645
727515
  }
726646
- return posix8.relative(from2, to);
727516
+ return posix9.relative(from2, to);
726647
727517
  }
726648
727518
  function toPosixPath(path39) {
726649
727519
  if (getPlatform() === "windows") {
@@ -726838,7 +727708,7 @@ function pathInWorkingPath(path39, workingPath) {
726838
727708
  if (containsPathTraversal(relative32)) {
726839
727709
  return false;
726840
727710
  }
726841
- return !posix8.isAbsolute(relative32);
727711
+ return !posix9.isAbsolute(relative32);
726842
727712
  }
726843
727713
  function rootPathForSource(source2) {
726844
727714
  switch (source2) {
@@ -726855,25 +727725,25 @@ function rootPathForSource(source2) {
726855
727725
  }
726856
727726
  }
726857
727727
  function prependDirSep(path39) {
726858
- return posix8.join(DIR_SEP, path39);
727728
+ return posix9.join(DIR_SEP2, path39);
726859
727729
  }
726860
727730
  function normalizePatternToPath({
726861
727731
  patternRoot,
726862
727732
  pattern,
726863
727733
  rootPath
726864
727734
  }) {
726865
- const fullPattern = posix8.join(patternRoot, pattern);
727735
+ const fullPattern = posix9.join(patternRoot, pattern);
726866
727736
  if (patternRoot === rootPath) {
726867
727737
  return prependDirSep(pattern);
726868
- } else if (fullPattern.startsWith(`${rootPath}${DIR_SEP}`)) {
727738
+ } else if (fullPattern.startsWith(`${rootPath}${DIR_SEP2}`)) {
726869
727739
  const relativePart = fullPattern.slice(rootPath.length);
726870
727740
  return prependDirSep(relativePart);
726871
727741
  } else {
726872
- const relativePath2 = posix8.relative(rootPath, patternRoot);
726873
- if (!relativePath2 || relativePath2.startsWith(`..${DIR_SEP}`) || relativePath2 === "..") {
727742
+ const relativePath2 = posix9.relative(rootPath, patternRoot);
727743
+ if (!relativePath2 || relativePath2.startsWith(`..${DIR_SEP2}`) || relativePath2 === "..") {
726874
727744
  return null;
726875
727745
  } else {
726876
- const relativePattern = posix8.join(relativePath2, pattern);
727746
+ const relativePattern = posix9.join(relativePath2, pattern);
726877
727747
  return prependDirSep(relativePattern);
726878
727748
  }
726879
727749
  }
@@ -726906,7 +727776,7 @@ function getFileReadIgnorePatterns(toolPermissionContext) {
726906
727776
  return result;
726907
727777
  }
726908
727778
  function patternWithRoot(pattern, source2) {
726909
- if (pattern.startsWith(`${DIR_SEP}${DIR_SEP}`)) {
727779
+ if (pattern.startsWith(`${DIR_SEP2}${DIR_SEP2}`)) {
726910
727780
  const patternWithoutDoubleSlash = pattern.slice(1);
726911
727781
  if (getPlatform() === "windows" && patternWithoutDoubleSlash.match(/^\/[a-z]\//i)) {
726912
727782
  const driveLetter = patternWithoutDoubleSlash[1]?.toUpperCase() ?? "C";
@@ -726920,21 +727790,21 @@ function patternWithRoot(pattern, source2) {
726920
727790
  }
726921
727791
  return {
726922
727792
  relativePattern: patternWithoutDoubleSlash,
726923
- root: DIR_SEP
727793
+ root: DIR_SEP2
726924
727794
  };
726925
- } else if (pattern.startsWith(`~${DIR_SEP}`)) {
727795
+ } else if (pattern.startsWith(`~${DIR_SEP2}`)) {
726926
727796
  return {
726927
727797
  relativePattern: pattern.slice(1),
726928
727798
  root: homedir44().normalize("NFC")
726929
727799
  };
726930
- } else if (pattern.startsWith(DIR_SEP)) {
727800
+ } else if (pattern.startsWith(DIR_SEP2)) {
726931
727801
  return {
726932
727802
  relativePattern: pattern,
726933
727803
  root: rootPathForSource(source2)
726934
727804
  };
726935
727805
  }
726936
727806
  let normalizedPattern = pattern;
726937
- if (pattern.startsWith(`.${DIR_SEP}`)) {
727807
+ if (pattern.startsWith(`.${DIR_SEP2}`)) {
726938
727808
  normalizedPattern = pattern.slice(2);
726939
727809
  }
726940
727810
  return {
@@ -727024,6 +727894,24 @@ function getPatternsByRoot(toolPermissionContext, toolType, behavior) {
727024
727894
  patternsByRoot.set(root3, patternsForRoot);
727025
727895
  }
727026
727896
  patternsForRoot.set(relativePattern, rule);
727897
+ if (behavior === "allow" || root3 === null) {
727898
+ continue;
727899
+ }
727900
+ const twins = getOrInitPhysicalTwins(makePhysicalTwinsKey(root3, relativePattern));
727901
+ const twin = resolvePhysicalTwinPattern(root3, relativePattern);
727902
+ if (twin !== null) {
727903
+ twins.add(twin);
727904
+ }
727905
+ for (const twinPattern of twins) {
727906
+ let rootSlashPatterns = patternsByRoot.get(DIR_SEP2);
727907
+ if (rootSlashPatterns === undefined) {
727908
+ rootSlashPatterns = new Map;
727909
+ patternsByRoot.set(DIR_SEP2, rootSlashPatterns);
727910
+ }
727911
+ if (!rootSlashPatterns.has(twinPattern)) {
727912
+ rootSlashPatterns.set(twinPattern, rule);
727913
+ }
727914
+ }
727027
727915
  }
727028
727916
  return patternsByRoot;
727029
727917
  }
@@ -727036,7 +727924,7 @@ function matchingRuleForInput(path39, toolPermissionContext, toolType, behavior)
727036
727924
  for (const [root3, { patternMap, getIg }] of matchersByRoot.entries()) {
727037
727925
  const ig = getIg();
727038
727926
  const relativePathStr = relativePath(root3 ?? getCwd(), fileAbsolutePath ?? getCwd());
727039
- if (relativePathStr.startsWith(`..${DIR_SEP}`)) {
727927
+ if (relativePathStr.startsWith(`..${DIR_SEP2}`)) {
727040
727928
  continue;
727041
727929
  }
727042
727930
  if (!relativePathStr) {
@@ -727497,7 +728385,7 @@ function checkReadableInternalPath(absolutePath, input2) {
727497
728385
  }
727498
728386
  return { behavior: "passthrough", message: "" };
727499
728387
  }
727500
- var import_ignore6, DANGEROUS_FILES2, DANGEROUS_DIRECTORIES2, DIR_SEP, getClaudeTempDir, getBundledSkillsRoot, getResolvedWorkingDirPaths, MATCHER_RECOMPILE_THRESHOLD = 1e4, MATCHER_CACHE_MAX_ENTRIES = 16, matcherCache;
728388
+ var import_ignore6, DANGEROUS_FILES2, DANGEROUS_DIRECTORIES2, DIR_SEP2, getClaudeTempDir, getBundledSkillsRoot, getResolvedWorkingDirPaths, MATCHER_RECOMPILE_THRESHOLD = 1e4, MATCHER_CACHE_MAX_ENTRIES = 16, matcherCache;
727501
728389
  var init_filesystem = __esm(() => {
727502
728390
  init_featureFlags();
727503
728391
  init_memoize();
@@ -727520,6 +728408,7 @@ var init_filesystem = __esm(() => {
727520
728408
  init_windowsPaths();
727521
728409
  init_PermissionUpdate();
727522
728410
  init_permissions2();
728411
+ init_symlinkEquivalences();
727523
728412
  import_ignore6 = __toESM(require_ignore(), 1);
727524
728413
  DANGEROUS_FILES2 = [
727525
728414
  ".gitconfig",
@@ -727540,7 +728429,7 @@ var init_filesystem = __esm(() => {
727540
728429
  ".claude",
727541
728430
  ".husky"
727542
728431
  ];
727543
- DIR_SEP = posix8.sep;
728432
+ DIR_SEP2 = posix9.sep;
727544
728433
  getClaudeTempDir = memoize_default(function getClaudeTempDir2() {
727545
728434
  const baseTmpDir = process.env.CLAUDE_CODE_TMPDIR || (getPlatform() === "windows" ? tmpdir15() : "/tmp");
727546
728435
  const fs26 = getFsImplementation();
@@ -728392,38 +729281,6 @@ var init_hooks4 = __esm(() => {
728392
729281
  });
728393
729282
  });
728394
729283
 
728395
- // src/utils/combinedAbortSignal.ts
728396
- function createCombinedAbortSignal(signal, opts) {
728397
- const { signalB, timeoutMs } = opts ?? {};
728398
- const combined = createAbortController();
728399
- if (signal?.aborted || signalB?.aborted) {
728400
- combined.abort();
728401
- return { signal: combined.signal, cleanup: () => {} };
728402
- }
728403
- let timer2;
728404
- const abortCombined = () => {
728405
- if (timer2 !== undefined)
728406
- clearTimeout(timer2);
728407
- combined.abort();
728408
- };
728409
- if (timeoutMs !== undefined) {
728410
- timer2 = setTimeout(abortCombined, timeoutMs);
728411
- timer2.unref?.();
728412
- }
728413
- signal?.addEventListener("abort", abortCombined);
728414
- signalB?.addEventListener("abort", abortCombined);
728415
- const cleanup2 = () => {
728416
- if (timer2 !== undefined)
728417
- clearTimeout(timer2);
728418
- signal?.removeEventListener("abort", abortCombined);
728419
- signalB?.removeEventListener("abort", abortCombined);
728420
- };
728421
- return { signal: combined.signal, cleanup: cleanup2 };
728422
- }
728423
- var init_combinedAbortSignal = __esm(() => {
728424
- init_abortController();
728425
- });
728426
-
728427
729284
  // src/utils/hooks/hookHelpers.ts
728428
729285
  function addArgumentsToPrompt(prompt, jsonInput) {
728429
729286
  return substituteArguments(prompt, jsonInput);
@@ -729259,6 +730116,7 @@ __export(exports_hooks2, {
729259
730116
  getTaskCreatedHookMessage: () => getTaskCreatedHookMessage,
729260
730117
  getTaskCompletedHookMessage: () => getTaskCompletedHookMessage,
729261
730118
  getStopHookMessage: () => getStopHookMessage,
730119
+ getSessionEndHooksBudgetMs: () => getSessionEndHooksBudgetMs,
729262
730120
  getSessionEndHookTimeoutMs: () => getSessionEndHookTimeoutMs,
729263
730121
  getPreToolHookBlockingMessage: () => getPreToolHookBlockingMessage,
729264
730122
  getMatchingHooks: () => getMatchingHooks,
@@ -729309,9 +730167,28 @@ function hookCallbackTimeoutMessage(hookName, timeoutMs) {
729309
730167
  return `${hookName} hook callback timed out after ${timeoutMs}ms`;
729310
730168
  }
729311
730169
  function getSessionEndHookTimeoutMs() {
729312
- const raw = process.env.CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS;
729313
- const parsed = raw ? parseEnvInt(raw) : NaN;
729314
- return Number.isFinite(parsed) && parsed > 0 ? parsed : SESSION_END_HOOK_TIMEOUT_MS_DEFAULT;
730170
+ const parsed = parseEnvInt(process.env.CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS);
730171
+ return parsed ?? SESSION_END_HOOK_TIMEOUT_MS_DEFAULT;
730172
+ }
730173
+ function getSessionEndHooksBudgetMs() {
730174
+ const fromEnv5 = parseEnvInt(process.env.CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS);
730175
+ if (fromEnv5 !== undefined) {
730176
+ return fromEnv5;
730177
+ }
730178
+ let maxHookTimeoutMs = 0;
730179
+ try {
730180
+ for (const matcher of getHooksConfigFromSnapshot()?.SessionEnd ?? []) {
730181
+ for (const hook of matcher.hooks ?? []) {
730182
+ const timeoutSec = hook.timeout;
730183
+ if (timeoutSec && timeoutSec * 1000 > maxHookTimeoutMs) {
730184
+ maxHookTimeoutMs = timeoutSec * 1000;
730185
+ }
730186
+ }
730187
+ }
730188
+ } catch (e4) {
730189
+ logError2(e4);
730190
+ }
730191
+ return Math.max(SESSION_END_HOOK_TIMEOUT_MS_DEFAULT, Math.min(maxHookTimeoutMs, SESSION_END_HOOKS_BUDGET_MS_MAX));
729315
730192
  }
729316
730193
  function executeInBackground({
729317
730194
  processId,
@@ -732643,7 +733520,7 @@ async function* executeMessageDisplayHooks(display, getAppState, agentId, signal
732643
733520
  timeoutMs
732644
733521
  });
732645
733522
  }
732646
- var TOOL_HOOK_EXECUTION_TIMEOUT_MS, PRE_TOOL_USE_HOOK_TIMEOUT_MESSAGE = "PreToolUse hook did not respond before its timeout (host client may be unreachable). The tool call was not executed; other configured hooks may not have completed.", SESSION_END_HOOK_TIMEOUT_MS_DEFAULT = 1500, BACKGROUND_TASK_TYPE_LABELS, HOOK_STRING_CAP = 1000, HOOK_JSON_VALIDATION_ERROR_PREFIX = "Hook JSON output validation failed \u2014 ", HOOK_JSON_DISCRIMINATOR_KEYS, MISSING_SCRIPT_HOOK_EVENTS, MATCHER_COMMA_HYPHEN_EVENTS;
733523
+ var TOOL_HOOK_EXECUTION_TIMEOUT_MS, PRE_TOOL_USE_HOOK_TIMEOUT_MESSAGE = "PreToolUse hook did not respond before its timeout (host client may be unreachable). The tool call was not executed; other configured hooks may not have completed.", SESSION_END_HOOK_TIMEOUT_MS_DEFAULT = 1500, SESSION_END_HOOKS_BUDGET_MS_MAX = 60000, BACKGROUND_TASK_TYPE_LABELS, HOOK_STRING_CAP = 1000, HOOK_JSON_VALIDATION_ERROR_PREFIX = "Hook JSON output validation failed \u2014 ", HOOK_JSON_DISCRIMINATOR_KEYS, MISSING_SCRIPT_HOOK_EVENTS, MATCHER_COMMA_HYPHEN_EVENTS;
732647
733524
  var init_hooks5 = __esm(() => {
732648
733525
  init_file();
732649
733526
  init_envValidation();
@@ -762547,6 +763424,14 @@ var init_useBuddyNotification = __esm(() => {
762547
763424
  jsx_runtime402 = __toESM(require_jsx_runtime(), 1);
762548
763425
  });
762549
763426
 
763427
+ // src/hooks/historyEdited.ts
763428
+ function computeHistoryEdited(historyIndex, currentInput, recalledValue) {
763429
+ return historyIndex > 0 && currentInput !== recalledValue;
763430
+ }
763431
+ function computeSuppressSuggestions(isSearchingHistory, historyIndex, historyEdited) {
763432
+ return isSearchingHistory || historyIndex > 0 && !historyEdited;
763433
+ }
763434
+
762550
763435
  // src/hooks/useIdeConnectionStatus.ts
762551
763436
  function useIdeConnectionStatus(mcpClients) {
762552
763437
  return import_react223.useMemo(() => {
@@ -764264,6 +765149,7 @@ function useArrowKeyHistory(onSetInput, currentInput, pastedContents, setCursorO
764264
765149
  const historyCache = import_react235.useRef([]);
764265
765150
  const historyCacheModeFilter = import_react235.useRef(undefined);
764266
765151
  const historyIndexRef = import_react235.useRef(0);
765152
+ const recalledValueRef = import_react235.useRef(null);
764267
765153
  const initialModeFilterRef = import_react235.useRef(undefined);
764268
765154
  const currentInputRef = import_react235.useRef(currentInput);
764269
765155
  const pastedContentsRef = import_react235.useRef(pastedContents);
@@ -764272,6 +765158,7 @@ function useArrowKeyHistory(onSetInput, currentInput, pastedContents, setCursorO
764272
765158
  pastedContentsRef.current = pastedContents;
764273
765159
  currentModeRef.current = currentMode;
764274
765160
  const setInputWithCursor = import_react235.useCallback((value, mode, contents, cursorToStart = false) => {
765161
+ recalledValueRef.current = value;
764275
765162
  onSetInput(value, mode, contents);
764276
765163
  setCursorOffset?.(cursorToStart ? 0 : value.length);
764277
765164
  }, [onSetInput, setCursorOffset]);
@@ -764367,6 +765254,7 @@ function useArrowKeyHistory(onSetInput, currentInput, pastedContents, setCursorO
764367
765254
  setHistoryIndex(0);
764368
765255
  historyIndexRef.current = 0;
764369
765256
  initialModeFilterRef.current = undefined;
765257
+ recalledValueRef.current = null;
764370
765258
  removeNotification("search-history-hint");
764371
765259
  historyCache.current = [];
764372
765260
  historyCacheModeFilter.current = undefined;
@@ -764376,6 +765264,7 @@ function useArrowKeyHistory(onSetInput, currentInput, pastedContents, setCursorO
764376
765264
  }, [removeNotification]);
764377
765265
  return {
764378
765266
  historyIndex,
765267
+ historyEdited: computeHistoryEdited(historyIndex, currentInput, recalledValueRef.current),
764379
765268
  setHistoryIndex,
764380
765269
  onHistoryUp,
764381
765270
  onHistoryDown,
@@ -764383,7 +765272,7 @@ function useArrowKeyHistory(onSetInput, currentInput, pastedContents, setCursorO
764383
765272
  dismissSearchHint
764384
765273
  };
764385
765274
  }
764386
- var import_react235, jsx_runtime414, HISTORY_CHUNK_SIZE = 10, pendingLoad = null, pendingLoadTarget = 0, pendingLoadModeFilter = undefined;
765275
+ var import_react235, jsx_runtime414, HISTORY_CHUNK_SIZE = 10, pendingLoad = null, pendingLoadTarget = 0, pendingLoadModeFilter;
764387
765276
  var init_useArrowKeyHistory = __esm(() => {
764388
765277
  init_notifications();
764389
765278
  init_ConfigurableShortcutHint();
@@ -776386,7 +777275,8 @@ function PromptInput({
776386
777275
  onHistoryUp,
776387
777276
  onHistoryDown,
776388
777277
  dismissSearchHint,
776389
- historyIndex
777278
+ historyIndex,
777279
+ historyEdited
776390
777280
  } = useArrowKeyHistory((value, historyMode, pastedContents2) => {
776391
777281
  onChange(value);
776392
777282
  onModeChange(historyMode);
@@ -776537,7 +777427,7 @@ function PromptInput({
776537
777427
  agents: agents2,
776538
777428
  setSuggestionsState,
776539
777429
  suggestionsState,
776540
- suppressSuggestions: isSearchingHistory || historyIndex > 0,
777430
+ suppressSuggestions: computeSuppressSuggestions(isSearchingHistory, historyIndex, historyEdited),
776541
777431
  markAccepted,
776542
777432
  onModeChange
776543
777433
  });
@@ -797954,7 +798844,10 @@ function useMcpConnectivityStatus(t0) {
797954
798844
  }
797955
798845
  const failedLocalClients = mcpClients.filter(_temp225);
797956
798846
  const failedClaudeAiClients = mcpClients.filter(_temp286);
797957
- const needsAuthCount = getMcpNeedsAuthCount(mcpClients);
798847
+ if (countNoticedServersNowConnected(mcpClients) > 0) {
798848
+ pruneNoticedServersNowConnected(mcpClients);
798849
+ }
798850
+ const needsAuthCount = countNeedsAuthToAnnounce(mcpClients, MCP_NEEDS_AUTH_NOTICE_DEPS);
797958
798851
  if (failedLocalClients.length === 0 && failedClaudeAiClients.length === 0 && needsAuthCount === 0) {
797959
798852
  return;
797960
798853
  }
@@ -798031,6 +798924,7 @@ function useMcpConnectivityStatus(t0) {
798031
798924
  }),
798032
798925
  priority: "medium"
798033
798926
  });
798927
+ markNeedsAuthNoticed(mcpClients, MCP_NEEDS_AUTH_NOTICE_DEPS);
798034
798928
  }
798035
798929
  };
798036
798930
  t32 = [addNotification, mcpClients];
@@ -798050,16 +798944,21 @@ function _temp286(client_0) {
798050
798944
  function _temp225(client8) {
798051
798945
  return client8.type === "failed" && client8.config.type !== "sse-ide" && client8.config.type !== "ws-ide" && client8.config.type !== "claudeai-proxy";
798052
798946
  }
798053
- var import_compiler_runtime326, import_react303, jsx_runtime455, EMPTY_MCP_CLIENTS;
798947
+ var import_compiler_runtime326, import_react303, jsx_runtime455, EMPTY_MCP_CLIENTS, MCP_NEEDS_AUTH_NOTICE_DEPS;
798054
798948
  var init_useMcpConnectivityStatus = __esm(() => {
798055
798949
  init_notifications();
798056
798950
  init_state();
798057
798951
  init_ink2();
798058
798952
  init_claudeai();
798953
+ init_mcpNeedsAuthNotice();
798059
798954
  import_compiler_runtime326 = __toESM(require_compiler_runtime(), 1);
798060
798955
  import_react303 = __toESM(require_react(), 1);
798061
798956
  jsx_runtime455 = __toESM(require_jsx_runtime(), 1);
798062
798957
  EMPTY_MCP_CLIENTS = [];
798958
+ MCP_NEEDS_AUTH_NOTICE_DEPS = {
798959
+ hasEverConnected: hasClaudeAiMcpEverConnected,
798960
+ connectedThisSession: isClaudeAiMcpCurrentlyConnected
798961
+ };
798063
798962
  });
798064
798963
 
798065
798964
  // src/hooks/notifs/useAutoModeUnavailableNotification.ts
@@ -807293,13 +808192,13 @@ var init_bootstrap = __esm(() => {
807293
808192
  });
807294
808193
 
807295
808194
  // src/utils/warningHandler.ts
807296
- import { posix as posix9, win32 as win324 } from "path";
808195
+ import { posix as posix10, win32 as win324 } from "path";
807297
808196
  function isRunningFromBuildDirectory() {
807298
808197
  let invokedPath = process.argv[1] || "";
807299
808198
  let execPath2 = process.execPath || process.argv[0] || "";
807300
808199
  if (getPlatform() === "windows") {
807301
- invokedPath = invokedPath.split(win324.sep).join(posix9.sep);
807302
- execPath2 = execPath2.split(win324.sep).join(posix9.sep);
808200
+ invokedPath = invokedPath.split(win324.sep).join(posix10.sep);
808201
+ execPath2 = execPath2.split(win324.sep).join(posix10.sep);
807303
808202
  }
807304
808203
  const pathsToCheck = [invokedPath, execPath2];
807305
808204
  const buildDirs = [
@@ -824005,11 +824904,14 @@ async function mcpListHandler() {
824005
824904
  }), {
824006
824905
  concurrency: getMcpServerConnectionBatchSize()
824007
824906
  });
824907
+ const displayConfigs = getDisplayServers(configs, resolveUnexpandedMcpServers);
824008
824908
  for (const {
824009
824909
  name: name3,
824010
- server,
824011
824910
  status: status2
824012
824911
  } of results) {
824912
+ const server = displayConfigs[name3];
824913
+ if (!server)
824914
+ continue;
824013
824915
  if (server.type === "sse") {
824014
824916
  console.log(`${name3}: ${server.url} (SSE) - ${status2}`);
824015
824917
  } else if (server.type === "http") {
@@ -824036,12 +824938,13 @@ async function mcpGetHandler(name3) {
824036
824938
  console.log(` Scope: ${getScopeLabel(server.scope)}`);
824037
824939
  const status2 = await checkMcpServerHealth(name3, server);
824038
824940
  console.log(` Status: ${status2}`);
824039
- if (server.type === "sse") {
824941
+ const display = getDisplayConfig(name3, server, resolveUnexpandedMcpServers);
824942
+ if (display.type === "sse") {
824040
824943
  console.log(` Type: sse`);
824041
- console.log(` URL: ${server.url}`);
824042
- if (server.headers) {
824944
+ console.log(` URL: ${display.url}`);
824945
+ if (display.headers) {
824043
824946
  console.log(" Headers:");
824044
- for (const [key4, value] of Object.entries(server.headers)) {
824947
+ for (const [key4, value] of Object.entries(display.headers)) {
824045
824948
  console.log(` ${key4}: ${value}`);
824046
824949
  }
824047
824950
  }
@@ -824057,12 +824960,12 @@ async function mcpGetHandler(name3) {
824057
824960
  parts.push(`callback_port ${server.oauth.callbackPort}`);
824058
824961
  console.log(` OAuth: ${parts.join(", ")}`);
824059
824962
  }
824060
- } else if (server.type === "http") {
824963
+ } else if (display.type === "http") {
824061
824964
  console.log(` Type: http`);
824062
- console.log(` URL: ${server.url}`);
824063
- if (server.headers) {
824965
+ console.log(` URL: ${display.url}`);
824966
+ if (display.headers) {
824064
824967
  console.log(" Headers:");
824065
- for (const [key4, value] of Object.entries(server.headers)) {
824968
+ for (const [key4, value] of Object.entries(display.headers)) {
824066
824969
  console.log(` ${key4}: ${value}`);
824067
824970
  }
824068
824971
  }
@@ -824078,14 +824981,14 @@ async function mcpGetHandler(name3) {
824078
824981
  parts.push(`callback_port ${server.oauth.callbackPort}`);
824079
824982
  console.log(` OAuth: ${parts.join(", ")}`);
824080
824983
  }
824081
- } else if (server.type === "stdio") {
824984
+ } else if (display.type === "stdio") {
824082
824985
  console.log(` Type: stdio`);
824083
- console.log(` Command: ${server.command}`);
824084
- const args = Array.isArray(server.args) ? server.args : [];
824986
+ console.log(` Command: ${display.command}`);
824987
+ const args = Array.isArray(display.args) ? display.args : [];
824085
824988
  console.log(` Args: ${args.join(" ")}`);
824086
- if (server.env) {
824989
+ if (display.env) {
824087
824990
  console.log(" Environment:");
824088
- for (const [key4, value] of Object.entries(server.env)) {
824991
+ for (const [key4, value] of Object.entries(display.env)) {
824089
824992
  console.log(` ${key4}=${value}`);
824090
824993
  }
824091
824994
  }
@@ -824212,7 +825115,7 @@ After authorizing, paste the full redirect URL here and press Enter:`);
824212
825115
  });
824213
825116
  cliOk(`Successfully authenticated with MCP server "${name3}".`);
824214
825117
  } catch (error52) {
824215
- cliError(`Failed to authenticate with MCP server "${name3}": ${error52.message}`);
825118
+ cliError(`Failed to authenticate with MCP server "${name3}": ${redactMcpErrorDetail(name3, server, error52.message, resolveUnexpandedMcpServers)}`);
824216
825119
  }
824217
825120
  }
824218
825121
  async function mcpLogoutHandler(name3) {
@@ -824245,6 +825148,7 @@ var init_mcp5 = __esm(() => {
824245
825148
  init_auth11();
824246
825149
  init_client12();
824247
825150
  init_config6();
825151
+ init_redaction();
824248
825152
  init_utils9();
824249
825153
  init_normalization();
824250
825154
  init_AppState();