[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6KKG7XT8HHSTEZQAE2CD6SP":3,"skill-same:01M6KKG7XT8HHSTEZQAE2CD6SP":73},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"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":51,"updatedAt":52,"install":53,"resources":66},"01M6KKG7XT8HHSTEZQAE2CD6SP","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.","AG064\u002FOpenSpace","AG064","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F184930299?v=4","01M6KHVFG7TB73NHX3RDYSTMH2","01M6KHVFMM7XA2PZA9Z83PHS3V",0,"MIT","https:\u002F\u002Fgithub.com\u002FAG064\u002FOpenSpace\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","ff671ef61ed6587c49bd54c81cdc751c0b99e363","showcase\u002Fskills\u002Fpanel-data-resilient","https:\u002F\u002Fgithub.com\u002FAG064\u002FOpenSpace","https:\u002F\u002Fgithub.com\u002FAG064","AG064, E.Mi.\r\n\r\nA person who thinks all the time, yet all they have to think about is nothing. I want to improve the world and work on open source projects","2026-10-08 06:53:48",{"source":8,"skillName":5,"commands":54,"prompt":64,"zipAvailable":65},[55,58,61],{"tool":56,"command":57},"npx","npx skills add AG064\u002FOpenSpace --skill panel-data-resilient",{"tool":59,"command":60},"bunx","bunx skills add AG064\u002FOpenSpace --skill panel-data-resilient",{"tool":62,"command":63},"pnpm","pnpm dlx skills add AG064\u002FOpenSpace --skill panel-data-resilient","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FAG064\u002FOpenSpace\u002Fblob\u002Fmain\u002Fshowcase\u002Fskills\u002Fpanel-data-resilient\u002FSKILL.md",true,[67],{"path":68,"resourceType":69,"resourceTypeDesc":70,"sizeBytes":71,"sourceHtmlUrl":72},".skill_id","OTHER","其他",33,"https:\u002F\u002Fgithub.com\u002FAG064\u002FOpenSpace\u002Fblob\u002Fmain\u002Fshowcase\u002Fskills\u002Fpanel-data-resilient\u002F.skill_id",[74,97,113,122,142,158],{"skillNo":75,"name":76,"nameZh":6,"description":77,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":78,"categories":79,"keywords":80,"publishedAt":41},"01M6KKMPWA0B5SCCH766F8M5EA","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\u002FAG064\u002FOpenSpace\u002Fblob\u002Fmain\u002Fshowcase\u002Fskills\u002Fwrite-special-chars-ts-check\u002FSKILL.md",[],[81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,33],"write special chars ts check","check","write","filters","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":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":101,"categories":102,"keywords":103,"publishedAt":41},"01M6KKMJXVBNVEY3TRK055F4A7","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\u002FAG064\u002FOpenSpace\u002Fblob\u002Fmain\u002Fshowcase\u002Fskills\u002Fwrite-special-chars-readback\u002FSKILL.md",[],[104,105,83,94,106,107,95,96,108,109,110,111,112,87,89,29],"readback","write special chars readback","cleanup","read","scripts","verification","via","post","helper",{"skillNo":114,"name":115,"nameZh":6,"description":116,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":117,"categories":118,"keywords":119,"publishedAt":41},"01M6KKMEGX9M9NC105J0W3Q5B9","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\u002FAG064\u002FOpenSpace\u002Fblob\u002Fmain\u002Fshowcase\u002Fskills\u002Fwrite-special-chars-heredoc\u002FSKILL.md",[],[83,120,96,87,110,94,121,95,89],"write special chars heredoc","shell",{"skillNo":123,"name":124,"nameZh":6,"description":125,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":126,"categories":127,"keywords":129,"publishedAt":41},"01M6KKM8EJ2AATVHZBNB916WT0","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\u002FAG064\u002FOpenSpace\u002Fblob\u002Fmain\u002Fshowcase\u002Fskills\u002Fworldmonitor-reference\u002FSKILL.md",[128],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},[130,131,132,40,33,133,38,134,135,136,87,137,24,34,138,139,140,35,25,141],"reference","worldmonitor","worldmonitor reference","css","extracting","hierarchy","source","layer","edge functions","integrations","open","scheduler",{"skillNo":143,"name":144,"nameZh":6,"description":145,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":146,"categories":147,"keywords":148,"publishedAt":41},"01M6KKM39PHYK627F19GE2B9XN","virtual-list","Implement efficient virtual scrolling for rendering large lists with DOM recycling, chunk-based rendering, and performance optimizations","https:\u002F\u002Fgithub.com\u002FAG064\u002FOpenSpace\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":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":162,"categories":163,"keywords":164,"publishedAt":41},"01M6KKKY7T2P61Y0JH54CDEJKQ","verify-directory-structure","Diagnose and resolve file access issues by first verifying the directory structure.","https:\u002F\u002Fgithub.com\u002FAG064\u002FOpenSpace\u002Fblob\u002Fmain\u002Fshowcase\u002Fskills\u002Fverify-directory-structure\u002FSKILL.md",[],[165,166,167,168,169,170,95,171,172,173],"directory","verify","structure","verify directory structure","access","first","issues","diagnose","file access"]