diff --git a/.github/workflows/validate-skill-types.yml b/.github/workflows/validate-skill-types.yml new file mode 100644 index 0000000..191c5ff --- /dev/null +++ b/.github/workflows/validate-skill-types.yml @@ -0,0 +1,36 @@ +name: Validate skill agent-types + +on: + pull_request: + paths: + - 'skills/*/SKILL.md' + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Check all skills have agent-types frontmatter + run: | + ERRORS=0 + for dir in skills/*/; do + skill_name=$(basename "$dir") + skill_file="$dir/SKILL.md" + [ -f "$skill_file" ] || continue + case "$skill_name" in int-*) continue ;; esac + + agent_types=$(head -20 "$skill_file" | grep "^agent-types:" | sed 's/agent-types: *//') + if [ -z "$agent_types" ]; then + echo "::error::Skill '$skill_name' is missing agent-types in SKILL.md frontmatter. Add 'agent-types: classic', 'agent-types: modern', or 'agent-types: both'." + ERRORS=1 + elif [ "$agent_types" != "classic" ] && [ "$agent_types" != "modern" ] && [ "$agent_types" != "both" ]; then + echo "::error::Skill '$skill_name' has invalid agent-types: '$agent_types'. Must be 'classic', 'modern', or 'both'." + ERRORS=1 + fi + done + + if [ "$ERRORS" -eq 1 ]; then + exit 1 + fi + echo "All skills have valid agent-types frontmatter." diff --git a/agents/copilot-studio-author.md b/agents/copilot-studio-author.md index 1c08daf..c72668c 100644 --- a/agents/copilot-studio-author.md +++ b/agents/copilot-studio-author.md @@ -1,8 +1,8 @@ --- name: Copilot Studio Author description: > - [THIS IS A SUB-AGENT] Copilot Studio YAML authoring specialist. This sub-agent creates and edits topics, actions, knowledge sources, child agents, and global variables. Use when building or modifying Copilot Studio agent YAML files. Always use this in case there's overlap with a skill. - USE FOR: build Copilot Studio agent, create new agent, scaffold agent project, create topic, add knowledge source, add action, edit topic, create child agent, add global variable, new Copilot Studio bot, GPT agent, AI agent in Copilot Studio. + [THIS IS A SUB-AGENT] Copilot Studio YAML authoring specialist. This sub-agent creates and edits topics, actions, knowledge sources, skills, tools, child agents, and global variables. Supports both classic and modern agents. Use when building or modifying Copilot Studio agent YAML files. Always use this in case there's overlap with a skill. + USE FOR: build Copilot Studio agent, create new agent, scaffold agent project, create topic, add knowledge source, add action, edit topic, create child agent, add global variable, new Copilot Studio bot, GPT agent, AI agent in Copilot Studio, create skill, add tool, edit skill. DO NOT USE FOR: deploying agents (use manage), testing agents (use test), debugging YAML errors (use advisor). Always use this agent when the user wants to build or modify Copilot Studio agent YAML files, even if there's overlap with a skill. skills: @@ -39,12 +39,25 @@ Then close with: Do **not** proceed with any authoring task until an `agent.mcs.yml` file exists. +## CRITICAL: Detect agent type — classic vs modern + +After finding `agent.mcs.yml`, read `settings.mcs.yml` in the same directory to determine the agent type: + +- **Modern agent** if `template` contains `cliagent` or the recognizer is `CLICopilotRecognizer` or `CLIAgentRecognizer` +- **Classic agent** otherwise + +This determines which skills you can use. **Using the wrong skill type will fail** — classic skills don't work on modern agents and vice versa. Use the correct dispatch table below. + ## CRITICAL: Always use skills — never do things manually You MUST use the appropriate skill for every task. **NEVER** write or edit YAML files yourself when a skill exists for that task. Skills contain the correct templates, schema validation, and patterns — doing it manually risks hallucinated kinds, missing required fields, and broken YAML. **Before acting on any request**, check this list and invoke the matching skill: +### Classic agent skills + +Use these when the agent type is **classic** (standard Generative Orchestration agent): + | Task | Skill to invoke | |------|----------------| | Create a new topic | `/copilot-studio:new-topic` | @@ -58,11 +71,37 @@ You MUST use the appropriate skill for every task. **NEVER** write or edit YAML | Edit agent settings or instructions | `/copilot-studio:edit-agent` | | Modify trigger phrases or model description | `/copilot-studio:edit-triggers` | | Add an adaptive card | `/copilot-studio:add-adaptive-card` | +| List all topics in the agent | `/copilot-studio:list-topics` | + +### Modern agent skills + +Use these when the agent type is **modern** (agent with `cliagent-1.0.0` template): + +| Task | Skill to invoke | +|------|----------------| +| Create a new skill | `/copilot-studio:new-skill` | +| Edit a skill | `/copilot-studio:edit-skill` | +| Add a tool (connector, MCP, workflow) | `/copilot-studio:add-tool` | +| Add a knowledge source | `/copilot-studio:add-knowledge-modern` | +| List skills and tools | `/copilot-studio:list-skills` | +| Edit agent settings, instructions, output | `/copilot-studio:edit-agent-modern` | + +Modern agents do NOT have topics, action nodes, triggers, adaptive cards, global variables, or generative answer nodes. If the user asks for any of these, explain that modern agents use a different model: +- **Topics** → Skills (markdown instructions the orchestrator invokes) +- **Connector actions** → Tools — use `/copilot-studio:add-tool` (guides through UI connection setup, then YAML editing) +- **Trigger phrases** → Skill descriptions (the orchestrator routes based on description) +- **Adaptive Cards** → Not available (output is text or structured JSON) +- **Global variables** → Not supported at runtime yet +- **Knowledge sources** → Use `/copilot-studio:add-knowledge-modern` (websites are YAML-authorable, others need UI) + +### Shared skills (both agent types) + +| Task | Skill to invoke | +|------|----------------| | Reference a pattern's YAML structure | Read the pattern file from `int-patterns` | | Validate a YAML file | `/copilot-studio:validate` | | Look up a schema definition | `/copilot-studio:lookup-schema` | | List valid kind values | `/copilot-studio:list-kinds` | -| List all topics in the agent | `/copilot-studio:list-topics` | Only if NO skill matches the task may you work manually — and even then, you MUST validate with `/copilot-studio:validate` afterward. diff --git a/evals/evaluate.py b/evals/evaluate.py index 50ee81d..832835a 100644 --- a/evals/evaluate.py +++ b/evals/evaluate.py @@ -120,9 +120,12 @@ def run_cli(cli: str, prompt: str, cwd: Path, timeout: int = 600, plugin_dir: st cmd.extend(["--allowedTools", "Bash(node *) Read Write Glob Edit"]) if plugin_dir: cmd.extend(["--plugin-dir", plugin_dir]) - # Inject PreToolUse hook to trace skill invocations inside sub-agents + # Inject PreToolUse hooks: + # 1. Trace skill invocations inside sub-agents + # 2. Filter skills by agent type (blocks incompatible skills) # Use forward slashes for cross-platform compatibility in node command hook_path = str(HOOK_SCRIPT).replace("\\", "/") + filter_path = str(REPO_ROOT / "hooks" / "filter-skills.js").replace("\\", "/") hook_settings = json.dumps({ "hooks": { "PreToolUse": [{ diff --git a/evals/fixtures/modern-agent/agent.mcs.yml b/evals/fixtures/modern-agent/agent.mcs.yml new file mode 100644 index 0000000..a88692f --- /dev/null +++ b/evals/fixtures/modern-agent/agent.mcs.yml @@ -0,0 +1 @@ +kind: GptComponentMetadata diff --git a/evals/fixtures/modern-agent/knowledge/httpswwwcontosocom_abc1.mcs.yml b/evals/fixtures/modern-agent/knowledge/httpswwwcontosocom_abc1.mcs.yml new file mode 100644 index 0000000..8e25a3e --- /dev/null +++ b/evals/fixtures/modern-agent/knowledge/httpswwwcontosocom_abc1.mcs.yml @@ -0,0 +1,6 @@ +mcs.metadata: + componentName: https://www.contoso.com +kind: KnowledgeSourceConfiguration +source: + kind: WebsiteKnowledgeSource + siteUrl: https://www.contoso.com diff --git a/evals/fixtures/modern-agent/settings.mcs.yml b/evals/fixtures/modern-agent/settings.mcs.yml new file mode 100644 index 0000000..c9f45c3 --- /dev/null +++ b/evals/fixtures/modern-agent/settings.mcs.yml @@ -0,0 +1,24 @@ +displayName: Eval Modern Agent +schemaName: eval_modernAgent +accessControlPolicy: GroupMembership +authenticationMode: None +authenticationTrigger: AsNeeded +configuration: + recognizer: + $kind: CLICopilotRecognizer + + agentSettings: + $kind: AgentSettings + instructions: + $kind: Instructions + segments: + - $kind: StaticSegment + value: You are a helpful customer support agent for Contoso Electronics. + + conversationStarters: + - $kind: ConversationStarter + title: Get Started + text: How can you help me? + +template: cliagent-1.0.0 +language: 1033 diff --git a/evals/fixtures/modern-agent/topics/Default_orderLookup.mcs.yml b/evals/fixtures/modern-agent/topics/Default_orderLookup.mcs.yml new file mode 100644 index 0000000..2f37778 --- /dev/null +++ b/evals/fixtures/modern-agent/topics/Default_orderLookup.mcs.yml @@ -0,0 +1,15 @@ +mcs.metadata: + componentName: OrderLookup + description: Looks up order status when the customer asks about shipping or delivery. +kind: InlineAgentSkill +content: |- + --- + name: OrderLookup + description: Looks up order status when the customer asks about shipping or delivery. + --- + # Order Lookup + + When the user asks about their order status: + 1. Ask for their order number + 2. Tell them you're looking it up + 3. Respond with a placeholder status diff --git a/evals/fixtures/modern-agent/translations/Default_draft_eval.action.MSNWeather-Getcurrentweather.mcs.yml b/evals/fixtures/modern-agent/translations/Default_draft_eval.action.MSNWeather-Getcurrentweather.mcs.yml new file mode 100644 index 0000000..e32e67a --- /dev/null +++ b/evals/fixtures/modern-agent/translations/Default_draft_eval.action.MSNWeather-Getcurrentweather.mcs.yml @@ -0,0 +1,7 @@ +mcs.metadata: + componentName: MSN Weather — Get current weather + description: Get the current weather for a location. +kind: ConnectorTool +connectorId: /providers/Microsoft.PowerApps/apis/shared_msnweather +connectionReference: eval_modernAgent.shared_msnweather.abc123 +operationId: CurrentWeather diff --git a/evals/scenarios/skill-filtering.json b/evals/scenarios/skill-filtering.json new file mode 100644 index 0000000..67da786 --- /dev/null +++ b/evals/scenarios/skill-filtering.json @@ -0,0 +1,91 @@ +{ + "scenario_name": "skill-filtering", + "evals": [ + { + "id": 1, + "name": "Create a new skill on modern agent", + "prompt": "Create a skill called ReturnPolicy that explains our 30-day return policy when customers ask about returns or refunds.", + "fixture": "modern-agent", + "mock_scripts": [], + "checks": { + "skill_invoked": "copilot-studio:new-skill", + "files_created": [ + { + "pattern": "topics/*.mcs.yml", + "min_count": 1 + } + ], + "content_contains": [ + "InlineAgentSkill", + "return", + "30" + ], + "no_placeholders": true + } + }, + { + "id": 2, + "name": "Edit existing skill description on modern agent", + "prompt": "Update the OrderLookup skill description to also mention 'order cancellation' and 'refund status' so the orchestrator routes those questions to it too.", + "fixture": "modern-agent", + "mock_scripts": [], + "checks": { + "skill_invoked": "copilot-studio:edit-skill", + "content_contains": [ + "cancellation", + "refund" + ] + } + }, + { + "id": 3, + "name": "Edit modern agent instructions", + "prompt": "Change the agent's instructions to: 'You are a friendly tech support agent for Contoso Electronics. Always greet the customer by name if available. Escalate complex hardware issues to a human agent.'", + "fixture": "modern-agent", + "mock_scripts": [], + "checks": { + "skill_invoked": "copilot-studio:edit-agent-modern", + "content_contains": [ + "Contoso Electronics", + "escalate", + "hardware" + ] + } + }, + { + "id": 4, + "name": "Add website knowledge source on modern agent", + "prompt": "Add https://learn.microsoft.com/en-us/copilot-studio/ as a knowledge source so the agent can answer questions about Copilot Studio.", + "fixture": "modern-agent", + "mock_scripts": [], + "checks": { + "skill_invoked": "copilot-studio:add-knowledge-modern", + "files_created": [ + { + "pattern": "knowledge/*.mcs.yml", + "min_count": 1 + } + ], + "content_contains": [ + "WebsiteKnowledgeSource", + "learn.microsoft.com" + ] + } + }, + { + "id": 5, + "name": "Add conversation starters on modern agent", + "prompt": "Add three conversation starters: 'Check order status', 'Return a product', and 'Contact support'.", + "fixture": "modern-agent", + "mock_scripts": [], + "checks": { + "skill_invoked": "copilot-studio:edit-agent-modern", + "content_contains": [ + "ConversationStarter", + "order status", + "Return" + ] + } + } + ] +} diff --git a/hooks/filter-skills.js b/hooks/filter-skills.js new file mode 100644 index 0000000..d8e1fa8 --- /dev/null +++ b/hooks/filter-skills.js @@ -0,0 +1,74 @@ +const fs = require('fs'); +const path = require('path'); + +const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT || path.join(__dirname, '..'); + +// Detect agent type from settings.mcs.yml +function detectAgentType(cwd) { + function findSettings(dir, depth) { + if (depth > 4) return null; + try { + const entries = fs.readdirSync(dir, { withFileTypes: true }); + for (const e of entries) { + if (e.name === 'settings.mcs.yml' && e.isFile()) return path.join(dir, e.name); + } + for (const e of entries) { + if (e.isDirectory() && !e.name.startsWith('.') && e.name !== 'node_modules') { + const found = findSettings(path.join(dir, e.name), depth + 1); + if (found) return found; + } + } + } catch {} + return null; + } + + const settingsPath = findSettings(cwd, 0); + if (!settingsPath) return ''; + + const content = fs.readFileSync(settingsPath, 'utf8'); + if (/template:\s*cliagent-/.test(content) || + /\$kind:\s*CLICopilotRecognizer/.test(content) || + /kind:\s*CLICopilotRecognizer/.test(content) || + /kind:\s*CLIAgentRecognizer/.test(content)) { + return 'modern'; + } + return 'classic'; +} + +// Read agent-types from a skill's SKILL.md frontmatter +function getSkillAgentType(skillName) { + const skillFile = path.join(pluginRoot, 'skills', skillName, 'SKILL.md'); + try { + // Read just the frontmatter (first 20 lines is plenty) + const content = fs.readFileSync(skillFile, 'utf8'); + const match = content.match(/^agent-types:\s*(.+)$/m); + return match ? match[1].trim() : 'both'; + } catch { + return 'both'; // Unknown skill — allow + } +} + +let input = ''; +process.stdin.setEncoding('utf8'); +process.stdin.on('data', (chunk) => { input += chunk; }); +process.stdin.on('end', () => { + try { + const data = JSON.parse(input); + const skillField = (data.tool_input && data.tool_input.skill) || ''; + const command = skillField.includes(':') ? skillField.split(':').pop() : skillField; + if (!command) process.exit(0); + + const skillType = getSkillAgentType(command); + if (skillType === 'both') process.exit(0); + + const cwd = data.cwd || process.cwd(); + const agentType = detectAgentType(cwd); + if (!agentType || agentType === skillType) process.exit(0); + + const labels = { modern: 'Modern Agents', classic: 'Generative Orchestration agents' }; + process.stdout.write(JSON.stringify({ + decision: 'block', + reason: 'The "' + command + '" skill is for ' + labels[skillType] + ' only. This workspace contains a ' + labels[agentType] + ' workspace.' + })); + } catch {} +}); diff --git a/hooks/hooks.json b/hooks/hooks.json index d034f7f..5dd55ef 100644 --- a/hooks/hooks.json +++ b/hooks/hooks.json @@ -17,6 +17,19 @@ } ] } + ], + "PreToolUse": [ + { + "matcher": "Skill", + "hooks": [ + { + "type": "command", + "command": "node -e \"var r=process.env.CLAUDE_PLUGIN_ROOT;if(r){var p=require('path');require(p.join(r,'hooks','filter-skills.js'))}\"", + "bash": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/filter-skills.js\"", + "powershell": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/filter-skills.js\"" + } + ] + } ] } } \ No newline at end of file diff --git a/hooks/system-prompt.md b/hooks/system-prompt.md index f8b8cc4..ecaf18f 100644 --- a/hooks/system-prompt.md +++ b/hooks/system-prompt.md @@ -38,6 +38,15 @@ This check prevents users from ending up in a dead end where YAML files are crea - As you have now understood, for Copilot Studio projects and requests, you're the 'manager' of those sub-agents that can work for you. In all cases, regardless of the task, you are still allowed to ask the user for clarifications if you don't understand the request, or if you need more details to be able to provide a better answer or to be able to choose better which sub-agent to call and how. Sub-agents might also ask you for clarifications, and in those cases, you should relay the questions to the user and then provide the answers back to the sub-agent. - Sub-agents should be given the broad context on the task they need to perform, with all the details you can gather from the user's request, but without providing yourself the way to achieve the task, because that's the job of the sub-agent. For example, if the user is asking to add a new feature to their agent, you should provide the sub-agent with all the details about the feature, about the agent, and about anything else that can be useful for the sub-agent to perform the task, but you should not provide instructions to the sub-agent on how to implement that feature like 'build a topic with this YAML code [...]', because that's what the sub-agent is for. You should let the sub-agent figure out how to implement that feature by itself, based on the context and details you provided. Sub-agents are designed to be autonomous and to figure out by themselves how to perform the tasks they're assigned, so you should trust them and give them the freedom to do their job. The only exception for this is if the user explicitly gives you non-functional requirements on how the task should be performed, for example if the user says 'I want you to build a topic that [...]', in such case you can tell the sub-agent that a topic should be built. But for general requests like 'The agent should be able to [...]' then you shouldn't provide instructions to the sub-agent on how to implement that, but just give them the context and let them figure out the best way to do it. +## Agent types: classic vs modern + +Copilot Studio has two agent types. The plugin auto-detects which type is in the workspace and blocks incompatible skills: + +- **Classic (Generative Orchestration)** agents use topics, action nodes, triggers, Power Fx, and adaptive cards. Most existing skills target this type. +- **Modern** agents use instructions, inline skills, declarative tools, and markdown. They have `template: cliagent-1.0.0` in `settings.mcs.yml`. A different set of skills targets this type. + +The Author agent detects the type automatically and uses the correct skills. You don't need to worry about this — just delegate to the Author and it will handle it. + ## Sub-agents available for Copilot Studio requests The agents you have at your disposal to handle Copilot Studio requests include, but are not limited to: - Advisor Agent: this is the advisory agent for design guidance, agent review, and troubleshooting. It recommends proven design patterns before authoring begins, reviews existing agent YAML against patterns and known pitfalls, and troubleshoots validation errors and unexpected behavior. Use this agent when the user asks for design recommendations ("how should I build…"), wants their agent reviewed or audited, or reports something not working ("my topic isn't triggering", "the agent is hallucinating", "wrong topic fires", validation errors, unexpected behavior). The Advisor presents patterns as suggestions — the user decides what to adopt. You can also call the Advisor for troubleshooting when needed (e.g., the Author hits a validation error you can't resolve). diff --git a/scripts/manage-agent.bundle.js b/scripts/manage-agent.bundle.js index b217304..5a714d7 100644 --- a/scripts/manage-agent.bundle.js +++ b/scripts/manage-agent.bundle.js @@ -4523,8 +4523,7 @@ var require_msal_node = __commonJS({ refresh_on: atEntity.refreshOn, key_id: atEntity.keyId, token_type: atEntity.tokenType, - userAssertionHash: atEntity.userAssertionHash, - resource: atEntity.resource + userAssertionHash: atEntity.userAssertionHash }; }); return accessTokens; @@ -4799,8 +4798,6 @@ var require_msal_node = __commonJS({ var BROKER_CLIENT_ID = "brk_client_id"; var BROKER_REDIRECT_URI = "brk_redirect_uri"; var INSTANCE_AWARE = "instance_aware"; - var RESOURCE = "resource"; - var CLI_DATA = "clidata"; function getDefaultErrorMessage(code) { return `See https://aka.ms/msal.js.errors#${code} for details`; } @@ -4995,8 +4992,6 @@ var require_msal_node = __commonJS({ var methodNotImplemented = "method_not_implemented"; var nestedAppAuthBridgeDisabled = "nested_app_auth_bridge_disabled"; var platformBrokerError = "platform_broker_error"; - var resourceParameterRequired = "resource_parameter_required"; - var misplacedResourceParam = "misplaced_resource_parameter"; var ClientAuthErrorCodes = /* @__PURE__ */ Object.freeze({ __proto__: null, authTimeNotFound, @@ -5016,7 +5011,6 @@ var require_msal_node = __commonJS({ keyIdMissing, maxAgeTranspired, methodNotImplemented, - misplacedResourceParam, multipleMatchingAppMetadata, multipleMatchingTokens, nestedAppAuthBridgeDisabled, @@ -5030,7 +5024,6 @@ var require_msal_node = __commonJS({ openIdConfigError, platformBrokerError, requestCannotBeMade, - resourceParameterRequired, stateMismatch, stateNotFound, tokenClaimsCnfRequiredForSignedJwt, @@ -5259,17 +5252,14 @@ var require_msal_node = __commonJS({ function addSid(parameters, sid) { parameters.set(SID, sid); } - function addClaims(parameters, claims, clientCapabilities, skipBrokerClaims) { - const configClaims = skipBrokerClaims && parameters.has(BROKER_CLIENT_ID) ? void 0 : clientCapabilities; - if (!StringUtils.isEmptyObj(claims) || configClaims && configClaims.length > 0) { - const mergedClaims = addClientCapabilitiesToClaims(claims, configClaims); - try { - JSON.parse(mergedClaims); - } catch (e) { - throw createClientConfigurationError(invalidClaims); - } - parameters.set(CLAIMS, mergedClaims); + function addClaims(parameters, claims, clientCapabilities) { + const mergedClaims = addClientCapabilitiesToClaims(claims, clientCapabilities); + try { + JSON.parse(mergedClaims); + } catch (e) { + throw createClientConfigurationError(invalidClaims); } + parameters.set(CLAIMS, mergedClaims); } function addCorrelationId(parameters, correlationId) { parameters.set(CLIENT_REQUEST_ID, correlationId); @@ -5348,9 +5338,6 @@ var require_msal_node = __commonJS({ function addClientInfo(parameters) { parameters.set(CLIENT_INFO, "1"); } - function addCliData(parameters) { - parameters.set(CLI_DATA, "1"); - } function addInstanceAware(parameters) { if (!parameters.has(INSTANCE_AWARE)) { parameters.set(INSTANCE_AWARE, "true"); @@ -5420,11 +5407,6 @@ var require_msal_node = __commonJS({ parameters.set(BROKER_REDIRECT_URI, brokerRedirectUri); } } - function addResource(parameters, resource) { - if (resource) { - parameters.set(RESOURCE, resource); - } - } function stripLeadingHashOrQuery(responseString) { if (responseString.startsWith("#/")) { return responseString.substring(2); @@ -5709,7 +5691,7 @@ var require_msal_node = __commonJS({ } }; var name$1 = "@azure/msal-common"; - var version$1 = "16.5.1"; + var version$1 = "16.2.0"; var AzureCloudInstance = { // AzureCloudInstance is not specified. None: "none", @@ -5737,8 +5719,7 @@ var require_msal_node = __commonJS({ name: name2, username: preferred_username || upn || "", loginHint: login_hint, - isHomeTenant: tenantIdMatchesHomeTenant(tenantId2, homeAccountId), - upn + isHomeTenant: tenantIdMatchesHomeTenant(tenantId2, homeAccountId) }; } else { return { @@ -6237,10 +6218,6 @@ var require_msal_node = __commonJS({ * Gets first tenanted AccountInfo object found based on provided filters */ getAccountInfoFilteredBy(accountFilter, correlationId) { - if (Object.keys(accountFilter).length === 0 || Object.values(accountFilter).every((value) => value === null || value === void 0 || value === "")) { - this.commonLogger.warning("getAccountInfoFilteredBy: Account filter is empty or invalid, returning null", correlationId); - return null; - } const allAccounts = this.getAllAccounts(accountFilter, correlationId); if (allAccounts.length > 1) { const sortedAccounts = allAccounts.sort((account) => { @@ -6329,15 +6306,6 @@ var require_msal_node = __commonJS({ if (tenantProfileFilter.isHomeTenant !== void 0 && !(tenantProfile.isHomeTenant === tenantProfileFilter.isHomeTenant)) { return false; } - if (!!tenantProfileFilter.username && !(this.matchUsername(tenantProfile.username, tenantProfileFilter.username) || !this.matchUsername(tenantProfile.upn, tenantProfileFilter.username))) { - return false; - } - if (!!tenantProfileFilter.loginHint && !this.matchLoginHintWithTenantProfile(tenantProfile, tenantProfileFilter.loginHint)) { - return false; - } - if (!!tenantProfileFilter.upn && !(tenantProfile.upn === tenantProfileFilter.upn)) { - return false; - } return true; } idTokenClaimsMatchTenantProfileFilter(idTokenClaims, tenantProfileFilter) { @@ -6348,7 +6316,7 @@ var require_msal_node = __commonJS({ if (!!tenantProfileFilter.loginHint && !this.matchLoginHintFromTokenClaims(idTokenClaims, tenantProfileFilter.loginHint)) { return false; } - if (!!tenantProfileFilter.username && !this.matchUsername(idTokenClaims.preferred_username, tenantProfileFilter.username) && !this.matchUsername(idTokenClaims.upn, tenantProfileFilter.username)) { + if (!!tenantProfileFilter.username && !this.matchUsername(idTokenClaims.preferred_username, tenantProfileFilter.username)) { return false; } if (!!tenantProfileFilter.name && !this.matchName(idTokenClaims, tenantProfileFilter.name)) { @@ -6440,6 +6408,9 @@ var require_msal_node = __commonJS({ if (!!accountFilter.homeAccountId && !this.matchHomeAccountId(entity, accountFilter.homeAccountId)) { return; } + if (!!accountFilter.username && !this.matchUsername(entity.username, accountFilter.username)) { + return; + } if (!!accountFilter.environment && !this.matchEnvironment(entity, accountFilter.environment, correlationId)) { return; } @@ -6454,10 +6425,7 @@ var require_msal_node = __commonJS({ } const tenantProfileFilter = { localAccountId: accountFilter?.localAccountId, - name: accountFilter?.name, - username: accountFilter?.username, - loginHint: accountFilter?.loginHint, - upn: accountFilter?.upn + name: accountFilter?.name }; const matchingTenantProfiles = entity.tenantProfiles?.filter((tenantProfile) => { return this.tenantProfileMatchesFilter(tenantProfile, tenantProfileFilter); @@ -6676,10 +6644,10 @@ var require_msal_node = __commonJS({ const numHomeIdTokens = homeIdTokenMap.size; if (numHomeIdTokens < 1) { this.commonLogger.info("CacheManager:getIdToken - Multiple ID tokens found for account but none match account entity tenant id, returning first result", correlationId); - return idTokenMap.values().next().value ?? null; + return idTokenMap.values().next().value; } else if (numHomeIdTokens === 1) { this.commonLogger.info("CacheManager:getIdToken - Multiple ID tokens found for account, defaulting to home tenant profile", correlationId); - return homeIdTokenMap.values().next().value ?? null; + return homeIdTokenMap.values().next().value; } else { tokensToBeRemoved = homeIdTokenMap; } @@ -6692,7 +6660,7 @@ var require_msal_node = __commonJS({ return null; } this.commonLogger.info("CacheManager:getIdToken - Returning ID token", correlationId); - return idTokenMap.values().next().value ?? null; + return idTokenMap.values().next().value; } /** * Gets all idTokens matching the given filter @@ -6966,15 +6934,6 @@ var require_msal_node = __commonJS({ matchUsername(cachedUsername, filterUsername) { return !!(cachedUsername && typeof cachedUsername === "string" && filterUsername?.toLowerCase() === cachedUsername.toLowerCase()); } - /** - * helper to match loginhints - * @param entity - * @param loginHint - * @returns - */ - matchLoginHintWithTenantProfile(tenantProfile, loginHintFilter) { - return tenantProfile.loginHint === loginHintFilter || tenantProfile.username === loginHintFilter || tenantProfile.upn === loginHintFilter; - } /** * helper to match assertion * @param value @@ -7061,9 +7020,6 @@ var require_msal_node = __commonJS({ if (tokenClaims.upn === loginHint) { return true; } - if (tokenClaims.emails && tokenClaims.emails.includes(loginHint)) { - return true; - } return false; } /** @@ -7328,31 +7284,104 @@ var require_msal_node = __commonJS({ clientCapabilities: [], azureCloudOptions: DEFAULT_AZURE_CLOUD_OPTIONS, instanceAware: false, - isMcp: false, ...authOptions }; } function isOidcProtocolMode(config) { return config.authOptions.authority.options.protocolMode === ProtocolMode.OIDC; } - var TokenCacheContext = class { - constructor(tokenCache, hasChanged) { - this.cache = tokenCache; - this.hasChanged = hasChanged; - } - /** - * boolean which indicates the changes in cache - */ - get cacheHasChanged() { - return this.hasChanged; + var ServerError = class _ServerError extends AuthError { + constructor(errorCode, errorMessage, subError, errorNo, status) { + super(errorCode, errorMessage, subError); + this.name = "ServerError"; + this.errorNo = errorNo; + this.status = status; + Object.setPrototypeOf(this, _ServerError.prototype); } - /** - * function to retrieve the token cache - */ - get tokenCache() { - return this.cache; + }; + var noTokensFound = "no_tokens_found"; + var nativeAccountUnavailable = "native_account_unavailable"; + var refreshTokenExpired = "refresh_token_expired"; + var uxNotAllowed = "ux_not_allowed"; + var interactionRequired = "interaction_required"; + var consentRequired = "consent_required"; + var loginRequired = "login_required"; + var badToken = "bad_token"; + var interruptedUser = "interrupted_user"; + var InteractionRequiredAuthErrorCodes = /* @__PURE__ */ Object.freeze({ + __proto__: null, + badToken, + consentRequired, + interactionRequired, + interruptedUser, + loginRequired, + nativeAccountUnavailable, + noTokensFound, + refreshTokenExpired, + uxNotAllowed + }); + var InteractionRequiredServerErrorMessage = [ + interactionRequired, + consentRequired, + loginRequired, + badToken, + uxNotAllowed, + interruptedUser + ]; + var InteractionRequiredAuthSubErrorMessage = [ + "message_only", + "additional_action", + "basic_action", + "user_password_expired", + "consent_required", + "bad_token", + "ux_not_allowed", + "interrupted_user" + ]; + var InteractionRequiredAuthError = class _InteractionRequiredAuthError extends AuthError { + constructor(errorCode, errorMessage, subError, timestamp, traceId, correlationId, claims, errorNo) { + super(errorCode, errorMessage, subError); + Object.setPrototypeOf(this, _InteractionRequiredAuthError.prototype); + this.timestamp = timestamp || ""; + this.traceId = traceId || ""; + this.correlationId = correlationId || ""; + this.claims = claims || ""; + this.name = "InteractionRequiredAuthError"; + this.errorNo = errorNo; } }; + function isInteractionRequiredError(errorCode, errorString, subError) { + const isInteractionRequiredErrorCode = !!errorCode && InteractionRequiredServerErrorMessage.indexOf(errorCode) > -1; + const isInteractionRequiredSubError = !!subError && InteractionRequiredAuthSubErrorMessage.indexOf(subError) > -1; + const isInteractionRequiredErrorDesc = !!errorString && InteractionRequiredServerErrorMessage.some((irErrorCode) => { + return errorString.indexOf(irErrorCode) > -1; + }); + return isInteractionRequiredErrorCode || isInteractionRequiredErrorDesc || isInteractionRequiredSubError; + } + function createInteractionRequiredAuthError(errorCode, errorMessage) { + return new InteractionRequiredAuthError(errorCode, errorMessage); + } + function parseRequestState(base64Decode, state) { + if (!base64Decode) { + throw createClientAuthError(noCryptoObject); + } + if (!state) { + throw createClientAuthError(invalidState); + } + try { + const splitState = state.split(RESOURCE_DELIM); + const libraryState = splitState[0]; + const userState = splitState.length > 1 ? splitState.slice(1).join(RESOURCE_DELIM) : ""; + const libraryStateString = base64Decode(libraryState); + const libraryStateObj = JSON.parse(libraryStateString); + return { + userRequestState: userState || "", + libraryState: libraryStateObj + }; + } catch (e) { + throw createClientAuthError(invalidState); + } + } function nowSeconds() { return Math.round((/* @__PURE__ */ new Date()).getTime() / 1e3); } @@ -7374,51 +7403,215 @@ var require_msal_node = __commonJS({ function delay(t, value) { return new Promise((resolve) => setTimeout(() => resolve(value), t)); } - function createIdTokenEntity(homeAccountId, environment, idToken, clientId, tenantId) { - const idTokenEntity = { - credentialType: CredentialType.ID_TOKEN, - homeAccountId, - environment, - clientId, - secret: idToken, - realm: tenantId, - lastUpdatedAt: Date.now().toString() - // Set the last updated time to now + var NetworkClientSendPostRequestAsync = "networkClientSendPostRequestAsync"; + var RefreshTokenClientExecutePostToTokenEndpoint = "refreshTokenClientExecutePostToTokenEndpoint"; + var AuthorizationCodeClientExecutePostToTokenEndpoint = "authorizationCodeClientExecutePostToTokenEndpoint"; + var RefreshTokenClientExecuteTokenRequest = "refreshTokenClientExecuteTokenRequest"; + var RefreshTokenClientAcquireToken = "refreshTokenClientAcquireToken"; + var RefreshTokenClientAcquireTokenWithCachedRefreshToken = "refreshTokenClientAcquireTokenWithCachedRefreshToken"; + var RefreshTokenClientCreateTokenRequestBody = "refreshTokenClientCreateTokenRequestBody"; + var SilentFlowClientGenerateResultFromCacheRecord = "silentFlowClientGenerateResultFromCacheRecord"; + var AuthClientExecuteTokenRequest = "authClientExecuteTokenRequest"; + var AuthClientCreateTokenRequestBody = "authClientCreateTokenRequestBody"; + var UpdateTokenEndpointAuthority = "updateTokenEndpointAuthority"; + var PopTokenGenerateCnf = "popTokenGenerateCnf"; + var HandleServerTokenResponse = "handleServerTokenResponse"; + var AuthorityResolveEndpointsAsync = "authorityResolveEndpointsAsync"; + var AuthorityGetCloudDiscoveryMetadataFromNetwork = "authorityGetCloudDiscoveryMetadataFromNetwork"; + var AuthorityUpdateCloudDiscoveryMetadata = "authorityUpdateCloudDiscoveryMetadata"; + var AuthorityGetEndpointMetadataFromNetwork = "authorityGetEndpointMetadataFromNetwork"; + var AuthorityUpdateEndpointMetadata = "authorityUpdateEndpointMetadata"; + var AuthorityUpdateMetadataWithRegionalInformation = "authorityUpdateMetadataWithRegionalInformation"; + var RegionDiscoveryDetectRegion = "regionDiscoveryDetectRegion"; + var RegionDiscoveryGetRegionFromIMDS = "regionDiscoveryGetRegionFromIMDS"; + var RegionDiscoveryGetCurrentVersion = "regionDiscoveryGetCurrentVersion"; + var CacheManagerGetRefreshToken = "cacheManagerGetRefreshToken"; + var invoke = (callback, eventName, logger, telemetryClient, correlationId) => { + return (...args) => { + logger.trace(`Executing function '${eventName}'`, correlationId); + const inProgressEvent = telemetryClient.startMeasurement(eventName, correlationId); + if (correlationId) { + telemetryClient.incrementFields({ [`ext.${eventName}CallCount`]: 1 }, correlationId); + } + try { + const result = callback(...args); + inProgressEvent.end({ + success: true + }); + logger.trace(`Returning result from '${eventName}'`, correlationId); + return result; + } catch (e) { + logger.trace(`Error occurred in '${eventName}'`, correlationId); + try { + logger.trace(JSON.stringify(e), correlationId); + } catch (e2) { + logger.trace("Unable to print error message.", correlationId); + } + inProgressEvent.end({ + success: false + }, e); + throw e; + } }; - return idTokenEntity; - } - function createAccessTokenEntity(homeAccountId, environment, accessToken, clientId, tenantId, scopes, expiresOn, extExpiresOn, base64Decode, refreshOn, tokenType, userAssertionHash, keyId) { - const atEntity = { - homeAccountId, - credentialType: CredentialType.ACCESS_TOKEN, - secret: accessToken, - cachedAt: nowSeconds().toString(), - expiresOn: expiresOn.toString(), - extendedExpiresOn: extExpiresOn.toString(), - environment, - clientId, - realm: tenantId, - target: scopes, - tokenType: tokenType || AuthenticationScheme.BEARER, - lastUpdatedAt: Date.now().toString() - // Set the last updated time to now + }; + var invokeAsync = (callback, eventName, logger, telemetryClient, correlationId) => { + return (...args) => { + logger.trace(`Executing function '${eventName}'`, correlationId); + const inProgressEvent = telemetryClient.startMeasurement(eventName, correlationId); + if (correlationId) { + telemetryClient.incrementFields({ [`ext.${eventName}CallCount`]: 1 }, correlationId); + } + return callback(...args).then((response) => { + logger.trace(`Returning result from '${eventName}'`, correlationId); + inProgressEvent.end({ + success: true + }); + return response; + }).catch((e) => { + logger.trace(`Error occurred in '${eventName}'`, correlationId); + try { + logger.trace(JSON.stringify(e), correlationId); + } catch (e2) { + logger.trace("Unable to print error message.", correlationId); + } + inProgressEvent.end({ + success: false + }, e); + throw e; + }); }; - if (userAssertionHash) { - atEntity.userAssertionHash = userAssertionHash; - } - if (refreshOn) { - atEntity.refreshOn = refreshOn.toString(); + }; + var KeyLocation = { + SW: "sw" + }; + var PopTokenGenerator = class { + constructor(cryptoUtils, performanceClient) { + this.cryptoUtils = cryptoUtils; + this.performanceClient = performanceClient; } - if (atEntity.tokenType?.toLowerCase() !== AuthenticationScheme.BEARER.toLowerCase()) { - atEntity.credentialType = CredentialType.ACCESS_TOKEN_WITH_AUTH_SCHEME; - switch (atEntity.tokenType) { - case AuthenticationScheme.POP: - const tokenClaims = extractTokenClaims(accessToken, base64Decode); - if (!tokenClaims?.cnf?.kid) { - throw createClientAuthError(tokenClaimsCnfRequiredForSignedJwt); - } - atEntity.keyId = tokenClaims.cnf.kid; - break; + /** + * Generates the req_cnf validated at the RP in the POP protocol for SHR parameters + * and returns an object containing the keyid, the full req_cnf string and the req_cnf string hash + * @param request + * @returns + */ + async generateCnf(request, logger) { + const reqCnf = await invokeAsync(this.generateKid.bind(this), PopTokenGenerateCnf, logger, this.performanceClient, request.correlationId)(request); + const reqCnfString = this.cryptoUtils.base64UrlEncode(JSON.stringify(reqCnf)); + return { + kid: reqCnf.kid, + reqCnfString + }; + } + /** + * Generates key_id for a SHR token request + * @param request + * @returns + */ + async generateKid(request) { + const kidThumbprint = await this.cryptoUtils.getPublicKeyThumbprint(request); + return { + kid: kidThumbprint, + xms_ksl: KeyLocation.SW + }; + } + /** + * Signs the POP access_token with the local generated key-pair + * @param accessToken + * @param request + * @returns + */ + async signPopToken(accessToken, keyId, request) { + return this.signPayload(accessToken, keyId, request); + } + /** + * Utility function to generate the signed JWT for an access_token + * @param payload + * @param kid + * @param request + * @param claims + * @returns + */ + async signPayload(payload, keyId, request, claims) { + const { resourceRequestMethod, resourceRequestUri, shrClaims, shrNonce, shrOptions } = request; + const resourceUrlString = resourceRequestUri ? new UrlString(resourceRequestUri) : void 0; + const resourceUrlComponents = resourceUrlString?.getUrlComponents(); + return this.cryptoUtils.signJwt({ + at: payload, + ts: nowSeconds(), + m: resourceRequestMethod?.toUpperCase(), + u: resourceUrlComponents?.HostNameAndPort, + nonce: shrNonce || this.cryptoUtils.createNewGuid(), + p: resourceUrlComponents?.AbsolutePath, + q: resourceUrlComponents?.QueryString ? [[], resourceUrlComponents.QueryString] : void 0, + client_claims: shrClaims || void 0, + ...claims + }, keyId, shrOptions, request.correlationId); + } + }; + var TokenCacheContext = class { + constructor(tokenCache, hasChanged) { + this.cache = tokenCache; + this.hasChanged = hasChanged; + } + /** + * boolean which indicates the changes in cache + */ + get cacheHasChanged() { + return this.hasChanged; + } + /** + * function to retrieve the token cache + */ + get tokenCache() { + return this.cache; + } + }; + function createIdTokenEntity(homeAccountId, environment, idToken, clientId, tenantId) { + const idTokenEntity = { + credentialType: CredentialType.ID_TOKEN, + homeAccountId, + environment, + clientId, + secret: idToken, + realm: tenantId, + lastUpdatedAt: Date.now().toString() + // Set the last updated time to now + }; + return idTokenEntity; + } + function createAccessTokenEntity(homeAccountId, environment, accessToken, clientId, tenantId, scopes, expiresOn, extExpiresOn, base64Decode, refreshOn, tokenType, userAssertionHash, keyId) { + const atEntity = { + homeAccountId, + credentialType: CredentialType.ACCESS_TOKEN, + secret: accessToken, + cachedAt: nowSeconds().toString(), + expiresOn: expiresOn.toString(), + extendedExpiresOn: extExpiresOn.toString(), + environment, + clientId, + realm: tenantId, + target: scopes, + tokenType: tokenType || AuthenticationScheme.BEARER, + lastUpdatedAt: Date.now().toString() + // Set the last updated time to now + }; + if (userAssertionHash) { + atEntity.userAssertionHash = userAssertionHash; + } + if (refreshOn) { + atEntity.refreshOn = refreshOn.toString(); + } + if (atEntity.tokenType?.toLowerCase() !== AuthenticationScheme.BEARER.toLowerCase()) { + atEntity.credentialType = CredentialType.ACCESS_TOKEN_WITH_AUTH_SCHEME; + switch (atEntity.tokenType) { + case AuthenticationScheme.POP: + const tokenClaims = extractTokenClaims(accessToken, base64Decode); + if (!tokenClaims?.cnf?.kid) { + throw createClientAuthError(tokenClaimsCnfRequiredForSignedJwt); + } + atEntity.keyId = tokenClaims.cnf.kid; + break; case AuthenticationScheme.SSH: atEntity.keyId = keyId; } @@ -7525,284 +7718,46 @@ var require_msal_node = __commonJS({ function isAuthorityMetadataExpired(metadata) { return metadata.expiresAt <= nowSeconds(); } - var NetworkClientSendPostRequestAsync = "networkClientSendPostRequestAsync"; - var RefreshTokenClientExecutePostToTokenEndpoint = "refreshTokenClientExecutePostToTokenEndpoint"; - var AuthorizationCodeClientExecutePostToTokenEndpoint = "authorizationCodeClientExecutePostToTokenEndpoint"; - var RefreshTokenClientExecuteTokenRequest = "refreshTokenClientExecuteTokenRequest"; - var RefreshTokenClientAcquireToken = "refreshTokenClientAcquireToken"; - var RefreshTokenClientAcquireTokenWithCachedRefreshToken = "refreshTokenClientAcquireTokenWithCachedRefreshToken"; - var RefreshTokenClientCreateTokenRequestBody = "refreshTokenClientCreateTokenRequestBody"; - var SilentFlowClientGenerateResultFromCacheRecord = "silentFlowClientGenerateResultFromCacheRecord"; - var AuthClientExecuteTokenRequest = "authClientExecuteTokenRequest"; - var AuthClientCreateTokenRequestBody = "authClientCreateTokenRequestBody"; - var UpdateTokenEndpointAuthority = "updateTokenEndpointAuthority"; - var PopTokenGenerateCnf = "popTokenGenerateCnf"; - var HandleServerTokenResponse = "handleServerTokenResponse"; - var AuthorityResolveEndpointsAsync = "authorityResolveEndpointsAsync"; - var AuthorityGetCloudDiscoveryMetadataFromNetwork = "authorityGetCloudDiscoveryMetadataFromNetwork"; - var AuthorityUpdateCloudDiscoveryMetadata = "authorityUpdateCloudDiscoveryMetadata"; - var AuthorityGetEndpointMetadataFromNetwork = "authorityGetEndpointMetadataFromNetwork"; - var AuthorityUpdateEndpointMetadata = "authorityUpdateEndpointMetadata"; - var AuthorityUpdateMetadataWithRegionalInformation = "authorityUpdateMetadataWithRegionalInformation"; - var RegionDiscoveryDetectRegion = "regionDiscoveryDetectRegion"; - var RegionDiscoveryGetRegionFromIMDS = "regionDiscoveryGetRegionFromIMDS"; - var RegionDiscoveryGetCurrentVersion = "regionDiscoveryGetCurrentVersion"; - var CacheManagerGetRefreshToken = "cacheManagerGetRefreshToken"; - var invoke = (callback, eventName, logger, telemetryClient, correlationId) => { - return (...args) => { - logger.trace(`Executing function '${eventName}'`, correlationId); - const inProgressEvent = telemetryClient.startMeasurement(eventName, correlationId); - if (correlationId) { - telemetryClient.incrementFields({ [`ext.${eventName}CallCount`]: 1 }, correlationId); - } - try { - const result = callback(...args); - inProgressEvent.end({ - success: true - }); - logger.trace(`Returning result from '${eventName}'`, correlationId); - return result; - } catch (e) { - logger.trace(`Error occurred in '${eventName}'`, correlationId); - try { - logger.trace(JSON.stringify(e), correlationId); - } catch (e2) { - logger.trace("Unable to print error message.", correlationId); - } - inProgressEvent.end({ - success: false - }, e); - throw e; - } - }; - }; - var invokeAsync = (callback, eventName, logger, telemetryClient, correlationId) => { - return (...args) => { - logger.trace(`Executing function '${eventName}'`, correlationId); - const inProgressEvent = telemetryClient.startMeasurement(eventName, correlationId); - if (correlationId) { - telemetryClient.incrementFields({ [`ext.${eventName}CallCount`]: 1 }, correlationId); - } - return callback(...args).then((response) => { - logger.trace(`Returning result from '${eventName}'`, correlationId); - inProgressEvent.end({ - success: true - }); - return response; - }).catch((e) => { - logger.trace(`Error occurred in '${eventName}'`, correlationId); - try { - logger.trace(JSON.stringify(e), correlationId); - } catch (e2) { - logger.trace("Unable to print error message.", correlationId); - } - inProgressEvent.end({ - success: false - }, e); - throw e; - }); - }; - }; - var KeyLocation = { - SW: "sw" - }; - var PopTokenGenerator = class { - constructor(cryptoUtils, performanceClient) { - this.cryptoUtils = cryptoUtils; + var ResponseHandler = class _ResponseHandler { + constructor(clientId, cacheStorage, cryptoObj, logger, performanceClient, serializableCache, persistencePlugin) { + this.clientId = clientId; + this.cacheStorage = cacheStorage; + this.cryptoObj = cryptoObj; + this.logger = logger; this.performanceClient = performanceClient; + this.serializableCache = serializableCache; + this.persistencePlugin = persistencePlugin; } /** - * Generates the req_cnf validated at the RP in the POP protocol for SHR parameters - * and returns an object containing the keyid, the full req_cnf string and the req_cnf string hash - * @param request - * @returns + * Function which validates server authorization token response. + * @param serverResponse + * @param correlationId + * @param refreshAccessToken */ - async generateCnf(request, logger) { - const reqCnf = await invokeAsync(this.generateKid.bind(this), PopTokenGenerateCnf, logger, this.performanceClient, request.correlationId)(request); - const reqCnfString = this.cryptoUtils.base64UrlEncode(JSON.stringify(reqCnf)); - return { - kid: reqCnf.kid, - reqCnfString - }; + validateTokenResponse(serverResponse, correlationId, refreshAccessToken) { + if (serverResponse.error || serverResponse.error_description || serverResponse.suberror) { + const errString = `Error(s): ${serverResponse.error_codes || NOT_AVAILABLE} - Timestamp: ${serverResponse.timestamp || NOT_AVAILABLE} - Description: ${serverResponse.error_description || NOT_AVAILABLE} - Correlation ID: ${serverResponse.correlation_id || NOT_AVAILABLE} - Trace ID: ${serverResponse.trace_id || NOT_AVAILABLE}`; + const serverErrorNo = serverResponse.error_codes?.length ? serverResponse.error_codes[0] : void 0; + const serverError = new ServerError(serverResponse.error, errString, serverResponse.suberror, serverErrorNo, serverResponse.status); + if (refreshAccessToken && serverResponse.status && serverResponse.status >= HTTP_SERVER_ERROR_RANGE_START && serverResponse.status <= HTTP_SERVER_ERROR_RANGE_END) { + this.logger.warning(`executeTokenRequest:validateTokenResponse - AAD is currently unavailable and the access token is unable to be refreshed. +${serverError}`, correlationId); + return; + } else if (refreshAccessToken && serverResponse.status && serverResponse.status >= HTTP_CLIENT_ERROR_RANGE_START && serverResponse.status <= HTTP_CLIENT_ERROR_RANGE_END) { + this.logger.warning(`executeTokenRequest:validateTokenResponse - AAD is currently available but is unable to refresh the access token. +${serverError}`, correlationId); + return; + } + if (isInteractionRequiredError(serverResponse.error, serverResponse.error_description, serverResponse.suberror)) { + throw new InteractionRequiredAuthError(serverResponse.error, serverResponse.error_description, serverResponse.suberror, serverResponse.timestamp || "", serverResponse.trace_id || "", serverResponse.correlation_id || "", serverResponse.claims || "", serverErrorNo); + } + throw serverError; + } } /** - * Generates key_id for a SHR token request - * @param request - * @returns - */ - async generateKid(request) { - const kidThumbprint = await this.cryptoUtils.getPublicKeyThumbprint(request); - return { - kid: kidThumbprint, - xms_ksl: KeyLocation.SW - }; - } - /** - * Signs the POP access_token with the local generated key-pair - * @param accessToken - * @param request - * @returns - */ - async signPopToken(accessToken, keyId, request) { - return this.signPayload(accessToken, keyId, request); - } - /** - * Utility function to generate the signed JWT for an access_token - * @param payload - * @param kid - * @param request - * @param claims - * @returns - */ - async signPayload(payload, keyId, request, claims) { - const { resourceRequestMethod, resourceRequestUri, shrClaims, shrNonce, shrOptions } = request; - const resourceUrlString = resourceRequestUri ? new UrlString(resourceRequestUri) : void 0; - const resourceUrlComponents = resourceUrlString?.getUrlComponents(); - return this.cryptoUtils.signJwt({ - at: payload, - ts: nowSeconds(), - m: resourceRequestMethod?.toUpperCase(), - u: resourceUrlComponents?.HostNameAndPort, - nonce: shrNonce || this.cryptoUtils.createNewGuid(), - p: resourceUrlComponents?.AbsolutePath, - q: resourceUrlComponents?.QueryString ? [[], resourceUrlComponents.QueryString] : void 0, - client_claims: shrClaims || void 0, - ...claims - }, keyId, shrOptions, request.correlationId); - } - }; - var noTokensFound = "no_tokens_found"; - var nativeAccountUnavailable = "native_account_unavailable"; - var refreshTokenExpired = "refresh_token_expired"; - var uxNotAllowed = "ux_not_allowed"; - var interactionRequired = "interaction_required"; - var consentRequired = "consent_required"; - var loginRequired = "login_required"; - var badToken = "bad_token"; - var interruptedUser = "interrupted_user"; - var InteractionRequiredAuthErrorCodes = /* @__PURE__ */ Object.freeze({ - __proto__: null, - badToken, - consentRequired, - interactionRequired, - interruptedUser, - loginRequired, - nativeAccountUnavailable, - noTokensFound, - refreshTokenExpired, - uxNotAllowed - }); - var InteractionRequiredServerErrorMessage = [ - interactionRequired, - consentRequired, - loginRequired, - badToken, - uxNotAllowed, - interruptedUser - ]; - var InteractionRequiredAuthSubErrorMessage = [ - "message_only", - "additional_action", - "basic_action", - "user_password_expired", - "consent_required", - "bad_token", - "ux_not_allowed", - "interrupted_user" - ]; - var InteractionRequiredAuthError = class _InteractionRequiredAuthError extends AuthError { - constructor(errorCode, errorMessage, subError, timestamp, traceId, correlationId, claims, errorNo) { - super(errorCode, errorMessage, subError); - Object.setPrototypeOf(this, _InteractionRequiredAuthError.prototype); - this.timestamp = timestamp || ""; - this.traceId = traceId || ""; - this.correlationId = correlationId || ""; - this.claims = claims || ""; - this.name = "InteractionRequiredAuthError"; - this.errorNo = errorNo; - } - }; - function isInteractionRequiredError(errorCode, errorString, subError) { - const isInteractionRequiredErrorCode = !!errorCode && InteractionRequiredServerErrorMessage.indexOf(errorCode) > -1; - const isInteractionRequiredSubError = !!subError && InteractionRequiredAuthSubErrorMessage.indexOf(subError) > -1; - const isInteractionRequiredErrorDesc = !!errorString && InteractionRequiredServerErrorMessage.some((irErrorCode) => { - return errorString.indexOf(irErrorCode) > -1; - }); - return isInteractionRequiredErrorCode || isInteractionRequiredErrorDesc || isInteractionRequiredSubError; - } - function createInteractionRequiredAuthError(errorCode, errorMessage) { - return new InteractionRequiredAuthError(errorCode, errorMessage); - } - var ServerError = class _ServerError extends AuthError { - constructor(errorCode, errorMessage, subError, errorNo, status) { - super(errorCode, errorMessage, subError); - this.name = "ServerError"; - this.errorNo = errorNo; - this.status = status; - Object.setPrototypeOf(this, _ServerError.prototype); - } - }; - function parseRequestState(base64Decode, state) { - if (!base64Decode) { - throw createClientAuthError(noCryptoObject); - } - if (!state) { - throw createClientAuthError(invalidState); - } - try { - const splitState = state.split(RESOURCE_DELIM); - const libraryState = splitState[0]; - const userState = splitState.length > 1 ? splitState.slice(1).join(RESOURCE_DELIM) : ""; - const libraryStateString = base64Decode(libraryState); - const libraryStateObj = JSON.parse(libraryStateString); - return { - userRequestState: userState || "", - libraryState: libraryStateObj - }; - } catch (e) { - throw createClientAuthError(invalidState); - } - } - var ResponseHandler = class _ResponseHandler { - constructor(clientId, cacheStorage, cryptoObj, logger, performanceClient, serializableCache, persistencePlugin) { - this.clientId = clientId; - this.cacheStorage = cacheStorage; - this.cryptoObj = cryptoObj; - this.logger = logger; - this.performanceClient = performanceClient; - this.serializableCache = serializableCache; - this.persistencePlugin = persistencePlugin; - } - /** - * Function which validates server authorization token response. - * @param serverResponse - * @param correlationId - * @param refreshAccessToken - */ - validateTokenResponse(serverResponse, correlationId, refreshAccessToken) { - if (serverResponse.error || serverResponse.error_description || serverResponse.suberror) { - const errString = `Error(s): ${serverResponse.error_codes || NOT_AVAILABLE} - Timestamp: ${serverResponse.timestamp || NOT_AVAILABLE} - Description: ${serverResponse.error_description || NOT_AVAILABLE} - Correlation ID: ${serverResponse.correlation_id || NOT_AVAILABLE} - Trace ID: ${serverResponse.trace_id || NOT_AVAILABLE}`; - const serverErrorNo = serverResponse.error_codes?.length ? serverResponse.error_codes[0] : void 0; - const serverError = new ServerError(serverResponse.error, errString, serverResponse.suberror, serverErrorNo, serverResponse.status); - if (refreshAccessToken && serverResponse.status && serverResponse.status >= HTTP_SERVER_ERROR_RANGE_START && serverResponse.status <= HTTP_SERVER_ERROR_RANGE_END) { - this.logger.warning(`executeTokenRequest:validateTokenResponse - AAD is currently unavailable and the access token is unable to be refreshed. -${serverError}`, correlationId); - return; - } else if (refreshAccessToken && serverResponse.status && serverResponse.status >= HTTP_CLIENT_ERROR_RANGE_START && serverResponse.status <= HTTP_CLIENT_ERROR_RANGE_END) { - this.logger.warning(`executeTokenRequest:validateTokenResponse - AAD is currently available but is unable to refresh the access token. -${serverError}`, correlationId); - return; - } - if (isInteractionRequiredError(serverResponse.error, serverResponse.error_description, serverResponse.suberror)) { - throw new InteractionRequiredAuthError(serverResponse.error, serverResponse.error_description, serverResponse.suberror, serverResponse.timestamp || "", serverResponse.trace_id || "", serverResponse.correlation_id || "", serverResponse.claims || "", serverErrorNo); - } - throw serverError; - } - } - /** - * Returns a constructed token response based on given string. Also manages the cache updates and cleanups. - * @param serverTokenResponse - * @param authority + * Returns a constructed token response based on given string. Also manages the cache updates and cleanups. + * @param serverTokenResponse + * @param authority */ async handleServerTokenResponse(serverTokenResponse, authority, reqTimestamp, request, apiId, authCodePayload, userAssertionHash, handlingRefreshTokenResponse, forceCacheRefreshTokenResponse, serverRequestId) { let idTokenClaims; @@ -7886,8 +7841,7 @@ ${serverError}`, correlationId); authCodePayload, void 0, // nativeAccountId - this.logger, - this.performanceClient + this.logger ); } let cachedAccessToken = null; @@ -7900,10 +7854,6 @@ ${serverError}`, correlationId); const extendedTokenExpirationSeconds = tokenExpirationSeconds + extExpiresIn; const refreshOnSeconds = refreshIn && refreshIn > 0 ? reqTimestamp + refreshIn : void 0; cachedAccessToken = createAccessTokenEntity(this.homeAccountIdentifier, env, serverTokenResponse.access_token, this.clientId, claimsTenantId || authority.tenant || "", responseScopes.printScopes(), tokenExpirationSeconds, extendedTokenExpirationSeconds, this.cryptoObj.base64Decode, refreshOnSeconds, serverTokenResponse.token_type, userAssertionHash, serverTokenResponse.key_id); - const resource = request.resource || null; - if (resource) { - cachedAccessToken.resource = resource; - } } let cachedRefreshToken = null; if (serverTokenResponse.refresh_token) { @@ -8006,15 +7956,16 @@ ${serverError}`, correlationId); }; } }; - function buildAccountToCache(cacheStorage, authority, homeAccountId, base64Decode, correlationId, idTokenClaims, clientInfo, environment, claimsTenantId, authCodePayload, nativeAccountId, logger, performanceClient) { + function buildAccountToCache(cacheStorage, authority, homeAccountId, base64Decode, correlationId, idTokenClaims, clientInfo, environment, claimsTenantId, authCodePayload, nativeAccountId, logger) { logger?.verbose("setCachedAccount called", correlationId); - const accountEnvironment = environment || authority.getPreferredCache(); - const matchedAccounts = cacheStorage.getAccountsFilteredBy({ homeAccountId, environment: accountEnvironment }, correlationId); - performanceClient?.addFields({ cacheMatchedAccounts: matchedAccounts.length }, correlationId); - if (matchedAccounts.length > 1) { - logger?.warning("Multiple base accounts matched homeAccountId. Ignoring cached account and creating a new base account.", correlationId); + const accountKeys = cacheStorage.getAccountKeys(); + const baseAccountKey = accountKeys.find((accountKey) => { + return accountKey.startsWith(homeAccountId); + }); + let cachedAccount = null; + if (baseAccountKey) { + cachedAccount = cacheStorage.getAccount(baseAccountKey, correlationId); } - const cachedAccount = matchedAccounts.length === 1 ? matchedAccounts[0] : null; const baseAccount = cachedAccount || createAccountEntity({ homeAccountId, idTokenClaims, @@ -9108,7 +9059,6 @@ Error Description: '${typedError.message}'`, this.correlationId); addRedirectUri(parameters, request.redirectUri); } addScopes(parameters, request.scopes, true, this.oidcDefaultScopes); - addResource(parameters, request.resource); addAuthorizationCode(parameters, request.code); addLibraryInfo(parameters, this.config.libraryInfo); addApplicationTelemetry(parameters, this.config.telemetry.application); @@ -9146,6 +9096,9 @@ Error Description: '${typedError.message}'`, this.correlationId); throw createClientConfigurationError(missingSshJwk); } } + if (!StringUtils.isEmptyObj(request.claims) || this.config.authOptions.clientCapabilities && this.config.authOptions.clientCapabilities.length > 0) { + addClaims(parameters, request.claims, this.config.authOptions.clientCapabilities); + } let ccsCred = void 0; if (request.clientInfo) { try { @@ -9187,7 +9140,6 @@ Error Description: '${typedError.message}'`, this.correlationId); }); } instrumentBrokerParams(parameters, request.correlationId, this.performanceClient); - addClaims(parameters, request.claims, this.config.authOptions.clientCapabilities, request.skipBrokerClaims); return mapToQueryString(parameters); } /** @@ -9376,6 +9328,9 @@ Error Description: '${typedError.message}'`, this.correlationId); throw createClientConfigurationError(missingSshJwk); } } + if (!StringUtils.isEmptyObj(request.claims) || this.config.authOptions.clientCapabilities && this.config.authOptions.clientCapabilities.length > 0) { + addClaims(parameters, request.claims, this.config.authOptions.clientCapabilities); + } if (this.config.systemOptions.preventCorsPreflight && request.ccsCredential) { switch (request.ccsCredential.type) { case CcsCredentialType.HOME_ACCOUNT_ID: @@ -9400,7 +9355,6 @@ Error Description: '${typedError.message}'`, this.correlationId); }); } instrumentBrokerParams(parameters, request.correlationId, this.performanceClient); - addClaims(parameters, request.claims, this.config.authOptions.clientCapabilities, request.skipBrokerClaims); return mapToQueryString(parameters); } }; @@ -9437,11 +9391,6 @@ Error Description: '${typedError.message}'`, this.correlationId); } else if (wasClockTurnedBack(cachedAccessToken.cachedAt) || isTokenExpired(cachedAccessToken.expiresOn, this.config.systemOptions.tokenRenewalOffsetSeconds)) { this.setCacheOutcome(CacheOutcome.CACHED_ACCESS_TOKEN_EXPIRED, request.correlationId); throw createClientAuthError(tokenRefreshRequired); - } else if (request.resource) { - if (cachedAccessToken.resource !== request.resource) { - this.setCacheOutcome(CacheOutcome.NO_CACHED_ACCESS_TOKEN, request.correlationId); - throw createClientAuthError(tokenRefreshRequired); - } } else if (cachedAccessToken.refreshOn && isTokenExpired(cachedAccessToken.refreshOn, 0)) { lastCacheOutcome = CacheOutcome.PROACTIVELY_REFRESHED; } @@ -9499,12 +9448,10 @@ Error Description: '${typedError.message}'`, this.correlationId); ...request.extraScopesToConsent || [] ]; addScopes(parameters, requestScopes, true, authOptions.authority.options.OIDCOptions?.defaultScopes); - addResource(parameters, request.resource); addRedirectUri(parameters, request.redirectUri); addCorrelationId(parameters, correlationId); addResponseMode(parameters, request.responseMode); addClientInfo(parameters); - addCliData(parameters); if (request.prompt) { addPrompt(parameters, request.prompt); } @@ -9568,10 +9515,12 @@ Error Description: '${typedError.message}'`, this.correlationId); if (request.state) { addState(parameters, request.state); } + if (request.claims || authOptions.clientCapabilities && authOptions.clientCapabilities.length > 0) { + addClaims(parameters, request.claims, authOptions.clientCapabilities); + } if (request.embeddedClientId) { addBrokerParameters(parameters, authOptions.clientId, authOptions.redirectUri); } - addClaims(parameters, request.claims, authOptions.clientCapabilities, request.skipBrokerClaims); if (authOptions.instanceAware && (!request.extraQueryParameters || !Object.keys(request.extraQueryParameters).includes(INSTANCE_AWARE))) { addInstanceAware(parameters); } @@ -9587,23 +9536,6 @@ Error Description: '${typedError.message}'`, this.correlationId); function extractLoginHint(account) { return account.loginHint || account.idTokenClaims?.login_hint || null; } - function enforceResourceParameter(isMcp, request) { - if (!isMcp) { - return; - } - if (request.resource && (containsResourceParam(request.extraParameters) || containsResourceParam(request.extraQueryParameters))) { - throw createClientAuthError(misplacedResourceParam); - } - if (!request.resource) { - throw createClientAuthError(resourceParameterRequired); - } - } - function containsResourceParam(params) { - if (!params) { - return false; - } - return Object.prototype.hasOwnProperty.call(params, "resource"); - } var unexpectedError = "unexpected_error"; var postRequestFailed = "post_request_failed"; var AuthErrorCodes = /* @__PURE__ */ Object.freeze({ @@ -9923,7 +9855,6 @@ Error Description: '${typedError.message}'`, this.correlationId); keyId: serializedAT.key_id, tokenType: serializedAT.token_type, userAssertionHash: serializedAT.userAssertionHash, - resource: serializedAT.resource, lastUpdatedAt: Date.now().toString() }; atObjects[key] = accessToken; @@ -10410,8 +10341,7 @@ Error Description: '${typedError.message}'`, this.correlationId); azureCloudOptions: { azureCloudInstance: AzureCloudInstance.None, tenant: "" - }, - isMcp: false + } }; var DEFAULT_LOGGER_OPTIONS = { loggerCallback: () => { @@ -11434,7 +11364,7 @@ Error Description: '${typedError.message}'`, this.correlationId); } }; var name = "@azure/msal-node"; - var version2 = "5.1.4"; + var version2 = "5.0.6"; var BaseClient = class { constructor(configuration) { this.config = buildClientConfiguration(configuration); @@ -11817,8 +11747,7 @@ Error Description: '${typedError.message}'`, this.correlationId); clientId: this.config.auth.clientId, authority: discoveredAuthority, clientCapabilities: this.config.auth.clientCapabilities, - redirectUri, - isMcp: this.config.auth.isMcp + redirectUri }, loggerOptions: { logLevel: this.config.system.loggerOptions.logLevel, @@ -12207,7 +12136,6 @@ Error Description: '${typedError.message}'`, this.correlationId); */ async acquireTokenByDeviceCode(request) { this.logger.info("acquireTokenByDeviceCode called", request.correlationId || ""); - enforceResourceParameter(this.config.auth.isMcp, request); const validRequest = Object.assign(request, await this.initializeBaseRequest(request)); const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenByDeviceCode, validRequest.correlationId); try { @@ -12230,7 +12158,6 @@ Error Description: '${typedError.message}'`, this.correlationId); async acquireTokenInteractive(request) { const correlationId = request.correlationId || this.cryptoProvider.createNewGuid(); this.logger.trace("acquireTokenInteractive called", correlationId); - enforceResourceParameter(this.config.auth.isMcp, request); const { openBrowser, successTemplate, errorTemplate, windowHandle, loopbackClient: customLoopbackClient, ...remainingProperties } = request; if (this.nativeBrokerPlugin) { const brokerRequest = { @@ -12306,7 +12233,6 @@ Error Description: '${typedError.message}'`, this.correlationId); async acquireTokenSilent(request) { const correlationId = request.correlationId || this.cryptoProvider.createNewGuid(); this.logger.trace("acquireTokenSilent called", correlationId); - enforceResourceParameter(this.config.auth.isMcp, request); if (this.nativeBrokerPlugin) { const brokerRequest = { ...request, @@ -12333,22 +12259,6 @@ Error Description: '${typedError.message}'`, this.correlationId); } return super.acquireTokenSilent(request); } - /** - * Acquires a token by exchanging the authorization code received from the first step of OAuth 2.0 Authorization Code Flow. - * In MCP mode, a resource parameter is required on the request. - */ - async acquireTokenByCode(request, authCodePayLoad) { - enforceResourceParameter(this.config.auth.isMcp, request); - return super.acquireTokenByCode(request, authCodePayLoad); - } - /** - * Acquires a token by exchanging the refresh token provided for a new set of tokens. - * In MCP mode, a resource parameter is required on the request. - */ - async acquireTokenByRefreshToken(request) { - enforceResourceParameter(this.config.auth.isMcp, request); - return super.acquireTokenByRefreshToken(request); - } /** * Removes cache artifacts associated with the given account * @param request - developer provided SignOutRequest @@ -14738,234 +14648,3490 @@ var init_open = __esm({ }); }); }; - open = (target, options) => { - if (typeof target !== "string") { - throw new TypeError("Expected a `target`"); + open = (target, options) => { + if (typeof target !== "string") { + throw new TypeError("Expected a `target`"); + } + return baseOpen({ + ...options, + target + }); + }; + openApp = (name, options) => { + if (typeof name !== "string" && !Array.isArray(name)) { + throw new TypeError("Expected a valid `name`"); + } + const { arguments: appArguments = [] } = options ?? {}; + if (appArguments !== void 0 && appArguments !== null && !Array.isArray(appArguments)) { + throw new TypeError("Expected `appArguments` as Array type"); + } + return baseOpen({ + ...options, + app: { + name, + arguments: appArguments + } + }); + }; + apps = { + browser: "browser", + browserPrivate: "browserPrivate" + }; + defineLazyProperty(apps, "chrome", () => detectPlatformBinary({ + darwin: "google chrome", + win32: "chrome", + // `chromium-browser` is the older deb package name used by Ubuntu/Debian before snap. + linux: ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser"] + }, { + wsl: { + ia32: "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe", + x64: ["/mnt/c/Program Files/Google/Chrome/Application/chrome.exe", "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe"] + } + })); + defineLazyProperty(apps, "brave", () => detectPlatformBinary({ + darwin: "brave browser", + win32: "brave", + linux: ["brave-browser", "brave"] + }, { + wsl: { + ia32: "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe", + x64: ["/mnt/c/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe", "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe"] + } + })); + defineLazyProperty(apps, "firefox", () => detectPlatformBinary({ + darwin: "firefox", + win32: String.raw`C:\Program Files\Mozilla Firefox\firefox.exe`, + linux: "firefox" + }, { + wsl: "/mnt/c/Program Files/Mozilla Firefox/firefox.exe" + })); + defineLazyProperty(apps, "edge", () => detectPlatformBinary({ + darwin: "microsoft edge", + win32: "msedge", + linux: ["microsoft-edge", "microsoft-edge-dev"] + }, { + wsl: "/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe" + })); + defineLazyProperty(apps, "safari", () => detectPlatformBinary({ + darwin: "Safari" + })); + open_default = open; + } +}); + +// src/shared-auth.js +var require_shared_auth = __commonJS({ + "src/shared-auth.js"(exports2, module2) { + var { log: log2 } = require_shared_utils(); + var { createCachePlugin } = require_msal_cache(); + var VSCODE_CLIENT_ID2 = "51f81489-12ee-4a9e-aaae-a2591f45987d"; + var ISLAND_RESOURCE_IDS = { + 0: "a522f059-bb65-47c0-8934-7db6e5286414", + 1: "a522f059-bb65-47c0-8934-7db6e5286414", + 2: "a522f059-bb65-47c0-8934-7db6e5286414", + 3: "a522f059-bb65-47c0-8934-7db6e5286414", + 4: "96ff4394-9197-43aa-b393-6a41652e21f8", + 5: "96ff4394-9197-43aa-b393-6a41652e21f8", + 6: "9315aedd-209b-43b3-b149-2abff6a95d59", + 7: "69c6e40c-465f-4154-987d-da5cba10734e", + 8: "bd4a9f18-e349-4c74-a6b7-65dd465ea9ab" + }; + function getIslandResourceId2(clusterCategory) { + const id = ISLAND_RESOURCE_IDS[clusterCategory]; + if (!id) throw new Error(`Unknown cluster category: ${clusterCategory}`); + return id; + } + var _cachePlugin = null; + var _msalApps = /* @__PURE__ */ new Map(); + async function getDefaultCachePlugin() { + if (!_cachePlugin) { + _cachePlugin = await createCachePlugin("manage-agent"); + } + return _cachePlugin; + } + async function createMsalApp(tenantId, clientId, cacheSlot) { + const msal = require_msal_node(); + if (cacheSlot) { + const plugin = await createCachePlugin(cacheSlot); + return new msal.PublicClientApplication({ + auth: { + clientId, + authority: `https://login.microsoftonline.com/${tenantId}` + }, + cache: { cachePlugin: plugin } + }); + } + const key = `${tenantId}:${clientId}`; + if (_msalApps.has(key)) return _msalApps.get(key); + const cachePlugin = await getDefaultCachePlugin(); + const app = new msal.PublicClientApplication({ + auth: { + clientId, + authority: `https://login.microsoftonline.com/${tenantId}` + }, + cache: { cachePlugin } + }); + _msalApps.set(key, app); + return app; + } + function buildTokenInfo2(result) { + return { + accessToken: result.accessToken, + expiresOn: result.expiresOn ? result.expiresOn.toISOString() : new Date(Date.now() + 3600 * 1e3).toISOString(), + scopes: result.scopes, + account: result.account ? { + homeAccountId: result.account.homeAccountId, + environment: result.account.environment, + tenantId: result.account.tenantId, + username: result.account.username + } : void 0 + }; + } + async function acquireTokenDeviceCode2(tenantId, clientId, scopes, cacheSlot) { + const app = await createMsalApp(tenantId, clientId, cacheSlot); + const result = await app.acquireTokenByDeviceCode({ + scopes, + deviceCodeCallback: (response) => { + log2(""); + log2(` ${response.message}`); + log2(""); + process.stdout.write( + JSON.stringify({ + status: "device_code", + userCode: response.userCode, + verificationUri: response.verificationUri, + message: response.message, + expiresIn: response.expiresIn + }) + "\n" + ); + } + }); + if (!result) throw new Error("Device code flow returned no result"); + return buildTokenInfo2(result); + } + async function acquireTokenInteractive2(tenantId, clientId, scopes, cacheSlot) { + const app = await createMsalApp(tenantId, clientId, cacheSlot); + const result = await app.acquireTokenInteractive({ + scopes, + openBrowser: async (url) => { + log2(""); + log2(` Open this URL to sign in: ${url}`); + log2(""); + const open2 = (await Promise.resolve().then(() => (init_open(), open_exports))).default; + await open2(url); + }, + successTemplate: "

