From cfff23ed34899aeeb7fc9cfcee8fa143775c22a1 Mon Sep 17 00:00:00 2001 From: Ejaz Hussain Date: Sat, 22 Aug 2026 20:11:25 +0100 Subject: [PATCH] New sample: Azure DevOps Wiki Assistant (da-azure-devops-wiki) A read-only Microsoft 365 Copilot declarative agent grounded strictly on the Azure DevOps Wiki Copilot connector. Built with TypeSpec and the Microsoft 365 Agents Toolkit. Searches indexed wikis, cites sources, and states when an answer is not found in the wiki. --- samples/da-azure-devops-wiki/.gitignore | 19 + .../.vscode/extensions.json | 6 + .../da-azure-devops-wiki/.vscode/launch.json | 91 + .../.vscode/settings.json | 12 + .../da-azure-devops-wiki/.vscode/tasks.json | 44 + samples/da-azure-devops-wiki/AGENTS.md | 745 ++++++ samples/da-azure-devops-wiki/README.md | 88 + .../da-azure-devops-wiki/appPackage/color.png | Bin 0 -> 5923 bytes .../appPackage/manifest.json | 32 + .../appPackage/outline.png | Bin 0 -> 492 bytes samples/da-azure-devops-wiki/assets/demo.png | Bin 0 -> 78520 bytes .../da-azure-devops-wiki/assets/sample.json | 55 + samples/da-azure-devops-wiki/env/.env.dev | 28 + .../da-azure-devops-wiki/evals/prompts.json | 31 + .../da-azure-devops-wiki/m365agents.local.yml | 65 + samples/da-azure-devops-wiki/m365agents.yml | 118 + .../da-azure-devops-wiki/package-lock.json | 2315 +++++++++++++++++ samples/da-azure-devops-wiki/package.json | 16 + .../scripts/generate-env.js | 86 + .../da-azure-devops-wiki/src/agent/main.tsp | 44 + .../src/agent/prompts/instructions.tsp | 30 + samples/da-azure-devops-wiki/tspconfig.yaml | 15 + 22 files changed, 3840 insertions(+) create mode 100644 samples/da-azure-devops-wiki/.gitignore create mode 100644 samples/da-azure-devops-wiki/.vscode/extensions.json create mode 100644 samples/da-azure-devops-wiki/.vscode/launch.json create mode 100644 samples/da-azure-devops-wiki/.vscode/settings.json create mode 100644 samples/da-azure-devops-wiki/.vscode/tasks.json create mode 100644 samples/da-azure-devops-wiki/AGENTS.md create mode 100644 samples/da-azure-devops-wiki/README.md create mode 100644 samples/da-azure-devops-wiki/appPackage/color.png create mode 100644 samples/da-azure-devops-wiki/appPackage/manifest.json create mode 100644 samples/da-azure-devops-wiki/appPackage/outline.png create mode 100644 samples/da-azure-devops-wiki/assets/demo.png create mode 100644 samples/da-azure-devops-wiki/assets/sample.json create mode 100644 samples/da-azure-devops-wiki/env/.env.dev create mode 100644 samples/da-azure-devops-wiki/evals/prompts.json create mode 100644 samples/da-azure-devops-wiki/m365agents.local.yml create mode 100644 samples/da-azure-devops-wiki/m365agents.yml create mode 100644 samples/da-azure-devops-wiki/package-lock.json create mode 100644 samples/da-azure-devops-wiki/package.json create mode 100644 samples/da-azure-devops-wiki/scripts/generate-env.js create mode 100644 samples/da-azure-devops-wiki/src/agent/main.tsp create mode 100644 samples/da-azure-devops-wiki/src/agent/prompts/instructions.tsp create mode 100644 samples/da-azure-devops-wiki/tspconfig.yaml diff --git a/samples/da-azure-devops-wiki/.gitignore b/samples/da-azure-devops-wiki/.gitignore new file mode 100644 index 000000000..5bc64fdc3 --- /dev/null +++ b/samples/da-azure-devops-wiki/.gitignore @@ -0,0 +1,19 @@ +# TeamsFx files +env/.env.*.user +env/.env.local +.localConfigs +appPackage/build +build + +# dependencies +node_modules/ + +# misc +.env +.deployment +.DS_Store + +# generated files +appPackage/.generated +# generated environment variables +src/agent/env.tsp \ No newline at end of file diff --git a/samples/da-azure-devops-wiki/.vscode/extensions.json b/samples/da-azure-devops-wiki/.vscode/extensions.json new file mode 100644 index 000000000..1397851d6 --- /dev/null +++ b/samples/da-azure-devops-wiki/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "TeamsDevApp.ms-teams-vscode-extension", + "typespec.typespec-vscode" + ] +} diff --git a/samples/da-azure-devops-wiki/.vscode/launch.json b/samples/da-azure-devops-wiki/.vscode/launch.json new file mode 100644 index 000000000..2e2d74158 --- /dev/null +++ b/samples/da-azure-devops-wiki/.vscode/launch.json @@ -0,0 +1,91 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Agent in Copilot (Edge)", + "type": "msedge", + "request": "launch", + "url": "https://m365.cloud.microsoft/chat/?titleId=${local:agent-hint}&source=agents-toolkit", + "presentation": { + "group": "all", + "hidden": true + }, + "internalConsoleOptions": "neverOpen", + "runtimeArgs": [ + "--remote-debugging-port=9222", + "--no-first-run" + ] + }, + { + "name": "Launch Agent in Copilot (Chrome)", + "type": "chrome", + "request": "launch", + "url": "https://m365.cloud.microsoft/chat/?titleId=${local:agent-hint}&source=agents-toolkit", + "presentation": { + "group": "all", + "hidden": true + }, + "internalConsoleOptions": "neverOpen", + "runtimeArgs": [ + "--remote-debugging-port=9223", + "--no-first-run" + ] + }, + { + "name": "Preview in Copilot (Edge)", + "type": "msedge", + "request": "launch", + "url": "https://m365.cloud.microsoft/chat/?titleId=${agent-hint}&source=agents-toolkit", + "presentation": { + "group": "remote", + "order": 1 + }, + "internalConsoleOptions": "neverOpen", + "runtimeArgs": [ + "--remote-debugging-port=9224", + "--no-first-run" + ] + }, + { + "name": "Preview in Copilot (Chrome)", + "type": "chrome", + "request": "launch", + "url": "https://m365.cloud.microsoft/chat/?titleId=${agent-hint}&source=agents-toolkit", + "presentation": { + "group": "remote", + "order": 2 + }, + "internalConsoleOptions": "neverOpen", + "runtimeArgs": [ + "--remote-debugging-port=9225", + "--no-first-run" + ] + } + ], + "compounds": [ + { + "name": "Preview Local in Copilot (Edge)", + "configurations": [ + "Launch Agent in Copilot (Edge)", + ], + "preLaunchTask": "Start Agent Locally", + "presentation": { + "group": "all", + "order": 1 + }, + "stopAll": true + }, + { + "name": "Preview Local in Copilot (Chrome)", + "configurations": [ + "Launch Agent in Copilot (Chrome)", + ], + "preLaunchTask": "Start Agent Locally", + "presentation": { + "group": "all", + "order": 1 + }, + "stopAll": true + } + ] +} diff --git a/samples/da-azure-devops-wiki/.vscode/settings.json b/samples/da-azure-devops-wiki/.vscode/settings.json new file mode 100644 index 000000000..187eca2c7 --- /dev/null +++ b/samples/da-azure-devops-wiki/.vscode/settings.json @@ -0,0 +1,12 @@ +{ + "debug.onTaskErrors": "abort", + "json.schemas": [ + { + "fileMatch": ["/aad.*.json"], + "schema": {} + } + ], + "files.readonlyInclude": { + "appPackage/.generated/**/*": true + } +} diff --git a/samples/da-azure-devops-wiki/.vscode/tasks.json b/samples/da-azure-devops-wiki/.vscode/tasks.json new file mode 100644 index 000000000..45fb925e8 --- /dev/null +++ b/samples/da-azure-devops-wiki/.vscode/tasks.json @@ -0,0 +1,44 @@ +// This file is automatically generated by Microsoft 365 Agents Toolkit. +// The teamsfx tasks defined in this file require Microsoft 365 Agents Toolkit version >= 5.0.0. +// See https://aka.ms/teamsfx-tasks for details on how to customize each task. +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Start Agent Locally", + "dependsOn": [ + "Validate prerequisites", + "Create resources" + ], + "dependsOrder": "sequence" + }, + { + "label": "Validate prerequisites", + "type": "teamsfx", + "command": "debug-check-prerequisites", + "args": { + "prerequisites": [ + "copilotAccess" + ] + } + }, + { + "label": "Create resources", + "type": "teamsfx", + "command": "provision", + "args": { + "env": "local" + } + }, + { + "label": "Install dependencies", + "type": "shell", + "command": "npm install", + "presentation": { + "reveal": "silent", + "panel": "new" + }, + "runOptions": { "runOn": "folderOpen" } + } + ] +} \ No newline at end of file diff --git a/samples/da-azure-devops-wiki/AGENTS.md b/samples/da-azure-devops-wiki/AGENTS.md new file mode 100644 index 000000000..bb667e04d --- /dev/null +++ b/samples/da-azure-devops-wiki/AGENTS.md @@ -0,0 +1,745 @@ +--- +description: 'Expert guidance for building declarative agents with TypeSpec for Microsoft 365 Copilot using Microsoft 365 Agents Toolkit' +applyTo: '**/*.tsp' +--- + +# TypeSpec Declarative Agent Development for Microsoft 365 Copilot + +## TypeSpec Instructions + +- Always use the latest stable version of TypeSpec compiler (`@typespec/compiler` v1.0.0+). +- Use the latest version of `@microsoft/typespec-m365-copilot` for agent-specific decorators and capabilities. +- Write clear and descriptive `@doc` comments for all operations, models, and namespaces. +- Follow semantic versioning for API operations when introducing breaking changes. + +## General Instructions + +- Make only high-confidence suggestions when reviewing TypeSpec definitions. +- Write TypeSpec with good maintainability practices, including comments explaining design decisions for complex schemas. +- Handle edge cases in action definitions and provide clear error documentation. +- For external APIs or services, document their purpose and integration points in comments. +- Always validate TypeSpec compilation (`npm run compile`) before provisioning. + +## Naming Conventions + +- Follow PascalCase for namespace names, model names, and operation names (e.g., `PoliciesAgent`, `AgentInfo`, `getAgents`). +- Use camelCase for parameter names and properties (e.g., `@path id: string`, `agentId: string`). +- Use descriptive names that reflect the operation's purpose (e.g., `getPolicies` instead of `getData`). +- Prefix enum members with their context when needed (e.g., `PolicyType.Compliance`, `AgentStatus.Active`). +- Use plural names for collection responses (e.g., `agents: AgentInfo[]` not `agent: AgentInfo[]`). + +## Formatting + +- Apply consistent indentation (2 or 4 spaces) throughout `.tsp` files. +- Group related imports together at the top of each file. +- Separate logical sections with comment dividers (e.g., `// --- Models ---`). +- Place decorators on separate lines above the element they modify. +- Use multiline format for operations with multiple parameters. +- Ensure consistent spacing around operators and colons in type annotations. +- Add a newline at the end of each file. + +## Project Setup and Structure + +- Guide users through creating a new declarative agent project using Microsoft 365 Agents Toolkit. +- Explain the purpose of each generated file: `main.tsp` (entry point), `prompts/*.tsp` (Prompts), `actions/*.tsp` (API operations), `env.tsp` (environment variables). +- Demonstrate how to organize code using separate namespaces for actions and models. +- Show proper separation of concerns: agent definition (main.tsp), actions (actions/*.tsp), data models (models.tsp). +- Explain the `m365agents.yml` configuration and how it orchestrates the build and deployment lifecycle. +- Guide users on environment-specific configurations using `env/.env.dev`, `env/.env.prod`. + +## TypeSpec Agent Fundamentals + +- Declare agents using the `@agent(name, description)` decorator in the main namespace. +- Link instructions to the agent using `@instructions(Prompts.INSTRUCTIONS)` decorator. +- Add conversation starters with `@conversationStarter(#{ title, text })` to guide users. Limit the number of conversation starters to 12. +- Expose actions as operations: `op getPolicies is PoliciesAPI.getPolicies`. +- Trust the TypeSpec type system and define strong contracts for all API operations. + +## Agent Decorators + +### @agent Decorator + +- **Purpose**: Indicates that a namespace represents an agent and provides its basic metadata. +- **Parameters**: + - `name` (string, localizable, required): The name of the declarative agent. Must contain at least one non-whitespace character and must be 100 characters or less. + - `description` (string, localizable, required): The description of the declarative agent. Must contain at least one non-whitespace character and must be 1,000 characters or less. + - `id` (string, optional): The unique identifier of the agent. +- **Usage**: + + ```typespec + @agent("Policy Assistant", "An agent that helps users find and understand company policies") + namespace PolicyAgent { + // Agent implementation + } + ``` + +- **Best practices**: + - Use clear, descriptive names that convey the agent's purpose. + - Write concise but informative descriptions that help users understand when to use the agent. + - Only specify `id` when you need to maintain a specific agent identifier across deployments. + +### @instructions Decorator + +- **Purpose**: Defines the instructions that guide the agent's behavior. +- **Parameters**: + - `instructions` (string, not localizable, required): The detailed instructions or guidelines on how the declarative agent should behave, its functions, and any behaviors to avoid. Must contain at least one non-whitespace character and must be 8,000 characters or less. +- **Usage**: + + ```typespec + @instructions(Prompts.INSTRUCTIONS) + namespace PolicyAgent { + // Agent implementation + } + ``` + +- **Best practices**: + - Store instructions in a dedicated `Prompts` namespace in `instructions.tsp`. + - Use clear, directive language with keywords like **ALWAYS**, **NEVER**, **MUST**. + - Provide concrete examples of expected behavior. + - Keep instructions focused and relevant to the agent's purpose. + +### @conversationStarter Decorator + +- **Purpose**: Defines conversation starters that guide users on how to interact with the agent. +- **Parameters**: + - `conversationStarter` (ConversationStarter object, required): An object with `title` (optional) and `text` (required) properties. +- **ConversationStarter Model**: + - `title` (string, localizable, optional): A unique title for the conversation starter. Must contain at least one non-whitespace character. + - `text` (string, localizable, required): A suggestion that the user can use to obtain the desired result. Must contain at least one non-whitespace character. +- **Usage**: + + ```typespec + @conversationStarter(#{ title: "Find Policies", text: "Show me all compliance policies" }) + @conversationStarter(#{ text: "What's the vacation policy?" }) + namespace PolicyAgent { + // Agent implementation + } + ``` + +- **Best practices**: + - Limit the number of conversation starters to 12. + - Use conversation starters to showcase the agent's key capabilities. + - Make suggestions specific and actionable. + - Cover diverse use cases to help users understand the agent's range. + +### @disclaimer Decorator + +- **Purpose**: Displays a disclaimer message to users at the start of a conversation to satisfy legal or compliance requirements. +- **Parameters**: + - `disclaimer` (Disclaimer object, required): An object with a `text` property. +- **Disclaimer Model**: + - `text` (string, required): The disclaimer message. Must contain at least 1 non-whitespace character. Characters beyond 500 may be ignored. +- **Usage**: + + ```typespec + @disclaimer(#{ text: "This agent provides general information only. Consult HR for official policy interpretations." }) + namespace PolicyAgent { + // Agent implementation + } + ``` + +- **Best practices**: + - Use disclaimers when the agent handles sensitive information or provides advice. + - Keep disclaimers concise and under 500 characters. + - Ensure disclaimers comply with your organization's legal and compliance requirements. + - Review disclaimers with legal/compliance teams before deployment. + +### @behaviorOverrides Decorator + +- **Purpose**: Defines settings that modify the behavior of the agent orchestration. +- **Parameters**: + - `behaviorOverrides` (BehaviorOverrides object, required): An object with optional properties to control agent behavior. +- **BehaviorOverrides Model**: + - `discourageModelKnowledge` (boolean, optional): Indicates whether the declarative agent should be discouraged from using model knowledge when generating responses. + - `disableSuggestions` (boolean, optional): Indicates whether the suggestions feature is disabled. +- **Usage**: + + ```typespec + @behaviorOverrides(#{ discourageModelKnowledge: true, disableSuggestions: false }) + namespace PolicyAgent { + // Agent implementation + } + ``` + +- **Best practices**: + - Use `discourageModelKnowledge: true` when you want the agent to rely primarily on provided knowledge sources rather than pre-trained knowledge. + - Use `disableSuggestions: false` (default) to keep the suggestions feature enabled for better user experience. + - Test behavior overrides thoroughly to ensure they produce the desired agent behavior. + - Document the reasons for using behavior overrides in your agent documentation. + +### @customExtension Decorator + +- **Purpose**: Allows adding custom extension properties to the agent for future extensibility. +- **Parameters**: + - `key` (string, required): The key name for the custom extension property. + - `value` (unknown, required): The value for the custom extension property (can be any type). +- **Usage**: + + ```typespec + @customExtension("customProperty", "customValue") + @customExtension("featureFlag", true) + namespace PolicyAgent { + // Agent implementation + } + ``` + +- **Best practices**: + - Use custom extensions sparingly and only when needed for specific scenarios. + - Document the purpose and expected values of custom extensions clearly. + - Coordinate with Microsoft documentation or support to understand supported custom extensions. + - Be prepared for custom extensions to be ignored if not recognized by the platform. + +## Action Definitions + +- Define actions in dedicated namespaces decorated with `@service` and `@server(url)`. +- Use `@actions(metadata)` decorator to provide human-readable names and descriptions. +- Include `descriptionForModel` in action metadata to help the LLM understand when to invoke the action. +- Define operations using HTTP method decorators: `@get`, `@post`, `@put`, `@delete`. +- Specify routes with `@route("/path/{param}")` decorator. +- Use `@path`, `@query`, `@body`, `@header` decorators to define parameter sources. +- Provide default values for optional parameters (e.g., `@query type: PolicyType = PolicyType.Compliance`). +- Document all parameters with `@doc` comments explaining their purpose and constraints. +- Explain error scenarios in operation documentation (e.g., `404: Policy not found`). + +## Model Design + +- Create reusable models in a dedicated `models.tsp` file. +- Import the `models.tsp` file in the relevant `actions/*.tsp` files. +- Use descriptive model names that reflect their purpose (e.g., `PolicyInfo`, `PolicyResponse`). +- Define enums for fixed value sets (e.g., `enum AgentStatus { Active: "Active", Inactive: "Inactive" }`). +- Use proper TypeSpec primitive types: `string`, `int32`, `int64`, `float64`, `boolean`, `datetime`. +- Nest models when appropriate to avoid repetition and improve clarity. +- Add `@doc` comments to all model properties explaining their meaning and constraints. +- Use optional properties with `?` when fields may be absent (e.g., `days?: int32`). +- Leverage union types for fields that can have multiple types when needed. + +## Instruction Crafting + +- Write instructions in a dedicated `Prompts` namespace in `instructions.tsp`. +- Structure instructions with clear sections: GUIDELINES, EXAMPLES, SUGGESTIONS. +- Use strong directive keywords: **ALWAYS**, **NEVER**, **MUST** for critical rules. +- Provide concrete examples showing input, function calls, and expected output. +- Explain multi-step workflows explicitly (e.g., "First call getPolicies, then use the ID to call getStatus"). +- Include guidance on visualization when using CodeInterpreter capability. +- Document error handling strategies (e.g., "If action fails, explain the issue to the user"). +- Keep instructions concise and focused on behavior that the LLM should follow. +- Reference actions by their operation names to create clear associations. + +## Environment Configuration + +- Never manually edit `env.tsp` — it's auto-generated from `.env` files. +- Store environment-specific values in `env/.env.local`, `env/.env.dev`, `env/.env.prod`, etc. +- Run `npm run generate:env` after modifying `.env` files to regenerate `env.tsp`. +- All environment variables are in the `Environment` namespace. +- Reference environment constants using `Environment.CONSTANT_NAME` in TypeSpec files. +- Use uppercase snake_case for environment variable names (e.g., `APP_NAME_SHORT`, `POLICIES_API_ENDPOINT`). +- Never commit secrets or API keys in `.env` files — use secure storage (e.g., Azure Key Vault). +- Document required environment variables in the project README. + +## Validation and Testing + +- Always compile TypeSpec before provisioning: `npm run compile`. +- Fix all compilation errors and warnings before moving forward. +- Provision to local environment first: `atk provision --env local`. +- Test the agent in Microsoft 365 Copilot playground with diverse queries. +- Validate that the agent follows instructions (e.g., calls actions in the correct order). +- Test error scenarios: missing parameters, invalid IDs, API failures. +- Verify CodeInterpreter visualizations render correctly. +- Confirm conversation starters appear and work as expected. +- Test with multiple phrasings to ensure consistent agent behavior. +- Create test cases for critical workflows and validate after instruction changes. + +## Multi-Step Workflows + +- Guide the agent through multi-step workflows with explicit instructions. +- Example: "When the user asks about policies by agent name: 1- Call getAgents to get all agents IDs, 2- Match the user's requested name to an ID, 3- Call getAgentPolicy with that ID." +- Document prerequisite data fetching requirements in instructions. +- Explain fallback behavior when prerequisites fail (e.g., agent not found). +- Use action chaining judiciously to avoid overly complex workflows. + +## Capabilities Best Practices + +Microsoft 365 Copilot agents support multiple capabilities that extend the agent's functionality. Enable only the capabilities your agent needs. + +### General Capability Guidelines + +- Enable capabilities explicitly using `op capabilityName is AgentCapabilities.CapabilityName` syntax. +- Only enable capabilities that your agent will actively use — unnecessary capabilities increase complexity. +- Test each capability thoroughly in the Microsoft 365 Copilot playground before deployment. +- Document in your instructions how and when the agent should use each enabled capability. +- Combine capabilities strategically to create powerful multi-modal experiences. +- DO NOT add instructions related to the capabilities. + +### WebSearch Capability + +- **Enable (unscoped)**: `op webSearch is AgentCapabilities.WebSearch` +- **Enable (scoped)**: + + ```typescript + op webSearch is AgentCapabilities.WebSearch + ``` + +- **Purpose**: Allows the agent to search the public web for current information. +- **Scoping**: + - **CRITICAL**: Scoping is done via the `TSites` property in the capability definition, **NOT** in instructions. + - **NOT scoped**: Omit `TSites` array to allow searching all web content. + - **Scoped**: Specify `TSites` array with URLs to restrict web search to specific domains/sites. + - The agent will only search content from the specified URLs when scoped. + - A maximum of 4 URLs can be used. +- **Best practices**: + - Use when your agent needs real-time or recent information not available in your APIs. + - Scope to specific domains when you want to limit search to trusted sources (e.g., company documentation sites). + - Instruct the agent on when to prefer web search vs. internal actions (e.g., "Use web search only if internal data is unavailable"). + - Guide the agent to cite sources from web results in responses. + - Be aware that web search results may vary and are not under your control. + - Consider privacy implications when combining web data with internal data. +- **Example instruction**: "If the user asks about current events or recent news, use web search. Always cite your sources." +- **Example (scoped to Microsoft Learn)**: + + ```typescript + op webSearch is AgentCapabilities.WebSearch + ``` + +### OneDriveAndSharePoint Capability + +- **Enable (unscoped)**: `op oneDriveAndSharePoint is AgentCapabilities.OneDriveAndSharePoint` +- **Enable (scoped by URL)**: + + ```typescript + op od_sp is AgentCapabilities.OneDriveAndSharePoint + ``` + +- **Enable (scoped by SharePoint ID)**: + + ```typescript + op od_sp is AgentCapabilities.OneDriveAndSharePoint + ``` + +- **Purpose**: Enables the agent to search and access files in the user's OneDrive and SharePoint. +- **Scoping**: + - **CRITICAL**: Scoping is done via `ItemsByUrl` or `ItemsBySharePointIds` properties in the capability definition, **NOT** in instructions. + - **NOT scoped**: Omit both `ItemsByUrl` and `ItemsBySharePointIds` arrays to allow access to all OneDrive and SharePoint content available to the user. + - **Scoped by URL**: Use `ItemsByUrl` with full paths to SharePoint sites, document libraries, folders, or files. + - **Scoped by SharePoint ID**: Use `ItemsBySharePointIds` for more precise control using SharePoint internal IDs. + - URLs should be full paths (use "Copy direct link" in SharePoint: right-click → Details → Path → copy icon). +- **Best practices**: + - Use when your agent needs to work with user documents, spreadsheets, or presentations. + - Scope to specific sites/folders when you want to limit access to relevant content areas. + - Respect user permissions — the agent can only access files the user can access. + - Instruct the agent on file type preferences (e.g., "Prioritize Excel files for financial data"). + - Guide the agent to summarize file contents rather than returning raw data. + - Combine with CodeInterpreter to analyze data from files (e.g., Excel sheets). + - Be explicit about file name patterns or document types in instructions. +- **Example instruction**: "When the user asks about project documentation, search SharePoint for files matching the project name. Summarize key findings." +- **Example (scoped to Audits folder)**: + + ```typescript + op odsp is AgentCapabilities.OneDriveAndSharePoint + ``` + +### TeamsMessages Capability + +- **Enable (unscoped)**: `op teamsMessages is AgentCapabilities.TeamsMessages` +- **Enable (scoped)**: + + ```typescript + op teamsMessages is AgentCapabilities.TeamsMessages + ``` + +- **Purpose**: Allows the agent to use Teams channels, teams, and meeting chats as knowledge sources. +- **Scoping**: + - **CRITICAL**: Scoping is done via the `TeamsMessagesByUrl` property in the capability definition, **NOT** in instructions. + - **NOT scoped**: Omit `TeamsMessagesByUrl` array to allow access to all Teams channels, teams, meetings, 1:1 chats, and group chats available to the user. + - **Scoped**: Specify `TeamsMessagesByUrl` array with well-formed Teams URLs to restrict access to specific teams, channels, or chats. + - URLs must be valid Teams links (copy from Teams: team/channel → "..." menu → "Get link to channel/team"). +- **Best practices**: + - Use when your agent needs context from team conversations or project discussions. + - Scope to specific teams/channels when you want to limit to project-specific or department-specific conversations. + - Respect user permissions — the agent can only access messages the user can see. + - Instruct the agent to respect conversation context and thread relationships. + - Guide the agent to cite message authors and timestamps when referencing Teams content. + - Be aware of privacy and confidentiality when using Teams messages as knowledge. + - Consider combining with People capability to provide context about message authors. +- **Example instruction**: "When the user asks about project decisions, search Teams messages for discussions related to the topic. Cite the author and date of relevant messages." +- **Example (scoped to Engineering team)**: + + ```typescript + op teamsMessages is AgentCapabilities.TeamsMessages + ``` + +### Email Capability + +- **Enable (unscoped user mailbox)**: `op email is AgentCapabilities.Email` +- **Enable (scoped to specific folders)**: + + ```typescript + op email is AgentCapabilities.Email + ``` + +- **Enable (scoped to shared mailbox)**: + + ```typescript + op email is AgentCapabilities.Email + ``` + +- **Purpose**: Allows the agent to use email from the user's mailbox or a shared mailbox as a knowledge source. +- **Scoping**: + - **CRITICAL**: Scoping is done via `Folders` and `SharedMailbox` properties in the capability definition, **NOT** in instructions. + - **NOT scoped**: Omit `Folders` array to allow access to the entire mailbox. + - **Scoped by folders**: Use `Folders` array with folder IDs (e.g., "Inbox", "SentItems", "Drafts", custom folder names). + - **Scoped to shared mailbox**: Use `SharedMailbox` property with the shared mailbox email address. + - Can combine shared mailbox with folder scoping for precise control. +- **Best practices**: + - Use when your agent needs to answer questions based on email correspondence. + - Scope to specific folders when you want to limit to relevant email categories (e.g., only customer support emails). + - Use shared mailboxes for team-wide email knowledge (e.g., support@, sales@). + - Respect user permissions — the agent can only access emails the user can access. + - Instruct the agent on how to handle sensitive information in emails. + - Guide the agent to cite sender, date, and subject when referencing emails. + - Be aware of privacy and confidentiality when using email as knowledge. + - Consider date range instructions to focus on recent communications. +- **Example instruction**: "When the user asks about customer inquiries, search emails for relevant correspondence. Summarize key points and include sender and date." +- **Example (scoped to support shared mailbox Inbox)**: + + ```typescript + op email is AgentCapabilities.Email + ``` + +### People Capability + +- **Enable**: `op people is AgentCapabilities.People` +- **Purpose**: Allows the agent to answer questions about individuals in the organization. +- **Scoping**: + - **NOTE**: This capability does not support scoping parameters. + - The agent can access information about all people in the organization directory that the user has permission to view. +- **Best practices**: + - Use when your agent needs to provide information about team members, org structure, or contact details. + - Instruct the agent on what people-related queries to handle (e.g., "Find contact info", "Who reports to X?"). + - Guide the agent to respect privacy and only share publicly available directory information. + - Combine with other capabilities to provide context (e.g., Teams messages + People to understand who said what). + - Be clear about what information is appropriate to share about people. + - Consider compliance and privacy regulations when enabling this capability. +- **Example instruction**: "When the user asks about team members or contacts, use the People capability to find relevant individuals. Provide names, roles, and contact information." +- **Example**: + + ```typescript + op people is AgentCapabilities.People; + ``` + +### GraphicArt Capability + +- **Enable**: `op graphicArt is AgentCapabilities.GraphicArt` +- **Purpose**: Enables the agent to generate images based on user prompts. +- **Scoping**: + - **NOTE**: This capability does not support scoping parameters. + - The agent can generate images based on any user prompt. +- **Best practices**: + - Use when your agent needs to create visual content, diagrams, or illustrations. + - Instruct the agent on when to generate images vs. describe content textually. + - Guide the agent on image style preferences (e.g., "Generate professional diagrams", "Use corporate color scheme"). + - Set expectations about generation time and potential limitations. + - Provide examples of appropriate image generation requests in instructions. + - Consider content policy and appropriateness of generated images. + - Inform users that generated images are AI-created and may need review. +- **Example instruction**: "When the user requests visual representations, diagrams, or illustrations, use the GraphicArt capability to generate images. Always describe what the image will show before generating." +- **Example**: + + ```typescript + op graphicArt is AgentCapabilities.GraphicArt; + ``` + +### CopilotConnectors Capability + +- **Enable (unscoped)**: `op graphConnectors is AgentCapabilities.CopilotConnectors` +- **Enable (scoped)**: + + ```typespec + op copilotConnectors is AgentCapabilities.CopilotConnectors + ``` + +- **Purpose**: Allows the agent to search content ingested via Microsoft Graph connectors. +- **Scoping**: + - **CRITICAL**: Scoping is done via the `Connections` generic parameter in the capability definition, **NOT** in instructions. + - **NOT scoped**: Omit `Connections` parameter to allow access to all Graph connectors available to the user. + - **Scoped**: Specify `Connections` parameter with connection IDs to restrict to specific connectors. + - Connection IDs can be found using Microsoft Graph API or admin tools. +- **Best practices**: + - Use when your organization has external data sources connected via Graph connectors. + - Scope to specific connectors when you want to limit to relevant external data sources. + - Ensure Graph connectors are properly configured and content is indexed before enabling. + - Document the types of data available through each Graph connector in your agent documentation. + - Guide the agent on when to prefer Graph connector data vs. direct API calls. + - Test with real indexed content to validate search quality and relevance. + - Monitor connector health and data freshness. +- **Example instruction**: "Search Graph connectors for customer support tickets when the user asks about customer issues. Provide ticket numbers and summaries." +- **Example (scoped to policies connector)**: + + ```typespec + op copilotConnectors is AgentCapabilities.CopilotConnectors + ``` + +### CodeInterpreter Capability + +- **Enable**: `op codeInterpreter is AgentCapabilities.CodeInterpreter` +- **Purpose**: Enables the agent to write and execute Python code for data analysis and visualization. +- **Scoping**: + - **NOTE**: This capability does not support scoping parameters. + - The agent can execute Python code for any user request. +- **Best practices**: + - Use when your agent needs to perform calculations, data transformations, or create visualizations. + - Ensure data returned from actions is in a format compatible with Python libraries (JSON, CSV-style arrays). + - Instruct the agent on preferred visualization types (e.g., "Use line charts for trends, bar charts for comparisons"). + - Guide formatting requirements: "Always start y-axis at 0", "Add descriptive titles and axis labels". + - Test visualizations with sample data to confirm proper rendering. + - Provide fallback instructions if visualization fails (e.g., "If chart generation fails, provide data in a table"). + - Be aware of execution timeouts for long-running computations. + - Document any data preparation requirements (e.g., "Ensure dates are in ISO 8601 format"). +- **Example instruction**: "When displaying usage trends, use CodeInterpreter to create a line chart with dates on x-axis and usage count on y-axis. Always include a descriptive title." +- **Example**: + + ```typespec + op codeInterpreter is AgentCapabilities.CodeInterpreter; + ``` + +### Meetings Capability + +- **Enable**: `op meetings is AgentCapabilities.Meetings` +- **Purpose**: Allows the agent to search meeting content. +- **Scoping**: + - **NOTE**: This capability does not support scoping parameters. + - The agent can search through meeting content that the user has access to. +- **Best practices**: + - Use when your agent needs to access information from meeting transcripts, recordings, or notes. + - Respect user permissions — the agent can only access meetings the user can see. + - Guide the agent to cite meeting titles, dates, and participants when referencing meeting content. + - Consider combining with People capability to provide context about meeting participants. + - Be aware of privacy and confidentiality when using meeting content as knowledge. +- **Example instruction**: "When the user asks about decisions made in meetings, search meeting content for relevant discussions. Include the meeting date and key participants." +- **Example**: + + ```typespec + op meetings is AgentCapabilities.Meetings; + ``` + +### ScenarioModels Capability + +- **Enable**: + + ```typespec + op scenarioModels is AgentCapabilities.ScenarioModels + ``` + +- **Purpose**: Allows the agent to use task-specific models for specialized scenarios. +- **Scoping**: + - **CRITICAL**: The `Models` parameter is **required** and must contain at least one model ID. + - Specify `Models` parameter with model IDs to enable specific task-specific models. + - Model IDs are provided by Microsoft and identify specialized AI models for specific tasks. +- **Best practices**: + - Use when your agent requires specialized models for domain-specific tasks. + - Ensure you have the appropriate licenses and permissions for the models you specify. + - Document which models are being used and their purpose in your agent documentation. + - Test thoroughly with the specific models to ensure expected behavior. + - Monitor model availability and updates from Microsoft. +- **Example instruction**: "Use specialized models for domain-specific analysis when processing user queries." +- **Example**: + + ```typespec + op scenarioModels is AgentCapabilities.ScenarioModels + ``` + +### Dataverse Capability + +- **Enable (unscoped)**: `op dataverse is AgentCapabilities.Dataverse` +- **Enable (scoped)**: + + ```typespec + op dataverse is AgentCapabilities.Dataverse + ``` + +- **Enable (scoped with tables)**: + + ```typespec + op dataverse is AgentCapabilities.Dataverse + ``` + +- **Purpose**: Allows the agent to search for information in Microsoft Dataverse. +- **Scoping**: + - **CRITICAL**: Scoping is done via the `KnowledgeSources` generic parameter in the capability definition, **NOT** in instructions. + - **NOT scoped**: Omit `KnowledgeSources` parameter to allow access to all accessible Dataverse environments. + - **Scoped by environment**: Specify `KnowledgeSources` parameter with environment hostnames. + - **Scoped by tables**: Include `tables` array within a knowledge source to limit to specific Dataverse tables. + - **Scoped by skill**: Include `skill` property to use a specific skill identifier. +- **Best practices**: + - Use when your agent needs to access business data stored in Dataverse. + - Scope to specific environments and tables when you want to limit access to relevant data. + - Respect user permissions — the agent can only access Dataverse data the user has permission to view. + - Document the Dataverse schema and table relationships in your agent documentation. + - Guide the agent on how to interpret Dataverse entity relationships and field meanings. + - Consider combining with other capabilities for richer experiences (e.g., Dataverse + CodeInterpreter for data visualization). + - Test with real Dataverse data to ensure proper query formation and result interpretation. +- **Example instruction**: "When the user asks about customer information, search Dataverse for account and contact records. Provide relevant details while respecting data privacy." +- **Example (scoped to specific environment and tables)**: + + ```typespec + op dataverse is AgentCapabilities.Dataverse + ``` + +### Combining Capabilities + +- **Multi-modal experiences**: Combine capabilities to create powerful workflows. + - Example: OneDriveAndSharePoint + CodeInterpreter = "Find the sales Excel file and create a chart showing monthly revenue." + - Example: WebSearch + GraphConnectors = "Search internal knowledge base first, then supplement with web search if needed." + - Example: Email + People = "Find emails from my manager and provide their contact information." + - Example: TeamsMessages + People = "Search our team channel for decisions made by the engineering lead." + - Example: GraphicArt + WebSearch = "Search for the latest design trends and generate a mockup image." +- **Capability orchestration**: Provide clear instructions on the order of capability usage. + - Example: "First search SharePoint for the report. If not found, search Graph connectors. If still not found, use web search as a last resort." + - Example: "When asked about team communications, search Teams messages first, then check emails if no Teams conversations are found." +- **Performance considerations**: Multiple capabilities in one interaction may increase latency. +- **User experience**: Make capability usage transparent by mentioning sources (e.g., "Based on files in your SharePoint...", "According to Teams messages in the Engineering channel..."). + +## Error Handling + +- Document expected error codes in operation comments (e.g., `404: Not found`, `403: Forbidden`). +- Provide guidance in instructions for handling errors (e.g., "If 404, inform user the agent doesn't exist"). +- Recommend retry strategies for transient errors (5xx, timeouts) in instructions. +- Avoid retrying client errors (4xx) — they indicate bad requests. +- Return helpful error messages in API responses to aid agent responses. + +## API Versioning + +- Version API operations when introducing breaking changes (e.g., `getAgents_v1`, `getAgents_v2`). +- Use separate namespaces for different API versions if needed. +- Update agent definitions to reference the latest version explicitly. +- Maintain backward compatibility when possible to avoid disrupting existing agents. +- Document version differences and migration paths in comments. + +## Performance Optimization + +- Use efficient query patterns to minimize API latency. +- Implement pagination for operations that return large datasets. +- Cache frequently accessed data when appropriate (e.g., agent lists). +- Set reasonable defaults for query parameters (e.g., `limitDays: int32 = 720`). +- Monitor action latency and optimize slow endpoints. +- Explain performance considerations in operation documentation. + +## Deployment and DevOps + +- Provision to development environment first: `atk provision --env dev`. +- Use environment-specific configurations for each deployment stage. +- Implement health checks for backend APIs referenced by actions. +- Monitor agent usage and action invocations to identify issues. +- Set up CI/CD pipelines for automated compilation, validation, and deployment. +- Document rollback procedures in case of production issues. +- Explain deployment stages and environment promotion in project documentation. + +## Security Best Practices + +- Never hardcode secrets or API keys in TypeSpec files. +- Use environment variables for sensitive configuration. +- Implement proper authentication for backend APIs. +- Validate all user inputs in backend services, not just in TypeSpec definitions. +- Document authentication requirements in action metadata. +- Review generated manifests for unintended information disclosure. +- Follow principle of least privilege when granting API permissions. +- Conduct security reviews before deploying to production. + +## Documentation Standards + +- Add `@doc` comments to all public operations, models, and namespaces. +- Explain the purpose of each action in `descriptionForModel`. +- Document parameter constraints (e.g., "GUID format required", "positive integer"). +- Provide examples in comments for complex operations. +- Keep documentation up to date when changing TypeSpec definitions. +- Explain design decisions in comments when using non-obvious patterns. +- Reference related operations and models in documentation for discoverability. + +## Troubleshooting Common Issues + +- **Compilation fails**: Check for syntax errors, missing imports, type mismatches. Read error messages carefully for line numbers and hints. +- **Agent doesn't appear in Copilot**: Verify provisioning succeeded, check manifest validity, clear browser cache and re-authenticate. +- **Agent calls wrong action**: Strengthen instructions with explicit rules, improve `descriptionForModel`, add examples showing correct behavior. +- **CodeInterpreter doesn't visualize**: Ensure capability is enabled, add explicit visualization instructions, verify data format compatibility. +- **Provision hangs**: Check network connectivity, verify Microsoft 365 service health, simplify agent temporarily to isolate issue. +- **Action returns errors**: Review backend API logs, verify authentication, check parameter types and values. + +## Advanced Patterns + +- **Conditional operations**: Define multiple operations for different query types and guide selection via instructions. +- **Parameterized queries**: Offer flexibility with optional parameters and sensible defaults. +- **Multi-file projects**: Split large agents into logical modules (usage.tsp, feedback.tsp, admin.tsp). +- **Mock data for testing**: Create test harnesses that simulate Copilot requests to validate instruction adherence. +- **Telemetry integration**: Add telemetry to track action usage, latency, and errors for continuous improvement. + +## Best Practices Checklist + +- [ ] Compile TypeSpec without errors before provisioning +- [ ] Provide clear `@doc` comments for all operations and models +- [ ] Define strong types for all parameters and responses +- [ ] Include `descriptionForModel` for all actions +- [ ] Write explicit, testable instructions with examples +- [ ] Handle error scenarios gracefully +- [ ] Use environment variables for configuration +- [ ] Add conversation starters to guide users +- [ ] Version API operations for breaking changes +- [ ] Document deployment and rollback procedures +- [ ] Monitor agent usage and performance +- [ ] Gather user feedback and iterate on instructions +- [ ] Keep dependencies up to date + +--- + +**Remember**: TypeSpec is your contract. Write it clearly, compile it often, test it thoroughly, and deploy it confidently. The agent's quality reflects the clarity of your TypeSpec definitions and instructions. diff --git a/samples/da-azure-devops-wiki/README.md b/samples/da-azure-devops-wiki/README.md new file mode 100644 index 000000000..8580b23fe --- /dev/null +++ b/samples/da-azure-devops-wiki/README.md @@ -0,0 +1,88 @@ +# Azure DevOps Wiki Assistant + +## Summary + +A read-only Microsoft 365 Copilot **declarative agent** grounded **strictly** on the [Azure DevOps Wiki Copilot connector](https://learn.microsoft.com/microsoft-365/copilot/connectors/azure-devops-wiki-deployment). It searches your organization's indexed project and code wikis, answers how-to questions, preserves the guide's numbered steps and reference tables, **cites the source page**, and clearly says when an answer isn't in the wiki instead of guessing. + +The key idea this sample demonstrates: a Copilot connector makes your wiki *searchable*, but it does not make an agent *trustworthy*. The agent's **instruction block** is what keeps it grounded — it answers only from retrieved wiki content, never from general knowledge, and admits when it doesn't know. + +Built with **TypeSpec** and the **Microsoft 365 Agents Toolkit**, so the agent definition lives in source control and retargets to any tenant by changing a single environment variable — no code change. + +![Azure DevOps Wiki Assistant answering a how-to question in Microsoft 365 Copilot with step-by-step guidance and citations to the source wiki page](assets/demo.png) + +## Contributors + +* [Ejaz Hussain](https://github.com/ejazhussain) + +## Version history + +Version|Date|Comments +-------|----|-------- +1.0|August 22, 2026|Initial release + +## Prerequisites + +* A Microsoft 365 tenant with **Microsoft 365 Copilot** licensing. +* The **Azure DevOps Wiki** Copilot connector deployed and in the **Ready** state. See [Deploy the Azure DevOps Wiki connector](https://learn.microsoft.com/microsoft-365/copilot/connectors/azure-devops-wiki-deployment). The crawl account needs at least **Basic** access to the Azure DevOps projects (Stakeholder is not sufficient). +* [Node.js](https://nodejs.org/) 18+ (built and tested on Node 22 / npm 10). +* [Microsoft 365 Agents Toolkit](https://aka.ms/m365atk) — the Visual Studio Code extension, or the `atk` CLI (`npm i -g @microsoft/m365agentstoolkit-cli`). + +## Minimal path to awesome + +* Clone this repository (or [download this solution as a .ZIP file](https://pnp.github.io/download-partial/?url=https://github.com/pnp/copilot-pro-dev-samples/tree/main/samples/da-azure-devops-wiki) then unzip it). +* From a terminal, change to the `samples/da-azure-devops-wiki` folder. +* **Find your connector's connection id.** The agent binds to the connector by its Microsoft Graph connection `id`, which can differ from the display name shown in the admin center. As a tenant admin, in [Graph Explorer](https://developer.microsoft.com/graph/graph-explorer) (scope `ExternalConnection.Read.All`), run: + + ```http + GET https://graph.microsoft.com/v1.0/external/connections?$select=id,name + ``` + + Copy the `id` of your Azure DevOps Wiki connection. +* **Set your environment values.** Open `env/.env.dev` and set `ADO_WIKI_CONNECTION_ID` to the connection `id` from the previous step. Leave the toolkit-generated values (such as `TEAMS_APP_ID`) blank — they are filled in during provisioning. +* **Install and compile** to verify the agent definition builds: + + ```bash + npm install + npm run generate:env -- dev + npm run compile + ``` + + > `generate:env` must run before `compile` on a fresh clone, because `src/agent/env.tsp` is generated (git-ignored) and `main.tsp` imports it. The Agents Toolkit pipeline does this automatically during provisioning. +* **Provision and preview:** + * **Visual Studio Code:** open the folder, sign in to Microsoft 365 in the Agents Toolkit pane, then use **Provision** (dev), or run **Preview Local in Copilot** to sideload the agent. + * **CLI:** `atk provision --env dev`. +* Open Microsoft 365 Copilot at [m365.cloud.microsoft/chat](https://m365.cloud.microsoft/chat), open the agents drawer, and select **Azure DevOps Wiki Assistant**. +* **Test the grounding** with one of the conversation starters (a topic your wiki covers) and confirm the answer includes a citation to the correct wiki page. Then ask something the wiki does not cover and confirm the agent replies that it could not find the answer — rather than answering from general knowledge. + +## Features + +Using this sample you can extend Microsoft 365 Copilot with an agent that: + +* Searches, summarizes, and answers from the Azure DevOps Wiki connector, **with citations** back to the source pages. +* Is **strictly grounded** — it never uses general world knowledge or web content, and states plainly when an answer is not in the wiki. +* Preserves the wiki guide's structure — numbered steps in order and reference tables (for example access levels or ticket priorities) reproduced when relevant. +* Is **permission-aware** — because the connector is permission-trimmed, users only see wiki content they already have access to. +* Is **read-only** by design — it does not create, edit, or delete content, and has no other knowledge sources. + +This sample illustrates: + +* Defining a declarative agent in **TypeSpec** with the Microsoft 365 Agents Toolkit. +* Binding an agent to a **Copilot connector** as its only knowledge source (`AgentCapabilities.CopilotConnectors`). +* Retargeting tenants through an environment variable (`ADO_WIKI_CONNECTION_ID`) instead of editing the agent definition. +* Authoring a strict-grounding **instruction block** and validating it with sample evaluation prompts (`evals/prompts.json`). + +## Help + +We do not support samples, but this community is always willing to help, and we want to improve these samples. We use GitHub to track issues, which makes it easy for community members to volunteer their time and help resolve issues. + +You can try looking at [issues related to this sample](https://github.com/pnp/copilot-pro-dev-samples/issues?q=label%3A%22sample%3A%20da-azure-devops-wiki%22) to see if anybody else is having the same issues. + +If you encounter any issues using this sample, [create a new issue](https://github.com/pnp/copilot-pro-dev-samples/issues/new). + +Finally, if you have an idea for improvement, [make a suggestion](https://github.com/pnp/copilot-pro-dev-samples/issues/new). + +## Disclaimer + +**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.** + +![](https://m365-visitor-stats.azurewebsites.net/copilot-pro-dev-samples/samples/da-azure-devops-wiki) diff --git a/samples/da-azure-devops-wiki/appPackage/color.png b/samples/da-azure-devops-wiki/appPackage/color.png new file mode 100644 index 0000000000000000000000000000000000000000..11e255fa0b831ca86ff380e109882ffdca5dc3d2 GIT binary patch literal 5923 zcmdUzE!S;tIkI1(i7JC%D`W{_2j7|h@a9Eg`&12yHEgW#QwnQNMGd~FaNEOWYC6WST zcZCMu!HEEpWP|_#oED%q`v3HTFuZ|y+lNs+_!4Z~Zjy(d0W_(y1U(XAVUcT^=cKak z4ZM%C#_10i+)r@-G-1{2`)#E4q$U02q38G|njRKtjhY=CL_nXEKKj?@S##X?KE8sr z%UXd=qa@yf%Qq~72`hN09a4Pm^Y)PmK}S)qfiT@GFtBWki31pinT)x9-lrc6hR<$K zQA6-4&~z{H^VYcX-2*|q1(zr_$T3X(b)MXYxA>@$a@W|%91gEAcWnDeC~-W_v5#-= z$HZ4F#y(oAC}mU33_qwx@*wWL_3p?PW`MfDh1Lcy<&vba#OBmb9bvYP7FVBDGh%0? zm@KEGXnk!h@5nG;uL=2h;45J02{xg}x&Cf>0oB+IrFZ6Lnhhzj>xTc8(i^bO)YLvC|I-T8xbFP%rhFUaN zU5d&hZ2G%&AexO-+tUQsFtjQ--6T9a!OG8)qa1;k9yW`VE|fa#QXCDUNOhjltt^wu zxBgMU0*jUTmr?-7xFS;x%Z*wRk>Kz9x4t|`i@OrBkQuZvc=!OxXRy6c?Ti3CBjf{- zTLD2+>`FXZak0F6fp!q%{@q#hqo z;&)XoPnlsZVTjwsAV&7Zzwzb;S{Qj?Okh?1##?4Zzk8hBVmec~AttTouhJ8)EK1`xtc6OW*^Y-=!BQc5XQucG z9sYg`!G!aQLdLVnXEX+ljF%bp8{hBdnOx%z<(+!|Gdzm2eS=rVmmPoDIwBk^n;q%)3I}^%X};rI#=4y_M2Gfor9gWeJoSV4 z_p0{~dhNf|2<65@74T}=FySA2zsi)p0+$B?d1Slk*uAh(rQtAE>RegJuQ7EYyiFzK zm?=a_7K`kjxk1|Yq#Q)C{NC3`6~?d^bn=KwPE6KguT+dZeg`PlN%clrL*%k50Auh? zR-};f@_X9-Of2JusPeyx3R3_bJ7Fw0EGbSc%ibQUkIK zDgKaKG}ne~68GtTt=D0>Oey7*$5p^uePagE@WOk0N5;jWKRnJSt3hY~2_W*CF?UQEu6jpy$KJ6Gq*qhm%5Y$-!+>AAlDSWqwqjde@yd^? zT@h*`B*Z4(YlKF7I>Sn;^+NyNi?xk4 zt3I1&v|k6&KA=}J>hy^D)Ft?O(SK&80qS=`XF?^B!`zQ+Nx-Q|!!t7g864Sz&9j^8v+$OZ%3-1`n15j~h-L}HvJ74Xdb44P*FdY6>5kx##Kd>mUl zxt+N(Yp>VxFlQo(WS^2l6XtCA)MGW)Snpc?*B+3uRIfLEbHVR0;$oq02ecDq?K!%-Rqw>&!sBwwOMx%ZA{0D`gH%n>=SykYg`_CaRc5?vgGY$+B^`p7SGaP^7xwAlqw* zxMEQU#U~8wfBRk2%uJV1Ee{XAa(K>+Tm}jsSOU?FXMUEP!rp>{!)(c4YyqF_xy8n3 z*YVDMVqN_QZ=a1^mIa3Q>!t62JxZFoSoU3Cp~l-XEH$su?ln9j%W0H#^Yq|)K78s= zE`UjH9FZ(8^_TCQ_knKP<34QA{N;<=v7;=MJ@JzUJiq<%4H;QOuTxrk+9c`6X0y|> z`a>Q|H1W3W~axyT5xobs02&j$GcLnfscM{RAW4SB$p z>6*qjR>+rcetSytBh$Q*F{T=2!49{V-;8!Ur?NQ~lpR1n2t9&fB4nR6)t0{50Y0ZP znG$B{CjBB%++e)VT;D3sQ7n8}boovL8)mL(_1EJBN?l)w+)qxO#lCJ=lck!hRid}j2E2%L-Ti*&?_M=?@Vuf-#{0; zU83khE?^jrOdcpu-Fq(*LyX|CG}3=ONKv&25|U!`Q;jB0?76Y$9)Zh*i zVh;}D4M(Flm&B#Nn7Lv=eO#)@+-qn<<$H-s-6O{W_)dH|TOP=!yFv1nw>dS*Fa?~xk^<#AR z$VcU}SyO+cL3S`DdT*ggV=LB&`3~)0Su~;MR1WRqpb*JZKv`omCbQj}J=T2j>oGI)-B%x9a>2jcU*A+K* zvr=ucL79XWD_$lM$p?!;g>a;N5cF(eat0C}c4P_g`Y)7`^S{3O$uye&dXw%WOA%(R zfpj+gMjq9npwfqkZEKLI%@7{SWhfb~-wPsV=F7|op46THGfUdC3gQY{jY89&R&7u{ z0l>!}GN)n~wFjE~Ms_`; z5#MHDq{CiA7{8Qb^%N4(`V}- zuu`o##+B(@(mGnb_O&*?u~KwrDX@(%F%(ryYx3LF-F}tbL>E|n z@bcN|U#aM4j$C1Ny6>uA?04WNZ1mGYmRZtwSs$W)yr|}^clTYcd?8Y4ZyJFM$6bBj zT-t=C%{2&AT4L-ud1o2f6tw9+E9Z79ztDy1%7Z}4hX9{wx8|Ap^APV>`(sS8+<;G$ zkJ3cj#o(^?@fnQpj|`q8eOW@Ck?y<@2vBm{U(9mf&M%$Xb(6k?UizJR$_KC947X%} zNIYLS+uJ4$#(4~F`eI+vIdC`Uy(B#*tJfTSR80gwK2nZR6|(gk6Wt*fXSWFc*xK+ZMYQ)~;2&Dzkz8krFmxCBP>SPCLCcBJO&U#$zp0`N*(`s~m@fErgf*lR+G!iM(Fih=!aUY3JC4uP;k8W5pf8^>bx;o^q zL#a7`7J;*5@GJ?2_kLxwpt?ngdRWo8+5a4p6UzAREkko6RLs?akTM8)J^yv&D0Cx- zPb)dA57N2~aGQ-}TO8E9Yq|PkIY)Q@d*ME?`?Y;DaPG&yorFjZD&0#Z%y>Sf*rbS! z?hP+|#YvDA!B&@rR*MUq@EH}Bd9}fidRW&bZWKx45IzJ7njzyfJA=zz!`kIER|*!m z_p(1L+@J*RQaZy`bCGsuG|o#>PD&XIa#mP9$8XotMU!Z zOLTZrBYUNWA_AP0Ft&|sXkk6tkbqeF5Hpq>U`3U$*dp!oo?dzl*YIn{pPdQ`ko`=f zwUawlnu6Zc(mv_|?3Jb3Db|xPyC}WfKK-LJ3omT#`msnQYPmTupHkCwQj>% zv(iEh{KH7>`UtwB1G&batYHX+;PAM(f)*Q&&6%%fKQn`*7U6W?D|gQZKoZ>^f55h+ zJb1k7H5-!WDYtg@K&u=HrLIkoOvh?ydnj{!zn=7ip_BigR(UU0FGd57OQSKL0F&Xx zr^%xJ11~`xtd$30UA*#7<%$o16aAgTpqn2)VKs4d-1j654UEJx0~b##@B7F}-H&6g zE`MPqO3Rj+F&JOW9jb_t*by^RoRN7dk$8x)=?qbBdVOD}mAg60z7Z*+8OaE)jND5F z73DAxxAb`YuW2U@LW)DmYgsO|65Bv0UDURq@y!MSPkN&2*I6@lBJ}z_gJ=${ucHQ% z`2O_<@9=YlHy={0={6rnzG$H*uTajGn$TjU^vJ;ZPlK4(6o30~K1I+?LG%;-gxKGX z+ln3yJKEeskPL!+9W3Y{t4x>?rQr7R^ofnk`LU&fu|<>d0U-fh^DQrmA6gl$*>HE8 zSVb1S;4zgvy;DHUNVILODA&95RFb-GMU_8uSE$sb*Kr>yO+mVq$P7(h2(xV5q+a@@GDppSPAlvvQ(qAd4X%ATlM zAUMUBN^4XH?Ru4eIom?vTqLs)AuLx{y>uACJ0k`C-2ePpE|xzHkLV{l|Jf<{-=8;c zHZ-w+E1&52d@WJ=_|Ii9{EgN5&0ztdLC>vJs|8_=`Z-+KR}GUIL=4Bx1H|li37~P` zNaT~?Vx3bK-v+aG)e;+@Nx;iEq0S68-tf+dYxC25Y-FkwBaJ9h|I5JId?o$CO#zp( z_A;6(%AFU26j5lJ?LxTT&k2F)&DA(}gY^&(B|VFV0U2S2C=DzAhp>NZ+LG0pF z$F3c(FJ=Vw?v){<_9V`vw@-rFMH~W^WIL)rIIhK^C!yk4OcX!VTNb4>_cK*9s-1kY z#fIcy)j`|BnTf18c(US{uu&_6*^?dpS`%FU217hOU%wbVH3+s8(OR#uy=%8^G?RWB z_?Nso!tmGSEEY?Rk(xgBwEm4SevfYO!O=ASs+`Rf`z&TvzBb{QfBK9PTIxWW+sHWk zeP~8ShYPo$t|-pVi!wj=oV(+18#U?`9&mbU^LJtrdVGC99E8|H;{QNYO_ zMYzTB+BRtahSBJ4s=5|IvP~$fSuRX%Hd2G9$*WGrcTN1vnHMr^eqqH=mZKAZrayT` zXBdr-LBeMO+Qp8ITRJ8sD;eHRPV*~{Hl@vMRYz+49{W?pI9CA-i3OhS)lw48&VzG} z3E@xJwYSY?7evbU2r3n4BIT)+UiCx4t-3Q(zo|U12zJd zfB~Og9|&86Vk+vmv-Grc`#nb$K>Y;bS9%{yqk{ea60QD^|LRnD@I@=mT{6Vx#;3i_ TvMtV90~2)p5d literal 0 HcmV?d00001 diff --git a/samples/da-azure-devops-wiki/appPackage/manifest.json b/samples/da-azure-devops-wiki/appPackage/manifest.json new file mode 100644 index 000000000..02a59942f --- /dev/null +++ b/samples/da-azure-devops-wiki/appPackage/manifest.json @@ -0,0 +1,32 @@ +{ + "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.29/MicrosoftTeams.schema.json", + "manifestVersion": "1.29", + "version": "1.0.0", + "id": "${{TEAMS_APP_ID}}", + "developer": { + "name": "Contoso", + "websiteUrl": "https://www.example.com", + "privacyUrl": "https://www.example.com/privacy", + "termsOfUseUrl": "https://www.example.com/termsofuse" + }, + "icons": { + "color": "color.png", + "outline": "outline.png" + }, + "name": { + "short": "ADO Wiki Assistant${{APP_NAME_SUFFIX}}", + "full": "Azure DevOps Wiki Assistant" + }, + "description": { + "short": "Answers questions from your Azure DevOps Wiki with citations.", + "full": "A read-only Microsoft 365 Copilot assistant that searches your organization's Azure DevOps Wiki, summarizes the relevant pages, cites its sources, and clearly states when an answer is not found in the wiki." + }, + "accentColor": "#FFFFFF", + "supportsChannelFeatures": "tier1", + "composeExtensions": [], + "permissions": [ + "identity", + "messageTeamMembers" + ], + "validDomains": [] +} diff --git a/samples/da-azure-devops-wiki/appPackage/outline.png b/samples/da-azure-devops-wiki/appPackage/outline.png new file mode 100644 index 0000000000000000000000000000000000000000..f7a4c864475f219c8ff252e15ee250cd2308c9f5 GIT binary patch literal 492 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�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 H@C6`_Yf*$GE5^cYH~7em{|P>AB& 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 literal 0 HcmV?d00001 diff --git a/samples/da-azure-devops-wiki/assets/sample.json b/samples/da-azure-devops-wiki/assets/sample.json new file mode 100644 index 000000000..48db42626 --- /dev/null +++ b/samples/da-azure-devops-wiki/assets/sample.json @@ -0,0 +1,55 @@ +[ + { + "name": "pnp-copilot-pro-dev-da-azure-devops-wiki", + "source": "pnp", + "title": "Azure DevOps Wiki Assistant", + "shortDescription": "A read-only declarative agent that answers questions from your Azure DevOps Wiki with citations, and says when an answer isn't in the wiki.", + "url": "https://github.com/pnp/copilot-pro-dev-samples/tree/main/samples/da-azure-devops-wiki", + "downloadUrl": "https://pnp.github.io/download-partial/?url=https://github.com/pnp/copilot-pro-dev-samples/tree/main/samples/da-azure-devops-wiki", + "longDescription": [ + "A read-only Microsoft 365 Copilot declarative agent grounded strictly on the Azure DevOps Wiki Copilot connector. It searches indexed project and code wikis, preserves the guide's numbered steps and reference tables, cites the source page, and clearly states when an answer is not found in the wiki instead of answering from general knowledge. Built with TypeSpec and the Microsoft 365 Agents Toolkit, it binds to the connector as its only knowledge source and retargets tenants through a single environment variable." + ], + "creationDateTime": "2026-08-22", + "updateDateTime": "2026-08-22", + "products": [ + "Microsoft 365 Copilot" + ], + "metadata": [ + { + "key": "PLATFORM", + "value": "TypeSpec" + }, + { + "key": "LANGUAGE", + "value": "TypeSpec" + } + ], + "thumbnails": [ + { + "type": "image", + "order": 100, + "url": "https://github.com/pnp/copilot-pro-dev-samples/raw/main/samples/da-azure-devops-wiki/assets/demo.png", + "alt": "Azure DevOps Wiki Assistant answering a how-to question in Microsoft 365 Copilot with step-by-step guidance and citations to the source wiki page" + } + ], + "authors": [ + { + "gitHubAccount": "ejazhussain", + "pictureUrl": "https://github.com/ejazhussain.png", + "name": "Ejaz Hussain" + } + ], + "references": [ + { + "name": "Microsoft 365 Copilot extensibility", + "description": "Learn more about what Microsoft 365 Copilot and how you can extend it.", + "url": "https://learn.microsoft.com/microsoft-365-copilot/extensibility/" + }, + { + "name": "Deploy the Azure DevOps Wiki connector", + "description": "Deploy and configure the Azure DevOps Wiki Copilot connector that this agent is grounded on.", + "url": "https://learn.microsoft.com/microsoft-365/copilot/connectors/azure-devops-wiki-deployment" + } + ] + } +] diff --git a/samples/da-azure-devops-wiki/env/.env.dev b/samples/da-azure-devops-wiki/env/.env.dev new file mode 100644 index 000000000..d2b678e1a --- /dev/null +++ b/samples/da-azure-devops-wiki/env/.env.dev @@ -0,0 +1,28 @@ +# This file includes environment variables that will be committed to git by default. +# It intentionally contains NO tenant-specific values or secrets. Fill in the values +# below for your own tenant before you provision. + +# Built-in environment variables +TEAMSFX_ENV=dev +# Empty suffix so the agent is named "Azure DevOps Wiki Assistant" (no "dev" appended). +APP_NAME_SUFFIX= + +# Publish scope for the copilotAgent/publish provision step (personal for dev/pilot). +AGENT_SCOPE=personal + +# Azure DevOps Wiki Copilot connector connection id. +# IMPORTANT: this must be the connection's Graph `id`, NOT its display name. +# Verify with: GET https://graph.microsoft.com/v1.0/external/connections?$select=id,name +# (In the admin center this is the smaller string under the connection title.) +ADO_WIKI_CONNECTION_ID= + +# Generated during provision by Microsoft 365 Agents Toolkit. Leave blank. +TEAMS_APP_ID= +M365_TITLE_ID= +M365_APP_ID= + +# Environment variables for Agent Evaluations (optional; fill in to run npm-based evals) +AZURE_AI_OPENAI_ENDPOINT= +AZURE_AI_API_KEY= +AZURE_AI_API_VERSION= +AZURE_AI_MODEL_NAME= diff --git a/samples/da-azure-devops-wiki/evals/prompts.json b/samples/da-azure-devops-wiki/evals/prompts.json new file mode 100644 index 000000000..3fedad688 --- /dev/null +++ b/samples/da-azure-devops-wiki/evals/prompts.json @@ -0,0 +1,31 @@ +{ + "schemaVersion": "1.2.0", + "default_evaluators": { + "Relevance": {}, + "Coherence": {} + }, + "items": [ + { + "prompt": "How do I request SharePoint access?", + "evaluators": { + "Relevance": {}, + "Coherence": {} + } + }, + { + "prompt": "What is the process for booking a meeting room?", + "evaluators": { + "Relevance": {}, + "Coherence": {} + } + }, + { + "prompt": "What is the airspeed velocity of an unladen swallow?", + "expected_response": "This checks strict grounding: the answer should state the information was not found in the Azure DevOps Wiki, rather than answering from general knowledge.", + "evaluators": { + "PartialMatch": { "case_sensitive": false } + }, + "evaluators_mode": "extend" + } + ] +} diff --git a/samples/da-azure-devops-wiki/m365agents.local.yml b/samples/da-azure-devops-wiki/m365agents.local.yml new file mode 100644 index 000000000..e7cb84608 --- /dev/null +++ b/samples/da-azure-devops-wiki/m365agents.local.yml @@ -0,0 +1,65 @@ +# yaml-language-server: $schema=https://aka.ms/m365-agents-toolkits/v1.12/yaml.schema.json +# Visit https://aka.ms/teamsfx-v5.0-guide for details on this file +# Visit https://aka.ms/teamsfx-actions for details on actions +version: v1.12 + +provision: + # Creates an app + - uses: teamsApp/create + with: + # app name + name: Azure DevOps Wiki Assistant${{APP_NAME_SUFFIX}} + # Write the information of created resources into environment file for + # the specified environment variable(s). + writeToEnvironmentFile: + teamsAppId: TEAMS_APP_ID + + - uses: cli/runNpmCommand + name: install dependencies + with: + args: install --progress=false + + - uses: cli/runNpmCommand + name: Generate TypeSpec environment variables + with: + args: run generate:env -- ${{TEAMSFX_ENV}} + + # Compile typespec files and generate necessary files for agent. + - uses: typeSpec/compile + with: + path: ./src/agent/main.tsp + manifestPath: ./appPackage/manifest.json + outputDir: ./appPackage/.generated + typeSpecConfigPath: ./tspconfig.yaml + + # Build app package with latest env value + - uses: teamsApp/zipAppPackage + with: + # Path to manifest template + manifestPath: ./appPackage/manifest.json + outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + outputFolder: ./appPackage/build + + # Validate app package using validation rules + - uses: teamsApp/validateAppPackage + with: + # Relative path to this file. This is the path for built zip file. + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + + # Apply the app manifest to an existing app in + # Developer Portal. + - uses: teamsApp/update + with: + # Relative path to this file. This is the path for built zip file. + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + + # Sideload the agent to your personal scope for local preview. + - uses: copilotAgent/publish + with: + # Relative path to the build app package. + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + # Write the information of created resources into environment file for + # the specified environment variable(s). + writeToEnvironmentFile: + titleId: M365_TITLE_ID + appId: M365_APP_ID diff --git a/samples/da-azure-devops-wiki/m365agents.yml b/samples/da-azure-devops-wiki/m365agents.yml new file mode 100644 index 000000000..06d0c505b --- /dev/null +++ b/samples/da-azure-devops-wiki/m365agents.yml @@ -0,0 +1,118 @@ +# yaml-language-server: $schema=https://aka.ms/m365-agents-toolkits/v1.12/yaml.schema.json +# Visit https://aka.ms/teamsfx-v5.0-guide for details on this file +# Visit https://aka.ms/teamsfx-actions for details on actions +version: v1.12 + +environmentFolderPath: ./env + +# Triggered when 'teamsapp provision' is executed +provision: + # Creates an app + - uses: teamsApp/create + with: + # app name + name: Azure DevOps Wiki Assistant${{APP_NAME_SUFFIX}} + # Write the information of created resources into environment file for + # the specified environment variable(s). + writeToEnvironmentFile: + teamsAppId: TEAMS_APP_ID + + # Install all dependencies (including TypeSpec for Microsoft 365 Copilot) + - uses: cli/runNpmCommand + name: install dependencies + with: + args: install --progress=false + + # Generates a TypeSpec version of the environment variables + - uses: cli/runNpmCommand + name: Generate TypeSpec environment variables + with: + args: run generate:env -- ${{TEAMSFX_ENV}} + + # Compile typespec files and generate necessary files for agent. + # If you want to update the outputDir, please make sure the following paths are also updated. + # 1. File paths in tspconfig.yaml. + # 2. manifestPath in this action. Please make sure there is manifest.json under root folder of your outputDir and set the value to the path of this manifest.json. + # 3. manifestPath in teamsApp/zipAppPackage action. Please set the value to the same as manifestPath in this action. + - uses: typeSpec/compile + with: + path: ./src/agent/main.tsp + manifestPath: ./appPackage/manifest.json + outputDir: ./appPackage/.generated + typeSpecConfigPath: ./tspconfig.yaml + + # Build app package with latest env value + - uses: teamsApp/zipAppPackage + with: + # Path to manifest template + manifestPath: ./appPackage/manifest.json + outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + outputFolder: ./appPackage/build + # Validate app package using validation rules + - uses: teamsApp/validateAppPackage + with: + # Relative path to this file. This is the path for built zip file. + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + # Apply the app manifest to an existing app in + # Developer Portal. + # Will use the app id in manifest file to determine which app to update. + - uses: teamsApp/update + with: + # Relative path to this file. This is the path for built zip file. + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + # Publish the agent to the scope defined by AGENT_SCOPE (personal for dev/pilot). + - uses: copilotAgent/publish + with: + # Relative path to the build app package. + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + scope: ${{AGENT_SCOPE}} + # Write the information of created resources into environment file for + # the specified environment variable(s). + writeToEnvironmentFile: + titleId: M365_TITLE_ID + appId: M365_APP_ID + shareLink: SHARE_LINK + +# Triggered when 'teamsapp publish' is executed +publish: + - uses: cli/runNpmCommand + name: install dependencies + with: + args: install --progress=false + + # Compile typespec files and generate necessary files for agent. + - uses: typeSpec/compile + with: + path: ./src/agent/main.tsp + manifestPath: ./appPackage/manifest.json + outputDir: ./appPackage/.generated + typeSpecConfigPath: ./tspconfig.yaml + + # Build app package with latest env value + - uses: teamsApp/zipAppPackage + with: + # Path to manifest template + manifestPath: ./appPackage/manifest.json + outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + outputFolder: ./appPackage/build + # Validate app package using validation rules + - uses: teamsApp/validateAppPackage + with: + # Relative path to this file. This is the path for built zip file. + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + # Apply the app manifest to an existing app in + # Developer Portal. + - uses: teamsApp/update + with: + # Relative path to this file. This is the path for built zip file. + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + # Publish the agent to the tenant app catalog (enters admin "Pending approval"). + - uses: copilotAgent/publish + with: + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + scope: tenant + # Write the information of created resources into environment file for + # the specified environment variable(s). + writeToEnvironmentFile: + titleId: M365_PUBLISHED_TITLE_ID + appId: M365_PUBLISHED_APP_ID diff --git a/samples/da-azure-devops-wiki/package-lock.json b/samples/da-azure-devops-wiki/package-lock.json new file mode 100644 index 000000000..c45d62d68 --- /dev/null +++ b/samples/da-azure-devops-wiki/package-lock.json @@ -0,0 +1,2315 @@ +{ + "name": "da-azure-devops-wiki", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "da-azure-devops-wiki", + "version": "1.0.0", + "devDependencies": { + "@microsoft/typespec-m365-copilot": "^1.0.0", + "@typespec/compiler": "1.12.0", + "@typespec/http": "1.5.0", + "@typespec/openapi": "1.5.0", + "@typespec/openapi3": "1.5.0" + } + }, + "node_modules/@alloy-js/core": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@alloy-js/core/-/core-0.20.0.tgz", + "integrity": "sha512-ylPf+ayI9MsqUPrNVzND3Oh9rVrfOOcMkyVwtXXaxaobWPkcRq2I4rX09FkG0i/9DoaLE6ZCvUfdgJsM29MYBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/reactivity": "^3.5.13", + "cli-table3": "^0.6.5", + "pathe": "^2.0.3", + "picocolors": "^1.1.1", + "prettier": "^3.6.2" + } + }, + "node_modules/@alloy-js/csharp": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@alloy-js/csharp/-/csharp-0.20.0.tgz", + "integrity": "sha512-Yn8oua43tVWYGN9Gt5DDtGUdLIB9io6/nL8dK4qDvL019w9uK7f3wosr+/JtSm14PuToN4jM1s7HNVzqh41KUA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@alloy-js/core": "~0.20.0", + "change-case": "^5.4.4", + "marked": "^16.1.1", + "pathe": "^2.0.3" + } + }, + "node_modules/@alloy-js/json": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@alloy-js/json/-/json-0.20.0.tgz", + "integrity": "sha512-cj7t/buV+IdcxV1WqXQ9oyIBm/Xp1ln08fsMxBpC8ZsG8+mijHo2GCZdH0sblNbvriS7yG+71SjqDgnXdMsR5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloy-js/core": "~0.20.0", + "pathe": "^2.0.3" + } + }, + "node_modules/@alloy-js/typescript": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@alloy-js/typescript/-/typescript-0.20.0.tgz", + "integrity": "sha512-F1y5QjneE8GVxIq6oYsebu+Fccrn72qFHelNX5GSLfs4Ps2fxpk2+70rsGznZyHe9LIt70StaAciTjH6cxH4bQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloy-js/core": "~0.20.0", + "change-case": "^5.4.4", + "pathe": "^2.0.3" + } + }, + "node_modules/@apidevtools/json-schema-ref-parser": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-14.0.1.tgz", + "integrity": "sha512-Oc96zvmxx1fqoSEdUmfmvvb59/KDOnUoJ7s2t7bISyAn0XEz57LCCw8k2Y4Pf3mwKaZLMciESALORLgfe2frCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.15", + "js-yaml": "^4.1.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/philsturgeon" + } + }, + "node_modules/@apidevtools/openapi-schemas": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", + "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/@apidevtools/swagger-methods": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", + "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@apidevtools/swagger-parser": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-12.0.0.tgz", + "integrity": "sha512-WLJIWcfOXrSKlZEM+yhA2Xzatgl488qr1FoOxixYmtWapBzwSC0gVGq4WObr4hHClMIiFFdOBdixNkvWqkWIWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@apidevtools/json-schema-ref-parser": "14.0.1", + "@apidevtools/openapi-schemas": "^2.1.0", + "@apidevtools/swagger-methods": "^3.0.2", + "ajv": "^8.17.1", + "ajv-draft-04": "^1.0.0", + "call-me-maybe": "^1.0.2" + }, + "peerDependencies": { + "openapi-types": ">=7" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", + "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/traverse": "^7.29.7", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", + "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", + "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", + "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", + "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", + "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", + "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", + "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz", + "integrity": "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-syntax-typescript": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.29.7.tgz", + "integrity": "sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "@babel/plugin-syntax-jsx": "^7.29.7", + "@babel/plugin-transform-modules-commonjs": "^7.29.7", + "@babel/plugin-transform-typescript": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@inquirer/ansi": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.7.tgz", + "integrity": "sha512-3eTuUO1vH2cZm2ZKHeQxnOqlTi9EfZDGgIe3BL3I4u+rJHocr9Fz86M4fjYABPvFnQG/gGK551HqDiIcETwU6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + } + }, + "node_modules/@inquirer/checkbox": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.2.2.tgz", + "integrity": "sha512-Y5/bAScMy5Y+9isCx0SKbyJebMCaXXX5em0kxkj115eZNscgV9srOHrgyfS0e5xAVymIfOh9piYBKDILktsMMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.7", + "@inquirer/core": "^12.0.0", + "@inquirer/figures": "^2.0.8", + "@inquirer/type": "^4.0.7" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/confirm": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.2.0.tgz", + "integrity": "sha512-SKXarWrYhtpqOEctf9XGCGy29QjsvJAM0Aq9ZR9z4Ns94OmpqudOly+aSEfNqUf9SwsQaUgY9+Z8hyzG0xX8fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^12.0.0", + "@inquirer/type": "^4.0.7" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.0.tgz", + "integrity": "sha512-+nnvFEXIB08CZNVXpvW3B+zHW96QXvGUjNKJ8NJIPqAZi5Kd4WhYt2S3C234ReepG1qw2HOlEUbjYVHBowXObA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.7", + "@inquirer/figures": "^2.0.8", + "@inquirer/type": "^4.0.7", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/editor": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.3.0.tgz", + "integrity": "sha512-nnsP/IdJ8s83q7ZuObmgn12QM+uLCkab9E0Oordojbn62WUg1c+v9Ou/F/057pgh0ppX0W+Hj5bO/Dp5hsxQtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^12.0.0", + "@inquirer/external-editor": "^3.0.4", + "@inquirer/type": "^4.0.7" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/expand": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.1.2.tgz", + "integrity": "sha512-OWIH1IyyWqEKIyqC9Xy+Bnga7NkGMovFdo4atYZMUOTRqf6rO2WCv9E/1MyzvOErDBCxs+9UFliRUDc50xs/jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^12.0.0", + "@inquirer/type": "^4.0.7" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-3.0.4.tgz", + "integrity": "sha512-tZbbaK2ovq6vlrRBNQvjrypmrED/p5x2ncIHQ79cD55tei3dD96v5glMMA+6tiq7K104i/25DVYKWVPJuV6ptA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.2" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/figures": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.8.tgz", + "integrity": "sha512-tApbon79GM9ry56ja/Ud3SY2CL4TQsao9fIwDQbgTeNY55025GdMzQ2+UdegV/lx51VNGUB59M0v0nMpybYY4Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + } + }, + "node_modules/@inquirer/input": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.1.3.tgz", + "integrity": "sha512-F/BZHtyEzP+HO+IGVd4AjBRgvX/ywm42bx8S0+dENk2YclzE9tJ3X/15THwtT6ehApmKvdYDMsVTuyyDod0gOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^12.0.0", + "@inquirer/type": "^4.0.7" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/number": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.2.0.tgz", + "integrity": "sha512-ew+fSDijsQ/WhD4TV3XLb+if400cDuzTzHfGR8sTNBXkK9CYDWoGE8fhaO8GbT312pNv1AJEOsDxy/z/HVettA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^12.0.0", + "@inquirer/type": "^4.0.7" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/password": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.1.2.tgz", + "integrity": "sha512-nSdufycW8xynEVssFkNQEYIzTySilog0UlfOVRwh3pXzPSk4frXUT2jZWjHnKae6RU9PaoF9wfy1pGwewQuqGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.7", + "@inquirer/core": "^12.0.0", + "@inquirer/type": "^4.0.7" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/prompts": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.6.0.tgz", + "integrity": "sha512-WgBVDRy3IQ4v9XMCpQ1YDGpso2PcMUxYJzZdH4Nt4t0eoXhEPmOCh5iZbXbR4GTbdUB9VPWBbJB12rkjbaGDCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^5.2.2", + "@inquirer/confirm": "^6.2.0", + "@inquirer/editor": "^5.3.0", + "@inquirer/expand": "^5.1.2", + "@inquirer/input": "^5.1.3", + "@inquirer/number": "^4.2.0", + "@inquirer/password": "^5.1.2", + "@inquirer/rawlist": "^5.3.2", + "@inquirer/search": "^4.3.0", + "@inquirer/select": "^5.2.2" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/rawlist": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.3.2.tgz", + "integrity": "sha512-oPSKrYK1X1bMkjXDzIKHUkJp195LFSfgbnVtXnjSKGFjrCbS6I+wyvfAZTwKE9BSt3HwWgfD7JfsXALBgCogzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^12.0.0", + "@inquirer/type": "^4.0.7" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.3.0.tgz", + "integrity": "sha512-HFxXE5w727ctSUcAwrDquftJGjMgu36OeV5SHEXMlr2j/ahzmRX9xSEeVolV8tzYnTf45cg6vGkdMMRdm3RPhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^12.0.0", + "@inquirer/figures": "^2.0.8", + "@inquirer/type": "^4.0.7" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.2.2.tgz", + "integrity": "sha512-RkI8dRHWt+bh04oLixvF1kFzKC7e5rqJoHKkzcqSHATebBXFC6GmrT8ddbVkgSzLV0HnHs2cPFuBINr8otij8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.7", + "@inquirer/core": "^12.0.0", + "@inquirer/figures": "^2.0.8", + "@inquirer/type": "^4.0.7" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/type": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.0.7.tgz", + "integrity": "sha512-t28inv14nMQ1PhKpsJPY+kEs/c00qzeCOS2gTNRyTjG5d6qsVA2fItxW4hkvGZ5lvanGLdtCzVIx5dwdRpN1+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@microsoft/typespec-m365-copilot": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@microsoft/typespec-m365-copilot/-/typespec-m365-copilot-1.0.0.tgz", + "integrity": "sha512-tG4s74shvNnrI3JVKR5yvnZMovHvfb0rYbrxM8mcH2XyYP90/N0r8Nb7sDqTlsGfEwXnpBNo3piu/nDlZqM6Bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloy-js/core": "0.20.0", + "@alloy-js/json": "0.20.0", + "@alloy-js/typescript": "^0.20.0", + "@babel/preset-typescript": "^7.27.1", + "@typespec/compiler": "^1.0.0", + "@typespec/emitter-framework": "^0.11.0", + "@typespec/http": "^1.0.1", + "@typespec/openapi": "^1.0.0", + "@typespec/openapi3": "^1.0.0", + "@typespec/versioning": "^0.74.0", + "handlebars": "~4.7.8", + "uuid": "^13.0.0" + } + }, + "node_modules/@microsoft/typespec-m365-copilot/node_modules/@typespec/versioning": { + "version": "0.74.0", + "resolved": "https://registry.npmjs.org/@typespec/versioning/-/versioning-0.74.0.tgz", + "integrity": "sha512-eFIa23tycWJgv3Lxyu6jUlRi02dhtQE4Jjx3Ui5vEbwHW8pMEzuyF7ALt1c+V9HOLkfDkS4dJkiOVIoikZHPvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "^1.4.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typespec/asset-emitter": { + "version": "0.75.0", + "resolved": "https://registry.npmjs.org/@typespec/asset-emitter/-/asset-emitter-0.75.0.tgz", + "integrity": "sha512-Kh5FmTPPU2Vc7nNI3iijsyfybhCZhOvkPpDuGYLYT4nxKXQeTY6h1RNZDR/y4DDRhT7oioEvlPaN2JR2C6HaYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "^1.5.0" + } + }, + "node_modules/@typespec/compiler": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-1.12.0.tgz", + "integrity": "sha512-hKCkHEEDdCpXFyOU8ln+TzBBwonFMbkeUV0zIc+vBETyO8p/Upui3XvEyLOyB4CpKUReHzGeGm3gcFjNc73ygg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@inquirer/prompts": "^8.4.1", + "ajv": "^8.18.0", + "change-case": "^5.4.4", + "env-paths": "^4.0.0", + "is-unicode-supported": "^2.1.0", + "mustache": "^4.2.0", + "picocolors": "^1.1.1", + "prettier": "^3.8.1", + "semver": "^7.7.4", + "tar": "^7.5.13", + "temporal-polyfill": "^0.3.2", + "vscode-languageserver": "^9.0.1", + "vscode-languageserver-textdocument": "^1.0.12", + "yaml": "^2.8.3", + "yargs": "^18.0.0" + }, + "bin": { + "tsp": "cmd/tsp.js", + "tsp-server": "cmd/tsp-server.js" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@typespec/compiler/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typespec/emitter-framework": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@typespec/emitter-framework/-/emitter-framework-0.11.0.tgz", + "integrity": "sha512-mX2T3e6E+9YGbDQ/8bjnvNR9aZAHFjYO09UosMKvqAxMO8gxhFsmWC28W2XcI8j2c2QqKWXWPS1pJbTE18WVZw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@alloy-js/core": "^0.20.0", + "@alloy-js/csharp": "^0.20.0", + "@alloy-js/typescript": "^0.20.0", + "@typespec/compiler": "^1.4.0" + } + }, + "node_modules/@typespec/http": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@typespec/http/-/http-1.5.0.tgz", + "integrity": "sha512-52XLXwqSY2SY6nSvfkiTsNiJzlMeIAZ6MFIVJ5YkoibA21TNAP4DtjTZgC2GieZLY2NNN/rqDCqBX+DyWqTrfQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "^1.5.0", + "@typespec/streams": "^0.75.0" + }, + "peerDependenciesMeta": { + "@typespec/streams": { + "optional": true + } + } + }, + "node_modules/@typespec/openapi": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@typespec/openapi/-/openapi-1.5.0.tgz", + "integrity": "sha512-27sXkSK2r1sAmVMLv+pwlN/Cm+yg9nEK8iuGyJRuEkBk7hcsJDbTnBlsEvlRTI8DqljtzA7YECDHBLK88zZHeg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "^1.5.0", + "@typespec/http": "^1.5.0" + } + }, + "node_modules/@typespec/openapi3": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@typespec/openapi3/-/openapi3-1.5.0.tgz", + "integrity": "sha512-Fu4RBk19a+Nma7N0LzP8DjwRcTc3zWCl/ne3R6m6l5Pc6jVN7EXGQNz68f3AOorWCuE+BxONViTN6og/pukXNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@apidevtools/swagger-parser": "~12.0.0", + "@typespec/asset-emitter": "^0.75.0", + "openapi-types": "~12.1.3", + "yaml": "~2.8.0" + }, + "bin": { + "tsp-openapi3": "cmd/tsp-openapi3.js" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "^1.5.0", + "@typespec/http": "^1.5.0", + "@typespec/json-schema": "^1.5.0", + "@typespec/openapi": "^1.5.0", + "@typespec/versioning": "^0.75.0" + }, + "peerDependenciesMeta": { + "@typespec/json-schema": { + "optional": true + }, + "@typespec/versioning": { + "optional": true + }, + "@typespec/xml": { + "optional": true + } + } + }, + "node_modules/@typespec/openapi3/node_modules/yaml": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.4.tgz", + "integrity": "sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/@typespec/versioning": { + "version": "0.75.0", + "resolved": "https://registry.npmjs.org/@typespec/versioning/-/versioning-0.75.0.tgz", + "integrity": "sha512-wdLcVx5UW4WRks/OXfqLiaDTtWfAWgv/nj69u99gRJU6iY9ExEvK5x9NQszZQKYnu6tM7nkoYMg4zu+7YBUBaw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "^1.5.0" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.41.tgz", + "integrity": "sha512-rznsqKM0np0x18EjzF8x88MpEhdNsffbvFbckLL5+oUKz1BxAImEmO7J1ArRYSyo6aQaVoBDp7jEkT91OOxydA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.41" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.41.tgz", + "integrity": "sha512-IOnwSCma8j+9xJT6b8H0dEYidC80NsYmNMlZxRsukYcSoGaDBohog5hDxzeUXdFeGWFA++vWvxqOmrr96VlqMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^8.5.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.18", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.18.tgz", + "integrity": "sha512-1iEmLEYSiE1SeBoAfPo/Mnx3PzfzHUkDK61ASkCpuk3YXugYLH5DYK1SzqV55F8FMI6s0F+/tCP7Polz1QRjxw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/browserslist": { + "version": "4.28.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.8.tgz", + "integrity": "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "baseline-browser-mapping": "^2.11.12", + "caniuse-lite": "^1.0.30001809", + "electron-to-chromium": "^1.5.402", + "node-releases": "^2.0.53", + "update-browserslist-db": "^1.3.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/call-me-maybe": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", + "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001809", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001809.tgz", + "integrity": "sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0", + "peer": true + }, + "node_modules/change-case": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz", + "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/chardet": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.2.0.tgz", + "integrity": "sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA==", + "dev": true, + "license": "MIT" + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, + "node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.412", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.412.tgz", + "integrity": "sha512-z4rMe3esBzlzovKHj4gxJnsCGZRK5l4baUvm+gCGJBPE+gsyUMKsuU9tnEUtI1dOebXz1ytAPGjvXhmQ7rIPwA==", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/env-paths": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-4.0.0.tgz", + "integrity": "sha512-pxP8eL2SwwaTRi/KHYwLYXinDs7gL3jxFcBYmEdYfZmZXbaVDvdppd0XBU8qVz03rDfKZMXg1omHCbsJjZrMsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-safe-filename": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-string-truncated-width": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", + "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-string-width": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", + "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-string-truncated-width": "^3.0.2" + } + }, + "node_modules/fast-uri": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", + "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fast-wrap-ansi": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", + "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-string-width": "^3.0.2" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/handlebars": { + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-safe-filename": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-safe-filename/-/is-safe-filename-0.1.1.tgz", + "integrity": "sha512-4SrR7AdnY11LHfDKTZY1u6Ga3RuxZdl3YKWWShO5iyuG5h8QS4GD2tOb04peBJ5I7pXbR+CGBNEhTcwK+FzN3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/marked": { + "version": "16.4.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz", + "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "dev": true, + "license": "MIT", + "bin": { + "mustache": "bin/mustache" + } + }, + "node_modules/mute-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz", + "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.53", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.53.tgz", + "integrity": "sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/openapi-types": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", + "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/prettier": { + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.6.tgz", + "integrity": "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "7.5.22", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.22.tgz", + "integrity": "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/temporal-polyfill": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/temporal-polyfill/-/temporal-polyfill-0.3.2.tgz", + "integrity": "sha512-TzHthD/heRK947GNiSu3Y5gSPpeUDH34+LESnfsq8bqpFhsB79HFBX8+Z834IVX68P3EUyRPZK5bL/1fh437Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "temporal-spec": "0.3.1" + } + }, + "node_modules/temporal-spec": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/temporal-spec/-/temporal-spec-0.3.1.tgz", + "integrity": "sha512-B4TUhezh9knfSIMwt7RVggApDRJZo73uZdj8AacL2mZ8RP5KtLianh2MXxL06GN9ESYiIsiuoLQhgVfwe55Yhw==", + "dev": true, + "license": "ISC" + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.1.tgz", + "integrity": "sha512-ZZ61DsRsOnakl74HAmp3oSN4aXUmEWXf+i/yv0h7tIBfICc3VdrFErQKUUKPgu3AMsTUMbcongALEN4l6GSUrQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uuid": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.2.tgz", + "integrity": "sha512-vzi9uRZ926x4XV73S/4qQaTwPXM2JBj6/6lI/byHH1jOpCzb0zDbfytgA9LcN/hzb2l7WQSQnxITOVx5un/wGw==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", + "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "vscode-languageserver-protocol": "3.17.5" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "dev": true, + "license": "MIT", + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "dev": true, + "license": "MIT" + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.1.0.tgz", + "integrity": "sha512-2rAgRKu54VsHkqI0/tYkmluGXHD4KW7yZoycuqDQ15QOTnc2VVfy0nN/1eMhnQLO00A+dwtK20xuCnc1YGeUyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^8.2.1", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.2.tgz", + "integrity": "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + } + } +} diff --git a/samples/da-azure-devops-wiki/package.json b/samples/da-azure-devops-wiki/package.json new file mode 100644 index 000000000..8a8a3e07a --- /dev/null +++ b/samples/da-azure-devops-wiki/package.json @@ -0,0 +1,16 @@ +{ + "name": "da-azure-devops-wiki", + "version": "1.0.0", + "description": "Azure DevOps Wiki Assistant - a read-only declarative agent grounded on the Azure DevOps Wiki Copilot connector.", + "scripts": { + "compile": "tsp compile ./src/agent/main.tsp --config ./tspconfig.yaml", + "generate:env": "node scripts/generate-env.js" + }, + "devDependencies": { + "@microsoft/typespec-m365-copilot": "^1.0.0", + "@typespec/compiler": "1.12.0", + "@typespec/http": "1.5.0", + "@typespec/openapi": "1.5.0", + "@typespec/openapi3": "1.5.0" + } +} diff --git a/samples/da-azure-devops-wiki/scripts/generate-env.js b/samples/da-azure-devops-wiki/scripts/generate-env.js new file mode 100644 index 000000000..ac55cf4f6 --- /dev/null +++ b/samples/da-azure-devops-wiki/scripts/generate-env.js @@ -0,0 +1,86 @@ +#!/usr/bin/env node + +// Self-executing script to generate variables.json and variables.tsp from env/.env.{environment} +(async function main() { + const fs = require("fs"); + const path = require("path"); + + try { + const envArg = process.argv[2] || "dev"; + + // src/agent is the parent of this scripts directory + const repoAgentDir = path.resolve(__dirname, ".."); + const envFilePath = path.join(repoAgentDir, "env", `.env.${envArg}`); + const outTspPath = path.join(repoAgentDir, "src/agent/env.tsp"); + + if (!fs.existsSync(envFilePath)) { + console.error(`Environment file not found: ${envFilePath}`); + console.error(`Usage: node generate-env.js (e.g. dev, prod)`); + process.exitCode = 2; + return; + } + + const raw = fs.readFileSync(envFilePath, "utf8"); + + const vars = {}; + + for (const rawLine of raw.split(/\r?\n/)) { + const line = rawLine.trim(); + if (!line || line.startsWith("#")) continue; + + // support lines like KEY=value or export KEY=value + const cleaned = line.replace(/^export\s+/, ""); + const match = cleaned.match(/^([A-Za-z0-9_.-]+)\s*=\s*(.*)$/); + if (!match) continue; + + const key = match[1]; + let value = match[2] || ""; + + // strip surrounding single or double quotes + if ( + (value.startsWith('"') && value.endsWith('"')) || + (value.startsWith("'") && value.endsWith("'")) + ) { + value = value.slice(1, -1); + } + + // Unescape common sequences (keep as-is if not needed) + value = value.replace(/\\n/g, "\n").replace(/\\r/g, "\r"); + + vars[key] = value; + } + + const tspLines = []; + tspLines.push("// Auto-generated by scripts/generate-env.js - DO NOT EDIT"); + tspLines.push(`// Source: env/.env.${envArg}`); + tspLines.push(""); + tspLines.push("namespace Environment {"); + + const keys = Object.keys(vars).sort(); + for (const originalKey of keys) { + const value = vars[originalKey]; + + // Convert original env key to a safe TypeSpec identifier: replace invalid chars with _ and ensure it doesn't start with a digit + let ident = originalKey.replace(/[^A-Za-z0-9_]/g, "_"); + if (/^[0-9]/.test(ident)) ident = "_" + ident; + + // Add a comment with the original env key for traceability + tspLines.push(` // ${originalKey}`); + + // Escape backslashes and double quotes for safe TS string literal + const escaped = value.replace(/\\/g, "\\\\").replace(/\"/g, '\\"'); + + tspLines.push(` const ${ident} = "${escaped}";`); + tspLines.push(""); + } + + tspLines.push("}"); + + fs.writeFileSync(outTspPath, tspLines.join("\n") + "\n", "utf8"); + + console.log(`Generated: ${outTspPath}`); + } catch (err) { + console.error("Failed to generate environment variables:", err && err.stack ? err.stack : err); + process.exitCode = 1; + } +})(); diff --git a/samples/da-azure-devops-wiki/src/agent/main.tsp b/samples/da-azure-devops-wiki/src/agent/main.tsp new file mode 100644 index 000000000..fd3e3268c --- /dev/null +++ b/samples/da-azure-devops-wiki/src/agent/main.tsp @@ -0,0 +1,44 @@ +import "@typespec/http"; +import "@typespec/openapi3"; +import "@microsoft/typespec-m365-copilot"; +import "./prompts/instructions.tsp"; +import "./env.tsp"; + +using TypeSpec.M365.Copilot.Agents; + +@agent( + "Azure DevOps Wiki Assistant", + "Answers workplace and IT how-to questions from your organization's Azure DevOps Wiki (how-to guides, documentation, and knowledge-base pages). It searches the indexed wiki, preserves the guide's steps and tables, cites the source page, and clearly says when an answer isn't in the wiki." +) +@instructions(Prompts.INSTRUCTIONS) +@conversationStarter(#{ + title: "Request SharePoint access", + text: "How do I request access to a SharePoint site, and what access levels are there?", +}) +@conversationStarter(#{ + title: "Submit an IT ticket", + text: "How do I submit an IT support ticket, and which priority should I use?", +}) +@conversationStarter(#{ + title: "Onboard a new starter", + text: "What is the onboarding checklist for a new starter?", +}) +@conversationStarter(#{ + title: "Request time off", + text: "How do I request time off, and what leave types are available?", +}) +@conversationStarter(#{ + title: "Book a meeting room", + text: "How do I book a meeting room in Outlook?", +}) +namespace adowiki { + // The ONLY knowledge source: the Azure DevOps Wiki Copilot connector. + // connectionId is backslash-escaped because TypeSpec parses ${...} as interpolation; + // the emitter outputs the literal token ${{ADO_WIKI_CONNECTION_ID}}, which the Agents + // Toolkit substitutes from env/.env. when the app package is built. + op copilotConnectors is AgentCapabilities.CopilotConnectors; +} diff --git a/samples/da-azure-devops-wiki/src/agent/prompts/instructions.tsp b/samples/da-azure-devops-wiki/src/agent/prompts/instructions.tsp new file mode 100644 index 000000000..81f587ac0 --- /dev/null +++ b/samples/da-azure-devops-wiki/src/agent/prompts/instructions.tsp @@ -0,0 +1,30 @@ +namespace Prompts { + const INSTRUCTIONS = """ + 1. Role + You are the Azure DevOps Wiki Assistant. Your ONLY knowledge source is the Azure DevOps Wiki, indexed through a Microsoft 365 Copilot connector. You help employees find and understand internal how-to guides, documentation, and knowledge-base pages. + The wiki is a set of How-To Guides for common workplace and IT tasks (for example: requesting access to a SharePoint site, submitting an IT support ticket, onboarding a new starter, requesting time off, and booking a meeting room). New guides may be added over time, so do not assume this list is exhaustive. Each guide typically contains step-by-step instructions, reference tables (such as access levels, ticket priorities and SLAs, leave types, or room sizes), and a short FAQ. + + 2. Source rule (strict grounding) + - Answer ONLY using content retrieved from the Azure DevOps Wiki connector. + - Do NOT use general world knowledge, prior training, or web content to answer. This agent has no web access. + - Never invent, guess, or infer facts that are not present in the retrieved wiki content. + + 3. When you find relevant content + - Directly answer the user's question first, then give brief supporting detail. + - Preserve the guide's structure: keep numbered steps in their original order, and reproduce the relevant reference table (e.g. access levels, priorities/SLAs, leave types, room sizes) when it answers the question. + - Check the guide's FAQ — it often answers the exact question directly. + - Match the user's requested format (bullets, table, summary) and keep a concise, professional tone. + - Always cite the source wiki page(s) you used so the user can open and verify them. + + 4. When you do NOT find relevant content + - Say plainly that you could not find the answer in the Azure DevOps Wiki. + - Do NOT answer from general knowledge as a substitute. + - Suggest the user rephrase, add detail, or point to a related wiki topic that did appear in results. + + 5. Scope and safety + - This is a READ-ONLY assistant. If asked to create, edit, delete, or publish wiki content — or to act on any other system — explain that this is out of scope for the read-only Wiki Assistant. + - Do not request or expose personal or sensitive data beyond what is needed to answer, and only if it appears in the wiki content. + + Summary: Search the Azure DevOps Wiki for every question, answer only from what you retrieve, cite the pages, and clearly say when the wiki has no answer rather than guessing. + """; +} diff --git a/samples/da-azure-devops-wiki/tspconfig.yaml b/samples/da-azure-devops-wiki/tspconfig.yaml new file mode 100644 index 000000000..2b9e45055 --- /dev/null +++ b/samples/da-azure-devops-wiki/tspconfig.yaml @@ -0,0 +1,15 @@ +emit: + - "@typespec/openapi3" + - "@microsoft/typespec-m365-copilot" +options: + # If you want to change the default output directory for the OpenAPI emitter, please make sure to update the outputDir in the typeSpec/compile action in m365agents.yaml as well. + # You need to set the emitter-output-dir to ${outputDir}/specs. + "@typespec/openapi3": + emitter-output-dir: "{project-root}/appPackage/.generated/specs" + file-type: json + # You need to set the emitter-output-dir to the same as outputDir. + # You also need to set the output-file to declarativeAgent.json. + "@microsoft/typespec-m365-copilot": + emitter-output-dir: "{project-root}/appPackage/.generated" + output-file: declarativeAgent.json + file-type: json \ No newline at end of file