{
  "always_run_in_app": false,
  "icon": {
    "color": "deep-blue",
    "glyph": "chart-line"
  },
  "name": "行情",
  "script": "// 行情小组件 · 自动更新版 (loader)\n//\n// 装这个就不用再管更新：它每天从 Worker 拉一次最新脚本，缓存到本地后执行。\n// 逻辑改动只需重新部署 Worker，手机上什么都不用动。\n//\n// 取舍：这等于让 Worker 决定手机上跑什么代码。域名/账号一旦被攻破，\n// 任意 JS 就会拿到 Scriptable 的权限（文件、日历、定位…）。\n// 不接受这个前提就装完整版(/widget.scriptable)，自己手动更新。\n//\n// 安装：手机 Safari 打开面板 → 「一键安装(自动更新)」\n\nconst SOURCE_URL = \"https://widget.sudoo.dev/widget.js\";\nconst CHECK_EVERY_HOURS = 24;\n\nconst fm = FileManager.local();\nconst cachePath = fm.joinPath(fm.libraryDirectory(), \"market-widget-source.js\");\nconst stampPath = fm.joinPath(fm.libraryDirectory(), \"market-widget-source.stamp\");\n\nfunction readStamp() {\n  try {\n    return fm.fileExists(stampPath) ? Number(fm.readString(stampPath)) || 0 : 0;\n  } catch (e) {\n    return 0;\n  }\n}\n\nasync function fetchSource() {\n  const r = new Request(SOURCE_URL);\n  r.timeoutInterval = 15;\n  const src = await r.loadString();\n  // 别把错误页/空响应写进缓存，否则下次启动直接炸\n  if (!src || src.length < 500 || src.indexOf(\"Script.setWidget\") === -1) {\n    throw new Error(\"下载到的不像小组件脚本\");\n  }\n  return src;\n}\n\nasync function getSource() {\n  const fresh = Date.now() - readStamp() < CHECK_EVERY_HOURS * 3600e3;\n  const cached = fm.fileExists(cachePath);\n  if (fresh && cached) return fm.readString(cachePath);\n\n  try {\n    const src = await fetchSource();\n    fm.writeString(cachePath, src);\n    fm.writeString(stampPath, String(Date.now()));\n    return src;\n  } catch (e) {\n    // 更新失败不该让桌面上的小组件变白：有缓存就接着用\n    if (cached) return fm.readString(cachePath);\n    throw e;\n  }\n}\n\nfunction errorWidget(msg) {\n  const w = new ListWidget();\n  w.backgroundColor = Color.dynamic(new Color(\"#ffffff\"), new Color(\"#000000\"));\n  w.setPadding(16, 16, 16, 16);\n  const t = w.addText(\"行情脚本加载失败\");\n  t.font = Font.semiboldSystemFont(13);\n  w.addSpacer(6);\n  const d = w.addText(String(msg).slice(0, 90));\n  d.font = Font.systemFont(11);\n  d.textColor = Color.gray();\n  w.refreshAfterDate = new Date(Date.now() + 15 * 60e3);\n  return w;\n}\n\ntry {\n  const src = await getSource();\n  // 脚本用了顶层 await，包进 AsyncFunction 才能执行；\n  // Script/Request/config 等都是全局，函数体里照样拿得到。\n  const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor;\n  await new AsyncFunction(src)();\n} catch (e) {\n  const w = errorWidget((e && e.message) || e);\n  Script.setWidget(w);\n  if (!config.runsInWidget) await w.presentMedium();\n  Script.complete();\n}\n",
  "share_sheet_inputs": []
}