Login successful. You can close this tab.

" + }); + if (!result) throw new Error("Interactive flow returned no result"); + return buildTokenInfo2(result); + } + async function acquireTokenSilent2(tenantId, clientId, scopes, cacheSlot) { + const app = await createMsalApp(tenantId, clientId, cacheSlot); + const allAccounts = await app.getTokenCache().getAllAccounts(); + const accounts = allAccounts.filter((a) => a.tenantId === tenantId); + if (accounts.length > 0) { + try { + const result = await app.acquireTokenSilent({ + scopes, + account: accounts[0] + }); + if (result) { + const scopeKey = scopes[0]; + log2(`${scopeKey}: silently refreshed (expires ${result.expiresOn?.toISOString()})`); + return buildTokenInfo2(result); + } + } catch (e) { + log2(`Silent refresh failed: ${e.message}`); + } + } + return null; + } + async function getOrAcquireToken2(tenantId, clientId, scopes, label, cacheSlot) { + const silent = await acquireTokenSilent2(tenantId, clientId, scopes, cacheSlot); + if (silent) { + log2(`${label}: using cached token (expires ${silent.expiresOn})`); + return silent; + } + log2(`${label}: starting interactive login...`); + return acquireTokenInteractive2(tenantId, clientId, scopes, cacheSlot); + } + async function getOrAcquireIslandToken2(tenantId, clusterCategory, label) { + const resourceId = getIslandResourceId2(clusterCategory); + return getOrAcquireToken2( + tenantId, + VSCODE_CLIENT_ID2, + [`api://${resourceId}/.default`], + label + ); + } + module2.exports = { + VSCODE_CLIENT_ID: VSCODE_CLIENT_ID2, + ISLAND_RESOURCE_IDS, + getIslandResourceId: getIslandResourceId2, + createMsalApp, + buildTokenInfo: buildTokenInfo2, + acquireTokenDeviceCode: acquireTokenDeviceCode2, + acquireTokenInteractive: acquireTokenInteractive2, + acquireTokenSilent: acquireTokenSilent2, + getOrAcquireToken: getOrAcquireToken2, + getOrAcquireIslandToken: getOrAcquireIslandToken2 + }; + } +}); + +// ../../node_modules/vscode-jsonrpc/lib/common/is.js +var require_is = __commonJS({ + "../../node_modules/vscode-jsonrpc/lib/common/is.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.stringArray = exports2.array = exports2.func = exports2.error = exports2.number = exports2.string = exports2.boolean = void 0; + function boolean(value) { + return value === true || value === false; + } + exports2.boolean = boolean; + function string(value) { + return typeof value === "string" || value instanceof String; + } + exports2.string = string; + function number(value) { + return typeof value === "number" || value instanceof Number; + } + exports2.number = number; + function error(value) { + return value instanceof Error; + } + exports2.error = error; + function func(value) { + return typeof value === "function"; + } + exports2.func = func; + function array(value) { + return Array.isArray(value); + } + exports2.array = array; + function stringArray(value) { + return array(value) && value.every((elem) => string(elem)); + } + exports2.stringArray = stringArray; + } +}); + +// ../../node_modules/vscode-jsonrpc/lib/common/messages.js +var require_messages = __commonJS({ + "../../node_modules/vscode-jsonrpc/lib/common/messages.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.Message = exports2.NotificationType9 = exports2.NotificationType8 = exports2.NotificationType7 = exports2.NotificationType6 = exports2.NotificationType5 = exports2.NotificationType4 = exports2.NotificationType3 = exports2.NotificationType2 = exports2.NotificationType1 = exports2.NotificationType0 = exports2.NotificationType = exports2.RequestType9 = exports2.RequestType8 = exports2.RequestType7 = exports2.RequestType6 = exports2.RequestType5 = exports2.RequestType4 = exports2.RequestType3 = exports2.RequestType2 = exports2.RequestType1 = exports2.RequestType = exports2.RequestType0 = exports2.AbstractMessageSignature = exports2.ParameterStructures = exports2.ResponseError = exports2.ErrorCodes = void 0; + var is = require_is(); + var ErrorCodes; + (function(ErrorCodes2) { + ErrorCodes2.ParseError = -32700; + ErrorCodes2.InvalidRequest = -32600; + ErrorCodes2.MethodNotFound = -32601; + ErrorCodes2.InvalidParams = -32602; + ErrorCodes2.InternalError = -32603; + ErrorCodes2.jsonrpcReservedErrorRangeStart = -32099; + ErrorCodes2.serverErrorStart = -32099; + ErrorCodes2.MessageWriteError = -32099; + ErrorCodes2.MessageReadError = -32098; + ErrorCodes2.PendingResponseRejected = -32097; + ErrorCodes2.ConnectionInactive = -32096; + ErrorCodes2.ServerNotInitialized = -32002; + ErrorCodes2.UnknownErrorCode = -32001; + ErrorCodes2.jsonrpcReservedErrorRangeEnd = -32e3; + ErrorCodes2.serverErrorEnd = -32e3; + })(ErrorCodes || (exports2.ErrorCodes = ErrorCodes = {})); + var ResponseError = class _ResponseError extends Error { + constructor(code, message, data) { + super(message); + this.code = is.number(code) ? code : ErrorCodes.UnknownErrorCode; + this.data = data; + Object.setPrototypeOf(this, _ResponseError.prototype); + } + toJson() { + const result = { + code: this.code, + message: this.message + }; + if (this.data !== void 0) { + result.data = this.data; + } + return result; + } + }; + exports2.ResponseError = ResponseError; + var ParameterStructures = class _ParameterStructures { + constructor(kind) { + this.kind = kind; + } + static is(value) { + return value === _ParameterStructures.auto || value === _ParameterStructures.byName || value === _ParameterStructures.byPosition; + } + toString() { + return this.kind; + } + }; + exports2.ParameterStructures = ParameterStructures; + ParameterStructures.auto = new ParameterStructures("auto"); + ParameterStructures.byPosition = new ParameterStructures("byPosition"); + ParameterStructures.byName = new ParameterStructures("byName"); + var AbstractMessageSignature = class { + constructor(method, numberOfParams) { + this.method = method; + this.numberOfParams = numberOfParams; + } + get parameterStructures() { + return ParameterStructures.auto; + } + }; + exports2.AbstractMessageSignature = AbstractMessageSignature; + var RequestType0 = class extends AbstractMessageSignature { + constructor(method) { + super(method, 0); + } + }; + exports2.RequestType0 = RequestType0; + var RequestType = class extends AbstractMessageSignature { + constructor(method, _parameterStructures = ParameterStructures.auto) { + super(method, 1); + this._parameterStructures = _parameterStructures; + } + get parameterStructures() { + return this._parameterStructures; + } + }; + exports2.RequestType = RequestType; + var RequestType1 = class extends AbstractMessageSignature { + constructor(method, _parameterStructures = ParameterStructures.auto) { + super(method, 1); + this._parameterStructures = _parameterStructures; + } + get parameterStructures() { + return this._parameterStructures; + } + }; + exports2.RequestType1 = RequestType1; + var RequestType2 = class extends AbstractMessageSignature { + constructor(method) { + super(method, 2); + } + }; + exports2.RequestType2 = RequestType2; + var RequestType3 = class extends AbstractMessageSignature { + constructor(method) { + super(method, 3); + } + }; + exports2.RequestType3 = RequestType3; + var RequestType4 = class extends AbstractMessageSignature { + constructor(method) { + super(method, 4); + } + }; + exports2.RequestType4 = RequestType4; + var RequestType5 = class extends AbstractMessageSignature { + constructor(method) { + super(method, 5); + } + }; + exports2.RequestType5 = RequestType5; + var RequestType6 = class extends AbstractMessageSignature { + constructor(method) { + super(method, 6); + } + }; + exports2.RequestType6 = RequestType6; + var RequestType7 = class extends AbstractMessageSignature { + constructor(method) { + super(method, 7); + } + }; + exports2.RequestType7 = RequestType7; + var RequestType8 = class extends AbstractMessageSignature { + constructor(method) { + super(method, 8); + } + }; + exports2.RequestType8 = RequestType8; + var RequestType9 = class extends AbstractMessageSignature { + constructor(method) { + super(method, 9); + } + }; + exports2.RequestType9 = RequestType9; + var NotificationType = class extends AbstractMessageSignature { + constructor(method, _parameterStructures = ParameterStructures.auto) { + super(method, 1); + this._parameterStructures = _parameterStructures; + } + get parameterStructures() { + return this._parameterStructures; + } + }; + exports2.NotificationType = NotificationType; + var NotificationType0 = class extends AbstractMessageSignature { + constructor(method) { + super(method, 0); + } + }; + exports2.NotificationType0 = NotificationType0; + var NotificationType1 = class extends AbstractMessageSignature { + constructor(method, _parameterStructures = ParameterStructures.auto) { + super(method, 1); + this._parameterStructures = _parameterStructures; + } + get parameterStructures() { + return this._parameterStructures; + } + }; + exports2.NotificationType1 = NotificationType1; + var NotificationType2 = class extends AbstractMessageSignature { + constructor(method) { + super(method, 2); + } + }; + exports2.NotificationType2 = NotificationType2; + var NotificationType3 = class extends AbstractMessageSignature { + constructor(method) { + super(method, 3); + } + }; + exports2.NotificationType3 = NotificationType3; + var NotificationType4 = class extends AbstractMessageSignature { + constructor(method) { + super(method, 4); + } + }; + exports2.NotificationType4 = NotificationType4; + var NotificationType5 = class extends AbstractMessageSignature { + constructor(method) { + super(method, 5); + } + }; + exports2.NotificationType5 = NotificationType5; + var NotificationType6 = class extends AbstractMessageSignature { + constructor(method) { + super(method, 6); + } + }; + exports2.NotificationType6 = NotificationType6; + var NotificationType7 = class extends AbstractMessageSignature { + constructor(method) { + super(method, 7); + } + }; + exports2.NotificationType7 = NotificationType7; + var NotificationType8 = class extends AbstractMessageSignature { + constructor(method) { + super(method, 8); + } + }; + exports2.NotificationType8 = NotificationType8; + var NotificationType9 = class extends AbstractMessageSignature { + constructor(method) { + super(method, 9); + } + }; + exports2.NotificationType9 = NotificationType9; + var Message; + (function(Message2) { + function isRequest(message) { + const candidate = message; + return candidate && is.string(candidate.method) && (is.string(candidate.id) || is.number(candidate.id)); + } + Message2.isRequest = isRequest; + function isNotification(message) { + const candidate = message; + return candidate && is.string(candidate.method) && message.id === void 0; + } + Message2.isNotification = isNotification; + function isResponse(message) { + const candidate = message; + return candidate && (candidate.result !== void 0 || !!candidate.error) && (is.string(candidate.id) || is.number(candidate.id) || candidate.id === null); + } + Message2.isResponse = isResponse; + })(Message || (exports2.Message = Message = {})); + } +}); + +// ../../node_modules/vscode-jsonrpc/lib/common/linkedMap.js +var require_linkedMap = __commonJS({ + "../../node_modules/vscode-jsonrpc/lib/common/linkedMap.js"(exports2) { + "use strict"; + var _a; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.LRUCache = exports2.LinkedMap = exports2.Touch = void 0; + var Touch; + (function(Touch2) { + Touch2.None = 0; + Touch2.First = 1; + Touch2.AsOld = Touch2.First; + Touch2.Last = 2; + Touch2.AsNew = Touch2.Last; + })(Touch || (exports2.Touch = Touch = {})); + var LinkedMap = class { + constructor() { + this[_a] = "LinkedMap"; + this._map = /* @__PURE__ */ new Map(); + this._head = void 0; + this._tail = void 0; + this._size = 0; + this._state = 0; + } + clear() { + this._map.clear(); + this._head = void 0; + this._tail = void 0; + this._size = 0; + this._state++; + } + isEmpty() { + return !this._head && !this._tail; + } + get size() { + return this._size; + } + get first() { + return this._head?.value; + } + get last() { + return this._tail?.value; + } + has(key) { + return this._map.has(key); + } + get(key, touch = Touch.None) { + const item = this._map.get(key); + if (!item) { + return void 0; + } + if (touch !== Touch.None) { + this.touch(item, touch); + } + return item.value; + } + set(key, value, touch = Touch.None) { + let item = this._map.get(key); + if (item) { + item.value = value; + if (touch !== Touch.None) { + this.touch(item, touch); + } + } else { + item = { key, value, next: void 0, previous: void 0 }; + switch (touch) { + case Touch.None: + this.addItemLast(item); + break; + case Touch.First: + this.addItemFirst(item); + break; + case Touch.Last: + this.addItemLast(item); + break; + default: + this.addItemLast(item); + break; + } + this._map.set(key, item); + this._size++; + } + return this; + } + delete(key) { + return !!this.remove(key); + } + remove(key) { + const item = this._map.get(key); + if (!item) { + return void 0; + } + this._map.delete(key); + this.removeItem(item); + this._size--; + return item.value; + } + shift() { + if (!this._head && !this._tail) { + return void 0; + } + if (!this._head || !this._tail) { + throw new Error("Invalid list"); + } + const item = this._head; + this._map.delete(item.key); + this.removeItem(item); + this._size--; + return item.value; + } + forEach(callbackfn, thisArg) { + const state = this._state; + let current = this._head; + while (current) { + if (thisArg) { + callbackfn.bind(thisArg)(current.value, current.key, this); + } else { + callbackfn(current.value, current.key, this); + } + if (this._state !== state) { + throw new Error(`LinkedMap got modified during iteration.`); + } + current = current.next; + } + } + keys() { + const state = this._state; + let current = this._head; + const iterator = { + [Symbol.iterator]: () => { + return iterator; + }, + next: () => { + if (this._state !== state) { + throw new Error(`LinkedMap got modified during iteration.`); + } + if (current) { + const result = { value: current.key, done: false }; + current = current.next; + return result; + } else { + return { value: void 0, done: true }; + } + } + }; + return iterator; + } + values() { + const state = this._state; + let current = this._head; + const iterator = { + [Symbol.iterator]: () => { + return iterator; + }, + next: () => { + if (this._state !== state) { + throw new Error(`LinkedMap got modified during iteration.`); + } + if (current) { + const result = { value: current.value, done: false }; + current = current.next; + return result; + } else { + return { value: void 0, done: true }; + } + } + }; + return iterator; + } + entries() { + const state = this._state; + let current = this._head; + const iterator = { + [Symbol.iterator]: () => { + return iterator; + }, + next: () => { + if (this._state !== state) { + throw new Error(`LinkedMap got modified during iteration.`); + } + if (current) { + const result = { value: [current.key, current.value], done: false }; + current = current.next; + return result; + } else { + return { value: void 0, done: true }; + } + } + }; + return iterator; + } + [(_a = Symbol.toStringTag, Symbol.iterator)]() { + return this.entries(); + } + trimOld(newSize) { + if (newSize >= this.size) { + return; + } + if (newSize === 0) { + this.clear(); + return; + } + let current = this._head; + let currentSize = this.size; + while (current && currentSize > newSize) { + this._map.delete(current.key); + current = current.next; + currentSize--; + } + this._head = current; + this._size = currentSize; + if (current) { + current.previous = void 0; + } + this._state++; + } + addItemFirst(item) { + if (!this._head && !this._tail) { + this._tail = item; + } else if (!this._head) { + throw new Error("Invalid list"); + } else { + item.next = this._head; + this._head.previous = item; + } + this._head = item; + this._state++; + } + addItemLast(item) { + if (!this._head && !this._tail) { + this._head = item; + } else if (!this._tail) { + throw new Error("Invalid list"); + } else { + item.previous = this._tail; + this._tail.next = item; + } + this._tail = item; + this._state++; + } + removeItem(item) { + if (item === this._head && item === this._tail) { + this._head = void 0; + this._tail = void 0; + } else if (item === this._head) { + if (!item.next) { + throw new Error("Invalid list"); + } + item.next.previous = void 0; + this._head = item.next; + } else if (item === this._tail) { + if (!item.previous) { + throw new Error("Invalid list"); + } + item.previous.next = void 0; + this._tail = item.previous; + } else { + const next = item.next; + const previous = item.previous; + if (!next || !previous) { + throw new Error("Invalid list"); + } + next.previous = previous; + previous.next = next; + } + item.next = void 0; + item.previous = void 0; + this._state++; + } + touch(item, touch) { + if (!this._head || !this._tail) { + throw new Error("Invalid list"); + } + if (touch !== Touch.First && touch !== Touch.Last) { + return; + } + if (touch === Touch.First) { + if (item === this._head) { + return; + } + const next = item.next; + const previous = item.previous; + if (item === this._tail) { + previous.next = void 0; + this._tail = previous; + } else { + next.previous = previous; + previous.next = next; + } + item.previous = void 0; + item.next = this._head; + this._head.previous = item; + this._head = item; + this._state++; + } else if (touch === Touch.Last) { + if (item === this._tail) { + return; + } + const next = item.next; + const previous = item.previous; + if (item === this._head) { + next.previous = void 0; + this._head = next; + } else { + next.previous = previous; + previous.next = next; + } + item.next = void 0; + item.previous = this._tail; + this._tail.next = item; + this._tail = item; + this._state++; + } + } + toJSON() { + const data = []; + this.forEach((value, key) => { + data.push([key, value]); + }); + return data; + } + fromJSON(data) { + this.clear(); + for (const [key, value] of data) { + this.set(key, value); + } + } + }; + exports2.LinkedMap = LinkedMap; + var LRUCache = class extends LinkedMap { + constructor(limit, ratio = 1) { + super(); + this._limit = limit; + this._ratio = Math.min(Math.max(0, ratio), 1); + } + get limit() { + return this._limit; + } + set limit(limit) { + this._limit = limit; + this.checkTrim(); + } + get ratio() { + return this._ratio; + } + set ratio(ratio) { + this._ratio = Math.min(Math.max(0, ratio), 1); + this.checkTrim(); + } + get(key, touch = Touch.AsNew) { + return super.get(key, touch); + } + peek(key) { + return super.get(key, Touch.None); + } + set(key, value) { + super.set(key, value, Touch.Last); + this.checkTrim(); + return this; + } + checkTrim() { + if (this.size > this._limit) { + this.trimOld(Math.round(this._limit * this._ratio)); + } + } + }; + exports2.LRUCache = LRUCache; + } +}); + +// ../../node_modules/vscode-jsonrpc/lib/common/disposable.js +var require_disposable = __commonJS({ + "../../node_modules/vscode-jsonrpc/lib/common/disposable.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.Disposable = void 0; + var Disposable; + (function(Disposable2) { + function create(func) { + return { + dispose: func + }; + } + Disposable2.create = create; + })(Disposable || (exports2.Disposable = Disposable = {})); + } +}); + +// ../../node_modules/vscode-jsonrpc/lib/common/ral.js +var require_ral = __commonJS({ + "../../node_modules/vscode-jsonrpc/lib/common/ral.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + var _ral; + function RAL() { + if (_ral === void 0) { + throw new Error(`No runtime abstraction layer installed`); + } + return _ral; + } + (function(RAL2) { + function install(ral) { + if (ral === void 0) { + throw new Error(`No runtime abstraction layer provided`); + } + _ral = ral; + } + RAL2.install = install; + })(RAL || (RAL = {})); + exports2.default = RAL; + } +}); + +// ../../node_modules/vscode-jsonrpc/lib/common/events.js +var require_events = __commonJS({ + "../../node_modules/vscode-jsonrpc/lib/common/events.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.Emitter = exports2.Event = void 0; + var ral_1 = require_ral(); + var Event; + (function(Event2) { + const _disposable = { dispose() { + } }; + Event2.None = function() { + return _disposable; + }; + })(Event || (exports2.Event = Event = {})); + var CallbackList = class { + add(callback, context = null, bucket) { + if (!this._callbacks) { + this._callbacks = []; + this._contexts = []; + } + this._callbacks.push(callback); + this._contexts.push(context); + if (Array.isArray(bucket)) { + bucket.push({ dispose: () => this.remove(callback, context) }); + } + } + remove(callback, context = null) { + if (!this._callbacks) { + return; + } + let foundCallbackWithDifferentContext = false; + for (let i = 0, len = this._callbacks.length; i < len; i++) { + if (this._callbacks[i] === callback) { + if (this._contexts[i] === context) { + this._callbacks.splice(i, 1); + this._contexts.splice(i, 1); + return; + } else { + foundCallbackWithDifferentContext = true; + } + } + } + if (foundCallbackWithDifferentContext) { + throw new Error("When adding a listener with a context, you should remove it with the same context"); + } + } + invoke(...args) { + if (!this._callbacks) { + return []; + } + const ret = [], callbacks = this._callbacks.slice(0), contexts = this._contexts.slice(0); + for (let i = 0, len = callbacks.length; i < len; i++) { + try { + ret.push(callbacks[i].apply(contexts[i], args)); + } catch (e) { + (0, ral_1.default)().console.error(e); + } + } + return ret; + } + isEmpty() { + return !this._callbacks || this._callbacks.length === 0; + } + dispose() { + this._callbacks = void 0; + this._contexts = void 0; + } + }; + var Emitter = class _Emitter { + constructor(_options) { + this._options = _options; + } + /** + * For the public to allow to subscribe + * to events from this Emitter + */ + get event() { + if (!this._event) { + this._event = (listener, thisArgs, disposables) => { + if (!this._callbacks) { + this._callbacks = new CallbackList(); + } + if (this._options && this._options.onFirstListenerAdd && this._callbacks.isEmpty()) { + this._options.onFirstListenerAdd(this); + } + this._callbacks.add(listener, thisArgs); + const result = { + dispose: () => { + if (!this._callbacks) { + return; + } + this._callbacks.remove(listener, thisArgs); + result.dispose = _Emitter._noop; + if (this._options && this._options.onLastListenerRemove && this._callbacks.isEmpty()) { + this._options.onLastListenerRemove(this); + } + } + }; + if (Array.isArray(disposables)) { + disposables.push(result); + } + return result; + }; + } + return this._event; + } + /** + * To be kept private to fire an event to + * subscribers + */ + fire(event) { + if (this._callbacks) { + this._callbacks.invoke.call(this._callbacks, event); + } + } + dispose() { + if (this._callbacks) { + this._callbacks.dispose(); + this._callbacks = void 0; + } + } + }; + exports2.Emitter = Emitter; + Emitter._noop = function() { + }; + } +}); + +// ../../node_modules/vscode-jsonrpc/lib/common/cancellation.js +var require_cancellation = __commonJS({ + "../../node_modules/vscode-jsonrpc/lib/common/cancellation.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.CancellationTokenSource = exports2.CancellationToken = void 0; + var ral_1 = require_ral(); + var Is = require_is(); + var events_1 = require_events(); + var CancellationToken; + (function(CancellationToken2) { + CancellationToken2.None = Object.freeze({ + isCancellationRequested: false, + onCancellationRequested: events_1.Event.None + }); + CancellationToken2.Cancelled = Object.freeze({ + isCancellationRequested: true, + onCancellationRequested: events_1.Event.None + }); + function is(value) { + const candidate = value; + return candidate && (candidate === CancellationToken2.None || candidate === CancellationToken2.Cancelled || Is.boolean(candidate.isCancellationRequested) && !!candidate.onCancellationRequested); + } + CancellationToken2.is = is; + })(CancellationToken || (exports2.CancellationToken = CancellationToken = {})); + var shortcutEvent = Object.freeze(function(callback, context) { + const handle = (0, ral_1.default)().timer.setTimeout(callback.bind(context), 0); + return { dispose() { + handle.dispose(); + } }; + }); + var MutableToken = class { + constructor() { + this._isCancelled = false; + } + cancel() { + if (!this._isCancelled) { + this._isCancelled = true; + if (this._emitter) { + this._emitter.fire(void 0); + this.dispose(); + } + } + } + get isCancellationRequested() { + return this._isCancelled; + } + get onCancellationRequested() { + if (this._isCancelled) { + return shortcutEvent; + } + if (!this._emitter) { + this._emitter = new events_1.Emitter(); + } + return this._emitter.event; + } + dispose() { + if (this._emitter) { + this._emitter.dispose(); + this._emitter = void 0; + } + } + }; + var CancellationTokenSource = class { + get token() { + if (!this._token) { + this._token = new MutableToken(); + } + return this._token; + } + cancel() { + if (!this._token) { + this._token = CancellationToken.Cancelled; + } else { + this._token.cancel(); + } + } + dispose() { + if (!this._token) { + this._token = CancellationToken.None; + } else if (this._token instanceof MutableToken) { + this._token.dispose(); + } + } + }; + exports2.CancellationTokenSource = CancellationTokenSource; + } +}); + +// ../../node_modules/vscode-jsonrpc/lib/common/sharedArrayCancellation.js +var require_sharedArrayCancellation = __commonJS({ + "../../node_modules/vscode-jsonrpc/lib/common/sharedArrayCancellation.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.SharedArrayReceiverStrategy = exports2.SharedArraySenderStrategy = void 0; + var cancellation_1 = require_cancellation(); + var CancellationState; + (function(CancellationState2) { + CancellationState2.Continue = 0; + CancellationState2.Cancelled = 1; + })(CancellationState || (CancellationState = {})); + var SharedArraySenderStrategy = class { + constructor() { + this.buffers = /* @__PURE__ */ new Map(); + } + enableCancellation(request) { + if (request.id === null) { + return; + } + const buffer = new SharedArrayBuffer(4); + const data = new Int32Array(buffer, 0, 1); + data[0] = CancellationState.Continue; + this.buffers.set(request.id, buffer); + request.$cancellationData = buffer; + } + async sendCancellation(_conn, id) { + const buffer = this.buffers.get(id); + if (buffer === void 0) { + return; + } + const data = new Int32Array(buffer, 0, 1); + Atomics.store(data, 0, CancellationState.Cancelled); + } + cleanup(id) { + this.buffers.delete(id); + } + dispose() { + this.buffers.clear(); + } + }; + exports2.SharedArraySenderStrategy = SharedArraySenderStrategy; + var SharedArrayBufferCancellationToken = class { + constructor(buffer) { + this.data = new Int32Array(buffer, 0, 1); + } + get isCancellationRequested() { + return Atomics.load(this.data, 0) === CancellationState.Cancelled; + } + get onCancellationRequested() { + throw new Error(`Cancellation over SharedArrayBuffer doesn't support cancellation events`); + } + }; + var SharedArrayBufferCancellationTokenSource = class { + constructor(buffer) { + this.token = new SharedArrayBufferCancellationToken(buffer); + } + cancel() { + } + dispose() { + } + }; + var SharedArrayReceiverStrategy = class { + constructor() { + this.kind = "request"; + } + createCancellationTokenSource(request) { + const buffer = request.$cancellationData; + if (buffer === void 0) { + return new cancellation_1.CancellationTokenSource(); + } + return new SharedArrayBufferCancellationTokenSource(buffer); + } + }; + exports2.SharedArrayReceiverStrategy = SharedArrayReceiverStrategy; + } +}); + +// ../../node_modules/vscode-jsonrpc/lib/common/semaphore.js +var require_semaphore = __commonJS({ + "../../node_modules/vscode-jsonrpc/lib/common/semaphore.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.Semaphore = void 0; + var ral_1 = require_ral(); + var Semaphore = class { + constructor(capacity = 1) { + if (capacity <= 0) { + throw new Error("Capacity must be greater than 0"); + } + this._capacity = capacity; + this._active = 0; + this._waiting = []; + } + lock(thunk) { + return new Promise((resolve, reject) => { + this._waiting.push({ thunk, resolve, reject }); + this.runNext(); + }); + } + get active() { + return this._active; + } + runNext() { + if (this._waiting.length === 0 || this._active === this._capacity) { + return; + } + (0, ral_1.default)().timer.setImmediate(() => this.doRunNext()); + } + doRunNext() { + if (this._waiting.length === 0 || this._active === this._capacity) { + return; + } + const next = this._waiting.shift(); + this._active++; + if (this._active > this._capacity) { + throw new Error(`To many thunks active`); + } + try { + const result = next.thunk(); + if (result instanceof Promise) { + result.then((value) => { + this._active--; + next.resolve(value); + this.runNext(); + }, (err) => { + this._active--; + next.reject(err); + this.runNext(); + }); + } else { + this._active--; + next.resolve(result); + this.runNext(); + } + } catch (err) { + this._active--; + next.reject(err); + this.runNext(); + } + } + }; + exports2.Semaphore = Semaphore; + } +}); + +// ../../node_modules/vscode-jsonrpc/lib/common/messageReader.js +var require_messageReader = __commonJS({ + "../../node_modules/vscode-jsonrpc/lib/common/messageReader.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.ReadableStreamMessageReader = exports2.AbstractMessageReader = exports2.MessageReader = void 0; + var ral_1 = require_ral(); + var Is = require_is(); + var events_1 = require_events(); + var semaphore_1 = require_semaphore(); + var MessageReader; + (function(MessageReader2) { + function is(value) { + let candidate = value; + return candidate && Is.func(candidate.listen) && Is.func(candidate.dispose) && Is.func(candidate.onError) && Is.func(candidate.onClose) && Is.func(candidate.onPartialMessage); + } + MessageReader2.is = is; + })(MessageReader || (exports2.MessageReader = MessageReader = {})); + var AbstractMessageReader = class { + constructor() { + this.errorEmitter = new events_1.Emitter(); + this.closeEmitter = new events_1.Emitter(); + this.partialMessageEmitter = new events_1.Emitter(); + } + dispose() { + this.errorEmitter.dispose(); + this.closeEmitter.dispose(); + } + get onError() { + return this.errorEmitter.event; + } + fireError(error) { + this.errorEmitter.fire(this.asError(error)); + } + get onClose() { + return this.closeEmitter.event; + } + fireClose() { + this.closeEmitter.fire(void 0); + } + get onPartialMessage() { + return this.partialMessageEmitter.event; + } + firePartialMessage(info) { + this.partialMessageEmitter.fire(info); + } + asError(error) { + if (error instanceof Error) { + return error; + } else { + return new Error(`Reader received error. Reason: ${Is.string(error.message) ? error.message : "unknown"}`); + } + } + }; + exports2.AbstractMessageReader = AbstractMessageReader; + var ResolvedMessageReaderOptions; + (function(ResolvedMessageReaderOptions2) { + function fromOptions(options) { + let charset; + let result; + let contentDecoder; + const contentDecoders = /* @__PURE__ */ new Map(); + let contentTypeDecoder; + const contentTypeDecoders = /* @__PURE__ */ new Map(); + if (options === void 0 || typeof options === "string") { + charset = options ?? "utf-8"; + } else { + charset = options.charset ?? "utf-8"; + if (options.contentDecoder !== void 0) { + contentDecoder = options.contentDecoder; + contentDecoders.set(contentDecoder.name, contentDecoder); + } + if (options.contentDecoders !== void 0) { + for (const decoder of options.contentDecoders) { + contentDecoders.set(decoder.name, decoder); + } + } + if (options.contentTypeDecoder !== void 0) { + contentTypeDecoder = options.contentTypeDecoder; + contentTypeDecoders.set(contentTypeDecoder.name, contentTypeDecoder); + } + if (options.contentTypeDecoders !== void 0) { + for (const decoder of options.contentTypeDecoders) { + contentTypeDecoders.set(decoder.name, decoder); + } + } + } + if (contentTypeDecoder === void 0) { + contentTypeDecoder = (0, ral_1.default)().applicationJson.decoder; + contentTypeDecoders.set(contentTypeDecoder.name, contentTypeDecoder); + } + return { charset, contentDecoder, contentDecoders, contentTypeDecoder, contentTypeDecoders }; + } + ResolvedMessageReaderOptions2.fromOptions = fromOptions; + })(ResolvedMessageReaderOptions || (ResolvedMessageReaderOptions = {})); + var ReadableStreamMessageReader = class extends AbstractMessageReader { + constructor(readable, options) { + super(); + this.readable = readable; + this.options = ResolvedMessageReaderOptions.fromOptions(options); + this.buffer = (0, ral_1.default)().messageBuffer.create(this.options.charset); + this._partialMessageTimeout = 1e4; + this.nextMessageLength = -1; + this.messageToken = 0; + this.readSemaphore = new semaphore_1.Semaphore(1); + } + set partialMessageTimeout(timeout) { + this._partialMessageTimeout = timeout; + } + get partialMessageTimeout() { + return this._partialMessageTimeout; + } + listen(callback) { + this.nextMessageLength = -1; + this.messageToken = 0; + this.partialMessageTimer = void 0; + this.callback = callback; + const result = this.readable.onData((data) => { + this.onData(data); + }); + this.readable.onError((error) => this.fireError(error)); + this.readable.onClose(() => this.fireClose()); + return result; + } + onData(data) { + try { + this.buffer.append(data); + while (true) { + if (this.nextMessageLength === -1) { + const headers = this.buffer.tryReadHeaders(true); + if (!headers) { + return; + } + const contentLength = headers.get("content-length"); + if (!contentLength) { + this.fireError(new Error(`Header must provide a Content-Length property. +${JSON.stringify(Object.fromEntries(headers))}`)); + return; + } + const length = parseInt(contentLength); + if (isNaN(length)) { + this.fireError(new Error(`Content-Length value must be a number. Got ${contentLength}`)); + return; + } + this.nextMessageLength = length; + } + const body = this.buffer.tryReadBody(this.nextMessageLength); + if (body === void 0) { + this.setPartialMessageTimer(); + return; + } + this.clearPartialMessageTimer(); + this.nextMessageLength = -1; + this.readSemaphore.lock(async () => { + const bytes = this.options.contentDecoder !== void 0 ? await this.options.contentDecoder.decode(body) : body; + const message = await this.options.contentTypeDecoder.decode(bytes, this.options); + this.callback(message); + }).catch((error) => { + this.fireError(error); + }); + } + } catch (error) { + this.fireError(error); + } + } + clearPartialMessageTimer() { + if (this.partialMessageTimer) { + this.partialMessageTimer.dispose(); + this.partialMessageTimer = void 0; + } + } + setPartialMessageTimer() { + this.clearPartialMessageTimer(); + if (this._partialMessageTimeout <= 0) { + return; + } + this.partialMessageTimer = (0, ral_1.default)().timer.setTimeout((token, timeout) => { + this.partialMessageTimer = void 0; + if (token === this.messageToken) { + this.firePartialMessage({ messageToken: token, waitingTime: timeout }); + this.setPartialMessageTimer(); + } + }, this._partialMessageTimeout, this.messageToken, this._partialMessageTimeout); + } + }; + exports2.ReadableStreamMessageReader = ReadableStreamMessageReader; + } +}); + +// ../../node_modules/vscode-jsonrpc/lib/common/messageWriter.js +var require_messageWriter = __commonJS({ + "../../node_modules/vscode-jsonrpc/lib/common/messageWriter.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.WriteableStreamMessageWriter = exports2.AbstractMessageWriter = exports2.MessageWriter = void 0; + var ral_1 = require_ral(); + var Is = require_is(); + var semaphore_1 = require_semaphore(); + var events_1 = require_events(); + var ContentLength = "Content-Length: "; + var CRLF = "\r\n"; + var MessageWriter; + (function(MessageWriter2) { + function is(value) { + let candidate = value; + return candidate && Is.func(candidate.dispose) && Is.func(candidate.onClose) && Is.func(candidate.onError) && Is.func(candidate.write); + } + MessageWriter2.is = is; + })(MessageWriter || (exports2.MessageWriter = MessageWriter = {})); + var AbstractMessageWriter = class { + constructor() { + this.errorEmitter = new events_1.Emitter(); + this.closeEmitter = new events_1.Emitter(); + } + dispose() { + this.errorEmitter.dispose(); + this.closeEmitter.dispose(); + } + get onError() { + return this.errorEmitter.event; + } + fireError(error, message, count) { + this.errorEmitter.fire([this.asError(error), message, count]); + } + get onClose() { + return this.closeEmitter.event; + } + fireClose() { + this.closeEmitter.fire(void 0); + } + asError(error) { + if (error instanceof Error) { + return error; + } else { + return new Error(`Writer received error. Reason: ${Is.string(error.message) ? error.message : "unknown"}`); + } + } + }; + exports2.AbstractMessageWriter = AbstractMessageWriter; + var ResolvedMessageWriterOptions; + (function(ResolvedMessageWriterOptions2) { + function fromOptions(options) { + if (options === void 0 || typeof options === "string") { + return { charset: options ?? "utf-8", contentTypeEncoder: (0, ral_1.default)().applicationJson.encoder }; + } else { + return { charset: options.charset ?? "utf-8", contentEncoder: options.contentEncoder, contentTypeEncoder: options.contentTypeEncoder ?? (0, ral_1.default)().applicationJson.encoder }; + } + } + ResolvedMessageWriterOptions2.fromOptions = fromOptions; + })(ResolvedMessageWriterOptions || (ResolvedMessageWriterOptions = {})); + var WriteableStreamMessageWriter = class extends AbstractMessageWriter { + constructor(writable, options) { + super(); + this.writable = writable; + this.options = ResolvedMessageWriterOptions.fromOptions(options); + this.errorCount = 0; + this.writeSemaphore = new semaphore_1.Semaphore(1); + this.writable.onError((error) => this.fireError(error)); + this.writable.onClose(() => this.fireClose()); + } + async write(msg) { + return this.writeSemaphore.lock(async () => { + const payload = this.options.contentTypeEncoder.encode(msg, this.options).then((buffer) => { + if (this.options.contentEncoder !== void 0) { + return this.options.contentEncoder.encode(buffer); + } else { + return buffer; + } + }); + return payload.then((buffer) => { + const headers = []; + headers.push(ContentLength, buffer.byteLength.toString(), CRLF); + headers.push(CRLF); + return this.doWrite(msg, headers, buffer); + }, (error) => { + this.fireError(error); + throw error; + }); + }); + } + async doWrite(msg, headers, data) { + try { + await this.writable.write(headers.join(""), "ascii"); + return this.writable.write(data); + } catch (error) { + this.handleError(error, msg); + return Promise.reject(error); + } + } + handleError(error, msg) { + this.errorCount++; + this.fireError(error, msg, this.errorCount); + } + end() { + this.writable.end(); + } + }; + exports2.WriteableStreamMessageWriter = WriteableStreamMessageWriter; + } +}); + +// ../../node_modules/vscode-jsonrpc/lib/common/messageBuffer.js +var require_messageBuffer = __commonJS({ + "../../node_modules/vscode-jsonrpc/lib/common/messageBuffer.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.AbstractMessageBuffer = void 0; + var CR = 13; + var LF = 10; + var CRLF = "\r\n"; + var AbstractMessageBuffer = class { + constructor(encoding = "utf-8") { + this._encoding = encoding; + this._chunks = []; + this._totalLength = 0; + } + get encoding() { + return this._encoding; + } + append(chunk) { + const toAppend = typeof chunk === "string" ? this.fromString(chunk, this._encoding) : chunk; + this._chunks.push(toAppend); + this._totalLength += toAppend.byteLength; + } + tryReadHeaders(lowerCaseKeys = false) { + if (this._chunks.length === 0) { + return void 0; + } + let state = 0; + let chunkIndex = 0; + let offset = 0; + let chunkBytesRead = 0; + row: while (chunkIndex < this._chunks.length) { + const chunk = this._chunks[chunkIndex]; + offset = 0; + column: while (offset < chunk.length) { + const value = chunk[offset]; + switch (value) { + case CR: + switch (state) { + case 0: + state = 1; + break; + case 2: + state = 3; + break; + default: + state = 0; + } + break; + case LF: + switch (state) { + case 1: + state = 2; + break; + case 3: + state = 4; + offset++; + break row; + default: + state = 0; + } + break; + default: + state = 0; + } + offset++; + } + chunkBytesRead += chunk.byteLength; + chunkIndex++; + } + if (state !== 4) { + return void 0; + } + const buffer = this._read(chunkBytesRead + offset); + const result = /* @__PURE__ */ new Map(); + const headers = this.toString(buffer, "ascii").split(CRLF); + if (headers.length < 2) { + return result; + } + for (let i = 0; i < headers.length - 2; i++) { + const header = headers[i]; + const index = header.indexOf(":"); + if (index === -1) { + throw new Error(`Message header must separate key and value using ':' +${header}`); + } + const key = header.substr(0, index); + const value = header.substr(index + 1).trim(); + result.set(lowerCaseKeys ? key.toLowerCase() : key, value); + } + return result; + } + tryReadBody(length) { + if (this._totalLength < length) { + return void 0; + } + return this._read(length); + } + get numberOfBytes() { + return this._totalLength; + } + _read(byteCount) { + if (byteCount === 0) { + return this.emptyBuffer(); + } + if (byteCount > this._totalLength) { + throw new Error(`Cannot read so many bytes!`); + } + if (this._chunks[0].byteLength === byteCount) { + const chunk = this._chunks[0]; + this._chunks.shift(); + this._totalLength -= byteCount; + return this.asNative(chunk); + } + if (this._chunks[0].byteLength > byteCount) { + const chunk = this._chunks[0]; + const result2 = this.asNative(chunk, byteCount); + this._chunks[0] = chunk.slice(byteCount); + this._totalLength -= byteCount; + return result2; + } + const result = this.allocNative(byteCount); + let resultOffset = 0; + let chunkIndex = 0; + while (byteCount > 0) { + const chunk = this._chunks[chunkIndex]; + if (chunk.byteLength > byteCount) { + const chunkPart = chunk.slice(0, byteCount); + result.set(chunkPart, resultOffset); + resultOffset += byteCount; + this._chunks[chunkIndex] = chunk.slice(byteCount); + this._totalLength -= byteCount; + byteCount -= byteCount; + } else { + result.set(chunk, resultOffset); + resultOffset += chunk.byteLength; + this._chunks.shift(); + this._totalLength -= chunk.byteLength; + byteCount -= chunk.byteLength; + } + } + return result; + } + }; + exports2.AbstractMessageBuffer = AbstractMessageBuffer; + } +}); + +// ../../node_modules/vscode-jsonrpc/lib/common/connection.js +var require_connection = __commonJS({ + "../../node_modules/vscode-jsonrpc/lib/common/connection.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.createMessageConnection = exports2.ConnectionOptions = exports2.MessageStrategy = exports2.CancellationStrategy = exports2.CancellationSenderStrategy = exports2.CancellationReceiverStrategy = exports2.RequestCancellationReceiverStrategy = exports2.IdCancellationReceiverStrategy = exports2.ConnectionStrategy = exports2.ConnectionError = exports2.ConnectionErrors = exports2.LogTraceNotification = exports2.SetTraceNotification = exports2.TraceFormat = exports2.TraceValues = exports2.Trace = exports2.NullLogger = exports2.ProgressType = exports2.ProgressToken = void 0; + var ral_1 = require_ral(); + var Is = require_is(); + var messages_1 = require_messages(); + var linkedMap_1 = require_linkedMap(); + var events_1 = require_events(); + var cancellation_1 = require_cancellation(); + var CancelNotification; + (function(CancelNotification2) { + CancelNotification2.type = new messages_1.NotificationType("$/cancelRequest"); + })(CancelNotification || (CancelNotification = {})); + var ProgressToken; + (function(ProgressToken2) { + function is(value) { + return typeof value === "string" || typeof value === "number"; + } + ProgressToken2.is = is; + })(ProgressToken || (exports2.ProgressToken = ProgressToken = {})); + var ProgressNotification; + (function(ProgressNotification2) { + ProgressNotification2.type = new messages_1.NotificationType("$/progress"); + })(ProgressNotification || (ProgressNotification = {})); + var ProgressType = class { + constructor() { + } + }; + exports2.ProgressType = ProgressType; + var StarRequestHandler; + (function(StarRequestHandler2) { + function is(value) { + return Is.func(value); + } + StarRequestHandler2.is = is; + })(StarRequestHandler || (StarRequestHandler = {})); + exports2.NullLogger = Object.freeze({ + error: () => { + }, + warn: () => { + }, + info: () => { + }, + log: () => { + } + }); + var Trace; + (function(Trace2) { + Trace2[Trace2["Off"] = 0] = "Off"; + Trace2[Trace2["Messages"] = 1] = "Messages"; + Trace2[Trace2["Compact"] = 2] = "Compact"; + Trace2[Trace2["Verbose"] = 3] = "Verbose"; + })(Trace || (exports2.Trace = Trace = {})); + var TraceValues; + (function(TraceValues2) { + TraceValues2.Off = "off"; + TraceValues2.Messages = "messages"; + TraceValues2.Compact = "compact"; + TraceValues2.Verbose = "verbose"; + })(TraceValues || (exports2.TraceValues = TraceValues = {})); + (function(Trace2) { + function fromString(value) { + if (!Is.string(value)) { + return Trace2.Off; + } + value = value.toLowerCase(); + switch (value) { + case "off": + return Trace2.Off; + case "messages": + return Trace2.Messages; + case "compact": + return Trace2.Compact; + case "verbose": + return Trace2.Verbose; + default: + return Trace2.Off; + } + } + Trace2.fromString = fromString; + function toString(value) { + switch (value) { + case Trace2.Off: + return "off"; + case Trace2.Messages: + return "messages"; + case Trace2.Compact: + return "compact"; + case Trace2.Verbose: + return "verbose"; + default: + return "off"; + } + } + Trace2.toString = toString; + })(Trace || (exports2.Trace = Trace = {})); + var TraceFormat; + (function(TraceFormat2) { + TraceFormat2["Text"] = "text"; + TraceFormat2["JSON"] = "json"; + })(TraceFormat || (exports2.TraceFormat = TraceFormat = {})); + (function(TraceFormat2) { + function fromString(value) { + if (!Is.string(value)) { + return TraceFormat2.Text; + } + value = value.toLowerCase(); + if (value === "json") { + return TraceFormat2.JSON; + } else { + return TraceFormat2.Text; + } + } + TraceFormat2.fromString = fromString; + })(TraceFormat || (exports2.TraceFormat = TraceFormat = {})); + var SetTraceNotification; + (function(SetTraceNotification2) { + SetTraceNotification2.type = new messages_1.NotificationType("$/setTrace"); + })(SetTraceNotification || (exports2.SetTraceNotification = SetTraceNotification = {})); + var LogTraceNotification; + (function(LogTraceNotification2) { + LogTraceNotification2.type = new messages_1.NotificationType("$/logTrace"); + })(LogTraceNotification || (exports2.LogTraceNotification = LogTraceNotification = {})); + var ConnectionErrors; + (function(ConnectionErrors2) { + ConnectionErrors2[ConnectionErrors2["Closed"] = 1] = "Closed"; + ConnectionErrors2[ConnectionErrors2["Disposed"] = 2] = "Disposed"; + ConnectionErrors2[ConnectionErrors2["AlreadyListening"] = 3] = "AlreadyListening"; + })(ConnectionErrors || (exports2.ConnectionErrors = ConnectionErrors = {})); + var ConnectionError = class _ConnectionError extends Error { + constructor(code, message) { + super(message); + this.code = code; + Object.setPrototypeOf(this, _ConnectionError.prototype); + } + }; + exports2.ConnectionError = ConnectionError; + var ConnectionStrategy; + (function(ConnectionStrategy2) { + function is(value) { + const candidate = value; + return candidate && Is.func(candidate.cancelUndispatched); + } + ConnectionStrategy2.is = is; + })(ConnectionStrategy || (exports2.ConnectionStrategy = ConnectionStrategy = {})); + var IdCancellationReceiverStrategy; + (function(IdCancellationReceiverStrategy2) { + function is(value) { + const candidate = value; + return candidate && (candidate.kind === void 0 || candidate.kind === "id") && Is.func(candidate.createCancellationTokenSource) && (candidate.dispose === void 0 || Is.func(candidate.dispose)); + } + IdCancellationReceiverStrategy2.is = is; + })(IdCancellationReceiverStrategy || (exports2.IdCancellationReceiverStrategy = IdCancellationReceiverStrategy = {})); + var RequestCancellationReceiverStrategy; + (function(RequestCancellationReceiverStrategy2) { + function is(value) { + const candidate = value; + return candidate && candidate.kind === "request" && Is.func(candidate.createCancellationTokenSource) && (candidate.dispose === void 0 || Is.func(candidate.dispose)); + } + RequestCancellationReceiverStrategy2.is = is; + })(RequestCancellationReceiverStrategy || (exports2.RequestCancellationReceiverStrategy = RequestCancellationReceiverStrategy = {})); + var CancellationReceiverStrategy; + (function(CancellationReceiverStrategy2) { + CancellationReceiverStrategy2.Message = Object.freeze({ + createCancellationTokenSource(_) { + return new cancellation_1.CancellationTokenSource(); + } + }); + function is(value) { + return IdCancellationReceiverStrategy.is(value) || RequestCancellationReceiverStrategy.is(value); + } + CancellationReceiverStrategy2.is = is; + })(CancellationReceiverStrategy || (exports2.CancellationReceiverStrategy = CancellationReceiverStrategy = {})); + var CancellationSenderStrategy; + (function(CancellationSenderStrategy2) { + CancellationSenderStrategy2.Message = Object.freeze({ + sendCancellation(conn, id) { + return conn.sendNotification(CancelNotification.type, { id }); + }, + cleanup(_) { + } + }); + function is(value) { + const candidate = value; + return candidate && Is.func(candidate.sendCancellation) && Is.func(candidate.cleanup); + } + CancellationSenderStrategy2.is = is; + })(CancellationSenderStrategy || (exports2.CancellationSenderStrategy = CancellationSenderStrategy = {})); + var CancellationStrategy; + (function(CancellationStrategy2) { + CancellationStrategy2.Message = Object.freeze({ + receiver: CancellationReceiverStrategy.Message, + sender: CancellationSenderStrategy.Message + }); + function is(value) { + const candidate = value; + return candidate && CancellationReceiverStrategy.is(candidate.receiver) && CancellationSenderStrategy.is(candidate.sender); + } + CancellationStrategy2.is = is; + })(CancellationStrategy || (exports2.CancellationStrategy = CancellationStrategy = {})); + var MessageStrategy; + (function(MessageStrategy2) { + function is(value) { + const candidate = value; + return candidate && Is.func(candidate.handleMessage); + } + MessageStrategy2.is = is; + })(MessageStrategy || (exports2.MessageStrategy = MessageStrategy = {})); + var ConnectionOptions; + (function(ConnectionOptions2) { + function is(value) { + const candidate = value; + return candidate && (CancellationStrategy.is(candidate.cancellationStrategy) || ConnectionStrategy.is(candidate.connectionStrategy) || MessageStrategy.is(candidate.messageStrategy)); + } + ConnectionOptions2.is = is; + })(ConnectionOptions || (exports2.ConnectionOptions = ConnectionOptions = {})); + var ConnectionState; + (function(ConnectionState2) { + ConnectionState2[ConnectionState2["New"] = 1] = "New"; + ConnectionState2[ConnectionState2["Listening"] = 2] = "Listening"; + ConnectionState2[ConnectionState2["Closed"] = 3] = "Closed"; + ConnectionState2[ConnectionState2["Disposed"] = 4] = "Disposed"; + })(ConnectionState || (ConnectionState = {})); + function createMessageConnection(messageReader, messageWriter, _logger, options) { + const logger = _logger !== void 0 ? _logger : exports2.NullLogger; + let sequenceNumber = 0; + let notificationSequenceNumber = 0; + let unknownResponseSequenceNumber = 0; + const version2 = "2.0"; + let starRequestHandler = void 0; + const requestHandlers = /* @__PURE__ */ new Map(); + let starNotificationHandler = void 0; + const notificationHandlers = /* @__PURE__ */ new Map(); + const progressHandlers = /* @__PURE__ */ new Map(); + let timer; + let messageQueue = new linkedMap_1.LinkedMap(); + let responsePromises = /* @__PURE__ */ new Map(); + let knownCanceledRequests = /* @__PURE__ */ new Set(); + let requestTokens = /* @__PURE__ */ new Map(); + let trace = Trace.Off; + let traceFormat = TraceFormat.Text; + let tracer; + let state = ConnectionState.New; + const errorEmitter = new events_1.Emitter(); + const closeEmitter = new events_1.Emitter(); + const unhandledNotificationEmitter = new events_1.Emitter(); + const unhandledProgressEmitter = new events_1.Emitter(); + const disposeEmitter = new events_1.Emitter(); + const cancellationStrategy = options && options.cancellationStrategy ? options.cancellationStrategy : CancellationStrategy.Message; + function createRequestQueueKey(id) { + if (id === null) { + throw new Error(`Can't send requests with id null since the response can't be correlated.`); + } + return "req-" + id.toString(); + } + function createResponseQueueKey(id) { + if (id === null) { + return "res-unknown-" + (++unknownResponseSequenceNumber).toString(); + } else { + return "res-" + id.toString(); + } + } + function createNotificationQueueKey() { + return "not-" + (++notificationSequenceNumber).toString(); + } + function addMessageToQueue(queue, message) { + if (messages_1.Message.isRequest(message)) { + queue.set(createRequestQueueKey(message.id), message); + } else if (messages_1.Message.isResponse(message)) { + queue.set(createResponseQueueKey(message.id), message); + } else { + queue.set(createNotificationQueueKey(), message); + } + } + function cancelUndispatched(_message) { + return void 0; + } + function isListening() { + return state === ConnectionState.Listening; + } + function isClosed() { + return state === ConnectionState.Closed; + } + function isDisposed() { + return state === ConnectionState.Disposed; + } + function closeHandler() { + if (state === ConnectionState.New || state === ConnectionState.Listening) { + state = ConnectionState.Closed; + closeEmitter.fire(void 0); + } + } + function readErrorHandler(error) { + errorEmitter.fire([error, void 0, void 0]); + } + function writeErrorHandler(data) { + errorEmitter.fire(data); + } + messageReader.onClose(closeHandler); + messageReader.onError(readErrorHandler); + messageWriter.onClose(closeHandler); + messageWriter.onError(writeErrorHandler); + function triggerMessageQueue() { + if (timer || messageQueue.size === 0) { + return; + } + timer = (0, ral_1.default)().timer.setImmediate(() => { + timer = void 0; + processMessageQueue(); + }); + } + function handleMessage(message) { + if (messages_1.Message.isRequest(message)) { + handleRequest(message); + } else if (messages_1.Message.isNotification(message)) { + handleNotification(message); + } else if (messages_1.Message.isResponse(message)) { + handleResponse(message); + } else { + handleInvalidMessage(message); + } + } + function processMessageQueue() { + if (messageQueue.size === 0) { + return; + } + const message = messageQueue.shift(); + try { + const messageStrategy = options?.messageStrategy; + if (MessageStrategy.is(messageStrategy)) { + messageStrategy.handleMessage(message, handleMessage); + } else { + handleMessage(message); + } + } finally { + triggerMessageQueue(); + } + } + const callback = (message) => { + try { + if (messages_1.Message.isNotification(message) && message.method === CancelNotification.type.method) { + const cancelId = message.params.id; + const key = createRequestQueueKey(cancelId); + const toCancel = messageQueue.get(key); + if (messages_1.Message.isRequest(toCancel)) { + const strategy = options?.connectionStrategy; + const response = strategy && strategy.cancelUndispatched ? strategy.cancelUndispatched(toCancel, cancelUndispatched) : cancelUndispatched(toCancel); + if (response && (response.error !== void 0 || response.result !== void 0)) { + messageQueue.delete(key); + requestTokens.delete(cancelId); + response.id = toCancel.id; + traceSendingResponse(response, message.method, Date.now()); + messageWriter.write(response).catch(() => logger.error(`Sending response for canceled message failed.`)); + return; + } + } + const cancellationToken = requestTokens.get(cancelId); + if (cancellationToken !== void 0) { + cancellationToken.cancel(); + traceReceivedNotification(message); + return; + } else { + knownCanceledRequests.add(cancelId); + } + } + addMessageToQueue(messageQueue, message); + } finally { + triggerMessageQueue(); + } + }; + function handleRequest(requestMessage) { + if (isDisposed()) { + return; + } + function reply(resultOrError, method, startTime2) { + const message = { + jsonrpc: version2, + id: requestMessage.id + }; + if (resultOrError instanceof messages_1.ResponseError) { + message.error = resultOrError.toJson(); + } else { + message.result = resultOrError === void 0 ? null : resultOrError; + } + traceSendingResponse(message, method, startTime2); + messageWriter.write(message).catch(() => logger.error(`Sending response failed.`)); + } + function replyError(error, method, startTime2) { + const message = { + jsonrpc: version2, + id: requestMessage.id, + error: error.toJson() + }; + traceSendingResponse(message, method, startTime2); + messageWriter.write(message).catch(() => logger.error(`Sending response failed.`)); + } + function replySuccess(result, method, startTime2) { + if (result === void 0) { + result = null; + } + const message = { + jsonrpc: version2, + id: requestMessage.id, + result + }; + traceSendingResponse(message, method, startTime2); + messageWriter.write(message).catch(() => logger.error(`Sending response failed.`)); + } + traceReceivedRequest(requestMessage); + const element = requestHandlers.get(requestMessage.method); + let type; + let requestHandler; + if (element) { + type = element.type; + requestHandler = element.handler; + } + const startTime = Date.now(); + if (requestHandler || starRequestHandler) { + const tokenKey = requestMessage.id ?? String(Date.now()); + const cancellationSource = IdCancellationReceiverStrategy.is(cancellationStrategy.receiver) ? cancellationStrategy.receiver.createCancellationTokenSource(tokenKey) : cancellationStrategy.receiver.createCancellationTokenSource(requestMessage); + if (requestMessage.id !== null && knownCanceledRequests.has(requestMessage.id)) { + cancellationSource.cancel(); + } + if (requestMessage.id !== null) { + requestTokens.set(tokenKey, cancellationSource); + } + try { + let handlerResult; + if (requestHandler) { + if (requestMessage.params === void 0) { + if (type !== void 0 && type.numberOfParams !== 0) { + replyError(new messages_1.ResponseError(messages_1.ErrorCodes.InvalidParams, `Request ${requestMessage.method} defines ${type.numberOfParams} params but received none.`), requestMessage.method, startTime); + return; + } + handlerResult = requestHandler(cancellationSource.token); + } else if (Array.isArray(requestMessage.params)) { + if (type !== void 0 && type.parameterStructures === messages_1.ParameterStructures.byName) { + replyError(new messages_1.ResponseError(messages_1.ErrorCodes.InvalidParams, `Request ${requestMessage.method} defines parameters by name but received parameters by position`), requestMessage.method, startTime); + return; + } + handlerResult = requestHandler(...requestMessage.params, cancellationSource.token); + } else { + if (type !== void 0 && type.parameterStructures === messages_1.ParameterStructures.byPosition) { + replyError(new messages_1.ResponseError(messages_1.ErrorCodes.InvalidParams, `Request ${requestMessage.method} defines parameters by position but received parameters by name`), requestMessage.method, startTime); + return; + } + handlerResult = requestHandler(requestMessage.params, cancellationSource.token); + } + } else if (starRequestHandler) { + handlerResult = starRequestHandler(requestMessage.method, requestMessage.params, cancellationSource.token); + } + const promise = handlerResult; + if (!handlerResult) { + requestTokens.delete(tokenKey); + replySuccess(handlerResult, requestMessage.method, startTime); + } else if (promise.then) { + promise.then((resultOrError) => { + requestTokens.delete(tokenKey); + reply(resultOrError, requestMessage.method, startTime); + }, (error) => { + requestTokens.delete(tokenKey); + if (error instanceof messages_1.ResponseError) { + replyError(error, requestMessage.method, startTime); + } else if (error && Is.string(error.message)) { + replyError(new messages_1.ResponseError(messages_1.ErrorCodes.InternalError, `Request ${requestMessage.method} failed with message: ${error.message}`), requestMessage.method, startTime); + } else { + replyError(new messages_1.ResponseError(messages_1.ErrorCodes.InternalError, `Request ${requestMessage.method} failed unexpectedly without providing any details.`), requestMessage.method, startTime); + } + }); + } else { + requestTokens.delete(tokenKey); + reply(handlerResult, requestMessage.method, startTime); + } + } catch (error) { + requestTokens.delete(tokenKey); + if (error instanceof messages_1.ResponseError) { + reply(error, requestMessage.method, startTime); + } else if (error && Is.string(error.message)) { + replyError(new messages_1.ResponseError(messages_1.ErrorCodes.InternalError, `Request ${requestMessage.method} failed with message: ${error.message}`), requestMessage.method, startTime); + } else { + replyError(new messages_1.ResponseError(messages_1.ErrorCodes.InternalError, `Request ${requestMessage.method} failed unexpectedly without providing any details.`), requestMessage.method, startTime); + } + } + } else { + replyError(new messages_1.ResponseError(messages_1.ErrorCodes.MethodNotFound, `Unhandled method ${requestMessage.method}`), requestMessage.method, startTime); + } + } + function handleResponse(responseMessage) { + if (isDisposed()) { + return; + } + if (responseMessage.id === null) { + if (responseMessage.error) { + logger.error(`Received response message without id: Error is: +${JSON.stringify(responseMessage.error, void 0, 4)}`); + } else { + logger.error(`Received response message without id. No further error information provided.`); + } + } else { + const key = responseMessage.id; + const responsePromise = responsePromises.get(key); + traceReceivedResponse(responseMessage, responsePromise); + if (responsePromise !== void 0) { + responsePromises.delete(key); + try { + if (responseMessage.error) { + const error = responseMessage.error; + responsePromise.reject(new messages_1.ResponseError(error.code, error.message, error.data)); + } else if (responseMessage.result !== void 0) { + responsePromise.resolve(responseMessage.result); + } else { + throw new Error("Should never happen."); + } + } catch (error) { + if (error.message) { + logger.error(`Response handler '${responsePromise.method}' failed with message: ${error.message}`); + } else { + logger.error(`Response handler '${responsePromise.method}' failed unexpectedly.`); + } + } + } + } + } + function handleNotification(message) { + if (isDisposed()) { + return; + } + let type = void 0; + let notificationHandler; + if (message.method === CancelNotification.type.method) { + const cancelId = message.params.id; + knownCanceledRequests.delete(cancelId); + traceReceivedNotification(message); + return; + } else { + const element = notificationHandlers.get(message.method); + if (element) { + notificationHandler = element.handler; + type = element.type; + } + } + if (notificationHandler || starNotificationHandler) { + try { + traceReceivedNotification(message); + if (notificationHandler) { + if (message.params === void 0) { + if (type !== void 0) { + if (type.numberOfParams !== 0 && type.parameterStructures !== messages_1.ParameterStructures.byName) { + logger.error(`Notification ${message.method} defines ${type.numberOfParams} params but received none.`); + } + } + notificationHandler(); + } else if (Array.isArray(message.params)) { + const params = message.params; + if (message.method === ProgressNotification.type.method && params.length === 2 && ProgressToken.is(params[0])) { + notificationHandler({ token: params[0], value: params[1] }); + } else { + if (type !== void 0) { + if (type.parameterStructures === messages_1.ParameterStructures.byName) { + logger.error(`Notification ${message.method} defines parameters by name but received parameters by position`); + } + if (type.numberOfParams !== message.params.length) { + logger.error(`Notification ${message.method} defines ${type.numberOfParams} params but received ${params.length} arguments`); + } + } + notificationHandler(...params); + } + } else { + if (type !== void 0 && type.parameterStructures === messages_1.ParameterStructures.byPosition) { + logger.error(`Notification ${message.method} defines parameters by position but received parameters by name`); + } + notificationHandler(message.params); + } + } else if (starNotificationHandler) { + starNotificationHandler(message.method, message.params); + } + } catch (error) { + if (error.message) { + logger.error(`Notification handler '${message.method}' failed with message: ${error.message}`); + } else { + logger.error(`Notification handler '${message.method}' failed unexpectedly.`); + } + } + } else { + unhandledNotificationEmitter.fire(message); + } + } + function handleInvalidMessage(message) { + if (!message) { + logger.error("Received empty message."); + return; + } + logger.error(`Received message which is neither a response nor a notification message: +${JSON.stringify(message, null, 4)}`); + const responseMessage = message; + if (Is.string(responseMessage.id) || Is.number(responseMessage.id)) { + const key = responseMessage.id; + const responseHandler = responsePromises.get(key); + if (responseHandler) { + responseHandler.reject(new Error("The received response has neither a result nor an error property.")); + } + } + } + function stringifyTrace(params) { + if (params === void 0 || params === null) { + return void 0; + } + switch (trace) { + case Trace.Verbose: + return JSON.stringify(params, null, 4); + case Trace.Compact: + return JSON.stringify(params); + default: + return void 0; + } + } + function traceSendingRequest(message) { + if (trace === Trace.Off || !tracer) { + return; + } + if (traceFormat === TraceFormat.Text) { + let data = void 0; + if ((trace === Trace.Verbose || trace === Trace.Compact) && message.params) { + data = `Params: ${stringifyTrace(message.params)} + +`; + } + tracer.log(`Sending request '${message.method} - (${message.id})'.`, data); + } else { + logLSPMessage("send-request", message); + } + } + function traceSendingNotification(message) { + if (trace === Trace.Off || !tracer) { + return; + } + if (traceFormat === TraceFormat.Text) { + let data = void 0; + if (trace === Trace.Verbose || trace === Trace.Compact) { + if (message.params) { + data = `Params: ${stringifyTrace(message.params)} + +`; + } else { + data = "No parameters provided.\n\n"; + } + } + tracer.log(`Sending notification '${message.method}'.`, data); + } else { + logLSPMessage("send-notification", message); + } + } + function traceSendingResponse(message, method, startTime) { + if (trace === Trace.Off || !tracer) { + return; + } + if (traceFormat === TraceFormat.Text) { + let data = void 0; + if (trace === Trace.Verbose || trace === Trace.Compact) { + if (message.error && message.error.data) { + data = `Error data: ${stringifyTrace(message.error.data)} + +`; + } else { + if (message.result) { + data = `Result: ${stringifyTrace(message.result)} + +`; + } else if (message.error === void 0) { + data = "No result returned.\n\n"; + } + } + } + tracer.log(`Sending response '${method} - (${message.id})'. Processing request took ${Date.now() - startTime}ms`, data); + } else { + logLSPMessage("send-response", message); + } + } + function traceReceivedRequest(message) { + if (trace === Trace.Off || !tracer) { + return; + } + if (traceFormat === TraceFormat.Text) { + let data = void 0; + if ((trace === Trace.Verbose || trace === Trace.Compact) && message.params) { + data = `Params: ${stringifyTrace(message.params)} + +`; + } + tracer.log(`Received request '${message.method} - (${message.id})'.`, data); + } else { + logLSPMessage("receive-request", message); + } + } + function traceReceivedNotification(message) { + if (trace === Trace.Off || !tracer || message.method === LogTraceNotification.type.method) { + return; + } + if (traceFormat === TraceFormat.Text) { + let data = void 0; + if (trace === Trace.Verbose || trace === Trace.Compact) { + if (message.params) { + data = `Params: ${stringifyTrace(message.params)} + +`; + } else { + data = "No parameters provided.\n\n"; + } + } + tracer.log(`Received notification '${message.method}'.`, data); + } else { + logLSPMessage("receive-notification", message); + } + } + function traceReceivedResponse(message, responsePromise) { + if (trace === Trace.Off || !tracer) { + return; + } + if (traceFormat === TraceFormat.Text) { + let data = void 0; + if (trace === Trace.Verbose || trace === Trace.Compact) { + if (message.error && message.error.data) { + data = `Error data: ${stringifyTrace(message.error.data)} + +`; + } else { + if (message.result) { + data = `Result: ${stringifyTrace(message.result)} + +`; + } else if (message.error === void 0) { + data = "No result returned.\n\n"; + } + } + } + if (responsePromise) { + const error = message.error ? ` Request failed: ${message.error.message} (${message.error.code}).` : ""; + tracer.log(`Received response '${responsePromise.method} - (${message.id})' in ${Date.now() - responsePromise.timerStart}ms.${error}`, data); + } else { + tracer.log(`Received response ${message.id} without active response promise.`, data); + } + } else { + logLSPMessage("receive-response", message); + } + } + function logLSPMessage(type, message) { + if (!tracer || trace === Trace.Off) { + return; + } + const lspMessage = { + isLSPMessage: true, + type, + message, + timestamp: Date.now() + }; + tracer.log(lspMessage); + } + function throwIfClosedOrDisposed() { + if (isClosed()) { + throw new ConnectionError(ConnectionErrors.Closed, "Connection is closed."); + } + if (isDisposed()) { + throw new ConnectionError(ConnectionErrors.Disposed, "Connection is disposed."); + } + } + function throwIfListening() { + if (isListening()) { + throw new ConnectionError(ConnectionErrors.AlreadyListening, "Connection is already listening"); + } + } + function throwIfNotListening() { + if (!isListening()) { + throw new Error("Call listen() first."); + } + } + function undefinedToNull(param) { + if (param === void 0) { + return null; + } else { + return param; + } + } + function nullToUndefined(param) { + if (param === null) { + return void 0; + } else { + return param; + } + } + function isNamedParam(param) { + return param !== void 0 && param !== null && !Array.isArray(param) && typeof param === "object"; + } + function computeSingleParam(parameterStructures, param) { + switch (parameterStructures) { + case messages_1.ParameterStructures.auto: + if (isNamedParam(param)) { + return nullToUndefined(param); + } else { + return [undefinedToNull(param)]; + } + case messages_1.ParameterStructures.byName: + if (!isNamedParam(param)) { + throw new Error(`Received parameters by name but param is not an object literal.`); + } + return nullToUndefined(param); + case messages_1.ParameterStructures.byPosition: + return [undefinedToNull(param)]; + default: + throw new Error(`Unknown parameter structure ${parameterStructures.toString()}`); + } + } + function computeMessageParams(type, params) { + let result; + const numberOfParams = type.numberOfParams; + switch (numberOfParams) { + case 0: + result = void 0; + break; + case 1: + result = computeSingleParam(type.parameterStructures, params[0]); + break; + default: + result = []; + for (let i = 0; i < params.length && i < numberOfParams; i++) { + result.push(undefinedToNull(params[i])); + } + if (params.length < numberOfParams) { + for (let i = params.length; i < numberOfParams; i++) { + result.push(null); + } + } + break; + } + return result; + } + const connection = { + sendNotification: (type, ...args) => { + throwIfClosedOrDisposed(); + let method; + let messageParams; + if (Is.string(type)) { + method = type; + const first = args[0]; + let paramStart = 0; + let parameterStructures = messages_1.ParameterStructures.auto; + if (messages_1.ParameterStructures.is(first)) { + paramStart = 1; + parameterStructures = first; + } + let paramEnd = args.length; + const numberOfParams = paramEnd - paramStart; + switch (numberOfParams) { + case 0: + messageParams = void 0; + break; + case 1: + messageParams = computeSingleParam(parameterStructures, args[paramStart]); + break; + default: + if (parameterStructures === messages_1.ParameterStructures.byName) { + throw new Error(`Received ${numberOfParams} parameters for 'by Name' notification parameter structure.`); + } + messageParams = args.slice(paramStart, paramEnd).map((value) => undefinedToNull(value)); + break; + } + } else { + const params = args; + method = type.method; + messageParams = computeMessageParams(type, params); + } + const notificationMessage = { + jsonrpc: version2, + method, + params: messageParams + }; + traceSendingNotification(notificationMessage); + return messageWriter.write(notificationMessage).catch((error) => { + logger.error(`Sending notification failed.`); + throw error; + }); + }, + onNotification: (type, handler) => { + throwIfClosedOrDisposed(); + let method; + if (Is.func(type)) { + starNotificationHandler = type; + } else if (handler) { + if (Is.string(type)) { + method = type; + notificationHandlers.set(type, { type: void 0, handler }); + } else { + method = type.method; + notificationHandlers.set(type.method, { type, handler }); + } + } + return { + dispose: () => { + if (method !== void 0) { + notificationHandlers.delete(method); + } else { + starNotificationHandler = void 0; + } + } + }; + }, + onProgress: (_type, token, handler) => { + if (progressHandlers.has(token)) { + throw new Error(`Progress handler for token ${token} already registered`); + } + progressHandlers.set(token, handler); + return { + dispose: () => { + progressHandlers.delete(token); + } + }; + }, + sendProgress: (_type, token, value) => { + return connection.sendNotification(ProgressNotification.type, { token, value }); + }, + onUnhandledProgress: unhandledProgressEmitter.event, + sendRequest: (type, ...args) => { + throwIfClosedOrDisposed(); + throwIfNotListening(); + let method; + let messageParams; + let token = void 0; + if (Is.string(type)) { + method = type; + const first = args[0]; + const last = args[args.length - 1]; + let paramStart = 0; + let parameterStructures = messages_1.ParameterStructures.auto; + if (messages_1.ParameterStructures.is(first)) { + paramStart = 1; + parameterStructures = first; + } + let paramEnd = args.length; + if (cancellation_1.CancellationToken.is(last)) { + paramEnd = paramEnd - 1; + token = last; + } + const numberOfParams = paramEnd - paramStart; + switch (numberOfParams) { + case 0: + messageParams = void 0; + break; + case 1: + messageParams = computeSingleParam(parameterStructures, args[paramStart]); + break; + default: + if (parameterStructures === messages_1.ParameterStructures.byName) { + throw new Error(`Received ${numberOfParams} parameters for 'by Name' request parameter structure.`); + } + messageParams = args.slice(paramStart, paramEnd).map((value) => undefinedToNull(value)); + break; + } + } else { + const params = args; + method = type.method; + messageParams = computeMessageParams(type, params); + const numberOfParams = type.numberOfParams; + token = cancellation_1.CancellationToken.is(params[numberOfParams]) ? params[numberOfParams] : void 0; + } + const id = sequenceNumber++; + let disposable; + if (token) { + disposable = token.onCancellationRequested(() => { + const p = cancellationStrategy.sender.sendCancellation(connection, id); + if (p === void 0) { + logger.log(`Received no promise from cancellation strategy when cancelling id ${id}`); + return Promise.resolve(); + } else { + return p.catch(() => { + logger.log(`Sending cancellation messages for id ${id} failed`); + }); + } + }); + } + const requestMessage = { + jsonrpc: version2, + id, + method, + params: messageParams + }; + traceSendingRequest(requestMessage); + if (typeof cancellationStrategy.sender.enableCancellation === "function") { + cancellationStrategy.sender.enableCancellation(requestMessage); + } + return new Promise(async (resolve, reject) => { + const resolveWithCleanup = (r) => { + resolve(r); + cancellationStrategy.sender.cleanup(id); + disposable?.dispose(); + }; + const rejectWithCleanup = (r) => { + reject(r); + cancellationStrategy.sender.cleanup(id); + disposable?.dispose(); + }; + const responsePromise = { method, timerStart: Date.now(), resolve: resolveWithCleanup, reject: rejectWithCleanup }; + try { + responsePromises.set(id, responsePromise); + await messageWriter.write(requestMessage); + } catch (error) { + responsePromises.delete(id); + responsePromise.reject(new messages_1.ResponseError(messages_1.ErrorCodes.MessageWriteError, error.message ? error.message : "Unknown reason")); + logger.error(`Sending request failed.`); + throw error; + } + }); + }, + onRequest: (type, handler) => { + throwIfClosedOrDisposed(); + let method = null; + if (StarRequestHandler.is(type)) { + method = void 0; + starRequestHandler = type; + } else if (Is.string(type)) { + method = null; + if (handler !== void 0) { + method = type; + requestHandlers.set(type, { handler, type: void 0 }); + } + } else { + if (handler !== void 0) { + method = type.method; + requestHandlers.set(type.method, { type, handler }); + } + } + return { + dispose: () => { + if (method === null) { + return; + } + if (method !== void 0) { + requestHandlers.delete(method); + } else { + starRequestHandler = void 0; + } + } + }; + }, + hasPendingResponse: () => { + return responsePromises.size > 0; + }, + trace: async (_value, _tracer, sendNotificationOrTraceOptions) => { + let _sendNotification = false; + let _traceFormat = TraceFormat.Text; + if (sendNotificationOrTraceOptions !== void 0) { + if (Is.boolean(sendNotificationOrTraceOptions)) { + _sendNotification = sendNotificationOrTraceOptions; + } else { + _sendNotification = sendNotificationOrTraceOptions.sendNotification || false; + _traceFormat = sendNotificationOrTraceOptions.traceFormat || TraceFormat.Text; + } + } + trace = _value; + traceFormat = _traceFormat; + if (trace === Trace.Off) { + tracer = void 0; + } else { + tracer = _tracer; + } + if (_sendNotification && !isClosed() && !isDisposed()) { + await connection.sendNotification(SetTraceNotification.type, { value: Trace.toString(_value) }); + } + }, + onError: errorEmitter.event, + onClose: closeEmitter.event, + onUnhandledNotification: unhandledNotificationEmitter.event, + onDispose: disposeEmitter.event, + end: () => { + messageWriter.end(); + }, + dispose: () => { + if (isDisposed()) { + return; + } + state = ConnectionState.Disposed; + disposeEmitter.fire(void 0); + const error = new messages_1.ResponseError(messages_1.ErrorCodes.PendingResponseRejected, "Pending response rejected since connection got disposed"); + for (const promise of responsePromises.values()) { + promise.reject(error); + } + responsePromises = /* @__PURE__ */ new Map(); + requestTokens = /* @__PURE__ */ new Map(); + knownCanceledRequests = /* @__PURE__ */ new Set(); + messageQueue = new linkedMap_1.LinkedMap(); + if (Is.func(messageWriter.dispose)) { + messageWriter.dispose(); + } + if (Is.func(messageReader.dispose)) { + messageReader.dispose(); + } + }, + listen: () => { + throwIfClosedOrDisposed(); + throwIfListening(); + state = ConnectionState.Listening; + messageReader.listen(callback); + }, + inspect: () => { + (0, ral_1.default)().console.log("inspect"); + } + }; + connection.onNotification(LogTraceNotification.type, (params) => { + if (trace === Trace.Off || !tracer) { + return; + } + const verbose = trace === Trace.Verbose || trace === Trace.Compact; + tracer.log(params.message, verbose ? params.verbose : void 0); + }); + connection.onNotification(ProgressNotification.type, (params) => { + const handler = progressHandlers.get(params.token); + if (handler) { + handler(params.value); + } else { + unhandledProgressEmitter.fire(params); + } + }); + return connection; + } + exports2.createMessageConnection = createMessageConnection; + } +}); + +// ../../node_modules/vscode-jsonrpc/lib/common/api.js +var require_api = __commonJS({ + "../../node_modules/vscode-jsonrpc/lib/common/api.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.ProgressType = exports2.ProgressToken = exports2.createMessageConnection = exports2.NullLogger = exports2.ConnectionOptions = exports2.ConnectionStrategy = exports2.AbstractMessageBuffer = exports2.WriteableStreamMessageWriter = exports2.AbstractMessageWriter = exports2.MessageWriter = exports2.ReadableStreamMessageReader = exports2.AbstractMessageReader = exports2.MessageReader = exports2.SharedArrayReceiverStrategy = exports2.SharedArraySenderStrategy = exports2.CancellationToken = exports2.CancellationTokenSource = exports2.Emitter = exports2.Event = exports2.Disposable = exports2.LRUCache = exports2.Touch = exports2.LinkedMap = exports2.ParameterStructures = exports2.NotificationType9 = exports2.NotificationType8 = exports2.NotificationType7 = exports2.NotificationType6 = exports2.NotificationType5 = exports2.NotificationType4 = exports2.NotificationType3 = exports2.NotificationType2 = exports2.NotificationType1 = exports2.NotificationType0 = exports2.NotificationType = exports2.ErrorCodes = exports2.ResponseError = exports2.RequestType9 = exports2.RequestType8 = exports2.RequestType7 = exports2.RequestType6 = exports2.RequestType5 = exports2.RequestType4 = exports2.RequestType3 = exports2.RequestType2 = exports2.RequestType1 = exports2.RequestType0 = exports2.RequestType = exports2.Message = exports2.RAL = void 0; + exports2.MessageStrategy = exports2.CancellationStrategy = exports2.CancellationSenderStrategy = exports2.CancellationReceiverStrategy = exports2.ConnectionError = exports2.ConnectionErrors = exports2.LogTraceNotification = exports2.SetTraceNotification = exports2.TraceFormat = exports2.TraceValues = exports2.Trace = void 0; + var messages_1 = require_messages(); + Object.defineProperty(exports2, "Message", { enumerable: true, get: function() { + return messages_1.Message; + } }); + Object.defineProperty(exports2, "RequestType", { enumerable: true, get: function() { + return messages_1.RequestType; + } }); + Object.defineProperty(exports2, "RequestType0", { enumerable: true, get: function() { + return messages_1.RequestType0; + } }); + Object.defineProperty(exports2, "RequestType1", { enumerable: true, get: function() { + return messages_1.RequestType1; + } }); + Object.defineProperty(exports2, "RequestType2", { enumerable: true, get: function() { + return messages_1.RequestType2; + } }); + Object.defineProperty(exports2, "RequestType3", { enumerable: true, get: function() { + return messages_1.RequestType3; + } }); + Object.defineProperty(exports2, "RequestType4", { enumerable: true, get: function() { + return messages_1.RequestType4; + } }); + Object.defineProperty(exports2, "RequestType5", { enumerable: true, get: function() { + return messages_1.RequestType5; + } }); + Object.defineProperty(exports2, "RequestType6", { enumerable: true, get: function() { + return messages_1.RequestType6; + } }); + Object.defineProperty(exports2, "RequestType7", { enumerable: true, get: function() { + return messages_1.RequestType7; + } }); + Object.defineProperty(exports2, "RequestType8", { enumerable: true, get: function() { + return messages_1.RequestType8; + } }); + Object.defineProperty(exports2, "RequestType9", { enumerable: true, get: function() { + return messages_1.RequestType9; + } }); + Object.defineProperty(exports2, "ResponseError", { enumerable: true, get: function() { + return messages_1.ResponseError; + } }); + Object.defineProperty(exports2, "ErrorCodes", { enumerable: true, get: function() { + return messages_1.ErrorCodes; + } }); + Object.defineProperty(exports2, "NotificationType", { enumerable: true, get: function() { + return messages_1.NotificationType; + } }); + Object.defineProperty(exports2, "NotificationType0", { enumerable: true, get: function() { + return messages_1.NotificationType0; + } }); + Object.defineProperty(exports2, "NotificationType1", { enumerable: true, get: function() { + return messages_1.NotificationType1; + } }); + Object.defineProperty(exports2, "NotificationType2", { enumerable: true, get: function() { + return messages_1.NotificationType2; + } }); + Object.defineProperty(exports2, "NotificationType3", { enumerable: true, get: function() { + return messages_1.NotificationType3; + } }); + Object.defineProperty(exports2, "NotificationType4", { enumerable: true, get: function() { + return messages_1.NotificationType4; + } }); + Object.defineProperty(exports2, "NotificationType5", { enumerable: true, get: function() { + return messages_1.NotificationType5; + } }); + Object.defineProperty(exports2, "NotificationType6", { enumerable: true, get: function() { + return messages_1.NotificationType6; + } }); + Object.defineProperty(exports2, "NotificationType7", { enumerable: true, get: function() { + return messages_1.NotificationType7; + } }); + Object.defineProperty(exports2, "NotificationType8", { enumerable: true, get: function() { + return messages_1.NotificationType8; + } }); + Object.defineProperty(exports2, "NotificationType9", { enumerable: true, get: function() { + return messages_1.NotificationType9; + } }); + Object.defineProperty(exports2, "ParameterStructures", { enumerable: true, get: function() { + return messages_1.ParameterStructures; + } }); + var linkedMap_1 = require_linkedMap(); + Object.defineProperty(exports2, "LinkedMap", { enumerable: true, get: function() { + return linkedMap_1.LinkedMap; + } }); + Object.defineProperty(exports2, "LRUCache", { enumerable: true, get: function() { + return linkedMap_1.LRUCache; + } }); + Object.defineProperty(exports2, "Touch", { enumerable: true, get: function() { + return linkedMap_1.Touch; + } }); + var disposable_1 = require_disposable(); + Object.defineProperty(exports2, "Disposable", { enumerable: true, get: function() { + return disposable_1.Disposable; + } }); + var events_1 = require_events(); + Object.defineProperty(exports2, "Event", { enumerable: true, get: function() { + return events_1.Event; + } }); + Object.defineProperty(exports2, "Emitter", { enumerable: true, get: function() { + return events_1.Emitter; + } }); + var cancellation_1 = require_cancellation(); + Object.defineProperty(exports2, "CancellationTokenSource", { enumerable: true, get: function() { + return cancellation_1.CancellationTokenSource; + } }); + Object.defineProperty(exports2, "CancellationToken", { enumerable: true, get: function() { + return cancellation_1.CancellationToken; + } }); + var sharedArrayCancellation_1 = require_sharedArrayCancellation(); + Object.defineProperty(exports2, "SharedArraySenderStrategy", { enumerable: true, get: function() { + return sharedArrayCancellation_1.SharedArraySenderStrategy; + } }); + Object.defineProperty(exports2, "SharedArrayReceiverStrategy", { enumerable: true, get: function() { + return sharedArrayCancellation_1.SharedArrayReceiverStrategy; + } }); + var messageReader_1 = require_messageReader(); + Object.defineProperty(exports2, "MessageReader", { enumerable: true, get: function() { + return messageReader_1.MessageReader; + } }); + Object.defineProperty(exports2, "AbstractMessageReader", { enumerable: true, get: function() { + return messageReader_1.AbstractMessageReader; + } }); + Object.defineProperty(exports2, "ReadableStreamMessageReader", { enumerable: true, get: function() { + return messageReader_1.ReadableStreamMessageReader; + } }); + var messageWriter_1 = require_messageWriter(); + Object.defineProperty(exports2, "MessageWriter", { enumerable: true, get: function() { + return messageWriter_1.MessageWriter; + } }); + Object.defineProperty(exports2, "AbstractMessageWriter", { enumerable: true, get: function() { + return messageWriter_1.AbstractMessageWriter; + } }); + Object.defineProperty(exports2, "WriteableStreamMessageWriter", { enumerable: true, get: function() { + return messageWriter_1.WriteableStreamMessageWriter; + } }); + var messageBuffer_1 = require_messageBuffer(); + Object.defineProperty(exports2, "AbstractMessageBuffer", { enumerable: true, get: function() { + return messageBuffer_1.AbstractMessageBuffer; + } }); + var connection_1 = require_connection(); + Object.defineProperty(exports2, "ConnectionStrategy", { enumerable: true, get: function() { + return connection_1.ConnectionStrategy; + } }); + Object.defineProperty(exports2, "ConnectionOptions", { enumerable: true, get: function() { + return connection_1.ConnectionOptions; + } }); + Object.defineProperty(exports2, "NullLogger", { enumerable: true, get: function() { + return connection_1.NullLogger; + } }); + Object.defineProperty(exports2, "createMessageConnection", { enumerable: true, get: function() { + return connection_1.createMessageConnection; + } }); + Object.defineProperty(exports2, "ProgressToken", { enumerable: true, get: function() { + return connection_1.ProgressToken; + } }); + Object.defineProperty(exports2, "ProgressType", { enumerable: true, get: function() { + return connection_1.ProgressType; + } }); + Object.defineProperty(exports2, "Trace", { enumerable: true, get: function() { + return connection_1.Trace; + } }); + Object.defineProperty(exports2, "TraceValues", { enumerable: true, get: function() { + return connection_1.TraceValues; + } }); + Object.defineProperty(exports2, "TraceFormat", { enumerable: true, get: function() { + return connection_1.TraceFormat; + } }); + Object.defineProperty(exports2, "SetTraceNotification", { enumerable: true, get: function() { + return connection_1.SetTraceNotification; + } }); + Object.defineProperty(exports2, "LogTraceNotification", { enumerable: true, get: function() { + return connection_1.LogTraceNotification; + } }); + Object.defineProperty(exports2, "ConnectionErrors", { enumerable: true, get: function() { + return connection_1.ConnectionErrors; + } }); + Object.defineProperty(exports2, "ConnectionError", { enumerable: true, get: function() { + return connection_1.ConnectionError; + } }); + Object.defineProperty(exports2, "CancellationReceiverStrategy", { enumerable: true, get: function() { + return connection_1.CancellationReceiverStrategy; + } }); + Object.defineProperty(exports2, "CancellationSenderStrategy", { enumerable: true, get: function() { + return connection_1.CancellationSenderStrategy; + } }); + Object.defineProperty(exports2, "CancellationStrategy", { enumerable: true, get: function() { + return connection_1.CancellationStrategy; + } }); + Object.defineProperty(exports2, "MessageStrategy", { enumerable: true, get: function() { + return connection_1.MessageStrategy; + } }); + var ral_1 = require_ral(); + exports2.RAL = ral_1.default; + } +}); + +// ../../node_modules/vscode-jsonrpc/lib/node/ril.js +var require_ril = __commonJS({ + "../../node_modules/vscode-jsonrpc/lib/node/ril.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + var util_1 = require("util"); + var api_1 = require_api(); + var MessageBuffer = class _MessageBuffer extends api_1.AbstractMessageBuffer { + constructor(encoding = "utf-8") { + super(encoding); + } + emptyBuffer() { + return _MessageBuffer.emptyBuffer; + } + fromString(value, encoding) { + return Buffer.from(value, encoding); + } + toString(value, encoding) { + if (value instanceof Buffer) { + return value.toString(encoding); + } else { + return new util_1.TextDecoder(encoding).decode(value); + } + } + asNative(buffer, length) { + if (length === void 0) { + return buffer instanceof Buffer ? buffer : Buffer.from(buffer); + } else { + return buffer instanceof Buffer ? buffer.slice(0, length) : Buffer.from(buffer, 0, length); + } + } + allocNative(length) { + return Buffer.allocUnsafe(length); + } + }; + MessageBuffer.emptyBuffer = Buffer.allocUnsafe(0); + var ReadableStreamWrapper = class { + constructor(stream) { + this.stream = stream; + } + onClose(listener) { + this.stream.on("close", listener); + return api_1.Disposable.create(() => this.stream.off("close", listener)); + } + onError(listener) { + this.stream.on("error", listener); + return api_1.Disposable.create(() => this.stream.off("error", listener)); + } + onEnd(listener) { + this.stream.on("end", listener); + return api_1.Disposable.create(() => this.stream.off("end", listener)); + } + onData(listener) { + this.stream.on("data", listener); + return api_1.Disposable.create(() => this.stream.off("data", listener)); + } + }; + var WritableStreamWrapper = class { + constructor(stream) { + this.stream = stream; + } + onClose(listener) { + this.stream.on("close", listener); + return api_1.Disposable.create(() => this.stream.off("close", listener)); + } + onError(listener) { + this.stream.on("error", listener); + return api_1.Disposable.create(() => this.stream.off("error", listener)); + } + onEnd(listener) { + this.stream.on("end", listener); + return api_1.Disposable.create(() => this.stream.off("end", listener)); + } + write(data, encoding) { + return new Promise((resolve, reject) => { + const callback = (error) => { + if (error === void 0 || error === null) { + resolve(); + } else { + reject(error); + } + }; + if (typeof data === "string") { + this.stream.write(data, encoding, callback); + } else { + this.stream.write(data, callback); + } + }); + } + end() { + this.stream.end(); + } + }; + var _ril = Object.freeze({ + messageBuffer: Object.freeze({ + create: (encoding) => new MessageBuffer(encoding) + }), + applicationJson: Object.freeze({ + encoder: Object.freeze({ + name: "application/json", + encode: (msg, options) => { + try { + return Promise.resolve(Buffer.from(JSON.stringify(msg, void 0, 0), options.charset)); + } catch (err) { + return Promise.reject(err); + } + } + }), + decoder: Object.freeze({ + name: "application/json", + decode: (buffer, options) => { + try { + if (buffer instanceof Buffer) { + return Promise.resolve(JSON.parse(buffer.toString(options.charset))); + } else { + return Promise.resolve(JSON.parse(new util_1.TextDecoder(options.charset).decode(buffer))); + } + } catch (err) { + return Promise.reject(err); + } + } + }) + }), + stream: Object.freeze({ + asReadableStream: (stream) => new ReadableStreamWrapper(stream), + asWritableStream: (stream) => new WritableStreamWrapper(stream) + }), + console, + timer: Object.freeze({ + setTimeout(callback, ms, ...args) { + const handle = setTimeout(callback, ms, ...args); + return { dispose: () => clearTimeout(handle) }; + }, + setImmediate(callback, ...args) { + const handle = setImmediate(callback, ...args); + return { dispose: () => clearImmediate(handle) }; + }, + setInterval(callback, ms, ...args) { + const handle = setInterval(callback, ms, ...args); + return { dispose: () => clearInterval(handle) }; + } + }) + }); + function RIL() { + return _ril; + } + (function(RIL2) { + function install() { + api_1.RAL.install(_ril); + } + RIL2.install = install; + })(RIL || (RIL = {})); + exports2.default = RIL; + } +}); + +// ../../node_modules/vscode-jsonrpc/lib/node/main.js +var require_main = __commonJS({ + "../../node_modules/vscode-jsonrpc/lib/node/main.js"(exports2) { + "use strict"; + var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) { + if (k2 === void 0) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { + return m[k]; + } }; + } + Object.defineProperty(o, k2, desc); + } : function(o, m, k, k2) { + if (k2 === void 0) k2 = k; + o[k2] = m[k]; + }); + var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p); + }; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.createMessageConnection = exports2.createServerSocketTransport = exports2.createClientSocketTransport = exports2.createServerPipeTransport = exports2.createClientPipeTransport = exports2.generateRandomPipeName = exports2.StreamMessageWriter = exports2.StreamMessageReader = exports2.SocketMessageWriter = exports2.SocketMessageReader = exports2.PortMessageWriter = exports2.PortMessageReader = exports2.IPCMessageWriter = exports2.IPCMessageReader = void 0; + var ril_1 = require_ril(); + ril_1.default.install(); + var path3 = require("path"); + var os3 = require("os"); + var crypto_1 = require("crypto"); + var net_1 = require("net"); + var api_1 = require_api(); + __exportStar(require_api(), exports2); + var IPCMessageReader = class extends api_1.AbstractMessageReader { + constructor(process9) { + super(); + this.process = process9; + let eventEmitter = this.process; + eventEmitter.on("error", (error) => this.fireError(error)); + eventEmitter.on("close", () => this.fireClose()); + } + listen(callback) { + this.process.on("message", callback); + return api_1.Disposable.create(() => this.process.off("message", callback)); } - return baseOpen({ - ...options, - target - }); }; - openApp = (name, options) => { - if (typeof name !== "string" && !Array.isArray(name)) { - throw new TypeError("Expected a valid `name`"); + exports2.IPCMessageReader = IPCMessageReader; + var IPCMessageWriter = class extends api_1.AbstractMessageWriter { + constructor(process9) { + super(); + this.process = process9; + this.errorCount = 0; + const eventEmitter = this.process; + eventEmitter.on("error", (error) => this.fireError(error)); + eventEmitter.on("close", () => this.fireClose); + } + write(msg) { + try { + if (typeof this.process.send === "function") { + this.process.send(msg, void 0, void 0, (error) => { + if (error) { + this.errorCount++; + this.handleError(error, msg); + } else { + this.errorCount = 0; + } + }); + } + return Promise.resolve(); + } catch (error) { + this.handleError(error, msg); + return Promise.reject(error); + } } - const { arguments: appArguments = [] } = options ?? {}; - if (appArguments !== void 0 && appArguments !== null && !Array.isArray(appArguments)) { - throw new TypeError("Expected `appArguments` as Array type"); + handleError(error, msg) { + this.errorCount++; + this.fireError(error, msg, this.errorCount); } - return baseOpen({ - ...options, - app: { - name, - arguments: appArguments + end() { + } + }; + exports2.IPCMessageWriter = IPCMessageWriter; + var PortMessageReader = class extends api_1.AbstractMessageReader { + constructor(port) { + super(); + this.onData = new api_1.Emitter(); + port.on("close", () => this.fireClose); + port.on("error", (error) => this.fireError(error)); + port.on("message", (message) => { + this.onData.fire(message); + }); + } + listen(callback) { + return this.onData.event(callback); + } + }; + exports2.PortMessageReader = PortMessageReader; + var PortMessageWriter = class extends api_1.AbstractMessageWriter { + constructor(port) { + super(); + this.port = port; + this.errorCount = 0; + port.on("close", () => this.fireClose()); + port.on("error", (error) => this.fireError(error)); + } + write(msg) { + try { + this.port.postMessage(msg); + return Promise.resolve(); + } catch (error) { + this.handleError(error, msg); + return Promise.reject(error); } - }); + } + handleError(error, msg) { + this.errorCount++; + this.fireError(error, msg, this.errorCount); + } + end() { + } }; - apps = { - browser: "browser", - browserPrivate: "browserPrivate" + exports2.PortMessageWriter = PortMessageWriter; + var SocketMessageReader = class extends api_1.ReadableStreamMessageReader { + constructor(socket, encoding = "utf-8") { + super((0, ril_1.default)().stream.asReadableStream(socket), encoding); + } }; - defineLazyProperty(apps, "chrome", () => detectPlatformBinary({ - darwin: "google chrome", - win32: "chrome", - // `chromium-browser` is the older deb package name used by Ubuntu/Debian before snap. - linux: ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser"] - }, { - wsl: { - ia32: "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe", - x64: ["/mnt/c/Program Files/Google/Chrome/Application/chrome.exe", "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe"] + exports2.SocketMessageReader = SocketMessageReader; + var SocketMessageWriter = class extends api_1.WriteableStreamMessageWriter { + constructor(socket, options) { + super((0, ril_1.default)().stream.asWritableStream(socket), options); + this.socket = socket; } - })); - defineLazyProperty(apps, "brave", () => detectPlatformBinary({ - darwin: "brave browser", - win32: "brave", - linux: ["brave-browser", "brave"] - }, { - wsl: { - ia32: "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe", - x64: ["/mnt/c/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe", "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe"] + dispose() { + super.dispose(); + this.socket.destroy(); } - })); - defineLazyProperty(apps, "firefox", () => detectPlatformBinary({ - darwin: "firefox", - win32: String.raw`C:\Program Files\Mozilla Firefox\firefox.exe`, - linux: "firefox" - }, { - wsl: "/mnt/c/Program Files/Mozilla Firefox/firefox.exe" - })); - defineLazyProperty(apps, "edge", () => detectPlatformBinary({ - darwin: "microsoft edge", - win32: "msedge", - linux: ["microsoft-edge", "microsoft-edge-dev"] - }, { - wsl: "/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe" - })); - defineLazyProperty(apps, "safari", () => detectPlatformBinary({ - darwin: "Safari" - })); - open_default = open; - } -}); - -// src/shared-auth.js -var require_shared_auth = __commonJS({ - "src/shared-auth.js"(exports2, module2) { - var { log: log2 } = require_shared_utils(); - var { createCachePlugin } = require_msal_cache(); - var VSCODE_CLIENT_ID2 = "51f81489-12ee-4a9e-aaae-a2591f45987d"; - var ISLAND_RESOURCE_IDS = { - 0: "a522f059-bb65-47c0-8934-7db6e5286414", - 1: "a522f059-bb65-47c0-8934-7db6e5286414", - 2: "a522f059-bb65-47c0-8934-7db6e5286414", - 3: "a522f059-bb65-47c0-8934-7db6e5286414", - 4: "96ff4394-9197-43aa-b393-6a41652e21f8", - 5: "96ff4394-9197-43aa-b393-6a41652e21f8", - 6: "9315aedd-209b-43b3-b149-2abff6a95d59", - 7: "69c6e40c-465f-4154-987d-da5cba10734e", - 8: "bd4a9f18-e349-4c74-a6b7-65dd465ea9ab" }; - function getIslandResourceId2(clusterCategory) { - const id = ISLAND_RESOURCE_IDS[clusterCategory]; - if (!id) throw new Error(`Unknown cluster category: ${clusterCategory}`); - return id; - } - var _cachePlugin = null; - var _msalApps = /* @__PURE__ */ new Map(); - async function getDefaultCachePlugin() { - if (!_cachePlugin) { - _cachePlugin = await createCachePlugin("manage-agent"); + exports2.SocketMessageWriter = SocketMessageWriter; + var StreamMessageReader = class extends api_1.ReadableStreamMessageReader { + constructor(readable, encoding) { + super((0, ril_1.default)().stream.asReadableStream(readable), encoding); } - return _cachePlugin; + }; + exports2.StreamMessageReader = StreamMessageReader; + var StreamMessageWriter = class extends api_1.WriteableStreamMessageWriter { + constructor(writable, options) { + super((0, ril_1.default)().stream.asWritableStream(writable), options); + } + }; + exports2.StreamMessageWriter = StreamMessageWriter; + var XDG_RUNTIME_DIR = process.env["XDG_RUNTIME_DIR"]; + var safeIpcPathLengths = /* @__PURE__ */ new Map([ + ["linux", 107], + ["darwin", 103] + ]); + function generateRandomPipeName() { + const randomSuffix = (0, crypto_1.randomBytes)(21).toString("hex"); + if (process.platform === "win32") { + return `\\\\.\\pipe\\vscode-jsonrpc-${randomSuffix}-sock`; + } + let result; + if (XDG_RUNTIME_DIR) { + result = path3.join(XDG_RUNTIME_DIR, `vscode-ipc-${randomSuffix}.sock`); + } else { + result = path3.join(os3.tmpdir(), `vscode-${randomSuffix}.sock`); + } + const limit = safeIpcPathLengths.get(process.platform); + if (limit !== void 0 && result.length > limit) { + (0, ril_1.default)().console.warn(`WARNING: IPC handle "${result}" is longer than ${limit} characters.`); + } + return result; } - async function createMsalApp(tenantId, clientId, cacheSlot) { - const msal = require_msal_node(); - if (cacheSlot) { - const plugin = await createCachePlugin(cacheSlot); - return new msal.PublicClientApplication({ - auth: { - clientId, - authority: `https://login.microsoftonline.com/${tenantId}` - }, - cache: { cachePlugin: plugin } + exports2.generateRandomPipeName = generateRandomPipeName; + function createClientPipeTransport(pipeName, encoding = "utf-8") { + let connectResolve; + const connected = new Promise((resolve, _reject) => { + connectResolve = resolve; + }); + return new Promise((resolve, reject) => { + let server = (0, net_1.createServer)((socket) => { + server.close(); + connectResolve([ + new SocketMessageReader(socket, encoding), + new SocketMessageWriter(socket, encoding) + ]); + }); + server.on("error", reject); + server.listen(pipeName, () => { + server.removeListener("error", reject); + resolve({ + onConnected: () => { + return connected; + } + }); }); - } - const key = `${tenantId}:${clientId}`; - if (_msalApps.has(key)) return _msalApps.get(key); - const cachePlugin = await getDefaultCachePlugin(); - const app = new msal.PublicClientApplication({ - auth: { - clientId, - authority: `https://login.microsoftonline.com/${tenantId}` - }, - cache: { cachePlugin } }); - _msalApps.set(key, app); - return app; } - function buildTokenInfo2(result) { - return { - accessToken: result.accessToken, - expiresOn: result.expiresOn ? result.expiresOn.toISOString() : new Date(Date.now() + 3600 * 1e3).toISOString(), - scopes: result.scopes, - account: result.account ? { - homeAccountId: result.account.homeAccountId, - environment: result.account.environment, - tenantId: result.account.tenantId, - username: result.account.username - } : void 0 - }; + exports2.createClientPipeTransport = createClientPipeTransport; + function createServerPipeTransport(pipeName, encoding = "utf-8") { + const socket = (0, net_1.createConnection)(pipeName); + return [ + new SocketMessageReader(socket, encoding), + new SocketMessageWriter(socket, encoding) + ]; } - async function acquireTokenDeviceCode2(tenantId, clientId, scopes, cacheSlot) { - const app = await createMsalApp(tenantId, clientId, cacheSlot); - const result = await app.acquireTokenByDeviceCode({ - scopes, - deviceCodeCallback: (response) => { - log2(""); - log2(` ${response.message}`); - log2(""); - process.stdout.write( - JSON.stringify({ - status: "device_code", - userCode: response.userCode, - verificationUri: response.verificationUri, - message: response.message, - expiresIn: response.expiresIn - }) + "\n" - ); - } + exports2.createServerPipeTransport = createServerPipeTransport; + function createClientSocketTransport(port, encoding = "utf-8") { + let connectResolve; + const connected = new Promise((resolve, _reject) => { + connectResolve = resolve; }); - if (!result) throw new Error("Device code flow returned no result"); - return buildTokenInfo2(result); - } - async function acquireTokenInteractive2(tenantId, clientId, scopes, cacheSlot) { - const app = await createMsalApp(tenantId, clientId, cacheSlot); - const result = await app.acquireTokenInteractive({ - scopes, - openBrowser: async (url) => { - log2(""); - log2(` Open this URL to sign in: ${url}`); - log2(""); - const open2 = (await Promise.resolve().then(() => (init_open(), open_exports))).default; - await open2(url); - }, - successTemplate: "

