From 17636199d630f5fec95d288cb053f9a8d87911de Mon Sep 17 00:00:00 2001 From: ciscoRankush Date: Wed, 11 Mar 2026 14:12:18 +0530 Subject: [PATCH 1/6] chore: add spec-drift detection commands and pre-commit hook Add automated SDD documentation drift detection tooling: - /spec-drift: full scan command for validating all ai-docs against source code - /spec-drift-changed: incremental scan for changed files only - Pre-commit hook to block commits when ai-docs drift is unverified Co-Authored-By: Claude Opus 4.6 --- .claude/commands/spec-drift-changed.md | 161 ++++++++++++++++++++ .claude/commands/spec-drift.md | 199 +++++++++++++++++++++++++ .claude/hooks/check-ai-docs-drift.sh | 49 ++++++ 3 files changed, 409 insertions(+) create mode 100644 .claude/commands/spec-drift-changed.md create mode 100644 .claude/commands/spec-drift.md create mode 100755 .claude/hooks/check-ai-docs-drift.sh diff --git a/.claude/commands/spec-drift-changed.md b/.claude/commands/spec-drift-changed.md new file mode 100644 index 000000000..6455ebdeb --- /dev/null +++ b/.claude/commands/spec-drift-changed.md @@ -0,0 +1,161 @@ +# Spec Drift Detection — Changed Files Only + +Validate ai-docs affected by any staged/unstaged changes — whether the changes are to ai-docs themselves OR to source code that has corresponding ai-docs. Lightweight mode for pre-commit validation. + +## Step 1: Find All Changed Files + +Run these commands to find all changed files (staged and unstaged): + +```bash +# Get both staged and unstaged changed files +(git diff --name-only HEAD 2>/dev/null; git diff --name-only --cached 2>/dev/null) | sort -u +``` + +## Step 2: Identify ai-docs That Need Validation + +From the changed files, build TWO lists: + +### List A: Changed ai-docs files +Filter for files matching `ai-docs/*.md`. These docs changed directly and need validation. + +### List B: Source code files with corresponding ai-docs +For each changed source file under `packages/contact-center/` (excluding ai-docs files themselves): +1. Walk up the file's directory path +2. Check if any ancestor directory contains an `ai-docs/` folder +3. If yes, that `ai-docs/` folder needs validation against the updated source code + +Use this to discover ai-docs folders: +```bash +find packages/contact-center -type d -name "ai-docs" +``` + +Build a mapping like: +``` +Changed source file → ai-docs to validate +packages/contact-center/store/src/store.ts → packages/contact-center/store/ai-docs/ +packages/contact-center/task/src/widgets/CallControl/CallControl.tsx → packages/contact-center/task/ai-docs/widgets/CallControl/ +packages/contact-center/cc-components/src/SomeComponent.tsx → packages/contact-center/cc-components/ai-docs/ +``` + +For task widget source files, map to the widget-specific ai-docs: +- `packages/contact-center/task/src/widgets/CallControl/*` → `packages/contact-center/task/ai-docs/widgets/CallControl/` +- `packages/contact-center/task/src/widgets/IncomingTask/*` → `packages/contact-center/task/ai-docs/widgets/IncomingTask/` +- `packages/contact-center/task/src/widgets/OutdialCall/*` → `packages/contact-center/task/ai-docs/widgets/OutdialCall/` +- `packages/contact-center/task/src/widgets/TaskList/*` → `packages/contact-center/task/ai-docs/widgets/TaskList/` + +**Deduplicate**: If multiple source files map to the same ai-docs folder, validate that folder only once. + +### Combine Lists A and B +The final set of ai-docs folders to validate is the union of: +- Folders containing files from List A +- Folders identified from List B + +If NEITHER list has entries, report: **"No ai-docs affected by current changes — nothing to check."** and stop. + +## Step 3: Validate Affected ai-docs + +For each ai-docs folder that needs validation, spawn an Explore agent with this prompt: + +``` +You are validating SDD documentation accuracy against source code. + +SOURCE OF TRUTH (actual code): {source_code_directory} +DOCS TO VALIDATE: {ai_docs_folder} (all .md files in this folder) + +CHANGED SOURCE FILES (if any): {list of changed source files in this package} +CHANGED DOC FILES (if any): {list of changed ai-docs files} + +Read every markdown file in the ai-docs folder. For each document, check these 7 categories: + +1. FILE TREE: Read any documented file/directory trees. Glob the actual directory. Report missing/extra files. + +2. METHOD/API SIGNATURES: For every method documented, read the actual source and verify: name, params, param types, return type, modifiers. Flag any mismatch. Pay special attention to methods in changed source files — new methods may be missing from docs, or changed signatures may not be reflected. + +3. TYPE DEFINITIONS: For every type/enum/interface documented, find the actual definition in source. Compare name, fields, field types, enum values. Check if changed source files introduced new types not yet documented. + +4. EVENT NAMES: For every event constant or observable referenced, verify it exists in source with the exact name. For MobX: verify @observable/@computed/@action decorators. For React: verify prop callback names. Check if changed source files added new events not yet documented. + +5. ARCHITECTURE PATTERNS: Verify claims about MobX store patterns, React component patterns, singleton vs factory, component hierarchy, store injection. + +6. LINK VALIDATION: For every relative link [text](path), verify the target exists on disk. + +7. CODE EXAMPLES: For every code block, verify API names, method names, parameter names, import paths, MobX patterns are correct. + +For each finding, report: +- File: (path) +- Line/Section: (approximate line or section heading) +- Category: (1-7) +- Severity: Blocking / Important / Medium / Minor + - Blocking = wrong API that would cause runtime errors if an AI agent follows the docs + - Important = wrong params/types that would cause compilation errors + - Medium = incomplete or stale info (e.g., new methods/types/events missing from docs) + - Minor = broken links, cosmetic issues +- What doc says: (quoted) +- What code actually has: (evidence with file:line) +- Suggested fix: (exact replacement text) +``` + +Run all agents in parallel if multiple ai-docs folders are affected. + +## Step 4: Consolidate and Report + +Present findings in this format: + +```markdown +## Spec Drift Report — Changed Files +Generated: {date} +Trigger: {source code changes / ai-docs changes / both} +ai-docs folders checked: {list} + +### Changed Source Files +{list of changed source files and their mapped ai-docs folder} + +### Changed ai-docs Files +{list of changed ai-docs files, or "None"} + +### Summary + +| ai-docs Folder | Findings | Blocking | Important | Medium | Minor | +|----------------|----------|----------|-----------|--------|-------| +| ... | | | | | | + +### Blocking Findings +... + +### Important Findings +... + +### Medium Findings +... + +### Minor Findings +... + +### Actionable Fixes by File +(grouped by file path, each with exact old text -> new text) +``` + +## Step 5: Create Verification Marker + +After presenting the validation report (regardless of findings), create a verification marker so the pre-commit hook allows the commit: + +```bash +# Hash ALL staged contact-center files — must match the hook's hash logic exactly +STAGED_CC=$(git diff --cached --name-only 2>/dev/null | grep "^packages/contact-center/" | sort) +if [ -n "$STAGED_CC" ]; then + HASH=$(echo "$STAGED_CC" | shasum | cut -d' ' -f1) + touch "/tmp/.spec-drift-verified-${HASH}" + echo "Verification marker created: /tmp/.spec-drift-verified-${HASH}" +fi +``` + +Report to the user: "Verification marker created. The pre-commit hook will allow the next commit for these staged files." + +## Rules + +- Do NOT auto-fix anything — report findings only +- Always read actual source code to verify — never assume +- Use the Task tool with `subagent_type: "Explore"` for checker agents +- Run agents in parallel when multiple folders are affected +- Always create the verification marker at the end, even if there are findings (the developer decides whether to fix or commit as-is) +- The marker hash MUST match the hook's hash computation — both hash ALL staged `packages/contact-center/` files sorted alphabetically diff --git a/.claude/commands/spec-drift.md b/.claude/commands/spec-drift.md new file mode 100644 index 000000000..48a65f23a --- /dev/null +++ b/.claude/commands/spec-drift.md @@ -0,0 +1,199 @@ +# Spec Drift Detection — Full Scan + +Run a comprehensive validation of all SDD ai-docs against actual source code. Deploys a parallel agent team to catch documentation drift across 7 categories. + +## Step 1: Auto-Discovery + +Detect repo type and discover all ai-docs: + +1. **Repo detection**: This is ccWidgets — `packages/contact-center/` exists (no `@webex` scope) +2. **Root AGENTS.md**: `AGENTS.md` (repo root) +3. **Framework docs**: `ai-docs/` (README, RULES, patterns/*, templates/*) +4. **Package-level ai-docs**: Glob for `packages/contact-center/**/ai-docs/` to find all ai-docs folders +5. **Samples ai-docs**: Check `widgets-samples/**/ai-docs/` as well + +For each ai-docs folder found, identify its corresponding source code directory (the parent directory of `ai-docs/`). + +Build an inventory like: +``` +ai-docs folder → source directory +packages/contact-center/store/ai-docs/ → packages/contact-center/store/src/ +packages/contact-center/cc-components/ai-docs/ → packages/contact-center/cc-components/src/ +packages/contact-center/cc-widgets/ai-docs/ → packages/contact-center/cc-widgets/src/ +packages/contact-center/station-login/ai-docs/ → packages/contact-center/station-login/src/ +packages/contact-center/task/ai-docs/widgets/CallControl/ → packages/contact-center/task/src/widgets/CallControl/ +packages/contact-center/task/ai-docs/widgets/IncomingTask/ → packages/contact-center/task/src/widgets/IncomingTask/ +packages/contact-center/task/ai-docs/widgets/OutdialCall/ → packages/contact-center/task/src/widgets/OutdialCall/ +packages/contact-center/task/ai-docs/widgets/TaskList/ → packages/contact-center/task/src/widgets/TaskList/ +packages/contact-center/user-state/ai-docs/ → packages/contact-center/user-state/src/ +packages/contact-center/ui-logging/ai-docs/ → packages/contact-center/ui-logging/src/ +packages/contact-center/test-fixtures/ai-docs/ → packages/contact-center/test-fixtures/src/ +widgets-samples/cc/samples-cc-react-app/ai-docs/ → widgets-samples/cc/samples-cc-react-app/src/ +... (discover all that exist on the current branch) +``` + +## Step 2: Spawn Checker Agents in Parallel + +Use the Task tool to spawn agents. **All agents run in parallel.** + +### Per-Package Checker Agents (one per ai-docs folder) + +For EACH ai-docs folder discovered, spawn one Explore agent with this prompt: + +``` +You are validating SDD documentation accuracy. + +SOURCE OF TRUTH (actual code): {source_code_directory} +DOCS TO VALIDATE: {ai_docs_folder} + +Read every markdown file in the ai-docs folder. For each document, check these 7 categories: + +### Category 1: FILE TREE +Read any documented file/directory trees in the docs. Glob the actual directory. Report: +- Files listed in docs but missing on disk +- Files on disk but missing from docs +- Wrong nesting or directory structure + +### Category 2: METHOD/API SIGNATURES +For every method, function, or API endpoint documented: +- Read the actual source file +- Verify: method name, parameter names, parameter types, return type, access modifiers (public/private/static) +- Check if method actually exists in the documented file +- Flag any param that is documented but doesn't exist, or exists but isn't documented + +### Category 3: TYPE DEFINITIONS +For every type, enum, interface, or constant documented: +- Find the actual definition in source (check package-level types files and shared types) +- Compare: name, fields/members, field types, enum values +- Flag missing fields, wrong types, renamed types + +### Category 4: EVENT NAMES +For every event constant or observable referenced: +- Find the actual definition in source +- Verify the exact name matches +- For MobX observables: verify @observable, @computed, @action decorators match docs +- For React events: verify prop callback names match + +### Category 5: ARCHITECTURE PATTERNS +For claims about architectural patterns, verify: +- MobX store patterns: Are @observable, @action, @computed correctly documented? +- React component patterns: Are props, state, lifecycle methods correct? +- Singleton vs factory: Is the instantiation pattern correct? +- Component hierarchy: Are parent-child relationships correct? +- Store injection patterns: Are MobX store injections accurately described? + +### Category 6: LINK VALIDATION +For every relative markdown link [text](path): +- Resolve the path relative to the document's location +- Verify the target file exists on disk +- For anchor links (#section), verify the heading exists in the target + +### Category 7: CODE EXAMPLES +For every inline code block or code snippet: +- Verify API names, method names, parameter names are correct +- Verify import paths are valid +- Check that documented usage patterns match actual API signatures +- Verify MobX patterns use correct decorators and patterns + +## Output Format + +For each finding, report: +- **File**: (path to the ai-docs file with the issue) +- **Line/Section**: (approximate line number or section heading) +- **Category**: (1-7 from above) +- **Severity**: + - Blocking = wrong API that would cause runtime errors if AI agent follows the docs + - Important = wrong params/types that would cause compilation errors + - Medium = incomplete or stale info that would cause confusion + - Minor = broken links, cosmetic issues +- **What doc says**: (quoted text from the doc) +- **What code actually has**: (evidence from source, with file path and line) +- **Suggested fix**: (exact replacement text) + +If no issues found in a category, state "No issues found" for that category. +``` + +### Framework Agent + +Spawn one additional Explore agent for root-level framework validation: + +``` +Validate the root-level SDD framework documents for ccWidgets: + +1. **Root AGENTS.md** (repo root AGENTS.md): + - Package Routing Table: Every package listed must exist on disk at the documented path + - Every actual package directory under packages/contact-center/ should be listed + - Task classification types must be consistent with template directories that exist + - Quick Start Workflow steps must reference files that exist + +2. **ai-docs/RULES.md**: + - Test commands: Verify documented commands are correct + - Naming conventions: Verify claims against actual code + - Pattern references: All referenced patterns should exist + +3. **ai-docs/README.md**: + - File tree must match actual ai-docs directory structure + - All referenced documents must exist + +4. **ai-docs/patterns/*.md** (mobx-patterns, react-patterns, testing-patterns, typescript-patterns): + - Each pattern file's code examples must match actual source conventions + - MobX patterns must match actual decorator usage in stores + - React patterns must match actual component patterns + - Test patterns must reference correct commands and configs + +5. **ai-docs/templates/**: + - Cross-references to AGENTS.md sections must be valid + - Referenced file paths in templates must exist + - Workflow steps must be internally consistent + +For each finding, report: +- **File**: (path) +- **Line/Section**: (section heading or line) +- **Category**: (1-7: File Tree, Method/API, Type Definition, Event Name, Architecture Pattern, Link Validation, Code Example) +- **Severity**: Blocking / Important / Medium / Minor +- **What doc says**: (quoted) +- **What code actually has**: (evidence with file:line) +- **Suggested fix**: (replacement text) +``` + +## Step 3: Consolidate Results + +After ALL agents complete, consolidate into this report format: + +```markdown +## Spec Drift Report — ccWidgets +Generated: {date} +Scanned: {N} ai-docs folders, {M} documents + +### Summary + +| ai-docs Folder | Findings | Blocking | Important | Medium | Minor | +|----------------|----------|----------|-----------|--------|-------| +| (each folder) | | | | | | +| framework | | | | | | +| **Total** | **N** | | | | | + +### Blocking Findings +(must fix — wrong APIs that would cause runtime errors if AI agent follows the docs) + +### Important Findings +(wrong params, signatures, types — would cause compilation errors) + +### Medium Findings +(incomplete info, stale file trees — would cause confusion) + +### Minor Findings +(broken links, cosmetic issues) + +### Actionable Fixes by File +(grouped by file path, each with exact old text -> new text) +``` + +## Rules + +- Do NOT auto-fix anything — report findings only +- Always read actual source code to verify — never assume +- Use the Task tool with `subagent_type: "Explore"` for all checker agents +- Run all agents in parallel for speed +- If an ai-docs folder has no corresponding source directory, flag it as a Category 1 (File Tree) finding +- Count findings by severity in the summary table diff --git a/.claude/hooks/check-ai-docs-drift.sh b/.claude/hooks/check-ai-docs-drift.sh new file mode 100755 index 000000000..aaef3c881 --- /dev/null +++ b/.claude/hooks/check-ai-docs-drift.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# PreToolUse hook: Block git commit if contact-center code/docs changed without spec-drift verification +# +# Flow: +# 1. Read stdin to get the Bash command (JSON at tool_input.command) +# 2. If command is NOT git commit -> exit 0 (allow immediately) +# 3. Check if ANY staged files are under packages/contact-center/ +# 4. If none -> exit 0 (allow) +# 5. Check for verification marker (created by /spec-drift-changed) +# 6. If marker exists -> delete it, exit 0 (allow, one-time pass) +# 7. If no marker -> exit 2 (BLOCK, instruct to run /spec-drift-changed) + +CC_PKG="packages/contact-center" + +# Read tool input from stdin (JSON with tool_input.command) +INPUT=$(cat) +COMMAND=$(echo "$INPUT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('tool_input',{}).get('command',''))" 2>/dev/null) + +# Only gate git commit commands +case "$COMMAND" in + git\ commit*) ;; # Continue to check + *) exit 0 ;; # Not a commit, allow immediately +esac + +# Get staged files under the contact-center package +STAGED_CC=$(git diff --cached --name-only 2>/dev/null | grep "^${CC_PKG}/") + +if [ -z "$STAGED_CC" ]; then + exit 0 # No contact-center files staged, allow commit +fi + +# Compute hash of all staged contact-center files +HASH=$(echo "$STAGED_CC" | sort | shasum | cut -d' ' -f1) +MARKER="/tmp/.spec-drift-verified-${HASH}" + +if [ -f "$MARKER" ]; then + rm -f "$MARKER" # One-time use + exit 0 # Verified, allow commit +fi + +# Block the commit +echo "BLOCKED: contact-center files are staged but ai-docs have not been verified for spec drift." +echo "" +echo "Staged contact-center files:" +echo "$STAGED_CC" | sed 's/^/ - /' +echo "" +echo "Run /spec-drift-changed to validate ai-docs against source code before committing." +echo "The command will check documentation accuracy and create a verification marker." +exit 2 # Exit code 2 = blocking error in Claude Code hooks From 3cf0a3f6e5094239882d59ea802ebbc8dc4b600d Mon Sep 17 00:00:00 2001 From: Rankush Kumar Date: Mon, 23 Mar 2026 12:43:06 +0530 Subject: [PATCH 2/6] fix: address review comments on spec-drift tooling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Register hook in settings.json (was dead code without it) - Fail-closed when python3 unavailable or JSON parse fails - Use content-based hash (git diff --cached) instead of path-only hash - Don't consume marker in PreToolUse — invalidated naturally by content changes - Precise case pattern to avoid matching git commit-tree - Add shasum/sha256sum portability fallback - Fix "Task tool" → "Agent tool" references in command files - Add agent timeout handling rule - Add staged-only content note for verification marker - Make widget path mappings dynamic instead of hardcoded - Label inventory as example - Document advisory-only nature of verification Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/commands/spec-drift-changed.md | 25 +++++++++-------- .claude/commands/spec-drift.md | 7 +++-- .claude/hooks/check-ai-docs-drift.sh | 39 +++++++++++++++++--------- .claude/settings.json | 10 +++++++ 4 files changed, 54 insertions(+), 27 deletions(-) create mode 100644 .claude/settings.json diff --git a/.claude/commands/spec-drift-changed.md b/.claude/commands/spec-drift-changed.md index 6455ebdeb..be63b7b6c 100644 --- a/.claude/commands/spec-drift-changed.md +++ b/.claude/commands/spec-drift-changed.md @@ -37,11 +37,10 @@ packages/contact-center/task/src/widgets/CallControl/CallControl.tsx → package packages/contact-center/cc-components/src/SomeComponent.tsx → packages/contact-center/cc-components/ai-docs/ ``` -For task widget source files, map to the widget-specific ai-docs: -- `packages/contact-center/task/src/widgets/CallControl/*` → `packages/contact-center/task/ai-docs/widgets/CallControl/` -- `packages/contact-center/task/src/widgets/IncomingTask/*` → `packages/contact-center/task/ai-docs/widgets/IncomingTask/` -- `packages/contact-center/task/src/widgets/OutdialCall/*` → `packages/contact-center/task/ai-docs/widgets/OutdialCall/` -- `packages/contact-center/task/src/widgets/TaskList/*` → `packages/contact-center/task/ai-docs/widgets/TaskList/` +For task widget source files, map to the widget-specific ai-docs dynamically: +- `packages/contact-center/task/src/widgets/{WidgetName}/*` → `packages/contact-center/task/ai-docs/widgets/{WidgetName}/` (if the ai-docs folder exists) + +This covers all current and future widgets (e.g., CallControl, IncomingTask, OutdialCall, TaskList, and any new widgets added later). **Deduplicate**: If multiple source files map to the same ai-docs folder, validate that folder only once. @@ -140,22 +139,26 @@ ai-docs folders checked: {list} After presenting the validation report (regardless of findings), create a verification marker so the pre-commit hook allows the commit: ```bash -# Hash ALL staged contact-center files — must match the hook's hash logic exactly -STAGED_CC=$(git diff --cached --name-only 2>/dev/null | grep "^packages/contact-center/" | sort) +# Hash staged content (not just paths) — must match the hook's hash logic exactly +CC_PKG="packages/contact-center" +STAGED_CC=$(git diff --cached --name-only 2>/dev/null | grep "^${CC_PKG}/") if [ -n "$STAGED_CC" ]; then - HASH=$(echo "$STAGED_CC" | shasum | cut -d' ' -f1) + HASH=$(git diff --cached -- "$CC_PKG" | (shasum 2>/dev/null || sha256sum) | cut -d' ' -f1) touch "/tmp/.spec-drift-verified-${HASH}" echo "Verification marker created: /tmp/.spec-drift-verified-${HASH}" fi ``` +> **Note:** The verification marker covers only currently **staged** content. If you modify and re-stage files after verification, the content hash changes and you will need to re-run `/spec-drift-changed`. + Report to the user: "Verification marker created. The pre-commit hook will allow the next commit for these staged files." ## Rules - Do NOT auto-fix anything — report findings only - Always read actual source code to verify — never assume -- Use the Task tool with `subagent_type: "Explore"` for checker agents +- Use the Agent tool with `subagent_type: "Explore"` for checker agents - Run agents in parallel when multiple folders are affected -- Always create the verification marker at the end, even if there are findings (the developer decides whether to fix or commit as-is) -- The marker hash MUST match the hook's hash computation — both hash ALL staged `packages/contact-center/` files sorted alphabetically +- If an agent does not return within a reasonable time, note it as "Timed out — manual review needed" in the report and continue with available results +- Always create the verification marker at the end, even if there are findings — this tool is **advisory**: the developer decides whether to fix or commit as-is +- The marker hash MUST match the hook's hash computation — both use `git diff --cached` content (not just file paths) diff --git a/.claude/commands/spec-drift.md b/.claude/commands/spec-drift.md index 48a65f23a..1d5a834c1 100644 --- a/.claude/commands/spec-drift.md +++ b/.claude/commands/spec-drift.md @@ -14,7 +14,7 @@ Detect repo type and discover all ai-docs: For each ai-docs folder found, identify its corresponding source code directory (the parent directory of `ai-docs/`). -Build an inventory like: +Build an inventory (example — actual results will vary based on current branch): ``` ai-docs folder → source directory packages/contact-center/store/ai-docs/ → packages/contact-center/store/src/ @@ -34,7 +34,7 @@ widgets-samples/cc/samples-cc-react-app/ai-docs/ → widgets-sa ## Step 2: Spawn Checker Agents in Parallel -Use the Task tool to spawn agents. **All agents run in parallel.** +Use the Agent tool to spawn agents. **All agents run in parallel.** ### Per-Package Checker Agents (one per ai-docs folder) @@ -193,7 +193,8 @@ Scanned: {N} ai-docs folders, {M} documents - Do NOT auto-fix anything — report findings only - Always read actual source code to verify — never assume -- Use the Task tool with `subagent_type: "Explore"` for all checker agents +- Use the Agent tool with `subagent_type: "Explore"` for all checker agents - Run all agents in parallel for speed +- If an agent does not return within a reasonable time, note it as "Timed out — manual review needed" in the report and continue with available results - If an ai-docs folder has no corresponding source directory, flag it as a Category 1 (File Tree) finding - Count findings by severity in the summary table diff --git a/.claude/hooks/check-ai-docs-drift.sh b/.claude/hooks/check-ai-docs-drift.sh index aaef3c881..1c667d691 100755 --- a/.claude/hooks/check-ai-docs-drift.sh +++ b/.claude/hooks/check-ai-docs-drift.sh @@ -3,23 +3,37 @@ # # Flow: # 1. Read stdin to get the Bash command (JSON at tool_input.command) -# 2. If command is NOT git commit -> exit 0 (allow immediately) -# 3. Check if ANY staged files are under packages/contact-center/ -# 4. If none -> exit 0 (allow) -# 5. Check for verification marker (created by /spec-drift-changed) -# 6. If marker exists -> delete it, exit 0 (allow, one-time pass) -# 7. If no marker -> exit 2 (BLOCK, instruct to run /spec-drift-changed) +# 2. If python3 unavailable or JSON parse fails -> exit 2 (fail-closed) +# 3. If command is NOT git commit -> exit 0 (allow immediately) +# 4. Check if ANY staged files are under packages/contact-center/ +# 5. If none -> exit 0 (allow) +# 6. Check for verification marker (created by /spec-drift-changed) +# 7. If marker exists -> exit 0 (allow — marker stays until content changes) +# 8. If no marker -> exit 2 (BLOCK, instruct to run /spec-drift-changed) CC_PKG="packages/contact-center" +# Ensure python3 is available +if ! command -v python3 >/dev/null 2>&1; then + echo "ERROR: python3 is required for the spec-drift pre-commit hook but was not found." + echo "Install python3 or remove this hook from .claude/settings.json to proceed." + exit 2 +fi + # Read tool input from stdin (JSON with tool_input.command) INPUT=$(cat) COMMAND=$(echo "$INPUT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('tool_input',{}).get('command',''))" 2>/dev/null) -# Only gate git commit commands +# Fail-closed: if we couldn't parse the command, block rather than silently allow +if [ -z "$COMMAND" ]; then + echo "ERROR: Could not parse tool input. Blocking commit as a safety measure." + exit 2 +fi + +# Only gate git commit commands (precise match to avoid catching git commit-tree, etc.) case "$COMMAND" in - git\ commit*) ;; # Continue to check - *) exit 0 ;; # Not a commit, allow immediately + "git commit"|git\ commit\ *) ;; # Continue to check + *) exit 0 ;; # Not a commit, allow immediately esac # Get staged files under the contact-center package @@ -29,13 +43,12 @@ if [ -z "$STAGED_CC" ]; then exit 0 # No contact-center files staged, allow commit fi -# Compute hash of all staged contact-center files -HASH=$(echo "$STAGED_CC" | sort | shasum | cut -d' ' -f1) +# Compute hash from staged content (not just paths) to detect re-staged changes +HASH=$(git diff --cached -- "$CC_PKG" | (shasum 2>/dev/null || sha256sum) | cut -d' ' -f1) MARKER="/tmp/.spec-drift-verified-${HASH}" if [ -f "$MARKER" ]; then - rm -f "$MARKER" # One-time use - exit 0 # Verified, allow commit + exit 0 # Verified, allow commit (marker stays — invalidated naturally when content changes) fi # Block the commit diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 000000000..1a0518cfd --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,10 @@ +{ + "hooks": { + "PreToolUse": [ + { + "matcher": "Bash", + "hooks": [".claude/hooks/check-ai-docs-drift.sh"] + } + ] + } +} From dc755f4e1512b9ae31074c1c7c6eca6d30771312 Mon Sep 17 00:00:00 2001 From: Rankush Kumar Date: Tue, 24 Mar 2026 18:10:10 +0530 Subject: [PATCH 3/6] feat: add SDK dependency map generator and sync tooling Add cross-repo SDK synchronization tooling for detecting and tracking SDK API changes across the consumer codebase. - scripts/generate-sdk-deps.ts: scans all SDK imports, traces to file+line - sdk-dependencies.yaml: generated dependency map for @webex/contact-center - .claude/commands/sync-sdk.md: /sync-sdk skill for impact reports - .claude/hooks/check-sdk-version-change.sh: notifies on SDK version change - .sdk-cache/: cached manifest for version-to-version diffing Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/commands/sync-sdk.md | 52 + .claude/hooks/check-sdk-version-change.sh | 29 + .../@webex/contact-center.manifest.yaml | 1959 +++++++++++++++++ package.json | 8 +- scripts/generate-sdk-deps.ts | 419 ++++ scripts/tsconfig.json | 11 + sdk-dependencies.yaml | 168 ++ yarn.lock | 270 ++- 8 files changed, 2913 insertions(+), 3 deletions(-) create mode 100644 .claude/commands/sync-sdk.md create mode 100755 .claude/hooks/check-sdk-version-change.sh create mode 100644 .sdk-cache/@webex/contact-center.manifest.yaml create mode 100644 scripts/generate-sdk-deps.ts create mode 100644 scripts/tsconfig.json create mode 100644 sdk-dependencies.yaml diff --git a/.claude/commands/sync-sdk.md b/.claude/commands/sync-sdk.md new file mode 100644 index 000000000..573242fb0 --- /dev/null +++ b/.claude/commands/sync-sdk.md @@ -0,0 +1,52 @@ +Sync SDK dependencies and generate an impact report. + +## What this does + +1. Reads the SDK manifest from the local SDK checkout (via node_modules symlink or fallback local path) +2. Compares it against the cached previous manifest (if any) in `.sdk-cache/` +3. Regenerates `sdk-dependencies.yaml` by scanning all consumer source files +4. Cross-references manifest changes with the dependency map +5. Outputs a precise impact report showing which files need updating + +## Steps + +1. Run: `npx ts-node --project scripts/tsconfig.json scripts/generate-sdk-deps.ts` +2. Check if `.sdk-cache/@webex/contact-center.manifest.yaml` exists (previous cached manifest) +3. Read the current manifest from the SDK (via `node_modules/@webex/contact-center/sdk-manifest.yaml` or the local ccSDK path) +4. If a cached version exists, diff the two manifests: + - Find added/removed/changed methods + - Find added/removed/changed events + - Find added/removed/changed types +5. For each change, look up affected files in `sdk-dependencies.yaml` +6. Output the impact report in a structured format +7. Cache the current manifest to `.sdk-cache/@webex/contact-center.manifest.yaml` for future diffing + +## Impact Report Format + +``` +SDK Sync Report — @webex/contact-center +Previous: v -> Current: v + +=== BREAKING CHANGES === +1. Method: + Change: + Affected files: + -> : () + Action: + +=== ADDITIONS (non-breaking) === +2. Method: added + No current consumers. + +=== SUMMARY === +Breaking changes: N (affects M files) +Additions: N +Removals: N +``` + +## When to run + +- After bumping the SDK version in package.json +- After the SDK team notifies of API changes +- Before starting work that depends on SDK APIs +- Periodically to check for drift diff --git a/.claude/hooks/check-sdk-version-change.sh b/.claude/hooks/check-sdk-version-change.sh new file mode 100755 index 000000000..49185e45c --- /dev/null +++ b/.claude/hooks/check-sdk-version-change.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# PostToolUse hook: Detect SDK version changes in package.json files +# When a Write/Edit modifies a package.json that contains @webex/contact-center, +# remind the developer to run /sync-sdk. + +# Read tool input from stdin +INPUT=$(cat) + +# Extract the file path from the tool input +FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_response.filePath // empty' 2>/dev/null) + +# Only care about package.json files +if [[ "$FILE_PATH" != *"package.json" ]]; then + exit 0 +fi + +# Check if this package.json has an SDK dependency +if grep -q "@webex/contact-center" "$FILE_PATH" 2>/dev/null; then + # Check if the SDK version line was part of the change + # Use git diff to see if the version actually changed + SDK_CHANGED=$(git diff --no-index /dev/null "$FILE_PATH" 2>/dev/null | grep -c "@webex/contact-center" || true) + + if [ "$SDK_CHANGED" -gt 0 ]; then + echo '{"hookSpecificOutput":{"hookEventName":"PostToolUse","additionalContext":"SDK dependency @webex/contact-center detected in modified package.json. Remind the developer: Run /sync-sdk to check for breaking changes and regenerate the dependency map."}}' + exit 0 + fi +fi + +exit 0 diff --git a/.sdk-cache/@webex/contact-center.manifest.yaml b/.sdk-cache/@webex/contact-center.manifest.yaml new file mode 100644 index 000000000..ae9c9ccae --- /dev/null +++ b/.sdk-cache/@webex/contact-center.manifest.yaml @@ -0,0 +1,1959 @@ +name: "@webex/contact-center" +version: workspace +generated_at: "2026-03-24T11:15:48.070Z" +generator: generate-manifest.ts v1.0 +classes: + ContactCenter: + source: src/cc.ts + extends: WebexPlugin + methods: + register: + params: [] + returns: Promise + events_on_success: [] + events_on_failure: [] + deregister: + params: [] + returns: Promise + events_on_success: [] + events_on_failure: [] + getBuddyAgents: + params: + - name: data + type: BuddyAgents + required: true + returns: Promise + events_on_success: [] + events_on_failure: [] + stationLogin: + params: + - name: data + type: AgentLogin + required: true + returns: Promise + events_on_success: [] + events_on_failure: [] + stationLogout: + params: + - name: data + type: Logout + required: true + returns: Promise + events_on_success: [] + events_on_failure: [] + setAgentState: + params: + - name: data + type: StateChange + required: true + returns: Promise + events_on_success: [] + events_on_failure: [] + startOutdial: + params: + - name: destination + type: string + required: true + - name: origin + type: string + required: true + returns: Promise + events_on_success: [] + events_on_failure: [] + getOutdialAniEntries: + params: + - name: params + type: OutdialAniParams + required: true + returns: Promise + events_on_success: [] + events_on_failure: [] + uploadLogs: + params: [] + returns: Promise + events_on_success: [] + events_on_failure: [] + updateAgentProfile: + params: + - name: data + type: AgentProfileUpdate + required: true + returns: Promise + events_on_success: [] + events_on_failure: [] + getEntryPoints: + params: + - name: params + type: src/utils/PageCache:BaseSearchParams + required: false + returns: Promise + events_on_success: [] + events_on_failure: [] + getQueues: + params: + - name: params + type: ContactServiceQueueSearchParams + required: false + returns: Promise + events_on_success: [] + events_on_failure: [] + Task: + source: src/services/task/Task.ts + extends: EventEmitter + methods: + accept: + params: [] + returns: Promise + events_on_success: [] + events_on_failure: [] + decline: + params: [] + returns: Promise + events_on_success: [] + events_on_failure: [] + pauseRecording: + params: [] + returns: Promise + events_on_success: [] + events_on_failure: [] + resumeRecording: + params: + - name: resumeRecordingPayload + type: ResumeRecordingPayload + required: true + returns: Promise + events_on_success: [] + events_on_failure: [] + consult: + params: + - name: consultPayload + type: ConsultPayload + required: true + returns: Promise + events_on_success: [] + events_on_failure: [] + endConsult: + params: + - name: consultEndPayload + type: ConsultEndPayload + required: true + returns: Promise + events_on_success: [] + events_on_failure: [] + consultTransfer: + params: + - name: consultTransferPayload + type: ConsultTransferPayLoad + required: false + returns: Promise + events_on_success: [] + events_on_failure: [] + consultConference: + params: [] + returns: Promise + events_on_success: [] + events_on_failure: [] + exitConference: + params: [] + returns: Promise + events_on_success: [] + events_on_failure: [] + transferConference: + params: [] + returns: Promise + events_on_success: [] + events_on_failure: [] + switchCall: + params: [] + returns: Promise + events_on_success: [] + events_on_failure: [] + toggleMute: + params: [] + returns: Promise + events_on_success: [] + events_on_failure: [] + startTranscription: + params: [] + returns: Promise + events_on_success: + - task:transcriptionStarted + events_on_failure: + - task:transcriptionFailed + stopTranscription: + params: [] + returns: Promise + events_on_success: + - task:transcriptionStopped + events_on_failure: [] + unregisterWebCallListeners: + params: [] + returns: void + events_on_success: [] + events_on_failure: [] + cancelAutoWrapupTimer: + params: [] + returns: void + events_on_success: [] + events_on_failure: [] + hold: + params: [] + returns: Promise + events_on_success: [] + events_on_failure: [] + resume: + params: [] + returns: Promise + events_on_success: [] + events_on_failure: [] + holdResume: + params: [] + returns: Promise + events_on_success: [] + events_on_failure: [] + sendStateMachineEvent: + params: + - name: event + type: TaskEventPayload + required: true + returns: void + events_on_success: [] + events_on_failure: [] + updateTaskData: + params: + - name: updatedData + type: TaskData + required: true + - name: shouldOverwrite + type: boolean + required: false + returns: ITask + events_on_success: [] + events_on_failure: [] + transfer: + params: + - name: transferPayload + type: TransferPayLoad + required: true + returns: Promise + events_on_success: [] + events_on_failure: [] + end: + params: [] + returns: Promise + events_on_success: [] + events_on_failure: [] + wrapup: + params: + - name: wrapupPayload + type: WrapupPayLoad + required: true + returns: Promise + events_on_success: [] + events_on_failure: [] + AddressBook: + source: src/services/AddressBook.ts + extends: null + methods: + getEntries: + params: + - name: params + type: AddressBookEntrySearchParams + required: false + returns: Promise + events_on_success: [] + events_on_failure: [] +events: + TASK_EVENTS: + TASK_INCOMING: task:incoming + TASK_ASSIGNED: task:assigned + TASK_MEDIA: task:media + TASK_UNASSIGNED: task:unassigned + TASK_HOLD: task:hold + TASK_RESUME: task:resume + TASK_CONSULT_END: task:consultEnd + TASK_CONSULT_QUEUE_CANCELLED: task:consultQueueCancelled + TASK_CONSULT_QUEUE_FAILED: task:consultQueueFailed + TASK_UI_CONTROLS_UPDATED: task:ui-controls-updated + TASK_CONSULT_ACCEPTED: task:consultAccepted + TASK_CONSULTING: task:consulting + TASK_CONSULT_CREATED: task:consultCreated + TASK_OFFER_CONSULT: task:offerConsult + TASK_END: task:end + TASK_WRAPUP: task:wrapup + TASK_WRAPPEDUP: task:wrappedup + TASK_CLEANUP: task:cleanup + TASK_RECORDING_STARTED: task:recordingStarted + TASK_RECORDING_PAUSED: task:recordingPaused + TASK_RECORDING_PAUSE_FAILED: task:recordingPauseFailed + TASK_RECORDING_RESUMED: task:recordingResumed + TASK_RECORDING_RESUME_FAILED: task:recordingResumeFailed + TASK_REJECT: task:rejected + TASK_OUTDIAL_FAILED: task:outdialFailed + TASK_HYDRATE: task:hydrate + TASK_OFFER_CONTACT: task:offerContact + TASK_AUTO_ANSWERED: task:autoAnswered + TASK_CONFERENCE_ESTABLISHING: task:conferenceEstablishing + TASK_CONFERENCE_STARTED: task:conferenceStarted + TASK_CONFERENCE_FAILED: task:conferenceFailed + TASK_CONFERENCE_ENDED: task:conferenceEnded + TASK_PARTICIPANT_JOINED: task:participantJoined + TASK_PARTICIPANT_LEFT: task:participantLeft + TASK_CONFERENCE_TRANSFERRED: task:conferenceTransferred + TASK_CONFERENCE_TRANSFER_FAILED: task:conferenceTransferFailed + TASK_CONFERENCE_END_FAILED: task:conferenceEndFailed + TASK_PARTICIPANT_LEFT_FAILED: task:participantLeftFailed + TASK_EXIT_CONFERENCE: task:exitConference + TASK_TRANSFER_CONFERENCE: task:transferConference + TASK_SWITCH_CALL: task:switchCall + TASK_MERGED: task:merged + TASK_POST_CALL_ACTIVITY: task:postCallActivity + TASK_TRANSCRIPTION: task:transcription + TASK_TRANSCRIPTION_STARTED: task:transcriptionStarted + TASK_TRANSCRIPTION_STOPPED: task:transcriptionStopped + TASK_TRANSCRIPTION_FAILED: task:transcriptionFailed + AGENT_EVENTS: + AGENT_STATE_CHANGE: agent:stateChange + AGENT_MULTI_LOGIN: agent:multiLogin + AGENT_STATION_LOGIN_SUCCESS: agent:stationLoginSuccess + AGENT_STATION_LOGIN_FAILED: agent:stationLoginFailed + AGENT_LOGOUT_SUCCESS: agent:logoutSuccess + AGENT_LOGOUT_FAILED: agent:logoutFailed + AGENT_DN_REGISTERED: agent:dnRegistered + AGENT_RELOGIN_SUCCESS: agent:reloginSuccess + AGENT_STATE_CHANGE_SUCCESS: agent:stateChangeSuccess + AGENT_STATE_CHANGE_FAILED: agent:stateChangeFailed +types: + EntryPointRecord: + fields: + - name: id + type: string + required: true + - name: name + type: string + required: true + - name: description + type: string + required: false + - name: type + type: string + required: true + - name: isActive + type: boolean + required: true + - name: orgId + type: string + required: true + - name: createdAt + type: string + required: false + - name: updatedAt + type: string + required: false + - name: settings + type: Record + required: false + EntryPointListResponse: + kind: alias + values: + - PaginatedResponse + EntryPointSearchParams: + kind: alias + values: + - BaseSearchParams + AddressBookEntry: + fields: + - name: id + type: string + required: true + - name: organizationId + type: string + required: false + - name: version + type: number + required: false + - name: name + type: string + required: true + - name: number + type: string + required: true + - name: createdTime + type: number + required: false + - name: lastUpdatedTime + type: number + required: false + AddressBookEntriesResponse: + kind: alias + values: + - PaginatedResponse + AddressBookEntrySearchParams: + fields: + - name: addressBookId + type: string + required: false + ContactServiceQueuesResponse: + kind: alias + values: + - PaginatedResponse + ContactServiceQueueSearchParams: + fields: + - name: desktopProfileFilter + type: boolean + required: false + - name: provisioningView + type: boolean + required: false + - name: singleObjectResponse + type: boolean + required: false + ContactServiceQueue: + fields: + - name: organizationId + type: string + required: false + - name: id + type: string + required: false + - name: version + type: number + required: false + - name: name + type: string + required: true + - name: description + type: string + required: false + - name: queueType + type: "\"INBOUND\" | \"OUTBOUND\"" + required: true + - name: checkAgentAvailability + type: boolean + required: true + - name: channelType + type: "\"TELEPHONY\" | \"EMAIL\" | \"FAX\" | \"CHAT\" | \"VIDEO\" | \"OTHERS\" | \"SOCIAL_CHANNEL\"" + required: true + - name: socialChannelType + type: "\"MESSAGEBIRD\" | \"MESSENGER\" | \"WHATSAPP\" | \"APPLE_BUSINESS_CHAT\" | \"GOOGLE_BUSINESS_MESSAGES\"" + required: false + - name: serviceLevelThreshold + type: number + required: true + - name: maxActiveContacts + type: number + required: true + - name: maxTimeInQueue + type: number + required: true + - name: defaultMusicInQueueMediaFileId + type: string + required: true + - name: timezone + type: string + required: false + - name: active + type: boolean + required: true + - name: outdialCampaignEnabled + type: boolean + required: false + - name: monitoringPermitted + type: boolean + required: true + - name: parkingPermitted + type: boolean + required: true + - name: recordingPermitted + type: boolean + required: true + - name: recordingAllCallsPermitted + type: boolean + required: true + - name: pauseRecordingPermitted + type: boolean + required: true + - name: recordingPauseDuration + type: number + required: false + - name: controlFlowScriptUrl + type: string + required: true + - name: ivrRequeueUrl + type: string + required: true + - name: overflowNumber + type: string + required: false + - name: vendorId + type: string + required: false + - name: routingType + type: "\"LONGEST_AVAILABLE_AGENT\" | \"SKILLS_BASED\" | \"CIRCULAR\" | \"LINEAR\"" + required: true + - name: skillBasedRoutingType + type: "\"LONGEST_AVAILABLE_AGENT\" | \"BEST_AVAILABLE_AGENT\"" + required: false + - name: queueRoutingType + type: "\"TEAM_BASED\" | \"SKILL_BASED\" | \"AGENT_BASED\"" + required: true + - name: queueSkillRequirements + type: QueueSkillRequirement[] + required: false + - name: agents + type: QueueAgent[] + required: false + - name: callDistributionGroups + type: CallDistributionGroup[] + required: true + - name: xspVersion + type: string + required: false + - name: subscriptionId + type: string + required: false + - name: assistantSkill + type: AssistantSkillMapping + required: false + - name: systemDefault + type: boolean + required: false + - name: agentsLastUpdatedByUserName + type: string + required: false + - name: agentsLastUpdatedByUserEmailPrefix + type: string + required: false + - name: agentsLastUpdatedTime + type: number + required: false + - name: createdTime + type: number + required: false + - name: lastUpdatedTime + type: number + required: false + CC_EVENTS: + kind: alias + values: + - >- + "Welcome" | "AgentReloginSuccess" | "AgentReloginFailed" | "AgentDNRegistered" | "Logout" | "AgentLogoutSuccess" + | "AgentLogoutFailed" | "StationLogin" | "AgentStationLoginSuccess" | "AgentStationLoginFailed" | + "AgentStateChange" | "AGENT_MULTI_LOGIN" | "AgentStateChangeSuccess" | "AgentStateChangeFailed" | "BuddyAgents" + | "BuddyAgentsRetrieveFailed" | "AgentContactReserved" | "AgentContactAssignFailed" | "AgentOfferContactRona" | + "AgentContactHeld" | "AgentContactHoldFailed" | "AgentContactUnheld" | "AgentContactUnHoldFailed" | + "AgentConsultCreated" | "AgentOfferConsult" | "AgentConsulting" | "AgentConsultFailed" | "AgentCtqFailed" | + "AgentCtqCancelled" | "AgentCtqCancelFailed" | "AgentConsultEnded" | "AgentConsultEndFailed" | + "AgentConsultConferenceEnded" | "AgentConsultConferencing" | "AgentConsultConferenced" | + "AgentConsultConferenceFailed" | "ParticipantJoinedConference" | "ParticipantLeftConference" | + "ParticipantLeftConferenceFailed" | "AgentConsultConferenceEndFailed" | "AgentConferenceTransferred" | + "AgentConferenceTransferFailed" | "ParticipantPostCallActivity" | "ConsultedParticipantMoving" | + "REAL_TIME_TRANSCRIPTION" | "TranscriptionFailed" | "AgentBlindTransferred" | "AgentBlindTransferFailed" | + "AgentVteamTransferred" | "AgentVteamTransferFailed" | "AgentConsultTransferring" | "AgentConsultTransferred" | + "AgentConsultTransferFailed" | "ContactRecordingPaused" | "ContactRecordingStarted" | + "ContactRecordingPauseFailed" | "ContactRecordingResumed" | "ContactRecordingResumeFailed" | "ContactEnded" | + "ContactMerged" | "ContactUpdated" | "ContactOwnerChanged" | "AgentContactEndFailed" | "AgentWrapup" | + "AgentWrappedUp" | "AgentWrapupFailed" | "AgentOutboundFailed" | "AgentContact" | "AgentOfferContact" | + "AgentContactAssigned" | "AgentContactUnassigned" | "AgentInviteFailed" + ContactCenterEvents: + kind: alias + values: + - >- + "Welcome" | "AgentReloginSuccess" | "AgentReloginFailed" | "AgentDNRegistered" | "Logout" | "AgentLogoutSuccess" + | "AgentLogoutFailed" | "StationLogin" | "AgentStationLoginSuccess" | "AgentStationLoginFailed" | + "AgentStateChange" | "AGENT_MULTI_LOGIN" | "AgentStateChangeSuccess" | "AgentStateChangeFailed" | "BuddyAgents" + | "BuddyAgentsRetrieveFailed" | "AgentContactReserved" | "AgentContactAssignFailed" | "AgentOfferContactRona" | + "AgentContactHeld" | "AgentContactHoldFailed" | "AgentContactUnheld" | "AgentContactUnHoldFailed" | + "AgentConsultCreated" | "AgentOfferConsult" | "AgentConsulting" | "AgentConsultFailed" | "AgentCtqFailed" | + "AgentCtqCancelled" | "AgentCtqCancelFailed" | "AgentConsultEnded" | "AgentConsultEndFailed" | + "AgentConsultConferenceEnded" | "AgentConsultConferencing" | "AgentConsultConferenced" | + "AgentConsultConferenceFailed" | "ParticipantJoinedConference" | "ParticipantLeftConference" | + "ParticipantLeftConferenceFailed" | "AgentConsultConferenceEndFailed" | "AgentConferenceTransferred" | + "AgentConferenceTransferFailed" | "ParticipantPostCallActivity" | "ConsultedParticipantMoving" | + "REAL_TIME_TRANSCRIPTION" | "TranscriptionFailed" | "AgentBlindTransferred" | "AgentBlindTransferFailed" | + "AgentVteamTransferred" | "AgentVteamTransferFailed" | "AgentConsultTransferring" | "AgentConsultTransferred" | + "AgentConsultTransferFailed" | "ContactRecordingPaused" | "ContactRecordingStarted" | + "ContactRecordingPauseFailed" | "ContactRecordingResumed" | "ContactRecordingResumeFailed" | "ContactEnded" | + "ContactMerged" | "ContactUpdated" | "ContactOwnerChanged" | "AgentContactEndFailed" | "AgentWrapup" | + "AgentWrappedUp" | "AgentWrapupFailed" | "AgentOutboundFailed" | "AgentContact" | "AgentOfferContact" | + "AgentContactAssigned" | "AgentContactUnassigned" | "AgentInviteFailed" + IContactCenter: + fields: [] + CCPluginConfig: + fields: + - name: allowMultiLogin + type: boolean + required: true + - name: allowAutomatedRelogin + type: boolean + required: true + - name: clientType + type: string + required: true + - name: isKeepAliveEnabled + type: boolean + required: true + - name: force + type: boolean + required: true + - name: metrics + type: "{ clientName: string; clientType: string; }" + required: true + - name: logging + type: "{ enable: boolean; verboseEvents: boolean; }" + required: true + - name: callingClientConfig + type: CallingClientConfig + required: true + WebexSDK: + fields: + - name: version + type: string + required: true + - name: canAuthorize + type: boolean + required: true + - name: credentials + type: "{ getUserToken: () => Promise; getOrgId: () => string; }" + required: true + - name: ready + type: boolean + required: true + - name: request + type: "(payload: WebexRequestPayload) => Promise" + required: true + - name: once + type: "(event: string, callBack: () => void) => void" + required: true + - name: internal + type: IWebexInternal + required: true + - name: logger + type: Logger + required: true + LoginOption: + kind: alias + values: + - "\"AGENT_DN\" | \"EXTENSION\" | \"BROWSER\"" + AgentLogin: + fields: + - name: dialNumber + type: string + required: false + - name: teamId + type: string + required: true + - name: loginOption + type: LoginOption + required: true + AgentProfileUpdate: + kind: alias + values: + - "{ loginOption: LoginOption; dialNumber?: string; teamId: string; }" + StationLoginResponse: + kind: union + values: + - Agent.StationLoginSuccessResponse + - Error + StationLogoutResponse: + kind: union + values: + - Agent.LogoutSuccess + - Error + BuddyAgentsResponse: + kind: union + values: + - Agent.BuddyAgentsSuccess + - Error + BuddyAgents: + fields: + - name: mediaType + type: "\"telephony\" | \"chat\" | \"social\" | \"email\"" + required: true + - name: state + type: "\"Available\" | \"Idle\"" + required: false + SubscribeRequest: + fields: + - name: force + type: boolean + required: true + - name: isKeepAliveEnabled + type: boolean + required: true + - name: clientType + type: string + required: true + - name: allowMultiLogin + type: boolean + required: true + UploadLogsResponse: + fields: + - name: trackingid + type: string + required: false + - name: url + type: string + required: false + - name: userId + type: string + required: false + - name: feedbackId + type: string + required: false + - name: correlationId + type: string + required: false + UpdateDeviceTypeResponse: + kind: union + values: + - Agent.DeviceTypeUpdateSuccess + - Error + GenericError: + fields: + - name: details + type: "{ type: string; orgId: string; trackingId: string; data: Record; }" + required: true + SetStateResponse: + kind: union + values: + - Agent.StateChangeSuccess + - Error + AgentContact: + kind: alias + values: + - >- + { type: string; orgId: string; trackingId: string; data: { mediaResourceId: string; eventType: string; + eventTime?: number; agentId: string; destAgentId: string; trackingId: string; consultMediaResourceId: string; + interaction: Interaction; participantId?: string; fromOwner?: boolean; toOwner?: boolean; childInteractionId?: + string; interactionId: string; orgId: string; owner: string; queueMgr: string; queueName?: string; type: string; + ronaTimeout?: number; isConsulted?: boolean; isConferencing: boolean; updatedBy?: string; destinationType?: + string; autoResumed?: boolean; reasonCode?: string | number; reason?: string; consultingAgentId?: string; + taskId?: string; task?: Interaction; supervisorId?: string; monitorType?: string; supervisorDN?: string; id?: + string; isWebCallMute?: boolean; reservationInteractionId?: string; reservedAgentChannelId?: string; + monitoringState?: { type: string; }; supervisorName?: string; }; } + ITask: + fields: + - name: data + type: TaskData + required: true + - name: webCallMap + type: Record + required: true + - name: autoWrapup + type: AutoWrapup + required: false + - name: stateMachineService + type: AnyActorRef + required: false + - name: state + type: any + required: false + - name: sendStateMachineEvent + type: "(event: TaskEventPayload) => void" + required: true + Interaction: + fields: + - name: isFcManaged + type: boolean + required: true + - name: isTerminated + type: boolean + required: true + - name: mediaType + type: MEDIA_CHANNEL + required: true + - name: previousVTeams + type: string[] + required: true + - name: state + type: string + required: true + - name: currentVTeam + type: string + required: true + - name: participants + type: InteractionParticipants + required: true + - name: callAssociatedData + type: CallAssociatedData + required: false + - name: callAssociatedDetails + type: CallAssociatedDetails + required: false + - name: interactionId + type: string + required: true + - name: orgId + type: string + required: true + - name: createdTimestamp + type: number + required: false + - name: isWrapUpAssist + type: boolean + required: false + - name: parentInteractionId + type: string + required: false + - name: isMediaForked + type: boolean + required: false + - name: flowProperties + type: Record + required: false + - name: mediaProperties + type: Record + required: false + - name: callProcessingDetails + type: >- + { QMgrName: string; taskToBeSelfServiced: string; ani: string; displayAni: string; dnis: string; tenantId: + string; QueueId: string; vteamId: string; pauseResumeEnabled?: boolean; pauseDuration?: string; isPaused?: + boolean; recordInProgress?: boolean; recordingStarted?: boolean; customerRegion?: string; flowTagId?: string; + ctqInProgress?: boolean; outdialTransferToQueueEnabled?: boolean; convIvrTranscript?: string; customerName: + string; virtualTeamName: string; ronaTimeout: string; category: string; reason: string; sourceNumber: string; + sourcePage: string; appUser: string; customerNumber: string; reasonCode: string; IvrPath: string; pathId: + string; fromAddress: string; parentInteractionId?: string; childInteractionId?: string; relationshipType?: + string; parent_ANI?: string; parent_DNIS?: string; consultDestinationAgentJoined?: boolean | string; + consultDestinationAgentName?: string; parent_Agent_DN?: string; parent_Agent_Name?: string; + parent_Agent_TeamName?: string; isConferencing?: string; monitorType?: string; workflowName?: string; + workflowId?: string; monitoringInvisibleMode?: string; monitoringRequestId?: string; + participantInviteTimeout?: string; mohFileName?: string; CONTINUE_RECORDING_ON_TRANSFER?: string; EP_ID?: + string; ROUTING_TYPE?: string; fceRegisteredEvents?: string; isParked?: string; priority?: string; + routingStrategyId?: string; monitoringState?: string; BLIND_TRANSFER_IN_PROGRESS?: boolean; fcDesktopView?: + string; outdialAgentId?: string; } + required: true + - name: mainInteractionId + type: string + required: false + - name: queuedTimestamp + type: number + required: false + - name: media + type: Record + required: true + - name: owner + type: string + required: true + - name: mediaChannel + type: string + required: true + - name: contactDirection + type: "{ type: string; }" + required: true + - name: outboundType + type: string + required: false + - name: workflowManager + type: string + required: false + - name: callFlowParams + type: Record + required: false + TaskData: + fields: + - name: mediaResourceId + type: string + required: true + - name: eventType + type: string + required: true + - name: eventTime + type: number + required: false + - name: agentId + type: string + required: true + - name: destAgentId + type: string + required: true + - name: trackingId + type: string + required: true + - name: consultMediaResourceId + type: string + required: true + - name: interaction + type: Interaction + required: true + - name: participantId + type: string + required: false + - name: fromOwner + type: boolean + required: false + - name: toOwner + type: boolean + required: false + - name: childInteractionId + type: string + required: false + - name: interactionId + type: string + required: true + - name: orgId + type: string + required: true + - name: owner + type: string + required: true + - name: queueMgr + type: string + required: true + - name: queueName + type: string + required: false + - name: type + type: string + required: true + - name: ronaTimeout + type: number + required: false + - name: isConsulted + type: boolean + required: false + - name: isConferencing + type: boolean + required: true + - name: isConferenceInProgress + type: boolean + required: false + - name: updatedBy + type: string + required: false + - name: destinationType + type: string + required: false + - name: autoResumed + type: boolean + required: false + - name: reasonCode + type: string | number + required: false + - name: reason + type: string + required: false + - name: consultingAgentId + type: string + required: false + - name: taskId + type: string + required: false + - name: task + type: Interaction + required: false + - name: id + type: string + required: false + - name: isWebCallMute + type: boolean + required: false + - name: reservationInteractionId + type: string + required: false + - name: reservedAgentChannelId + type: string + required: false + - name: wrapUpRequired + type: boolean + required: false + - name: consultStatus + type: string + required: false + - name: isConsultInProgress + type: boolean + required: false + - name: isIncomingTask + type: boolean + required: false + - name: isOnHold + type: boolean + required: false + - name: isCustomerInCall + type: boolean + required: false + - name: conferenceParticipantsCount + type: number + required: false + - name: isSecondaryAgent + type: boolean + required: false + - name: isSecondaryEpDnAgent + type: boolean + required: false + - name: mpcState + type: string + required: false + - name: isAutoAnswering + type: boolean + required: false + - name: agentsPendingWrapUp + type: string[] + required: false + TaskResponse: + kind: union + values: + - AgentContact + - Error + - void + ConsultPayload: + fields: + - name: to + type: string + required: true + - name: destinationType + type: string + required: true + - name: holdParticipants + type: boolean + required: false + ConsultEndPayload: + fields: + - name: isConsult + type: boolean + required: true + - name: isSecondaryEpDnAgent + type: boolean + required: false + - name: queueId + type: string + required: false + - name: taskId + type: string + required: true + ConsultTransferPayLoad: + fields: + - name: to + type: string + required: true + - name: destinationType + type: string + required: true + DialerPayload: + fields: + - name: entryPointId + type: string + required: true + - name: destination + type: string + required: true + - name: direction + type: "\"OUTBOUND\"" + required: true + - name: attributes + type: "{ [key: string]: string; }" + required: true + - name: mediaType + type: "\"telephony\" | \"chat\" | \"social\" | \"email\"" + required: true + - name: outboundType + type: "\"OUTDIAL\" | \"CALLBACK\" | \"EXECUTE_FLOW\"" + required: true + - name: origin + type: string + required: true + TransferPayLoad: + fields: + - name: to + type: string + required: true + - name: destinationType + type: string + required: true + ResumeRecordingPayload: + fields: + - name: autoResumed + type: boolean + required: true + WrapupPayLoad: + fields: + - name: wrapUpReason + type: string + required: true + - name: auxCodeId + type: string + required: true + StateChange: + fields: + - name: state + type: string + required: true + - name: auxCodeId + type: string + required: true + - name: lastStateChangeReason + type: string + required: false + - name: agentId + type: string + required: false + Logout: + fields: + - name: logoutReason + type: "\"User requested logout\" | \"Inactivity Logout\" | \"User requested agent profile update\"" + required: false + StateChangeSuccess: + kind: alias + values: + - >- + { type: string; orgId: string; trackingId: string; data: { eventType: "AgentDesktopMessage"; agentId: string; + trackingId: string; auxCodeId: string; agentSessionId: string; orgId: string; status: string; subStatus: + "Available" | "Idle"; lastIdleCodeChangeTimestamp: number; lastStateChangeTimestamp: number; type: + "AgentStateChangeSuccess"; changedBy: string | null; changedById: string | null; changedByName: string | null; + lastStateChangeReason: string; }; } + StationLoginSuccess: + kind: alias + values: + - >- + { type: string; orgId: string; trackingId: string; data: { eventType: "AgentDesktopMessage"; agentId: string; + trackingId: string; auxCodeId: string; teamId: string; agentSessionId: string; orgId: string; interactionIds: + string[]; status: string; subStatus: "Available" | "Idle"; siteId: string; lastIdleCodeChangeTimestamp: number; + lastStateChangeTimestamp: number; profileType: string; channelsMap: Record; dialNumber?: + string; roles?: string[]; supervisorSessionId?: string; type: "AgentStationLoginSuccess"; }; } + StationLoginSuccessResponse: + fields: + - name: eventType + type: "\"AgentDesktopMessage\"" + required: true + - name: agentId + type: string + required: true + - name: trackingId + type: string + required: true + - name: auxCodeId + type: string + required: true + - name: teamId + type: string + required: true + - name: agentSessionId + type: string + required: true + - name: orgId + type: string + required: true + - name: interactionIds + type: string[] + required: true + - name: status + type: string + required: true + - name: subStatus + type: "\"Available\" | \"Idle\"" + required: true + - name: siteId + type: string + required: true + - name: lastIdleCodeChangeTimestamp + type: number + required: true + - name: lastStateChangeTimestamp + type: number + required: true + - name: profileType + type: string + required: true + - name: mmProfile + type: "{ chat: number; email: number; social: number; telephony: number; }" + required: true + - name: dialNumber + type: string + required: false + - name: roles + type: string[] + required: false + - name: supervisorSessionId + type: string + required: false + - name: type + type: "\"AgentStationLoginSuccess\"" + required: true + - name: notifsTrackingId + type: string + required: true + DeviceTypeUpdateSuccess: + kind: alias + values: + - "Omit & { type: \"AgentDeviceTypeUpdateSuccess\"; }" + LogoutSuccess: + kind: alias + values: + - >- + { type: string; orgId: string; trackingId: string; data: { eventType: "AgentDesktopMessage"; agentId: string; + trackingId: string; agentSessionId: string; orgId: string; status: string; subStatus: string; loggedOutBy?: + string; roles?: string[]; type: "AgentLogoutSuccess"; }; } + ReloginSuccess: + kind: alias + values: + - >- + { type: string; orgId: string; trackingId: string; data: { eventType: "AgentDesktopMessage"; agentId: string; + trackingId: string; auxCodeId: string; teamId: string; agentSessionId: string; dn: string; orgId: string; + interactionIds: string[]; isExtension: boolean; status: "LoggedIn"; subStatus: "Idle"; siteId: string; + lastIdleCodeChangeTimestamp: number; lastStateChangeTimestamp: number; lastStateChangeReason?: string; + profileType: string; channelsMap: Record; dialNumber?: string; roles?: string[]; deviceType?: + DeviceType; deviceId?: string | null; isEmergencyModalAlreadyDisplayed?: boolean; type: "AgentReloginSuccess"; + }; } + AgentState: + kind: union + values: + - "'Available'" + - "'Idle'" + - "'RONA'" + - string + UserStationLogin: + fields: + - name: dialNumber + type: string + required: false + - name: dn + type: string + required: false + - name: teamId + type: string + required: true + - name: teamName + type: string + required: true + - name: roles + type: string[] + required: false + - name: siteId + type: string + required: true + - name: usesOtherDN + type: boolean + required: true + - name: skillProfileId + type: string + required: false + - name: auxCodeId + type: string + required: true + - name: isExtension + type: boolean + required: false + - name: deviceType + type: string + required: false + - name: deviceId + type: string + required: false + - name: isEmergencyModalAlreadyDisplayed + type: boolean + required: false + DeviceType: + kind: union + values: + - LoginOption + - string + BuddyDetails: + fields: + - name: agentId + type: string + required: true + - name: state + type: string + required: true + - name: teamId + type: string + required: true + - name: dn + type: string + required: true + - name: agentName + type: string + required: true + - name: siteId + type: string + required: true + BuddyAgentsSuccess: + kind: alias + values: + - >- + { type: string; orgId: string; trackingId: string; data: { eventType: "AgentDesktopMessage"; agentId: string; + trackingId: string; agentSessionId: string; orgId: string; type: "BuddyAgents"; agentList: Array; + }; } + Profile: + fields: + - name: microsoftConfig + type: "{ showUserDetailsMS?: boolean; stateSynchronizationMS?: boolean; }" + required: false + - name: webexConfig + type: "{ showUserDetailsWebex?: boolean; stateSynchronizationWebex?: boolean; }" + required: false + - name: teams + type: Team[] + required: true + - name: defaultDn + type: string + required: true + - name: dn + type: string + required: false + - name: forceDefaultDn + type: boolean + required: true + - name: forceDefaultDnForAgent + type: boolean + required: true + - name: regexUS + type: string | RegExp + required: true + - name: regexOther + type: string | RegExp + required: true + - name: agentId + type: string + required: true + - name: agentName + type: string + required: true + - name: agentMailId + type: string + required: true + - name: agentProfileID + type: string + required: true + - name: dialPlan + type: DialPlan + required: true + - name: multimediaProfileId + type: string + required: true + - name: skillProfileId + type: string + required: true + - name: siteId + type: string + required: true + - name: enterpriseId + type: string + required: true + - name: privacyShieldVisible + type: boolean + required: true + - name: idleCodes + type: Entity[] + required: true + - name: idleCodesList + type: string[] + required: false + - name: idleCodesAccess + type: "\"ALL\" | \"SPECIFIC\"" + required: false + - name: wrapupCodes + type: Entity[] + required: true + - name: agentWrapUpCodes + type: agentWrapUpCodes + required: false + - name: agentDefaultWrapUpCode + type: agentDefaultWrapupCode + required: false + - name: defaultWrapupCode + type: string + required: true + - name: wrapUpData + type: WrapupData + required: true + - name: orgId + type: string + required: false + - name: isOutboundEnabledForTenant + type: boolean + required: true + - name: isOutboundEnabledForAgent + type: boolean + required: true + - name: isAdhocDialingEnabled + type: boolean + required: true + - name: isAgentAvailableAfterOutdial + type: boolean + required: true + - name: isCampaignManagementEnabled + type: boolean + required: true + - name: outDialEp + type: string + required: true + - name: isEndTaskEnabled + type: boolean + required: true + - name: isEndConsultEnabled + type: boolean + required: true + - name: lcmUrl + type: string + required: false + - name: agentDbId + type: string + required: true + - name: agentAnalyzerId + type: string + required: false + - name: allowConsultToQueue + type: boolean + required: true + - name: campaignManagerAdditionalInfo + type: string + required: false + - name: agentPersonalStatsEnabled + type: boolean + required: true + - name: addressBookId + type: string + required: false + - name: outdialANIId + type: string + required: false + - name: analyserUserId + type: string + required: false + - name: isCallMonitoringEnabled + type: boolean + required: false + - name: isMidCallMonitoringEnabled + type: boolean + required: false + - name: isBargeInEnabled + type: boolean + required: false + - name: isManagedTeamsEnabled + type: boolean + required: false + - name: isManagedQueuesEnabled + type: boolean + required: false + - name: isSendMessageEnabled + type: boolean + required: false + - name: isAgentStateChangeEnabled + type: boolean + required: false + - name: isSignOutAgentsEnabled + type: boolean + required: false + - name: urlMappings + type: URLMappings + required: false + - name: isTimeoutDesktopInactivityEnabled + type: boolean + required: true + - name: timeoutDesktopInactivityMins + type: number + required: false + - name: isAnalyzerEnabled + type: boolean + required: false + - name: tenantTimezone + type: string + required: false + - name: loginVoiceOptions + type: LoginOption[] + required: false + - name: deviceType + type: LoginOption + required: false + - name: currentTeamId + type: string + required: false + - name: webRtcEnabled + type: boolean + required: true + - name: organizationIdleCodes + type: Entity[] + required: false + - name: isRecordingManagementEnabled + type: boolean + required: false + - name: lostConnectionRecoveryTimeout + type: number + required: true + - name: maskSensitiveData + type: boolean + required: false + - name: isAgentLoggedIn + type: boolean + required: false + - name: lastStateAuxCodeId + type: string + required: false + - name: lastStateChangeTimestamp + type: number + required: false + - name: lastIdleCodeChangeTimestamp + type: number + required: false + AgentResponse: + fields: + - name: id + type: string + required: true + - name: ciUserId + type: string + required: true + - name: firstName + type: string + required: true + - name: lastName + type: string + required: true + - name: agentProfileId + type: string + required: true + - name: email + type: string + required: true + - name: teamIds + type: string[] + required: true + - name: multimediaProfileId + type: string + required: true + - name: skillProfileId + type: string + required: true + - name: siteId + type: string + required: true + - name: dbId + type: string + required: false + - name: defaultDialledNumber + type: string + required: false + DesktopProfileResponse: + fields: + - name: id + type: string + required: true + - name: name + type: string + required: true + - name: description + type: string + required: true + - name: parentType + type: string + required: true + - name: screenPopup + type: boolean + required: true + - name: loginVoiceOptions + type: LoginOption[] + required: true + - name: accessWrapUpCode + type: string + required: true + - name: accessIdleCode + type: string + required: true + - name: wrapUpCodes + type: string[] + required: true + - name: idleCodes + type: string[] + required: true + - name: dialPlanEnabled + type: boolean + required: true + - name: lastAgentRouting + type: boolean + required: true + - name: autoWrapUp + type: boolean + required: true + - name: agentPersonalGreeting + type: boolean + required: true + - name: autoAnswer + type: boolean + required: true + - name: autoWrapAfterSeconds + type: number + required: true + - name: agentAvailableAfterOutdial + type: boolean + required: true + - name: allowAutoWrapUpExtension + type: boolean + required: true + - name: accessQueue + type: string + required: true + - name: queues + type: string[] + required: true + - name: accessEntryPoint + type: string + required: true + - name: entryPoints + type: string[] + required: true + - name: accessBuddyTeam + type: string + required: true + - name: buddyTeams + type: string[] + required: true + - name: outdialEnabled + type: boolean + required: true + - name: outdialEntryPointId + type: string + required: true + - name: outdialANIId + type: string + required: true + - name: consultToQueue + type: boolean + required: true + - name: addressBookId + type: string + required: true + - name: viewableStatistics + type: >- + { id: string; agentStats: boolean; accessQueueStats: string; contactServiceQueues: string[]; + loggedInTeamStats: boolean; accessTeamStats: string; teams: string[]; } + required: true + - name: agentDNValidation + type: string + required: true + - name: agentDNValidationCriterions + type: string[] + required: true + - name: dialPlans + type: string[] + required: true + - name: timeoutDesktopInactivityCustomEnabled + type: boolean + required: true + - name: timeoutDesktopInactivityMins + type: number + required: true + - name: showUserDetailsMS + type: boolean + required: true + - name: stateSynchronizationMS + type: boolean + required: true + - name: showUserDetailsWebex + type: boolean + required: true + - name: stateSynchronizationWebex + type: boolean + required: true + - name: thresholdRules + type: Record[] + required: true + - name: active + type: boolean + required: true + - name: systemDefault + type: boolean + required: true + - name: createdTime + type: number + required: true + - name: lastUpdatedTime + type: number + required: true + MultimediaProfileResponse: + fields: + - name: organizationId + type: string + required: true + - name: id + type: string + required: true + - name: version + type: number + required: true + - name: name + type: string + required: true + - name: description + type: string + required: true + - name: chat + type: number + required: true + - name: email + type: number + required: true + - name: telephony + type: number + required: true + - name: social + type: number + required: true + - name: active + type: boolean + required: true + - name: blendingModeEnabled + type: boolean + required: true + - name: blendingMode + type: string + required: true + - name: systemDefault + type: boolean + required: true + - name: createdTime + type: number + required: true + - name: lastUpdatedTime + type: number + required: true + ListTeamsResponse: + fields: + - name: data + type: TeamList[] + required: true + - name: meta + type: "{ page: number; pageSize: number; totalPages: number; totalRecords: number; }" + required: true + ListAuxCodesResponse: + fields: + - name: data + type: AuxCode[] + required: true + - name: meta + type: "{ page: number; pageSize: number; totalPages: number; totalRecords: number; }" + required: true + SiteInfo: + fields: + - name: id + type: string + required: true + - name: name + type: string + required: true + - name: active + type: boolean + required: true + - name: multimediaProfileId + type: string + required: true + - name: systemDefault + type: boolean + required: true + OrgInfo: + fields: + - name: tenantId + type: string + required: true + - name: timezone + type: string + required: true + OrgSettings: + fields: + - name: webRtcEnabled + type: boolean + required: true + - name: maskSensitiveData + type: boolean + required: true + - name: campaignManagerEnabled + type: boolean + required: true + TenantData: + fields: + - name: timeoutDesktopInactivityMins + type: number + required: true + - name: forceDefaultDn + type: boolean + required: true + - name: dnDefaultRegex + type: string + required: true + - name: dnOtherRegex + type: string + required: true + - name: privacyShieldVisible + type: boolean + required: true + - name: outdialEnabled + type: boolean + required: true + - name: endCallEnabled + type: boolean + required: true + - name: endConsultEnabled + type: boolean + required: true + - name: callVariablesSuppressed + type: boolean + required: true + - name: timeoutDesktopInactivityEnabled + type: boolean + required: true + - name: lostConnectionRecoveryTimeout + type: number + required: true + URLMapping: + fields: + - name: id + type: string + required: true + - name: name + type: string + required: true + - name: url + type: string + required: true + - name: links + type: string[] + required: true + - name: createdTime + type: number + required: true + - name: lastUpdatedTime + type: number + required: true + DialPlanEntity: + fields: + - name: id + type: string + required: true + - name: regularExpression + type: string + required: true + - name: prefix + type: string + required: true + - name: strippedChars + type: string + required: true + - name: name + type: string + required: true + AuxCode: + fields: + - name: id + type: string + required: true + - name: active + type: boolean + required: true + - name: defaultCode + type: boolean + required: true + - name: isSystemCode + type: boolean + required: true + - name: description + type: string + required: true + - name: name + type: string + required: true + - name: workTypeCode + type: string + required: true + TeamList: + fields: + - name: id + type: string + required: true + - name: name + type: string + required: true + - name: teamType + type: string + required: true + - name: teamStatus + type: string + required: true + - name: active + type: boolean + required: true + - name: siteId + type: string + required: true + - name: siteName + type: string + required: true + - name: multiMediaProfileId + type: string + required: false + - name: userIds + type: string[] + required: true + - name: rankQueuesForTeam + type: boolean + required: true + - name: queueRankings + type: string[] + required: true + - name: dbId + type: string + required: false + - name: desktopLayoutId + type: string + required: false + WrapUpReason: + fields: + - name: isSystem + type: boolean + required: true + - name: name + type: string + required: true + - name: id + type: string + required: true + - name: isDefault + type: boolean + required: true + WebSocketEvent: + fields: + - name: type + type: CC_EVENTS + required: true + - name: data + type: >- + Agent.BuddyAgentsSuccess | Agent.LogoutSuccess | Agent.StateChangeSuccess | Agent.StationLoginSuccess | + Agent.ReloginSuccess | WelcomeEvent + required: true + WrapupData: + fields: + - name: wrapUpProps + type: >- + { autoWrapup?: boolean; autoWrapupInterval?: number; lastAgentRoute?: boolean; wrapUpReasonList: + Array; wrapUpCodesList?: Array; idleCodesAccess?: "ALL" | "SPECIFIC"; interactionId?: + string; allowCancelAutoWrapup?: boolean; } + required: true + Entity: + fields: + - name: isSystem + type: boolean + required: true + - name: name + type: string + required: true + - name: id + type: string + required: true + - name: isDefault + type: boolean + required: true + DialPlan: + fields: + - name: type + type: string + required: true + - name: dialPlanEntity + type: "{ regex: string; prefix: string; strippedChars: string; name: string; }[]" + required: true + AuxCodeType: + kind: union + values: + - typeof IDLE_CODE + - typeof WRAP_UP_CODE +constants: + IDLE_CODE: IDLE_CODE + WRAP_UP_CODE: WRAP_UP_CODE diff --git a/package.json b/package.json index 78c839418..0f2e63809 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,8 @@ "@semantic-release/git": "^10.0.1", "@semantic-release/github": "^11.0.1", "@testing-library/react-hooks": "^8.0.1", + "@types/js-yaml": "^4.0.9", + "@types/node": "^25.5.0", "@webex/cli-tools": "0.0.0-next.2", "@webex/package-tools": "0.0.0-next.6", "babel-jest": "^29.7.0", @@ -28,6 +30,7 @@ "husky": "^9.1.7", "jest": "29.7.0", "jest-canvas-mock": "^2.5.2", + "js-yaml": "^4.1.1", "node-gyp": "^10.2.0", "nodemailer": "^7.0.3", "os-browserify": "^0.3.0", @@ -38,6 +41,8 @@ "semantic-release": "^24.2.0", "stream-browserify": "^3.0.0", "style-loader": "^4.0.0", + "ts-morph": "^27.0.2", + "ts-node": "^10.9.2", "typescript": "^5.6.3", "vm-browserify": "^1.1.2", "webpack": "^5.96.1", @@ -67,6 +72,7 @@ "release:widgets": "semantic-release", "postinstall": "husky install", "prepare": "husky", - "package-tools": "webex-package-tools" + "package-tools": "webex-package-tools", + "generate:sdk-deps": "ts-node --project scripts/tsconfig.json scripts/generate-sdk-deps.ts" } } diff --git a/scripts/generate-sdk-deps.ts b/scripts/generate-sdk-deps.ts new file mode 100644 index 000000000..9477059f8 --- /dev/null +++ b/scripts/generate-sdk-deps.ts @@ -0,0 +1,419 @@ +/** + * Consumer SDK Dependency Map Generator + * + * Scans the ccWidgets monorepo for all imports from tracked SDK packages + * and produces sdk-dependencies.yaml mapping each SDK API to the exact + * consumer files and line numbers that use it. + * + * Usage: npx ts-node scripts/generate-sdk-deps.ts + */ + +import {Project, Node, SyntaxKind, SourceFile} from 'ts-morph'; +import * as yaml from 'js-yaml'; +import * as fs from 'fs'; +import * as path from 'path'; + +const REPO_ROOT = path.resolve(__dirname, '..'); +const OUTPUT_FILE = path.join(REPO_ROOT, 'sdk-dependencies.yaml'); + +// SDK packages to track — add more as needed +const TRACKED_SDKS = [ + '@webex/contact-center', +]; + +// Directories to scan (relative to repo root) +const SCAN_DIRS = [ + 'packages/contact-center', +]; + +// Skip test files, fixtures, ai-docs, and dist/build output +const SKIP_PATTERNS = [ + '/tests/', + '/test/', + '/__tests__/', + '/test-fixtures/', + '/ai-docs/', + '/dist/', + '/build/', + '/node_modules/', + '.test.ts', + '.test.tsx', + '.spec.ts', + '.spec.tsx', + '.d.ts', +]; + +interface UsageEntry { + file: string; + line: number; + context: string; +} + +interface MethodUsages { + usages: UsageEntry[]; +} + +interface EventUsages { + listeners: UsageEntry[]; +} + +interface TypeUsages { + imports: UsageEntry[]; +} + +interface SDKDependency { + version: string; + manifest_hash: string; + methods: Record; + events: Record; + types: Record; +} + +interface DependencyMap { + generated_at: string; + generator: string; + dependencies: Record; +} + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +function shouldSkip(filePath: string): boolean { + return SKIP_PATTERNS.some((p) => filePath.includes(p)); +} + +function relativePath(absPath: string): string { + return path.relative(REPO_ROOT, absPath); +} + +function getLineContext(sourceFile: SourceFile, line: number): string { + const fullText = sourceFile.getFullText(); + const lines = fullText.split('\n'); + if (line > 0 && line <= lines.length) { + return lines[line - 1].trim().substring(0, 100); + } + return ''; +} + +/** + * Find the SDK manifest — checks node_modules first, then known local paths. + */ +function findManifestPath(sdkPackage: string): string | null { + // 1. Check node_modules (works for both symlinked and npm-installed) + const nmPath = path.join(REPO_ROOT, 'node_modules', sdkPackage, 'sdk-manifest.yaml'); + if (fs.existsSync(nmPath)) return nmPath; + + // 2. Check known local SDK paths (for development when symlink is broken) + const localPaths: Record = { + '@webex/contact-center': path.resolve(REPO_ROOT, '../ccSDK/webex-js-sdk/packages/@webex/contact-center/sdk-manifest.yaml'), + }; + const localPath = localPaths[sdkPackage]; + if (localPath && fs.existsSync(localPath)) return localPath; + + return null; +} + +/** + * Read the SDK manifest to get the version and compute a simple hash for staleness detection. + */ +function getManifestInfo(sdkPackage: string): {version: string; hash: string} { + const manifestPath = findManifestPath(sdkPackage); + if (manifestPath) { + const content = fs.readFileSync(manifestPath, 'utf8'); + const manifest = yaml.load(content) as Record; + // Simple hash: first 8 chars of content hash + const crypto = require('crypto'); + const hash = crypto.createHash('md5').update(content).digest('hex').substring(0, 8); + return { + version: (manifest.version as string) || 'unknown', + hash, + }; + } + return {version: 'unknown', hash: 'no-manifest'}; +} + +/** + * Load the SDK manifest to know which exports are methods vs types vs events. + */ +function loadManifest(sdkPackage: string): {methods: Set; types: Set; events: Set} | null { + const manifestPath = findManifestPath(sdkPackage); + if (!manifestPath) return null; + + const content = fs.readFileSync(manifestPath, 'utf8'); + const manifest = yaml.load(content) as Record; + + const methods = new Set(); + const types = new Set(); + const events = new Set(); + + // Extract class method names + const classes = (manifest.classes || {}) as Record}>; + for (const [className, cls] of Object.entries(classes)) { + for (const methodName of Object.keys(cls.methods || {})) { + methods.add(`${className}.${methodName}`); + methods.add(methodName); // Also track bare method name + } + } + + // Extract type names + const typeEntries = (manifest.types || {}) as Record; + for (const typeName of Object.keys(typeEntries)) { + types.add(typeName); + } + + // Extract event string values + const eventEntries = (manifest.events || {}) as Record>; + for (const enumGroup of Object.values(eventEntries)) { + for (const eventValue of Object.values(enumGroup)) { + events.add(eventValue); + } + } + + return {methods, types, events}; +} + +// --------------------------------------------------------------------------- +// Main scanner +// --------------------------------------------------------------------------- + +function generate(): void { + console.log('Loading TypeScript project...'); + + const project = new Project({ + tsConfigFilePath: path.join(REPO_ROOT, 'tsconfig.json'), + skipAddingFilesFromTsConfig: true, + }); + + // Add source files from scan directories + for (const dir of SCAN_DIRS) { + const absDir = path.join(REPO_ROOT, dir); + project.addSourceFilesAtPaths([ + `${absDir}/**/*.ts`, + `${absDir}/**/*.tsx`, + ]); + } + + const sourceFiles = project.getSourceFiles().filter((sf) => !shouldSkip(sf.getFilePath())); + console.log(`Scanning ${sourceFiles.length} source files...`); + + const depMap: DependencyMap = { + generated_at: new Date().toISOString(), + generator: 'generate-sdk-deps.ts v1.0', + dependencies: {}, + }; + + // Initialize dependency entries for each tracked SDK + for (const sdk of TRACKED_SDKS) { + const manifestInfo = getManifestInfo(sdk); + depMap.dependencies[sdk] = { + version: manifestInfo.version, + manifest_hash: manifestInfo.hash, + methods: {}, + events: {}, + types: {}, + }; + } + + // Load manifest for classification + const manifests: Record> = {}; + for (const sdk of TRACKED_SDKS) { + manifests[sdk] = loadManifest(sdk); + } + + for (const sourceFile of sourceFiles) { + const filePath = sourceFile.getFilePath(); + const relPath = relativePath(filePath); + + // Find all import declarations from tracked SDKs + const imports = sourceFile.getImportDeclarations(); + + for (const imp of imports) { + const moduleSpecifier = imp.getModuleSpecifierValue(); + + // Check if this import is from a tracked SDK + const matchedSdk = TRACKED_SDKS.find((sdk) => + moduleSpecifier === sdk || moduleSpecifier.startsWith(sdk + '/') + ); + if (!matchedSdk) continue; + + const sdkDep = depMap.dependencies[matchedSdk]; + const manifest = manifests[matchedSdk]; + + // Process named imports + const namedImports = imp.getNamedImports(); + for (const named of namedImports) { + const importName = named.getName(); + const alias = named.getAliasNode()?.getText() || importName; + const line = named.getStartLineNumber(); + + // Classify: is this a type import or value import? + const isTypeOnly = imp.isTypeOnly() || named.isTypeOnly(); + + if (isTypeOnly || (manifest && manifest.types.has(importName) && !manifest.methods.has(importName))) { + // Type import + if (!sdkDep.types[importName]) { + sdkDep.types[importName] = {imports: []}; + } + sdkDep.types[importName].imports.push({ + file: relPath, + line, + context: getLineContext(sourceFile, line), + }); + } else { + // Value import — could be a class, enum, or constant + // Record the import itself + if (!sdkDep.types[importName]) { + sdkDep.types[importName] = {imports: []}; + } + sdkDep.types[importName].imports.push({ + file: relPath, + line, + context: getLineContext(sourceFile, line), + }); + + // Now find all usages of this imported symbol in the file + const localName = alias; + + // Find method calls: localName.methodName() or localName() + const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression); + for (const call of callExpressions) { + const callText = call.getExpression().getText(); + + // Match: instance.method() patterns + if (callText.startsWith(localName + '.')) { + const methodName = callText.replace(localName + '.', '').split('(')[0]; + const qualifiedName = `${importName}.${methodName}`; + const callLine = call.getStartLineNumber(); + + if (!sdkDep.methods[qualifiedName]) { + sdkDep.methods[qualifiedName] = {usages: []}; + } + sdkDep.methods[qualifiedName].usages.push({ + file: relPath, + line: callLine, + context: getLineContext(sourceFile, callLine), + }); + } + } + + // Find event listener registrations: .on('eventName', ...) or .on(ENUM.VALUE, ...) + for (const call of callExpressions) { + const expr = call.getExpression(); + if (!Node.isPropertyAccessExpression(expr)) continue; + const methodName = expr.getName(); + if (methodName !== 'on' && methodName !== 'off' && methodName !== 'once') continue; + + const obj = expr.getExpression().getText(); + if (obj !== localName && !obj.endsWith('.' + localName)) continue; + + const args = call.getArguments(); + if (args.length === 0) continue; + + const firstArg = args[0]; + let eventName: string | null = null; + + if (Node.isStringLiteral(firstArg)) { + eventName = firstArg.getLiteralValue(); + } else { + eventName = firstArg.getText(); + } + + if (eventName) { + const callLine = call.getStartLineNumber(); + if (!sdkDep.events[eventName]) { + sdkDep.events[eventName] = {listeners: []}; + } + sdkDep.events[eventName].listeners.push({ + file: relPath, + line: callLine, + context: getLineContext(sourceFile, callLine), + }); + } + } + } + } + + // Process default import (e.g., import Webex from '@webex/contact-center') + const defaultImport = imp.getDefaultImport(); + if (defaultImport) { + const importName = defaultImport.getText(); + const line = defaultImport.getStartLineNumber(); + + if (!sdkDep.types[importName]) { + sdkDep.types[importName] = {imports: []}; + } + sdkDep.types[importName].imports.push({ + file: relPath, + line, + context: getLineContext(sourceFile, line), + }); + + // Track method calls on the default import + const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression); + for (const call of callExpressions) { + const callText = call.getExpression().getText(); + if (callText.startsWith(importName + '.')) { + const methodName = callText.replace(importName + '.', '').split('(')[0]; + const callLine = call.getStartLineNumber(); + const qualifiedName = `default.${methodName}`; + + if (!sdkDep.methods[qualifiedName]) { + sdkDep.methods[qualifiedName] = {usages: []}; + } + sdkDep.methods[qualifiedName].usages.push({ + file: relPath, + line: callLine, + context: getLineContext(sourceFile, callLine), + }); + } + } + } + } + } + + // Clean up empty entries + for (const sdk of TRACKED_SDKS) { + const dep = depMap.dependencies[sdk]; + for (const [key, val] of Object.entries(dep.methods)) { + if (val.usages.length === 0) delete dep.methods[key]; + } + for (const [key, val] of Object.entries(dep.events)) { + if (val.listeners.length === 0) delete dep.events[key]; + } + for (const [key, val] of Object.entries(dep.types)) { + if (val.imports.length === 0) delete dep.types[key]; + } + } + + // Write YAML + const yamlContent = yaml.dump(depMap, { + lineWidth: 120, + noRefs: true, + sortKeys: false, + quotingType: '"', + forceQuotes: false, + }); + + fs.writeFileSync(OUTPUT_FILE, yamlContent, 'utf8'); + + // Summary + for (const [sdk, dep] of Object.entries(depMap.dependencies)) { + const methodCount = Object.keys(dep.methods).length; + const eventCount = Object.keys(dep.events).length; + const typeCount = Object.keys(dep.types).length; + const totalUsages = Object.values(dep.methods).reduce((s, m) => s + m.usages.length, 0) + + Object.values(dep.events).reduce((s, e) => s + e.listeners.length, 0) + + Object.values(dep.types).reduce((s, t) => s + t.imports.length, 0); + + console.log(`\n${sdk} (v${dep.version}):`); + console.log(` Methods: ${methodCount} (${Object.values(dep.methods).reduce((s, m) => s + m.usages.length, 0)} call sites)`); + console.log(` Events: ${eventCount} (${Object.values(dep.events).reduce((s, e) => s + e.listeners.length, 0)} listeners)`); + console.log(` Types: ${typeCount} (${Object.values(dep.types).reduce((s, t) => s + t.imports.length, 0)} imports)`); + console.log(` Total usages: ${totalUsages}`); + } + + console.log(`\nDependency map written: ${OUTPUT_FILE}`); +} + +generate(); diff --git a/scripts/tsconfig.json b/scripts/tsconfig.json new file mode 100644 index 000000000..524229d59 --- /dev/null +++ b/scripts/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "moduleResolution": "node", + "esModuleInterop": true, + "skipLibCheck": true, + "types": ["node"] + }, + "include": ["*.ts"] +} diff --git a/sdk-dependencies.yaml b/sdk-dependencies.yaml new file mode 100644 index 000000000..c5c1d2181 --- /dev/null +++ b/sdk-dependencies.yaml @@ -0,0 +1,168 @@ +generated_at: "2026-03-24T12:26:12.244Z" +generator: generate-sdk-deps.ts v1.0 +dependencies: + "@webex/contact-center": + version: workspace + manifest_hash: 2cee4d4a + methods: + default.init: + usages: + - file: packages/contact-center/store/src/store.ts + line: 141 + context: const webex = Webex.init({ + events: {} + types: + LogoutSuccess: + imports: + - file: packages/contact-center/station-login/src/helper.ts + line: 2 + context: import {LogoutSuccess, AgentProfileUpdate, LoginOption, StationLoginSuccessResponse} from '@webex/co + - file: packages/contact-center/cc-components/src/components/StationLogin/station-login.types.ts + line: 1 + context: import {StationLoginSuccessResponse, LogoutSuccess} from '@webex/contact-center'; + AgentProfileUpdate: + imports: + - file: packages/contact-center/station-login/src/helper.ts + line: 2 + context: import {LogoutSuccess, AgentProfileUpdate, LoginOption, StationLoginSuccessResponse} from '@webex/co + LoginOption: + imports: + - file: packages/contact-center/station-login/src/helper.ts + line: 2 + context: import {LogoutSuccess, AgentProfileUpdate, LoginOption, StationLoginSuccessResponse} from '@webex/co + StationLoginSuccessResponse: + imports: + - file: packages/contact-center/station-login/src/helper.ts + line: 2 + context: import {LogoutSuccess, AgentProfileUpdate, LoginOption, StationLoginSuccessResponse} from '@webex/co + - file: packages/contact-center/cc-components/src/components/StationLogin/station-login.types.ts + line: 1 + context: import {StationLoginSuccessResponse, LogoutSuccess} from '@webex/contact-center'; + ITask: + imports: + - file: packages/contact-center/store/src/store.ts + line: 2 + context: import Webex, {ITask} from '@webex/contact-center'; + - file: packages/contact-center/store/src/store.types.ts + line: 6 + context: ITask, + - file: packages/contact-center/task/src/helper.ts + line: 2 + context: import {AddressBookEntriesResponse, AddressBookEntrySearchParams, ITask} from '@webex/contact-center + - file: packages/contact-center/task/src/Utils/task-util.ts + line: 13 + context: import {ITask, Interaction} from '@webex/contact-center'; + Webex: + imports: + - file: packages/contact-center/store/src/store.ts + line: 2 + context: import Webex, {ITask} from '@webex/contact-center'; + AgentLogin: + imports: + - file: packages/contact-center/store/src/store.types.ts + line: 2 + context: AgentLogin, + Profile: + imports: + - file: packages/contact-center/store/src/store.types.ts + line: 3 + context: Profile, + BuddyDetails: + imports: + - file: packages/contact-center/store/src/store.types.ts + line: 4 + context: BuddyDetails, + ContactServiceQueue: + imports: + - file: packages/contact-center/store/src/store.types.ts + line: 5 + context: ContactServiceQueue, + BuddyAgents: + imports: + - file: packages/contact-center/store/src/store.types.ts + line: 7 + context: BuddyAgents, + BuddyAgentsResponse: + imports: + - file: packages/contact-center/store/src/store.types.ts + line: 8 + context: BuddyAgentsResponse, + StateChange: + imports: + - file: packages/contact-center/store/src/store.types.ts + line: 9 + context: StateChange, + Logout: + imports: + - file: packages/contact-center/store/src/store.types.ts + line: 10 + context: Logout, + EntryPointRecord: + imports: + - file: packages/contact-center/store/src/store.types.ts + line: 11 + context: EntryPointRecord, + EntryPointListResponse: + imports: + - file: packages/contact-center/store/src/store.types.ts + line: 12 + context: EntryPointListResponse, + EntryPointSearchParams: + imports: + - file: packages/contact-center/store/src/store.types.ts + line: 13 + context: EntryPointSearchParams, + AddressBookEntry: + imports: + - file: packages/contact-center/store/src/store.types.ts + line: 14 + context: AddressBookEntry, + - file: packages/contact-center/cc-components/src/components/task/OutdialCall/outdial-call.tsx + line: 4 + context: import {AddressBookEntry} from '@webex/contact-center'; + AddressBookEntriesResponse: + imports: + - file: packages/contact-center/store/src/store.types.ts + line: 15 + context: AddressBookEntriesResponse, + - file: packages/contact-center/task/src/helper.ts + line: 2 + context: import {AddressBookEntriesResponse, AddressBookEntrySearchParams, ITask} from '@webex/contact-center + AddressBookEntrySearchParams: + imports: + - file: packages/contact-center/store/src/store.types.ts + line: 16 + context: AddressBookEntrySearchParams, + - file: packages/contact-center/task/src/helper.ts + line: 2 + context: import {AddressBookEntriesResponse, AddressBookEntrySearchParams, ITask} from '@webex/contact-center + ContactServiceQueuesResponse: + imports: + - file: packages/contact-center/store/src/store.types.ts + line: 17 + context: ContactServiceQueuesResponse, + ContactServiceQueueSearchParams: + imports: + - file: packages/contact-center/store/src/store.types.ts + line: 18 + context: ContactServiceQueueSearchParams, + AddressBook: + imports: + - file: packages/contact-center/store/src/store.types.ts + line: 19 + context: AddressBook, + OutdialAniEntriesResponse: + imports: + - file: packages/contact-center/task/src/helper.ts + line: 25 + context: import {OutdialAniEntriesResponse} from '@webex/contact-center/dist/types/services/config/types'; + Interaction: + imports: + - file: packages/contact-center/task/src/Utils/task-util.ts + line: 13 + context: import {ITask, Interaction} from '@webex/contact-center'; + Team: + imports: + - file: packages/contact-center/cc-components/src/components/StationLogin/station-login.types.ts + line: 5 + context: import {Team} from '@webex/contact-center/dist/types/types'; diff --git a/yarn.lock b/yarn.lock index f6c2d52f0..cc43e0fcb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2700,6 +2700,15 @@ __metadata: languageName: node linkType: hard +"@cspotcode/source-map-support@npm:^0.8.0": + version: 0.8.1 + resolution: "@cspotcode/source-map-support@npm:0.8.1" + dependencies: + "@jridgewell/trace-mapping": "npm:0.3.9" + checksum: 10c0/05c5368c13b662ee4c122c7bfbe5dc0b613416672a829f3e78bc49a357a197e0218d6e74e7c66cfcd04e15a179acab080bd3c69658c9fbefd0e1ccd950a07fc6 + languageName: node + linkType: hard + "@dabh/diagnostics@npm:^2.0.2": version: 2.0.3 resolution: "@dabh/diagnostics@npm:2.0.3" @@ -3466,7 +3475,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/resolve-uri@npm:^3.1.0": +"@jridgewell/resolve-uri@npm:^3.0.3, @jridgewell/resolve-uri@npm:^3.1.0": version: 3.1.2 resolution: "@jridgewell/resolve-uri@npm:3.1.2" checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e @@ -3497,6 +3506,16 @@ __metadata: languageName: node linkType: hard +"@jridgewell/trace-mapping@npm:0.3.9": + version: 0.3.9 + resolution: "@jridgewell/trace-mapping@npm:0.3.9" + dependencies: + "@jridgewell/resolve-uri": "npm:^3.0.3" + "@jridgewell/sourcemap-codec": "npm:^1.4.10" + checksum: 10c0/fa425b606d7c7ee5bfa6a31a7b050dd5814b4082f318e0e4190f991902181b4330f43f4805db1dd4f2433fd0ed9cc7a7b9c2683f1deeab1df1b0a98b1e24055b + languageName: node + linkType: hard + "@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.18, @jridgewell/trace-mapping@npm:^0.3.20, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": version: 0.3.25 resolution: "@jridgewell/trace-mapping@npm:0.3.25" @@ -7603,6 +7622,45 @@ __metadata: languageName: node linkType: hard +"@ts-morph/common@npm:~0.28.1": + version: 0.28.1 + resolution: "@ts-morph/common@npm:0.28.1" + dependencies: + minimatch: "npm:^10.0.1" + path-browserify: "npm:^1.0.1" + tinyglobby: "npm:^0.2.14" + checksum: 10c0/d51276d840997e0f8f83e04f8b1689135bb12588a7ddbed575f87848d5737eeae31e242685d6449de27573e8ed30892157fea643393cb875e175f2711200bc50 + languageName: node + linkType: hard + +"@tsconfig/node10@npm:^1.0.7": + version: 1.0.12 + resolution: "@tsconfig/node10@npm:1.0.12" + checksum: 10c0/7bbbd7408cfaced86387a9b1b71cebc91c6fd701a120369735734da8eab1a4773fc079abd9f40c9e0b049e12586c8ac0e13f0da596bfd455b9b4c3faa813ebc5 + languageName: node + linkType: hard + +"@tsconfig/node12@npm:^1.0.7": + version: 1.0.11 + resolution: "@tsconfig/node12@npm:1.0.11" + checksum: 10c0/dddca2b553e2bee1308a056705103fc8304e42bb2d2cbd797b84403a223b25c78f2c683ec3e24a095e82cd435387c877239bffcb15a590ba817cd3f6b9a99fd9 + languageName: node + linkType: hard + +"@tsconfig/node14@npm:^1.0.0": + version: 1.0.3 + resolution: "@tsconfig/node14@npm:1.0.3" + checksum: 10c0/67c1316d065fdaa32525bc9449ff82c197c4c19092b9663b23213c8cbbf8d88b6ed6a17898e0cbc2711950fbfaf40388938c1c748a2ee89f7234fc9e7fe2bf44 + languageName: node + linkType: hard + +"@tsconfig/node16@npm:^1.0.2": + version: 1.0.4 + resolution: "@tsconfig/node16@npm:1.0.4" + checksum: 10c0/05f8f2734e266fb1839eb1d57290df1664fe2aa3b0fdd685a9035806daa635f7519bf6d5d9b33f6e69dd545b8c46bd6e2b5c79acb2b1f146e885f7f11a42a5bb + languageName: node + linkType: hard + "@tufjs/canonical-json@npm:2.0.0": version: 2.0.0 resolution: "@tufjs/canonical-json@npm:2.0.0" @@ -7984,6 +8042,13 @@ __metadata: languageName: node linkType: hard +"@types/js-yaml@npm:^4.0.9": + version: 4.0.9 + resolution: "@types/js-yaml@npm:4.0.9" + checksum: 10c0/24de857aa8d61526bbfbbaa383aa538283ad17363fcd5bb5148e2c7f604547db36646440e739d78241ed008702a8920665d1add5618687b6743858fae00da211 + languageName: node + linkType: hard + "@types/jsdom@npm:^20.0.0": version: 20.0.1 resolution: "@types/jsdom@npm:20.0.1" @@ -8180,6 +8245,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:^25.5.0": + version: 25.5.0 + resolution: "@types/node@npm:25.5.0" + dependencies: + undici-types: "npm:~7.18.0" + checksum: 10c0/70c508165b6758c4f88d4f91abca526c3985eee1985503d4c2bd994dbaf588e52ac57e571160f18f117d76e963570ac82bd20e743c18987e82564312b3b62119 + languageName: node + linkType: hard + "@types/normalize-package-data@npm:^2.4.0, @types/normalize-package-data@npm:^2.4.3": version: 2.4.4 resolution: "@types/normalize-package-data@npm:2.4.4" @@ -13003,6 +13077,15 @@ __metadata: languageName: node linkType: hard +"acorn-walk@npm:^8.1.1": + version: 8.3.5 + resolution: "acorn-walk@npm:8.3.5" + dependencies: + acorn: "npm:^8.11.0" + checksum: 10c0/e31bf5b5423ed1349437029d66d708b9fbd1b77a644b031501e2c753b028d13b56348210ed901d5b1d0d86eb3381c0a0fc0d0998511a9d546d1194936266a332 + languageName: node + linkType: hard + "acorn@npm:^6.4.1": version: 6.4.2 resolution: "acorn@npm:6.4.2" @@ -13039,6 +13122,15 @@ __metadata: languageName: node linkType: hard +"acorn@npm:^8.4.1": + version: 8.16.0 + resolution: "acorn@npm:8.16.0" + bin: + acorn: bin/acorn + checksum: 10c0/c9c52697227661b68d0debaf972222d4f622aa06b185824164e153438afa7b08273432ca43ea792cadb24dada1d46f6f6bb1ef8de9956979288cc1b96bf9914e + languageName: node + linkType: hard + "adaptive-expressions@npm:^4.15.0": version: 4.23.1 resolution: "adaptive-expressions@npm:4.23.1" @@ -13522,6 +13614,13 @@ __metadata: languageName: node linkType: hard +"arg@npm:^4.1.0": + version: 4.1.3 + resolution: "arg@npm:4.1.3" + checksum: 10c0/070ff801a9d236a6caa647507bdcc7034530604844d64408149a26b9e87c2f97650055c0f049abd1efc024b334635c01f29e0b632b371ac3f26130f4cf65997a + languageName: node + linkType: hard + "argparse@npm:^1.0.7": version: 1.0.10 resolution: "argparse@npm:1.0.10" @@ -14329,6 +14428,13 @@ __metadata: languageName: node linkType: hard +"balanced-match@npm:^4.0.2": + version: 4.0.4 + resolution: "balanced-match@npm:4.0.4" + checksum: 10c0/07e86102a3eb2ee2a6a1a89164f29d0dbaebd28f2ca3f5ca786f36b8b23d9e417eb3be45a4acf754f837be5ac0a2317de90d3fcb7f4f4dc95720a1f36b26a17b + languageName: node + linkType: hard + "bare-events@npm:^2.2.0": version: 2.5.0 resolution: "bare-events@npm:2.5.0" @@ -14572,6 +14678,15 @@ __metadata: languageName: node linkType: hard +"brace-expansion@npm:^5.0.2": + version: 5.0.4 + resolution: "brace-expansion@npm:5.0.4" + dependencies: + balanced-match: "npm:^4.0.2" + checksum: 10c0/359cbcfa80b2eb914ca1f3440e92313fbfe7919ee6b274c35db55bec555aded69dac5ee78f102cec90c35f98c20fa43d10936d0cd9978158823c249257e1643a + languageName: node + linkType: hard + "braces@npm:^2.3.1, braces@npm:^2.3.2": version: 2.3.2 resolution: "braces@npm:2.3.2" @@ -15788,6 +15903,13 @@ __metadata: languageName: node linkType: hard +"code-block-writer@npm:^13.0.3": + version: 13.0.3 + resolution: "code-block-writer@npm:13.0.3" + checksum: 10c0/87db97b37583f71cfd7eced8bf3f0a0a0ca53af912751a734372b36c08cd27f3e8a4878ec05591c0cd9ae11bea8add1423e132d660edd86aab952656dd41fd66 + languageName: node + linkType: hard + "collapse-white-space@npm:^1.0.2": version: 1.0.6 resolution: "collapse-white-space@npm:1.0.6" @@ -16574,6 +16696,13 @@ __metadata: languageName: node linkType: hard +"create-require@npm:^1.1.0": + version: 1.1.1 + resolution: "create-require@npm:1.1.1" + checksum: 10c0/157cbc59b2430ae9a90034a5f3a1b398b6738bf510f713edc4d4e45e169bc514d3d99dd34d8d01ca7ae7830b5b8b537e46ae8f3c8f932371b0875c0151d7ec91 + languageName: node + linkType: hard + "cross-fetch@npm:3.1.5": version: 3.1.5 resolution: "cross-fetch@npm:3.1.5" @@ -17660,6 +17789,13 @@ __metadata: languageName: node linkType: hard +"diff@npm:^4.0.1": + version: 4.0.4 + resolution: "diff@npm:4.0.4" + checksum: 10c0/855fb70b093d1d9643ddc12ea76dca90dc9d9cdd7f82c08ee8b9325c0dc5748faf3c82e2047ced5dcaa8b26e58f7903900be2628d0380a222c02d79d8de385df + languageName: node + linkType: hard + "diff@npm:^5.0.0, diff@npm:^5.1.0": version: 5.2.0 resolution: "diff@npm:5.2.0" @@ -19822,6 +19958,18 @@ __metadata: languageName: node linkType: hard +"fdir@npm:^6.5.0": + version: 6.5.0 + resolution: "fdir@npm:6.5.0" + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + checksum: 10c0/e345083c4306b3aed6cb8ec551e26c36bab5c511e99ea4576a16750ddc8d3240e63826cc624f5ae17ad4dc82e68a253213b60d556c11bfad064b7607847ed07f + languageName: node + linkType: hard + "fecha@npm:^4.2.0": version: 4.2.3 resolution: "fecha@npm:4.2.3" @@ -24296,6 +24444,17 @@ __metadata: languageName: node linkType: hard +"js-yaml@npm:^4.1.1": + version: 4.1.1 + resolution: "js-yaml@npm:4.1.1" + dependencies: + argparse: "npm:^2.0.1" + bin: + js-yaml: bin/js-yaml.js + checksum: 10c0/561c7d7088c40a9bb53cc75becbfb1df6ae49b34b5e6e5a81744b14ae8667ec564ad2527709d1a6e7d5e5fa6d483aa0f373a50ad98d42fde368ec4a190d4fae7 + languageName: node + linkType: hard + "jsbn@npm:1.1.0": version: 1.1.0 resolution: "jsbn@npm:1.1.0" @@ -25687,7 +25846,7 @@ __metadata: languageName: node linkType: hard -"make-error@npm:1.x, make-error@npm:^1.3.6": +"make-error@npm:1.x, make-error@npm:^1.1.1, make-error@npm:^1.3.6": version: 1.3.6 resolution: "make-error@npm:1.3.6" checksum: 10c0/171e458d86854c6b3fc46610cfacf0b45149ba043782558c6875d9f42f222124384ad0b468c92e996d815a8a2003817a710c0a160e49c1c394626f76fa45396f @@ -26296,6 +26455,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:^10.0.1": + version: 10.2.4 + resolution: "minimatch@npm:10.2.4" + dependencies: + brace-expansion: "npm:^5.0.2" + checksum: 10c0/35f3dfb7b99b51efd46afd378486889f590e7efb10e0f6a10ba6800428cf65c9a8dedb74427d0570b318d749b543dc4e85f06d46d2858bc8cac7e1eb49a95945 + languageName: node + linkType: hard + "minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" @@ -28452,6 +28620,13 @@ __metadata: languageName: node linkType: hard +"path-browserify@npm:^1.0.1": + version: 1.0.1 + resolution: "path-browserify@npm:1.0.1" + checksum: 10c0/8b8c3fd5c66bd340272180590ae4ff139769e9ab79522e2eb82e3d571a89b8117c04147f65ad066dccfb42fcad902e5b7d794b3d35e0fd840491a8ddbedf8c66 + languageName: node + linkType: hard + "path-dirname@npm:^1.0.0": version: 1.0.2 resolution: "path-dirname@npm:1.0.2" @@ -28661,6 +28836,13 @@ __metadata: languageName: node linkType: hard +"picomatch@npm:^4.0.3": + version: 4.0.4 + resolution: "picomatch@npm:4.0.4" + checksum: 10c0/e2c6023372cc7b5764719a5ffb9da0f8e781212fa7ca4bd0562db929df8e117460f00dff3cb7509dacfc06b86de924b247f504d0ce1806a37fac4633081466b0 + languageName: node + linkType: hard + "pid-port@npm:^0.1.0": version: 0.1.1 resolution: "pid-port@npm:0.1.1" @@ -33707,6 +33889,16 @@ __metadata: languageName: node linkType: hard +"tinyglobby@npm:^0.2.14": + version: 0.2.15 + resolution: "tinyglobby@npm:0.2.15" + dependencies: + fdir: "npm:^6.5.0" + picomatch: "npm:^4.0.3" + checksum: 10c0/869c31490d0d88eedb8305d178d4c75e7463e820df5a9b9d388291daf93e8b1eb5de1dad1c1e139767e4269fe75f3b10d5009b2cc14db96ff98986920a186844 + languageName: node + linkType: hard + "tippy.js@npm:^6.3.1": version: 6.3.7 resolution: "tippy.js@npm:6.3.7" @@ -34020,6 +34212,54 @@ __metadata: languageName: node linkType: hard +"ts-morph@npm:^27.0.2": + version: 27.0.2 + resolution: "ts-morph@npm:27.0.2" + dependencies: + "@ts-morph/common": "npm:~0.28.1" + code-block-writer: "npm:^13.0.3" + checksum: 10c0/224715cc6d97b8ff5afd3986f9629f912a0ebd83eaecbdca91c35cf10a98f607c663f666e7ea5e6afab00563d00dc80fa7a13552cc7f1cef735261c3217d0863 + languageName: node + linkType: hard + +"ts-node@npm:^10.9.2": + version: 10.9.2 + resolution: "ts-node@npm:10.9.2" + dependencies: + "@cspotcode/source-map-support": "npm:^0.8.0" + "@tsconfig/node10": "npm:^1.0.7" + "@tsconfig/node12": "npm:^1.0.7" + "@tsconfig/node14": "npm:^1.0.0" + "@tsconfig/node16": "npm:^1.0.2" + acorn: "npm:^8.4.1" + acorn-walk: "npm:^8.1.1" + arg: "npm:^4.1.0" + create-require: "npm:^1.1.0" + diff: "npm:^4.0.1" + make-error: "npm:^1.1.1" + v8-compile-cache-lib: "npm:^3.0.1" + yn: "npm:3.1.1" + peerDependencies: + "@swc/core": ">=1.2.50" + "@swc/wasm": ">=1.2.50" + "@types/node": "*" + typescript: ">=2.7" + peerDependenciesMeta: + "@swc/core": + optional: true + "@swc/wasm": + optional: true + bin: + ts-node: dist/bin.js + ts-node-cwd: dist/bin-cwd.js + ts-node-esm: dist/bin-esm.js + ts-node-script: dist/bin-script.js + ts-node-transpile-only: dist/bin-transpile.js + ts-script: dist/bin-script-deprecated.js + checksum: 10c0/5f29938489f96982a25ba650b64218e83a3357d76f7bede80195c65ab44ad279c8357264639b7abdd5d7e75fc269a83daa0e9c62fd8637a3def67254ecc9ddc2 + languageName: node + linkType: hard + "tsconfig-paths@npm:^3.15.0": version: 3.15.0 resolution: "tsconfig-paths@npm:3.15.0" @@ -34509,6 +34749,13 @@ __metadata: languageName: node linkType: hard +"undici-types@npm:~7.18.0": + version: 7.18.2 + resolution: "undici-types@npm:7.18.2" + checksum: 10c0/85a79189113a238959d7a647368e4f7c5559c3a404ebdb8fc4488145ce9426fcd82252a844a302798dfc0e37e6fb178ff481ed03bc4caf634c5757d9ef43521d + languageName: node + linkType: hard + "unfetch@npm:^4.2.0": version: 4.2.0 resolution: "unfetch@npm:4.2.0" @@ -35091,6 +35338,13 @@ __metadata: languageName: node linkType: hard +"v8-compile-cache-lib@npm:^3.0.1": + version: 3.0.1 + resolution: "v8-compile-cache-lib@npm:3.0.1" + checksum: 10c0/bdc36fb8095d3b41df197f5fb6f11e3a26adf4059df3213e3baa93810d8f0cc76f9a74aaefc18b73e91fe7e19154ed6f134eda6fded2e0f1c8d2272ed2d2d391 + languageName: node + linkType: hard + "v8-compile-cache@npm:^2.0.3": version: 2.4.0 resolution: "v8-compile-cache@npm:2.4.0" @@ -35395,6 +35649,8 @@ __metadata: "@semantic-release/git": "npm:^10.0.1" "@semantic-release/github": "npm:^11.0.1" "@testing-library/react-hooks": "npm:^8.0.1" + "@types/js-yaml": "npm:^4.0.9" + "@types/node": "npm:^25.5.0" "@webex/cli-tools": "npm:0.0.0-next.2" "@webex/package-tools": "npm:0.0.0-next.6" babel-jest: "npm:^29.7.0" @@ -35405,6 +35661,7 @@ __metadata: husky: "npm:^9.1.7" jest: "npm:29.7.0" jest-canvas-mock: "npm:^2.5.2" + js-yaml: "npm:^4.1.1" node-gyp: "npm:^10.2.0" nodemailer: "npm:^7.0.3" os-browserify: "npm:^0.3.0" @@ -35415,6 +35672,8 @@ __metadata: semantic-release: "npm:^24.2.0" stream-browserify: "npm:^3.0.0" style-loader: "npm:^4.0.0" + ts-morph: "npm:^27.0.2" + ts-node: "npm:^10.9.2" typescript: "npm:^5.6.3" vm-browserify: "npm:^1.1.2" webpack: "npm:^5.96.1" @@ -36538,6 +36797,13 @@ __metadata: languageName: node linkType: hard +"yn@npm:3.1.1": + version: 3.1.1 + resolution: "yn@npm:3.1.1" + checksum: 10c0/0732468dd7622ed8a274f640f191f3eaf1f39d5349a1b72836df484998d7d9807fbea094e2f5486d6b0cd2414aad5775972df0e68f8604db89a239f0f4bf7443 + languageName: node + linkType: hard + "yocto-queue@npm:^0.1.0": version: 0.1.0 resolution: "yocto-queue@npm:0.1.0" From ca127a0b12dfafe9613069d1916320a2ef1199c0 Mon Sep 17 00:00:00 2001 From: Rankush Kumar Date: Thu, 26 Mar 2026 14:13:53 +0530 Subject: [PATCH 4/6] docs: add SDK sync section to AGENTS.md Add usage instructions for SDK dependency tracking and /sync-sdk skill, including mandatory API verification steps for AI agents. Co-Authored-By: Claude Opus 4.6 (1M context) --- AGENTS.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 70963b493..8ebb32378 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -609,6 +609,34 @@ ccWidgets/ --- +## SDK Sync (Cross-Repo Dependency Tracking) + +This repo tracks all `@webex/contact-center` SDK API usages via `sdk-dependencies.yaml`. +When the SDK changes, run `/sync-sdk` to see which files are affected. + +### When to run +- After bumping SDK version in `package.json` +- After the SDK team notifies of API changes +- Before starting work that depends on SDK APIs + +### How to run +```bash +npm run generate:sdk-deps +``` +Or use the Claude Code skill: `/sync-sdk` + +### What it produces +`sdk-dependencies.yaml` — maps each SDK import to exact file + line number. + +### SDK API Verification (MANDATORY for AI agents) +Before generating code that calls `@webex/contact-center`: +1. Read the SDK manifest: `node_modules/@webex/contact-center/sdk-manifest.yaml` +2. Verify the method signature matches what you're about to write +3. Check `sdk-dependencies.yaml` for existing usage patterns +4. NEVER assume SDK method signatures from memory — always verify + +--- + ## Related Documentation - **Repository Rules:** [RULES.md](./RULES.md) From a0c204110057b7d2a70b34583208cee5d8ddae45 Mon Sep 17 00:00:00 2001 From: Rankush Kumar Date: Thu, 26 Mar 2026 14:24:00 +0530 Subject: [PATCH 5/6] chore: gitignore .sdk-cache/ and remove from tracking The .sdk-cache/ directory is a local dev cache for SDK manifest diffing. Each developer's cache reflects when they last ran /sync-sdk. It should not be committed. Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitignore | 3 + .../@webex/contact-center.manifest.yaml | 1959 ----------------- 2 files changed, 3 insertions(+), 1959 deletions(-) delete mode 100644 .sdk-cache/@webex/contact-center.manifest.yaml diff --git a/.gitignore b/.gitignore index 5f35c58cb..452996168 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,9 @@ node_modules/ .yarn/* !.yarn/releases +# SDK sync cache (local dev only) +.sdk-cache/ + # Playwright reports **/test-results/ **/playwright-report diff --git a/.sdk-cache/@webex/contact-center.manifest.yaml b/.sdk-cache/@webex/contact-center.manifest.yaml deleted file mode 100644 index ae9c9ccae..000000000 --- a/.sdk-cache/@webex/contact-center.manifest.yaml +++ /dev/null @@ -1,1959 +0,0 @@ -name: "@webex/contact-center" -version: workspace -generated_at: "2026-03-24T11:15:48.070Z" -generator: generate-manifest.ts v1.0 -classes: - ContactCenter: - source: src/cc.ts - extends: WebexPlugin - methods: - register: - params: [] - returns: Promise - events_on_success: [] - events_on_failure: [] - deregister: - params: [] - returns: Promise - events_on_success: [] - events_on_failure: [] - getBuddyAgents: - params: - - name: data - type: BuddyAgents - required: true - returns: Promise - events_on_success: [] - events_on_failure: [] - stationLogin: - params: - - name: data - type: AgentLogin - required: true - returns: Promise - events_on_success: [] - events_on_failure: [] - stationLogout: - params: - - name: data - type: Logout - required: true - returns: Promise - events_on_success: [] - events_on_failure: [] - setAgentState: - params: - - name: data - type: StateChange - required: true - returns: Promise - events_on_success: [] - events_on_failure: [] - startOutdial: - params: - - name: destination - type: string - required: true - - name: origin - type: string - required: true - returns: Promise - events_on_success: [] - events_on_failure: [] - getOutdialAniEntries: - params: - - name: params - type: OutdialAniParams - required: true - returns: Promise - events_on_success: [] - events_on_failure: [] - uploadLogs: - params: [] - returns: Promise - events_on_success: [] - events_on_failure: [] - updateAgentProfile: - params: - - name: data - type: AgentProfileUpdate - required: true - returns: Promise - events_on_success: [] - events_on_failure: [] - getEntryPoints: - params: - - name: params - type: src/utils/PageCache:BaseSearchParams - required: false - returns: Promise - events_on_success: [] - events_on_failure: [] - getQueues: - params: - - name: params - type: ContactServiceQueueSearchParams - required: false - returns: Promise - events_on_success: [] - events_on_failure: [] - Task: - source: src/services/task/Task.ts - extends: EventEmitter - methods: - accept: - params: [] - returns: Promise - events_on_success: [] - events_on_failure: [] - decline: - params: [] - returns: Promise - events_on_success: [] - events_on_failure: [] - pauseRecording: - params: [] - returns: Promise - events_on_success: [] - events_on_failure: [] - resumeRecording: - params: - - name: resumeRecordingPayload - type: ResumeRecordingPayload - required: true - returns: Promise - events_on_success: [] - events_on_failure: [] - consult: - params: - - name: consultPayload - type: ConsultPayload - required: true - returns: Promise - events_on_success: [] - events_on_failure: [] - endConsult: - params: - - name: consultEndPayload - type: ConsultEndPayload - required: true - returns: Promise - events_on_success: [] - events_on_failure: [] - consultTransfer: - params: - - name: consultTransferPayload - type: ConsultTransferPayLoad - required: false - returns: Promise - events_on_success: [] - events_on_failure: [] - consultConference: - params: [] - returns: Promise - events_on_success: [] - events_on_failure: [] - exitConference: - params: [] - returns: Promise - events_on_success: [] - events_on_failure: [] - transferConference: - params: [] - returns: Promise - events_on_success: [] - events_on_failure: [] - switchCall: - params: [] - returns: Promise - events_on_success: [] - events_on_failure: [] - toggleMute: - params: [] - returns: Promise - events_on_success: [] - events_on_failure: [] - startTranscription: - params: [] - returns: Promise - events_on_success: - - task:transcriptionStarted - events_on_failure: - - task:transcriptionFailed - stopTranscription: - params: [] - returns: Promise - events_on_success: - - task:transcriptionStopped - events_on_failure: [] - unregisterWebCallListeners: - params: [] - returns: void - events_on_success: [] - events_on_failure: [] - cancelAutoWrapupTimer: - params: [] - returns: void - events_on_success: [] - events_on_failure: [] - hold: - params: [] - returns: Promise - events_on_success: [] - events_on_failure: [] - resume: - params: [] - returns: Promise - events_on_success: [] - events_on_failure: [] - holdResume: - params: [] - returns: Promise - events_on_success: [] - events_on_failure: [] - sendStateMachineEvent: - params: - - name: event - type: TaskEventPayload - required: true - returns: void - events_on_success: [] - events_on_failure: [] - updateTaskData: - params: - - name: updatedData - type: TaskData - required: true - - name: shouldOverwrite - type: boolean - required: false - returns: ITask - events_on_success: [] - events_on_failure: [] - transfer: - params: - - name: transferPayload - type: TransferPayLoad - required: true - returns: Promise - events_on_success: [] - events_on_failure: [] - end: - params: [] - returns: Promise - events_on_success: [] - events_on_failure: [] - wrapup: - params: - - name: wrapupPayload - type: WrapupPayLoad - required: true - returns: Promise - events_on_success: [] - events_on_failure: [] - AddressBook: - source: src/services/AddressBook.ts - extends: null - methods: - getEntries: - params: - - name: params - type: AddressBookEntrySearchParams - required: false - returns: Promise - events_on_success: [] - events_on_failure: [] -events: - TASK_EVENTS: - TASK_INCOMING: task:incoming - TASK_ASSIGNED: task:assigned - TASK_MEDIA: task:media - TASK_UNASSIGNED: task:unassigned - TASK_HOLD: task:hold - TASK_RESUME: task:resume - TASK_CONSULT_END: task:consultEnd - TASK_CONSULT_QUEUE_CANCELLED: task:consultQueueCancelled - TASK_CONSULT_QUEUE_FAILED: task:consultQueueFailed - TASK_UI_CONTROLS_UPDATED: task:ui-controls-updated - TASK_CONSULT_ACCEPTED: task:consultAccepted - TASK_CONSULTING: task:consulting - TASK_CONSULT_CREATED: task:consultCreated - TASK_OFFER_CONSULT: task:offerConsult - TASK_END: task:end - TASK_WRAPUP: task:wrapup - TASK_WRAPPEDUP: task:wrappedup - TASK_CLEANUP: task:cleanup - TASK_RECORDING_STARTED: task:recordingStarted - TASK_RECORDING_PAUSED: task:recordingPaused - TASK_RECORDING_PAUSE_FAILED: task:recordingPauseFailed - TASK_RECORDING_RESUMED: task:recordingResumed - TASK_RECORDING_RESUME_FAILED: task:recordingResumeFailed - TASK_REJECT: task:rejected - TASK_OUTDIAL_FAILED: task:outdialFailed - TASK_HYDRATE: task:hydrate - TASK_OFFER_CONTACT: task:offerContact - TASK_AUTO_ANSWERED: task:autoAnswered - TASK_CONFERENCE_ESTABLISHING: task:conferenceEstablishing - TASK_CONFERENCE_STARTED: task:conferenceStarted - TASK_CONFERENCE_FAILED: task:conferenceFailed - TASK_CONFERENCE_ENDED: task:conferenceEnded - TASK_PARTICIPANT_JOINED: task:participantJoined - TASK_PARTICIPANT_LEFT: task:participantLeft - TASK_CONFERENCE_TRANSFERRED: task:conferenceTransferred - TASK_CONFERENCE_TRANSFER_FAILED: task:conferenceTransferFailed - TASK_CONFERENCE_END_FAILED: task:conferenceEndFailed - TASK_PARTICIPANT_LEFT_FAILED: task:participantLeftFailed - TASK_EXIT_CONFERENCE: task:exitConference - TASK_TRANSFER_CONFERENCE: task:transferConference - TASK_SWITCH_CALL: task:switchCall - TASK_MERGED: task:merged - TASK_POST_CALL_ACTIVITY: task:postCallActivity - TASK_TRANSCRIPTION: task:transcription - TASK_TRANSCRIPTION_STARTED: task:transcriptionStarted - TASK_TRANSCRIPTION_STOPPED: task:transcriptionStopped - TASK_TRANSCRIPTION_FAILED: task:transcriptionFailed - AGENT_EVENTS: - AGENT_STATE_CHANGE: agent:stateChange - AGENT_MULTI_LOGIN: agent:multiLogin - AGENT_STATION_LOGIN_SUCCESS: agent:stationLoginSuccess - AGENT_STATION_LOGIN_FAILED: agent:stationLoginFailed - AGENT_LOGOUT_SUCCESS: agent:logoutSuccess - AGENT_LOGOUT_FAILED: agent:logoutFailed - AGENT_DN_REGISTERED: agent:dnRegistered - AGENT_RELOGIN_SUCCESS: agent:reloginSuccess - AGENT_STATE_CHANGE_SUCCESS: agent:stateChangeSuccess - AGENT_STATE_CHANGE_FAILED: agent:stateChangeFailed -types: - EntryPointRecord: - fields: - - name: id - type: string - required: true - - name: name - type: string - required: true - - name: description - type: string - required: false - - name: type - type: string - required: true - - name: isActive - type: boolean - required: true - - name: orgId - type: string - required: true - - name: createdAt - type: string - required: false - - name: updatedAt - type: string - required: false - - name: settings - type: Record - required: false - EntryPointListResponse: - kind: alias - values: - - PaginatedResponse - EntryPointSearchParams: - kind: alias - values: - - BaseSearchParams - AddressBookEntry: - fields: - - name: id - type: string - required: true - - name: organizationId - type: string - required: false - - name: version - type: number - required: false - - name: name - type: string - required: true - - name: number - type: string - required: true - - name: createdTime - type: number - required: false - - name: lastUpdatedTime - type: number - required: false - AddressBookEntriesResponse: - kind: alias - values: - - PaginatedResponse - AddressBookEntrySearchParams: - fields: - - name: addressBookId - type: string - required: false - ContactServiceQueuesResponse: - kind: alias - values: - - PaginatedResponse - ContactServiceQueueSearchParams: - fields: - - name: desktopProfileFilter - type: boolean - required: false - - name: provisioningView - type: boolean - required: false - - name: singleObjectResponse - type: boolean - required: false - ContactServiceQueue: - fields: - - name: organizationId - type: string - required: false - - name: id - type: string - required: false - - name: version - type: number - required: false - - name: name - type: string - required: true - - name: description - type: string - required: false - - name: queueType - type: "\"INBOUND\" | \"OUTBOUND\"" - required: true - - name: checkAgentAvailability - type: boolean - required: true - - name: channelType - type: "\"TELEPHONY\" | \"EMAIL\" | \"FAX\" | \"CHAT\" | \"VIDEO\" | \"OTHERS\" | \"SOCIAL_CHANNEL\"" - required: true - - name: socialChannelType - type: "\"MESSAGEBIRD\" | \"MESSENGER\" | \"WHATSAPP\" | \"APPLE_BUSINESS_CHAT\" | \"GOOGLE_BUSINESS_MESSAGES\"" - required: false - - name: serviceLevelThreshold - type: number - required: true - - name: maxActiveContacts - type: number - required: true - - name: maxTimeInQueue - type: number - required: true - - name: defaultMusicInQueueMediaFileId - type: string - required: true - - name: timezone - type: string - required: false - - name: active - type: boolean - required: true - - name: outdialCampaignEnabled - type: boolean - required: false - - name: monitoringPermitted - type: boolean - required: true - - name: parkingPermitted - type: boolean - required: true - - name: recordingPermitted - type: boolean - required: true - - name: recordingAllCallsPermitted - type: boolean - required: true - - name: pauseRecordingPermitted - type: boolean - required: true - - name: recordingPauseDuration - type: number - required: false - - name: controlFlowScriptUrl - type: string - required: true - - name: ivrRequeueUrl - type: string - required: true - - name: overflowNumber - type: string - required: false - - name: vendorId - type: string - required: false - - name: routingType - type: "\"LONGEST_AVAILABLE_AGENT\" | \"SKILLS_BASED\" | \"CIRCULAR\" | \"LINEAR\"" - required: true - - name: skillBasedRoutingType - type: "\"LONGEST_AVAILABLE_AGENT\" | \"BEST_AVAILABLE_AGENT\"" - required: false - - name: queueRoutingType - type: "\"TEAM_BASED\" | \"SKILL_BASED\" | \"AGENT_BASED\"" - required: true - - name: queueSkillRequirements - type: QueueSkillRequirement[] - required: false - - name: agents - type: QueueAgent[] - required: false - - name: callDistributionGroups - type: CallDistributionGroup[] - required: true - - name: xspVersion - type: string - required: false - - name: subscriptionId - type: string - required: false - - name: assistantSkill - type: AssistantSkillMapping - required: false - - name: systemDefault - type: boolean - required: false - - name: agentsLastUpdatedByUserName - type: string - required: false - - name: agentsLastUpdatedByUserEmailPrefix - type: string - required: false - - name: agentsLastUpdatedTime - type: number - required: false - - name: createdTime - type: number - required: false - - name: lastUpdatedTime - type: number - required: false - CC_EVENTS: - kind: alias - values: - - >- - "Welcome" | "AgentReloginSuccess" | "AgentReloginFailed" | "AgentDNRegistered" | "Logout" | "AgentLogoutSuccess" - | "AgentLogoutFailed" | "StationLogin" | "AgentStationLoginSuccess" | "AgentStationLoginFailed" | - "AgentStateChange" | "AGENT_MULTI_LOGIN" | "AgentStateChangeSuccess" | "AgentStateChangeFailed" | "BuddyAgents" - | "BuddyAgentsRetrieveFailed" | "AgentContactReserved" | "AgentContactAssignFailed" | "AgentOfferContactRona" | - "AgentContactHeld" | "AgentContactHoldFailed" | "AgentContactUnheld" | "AgentContactUnHoldFailed" | - "AgentConsultCreated" | "AgentOfferConsult" | "AgentConsulting" | "AgentConsultFailed" | "AgentCtqFailed" | - "AgentCtqCancelled" | "AgentCtqCancelFailed" | "AgentConsultEnded" | "AgentConsultEndFailed" | - "AgentConsultConferenceEnded" | "AgentConsultConferencing" | "AgentConsultConferenced" | - "AgentConsultConferenceFailed" | "ParticipantJoinedConference" | "ParticipantLeftConference" | - "ParticipantLeftConferenceFailed" | "AgentConsultConferenceEndFailed" | "AgentConferenceTransferred" | - "AgentConferenceTransferFailed" | "ParticipantPostCallActivity" | "ConsultedParticipantMoving" | - "REAL_TIME_TRANSCRIPTION" | "TranscriptionFailed" | "AgentBlindTransferred" | "AgentBlindTransferFailed" | - "AgentVteamTransferred" | "AgentVteamTransferFailed" | "AgentConsultTransferring" | "AgentConsultTransferred" | - "AgentConsultTransferFailed" | "ContactRecordingPaused" | "ContactRecordingStarted" | - "ContactRecordingPauseFailed" | "ContactRecordingResumed" | "ContactRecordingResumeFailed" | "ContactEnded" | - "ContactMerged" | "ContactUpdated" | "ContactOwnerChanged" | "AgentContactEndFailed" | "AgentWrapup" | - "AgentWrappedUp" | "AgentWrapupFailed" | "AgentOutboundFailed" | "AgentContact" | "AgentOfferContact" | - "AgentContactAssigned" | "AgentContactUnassigned" | "AgentInviteFailed" - ContactCenterEvents: - kind: alias - values: - - >- - "Welcome" | "AgentReloginSuccess" | "AgentReloginFailed" | "AgentDNRegistered" | "Logout" | "AgentLogoutSuccess" - | "AgentLogoutFailed" | "StationLogin" | "AgentStationLoginSuccess" | "AgentStationLoginFailed" | - "AgentStateChange" | "AGENT_MULTI_LOGIN" | "AgentStateChangeSuccess" | "AgentStateChangeFailed" | "BuddyAgents" - | "BuddyAgentsRetrieveFailed" | "AgentContactReserved" | "AgentContactAssignFailed" | "AgentOfferContactRona" | - "AgentContactHeld" | "AgentContactHoldFailed" | "AgentContactUnheld" | "AgentContactUnHoldFailed" | - "AgentConsultCreated" | "AgentOfferConsult" | "AgentConsulting" | "AgentConsultFailed" | "AgentCtqFailed" | - "AgentCtqCancelled" | "AgentCtqCancelFailed" | "AgentConsultEnded" | "AgentConsultEndFailed" | - "AgentConsultConferenceEnded" | "AgentConsultConferencing" | "AgentConsultConferenced" | - "AgentConsultConferenceFailed" | "ParticipantJoinedConference" | "ParticipantLeftConference" | - "ParticipantLeftConferenceFailed" | "AgentConsultConferenceEndFailed" | "AgentConferenceTransferred" | - "AgentConferenceTransferFailed" | "ParticipantPostCallActivity" | "ConsultedParticipantMoving" | - "REAL_TIME_TRANSCRIPTION" | "TranscriptionFailed" | "AgentBlindTransferred" | "AgentBlindTransferFailed" | - "AgentVteamTransferred" | "AgentVteamTransferFailed" | "AgentConsultTransferring" | "AgentConsultTransferred" | - "AgentConsultTransferFailed" | "ContactRecordingPaused" | "ContactRecordingStarted" | - "ContactRecordingPauseFailed" | "ContactRecordingResumed" | "ContactRecordingResumeFailed" | "ContactEnded" | - "ContactMerged" | "ContactUpdated" | "ContactOwnerChanged" | "AgentContactEndFailed" | "AgentWrapup" | - "AgentWrappedUp" | "AgentWrapupFailed" | "AgentOutboundFailed" | "AgentContact" | "AgentOfferContact" | - "AgentContactAssigned" | "AgentContactUnassigned" | "AgentInviteFailed" - IContactCenter: - fields: [] - CCPluginConfig: - fields: - - name: allowMultiLogin - type: boolean - required: true - - name: allowAutomatedRelogin - type: boolean - required: true - - name: clientType - type: string - required: true - - name: isKeepAliveEnabled - type: boolean - required: true - - name: force - type: boolean - required: true - - name: metrics - type: "{ clientName: string; clientType: string; }" - required: true - - name: logging - type: "{ enable: boolean; verboseEvents: boolean; }" - required: true - - name: callingClientConfig - type: CallingClientConfig - required: true - WebexSDK: - fields: - - name: version - type: string - required: true - - name: canAuthorize - type: boolean - required: true - - name: credentials - type: "{ getUserToken: () => Promise; getOrgId: () => string; }" - required: true - - name: ready - type: boolean - required: true - - name: request - type: "(payload: WebexRequestPayload) => Promise" - required: true - - name: once - type: "(event: string, callBack: () => void) => void" - required: true - - name: internal - type: IWebexInternal - required: true - - name: logger - type: Logger - required: true - LoginOption: - kind: alias - values: - - "\"AGENT_DN\" | \"EXTENSION\" | \"BROWSER\"" - AgentLogin: - fields: - - name: dialNumber - type: string - required: false - - name: teamId - type: string - required: true - - name: loginOption - type: LoginOption - required: true - AgentProfileUpdate: - kind: alias - values: - - "{ loginOption: LoginOption; dialNumber?: string; teamId: string; }" - StationLoginResponse: - kind: union - values: - - Agent.StationLoginSuccessResponse - - Error - StationLogoutResponse: - kind: union - values: - - Agent.LogoutSuccess - - Error - BuddyAgentsResponse: - kind: union - values: - - Agent.BuddyAgentsSuccess - - Error - BuddyAgents: - fields: - - name: mediaType - type: "\"telephony\" | \"chat\" | \"social\" | \"email\"" - required: true - - name: state - type: "\"Available\" | \"Idle\"" - required: false - SubscribeRequest: - fields: - - name: force - type: boolean - required: true - - name: isKeepAliveEnabled - type: boolean - required: true - - name: clientType - type: string - required: true - - name: allowMultiLogin - type: boolean - required: true - UploadLogsResponse: - fields: - - name: trackingid - type: string - required: false - - name: url - type: string - required: false - - name: userId - type: string - required: false - - name: feedbackId - type: string - required: false - - name: correlationId - type: string - required: false - UpdateDeviceTypeResponse: - kind: union - values: - - Agent.DeviceTypeUpdateSuccess - - Error - GenericError: - fields: - - name: details - type: "{ type: string; orgId: string; trackingId: string; data: Record; }" - required: true - SetStateResponse: - kind: union - values: - - Agent.StateChangeSuccess - - Error - AgentContact: - kind: alias - values: - - >- - { type: string; orgId: string; trackingId: string; data: { mediaResourceId: string; eventType: string; - eventTime?: number; agentId: string; destAgentId: string; trackingId: string; consultMediaResourceId: string; - interaction: Interaction; participantId?: string; fromOwner?: boolean; toOwner?: boolean; childInteractionId?: - string; interactionId: string; orgId: string; owner: string; queueMgr: string; queueName?: string; type: string; - ronaTimeout?: number; isConsulted?: boolean; isConferencing: boolean; updatedBy?: string; destinationType?: - string; autoResumed?: boolean; reasonCode?: string | number; reason?: string; consultingAgentId?: string; - taskId?: string; task?: Interaction; supervisorId?: string; monitorType?: string; supervisorDN?: string; id?: - string; isWebCallMute?: boolean; reservationInteractionId?: string; reservedAgentChannelId?: string; - monitoringState?: { type: string; }; supervisorName?: string; }; } - ITask: - fields: - - name: data - type: TaskData - required: true - - name: webCallMap - type: Record - required: true - - name: autoWrapup - type: AutoWrapup - required: false - - name: stateMachineService - type: AnyActorRef - required: false - - name: state - type: any - required: false - - name: sendStateMachineEvent - type: "(event: TaskEventPayload) => void" - required: true - Interaction: - fields: - - name: isFcManaged - type: boolean - required: true - - name: isTerminated - type: boolean - required: true - - name: mediaType - type: MEDIA_CHANNEL - required: true - - name: previousVTeams - type: string[] - required: true - - name: state - type: string - required: true - - name: currentVTeam - type: string - required: true - - name: participants - type: InteractionParticipants - required: true - - name: callAssociatedData - type: CallAssociatedData - required: false - - name: callAssociatedDetails - type: CallAssociatedDetails - required: false - - name: interactionId - type: string - required: true - - name: orgId - type: string - required: true - - name: createdTimestamp - type: number - required: false - - name: isWrapUpAssist - type: boolean - required: false - - name: parentInteractionId - type: string - required: false - - name: isMediaForked - type: boolean - required: false - - name: flowProperties - type: Record - required: false - - name: mediaProperties - type: Record - required: false - - name: callProcessingDetails - type: >- - { QMgrName: string; taskToBeSelfServiced: string; ani: string; displayAni: string; dnis: string; tenantId: - string; QueueId: string; vteamId: string; pauseResumeEnabled?: boolean; pauseDuration?: string; isPaused?: - boolean; recordInProgress?: boolean; recordingStarted?: boolean; customerRegion?: string; flowTagId?: string; - ctqInProgress?: boolean; outdialTransferToQueueEnabled?: boolean; convIvrTranscript?: string; customerName: - string; virtualTeamName: string; ronaTimeout: string; category: string; reason: string; sourceNumber: string; - sourcePage: string; appUser: string; customerNumber: string; reasonCode: string; IvrPath: string; pathId: - string; fromAddress: string; parentInteractionId?: string; childInteractionId?: string; relationshipType?: - string; parent_ANI?: string; parent_DNIS?: string; consultDestinationAgentJoined?: boolean | string; - consultDestinationAgentName?: string; parent_Agent_DN?: string; parent_Agent_Name?: string; - parent_Agent_TeamName?: string; isConferencing?: string; monitorType?: string; workflowName?: string; - workflowId?: string; monitoringInvisibleMode?: string; monitoringRequestId?: string; - participantInviteTimeout?: string; mohFileName?: string; CONTINUE_RECORDING_ON_TRANSFER?: string; EP_ID?: - string; ROUTING_TYPE?: string; fceRegisteredEvents?: string; isParked?: string; priority?: string; - routingStrategyId?: string; monitoringState?: string; BLIND_TRANSFER_IN_PROGRESS?: boolean; fcDesktopView?: - string; outdialAgentId?: string; } - required: true - - name: mainInteractionId - type: string - required: false - - name: queuedTimestamp - type: number - required: false - - name: media - type: Record - required: true - - name: owner - type: string - required: true - - name: mediaChannel - type: string - required: true - - name: contactDirection - type: "{ type: string; }" - required: true - - name: outboundType - type: string - required: false - - name: workflowManager - type: string - required: false - - name: callFlowParams - type: Record - required: false - TaskData: - fields: - - name: mediaResourceId - type: string - required: true - - name: eventType - type: string - required: true - - name: eventTime - type: number - required: false - - name: agentId - type: string - required: true - - name: destAgentId - type: string - required: true - - name: trackingId - type: string - required: true - - name: consultMediaResourceId - type: string - required: true - - name: interaction - type: Interaction - required: true - - name: participantId - type: string - required: false - - name: fromOwner - type: boolean - required: false - - name: toOwner - type: boolean - required: false - - name: childInteractionId - type: string - required: false - - name: interactionId - type: string - required: true - - name: orgId - type: string - required: true - - name: owner - type: string - required: true - - name: queueMgr - type: string - required: true - - name: queueName - type: string - required: false - - name: type - type: string - required: true - - name: ronaTimeout - type: number - required: false - - name: isConsulted - type: boolean - required: false - - name: isConferencing - type: boolean - required: true - - name: isConferenceInProgress - type: boolean - required: false - - name: updatedBy - type: string - required: false - - name: destinationType - type: string - required: false - - name: autoResumed - type: boolean - required: false - - name: reasonCode - type: string | number - required: false - - name: reason - type: string - required: false - - name: consultingAgentId - type: string - required: false - - name: taskId - type: string - required: false - - name: task - type: Interaction - required: false - - name: id - type: string - required: false - - name: isWebCallMute - type: boolean - required: false - - name: reservationInteractionId - type: string - required: false - - name: reservedAgentChannelId - type: string - required: false - - name: wrapUpRequired - type: boolean - required: false - - name: consultStatus - type: string - required: false - - name: isConsultInProgress - type: boolean - required: false - - name: isIncomingTask - type: boolean - required: false - - name: isOnHold - type: boolean - required: false - - name: isCustomerInCall - type: boolean - required: false - - name: conferenceParticipantsCount - type: number - required: false - - name: isSecondaryAgent - type: boolean - required: false - - name: isSecondaryEpDnAgent - type: boolean - required: false - - name: mpcState - type: string - required: false - - name: isAutoAnswering - type: boolean - required: false - - name: agentsPendingWrapUp - type: string[] - required: false - TaskResponse: - kind: union - values: - - AgentContact - - Error - - void - ConsultPayload: - fields: - - name: to - type: string - required: true - - name: destinationType - type: string - required: true - - name: holdParticipants - type: boolean - required: false - ConsultEndPayload: - fields: - - name: isConsult - type: boolean - required: true - - name: isSecondaryEpDnAgent - type: boolean - required: false - - name: queueId - type: string - required: false - - name: taskId - type: string - required: true - ConsultTransferPayLoad: - fields: - - name: to - type: string - required: true - - name: destinationType - type: string - required: true - DialerPayload: - fields: - - name: entryPointId - type: string - required: true - - name: destination - type: string - required: true - - name: direction - type: "\"OUTBOUND\"" - required: true - - name: attributes - type: "{ [key: string]: string; }" - required: true - - name: mediaType - type: "\"telephony\" | \"chat\" | \"social\" | \"email\"" - required: true - - name: outboundType - type: "\"OUTDIAL\" | \"CALLBACK\" | \"EXECUTE_FLOW\"" - required: true - - name: origin - type: string - required: true - TransferPayLoad: - fields: - - name: to - type: string - required: true - - name: destinationType - type: string - required: true - ResumeRecordingPayload: - fields: - - name: autoResumed - type: boolean - required: true - WrapupPayLoad: - fields: - - name: wrapUpReason - type: string - required: true - - name: auxCodeId - type: string - required: true - StateChange: - fields: - - name: state - type: string - required: true - - name: auxCodeId - type: string - required: true - - name: lastStateChangeReason - type: string - required: false - - name: agentId - type: string - required: false - Logout: - fields: - - name: logoutReason - type: "\"User requested logout\" | \"Inactivity Logout\" | \"User requested agent profile update\"" - required: false - StateChangeSuccess: - kind: alias - values: - - >- - { type: string; orgId: string; trackingId: string; data: { eventType: "AgentDesktopMessage"; agentId: string; - trackingId: string; auxCodeId: string; agentSessionId: string; orgId: string; status: string; subStatus: - "Available" | "Idle"; lastIdleCodeChangeTimestamp: number; lastStateChangeTimestamp: number; type: - "AgentStateChangeSuccess"; changedBy: string | null; changedById: string | null; changedByName: string | null; - lastStateChangeReason: string; }; } - StationLoginSuccess: - kind: alias - values: - - >- - { type: string; orgId: string; trackingId: string; data: { eventType: "AgentDesktopMessage"; agentId: string; - trackingId: string; auxCodeId: string; teamId: string; agentSessionId: string; orgId: string; interactionIds: - string[]; status: string; subStatus: "Available" | "Idle"; siteId: string; lastIdleCodeChangeTimestamp: number; - lastStateChangeTimestamp: number; profileType: string; channelsMap: Record; dialNumber?: - string; roles?: string[]; supervisorSessionId?: string; type: "AgentStationLoginSuccess"; }; } - StationLoginSuccessResponse: - fields: - - name: eventType - type: "\"AgentDesktopMessage\"" - required: true - - name: agentId - type: string - required: true - - name: trackingId - type: string - required: true - - name: auxCodeId - type: string - required: true - - name: teamId - type: string - required: true - - name: agentSessionId - type: string - required: true - - name: orgId - type: string - required: true - - name: interactionIds - type: string[] - required: true - - name: status - type: string - required: true - - name: subStatus - type: "\"Available\" | \"Idle\"" - required: true - - name: siteId - type: string - required: true - - name: lastIdleCodeChangeTimestamp - type: number - required: true - - name: lastStateChangeTimestamp - type: number - required: true - - name: profileType - type: string - required: true - - name: mmProfile - type: "{ chat: number; email: number; social: number; telephony: number; }" - required: true - - name: dialNumber - type: string - required: false - - name: roles - type: string[] - required: false - - name: supervisorSessionId - type: string - required: false - - name: type - type: "\"AgentStationLoginSuccess\"" - required: true - - name: notifsTrackingId - type: string - required: true - DeviceTypeUpdateSuccess: - kind: alias - values: - - "Omit & { type: \"AgentDeviceTypeUpdateSuccess\"; }" - LogoutSuccess: - kind: alias - values: - - >- - { type: string; orgId: string; trackingId: string; data: { eventType: "AgentDesktopMessage"; agentId: string; - trackingId: string; agentSessionId: string; orgId: string; status: string; subStatus: string; loggedOutBy?: - string; roles?: string[]; type: "AgentLogoutSuccess"; }; } - ReloginSuccess: - kind: alias - values: - - >- - { type: string; orgId: string; trackingId: string; data: { eventType: "AgentDesktopMessage"; agentId: string; - trackingId: string; auxCodeId: string; teamId: string; agentSessionId: string; dn: string; orgId: string; - interactionIds: string[]; isExtension: boolean; status: "LoggedIn"; subStatus: "Idle"; siteId: string; - lastIdleCodeChangeTimestamp: number; lastStateChangeTimestamp: number; lastStateChangeReason?: string; - profileType: string; channelsMap: Record; dialNumber?: string; roles?: string[]; deviceType?: - DeviceType; deviceId?: string | null; isEmergencyModalAlreadyDisplayed?: boolean; type: "AgentReloginSuccess"; - }; } - AgentState: - kind: union - values: - - "'Available'" - - "'Idle'" - - "'RONA'" - - string - UserStationLogin: - fields: - - name: dialNumber - type: string - required: false - - name: dn - type: string - required: false - - name: teamId - type: string - required: true - - name: teamName - type: string - required: true - - name: roles - type: string[] - required: false - - name: siteId - type: string - required: true - - name: usesOtherDN - type: boolean - required: true - - name: skillProfileId - type: string - required: false - - name: auxCodeId - type: string - required: true - - name: isExtension - type: boolean - required: false - - name: deviceType - type: string - required: false - - name: deviceId - type: string - required: false - - name: isEmergencyModalAlreadyDisplayed - type: boolean - required: false - DeviceType: - kind: union - values: - - LoginOption - - string - BuddyDetails: - fields: - - name: agentId - type: string - required: true - - name: state - type: string - required: true - - name: teamId - type: string - required: true - - name: dn - type: string - required: true - - name: agentName - type: string - required: true - - name: siteId - type: string - required: true - BuddyAgentsSuccess: - kind: alias - values: - - >- - { type: string; orgId: string; trackingId: string; data: { eventType: "AgentDesktopMessage"; agentId: string; - trackingId: string; agentSessionId: string; orgId: string; type: "BuddyAgents"; agentList: Array; - }; } - Profile: - fields: - - name: microsoftConfig - type: "{ showUserDetailsMS?: boolean; stateSynchronizationMS?: boolean; }" - required: false - - name: webexConfig - type: "{ showUserDetailsWebex?: boolean; stateSynchronizationWebex?: boolean; }" - required: false - - name: teams - type: Team[] - required: true - - name: defaultDn - type: string - required: true - - name: dn - type: string - required: false - - name: forceDefaultDn - type: boolean - required: true - - name: forceDefaultDnForAgent - type: boolean - required: true - - name: regexUS - type: string | RegExp - required: true - - name: regexOther - type: string | RegExp - required: true - - name: agentId - type: string - required: true - - name: agentName - type: string - required: true - - name: agentMailId - type: string - required: true - - name: agentProfileID - type: string - required: true - - name: dialPlan - type: DialPlan - required: true - - name: multimediaProfileId - type: string - required: true - - name: skillProfileId - type: string - required: true - - name: siteId - type: string - required: true - - name: enterpriseId - type: string - required: true - - name: privacyShieldVisible - type: boolean - required: true - - name: idleCodes - type: Entity[] - required: true - - name: idleCodesList - type: string[] - required: false - - name: idleCodesAccess - type: "\"ALL\" | \"SPECIFIC\"" - required: false - - name: wrapupCodes - type: Entity[] - required: true - - name: agentWrapUpCodes - type: agentWrapUpCodes - required: false - - name: agentDefaultWrapUpCode - type: agentDefaultWrapupCode - required: false - - name: defaultWrapupCode - type: string - required: true - - name: wrapUpData - type: WrapupData - required: true - - name: orgId - type: string - required: false - - name: isOutboundEnabledForTenant - type: boolean - required: true - - name: isOutboundEnabledForAgent - type: boolean - required: true - - name: isAdhocDialingEnabled - type: boolean - required: true - - name: isAgentAvailableAfterOutdial - type: boolean - required: true - - name: isCampaignManagementEnabled - type: boolean - required: true - - name: outDialEp - type: string - required: true - - name: isEndTaskEnabled - type: boolean - required: true - - name: isEndConsultEnabled - type: boolean - required: true - - name: lcmUrl - type: string - required: false - - name: agentDbId - type: string - required: true - - name: agentAnalyzerId - type: string - required: false - - name: allowConsultToQueue - type: boolean - required: true - - name: campaignManagerAdditionalInfo - type: string - required: false - - name: agentPersonalStatsEnabled - type: boolean - required: true - - name: addressBookId - type: string - required: false - - name: outdialANIId - type: string - required: false - - name: analyserUserId - type: string - required: false - - name: isCallMonitoringEnabled - type: boolean - required: false - - name: isMidCallMonitoringEnabled - type: boolean - required: false - - name: isBargeInEnabled - type: boolean - required: false - - name: isManagedTeamsEnabled - type: boolean - required: false - - name: isManagedQueuesEnabled - type: boolean - required: false - - name: isSendMessageEnabled - type: boolean - required: false - - name: isAgentStateChangeEnabled - type: boolean - required: false - - name: isSignOutAgentsEnabled - type: boolean - required: false - - name: urlMappings - type: URLMappings - required: false - - name: isTimeoutDesktopInactivityEnabled - type: boolean - required: true - - name: timeoutDesktopInactivityMins - type: number - required: false - - name: isAnalyzerEnabled - type: boolean - required: false - - name: tenantTimezone - type: string - required: false - - name: loginVoiceOptions - type: LoginOption[] - required: false - - name: deviceType - type: LoginOption - required: false - - name: currentTeamId - type: string - required: false - - name: webRtcEnabled - type: boolean - required: true - - name: organizationIdleCodes - type: Entity[] - required: false - - name: isRecordingManagementEnabled - type: boolean - required: false - - name: lostConnectionRecoveryTimeout - type: number - required: true - - name: maskSensitiveData - type: boolean - required: false - - name: isAgentLoggedIn - type: boolean - required: false - - name: lastStateAuxCodeId - type: string - required: false - - name: lastStateChangeTimestamp - type: number - required: false - - name: lastIdleCodeChangeTimestamp - type: number - required: false - AgentResponse: - fields: - - name: id - type: string - required: true - - name: ciUserId - type: string - required: true - - name: firstName - type: string - required: true - - name: lastName - type: string - required: true - - name: agentProfileId - type: string - required: true - - name: email - type: string - required: true - - name: teamIds - type: string[] - required: true - - name: multimediaProfileId - type: string - required: true - - name: skillProfileId - type: string - required: true - - name: siteId - type: string - required: true - - name: dbId - type: string - required: false - - name: defaultDialledNumber - type: string - required: false - DesktopProfileResponse: - fields: - - name: id - type: string - required: true - - name: name - type: string - required: true - - name: description - type: string - required: true - - name: parentType - type: string - required: true - - name: screenPopup - type: boolean - required: true - - name: loginVoiceOptions - type: LoginOption[] - required: true - - name: accessWrapUpCode - type: string - required: true - - name: accessIdleCode - type: string - required: true - - name: wrapUpCodes - type: string[] - required: true - - name: idleCodes - type: string[] - required: true - - name: dialPlanEnabled - type: boolean - required: true - - name: lastAgentRouting - type: boolean - required: true - - name: autoWrapUp - type: boolean - required: true - - name: agentPersonalGreeting - type: boolean - required: true - - name: autoAnswer - type: boolean - required: true - - name: autoWrapAfterSeconds - type: number - required: true - - name: agentAvailableAfterOutdial - type: boolean - required: true - - name: allowAutoWrapUpExtension - type: boolean - required: true - - name: accessQueue - type: string - required: true - - name: queues - type: string[] - required: true - - name: accessEntryPoint - type: string - required: true - - name: entryPoints - type: string[] - required: true - - name: accessBuddyTeam - type: string - required: true - - name: buddyTeams - type: string[] - required: true - - name: outdialEnabled - type: boolean - required: true - - name: outdialEntryPointId - type: string - required: true - - name: outdialANIId - type: string - required: true - - name: consultToQueue - type: boolean - required: true - - name: addressBookId - type: string - required: true - - name: viewableStatistics - type: >- - { id: string; agentStats: boolean; accessQueueStats: string; contactServiceQueues: string[]; - loggedInTeamStats: boolean; accessTeamStats: string; teams: string[]; } - required: true - - name: agentDNValidation - type: string - required: true - - name: agentDNValidationCriterions - type: string[] - required: true - - name: dialPlans - type: string[] - required: true - - name: timeoutDesktopInactivityCustomEnabled - type: boolean - required: true - - name: timeoutDesktopInactivityMins - type: number - required: true - - name: showUserDetailsMS - type: boolean - required: true - - name: stateSynchronizationMS - type: boolean - required: true - - name: showUserDetailsWebex - type: boolean - required: true - - name: stateSynchronizationWebex - type: boolean - required: true - - name: thresholdRules - type: Record[] - required: true - - name: active - type: boolean - required: true - - name: systemDefault - type: boolean - required: true - - name: createdTime - type: number - required: true - - name: lastUpdatedTime - type: number - required: true - MultimediaProfileResponse: - fields: - - name: organizationId - type: string - required: true - - name: id - type: string - required: true - - name: version - type: number - required: true - - name: name - type: string - required: true - - name: description - type: string - required: true - - name: chat - type: number - required: true - - name: email - type: number - required: true - - name: telephony - type: number - required: true - - name: social - type: number - required: true - - name: active - type: boolean - required: true - - name: blendingModeEnabled - type: boolean - required: true - - name: blendingMode - type: string - required: true - - name: systemDefault - type: boolean - required: true - - name: createdTime - type: number - required: true - - name: lastUpdatedTime - type: number - required: true - ListTeamsResponse: - fields: - - name: data - type: TeamList[] - required: true - - name: meta - type: "{ page: number; pageSize: number; totalPages: number; totalRecords: number; }" - required: true - ListAuxCodesResponse: - fields: - - name: data - type: AuxCode[] - required: true - - name: meta - type: "{ page: number; pageSize: number; totalPages: number; totalRecords: number; }" - required: true - SiteInfo: - fields: - - name: id - type: string - required: true - - name: name - type: string - required: true - - name: active - type: boolean - required: true - - name: multimediaProfileId - type: string - required: true - - name: systemDefault - type: boolean - required: true - OrgInfo: - fields: - - name: tenantId - type: string - required: true - - name: timezone - type: string - required: true - OrgSettings: - fields: - - name: webRtcEnabled - type: boolean - required: true - - name: maskSensitiveData - type: boolean - required: true - - name: campaignManagerEnabled - type: boolean - required: true - TenantData: - fields: - - name: timeoutDesktopInactivityMins - type: number - required: true - - name: forceDefaultDn - type: boolean - required: true - - name: dnDefaultRegex - type: string - required: true - - name: dnOtherRegex - type: string - required: true - - name: privacyShieldVisible - type: boolean - required: true - - name: outdialEnabled - type: boolean - required: true - - name: endCallEnabled - type: boolean - required: true - - name: endConsultEnabled - type: boolean - required: true - - name: callVariablesSuppressed - type: boolean - required: true - - name: timeoutDesktopInactivityEnabled - type: boolean - required: true - - name: lostConnectionRecoveryTimeout - type: number - required: true - URLMapping: - fields: - - name: id - type: string - required: true - - name: name - type: string - required: true - - name: url - type: string - required: true - - name: links - type: string[] - required: true - - name: createdTime - type: number - required: true - - name: lastUpdatedTime - type: number - required: true - DialPlanEntity: - fields: - - name: id - type: string - required: true - - name: regularExpression - type: string - required: true - - name: prefix - type: string - required: true - - name: strippedChars - type: string - required: true - - name: name - type: string - required: true - AuxCode: - fields: - - name: id - type: string - required: true - - name: active - type: boolean - required: true - - name: defaultCode - type: boolean - required: true - - name: isSystemCode - type: boolean - required: true - - name: description - type: string - required: true - - name: name - type: string - required: true - - name: workTypeCode - type: string - required: true - TeamList: - fields: - - name: id - type: string - required: true - - name: name - type: string - required: true - - name: teamType - type: string - required: true - - name: teamStatus - type: string - required: true - - name: active - type: boolean - required: true - - name: siteId - type: string - required: true - - name: siteName - type: string - required: true - - name: multiMediaProfileId - type: string - required: false - - name: userIds - type: string[] - required: true - - name: rankQueuesForTeam - type: boolean - required: true - - name: queueRankings - type: string[] - required: true - - name: dbId - type: string - required: false - - name: desktopLayoutId - type: string - required: false - WrapUpReason: - fields: - - name: isSystem - type: boolean - required: true - - name: name - type: string - required: true - - name: id - type: string - required: true - - name: isDefault - type: boolean - required: true - WebSocketEvent: - fields: - - name: type - type: CC_EVENTS - required: true - - name: data - type: >- - Agent.BuddyAgentsSuccess | Agent.LogoutSuccess | Agent.StateChangeSuccess | Agent.StationLoginSuccess | - Agent.ReloginSuccess | WelcomeEvent - required: true - WrapupData: - fields: - - name: wrapUpProps - type: >- - { autoWrapup?: boolean; autoWrapupInterval?: number; lastAgentRoute?: boolean; wrapUpReasonList: - Array; wrapUpCodesList?: Array; idleCodesAccess?: "ALL" | "SPECIFIC"; interactionId?: - string; allowCancelAutoWrapup?: boolean; } - required: true - Entity: - fields: - - name: isSystem - type: boolean - required: true - - name: name - type: string - required: true - - name: id - type: string - required: true - - name: isDefault - type: boolean - required: true - DialPlan: - fields: - - name: type - type: string - required: true - - name: dialPlanEntity - type: "{ regex: string; prefix: string; strippedChars: string; name: string; }[]" - required: true - AuxCodeType: - kind: union - values: - - typeof IDLE_CODE - - typeof WRAP_UP_CODE -constants: - IDLE_CODE: IDLE_CODE - WRAP_UP_CODE: WRAP_UP_CODE From c82a0a1e3bdbfe70ad5799898413c65306ceeaec Mon Sep 17 00:00:00 2001 From: Rankush Kumar Date: Thu, 26 Mar 2026 14:36:21 +0530 Subject: [PATCH 6/6] refactor: consolidate SDK config into single SDK_CONFIG map Replace separate TRACKED_SDKS and SCAN_DIRS arrays with a single SDK_CONFIG array where each entry has package, scanDirs, and localManifestPath. Adding a new SDK dependency now requires one config entry instead of changes in multiple places. Co-Authored-By: Claude Opus 4.6 (1M context) --- scripts/generate-sdk-deps.ts | 78 ++++++++++++++++++++++-------------- sdk-dependencies.yaml | 4 +- 2 files changed, 50 insertions(+), 32 deletions(-) diff --git a/scripts/generate-sdk-deps.ts b/scripts/generate-sdk-deps.ts index 9477059f8..a0babf596 100644 --- a/scripts/generate-sdk-deps.ts +++ b/scripts/generate-sdk-deps.ts @@ -16,14 +16,26 @@ import * as path from 'path'; const REPO_ROOT = path.resolve(__dirname, '..'); const OUTPUT_FILE = path.join(REPO_ROOT, 'sdk-dependencies.yaml'); -// SDK packages to track — add more as needed -const TRACKED_SDKS = [ - '@webex/contact-center', -]; +// SDK dependency configuration — single source of truth. +// To track a new SDK, add one entry here. No other changes needed. +interface SDKConfigEntry { + package: string; + scanDirs: string[]; + localManifestPath: string; +} -// Directories to scan (relative to repo root) -const SCAN_DIRS = [ - 'packages/contact-center', +const SDK_CONFIG: SDKConfigEntry[] = [ + { + package: '@webex/contact-center', + scanDirs: ['packages/contact-center'], + localManifestPath: '../ccSDK/webex-js-sdk/packages/@webex/contact-center/sdk-manifest.yaml', + }, + // To add a new SDK: + // { + // package: '@webex/calling', + // scanDirs: ['packages/calling'], + // localManifestPath: '../ccSDK/webex-js-sdk/packages/calling/sdk-manifest.yaml', + // }, ]; // Skip test files, fixtures, ai-docs, and dist/build output @@ -97,19 +109,16 @@ function getLineContext(sourceFile: SourceFile, line: number): string { } /** - * Find the SDK manifest — checks node_modules first, then known local paths. + * Find the SDK manifest — checks node_modules first, then local path from config. */ -function findManifestPath(sdkPackage: string): string | null { +function findManifestPath(config: SDKConfigEntry): string | null { // 1. Check node_modules (works for both symlinked and npm-installed) - const nmPath = path.join(REPO_ROOT, 'node_modules', sdkPackage, 'sdk-manifest.yaml'); + const nmPath = path.join(REPO_ROOT, 'node_modules', config.package, 'sdk-manifest.yaml'); if (fs.existsSync(nmPath)) return nmPath; - // 2. Check known local SDK paths (for development when symlink is broken) - const localPaths: Record = { - '@webex/contact-center': path.resolve(REPO_ROOT, '../ccSDK/webex-js-sdk/packages/@webex/contact-center/sdk-manifest.yaml'), - }; - const localPath = localPaths[sdkPackage]; - if (localPath && fs.existsSync(localPath)) return localPath; + // 2. Check local path from config (for development when symlink is broken) + const localPath = path.resolve(REPO_ROOT, config.localManifestPath); + if (fs.existsSync(localPath)) return localPath; return null; } @@ -117,8 +126,8 @@ function findManifestPath(sdkPackage: string): string | null { /** * Read the SDK manifest to get the version and compute a simple hash for staleness detection. */ -function getManifestInfo(sdkPackage: string): {version: string; hash: string} { - const manifestPath = findManifestPath(sdkPackage); +function getManifestInfo(config: SDKConfigEntry): {version: string; hash: string} { + const manifestPath = findManifestPath(config); if (manifestPath) { const content = fs.readFileSync(manifestPath, 'utf8'); const manifest = yaml.load(content) as Record; @@ -136,8 +145,8 @@ function getManifestInfo(sdkPackage: string): {version: string; hash: string} { /** * Load the SDK manifest to know which exports are methods vs types vs events. */ -function loadManifest(sdkPackage: string): {methods: Set; types: Set; events: Set} | null { - const manifestPath = findManifestPath(sdkPackage); +function loadManifest(config: SDKConfigEntry): {methods: Set; types: Set; events: Set} | null { + const manifestPath = findManifestPath(config); if (!manifestPath) return null; const content = fs.readFileSync(manifestPath, 'utf8'); @@ -185,8 +194,14 @@ function generate(): void { skipAddingFilesFromTsConfig: true, }); - // Add source files from scan directories - for (const dir of SCAN_DIRS) { + // Add source files from all configured scan directories + const allScanDirs = new Set(); + for (const config of SDK_CONFIG) { + for (const dir of config.scanDirs) { + allScanDirs.add(dir); + } + } + for (const dir of allScanDirs) { const absDir = path.join(REPO_ROOT, dir); project.addSourceFilesAtPaths([ `${absDir}/**/*.ts`, @@ -204,9 +219,9 @@ function generate(): void { }; // Initialize dependency entries for each tracked SDK - for (const sdk of TRACKED_SDKS) { - const manifestInfo = getManifestInfo(sdk); - depMap.dependencies[sdk] = { + for (const config of SDK_CONFIG) { + const manifestInfo = getManifestInfo(config); + depMap.dependencies[config.package] = { version: manifestInfo.version, manifest_hash: manifestInfo.hash, methods: {}, @@ -217,10 +232,13 @@ function generate(): void { // Load manifest for classification const manifests: Record> = {}; - for (const sdk of TRACKED_SDKS) { - manifests[sdk] = loadManifest(sdk); + for (const config of SDK_CONFIG) { + manifests[config.package] = loadManifest(config); } + // Build lookup: package name -> set of all tracked packages + const trackedPackages = new Set(SDK_CONFIG.map(c => c.package)); + for (const sourceFile of sourceFiles) { const filePath = sourceFile.getFilePath(); const relPath = relativePath(filePath); @@ -232,7 +250,7 @@ function generate(): void { const moduleSpecifier = imp.getModuleSpecifierValue(); // Check if this import is from a tracked SDK - const matchedSdk = TRACKED_SDKS.find((sdk) => + const matchedSdk = [...trackedPackages].find((sdk) => moduleSpecifier === sdk || moduleSpecifier.startsWith(sdk + '/') ); if (!matchedSdk) continue; @@ -373,8 +391,8 @@ function generate(): void { } // Clean up empty entries - for (const sdk of TRACKED_SDKS) { - const dep = depMap.dependencies[sdk]; + for (const config of SDK_CONFIG) { + const dep = depMap.dependencies[config.package]; for (const [key, val] of Object.entries(dep.methods)) { if (val.usages.length === 0) delete dep.methods[key]; } diff --git a/sdk-dependencies.yaml b/sdk-dependencies.yaml index c5c1d2181..658cf8657 100644 --- a/sdk-dependencies.yaml +++ b/sdk-dependencies.yaml @@ -1,9 +1,9 @@ -generated_at: "2026-03-24T12:26:12.244Z" +generated_at: "2026-03-26T09:05:57.957Z" generator: generate-sdk-deps.ts v1.0 dependencies: "@webex/contact-center": version: workspace - manifest_hash: 2cee4d4a + manifest_hash: 977fc0b8 methods: default.init: usages: