[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6XC9XC01FJ5DCG2FNT2DHYQ":3,"skill-same:01M6XC9XC01FJ5DCG2FNT2DHYQ":72},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":22,"publishedAt":41,"linkOnly":42,"markdownContent":43,"markdownBody":44,"frontMatter":45,"refName":46,"commitSha":47,"skillDirectory":48,"forksCount":13,"repositoryHtmlUrl":49,"repositoryHomepageUrl":6,"ownerHtmlUrl":50,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":51,"install":52,"resources":65},"01M6XC9XC01FJ5DCG2FNT2DHYQ","panel-data-resilient",null,"Create resilient, data-driven dashboard panels with integrated API handling and UI components, combining circuit breaker patterns with vanilla TypeScript panel architecture.","UF-gzj\u002Fopenspace-claude-evolution","UF-gzj","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F272393507?v=4","01M6XBCZB755P01VVYGQWPYZY3","01M6XBCZFJA5AREA17WGETA3FW",0,"MIT","https:\u002F\u002Fgithub.com\u002FUF-gzj\u002Fopenspace-claude-evolution\u002Fblob\u002Fmain\u002Fshowcase\u002Fskills\u002Fpanel-data-resilient\u002FSKILL.md",[17],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000033","数据分析师","PROFESSION","适用职业",[23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40],"panel data resilient","panel","data","Circuit Breaker","data-driven","circuit","with","ui components","panels","driven","typescript","patterns","api","ui","create","architecture","components","dashboard","2026-11-10 10:12:30",false,"---\nname: panel-data-resilient\ndescription: Create resilient, data-driven dashboard panels with integrated API handling and UI components, combining circuit breaker patterns with vanilla TypeScript panel architecture.\n---\n\n# Resilient Panel Pattern\n\nThis skill merges the best of `data-service` and `panel-component` to create panels that are both resilient to API failures and easy to implement. Each panel manages its own data fetching with built-in circuit breaker patterns and renders content using vanilla TypeScript.\n\n## Architecture Overview\n\n1. **Service Module**: Each panel has a dedicated service module for data fetching, using circuit breakers for resilience.\n2. **Panel Class**: Extends a base `Panel` class with built-in loading\u002Ferror states and content rendering.\n3. **Data Flow**: Panels automatically fetch data, handle errors, and retry as needed.\n\n## Implementation\n\n### 1. Circuit Breaker Utility\n\nCreate `src\u002Futils\u002Fcircuit-breaker.ts` (same as in `data-service` but with enhanced logging):\n\n```typescript\ninterface CircuitState {\n  failures: number;\n  cooldownUntil: number;\n}\n\ninterface CacheEntry\u003CT> {\n  data: T;\n  timestamp: number;\n}\n\nexport interface CircuitBreakerOptions {\n  name: string;\n  maxFailures?: number;\n  cooldownMs?: number;\n  cacheTtlMs?: number;\n}\n\nexport class CircuitBreaker\u003CT> {\n  private state: CircuitState = { failures: 0, cooldownUntil: 0 };\n  private cache: CacheEntry\u003CT> | null = null;\n  private name: string;\n  private maxFailures: number;\n  private cooldownMs: number;\n  private cacheTtlMs: number;\n\n  constructor(options: CircuitBreakerOptions) {\n    this.name = options.name;\n    this.maxFailures = options.maxFailures ?? 2;\n    this.cooldownMs = options.cooldownMs ?? 5 * 60 * 1000;  \u002F\u002F 5 minutes\n    this.cacheTtlMs = options.cacheTtlMs ?? 10 * 60 * 1000; \u002F\u002F 10 minutes\n  }\n\n  isOnCooldown(): boolean {\n    if (Date.now() \u003C this.state.cooldownUntil) return true;\n    if (this.state.cooldownUntil > 0) {\n      this.state = { failures: 0, cooldownUntil: 0 };\n    }\n    return false;\n  }\n\n  getCached(): T | null {\n    if (this.cache && Date.now() - this.cache.timestamp \u003C this.cacheTtlMs) {\n      return this.cache.data;\n    }\n    return null;\n  }\n\n  recordSuccess(data: T): void {\n    this.state = { failures: 0, cooldownUntil: 0 };\n    this.cache = { data, timestamp: Date.now() };\n  }\n\n  recordFailure(error?: string): void {\n    this.state.failures++;\n    if (this.state.failures >= this.maxFailures) {\n      this.state.cooldownUntil = Date.now() + this.cooldownMs;\n      console.warn(`[${this.name}] Cooldown for ${this.cooldownMs \u002F 1000}s`);\n    }\n  }\n\n  async execute\u003CR extends T>(fn: () => Promise\u003CR>, defaultValue: R): Promise\u003CR> {\n    if (this.isOnCooldown()) {\n      const cached = this.getCached();\n      return (cached as R) ?? defaultValue;\n    }\n    const cached = this.getCached();\n    if (cached !== null) return cached as R;\n    try {\n      const result = await fn();\n      this.recordSuccess(result);\n      return result;\n    } catch (e) {\n      console.error(`[${this.name}] Failed:`, e);\n      this.recordFailure(String(e));\n      return defaultValue;\n    }\n  }\n}\n\nexport function createCircuitBreaker\u003CT>(options: CircuitBreakerOptions): CircuitBreaker\u003CT> {\n  return new CircuitBreaker\u003CT>(options);\n}\n```\n\n### 2. Base Panel Class\n\nCreate `src\u002Fcomponents\u002FPanel.ts` with enhanced error handling and retry logic:\n\n```typescript\nexport interface PanelOptions {\n  id: string;\n  title: string;\n  showCount?: boolean;\n  className?: string;\n}\n\nexport class Panel {\n  protected element: HTMLElement;\n  protected content: HTMLElement;\n  protected header: HTMLElement;\n  protected countEl: HTMLElement | null = null;\n  protected panelId: string;\n  private _fetching = false;\n\n  constructor(options: PanelOptions) {\n    this.panelId = options.id;\n    this.element = document.createElement('div');\n    this.element.className = `panel ${options.className || ''}`;\n    this.element.dataset.panel = options.id;\n\n    \u002F\u002F Header\n    this.header = document.createElement('div');\n    this.header.className = 'panel-header';\n\n    const headerLeft = document.createElement('div');\n    headerLeft.className = 'panel-header-left';\n\n    const title = document.createElement('span');\n    title.className = 'panel-title';\n    title.textContent = options.title;\n    headerLeft.appendChild(title);\n    this.header.appendChild(headerLeft);\n\n    \u002F\u002F Count badge (optional)\n    if (options.showCount) {\n      this.countEl = document.createElement('span');\n      this.countEl.className = 'panel-count';\n      this.countEl.textContent = '0';\n      this.header.appendChild(this.countEl);\n    }\n\n    \u002F\u002F Content area\n    this.content = document.createElement('div');\n    this.content.className = 'panel-content';\n    this.content.id = `${options.id}Content`;\n\n    this.element.appendChild(this.header);\n    this.element.appendChild(this.content);\n    this.showLoading();\n  }\n\n  public getElement(): HTMLElement { return this.element; }\n\n  public showLoading(message = 'Loading...'): void {\n    this.content.innerHTML = `\n      \u003Cdiv class=\"panel-loading\">\n        \u003Cdiv class=\"panel-loading-spinner\">\u003C\u002Fdiv>\n        \u003Cdiv class=\"panel-loading-text\">${message}\u003C\u002Fdiv>\n      \u003C\u002Fdiv>`;\n  }\n\n  public showError(message = 'Failed to load', onRetry?: () => void): void {\n    this.content.innerHTML = `\n      \u003Cdiv class=\"panel-error-state\">\n        \u003Cdiv class=\"panel-error-msg\">${message}\u003C\u002Fdiv>\n        ${onRetry ? '\u003Cbutton class=\"panel-retry-btn\" data-panel-retry>Retry\u003C\u002Fbutton>' : ''}\n      \u003C\u002Fdiv>`;\n    if (onRetry) {\n      this.content.querySelector('[data-panel-retry]')?.addEventListener('click', onRetry);\n    }\n  }\n\n  public setContent(html: string): void {\n    this.content.innerHTML = html;\n  }\n\n  public setCount(count: number): void {\n    if (this.countEl) this.countEl.textContent = count.toString();\n  }\n\n  public show(): void { this.element.classList.remove('hidden'); }\n  public hide(): void { this.element.classList.add('hidden'); }\n\n  protected setFetching(v: boolean): void { this._fetching = v; }\n  protected get isFetching(): boolean { return this._fetching; }\n\n  public destroy(): void {\n    this.element.remove();\n  }\n}\n```\n\n### 3. Example: StockPanel with Integrated Service\n\n```typescript\nimport { Panel } from '.\u002FPanel';\nimport { createCircuitBreaker } from '..\u002Futils\u002Fcircuit-breaker';\n\ninterface StockQuote {\n  symbol: string;\n  name: string;\n  price: number | null;\n  change: number | null;\n  sparkline?: number[];\n}\n\nconst breaker = createCircuitBreaker\u003CStockQuote[]>({\n  name: 'StockMarket',\n  cacheTtlMs: 60_000,\n});\n\nexport class StockPanel extends Panel {\n  private refreshTimer: ReturnType\u003Ctypeof setInterval> | null = null;\n\n  constructor() {\n    super({ id: 'stocks', title: 'Stock Market', showCount: true });\n    this.fetchData();\n    this.refreshTimer = setInterval(() => this.fetchData(), 60_000);\n  }\n\n  private async fetchData(): Promise\u003Cvoid> {\n    if (this.isFetching) return;\n    this.setFetching(true);\n    try {\n      const quotes = await breaker.execute(async () => {\n        const resp = await fetch('\u002Fapi\u002Fstocks');\n        if (!resp.ok) throw new Error(`HTTP ${resp.status}`);\n        return resp.json();\n      }, []);\n      this.render(quotes);\n      this.setCount(quotes.length);\n    } catch (err) {\n      this.showError('Failed to load stock data', () => this.fetchData());\n    } finally {\n      this.setFetching(false);\n    }\n  }\n\n  private render(quotes: StockQuote[]): void {\n    const rows = quotes.map(q => `\n      \u003Cdiv class=\"stock-row\">\n        \u003Cspan class=\"stock-symbol\">${q.symbol}\u003C\u002Fspan>\n        \u003Cspan class=\"stock-name\">${q.name}\u003C\u002Fspan>\n        \u003Cspan class=\"stock-price\">${q.price != null ? '$' + q.price.toFixed(2) : '—'}\u003C\u002Fspan>\n        \u003Cspan class=\"stock-change ${(q.change ?? 0) >= 0 ? 'positive' : 'negative'}\">\n          ${q.change != null ? (q.change >= 0 ? '+' : '') + q.change.toFixed(2) + '%' : '—'}\n        \u003C\u002Fspan>\n      \u003C\u002Fdiv>\n    `).join('');\n\n    this.setContent(`\u003Cdiv class=\"stock-list\">${rows}\u003C\u002Fdiv>`);\n  }\n\n  public override destroy(): void {\n    if (this.refreshTimer) clearInterval(this.refreshTimer);\n    super.destroy();\n  }\n}\n```\n\n## Key Patterns\n\n1. **Integrated Data Handling**: Each panel manages its own data fetching with built-in circuit breakers.\n2. **Resilient UI**: Automatic retry logic and graceful degradation when APIs fail.\n3. **Simple Implementation**: Just extend `Panel` and implement `fetchData()` and `render()`.\n4. **Type Safety**: Strongly typed data interfaces throughout.\n","# Resilient Panel Pattern\n\nThis skill merges the best of `data-service` and `panel-component` to create panels that are both resilient to API failures and easy to implement. Each panel manages its own data fetching with built-in circuit breaker patterns and renders content using vanilla TypeScript.\n\n## Architecture Overview\n\n1. **Service Module**: Each panel has a dedicated service module for data fetching, using circuit breakers for resilience.\n2. **Panel Class**: Extends a base `Panel` class with built-in loading\u002Ferror states and content rendering.\n3. **Data Flow**: Panels automatically fetch data, handle errors, and retry as needed.\n\n## Implementation\n\n### 1. Circuit Breaker Utility\n\nCreate `src\u002Futils\u002Fcircuit-breaker.ts` (same as in `data-service` but with enhanced logging):\n\n```typescript\ninterface CircuitState {\n  failures: number;\n  cooldownUntil: number;\n}\n\ninterface CacheEntry\u003CT> {\n  data: T;\n  timestamp: number;\n}\n\nexport interface CircuitBreakerOptions {\n  name: string;\n  maxFailures?: number;\n  cooldownMs?: number;\n  cacheTtlMs?: number;\n}\n\nexport class CircuitBreaker\u003CT> {\n  private state: CircuitState = { failures: 0, cooldownUntil: 0 };\n  private cache: CacheEntry\u003CT> | null = null;\n  private name: string;\n  private maxFailures: number;\n  private cooldownMs: number;\n  private cacheTtlMs: number;\n\n  constructor(options: CircuitBreakerOptions) {\n    this.name = options.name;\n    this.maxFailures = options.maxFailures ?? 2;\n    this.cooldownMs = options.cooldownMs ?? 5 * 60 * 1000;  \u002F\u002F 5 minutes\n    this.cacheTtlMs = options.cacheTtlMs ?? 10 * 60 * 1000; \u002F\u002F 10 minutes\n  }\n\n  isOnCooldown(): boolean {\n    if (Date.now() \u003C this.state.cooldownUntil) return true;\n    if (this.state.cooldownUntil > 0) {\n      this.state = { failures: 0, cooldownUntil: 0 };\n    }\n    return false;\n  }\n\n  getCached(): T | null {\n    if (this.cache && Date.now() - this.cache.timestamp \u003C this.cacheTtlMs) {\n      return this.cache.data;\n    }\n    return null;\n  }\n\n  recordSuccess(data: T): void {\n    this.state = { failures: 0, cooldownUntil: 0 };\n    this.cache = { data, timestamp: Date.now() };\n  }\n\n  recordFailure(error?: string): void {\n    this.state.failures++;\n    if (this.state.failures >= this.maxFailures) {\n      this.state.cooldownUntil = Date.now() + this.cooldownMs;\n      console.warn(`[${this.name}] Cooldown for ${this.cooldownMs \u002F 1000}s`);\n    }\n  }\n\n  async execute\u003CR extends T>(fn: () => Promise\u003CR>, defaultValue: R): Promise\u003CR> {\n    if (this.isOnCooldown()) {\n      const cached = this.getCached();\n      return (cached as R) ?? defaultValue;\n    }\n    const cached = this.getCached();\n    if (cached !== null) return cached as R;\n    try {\n      const result = await fn();\n      this.recordSuccess(result);\n      return result;\n    } catch (e) {\n      console.error(`[${this.name}] Failed:`, e);\n      this.recordFailure(String(e));\n      return defaultValue;\n    }\n  }\n}\n\nexport function createCircuitBreaker\u003CT>(options: CircuitBreakerOptions): CircuitBreaker\u003CT> {\n  return new CircuitBreaker\u003CT>(options);\n}\n```\n\n### 2. Base Panel Class\n\nCreate `src\u002Fcomponents\u002FPanel.ts` with enhanced error handling and retry logic:\n\n```typescript\nexport interface PanelOptions {\n  id: string;\n  title: string;\n  showCount?: boolean;\n  className?: string;\n}\n\nexport class Panel {\n  protected element: HTMLElement;\n  protected content: HTMLElement;\n  protected header: HTMLElement;\n  protected countEl: HTMLElement | null = null;\n  protected panelId: string;\n  private _fetching = false;\n\n  constructor(options: PanelOptions) {\n    this.panelId = options.id;\n    this.element = document.createElement('div');\n    this.element.className = `panel ${options.className || ''}`;\n    this.element.dataset.panel = options.id;\n\n    \u002F\u002F Header\n    this.header = document.createElement('div');\n    this.header.className = 'panel-header';\n\n    const headerLeft = document.createElement('div');\n    headerLeft.className = 'panel-header-left';\n\n    const title = document.createElement('span');\n    title.className = 'panel-title';\n    title.textContent = options.title;\n    headerLeft.appendChild(title);\n    this.header.appendChild(headerLeft);\n\n    \u002F\u002F Count badge (optional)\n    if (options.showCount) {\n      this.countEl = document.createElement('span');\n      this.countEl.className = 'panel-count';\n      this.countEl.textContent = '0';\n      this.header.appendChild(this.countEl);\n    }\n\n    \u002F\u002F Content area\n    this.content = document.createElement('div');\n    this.content.className = 'panel-content';\n    this.content.id = `${options.id}Content`;\n\n    this.element.appendChild(this.header);\n    this.element.appendChild(this.content);\n    this.showLoading();\n  }\n\n  public getElement(): HTMLElement { return this.element; }\n\n  public showLoading(message = 'Loading...'): void {\n    this.content.innerHTML = `\n      \u003Cdiv class=\"panel-loading\">\n        \u003Cdiv class=\"panel-loading-spinner\">\u003C\u002Fdiv>\n        \u003Cdiv class=\"panel-loading-text\">${message}\u003C\u002Fdiv>\n      \u003C\u002Fdiv>`;\n  }\n\n  public showError(message = 'Failed to load', onRetry?: () => void): void {\n    this.content.innerHTML = `\n      \u003Cdiv class=\"panel-error-state\">\n        \u003Cdiv class=\"panel-error-msg\">${message}\u003C\u002Fdiv>\n        ${onRetry ? '\u003Cbutton class=\"panel-retry-btn\" data-panel-retry>Retry\u003C\u002Fbutton>' : ''}\n      \u003C\u002Fdiv>`;\n    if (onRetry) {\n      this.content.querySelector('[data-panel-retry]')?.addEventListener('click', onRetry);\n    }\n  }\n\n  public setContent(html: string): void {\n    this.content.innerHTML = html;\n  }\n\n  public setCount(count: number): void {\n    if (this.countEl) this.countEl.textContent = count.toString();\n  }\n\n  public show(): void { this.element.classList.remove('hidden'); }\n  public hide(): void { this.element.classList.add('hidden'); }\n\n  protected setFetching(v: boolean): void { this._fetching = v; }\n  protected get isFetching(): boolean { return this._fetching; }\n\n  public destroy(): void {\n    this.element.remove();\n  }\n}\n```\n\n### 3. Example: StockPanel with Integrated Service\n\n```typescript\nimport { Panel } from '.\u002FPanel';\nimport { createCircuitBreaker } from '..\u002Futils\u002Fcircuit-breaker';\n\ninterface StockQuote {\n  symbol: string;\n  name: string;\n  price: number | null;\n  change: number | null;\n  sparkline?: number[];\n}\n\nconst breaker = createCircuitBreaker\u003CStockQuote[]>({\n  name: 'StockMarket',\n  cacheTtlMs: 60_000,\n});\n\nexport class StockPanel extends Panel {\n  private refreshTimer: ReturnType\u003Ctypeof setInterval> | null = null;\n\n  constructor() {\n    super({ id: 'stocks', title: 'Stock Market', showCount: true });\n    this.fetchData();\n    this.refreshTimer = setInterval(() => this.fetchData(), 60_000);\n  }\n\n  private async fetchData(): Promise\u003Cvoid> {\n    if (this.isFetching) return;\n    this.setFetching(true);\n    try {\n      const quotes = await breaker.execute(async () => {\n        const resp = await fetch('\u002Fapi\u002Fstocks');\n        if (!resp.ok) throw new Error(`HTTP ${resp.status}`);\n        return resp.json();\n      }, []);\n      this.render(quotes);\n      this.setCount(quotes.length);\n    } catch (err) {\n      this.showError('Failed to load stock data', () => this.fetchData());\n    } finally {\n      this.setFetching(false);\n    }\n  }\n\n  private render(quotes: StockQuote[]): void {\n    const rows = quotes.map(q => `\n      \u003Cdiv class=\"stock-row\">\n        \u003Cspan class=\"stock-symbol\">${q.symbol}\u003C\u002Fspan>\n        \u003Cspan class=\"stock-name\">${q.name}\u003C\u002Fspan>\n        \u003Cspan class=\"stock-price\">${q.price != null ? '$' + q.price.toFixed(2) : '—'}\u003C\u002Fspan>\n        \u003Cspan class=\"stock-change ${(q.change ?? 0) >= 0 ? 'positive' : 'negative'}\">\n          ${q.change != null ? (q.change >= 0 ? '+' : '') + q.change.toFixed(2) + '%' : '—'}\n        \u003C\u002Fspan>\n      \u003C\u002Fdiv>\n    `).join('');\n\n    this.setContent(`\u003Cdiv class=\"stock-list\">${rows}\u003C\u002Fdiv>`);\n  }\n\n  public override destroy(): void {\n    if (this.refreshTimer) clearInterval(this.refreshTimer);\n    super.destroy();\n  }\n}\n```\n\n## Key Patterns\n\n1. **Integrated Data Handling**: Each panel manages its own data fetching with built-in circuit breakers.\n2. **Resilient UI**: Automatic retry logic and graceful degradation when APIs fail.\n3. **Simple Implementation**: Just extend `Panel` and implement `fetchData()` and `render()`.\n4. **Type Safety**: Strongly typed data interfaces throughout.\n",{"name":5,"description":7},"main","0650921d63895de3997bc81f1ff1d0ac67032072","showcase\u002Fskills\u002Fpanel-data-resilient","https:\u002F\u002Fgithub.com\u002FUF-gzj\u002Fopenspace-claude-evolution","https:\u002F\u002Fgithub.com\u002FUF-gzj","2026-04-16 09:31:03",{"source":8,"skillName":5,"commands":53,"prompt":63,"zipAvailable":64},[54,57,60],{"tool":55,"command":56},"npx","npx skills add UF-gzj\u002Fopenspace-claude-evolution --skill panel-data-resilient",{"tool":58,"command":59},"bunx","bunx skills add UF-gzj\u002Fopenspace-claude-evolution --skill panel-data-resilient",{"tool":61,"command":62},"pnpm","pnpm dlx skills add UF-gzj\u002Fopenspace-claude-evolution --skill panel-data-resilient","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FUF-gzj\u002Fopenspace-claude-evolution\u002Fblob\u002Fmain\u002Fshowcase\u002Fskills\u002Fpanel-data-resilient\u002FSKILL.md",true,[66],{"path":67,"resourceType":68,"resourceTypeDesc":69,"sizeBytes":70,"sourceHtmlUrl":71},".skill_id","OTHER","其他",33,"https:\u002F\u002Fgithub.com\u002FUF-gzj\u002Fopenspace-claude-evolution\u002Fblob\u002Fmain\u002Fshowcase\u002Fskills\u002Fpanel-data-resilient\u002F.skill_id",[73,97,113,122,142,158],{"skillNo":74,"name":75,"nameZh":6,"description":76,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":77,"categories":78,"keywords":79,"publishedAt":41},"01M6XCCXD3NCM2YKR3WNGBASPC","write-special-chars-ts-check","Workaround for write_file failures caused by special characters (apostrophes, backticks, template literals) using a Python heredoc script, plus a reliable TypeScript type-checking step that filters output to only the newly-written files to avoid being misled by pre-existing errors.","https:\u002F\u002Fgithub.com\u002FUF-gzj\u002Fopenspace-claude-evolution\u002Fblob\u002Fmain\u002Fshowcase\u002Fskills\u002Fwrite-special-chars-ts-check\u002FSKILL.md",[],[80,81,82,33,83,84,85,86,87,88,89,90,91,92,93,94,95,96],"check","write","write special chars ts check","filters","characters","Existing","type-checking","for","errors","script","output","type","files","only","template","file","python",{"skillNo":98,"name":99,"nameZh":6,"description":100,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":101,"categories":102,"keywords":103,"publishedAt":41},"01M6XCCT7E3J922Q345PBGSHPN","write-special-chars-readback","Workaround for write_file failures caused by special characters (apostrophes, backticks, template literals) using a Python heredoc script, with mandatory post-write verification via read_file and cleanup of \u002Ftmp helper scripts.","https:\u002F\u002Fgithub.com\u002FUF-gzj\u002Fopenspace-claude-evolution\u002Fblob\u002Fmain\u002Fshowcase\u002Fskills\u002Fwrite-special-chars-readback\u002FSKILL.md",[],[104,105,81,95,106,96,107,108,109,110,111,94,112,29,84,87,89],"readback","write special chars readback","helper","post","via","scripts","cleanup","read","verification",{"skillNo":114,"name":115,"nameZh":6,"description":116,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":117,"categories":118,"keywords":119,"publishedAt":41},"01M6XCCMQX1R8B6FECWB3P63T7","write-special-chars-heredoc","Workaround for write_file failures caused by special characters (apostrophes, backticks, template literals) by using a Python heredoc script executed via shell.","https:\u002F\u002Fgithub.com\u002FUF-gzj\u002Fopenspace-claude-evolution\u002Fblob\u002Fmain\u002Fshowcase\u002Fskills\u002Fwrite-special-chars-heredoc\u002FSKILL.md",[],[120,81,84,121,89,108,94,95,96,87],"write special chars heredoc","shell",{"skillNo":123,"name":124,"nameZh":6,"description":125,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":126,"categories":127,"keywords":129,"publishedAt":41},"01M6XCCG41M994JJEX6VN52PEP","worldmonitor-reference","Curated architecture index of the WorldMonitor open-source dashboard. Reference for extracting patterns — vanilla TypeScript, Panel class hierarchy, service layer, CSS grid, API edge functions, refresh scheduler, and 60+ data source integrations.","https:\u002F\u002Fgithub.com\u002FUF-gzj\u002Fopenspace-claude-evolution\u002Fblob\u002Fmain\u002Fshowcase\u002Fskills\u002Fworldmonitor-reference\u002FSKILL.md",[128],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},[130,131,132,38,40,33,133,134,135,136,137,87,138,24,34,139,140,141,35,25],"reference","worldmonitor","worldmonitor reference","css","scheduler","layer","hierarchy","source","extracting","edge functions","integrations","open",{"skillNo":143,"name":144,"nameZh":6,"description":145,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":146,"categories":147,"keywords":148,"publishedAt":41},"01M6XCCCHWNKG2W4VH9E6A10HF","virtual-list","Implement efficient virtual scrolling for rendering large lists with DOM recycling, chunk-based rendering, and performance optimizations","https:\u002F\u002Fgithub.com\u002FUF-gzj\u002Fopenspace-claude-evolution\u002Fblob\u002Fmain\u002Fshowcase\u002Fskills\u002Fvirtual-list\u002FSKILL.md",[],[149,150,151,152,87,153,29,154,155,156,157],"virtual list","list","virtual","chunk","dom","rendering","recycling","implement","performance",{"skillNo":159,"name":160,"nameZh":6,"description":161,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":162,"categories":163,"keywords":164,"publishedAt":41},"01M6XCC7X8PKMR2DEW91XGHYSV","verify-directory-structure","Diagnose and resolve file access issues by first verifying the directory structure.","https:\u002F\u002Fgithub.com\u002FUF-gzj\u002Fopenspace-claude-evolution\u002Fblob\u002Fmain\u002Fshowcase\u002Fskills\u002Fverify-directory-structure\u002FSKILL.md",[],[165,166,167,168,169,170,95,171,172,173],"directory","verify directory structure","structure","verify","access","first","issues","diagnose","file access"]