Login successful. You can close this tab.

" + return new Promise((resolve, reject) => { + const server = (0, net_1.createServer)((socket) => { + server.close(); + connectResolve([ + new SocketMessageReader(socket, encoding), + new SocketMessageWriter(socket, encoding) + ]); + }); + server.on("error", reject); + server.listen(port, "127.0.0.1", () => { + server.removeListener("error", reject); + resolve({ + onConnected: () => { + return connected; + } + }); + }); }); - if (!result) throw new Error("Interactive flow returned no result"); - return buildTokenInfo2(result); } - async function acquireTokenSilent2(tenantId, clientId, scopes, cacheSlot) { - const app = await createMsalApp(tenantId, clientId, cacheSlot); - const allAccounts = await app.getTokenCache().getAllAccounts(); - const accounts = allAccounts.filter((a) => a.tenantId === tenantId); - if (accounts.length > 0) { - try { - const result = await app.acquireTokenSilent({ - scopes, - account: accounts[0] - }); - if (result) { - const scopeKey = scopes[0]; - log2(`${scopeKey}: silently refreshed (expires ${result.expiresOn?.toISOString()})`); - return buildTokenInfo2(result); - } - } catch (e) { - log2(`Silent refresh failed: ${e.message}`); - } - } - return null; + exports2.createClientSocketTransport = createClientSocketTransport; + function createServerSocketTransport(port, encoding = "utf-8") { + const socket = (0, net_1.createConnection)(port, "127.0.0.1"); + return [ + new SocketMessageReader(socket, encoding), + new SocketMessageWriter(socket, encoding) + ]; } - async function getOrAcquireToken2(tenantId, clientId, scopes, label, cacheSlot) { - const silent = await acquireTokenSilent2(tenantId, clientId, scopes, cacheSlot); - if (silent) { - log2(`${label}: using cached token (expires ${silent.expiresOn})`); - return silent; - } - log2(`${label}: starting interactive login...`); - return acquireTokenInteractive2(tenantId, clientId, scopes, cacheSlot); + exports2.createServerSocketTransport = createServerSocketTransport; + function isReadableStream(value) { + const candidate = value; + return candidate.read !== void 0 && candidate.addListener !== void 0; } - async function getOrAcquireIslandToken2(tenantId, clusterCategory, label) { - const resourceId = getIslandResourceId2(clusterCategory); - return getOrAcquireToken2( - tenantId, - VSCODE_CLIENT_ID2, - [`api://${resourceId}/.default`], - label - ); + function isWritableStream(value) { + const candidate = value; + return candidate.write !== void 0 && candidate.addListener !== void 0; } - module2.exports = { - VSCODE_CLIENT_ID: VSCODE_CLIENT_ID2, - ISLAND_RESOURCE_IDS, - getIslandResourceId: getIslandResourceId2, - createMsalApp, - buildTokenInfo: buildTokenInfo2, - acquireTokenDeviceCode: acquireTokenDeviceCode2, - acquireTokenInteractive: acquireTokenInteractive2, - acquireTokenSilent: acquireTokenSilent2, - getOrAcquireToken: getOrAcquireToken2, - getOrAcquireIslandToken: getOrAcquireIslandToken2 - }; + function createMessageConnection(input, output, logger, options) { + if (!logger) { + logger = api_1.NullLogger; + } + const reader = isReadableStream(input) ? new StreamMessageReader(input) : input; + const writer = isWritableStream(output) ? new StreamMessageWriter(output) : output; + if (api_1.ConnectionStrategy.is(options)) { + options = { connectionStrategy: options }; + } + return (0, api_1.createMessageConnection)(reader, writer, logger, options); + } + exports2.createMessageConnection = createMessageConnection; + } +}); + +// ../../node_modules/vscode-jsonrpc/node.js +var require_node = __commonJS({ + "../../node_modules/vscode-jsonrpc/node.js"(exports2, module2) { + "use strict"; + module2.exports = require_main(); } }); @@ -15073,6 +18239,9 @@ function parseArgs() { case "--force": parsed.force = true; break; + case "--cluster-category": + parsed.clusterCategory = parseInt(args[++i], 10); + break; case "--url": parsed.url = args[++i]; break; @@ -15215,7 +18384,7 @@ var LspClient = class { async start() { if (this.running) return; const net = require("net"); - const { SocketMessageReader, SocketMessageWriter, createMessageConnection } = require("vscode-jsonrpc/node"); + const { SocketMessageReader, SocketMessageWriter, createMessageConnection } = require_node(); const sessionId = randomUUID(); const pipePath = os2.platform() === "win32" ? `\\\\.\\pipe\\manage-agent-${sessionId}` : path2.join(os2.tmpdir(), `manage-agent-${sessionId}.sock`); const server = net.createServer(); @@ -16032,8 +19201,8 @@ async function cmdClone(args) { if (!args.environmentUrl) die("Could not resolve --environment-url (or CPS_ENVIRONMENT_URL)"); if (!args.agentMgmtUrl) die("Could not resolve --agent-mgmt-url (or CPS_AGENT_MGMT_URL)"); const envUrl = args.environmentUrl.replace(/\/+$/, ""); - const DEFAULT_CLUSTER_CATEGORY = 5; - const cpsToken = await getOrAcquireIslandToken(args.tenantId, DEFAULT_CLUSTER_CATEGORY, "Island API"); + const clusterCategory = args.clusterCategory != null ? args.clusterCategory : 5; + const cpsToken = await getOrAcquireIslandToken(args.tenantId, clusterCategory, "Island API"); const dvToken = await getOrAcquireToken(args.tenantId, VSCODE_CLIENT_ID, [`${envUrl}/.default`], "Dataverse API"); const [agentInfo, solVersions] = await Promise.all([ fetchAgentInfo(envUrl, args.agentId, dvToken.accessToken), @@ -16050,7 +19219,7 @@ async function cmdClone(args) { accountId: args.accountId || dvToken.account?.homeAccountId || "unknown", accountEmail: args.accountEmail || dvToken.account?.username || void 0, tenantId: args.tenantId, - clusterCategory: DEFAULT_CLUSTER_CATEGORY + clusterCategory }, copilotStudioAccessToken: cpsToken.accessToken, dataverseAccessToken: dvToken.accessToken, @@ -16127,6 +19296,6 @@ safe-buffer/index.js: (*! safe-buffer. MIT License. Feross Aboukhadijeh *) @azure/msal-node/lib/msal-node.cjs: - (*! @azure/msal-node v5.1.4 2026-04-21 *) - (*! @azure/msal-common v16.5.1 2026-04-21 *) + (*! @azure/msal-node v5.0.6 2026-03-02 *) + (*! @azure/msal-common v16.2.0 2026-03-02 *) */ diff --git a/scripts/src/manage-agent.js b/scripts/src/manage-agent.js index d51fdfc..d9b43cb 100644 --- a/scripts/src/manage-agent.js +++ b/scripts/src/manage-agent.js @@ -159,6 +159,9 @@ function parseArgs() { case "--force": parsed.force = true; break; + case "--cluster-category": + parsed.clusterCategory = parseInt(args[++i], 10); + break; case "--url": parsed.url = args[++i]; break; @@ -1365,9 +1368,10 @@ async function cmdClone(args) { const envUrl = args.environmentUrl.replace(/\/+$/, ""); - // Clone uses Island API token (same as push/pull) — default to Prod cluster (5) - const DEFAULT_CLUSTER_CATEGORY = 5; - const cpsToken = await getOrAcquireIslandToken(args.tenantId, DEFAULT_CLUSTER_CATEGORY, "Island API"); + // Clone uses Island API token (same as push/pull) + // Default to Prod cluster (5). Pass --cluster-category for non-prod environments. + const clusterCategory = args.clusterCategory != null ? args.clusterCategory : 5; + const cpsToken = await getOrAcquireIslandToken(args.tenantId, clusterCategory, "Island API"); const dvToken = await getOrAcquireToken(args.tenantId, VSCODE_CLIENT_ID, [`${envUrl}/.default`], "Dataverse API"); @@ -1393,7 +1397,7 @@ async function cmdClone(args) { accountId: args.accountId || dvToken.account?.homeAccountId || "unknown", accountEmail: args.accountEmail || dvToken.account?.username || undefined, tenantId: args.tenantId, - clusterCategory: DEFAULT_CLUSTER_CATEGORY, + clusterCategory, }, copilotStudioAccessToken: cpsToken.accessToken, dataverseAccessToken: dvToken.accessToken, diff --git a/skills/add-action/SKILL.md b/skills/add-action/SKILL.md index af192c6..55f9f73 100644 --- a/skills/add-action/SKILL.md +++ b/skills/add-action/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: classic description: Guide users through adding a new connector action to a Copilot Studio agent. Connector actions require UI-based connection setup, so this skill walks users through the Copilot Studio portal steps, then delegates to edit-action for YAML modifications. argument-hint: allowed-tools: Bash(node *connector-lookup.bundle.js *), Read diff --git a/skills/add-adaptive-card/SKILL.md b/skills/add-adaptive-card/SKILL.md index 591af37..fe5f332 100644 --- a/skills/add-adaptive-card/SKILL.md +++ b/skills/add-adaptive-card/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: classic description: Generate and insert an Adaptive Card into a Copilot Studio topic using AdaptiveCardPrompt. Use when the user asks to add an adaptive card, rich card, form card, info card, confirmation card, or interactive card to a topic. argument-hint: in allowed-tools: Bash(node *schema-lookup.bundle.js *), Read, Write, Edit, Glob diff --git a/skills/add-generative-answers/SKILL.md b/skills/add-generative-answers/SKILL.md index acf6069..f5161c8 100644 --- a/skills/add-generative-answers/SKILL.md +++ b/skills/add-generative-answers/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: classic description: Add generative answer nodes (SearchAndSummarizeContent or AnswerQuestionWithAI) to a Copilot Studio topic. Use this instead of /add-node when the user asks to add grounded answers, knowledge search, generative answers, or AI-powered responses — these nodes require specific patterns (ConditionGroup follow-up, knowledge source references, autoSend, responseCaptureType) that /add-node does not cover. argument-hint: allowed-tools: Bash(node *schema-lookup.bundle.js *), Read, Write, Edit, Glob diff --git a/skills/add-global-variable/SKILL.md b/skills/add-global-variable/SKILL.md index 5070003..b932f38 100644 --- a/skills/add-global-variable/SKILL.md +++ b/skills/add-global-variable/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: classic description: Add a global variable to a Copilot Studio agent. Use when the user needs a variable that persists across topics in the same conversation and can optionally be visible to the AI orchestrator. argument-hint: allowed-tools: Read, Write, Glob, Grep diff --git a/skills/add-knowledge-modern/SKILL.md b/skills/add-knowledge-modern/SKILL.md new file mode 100644 index 0000000..f7ec3a3 --- /dev/null +++ b/skills/add-knowledge-modern/SKILL.md @@ -0,0 +1,106 @@ +--- +user-invocable: false +agent-types: modern +description: Add a knowledge source to a modern Copilot Studio agent. Supports public websites (YAML-authorable) and SharePoint/files/Dataverse (require UI setup). Use when the user asks to add a knowledge source, documentation URL, or website. +argument-hint: +allowed-tools: Read, Write, Glob +context: fork +agent: copilot-studio-author +--- + +# Add Knowledge Source to a Modern Agent + +## Pre-checks + +1. Run `Glob: **/settings.mcs.yml` to find the agent workspace. +2. Read `settings.mcs.yml` and confirm it's a modern agent (`template: cliagent-1.0.0` or `$kind: CLICopilotRecognizer`). + +## Knowledge Source Types + +Modern agents support these knowledge sources: + +| Type | YAML-authorable? | Kind | +|------|-------------------|------| +| **Public websites** | YES — create YAML directly | `WebsiteKnowledgeSource` | +| **SharePoint** | Partial — URL in YAML, auth at runtime | `SharePointKnowledgeSource` | +| **Uploaded files** | NO — upload via UI, reference by schema name | `FileKnowledgeSource` | +| **Dataverse** | NO — configure via UI | `DataverseStructuredSearchSource` | +| **Azure AI Search** | NOT AVAILABLE for modern agents | — | +| **Dynamics 365** | NOT AVAILABLE for modern agents | — | + +If the user asks for Azure AI Search or Dynamics 365, explain these are not available for modern agents. + +## Adding a Public Website (YAML-authorable) + +This is the only type that can be fully created from YAML. + +1. Get the URL from the user +2. Generate a file name: sanitize the URL into a valid filename (e.g., `https://www.example.com` → `httpswwwexamplecom`) +3. Add a short random suffix to avoid conflicts (e.g., `httpswwwexamplecom_a3Bf`) +4. Create the file in `knowledge/` directory + +### File structure + +`knowledge/{sanitized_url}_{suffix}.mcs.yml`: + +```yaml +mcs.metadata: + componentName: {display URL, e.g. https://www.example.com} +kind: KnowledgeSourceConfiguration +source: + kind: WebsiteKnowledgeSource + siteUrl: {full URL} +``` + +### Example + +For `https://www.tomsguide.com`: + +```yaml +mcs.metadata: + componentName: https://www.tomsguide.com +kind: KnowledgeSourceConfiguration +source: + kind: WebsiteKnowledgeSource + siteUrl: https://www.tomsguide.com +``` + +### Key rules + +- The top-level kind is `KnowledgeSourceConfiguration` (NOT `KnowledgeSourceComponent` — that's the Dataverse registration, created automatically by the push) +- Use `kind:` discriminator (not `$kind:`) for knowledge files +- The `componentName` is typically the URL itself +- No `description` field in `mcs.metadata` for knowledge sources (unlike skills/tools) +- File goes in `knowledge/` directory + +## Adding SharePoint + +SharePoint knowledge can be partially created via YAML (the URL), but the user's permissions are evaluated at runtime by the platform. + +```yaml +mcs.metadata: + componentName: {SharePoint site name} +kind: KnowledgeSourceConfiguration +source: + kind: SharePointKnowledgeSource + siteUrl: {SharePoint site URL} +``` + +**URL normalization:** SharePoint URLs should be the root site URL (e.g., `https://contoso.sharepoint.com/sites/hr`), not a specific page or document URL. + +## Adding Files or Dataverse (UI required) + +For file uploads or Dataverse knowledge, guide the user to the UI: + +> File and Dataverse knowledge sources must be added through the Copilot Studio UI: +> +> 1. Open your agent in Copilot Studio +> 2. In the right panel, click **+** next to **Knowledge** +> 3. For files: drag and drop or click to upload +> 4. For Dataverse: select **Dataverse** and configure the search +> +> Once added, run `/copilot-studio:manage-agent` to **pull** the updated files locally. + +## After creation + +Tell the user to push with `/copilot-studio:manage-agent` to register the knowledge source in the environment. The orchestrator will automatically search it when answering user questions — no explicit wiring needed (unlike classic agents which may need `SearchAndSummarizeContent` nodes). diff --git a/skills/add-knowledge/SKILL.md b/skills/add-knowledge/SKILL.md index 40bb6f0..e31e8fe 100644 --- a/skills/add-knowledge/SKILL.md +++ b/skills/add-knowledge/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: classic description: Add a knowledge source (public website or SharePoint) to a Copilot Studio agent. Use when the user asks to add a knowledge source, documentation URL, website, or SharePoint site for the agent to search. argument-hint: allowed-tools: Bash(node *schema-lookup.bundle.js *), Read, Write, Glob diff --git a/skills/add-node/SKILL.md b/skills/add-node/SKILL.md index 057a084..57f549a 100644 --- a/skills/add-node/SKILL.md +++ b/skills/add-node/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: classic description: Add or modify a node in an existing Copilot Studio topic. Use when the user asks to add a question, message, condition, variable, or other node to a topic. Do NOT use this for generative answers or knowledge search — use /add-generative-answers instead. argument-hint: to allowed-tools: Bash(node *schema-lookup.bundle.js *), Read, Write, Edit, Glob diff --git a/skills/add-other-agents/SKILL.md b/skills/add-other-agents/SKILL.md index 91a0729..82913e7 100644 --- a/skills/add-other-agents/SKILL.md +++ b/skills/add-other-agents/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: classic description: Add child agents, connected agents, or other multi-agent patterns to a Copilot Studio agent. Use when the user asks to create a sub-agent, child agent, connected agent, or call another agent. argument-hint: allowed-tools: Bash(node *schema-lookup.bundle.js *), Read, Write, Glob diff --git a/skills/add-tool/SKILL.md b/skills/add-tool/SKILL.md new file mode 100644 index 0000000..f7e3cc1 --- /dev/null +++ b/skills/add-tool/SKILL.md @@ -0,0 +1,130 @@ +--- +user-invocable: false +agent-types: modern +description: Guide users through adding a tool (connector, MCP, or workflow) to a modern Copilot Studio agent. Tools require UI-based connection setup, so this skill walks users through the portal steps, then edits the YAML after pull. +argument-hint: +allowed-tools: Bash(node *connector-lookup.bundle.js *), Read, Edit, Glob +context: fork +agent: copilot-studio-author +--- + +# Add Tool (Guide) + +This skill guides users through adding a tool to their modern agent. **It does NOT create tool YAML from scratch** because tools require a connection reference that can only be created through the Copilot Studio UI. + +## Why This Is a Guide + +Tools need: +1. A **connection reference** — an authenticated link to the external service (Teams, Outlook, Weather, etc.) +2. The connection can only be created by the user authenticating in the Copilot Studio portal +3. Once the tool is added via the UI and pulled locally, the YAML can be edited + +## Pre-checks + +1. Run `Glob: **/settings.mcs.yml` to find the agent workspace. +2. Read `settings.mcs.yml` and confirm it's a modern agent (`template: cliagent-1.0.0` or `$kind: CLICopilotRecognizer`). + +## Tool Types + +Modern agents support these tool types: + +| Type | UI Path | YAML Kind | +|------|---------|-----------| +| **Connectors** (Outlook, Teams, SharePoint, Weather, etc.) | Tools → + → Connectors | `ConnectorTool` | +| **MCP servers** | Tools → + → Model Context Protocol (MCP) | `McpTool` | +| **Workflows** (Power Automate flows) | Tools → + → Workflows | `WorkflowTool` | + +## Connector Lookup + +Help the user find the right connector and operation before they go to the UI: + +```bash +node ${CLAUDE_SKILL_DIR}/../../scripts/connector-lookup.bundle.js list +node ${CLAUDE_SKILL_DIR}/../../scripts/connector-lookup.bundle.js operations +node ${CLAUDE_SKILL_DIR}/../../scripts/connector-lookup.bundle.js operation +node ${CLAUDE_SKILL_DIR}/../../scripts/connector-lookup.bundle.js search +``` + +`` matches by API name (`shared_msnweather`) or partial display name (`weather`). + +If the connector is not in the lookup, tell the user to find it directly in the CPS portal. + +## Instructions + +1. **Understand what the user wants** — ask clarifying questions if vague (e.g., "send a message" — Teams? Outlook? Slack?) + +2. **Search for the operation** using connector-lookup: + ```bash + node ${CLAUDE_SKILL_DIR}/../../scripts/connector-lookup.bundle.js search "" + ``` + +3. **Show the operation details** so the user knows what to look for: + ```bash + node ${CLAUDE_SKILL_DIR}/../../scripts/connector-lookup.bundle.js operation + ``` + +4. **Walk the user through the UI steps**: + + > Here's how to add this tool in Copilot Studio: + > + > 1. Open your agent in Copilot Studio + > 2. In the right panel, click **+** next to **Tools** + > 3. Select the **Connectors** tab (or **Model Context Protocol (MCP)** / **Workflows** depending on tool type) + > 4. Search for **{connector name}** + > 5. Select the **{operation name}** operation + > 6. Authenticate when prompted (this creates the connection reference) + > 7. Save the changes + > + > Once the tool is added, run `/copilot-studio:manage-agent` to **pull** the updated files locally. + +5. **After pull**, the tool YAML appears in `translations/` as a `ConnectorTool`: + + ```yaml + mcs.metadata: + componentName: MSN Weather — Get current weather + description: Get the current weather for a location. + kind: ConnectorTool + connectorId: /providers/Microsoft.PowerApps/apis/shared_msnweather + connectionReference: Default_draft_xxx.shared_msnweather.xxx + operationId: CurrentWeather + ``` + +6. **Offer to edit** the tool's description (which the orchestrator uses for routing): + + > I can now edit the tool's description to better match when it should be invoked. Would you like me to update it? + + Safe to edit: `componentName`, `description` in `mcs.metadata` + **NEVER modify**: `connectorId`, `connectionReference`, `operationId` — these are set by the connection and will break the tool if changed. + +## YAML Structure Reference + +### ConnectorTool (after pull) +```yaml +mcs.metadata: + componentName: {Display Name} + description: {When the orchestrator should invoke this tool} +kind: ConnectorTool +connectorId: /providers/Microsoft.PowerApps/apis/{connector_api_name} +connectionReference: {schema}.{connector}.{connection_id} +operationId: {operation_id} +``` + +### McpTool (after pull) +```yaml +mcs.metadata: + componentName: {Display Name} + description: {When to invoke} +kind: McpTool +connectorId: /providers/Microsoft.PowerApps/apis/{mcp_connector} +connectionReference: {schema}.{connector}.{connection_id} +operationId: {operation_id} +``` + +### WorkflowTool (after pull) +```yaml +mcs.metadata: + componentName: {Display Name} + description: {When to invoke} +kind: WorkflowTool +workflowId: {guid} +``` diff --git a/skills/analyze-evals/SKILL.md b/skills/analyze-evals/SKILL.md index a331683..3d502c7 100644 --- a/skills/analyze-evals/SKILL.md +++ b/skills/analyze-evals/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: both description: > Analyze exported evaluation results from Copilot Studio's Evaluate tab. The user provides a CSV file exported from the Copilot Studio UI; this skill diff --git a/skills/chat-directline/SKILL.md b/skills/chat-directline/SKILL.md index 9069288..982cf8d 100644 --- a/skills/chat-directline/SKILL.md +++ b/skills/chat-directline/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: both description: Send a message to a Copilot Studio agent via DirectLine v3. Use for agents with no auth or manual auth. Requires a token endpoint URL or DirectLine secret. argument-hint: allowed-tools: Bash(node *chat-with-agent.bundle.js *), Read, Glob diff --git a/skills/chat-sdk/SKILL.md b/skills/chat-sdk/SKILL.md index f5e5466..aae903b 100644 --- a/skills/chat-sdk/SKILL.md +++ b/skills/chat-sdk/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: both description: Send a message to a Copilot Studio agent via the Copilot Studio Client SDK (M365). Use for agents with integrated auth (Entra ID SSO). Requires an App Registration Client ID. argument-hint: allowed-tools: Bash(node *chat-with-agent.bundle.js *), Read, Glob diff --git a/skills/chat-with-agent/SKILL.md b/skills/chat-with-agent/SKILL.md index f944b6d..dcb68c5 100644 --- a/skills/chat-with-agent/SKILL.md +++ b/skills/chat-with-agent/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: both description: "DEPRECATED: Use /copilot-studio:detect-mode then /copilot-studio:chat-directline or /copilot-studio:chat-sdk instead." argument-hint: allowed-tools: Bash(node *chat-with-agent.bundle.js *), Read, Glob, Grep diff --git a/skills/clone-agent/SKILL.md b/skills/clone-agent/SKILL.md index de60804..c8c3dad 100644 --- a/skills/clone-agent/SKILL.md +++ b/skills/clone-agent/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: both description: Clone a Copilot Studio agent from the cloud. Guides through environment selection, agent selection, and downloads agent YAML files. argument-hint: [agent name or environment hint] allowed-tools: Bash(node *manage-agent.bundle.js *), Read, Glob, Grep diff --git a/skills/create-eval-set/SKILL.md b/skills/create-eval-set/SKILL.md index d2fa8b5..ddc5d5c 100644 --- a/skills/create-eval-set/SKILL.md +++ b/skills/create-eval-set/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: both description: > Create a test set CSV file for import into Copilot Studio's in-product Evaluate tab. Reads the agent's topics, instructions, and knowledge sources to generate meaningful diff --git a/skills/create-eval/SKILL.md b/skills/create-eval/SKILL.md index 5b3b648..8bbecf3 100644 --- a/skills/create-eval/SKILL.md +++ b/skills/create-eval/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: true +agent-types: both description: Create plugin development eval scenarios (JSON files with natural prompts and deterministic checks for testing plugin skills). NOT for Copilot Studio in-product evaluation — use /copilot-studio:create-eval-set for that. argument-hint: allowed-tools: Read, Write, Glob diff --git a/skills/detect-mode/SKILL.md b/skills/detect-mode/SKILL.md index adb6903..ba58fc3 100644 --- a/skills/detect-mode/SKILL.md +++ b/skills/detect-mode/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: both description: Detect a Copilot Studio agent's authentication mode (DirectLine vs M365) by querying Dataverse. Returns the mode and connection details needed to chat. argument-hint: [--agent-dir ] allowed-tools: Bash(node *chat-with-agent.bundle.js --detect-only *), Read, Glob diff --git a/skills/directline-chat/SKILL.md b/skills/directline-chat/SKILL.md index e98b506..dedd3ba 100644 --- a/skills/directline-chat/SKILL.md +++ b/skills/directline-chat/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: both description: "DEPRECATED: Use /copilot-studio:chat-with-agent instead — it auto-detects DirectLine vs M365 mode. This skill is kept for backwards compatibility only." argument-hint: allowed-tools: Bash(node *directline-chat.bundle.js *), Bash(node *manage-agent.bundle.js detect-mode *), Read, Glob, Grep diff --git a/skills/edit-action/SKILL.md b/skills/edit-action/SKILL.md index 0194327..8704c5c 100644 --- a/skills/edit-action/SKILL.md +++ b/skills/edit-action/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: classic description: Edit an existing action (TaskDialog) in a Copilot Studio agent. Supports connector actions and MCP server actions. Modify inputs, outputs, descriptions, connection mode, and other properties. argument-hint: allowed-tools: Bash(node *connector-lookup.bundle.js *), Bash(node *schema-lookup.bundle.js *), Read, Edit, Glob diff --git a/skills/edit-agent-modern/SKILL.md b/skills/edit-agent-modern/SKILL.md new file mode 100644 index 0000000..a548960 --- /dev/null +++ b/skills/edit-agent-modern/SKILL.md @@ -0,0 +1,123 @@ +--- +user-invocable: false +agent-types: modern +description: Edit modern Copilot Studio agent settings — instructions, output format, model, conversation starters. Use when the user asks to change agent behavior, instructions, or configuration. +allowed-tools: Read, Edit, Glob +context: fork +agent: copilot-studio-author +--- + +# Edit modern agent settings + +## Pre-checks + +1. Run `Glob: **/settings.mcs.yml` to find the agent workspace. +2. Read `settings.mcs.yml` and confirm it's a modern agent (look for `template: cliagent-1.0.0` or `$kind: CLICopilotRecognizer`). +3. If this is NOT a modern agent, STOP and tell the user this skill is for modern agents only. Suggest `/copilot-studio:edit-agent` for classic agents. + +## What can be edited + +All agent settings live in `settings.mcs.yml` under `configuration.agentSettings`. The structure uses `$kind:` discriminators. + +### Instructions + +Instructions are in `agentSettings.instructions.segments[]`. Each segment is a `StaticSegment` with a `value` field: + +```yaml +configuration: + recognizer: + $kind: CLICopilotRecognizer + + agentSettings: + $kind: AgentSettings + instructions: + $kind: Instructions + segments: + - $kind: StaticSegment + value: You are a helpful assistant. + - $kind: StaticSegment + value: Always be concise. +``` + +To edit instructions: +- Replace the `value` field of existing `StaticSegment` entries +- Add new segments to the `segments[]` array +- Can also use `ReferenceSegment` to reference system properties: + +```yaml + - $kind: ReferenceSegment + reference: + $kind: SystemReference + property: currentDateAndTime +``` + +### Output format + +Set under `agentSettings.output`: + +**Free-form text (default):** +```yaml + output: + $kind: TextAgentOutput +``` + +**JSON Schema-constrained:** +```yaml + output: + $kind: StructuredAgentOutput + schema: '{"type":"object","properties":{"answer":{"type":"string"}},"required":["answer"]}' +``` + +### Conversation starters + +Suggested prompt buttons at conversation start: + +```yaml + conversationStarters: + - $kind: ConversationStarter + title: Get Started + text: How can you help me? + - $kind: ConversationStarter + title: FAQ + text: What questions can you answer? +``` + +### Model selection + +Set the LLM model series: + +```yaml + model: + $kind: ModelConfig + series: Sonnet46 +``` + +Available series values: `Sonnet46`, `GPT4o`, `GPT5` (check with schema-lookup for current list). + +## NEVER modify + +These fields must NOT be changed — they will break the agent: + +- `schemaName` — Dataverse entity identifier +- `publishedOn` — managed by publish system +- `template` — must stay `cliagent-1.0.0` +- `language` — locale code +- `configuration.recognizer` — must stay `CLICopilotRecognizer` +- `displayName` — can be changed but only if user explicitly asks + +## What is NOT available in modern agents + +If the user asks for any of these, explain they are not available and suggest alternatives: + +| Request | Why not | Alternative | +|---------|---------|-------------| +| Add a topic | Modern agents don't have topics | Create a skill with `/copilot-studio:new-skill` | +| Add Adaptive Cards | Output is text/JSON only | Use `StructuredAgentOutput` for structured responses | +| Add variables | `AgentVariable` is not yet supported at runtime | The LLM tracks state within the conversation naturally | +| Add entities | No entity system | The LLM extracts information from natural language | +| Use Power Fx | No expression engine | Describe logic in instructions | +| Add voice/IVR | Not supported | Stay on classic if voice is required | + +## After editing + +Tell the user to push changes with `/copilot-studio:manage-agent` and test in the CPS Preview tab. diff --git a/skills/edit-agent/SKILL.md b/skills/edit-agent/SKILL.md index 019de3b..e601457 100644 --- a/skills/edit-agent/SKILL.md +++ b/skills/edit-agent/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: classic description: Edit Copilot Studio agent settings, instructions, or configuration. Use when the user asks to change agent instructions, display name, conversation starters, AI settings, or generative actions toggle. argument-hint: allowed-tools: Bash(node *schema-lookup.bundle.js *), Read, Edit, Glob diff --git a/skills/edit-skill/SKILL.md b/skills/edit-skill/SKILL.md new file mode 100644 index 0000000..6a140c9 --- /dev/null +++ b/skills/edit-skill/SKILL.md @@ -0,0 +1,92 @@ +--- +user-invocable: false +agent-types: modern +description: Edit an existing inline skill in a modern Copilot Studio agent. Modify the skill's markdown content, description, or name. Use when the user asks to change, update, or improve a skill. +argument-hint: +allowed-tools: Read, Edit, Glob, Grep +context: fork +agent: copilot-studio-author +--- + +# Edit an Existing Skill + +## Pre-checks + +1. Run `Glob: **/settings.mcs.yml` to find the agent workspace. +2. Confirm it's a modern agent (`template: cliagent-1.0.0` or `$kind: CLICopilotRecognizer`). + +## Find the skill + +Skills live in two locations: +- `topics/*.mcs.yml` — skills with `DialogComponent` registration (invocable by orchestrator) +- `translations/*.mcs.yml` — skills with `TranslationsComponent` only (content layer) + +Search both: + +``` +Glob: **/topics/*.mcs.yml +Glob: **/translations/*.mcs.yml +``` + +Filter to `InlineAgentSkill` files (not `ConnectorTool` or other types): + +``` +Grep: kind: InlineAgentSkill +``` + +If the user specifies a skill name, match against `componentName` in `mcs.metadata`. If ambiguous, list all skills and ask which one. + +## What can be edited + +### Skill description (mcs.metadata) + +The `description` in `mcs.metadata` is what the orchestrator uses to decide when to invoke the skill. This is the most impactful edit — improving it changes routing behavior. + +```yaml +mcs.metadata: + componentName: OrderLookup + description: Looks up order status by order number. Use when the customer asks about shipping, delivery, tracking, or order status. +``` + +**Guidelines for good descriptions:** +- Be specific about WHEN to invoke (not just what it does) +- Include synonyms the user might use +- Mention what NOT to route here if there's confusion with other skills + +### Skill name (componentName) + +Can be changed, but the file name should also match: `Default_{componentName}.mcs.yml` + +### Markdown content + +The `content` field contains the skill's instructions as markdown with YAML frontmatter: + +```yaml +content: |- + --- + name: OrderLookup + description: Looks up order status + --- + # Order Lookup + + When the user asks about their order: + 1. Ask for the order number + 2. Use the Order API tool to look up status + 3. Tell the user the result +``` + +**When editing content:** +- Keep the YAML frontmatter (`---` block with `name` and `description`) in sync with `mcs.metadata` +- The frontmatter `description` should match `mcs.metadata.description` +- The frontmatter `name` should match `mcs.metadata.componentName` +- Use markdown formatting (headers, lists, bold) for clarity +- Reference tools by name if the skill should use them + +## What NOT to edit + +- **`kind:`** — must stay `InlineAgentSkill` +- **File location** — moving from `topics/` to `translations/` or vice versa changes the Dataverse registration type. Don't move files between directories. + +## After editing + +Tell the user to push with `/copilot-studio:manage-agent` to sync changes to the environment. diff --git a/skills/edit-triggers/SKILL.md b/skills/edit-triggers/SKILL.md index 0753e68..f6b6afa 100644 --- a/skills/edit-triggers/SKILL.md +++ b/skills/edit-triggers/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: classic description: Modify topic triggers — trigger phrases and model description. Use when the user asks to add, remove, or change trigger phrases, or edit a topic's model description. argument-hint: allowed-tools: Read, Edit, Glob diff --git a/skills/list-kinds/SKILL.md b/skills/list-kinds/SKILL.md index 82e8b8e..1d71e43 100644 --- a/skills/list-kinds/SKILL.md +++ b/skills/list-kinds/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: both description: List all available kind discriminator values from the Copilot Studio YAML schema. Use when the user asks what kinds/types are available. argument-hint: allowed-tools: Bash(node *schema-lookup.bundle.js *) diff --git a/skills/list-skills/SKILL.md b/skills/list-skills/SKILL.md new file mode 100644 index 0000000..2fa796a --- /dev/null +++ b/skills/list-skills/SKILL.md @@ -0,0 +1,51 @@ +--- +user-invocable: false +agent-types: modern +description: List all skills and tools in a modern Copilot Studio agent. Use when the user wants to see what capabilities their agent has. +allowed-tools: Read, Glob, Grep +agent: copilot-studio-author +--- + +# List skills and tools in a modern agent + +## Pre-checks + +1. Run `Glob: **/settings.mcs.yml` to find the agent workspace. +2. Confirm it's a modern agent (look for `template: cliagent-1.0.0` or `$kind: CLICopilotRecognizer` in `settings.mcs.yml`). + +## Discover components + +Scan two directories for `.mcs.yml` files: + +1. `topics/*.mcs.yml` — skills and tools with `DialogComponent` registration (invocable by the orchestrator) +2. `translations/*.mcs.yml` — content-only components (`TranslationsComponent` — may not be invocable) + +For each file, extract: +- **componentName** from `mcs.metadata.componentName` +- **description** from `mcs.metadata.description` +- **kind** — the top-level `kind:` value (`InlineAgentSkill`, `ConnectorTool`, `McpTool`, `WorkflowTool`, `FabricTool`, `ConnectedAgentTool`) + +## Display results + +Present as a table: + +``` +| Name | Kind | Location | Description | +|------|------|----------|-------------| +| WeatherSkill | InlineAgentSkill | topics/ | Responds to weather questions | +| MSN Weather | ConnectorTool | topics/ | Gets current weather for a location | +| TravelBooking | InlineAgentSkill | translations/ | Helps plan trips (content only — not invocable) | +``` + +Note for the user: +- Components in `topics/` are registered as `DialogComponent` and can be invoked by the orchestrator +- Components in `translations/` are content-only (`TranslationsComponent`) — they exist but the orchestrator cannot see them. If a skill should be invocable, it needs to be in `topics/`. + +## Also show agent settings summary + +From `settings.mcs.yml`, show: +- **Display name**: from `displayName` +- **Instructions**: first 100 chars of the instruction segments +- **Output type**: `TextAgentOutput` or `StructuredAgentOutput` (or "not set" if absent) +- **Conversation starters**: list titles if present +- **Knowledge sources**: list any `knowledge/*.mcs.yml` files with their source type and URL diff --git a/skills/list-topics/SKILL.md b/skills/list-topics/SKILL.md index b97a032..d5861d5 100644 --- a/skills/list-topics/SKILL.md +++ b/skills/list-topics/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: classic description: List all topics in the Copilot Studio agent with their trigger types, phrases, and action counts. Use when the user wants to see what topics exist. allowed-tools: Read, Glob, Grep --- diff --git a/skills/lookup-schema/SKILL.md b/skills/lookup-schema/SKILL.md index 670823e..93b8902 100644 --- a/skills/lookup-schema/SKILL.md +++ b/skills/lookup-schema/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: both description: Look up Copilot Studio YAML schema definitions. Use when the user asks about schema structure, element properties, or how to use a specific YAML kind. argument-hint: allowed-tools: Bash(node *schema-lookup.bundle.js *) diff --git a/skills/manage-agent/SKILL.md b/skills/manage-agent/SKILL.md index 14b8303..727a453 100644 --- a/skills/manage-agent/SKILL.md +++ b/skills/manage-agent/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: both description: Push/pull Copilot Studio agent content via the VS Code extension's LanguageServerHost LSP binary. Handles authentication (interactive browser login for push/pull, device code flow for chat token), sync push, sync pull, clone, and diff operations. argument-hint: allowed-tools: Bash(node *manage-agent.bundle.js *), Read, Glob, Grep diff --git a/skills/new-skill/SKILL.md b/skills/new-skill/SKILL.md new file mode 100644 index 0000000..803828b --- /dev/null +++ b/skills/new-skill/SKILL.md @@ -0,0 +1,77 @@ +--- +user-invocable: false +agent-types: modern +description: Create a new inline skill for a modern Copilot Studio agent. Use when the user asks to add a skill, capability, or conversation behavior to their agent. +argument-hint: +allowed-tools: Read, Write, Glob +context: fork +agent: copilot-studio-author +--- + +# Create a new skill for a modern agent + +## Pre-checks + +1. Run `Glob: **/settings.mcs.yml` to find the agent workspace. +2. Read `settings.mcs.yml` and confirm it's a modern agent (look for `template: cliagent-1.0.0` or `$kind: CLICopilotRecognizer`). +3. If this is NOT a modern agent, STOP and tell the user this skill is for modern agents only. + +## Gather requirements + +Ask the user (if not already provided): +- **Skill name** — short, descriptive (e.g., "OrderLookup", "TravelBooking") +- **What should the skill do?** — the behavior, steps, and responses + +## Generate the skill file + +Create `topics/Default_{skillName}.mcs.yml` in the agent workspace directory (same level as `settings.mcs.yml`). + +Use this exact structure: + +```yaml +mcs.metadata: + componentName: {SkillName} + description: {one sentence — CRITICAL: the orchestrator uses this to decide when to invoke the skill} +kind: InlineAgentSkill +content: |- + --- + name: {SkillName} + description: {same description as above} + --- + {markdown instructions for the skill} +``` + +### Template reference + +Read the template at `${CLAUDE_SKILL_DIR}/../../templates/topics/cli-skill.mcs.yml` for the base structure. + +## Key rules + +### File location +- MUST be in the `topics/` directory — this creates a `DialogComponent` registration in Dataverse so the orchestrator can discover and invoke the skill. +- Files in `translations/` only create `TranslationsComponent` entries (content layer) — the skill will NOT be invocable. +- File naming convention: `Default_{camelCaseName}.mcs.yml` + +### Description is critical +The `description` field (in both `mcs.metadata` and the markdown frontmatter) replaces trigger phrases from classic agents. The orchestrator reads it to decide which skill to route to. Be specific: +- BAD: "Handles orders" (too vague) +- GOOD: "Looks up order status by order number. Use when the customer asks about shipping, delivery, or order tracking." + +### Markdown content +- Use headers, numbered steps, and clear instructions +- The content is what the LLM sees when the skill is invoked +- For multi-step flows, describe the conversation flow as numbered steps (ask X, then do Y, then respond with Z) +- Reference tools by name if the skill should use them: "Use the OrderAPI tool to look up the order" + +### Frontmatter required +The markdown content MUST start with YAML frontmatter (`---` delimiters) containing `name` and `description`. Without this, the CPS UI rejects the skill upload. + +### Discriminator +Use `kind:` (not `$kind:`) for skill files. Only `settings.mcs.yml` uses the `$kind:` discriminator. + +## After creation + +Tell the user: +1. The skill was created at `topics/Default_{name}.mcs.yml` +2. Push to the environment with `/copilot-studio:manage-agent` to register it +3. Test in the CPS Preview tab or via `/copilot-studio:chat-sdk` diff --git a/skills/new-topic/SKILL.md b/skills/new-topic/SKILL.md index aa6208c..54707ab 100644 --- a/skills/new-topic/SKILL.md +++ b/skills/new-topic/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: classic description: Create a new Copilot Studio topic YAML file. Use when the user asks to create a new topic, conversation flow, or dialog for their agent. argument-hint: allowed-tools: Bash(node *schema-lookup.bundle.js *), Bash(node *manage-agent.bundle.js *), Read, Write, Glob diff --git a/skills/run-eval/SKILL.md b/skills/run-eval/SKILL.md index 5fa10c4..fc61aea 100644 --- a/skills/run-eval/SKILL.md +++ b/skills/run-eval/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: both description: > Run evaluations against a Copilot Studio agent via the Power Platform Evaluation API. Works on DRAFT agents — no publish step required. Lists test sets, starts a run, diff --git a/skills/run-tests-kit/SKILL.md b/skills/run-tests-kit/SKILL.md index 1c5bf05..e4fbeea 100644 --- a/skills/run-tests-kit/SKILL.md +++ b/skills/run-tests-kit/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: both description: > Run a batch test suite via the Copilot Studio Kit (Dataverse API). Uses the Power CAT Copilot Studio Kit to execute test cases against a published agent diff --git a/skills/test-auth/SKILL.md b/skills/test-auth/SKILL.md index 1ee384e..c456490 100644 --- a/skills/test-auth/SKILL.md +++ b/skills/test-auth/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: both description: > Authenticate for Copilot Studio evaluation API and SDK chat. Caches a token that is shared across run-eval and chat-sdk skills. Run this before any diff --git a/skills/validate/SKILL.md b/skills/validate/SKILL.md index 3d30d0a..ec62b95 100644 --- a/skills/validate/SKILL.md +++ b/skills/validate/SKILL.md @@ -1,5 +1,6 @@ --- user-invocable: false +agent-types: both description: Validate Copilot Studio agent YAML files using the LSP binary's full diagnostics (YAML structure, Power Fx, schema, cross-file references). Use when the user asks to check, validate, or verify YAML files. argument-hint: allowed-tools: Bash(node *manage-agent.bundle.js *), Bash(node *schema-lookup.bundle.js *), Read, Glob diff --git a/templates/topics/cli-skill.mcs.yml b/templates/topics/cli-skill.mcs.yml new file mode 100644 index 0000000..278920f --- /dev/null +++ b/templates/topics/cli-skill.mcs.yml @@ -0,0 +1,14 @@ +# Name: _REPLACE +# Modern (CLI) agent inline skill template +# Place in topics/Default_{name}.mcs.yml +# Replace _REPLACE placeholders before use +mcs.metadata: + componentName: _REPLACE + description: _REPLACE +kind: InlineAgentSkill +content: |- + --- + name: _REPLACE + description: _REPLACE + --- + _REPLACE