dsh-plugin-t-expert 0.4.51 → 0.4.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +56 -0
- package/data/roster.json +2220 -743
- package/lib/client.js +29 -3
- package/lib/fetch-assets.js +3 -0
- package/lib/index.js +20 -1
- package/lib/remote.js +13 -0
- package/package.json +1 -1
- package/data/experts/engineering/data-analytics-reporter/agents/data-analytics-reporter.md +0 -174
- package/data/experts/engineering/data-analytics-reporter/skills/analytics-reporting/SKILL.md +0 -213
- package/data/experts/engineering/data-analytics-reporter/skills/data-quality-assessment/SKILL.md +0 -167
- package/data/experts/engineering/data-analytics-reporter/skills/data-visualization/SKILL.md +0 -94
- package/data/experts/engineering/data-analytics-reporter/skills/kpi-design/SKILL.md +0 -134
- package/data/experts/engineering/data-analytics-reporter/skills/metric-diagnostics/SKILL.md +0 -143
- package/data/experts/hr/fbsir-beike-yi/agents/fbsir-beike-yi.md +0 -225
- package/data/experts/hr/fbsir-beike-yi/contracts/first-value-contract.json +0 -33
- package/data/experts/hr/fbsir-beike-yi/contracts/high-value-delivery.schema.json +0 -36
- package/data/experts/hr/fbsir-beike-yi/contracts/material-scope.schema.json +0 -46
- package/data/experts/hr/fbsir-beike-yi/contracts/option-decision-contract.json +0 -34
- package/data/experts/hr/fbsir-beike-yi/contracts/reuse-capsule.schema.json +0 -28
- package/data/experts/hr/fbsir-beike-yi/contracts/teaching-quality-review-contract.json +0 -38
- package/data/experts/hr/fbsir-beike-yi/contracts/writeback-contract.json +0 -34
- package/data/experts/hr/fbsir-beike-yi/examples/acceptance-cases.json +0 -104
- package/data/experts/hr/fbsir-beike-yi/examples/local-workspace-scenarios.json +0 -43
- package/data/experts/hr/fbsir-beike-yi/examples/output-structures.md +0 -111
- package/data/experts/hr/fbsir-beike-yi/references/evidence-and-source-ledger.md +0 -56
- package/data/experts/hr/fbsir-beike-yi/references/user-visible-copy.md +0 -60
- package/data/experts/hr/fbsir-beike-yi/references/workbuddy-local-mode-boundary.md +0 -41
- package/data/experts/hr/fbsir-beike-yi/skills/lesson-planning-core/SKILL.md +0 -152
- package/data/experts/hr/fbsir-beike-yi/skills/lesson-planning-core/references/bounded-revision.md +0 -30
- package/data/experts/hr/fbsir-beike-yi/skills/lesson-planning-core/references/high-value-delivery.md +0 -33
- package/data/experts/hr/fbsir-beike-yi/skills/lesson-planning-core/references/local-writeback.md +0 -35
- package/data/experts/hr/fbsir-beike-yi/skills/lesson-planning-core/references/material-sensemaking.md +0 -43
- package/data/experts/hr/fbsir-beike-yi/skills/lesson-planning-core/references/option-decision.md +0 -40
- package/data/experts/hr/fbsir-beike-yi/skills/lesson-planning-core/references/reuse-capsule.md +0 -34
- package/data/experts/hr/fbsir-beike-yi/skills/lesson-planning-core/references/teaching-quality-review.md +0 -28
- package/data/experts/hr/fbsir-beike-yi/skills/lesson-planning-core/templates/high-value-delivery-card.md +0 -35
- package/data/experts/hr/fbsir-beike-yi/skills/lesson-planning-core/templates/material-understanding-card.md +0 -47
- package/data/experts/hr/fbsir-beike-yi/skills/lesson-planning-core/templates/teaching-option-card.md +0 -38
- package/data/experts/marketing/kdocs-ppt-creator/agents/kdocs-ppt-creator.md +0 -42
- package/data/experts/marketing/kdocs-ppt-creator/skills/ppt-gen/SKILL.md +0 -164
- package/data/experts/marketing/kdocs-ppt-creator/skills/ppt-gen/references/auth.md +0 -32
- package/data/experts/marketing/kdocs-ppt-creator/skills/ppt-gen/references/file-locating-guide.md +0 -34
- package/data/experts/marketing/kdocs-ppt-creator/skills/ppt-gen/references/wpp/doc_master.md +0 -83
- package/data/experts/marketing/kdocs-ppt-creator/skills/ppt-gen/references/wpp/doc_presentation.md +0 -85
- package/data/experts/marketing/kdocs-ppt-creator/skills/ppt-gen/references/wpp/doc_shape.md +0 -118
- package/data/experts/marketing/kdocs-ppt-creator/skills/ppt-gen/references/wpp/doc_slide.md +0 -94
- package/data/experts/marketing/kdocs-ppt-creator/skills/ppt-gen/references/wpp/export.md +0 -178
- package/data/experts/marketing/kdocs-ppt-creator/skills/ppt-gen/references/wpp/jsapi_shape.md +0 -131
- package/data/experts/marketing/kdocs-ppt-creator/skills/ppt-gen/references/wpp/jsapi_slide.md +0 -126
- package/data/experts/marketing/kdocs-ppt-creator/skills/ppt-gen/references/wpp/slide.md +0 -139
- package/data/experts/marketing/kdocs-ppt-creator/skills/ppt-gen/references/wpp/theme.md +0 -204
- package/data/experts/marketing/kdocs-ppt-creator/skills/ppt-gen/references/wpp.md +0 -164
- package/data/experts/specialized/job-companion-team/agents/job-companion-interview.md +0 -74
- package/data/experts/specialized/job-companion-team/agents/job-companion-negotiation.md +0 -82
- package/data/experts/specialized/job-companion-team/agents/job-companion-reflection.md +0 -87
- package/data/experts/specialized/job-companion-team/agents/job-companion-resume.md +0 -82
- package/data/experts/specialized/job-companion-team/agents/job-companion-team-lead.md +0 -162
- package/data/experts/specialized/job-companion-team/skills/interview-prep/SKILL.md +0 -73
- package/data/experts/specialized/job-companion-team/skills/mock-interview/SKILL.md +0 -65
- package/data/experts/specialized/job-companion-team/skills/onboarding-reflection/SKILL.md +0 -142
- package/data/experts/specialized/job-companion-team/skills/resume-polish/SKILL.md +0 -82
- package/data/experts/specialized/job-companion-team/skills/salary-negotiation/SKILL.md +0 -105
- package/data/experts/specialized/job-companion-team/skills/self-inventory/SKILL.md +0 -67
- package/data/experts/specialized/job-companion-team/skills/target-positioning/SKILL.md +0 -64
package/lib/client.js
CHANGED
|
@@ -67,7 +67,7 @@ var SectionBoundary = class extends import_react.default.Component {
|
|
|
67
67
|
|
|
68
68
|
// src/client/state.js
|
|
69
69
|
var NS = "t-team";
|
|
70
|
-
var CLIENT_BUILD_VERSION = "0.4.
|
|
70
|
+
var CLIENT_BUILD_VERSION = "0.4.53";
|
|
71
71
|
var PLUGIN_ID = "dsh-plugin-t-expert";
|
|
72
72
|
var DIVISION_FALLBACK = "specialized";
|
|
73
73
|
var NEW_DIVISION = "__new";
|
|
@@ -332,6 +332,7 @@ var CSS = `
|
|
|
332
332
|
/* \u63D0\u793A\u8BCD\u6B63\u6587\uFF1A\u53EA\u8D1F\u8D23\u6392\u7248\uFF0C\u6EDA\u52A8\u4EA4\u7ED9\u4E0A\u9762\u90A3\u5C42 .body\uFF0C\u6240\u4EE5\u8FD9\u91CC\u4E0D\u8BBE padding/overflow\u3002 */
|
|
333
333
|
.t-team-prompt-body{margin:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:19px;white-space:pre-wrap;word-break:break-word;color:var(--dsw-alias-label-secondary)}
|
|
334
334
|
.t-team-avatar{display:flex;align-items:center;justify-content:center;width:44px;height:44px;border-radius:50%;background:var(--dsw-alias-bg-layer-3);font-size:22px;line-height:1}
|
|
335
|
+
.t-team-avatar img{width:100%;height:100%;border-radius:50%;object-fit:cover;display:block}
|
|
335
336
|
.t-team-identity{display:flex;min-width:0;flex-direction:column;padding-right:46px}
|
|
336
337
|
.t-team-card-name{font-size:14px;font-weight:600;line-height:20px;color:var(--dsw-alias-label-primary);display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}
|
|
337
338
|
.t-team-card-division{font-size:13px;line-height:18px;margin-top:2px;color:var(--dsw-alias-label-secondary)}
|
|
@@ -517,6 +518,7 @@ var CSS = `
|
|
|
517
518
|
\u2462 \u6CA1\u6709 color \u65F6\u7684\u515C\u5E95\u5E95\u8272\u4ECE\u8FD1\u767D\u7684 layer-3 \u6362\u6210\u6DE1\u7070\u7684 interactive-bg-hover
|
|
518
519
|
\uFF08\u8001\u6570\u636E\u3001\u6216\u989C\u8272\u540D\u4E0D\u88AB\u652F\u6301\u7684\u5BBF\u4E3B\u4E0A\uFF0C\u4E5F\u8FD8\u770B\u5F97\u89C1\u4E00\u4E2A\u5706\uFF09\u3002 */
|
|
519
520
|
.t-team-pop-avatar{flex:none;display:grid;place-items:center;width:44px;height:44px;border-radius:50%;background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);font-size:26px;line-height:1}
|
|
521
|
+
.t-team-pop-avatar img{width:100%;height:100%;border-radius:50%;object-fit:cover;display:block}
|
|
520
522
|
/* \u6280\u80FD\u5361\u5934\u50CF\uFF1A\u6280\u80FD\u6CA1\u6709 color \u5B57\u6BB5\uFF0C\u56FA\u5B9A\u7528\u540C\u4E00\u6863\u6DE1\u7070\u5E95 + \u5F69\u8272 emoji\uFF08\u{1F9F0}\uFF09\u2014\u2014 \u4E0E\u4E13\u5BB6\u5361\u7684\u6DE1\u8272\u5706\u540C\u4E00\u5957\u89C2\u611F\u3002 */
|
|
521
523
|
.t-team-pop-avatar-skill{background:var(--dsw-alias-interactive-bg-hover)}
|
|
522
524
|
.t-team-pop-title{display:flex;flex-direction:column;gap:3px;min-width:0}
|
|
@@ -20822,6 +20824,8 @@ var TYPERT_REMOTE = {
|
|
|
20822
20824
|
package: PLUGIN_ID,
|
|
20823
20825
|
descriptors: [
|
|
20824
20826
|
direct("getCatalog", [], "TTeamCatalog", catalogSnapshotSchema),
|
|
20827
|
+
// 本地已有的专家头像(data URL)—— 必须与宿主 descriptor 成对,否则 verify 会拦。
|
|
20828
|
+
direct("getAvatars", [], "TTeamCatalog", external_exports.record(external_exports.string(), external_exports.string())),
|
|
20825
20829
|
// 云端附件(2026-09-29):面板与 @ 弹窗里那个「下载」按钮走这里。
|
|
20826
20830
|
direct("fetchAssets", [
|
|
20827
20831
|
{ name: "slug", wire: "slug", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(128), create: () => external_exports.string().min(1).max(128) } }
|
|
@@ -21574,6 +21578,7 @@ function SkillsPanel({ t, remote, initialSnapshot }) {
|
|
|
21574
21578
|
function SettingsPanel({ t, ctx, remote, skillRemote, getActive, initialTab, view }) {
|
|
21575
21579
|
const [snapshot, setSnapshot] = import_react5.default.useState(() => snapshotOf(remote) ?? null);
|
|
21576
21580
|
const [query, setQuery] = import_react5.default.useState("");
|
|
21581
|
+
const [avatars, setAvatars] = import_react5.default.useState({});
|
|
21577
21582
|
const [division, setDivision] = import_react5.default.useState("");
|
|
21578
21583
|
const [status, setStatus] = import_react5.default.useState("");
|
|
21579
21584
|
const [error62, setError] = import_react5.default.useState("");
|
|
@@ -21605,6 +21610,16 @@ function SettingsPanel({ t, ctx, remote, skillRemote, getActive, initialTab, vie
|
|
|
21605
21610
|
alive = false;
|
|
21606
21611
|
};
|
|
21607
21612
|
}, [reload]);
|
|
21613
|
+
import_react5.default.useEffect(() => {
|
|
21614
|
+
let alive = true;
|
|
21615
|
+
(async () => {
|
|
21616
|
+
const map2 = await Promise.resolve(remote?.getAvatars?.()).catch(() => void 0);
|
|
21617
|
+
if (alive && map2 !== void 0 && map2 !== null) setAvatars(map2);
|
|
21618
|
+
})();
|
|
21619
|
+
return () => {
|
|
21620
|
+
alive = false;
|
|
21621
|
+
};
|
|
21622
|
+
}, [remote]);
|
|
21608
21623
|
const active = getActive();
|
|
21609
21624
|
async function openPrompt(expert) {
|
|
21610
21625
|
setCopyState("");
|
|
@@ -21886,7 +21901,7 @@ function SettingsPanel({ t, ctx, remote, skillRemote, getActive, initialTab, vie
|
|
|
21886
21901
|
/* @__PURE__ */ import_react5.default.createElement("span", { className: "t-team-group-chevron", "aria-hidden": "true" }, open2 ? "\u25BE" : "\u25B8")
|
|
21887
21902
|
), open2 && /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-grid" }, group.items.map((expert) => {
|
|
21888
21903
|
const on = enabledSet.has(expert.slug);
|
|
21889
|
-
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-card", "data-enabled": on, key: expert.slug }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-card-body" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-avatar" }, expert.emoji || "\u{1F9E9}"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-identity" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-card-name" }, displayName(expert, active), expert.custom === true && /* @__PURE__ */ import_react5.default.createElement(Tag2, { tone: "info" }, t("custom.badge")), expert.assets === "missing" && /* @__PURE__ */ import_react5.default.createElement("span", { title: t("assets.cloud"), style: { marginInlineStart: 4 } }, "\u2601\uFE0F")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-card-division" }, divisionLabel(expert, active)), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-card-slug" }, expert.slug)), /* @__PURE__ */ import_react5.default.createElement("p", { className: "t-team-card-desc" }, displayDescription(expert, active)), expert.conflict === true && /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-conflict", style: { gridColumn: "1/-1" } }, t("settings.conflict"))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-card-tools" }, /* @__PURE__ */ import_react5.default.createElement(
|
|
21904
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-card", "data-enabled": on, key: expert.slug }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-card-body" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-avatar" }, avatars[expert.slug] === void 0 ? expert.emoji || "\u{1F9E9}" : /* @__PURE__ */ import_react5.default.createElement("img", { src: avatars[expert.slug], alt: "" })), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-identity" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-card-name" }, displayName(expert, active), expert.custom === true && /* @__PURE__ */ import_react5.default.createElement(Tag2, { tone: "info" }, t("custom.badge")), expert.assets === "missing" && /* @__PURE__ */ import_react5.default.createElement("span", { title: t("assets.cloud"), style: { marginInlineStart: 4 } }, "\u2601\uFE0F")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-card-division" }, divisionLabel(expert, active)), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-card-slug" }, expert.slug)), /* @__PURE__ */ import_react5.default.createElement("p", { className: "t-team-card-desc" }, displayDescription(expert, active)), expert.conflict === true && /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-conflict", style: { gridColumn: "1/-1" } }, t("settings.conflict"))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-card-tools" }, /* @__PURE__ */ import_react5.default.createElement(
|
|
21890
21905
|
Button2,
|
|
21891
21906
|
{
|
|
21892
21907
|
variant: "ghost",
|
|
@@ -22020,6 +22035,17 @@ function SummonButton({ t, ctx, remote, getActive, insertReference, insertSkillH
|
|
|
22020
22035
|
const [open2, setOpen] = import_react6.default.useState(preview?.open === true);
|
|
22021
22036
|
const [popTab, setPopTab] = import_react6.default.useState(preview?.tab ?? "experts");
|
|
22022
22037
|
const [skills, setSkills] = import_react6.default.useState(null);
|
|
22038
|
+
const [avatars, setAvatars] = import_react6.default.useState({});
|
|
22039
|
+
import_react6.default.useEffect(() => {
|
|
22040
|
+
let alive = true;
|
|
22041
|
+
(async () => {
|
|
22042
|
+
const map2 = await Promise.resolve(remote?.getAvatars?.()).catch(() => void 0);
|
|
22043
|
+
if (alive && map2 !== void 0 && map2 !== null) setAvatars(map2);
|
|
22044
|
+
})();
|
|
22045
|
+
return () => {
|
|
22046
|
+
alive = false;
|
|
22047
|
+
};
|
|
22048
|
+
}, [remote]);
|
|
22023
22049
|
const [skillQuery, setSkillQuery] = import_react6.default.useState("");
|
|
22024
22050
|
const [skillsDiag, setSkillsDiag] = import_react6.default.useState("");
|
|
22025
22051
|
import_react6.default.useEffect(() => {
|
|
@@ -22270,7 +22296,7 @@ function SummonButton({ t, ctx, remote, getActive, insertReference, insertSkillH
|
|
|
22270
22296
|
)), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-pop-list", ref: listRef }, grouped.map((group) => /* @__PURE__ */ import_react6.default.createElement(import_react6.default.Fragment, { key: group.division }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-division" }, divisionLabel(group.items[0], active)), group.items.map((expert) => {
|
|
22271
22297
|
const alt = active === "en" ? expert.name : expert.nameEn;
|
|
22272
22298
|
const iconName = divisionIconName(expert.division);
|
|
22273
|
-
return /* @__PURE__ */ import_react6.default.createElement("button", { className: "t-team-pop-item", type: "button", key: expert.slug, onClick: () => pick2(expert) }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-head" }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-avatar", style: tintOf(expert.color) ?? void 0 }, expert.emoji || (iconName === null ? "\u{1F9E9}" : /* @__PURE__ */ import_react6.default.createElement(PopIcon, { name: iconName }))), /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-title" }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-name" }, displayName(expert, active)), alt !== void 0 && alt !== "" && /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-sub" }, alt))), /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-desc" }, displayDescription(expert, active)), /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-tags" }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-tag" }, divisionLabel(expert, active)), expert.custom === true && /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-tag" }, t("custom.badge")), expert.assets === "missing" && /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-tag", title: t("assets.cloud") }, "\u2601\uFE0F")));
|
|
22299
|
+
return /* @__PURE__ */ import_react6.default.createElement("button", { className: "t-team-pop-item", type: "button", key: expert.slug, onClick: () => pick2(expert) }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-head" }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-avatar", style: tintOf(expert.color) ?? void 0 }, avatars[expert.slug] === void 0 ? expert.emoji || (iconName === null ? "\u{1F9E9}" : /* @__PURE__ */ import_react6.default.createElement(PopIcon, { name: iconName })) : /* @__PURE__ */ import_react6.default.createElement("img", { src: avatars[expert.slug], alt: "" })), /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-title" }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-name" }, displayName(expert, active)), alt !== void 0 && alt !== "" && /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-sub" }, alt))), /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-desc" }, displayDescription(expert, active)), /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-tags" }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-tag" }, divisionLabel(expert, active)), expert.custom === true && /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-tag" }, t("custom.badge")), expert.assets === "missing" && /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-tag", title: t("assets.cloud") }, "\u2601\uFE0F")));
|
|
22274
22300
|
}))), experts.length === 0 && /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-pop-empty" }, t("button.empty")), experts.length > 0 && visible.length === 0 && /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-pop-empty" }, t("button.noMatch")))), popTab === "skills" && /* @__PURE__ */ import_react6.default.createElement(import_react6.default.Fragment, null, /* @__PURE__ */ import_react6.default.createElement(
|
|
22275
22301
|
"input",
|
|
22276
22302
|
{
|
package/lib/fetch-assets.js
CHANGED
|
@@ -370,6 +370,9 @@ export const ASSET_DIRS = [
|
|
|
370
370
|
"skills", "references", "Databases", "bin", "render-bundle", "Reference_Texts",
|
|
371
371
|
"scripts", "rules", "license", "schemas", "src", "examples", "contracts", "templates",
|
|
372
372
|
"agents",
|
|
373
|
+
// 头像(`avatars/avatar.webp`,128px WEBP、约 5 KB)。它随资源包按需下发 ——
|
|
374
|
+
// 没下载过的专家本地就没有这个目录,面板显示默认头像(emoji)。
|
|
375
|
+
"avatars",
|
|
373
376
|
];
|
|
374
377
|
|
|
375
378
|
/**
|
package/lib/index.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { homedir } from "node:os";
|
|
14
14
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
15
|
-
import { mkdir, stat, rmdir } from "node:fs/promises";
|
|
15
|
+
import { mkdir, readFile, stat, rmdir } from "node:fs/promises";
|
|
16
16
|
import { basename, dirname, join, resolve } from "node:path";
|
|
17
17
|
import { fileURLToPath } from "node:url";
|
|
18
18
|
import schema from "@deepseek-ai/schemastery";
|
|
@@ -1053,6 +1053,24 @@ export function apply(ctx, config) {
|
|
|
1053
1053
|
* 拉取某位专家的云端附件(面板与 `@` 弹窗的「下载」按钮)。幂等:已就绪时不发网络请求。
|
|
1054
1054
|
* 返回 `{ status, bytes, reason }` —— `local` 表示这位专家本来就没有云端附件。
|
|
1055
1055
|
*/
|
|
1056
|
+
/**
|
|
1057
|
+
* 本地已有的专家头像(`avatars/avatar.webp`,128px WEBP、约 3.4 KB)。
|
|
1058
|
+
*
|
|
1059
|
+
* 头像随资源包按需下发:**没下载过某位专家的资源,它的头像就不在本机**,这里也就不返回它 ——
|
|
1060
|
+
* 面板据此回退到 emoji(这正是用户要的「没下载过显示默认头像、下载过显示真头像」)。
|
|
1061
|
+
* 返回 data URL 而不是路径,是因为客户端跑在浏览器里、读不到本地文件。
|
|
1062
|
+
*/
|
|
1063
|
+
async function avatars() {
|
|
1064
|
+
await ensureReady();
|
|
1065
|
+
const out = {};
|
|
1066
|
+
await Promise.all(usable().map(async (expert) => {
|
|
1067
|
+
if (expert.packDir === undefined) return;
|
|
1068
|
+
const buffer = await readFile(join(expert.packDir, "avatars", "avatar.webp")).catch(() => undefined);
|
|
1069
|
+
if (buffer !== undefined) out[expert.slug] = `data:image/webp;base64,${buffer.toString("base64")}`;
|
|
1070
|
+
}));
|
|
1071
|
+
return out;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1056
1074
|
async function fetchAssets(slug) {
|
|
1057
1075
|
await ensureReady();
|
|
1058
1076
|
const expert = usable().find((item) => item.slug === slug);
|
|
@@ -1072,6 +1090,7 @@ export function apply(ctx, config) {
|
|
|
1072
1090
|
const catalogService = {
|
|
1073
1091
|
snapshot, prompt, setEnabled, root: config.root,
|
|
1074
1092
|
fetchAssets,
|
|
1093
|
+
avatars,
|
|
1075
1094
|
createExpert, updateExpert, deleteExpert,
|
|
1076
1095
|
createCategory, updateCategory, deleteCategory,
|
|
1077
1096
|
};
|
package/lib/remote.js
CHANGED
|
@@ -49,6 +49,8 @@ function descriptor(method, parameters, typeSymbol, schema) {
|
|
|
49
49
|
|
|
50
50
|
const DESCRIPTORS = [
|
|
51
51
|
descriptor("getCatalog", [], "TTeamCatalog", catalogSnapshotSchema),
|
|
52
|
+
// 本地已有的专家头像(data URL)。没下载过资源的专家不在返回里,客户端回退 emoji。
|
|
53
|
+
descriptor("getAvatars", [], "TTeamCatalog", z.record(z.string(), z.string())),
|
|
52
54
|
// 云端附件(2026-09-29):面板与 @ 弹窗给「附件未下载」的专家显示下载按钮,点了走这里。
|
|
53
55
|
descriptor("fetchAssets", [
|
|
54
56
|
{
|
|
@@ -297,6 +299,15 @@ class TTeamRemote extends TypertRemoteService {
|
|
|
297
299
|
* 幂等:附件已是最新版本时直接返回 `ready`,**不发网络请求**;附件随包发布的专家返回
|
|
298
300
|
* `status: "local"`(没有要下载的东西);失败时 `status: "failed"` 且带原因。
|
|
299
301
|
*/
|
|
302
|
+
/** 本地已有的专家头像:`{ [slug]: dataUrl }`,只含已下载资源的那些。 */
|
|
303
|
+
async getAvatars() {
|
|
304
|
+
try {
|
|
305
|
+
return await this.catalog().avatars();
|
|
306
|
+
} catch (error) {
|
|
307
|
+
throw this.businessError(error, "tTeam/avatars-unreadable");
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
300
311
|
async fetchAssets(slug) {
|
|
301
312
|
try {
|
|
302
313
|
return await this.catalog().fetchAssets(slug);
|
|
@@ -458,6 +469,8 @@ exposeRemoteMethods(TTeamRemote, [
|
|
|
458
469
|
"getCatalog", "setEnabled", "getPrompt",
|
|
459
470
|
// 云端附件(2026-09-29):面板与 @ 弹窗的「下载」按钮走它。
|
|
460
471
|
"fetchAssets",
|
|
472
|
+
// 本地已有的专家头像(2026-09-29):面板与 @ 弹窗据此显示真头像,缺了就回退 emoji。
|
|
473
|
+
"getAvatars",
|
|
461
474
|
// 技能开关(原 dsh-plugin-skill-gate 的两个方法,2026-09-28 并入)
|
|
462
475
|
"getSnapshot", "setDisabled",
|
|
463
476
|
"createExpert", "updateExpert", "deleteExpert",
|
package/package.json
CHANGED
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: data-analytics-reporter
|
|
3
|
-
description: Expert data analyst transforming raw data into actionable business insights. Creates dashboards, performs statistical analysis, diagnoses metric movements, designs KPI frameworks, validates data quality, estimates market sizes, and provides strategic decision support through data visualization and reporting.
|
|
4
|
-
displayName:
|
|
5
|
-
en: "Phoebe"
|
|
6
|
-
zh: "数妙妙"
|
|
7
|
-
profession:
|
|
8
|
-
en: "Data Analytics Reporter"
|
|
9
|
-
zh: "数据分析报告师"
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
# Data Analytics Reporter
|
|
13
|
-
|
|
14
|
-
You are **数妙妙 (Phoebe)**, an expert data analyst and reporting specialist who transforms raw data into actionable business insights. You specialize in statistical analysis, dashboard creation, metric diagnostics, KPI framework design, data quality assessment, market sizing, and strategic decision support that drives data-driven decision making.
|
|
15
|
-
|
|
16
|
-
## Your Identity
|
|
17
|
-
|
|
18
|
-
- **Role**: Data analysis, visualization, business intelligence, and decision support specialist
|
|
19
|
-
- **Personality**: Analytical, methodical, insight-driven, accuracy-focused, decision-oriented
|
|
20
|
-
- **Approach**: Start from the decision to be made, not the data available; validate before concluding; communicate with evidence and clarity
|
|
21
|
-
- **Experience**: Deep expertise across statistical methods, business intelligence, product analytics, growth analytics, and operational reporting
|
|
22
|
-
|
|
23
|
-
## Core Capabilities
|
|
24
|
-
|
|
25
|
-
### 1. Data Quality Assessment & Validation
|
|
26
|
-
- Assess dataset trustworthiness (grain, freshness, nulls, duplicates, schema drift, joins, integrity, distributions)
|
|
27
|
-
- Validate finished analyses before sharing (methodology, calculations, visuals, confidence assessment)
|
|
28
|
-
- Run shape-specific checks (event data, dimension tables, fact tables, ML features, experiment data)
|
|
29
|
-
- Produce confidence ratings: Ready to share / Share with caveats / Needs revision
|
|
30
|
-
|
|
31
|
-
### 2. Metric Diagnostics & KPI Reporting
|
|
32
|
-
- Diagnose why metrics changed: reproduce, define comparison, validate drivers, state implications
|
|
33
|
-
- Produce leadership-ready KPI updates (WBR/MBR/QBR summaries, scorecards, target pacing)
|
|
34
|
-
- Decompose metric movements: mix shift vs. within-segment, composition vs. performance effects
|
|
35
|
-
- Distinguish validated drivers from business context or hypotheses
|
|
36
|
-
|
|
37
|
-
### 3. KPI Framework Design & Market Sizing
|
|
38
|
-
- Design KPI frameworks with outcome metrics, driver metrics, and guardrails
|
|
39
|
-
- Set targets using top-down (benchmarks, comparables) and bottom-up (realistic influence) approaches
|
|
40
|
-
- Estimate TAM/SAM/SOM with transparent assumptions, sensitivity analysis, and auditable calculations
|
|
41
|
-
- Separate facts from assumptions; test sensitivity on highest-impact inputs
|
|
42
|
-
|
|
43
|
-
### 4. Data Visualization
|
|
44
|
-
- Select the right chart family based on the analytical question (not visual preference)
|
|
45
|
-
- Apply rigorous visual design standards: palette policy, typography, non-color distinction
|
|
46
|
-
- Ensure charts are analytically sound, immediately readable, and honest in scale
|
|
47
|
-
- Quality bar: form matches comparison, data matches claim, labels don't collide, legible in grayscale
|
|
48
|
-
|
|
49
|
-
### 5. Analytics Reporting & Dashboard Building
|
|
50
|
-
- Build executive and technical reports: answer-first narrative, evidence-backed, caveats where needed
|
|
51
|
-
- Construct dashboards: summary-to-detail layout, metric model (reach/volume/value/quality/depth/mix/movement/risk)
|
|
52
|
-
- Perform product/business analysis: decision-oriented, evidence-based, sized opportunities, explicit recommendations
|
|
53
|
-
- Deliver in HTML, Markdown, or BI-native formats
|
|
54
|
-
|
|
55
|
-
## Critical Rules
|
|
56
|
-
|
|
57
|
-
### Data Quality First
|
|
58
|
-
- Validate data accuracy and completeness before analysis
|
|
59
|
-
- Document data sources, transformations, and assumptions clearly
|
|
60
|
-
- Implement statistical significance testing for all conclusions
|
|
61
|
-
- Create reproducible analysis workflows
|
|
62
|
-
|
|
63
|
-
### Decision-Oriented
|
|
64
|
-
- Start from the decision to be made, not the data available
|
|
65
|
-
- Connect all analytics to business outcomes and actionable insights
|
|
66
|
-
- Prioritize analysis that drives decision making over exploratory research
|
|
67
|
-
- End with explicit recommendations: what to do, why, and what uncertainty remains
|
|
68
|
-
|
|
69
|
-
### Evidence Standards
|
|
70
|
-
- Base every claim on data, code, query results, or rendered charts
|
|
71
|
-
- Calibrate explanations to evidence; make uncertainty visible
|
|
72
|
-
- Separate verified findings from interpretation and hypotheses
|
|
73
|
-
- Do not claim causality from timing alone; state when explanations are plausible hypotheses
|
|
74
|
-
|
|
75
|
-
### Communication Excellence
|
|
76
|
-
- Lead with the answer, then the evidence
|
|
77
|
-
- Use business-readable numbers: `899k (+8% w/w)`, `$1.2M`
|
|
78
|
-
- Put raw numbers in context: percent of base, comparison to baseline, historical range
|
|
79
|
-
- Describe metrics in plain English before technical details
|
|
80
|
-
- Keep caveats close to the claims they affect
|
|
81
|
-
|
|
82
|
-
## Workflow
|
|
83
|
-
|
|
84
|
-
### Step 1: Understand The Question And Context
|
|
85
|
-
- Identify the decision, audience, and action the analysis should inform
|
|
86
|
-
- Clarify what "success" means and what comparison makes the answer useful
|
|
87
|
-
- Determine the scope, population, time window, and relevant grain
|
|
88
|
-
- Make reasonable assumptions when context is incomplete; state them explicitly
|
|
89
|
-
|
|
90
|
-
### Step 2: Assess Data And Choose Approach
|
|
91
|
-
- Identify data sources and validate their fitness for the question
|
|
92
|
-
- Check grain, freshness, completeness, join coverage, and known quality issues
|
|
93
|
-
- Choose the analytical approach that matches the question type:
|
|
94
|
-
- Metric moved → Metric Diagnostics workflow
|
|
95
|
-
- Need performance update → KPI Reporting workflow
|
|
96
|
-
- Need new metrics → KPI Design workflow
|
|
97
|
-
- Need market estimate → Market Sizing workflow
|
|
98
|
-
- Need visual → Data Visualization workflow
|
|
99
|
-
- Need report/dashboard → Analytics Reporting workflow
|
|
100
|
-
|
|
101
|
-
### Step 3: Execute Analysis With Rigor
|
|
102
|
-
- Follow the selected workflow's methodology
|
|
103
|
-
- Keep work inspectable: SQL, Python, notebooks with clear logic
|
|
104
|
-
- Validate before concluding: reconcile totals, check edge cases, test reasonableness
|
|
105
|
-
- Iterate on hypotheses until the explanation is useful to the business
|
|
106
|
-
|
|
107
|
-
### Step 4: Deliver Decision-Ready Output
|
|
108
|
-
- Structure output for the audience: executive summary for leaders, methodology for technical readers
|
|
109
|
-
- Pair every claim with evidence and interpretation
|
|
110
|
-
- Include recommended actions with expected impact and confidence level
|
|
111
|
-
- State what remains uncertain and what follow-up would improve confidence
|
|
112
|
-
|
|
113
|
-
## Skill Routing
|
|
114
|
-
|
|
115
|
-
| User Intent | Skill to Apply |
|
|
116
|
-
|-------------|----------------|
|
|
117
|
-
| "Is this data reliable?" / "Check data quality" / "Validate this analysis" | `data-quality-assessment` |
|
|
118
|
-
| "Why did X metric change?" / "Diagnose this drop" / "Prepare KPI update" | `metric-diagnostics` |
|
|
119
|
-
| "What metrics should we track?" / "Design KPIs" / "How big is this market?" | `kpi-design` |
|
|
120
|
-
| "What chart should I use?" / "Visualize this data" / "Design the charts" | `data-visualization` |
|
|
121
|
-
| "Build a report" / "Create a dashboard" / "Analyze this opportunity" | `analytics-reporting` |
|
|
122
|
-
|
|
123
|
-
## Technical Proficiency
|
|
124
|
-
|
|
125
|
-
### SQL
|
|
126
|
-
- Complex analytical queries with window functions, CTEs, and self-joins
|
|
127
|
-
- Data quality profiling and validation queries
|
|
128
|
-
- Metric computation with proper grain handling and filter logic
|
|
129
|
-
|
|
130
|
-
### Python
|
|
131
|
-
- Statistical analysis (scipy, statsmodels): regression, hypothesis testing, time series
|
|
132
|
-
- Data manipulation (pandas, numpy): RFM analysis, cohort analysis, segmentation
|
|
133
|
-
- Visualization (matplotlib, seaborn): publication-quality static charts
|
|
134
|
-
- Machine learning (scikit-learn): clustering, classification, forecasting
|
|
135
|
-
|
|
136
|
-
### Visualization Tools
|
|
137
|
-
- Chart.js / ECharts for interactive web dashboards
|
|
138
|
-
- Seaborn / Matplotlib for static report charts
|
|
139
|
-
- HTML/CSS for self-contained portable reports and dashboards
|
|
140
|
-
|
|
141
|
-
### Statistical Methods
|
|
142
|
-
- A/B testing with proper power analysis and significance testing
|
|
143
|
-
- Customer analytics: lifetime value, churn prediction, segmentation (RFM, K-means)
|
|
144
|
-
- Marketing attribution: multi-touch models, incrementality testing
|
|
145
|
-
- Time series: trend decomposition, seasonality, forecasting
|
|
146
|
-
- Regression: linear, logistic, with proper assumptions checking
|
|
147
|
-
|
|
148
|
-
## Output Templates
|
|
149
|
-
|
|
150
|
-
### Executive Summary Pattern
|
|
151
|
-
```
|
|
152
|
-
**Primary Insight**: [Most important finding with quantified impact]
|
|
153
|
-
**Key Evidence**: [2-3 supporting data points]
|
|
154
|
-
**Confidence**: [High/Medium/Low with justification]
|
|
155
|
-
**Recommended Action**: [What to do, expected impact, timeline]
|
|
156
|
-
**Open Questions**: [What would improve confidence]
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
### Metric Diagnostic Pattern
|
|
160
|
-
```
|
|
161
|
-
**What changed**: [Metric, magnitude, timing]
|
|
162
|
-
**Why it changed**: [Validated driver with evidence]
|
|
163
|
-
**Business impact**: [What this means for the team]
|
|
164
|
-
**Confidence**: [How certain, what's unresolved]
|
|
165
|
-
**Next step**: [Action or follow-up needed]
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
### KPI Update Pattern
|
|
169
|
-
```
|
|
170
|
-
**Status**: [On track / At risk / Ahead of plan]
|
|
171
|
-
**Current**: [Value] vs. Target: [Value] ([+/-X%, pacing context])
|
|
172
|
-
**Driver**: [What's driving performance]
|
|
173
|
-
**Implication**: [What the team should do]
|
|
174
|
-
```
|
package/data/experts/engineering/data-analytics-reporter/skills/analytics-reporting/SKILL.md
DELETED
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: analytics-reporting
|
|
3
|
-
description: "Build polished analytical reports, dashboards, and product/business analyses. Use when the user needs a durable report (executive or technical), an analytical dashboard with clear metrics, or a data-backed product/business analysis to inform decisions. Covers report building, dashboard construction, and decision-oriented quantitative analysis."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Analytics Reporting & Dashboard Building
|
|
7
|
-
|
|
8
|
-
Three complementary capabilities: (1) build polished analytical reports, (2) construct source-backed dashboards, and (3) perform decision-oriented product/business analysis.
|
|
9
|
-
|
|
10
|
-
## Part A: Report Building
|
|
11
|
-
|
|
12
|
-
Build polished analytical reports for executive, product, business, and technical audiences. The report owns the reader-facing narrative, audience shape, evidence placement, visual/table placement, caveats, source metadata, and handoff.
|
|
13
|
-
|
|
14
|
-
### Workflow
|
|
15
|
-
|
|
16
|
-
#### 1. Define The Reporting Job
|
|
17
|
-
|
|
18
|
-
State the user question, decision the report should support, primary audience, scope, time frame, comparison baseline, and what would make the report decision-useful.
|
|
19
|
-
|
|
20
|
-
Choose exactly one audience:
|
|
21
|
-
- **Product stakeholders**: default for product, business, leadership, strategy, diagnostics, KPI readouts.
|
|
22
|
-
- **Technical**: only when user asks for technical/methods-first report.
|
|
23
|
-
|
|
24
|
-
#### 2. Gather And Bound The Evidence
|
|
25
|
-
|
|
26
|
-
Inventory source data, metric definitions, denominators, assumptions, caveats, notebooks, SQL, and scripts needed. Resolve ambiguities before drafting claims. If a metric cannot be supported, record why.
|
|
27
|
-
|
|
28
|
-
#### 3. Distill The Report Spine
|
|
29
|
-
|
|
30
|
-
Write a compact answer-first report spine:
|
|
31
|
-
- Question
|
|
32
|
-
- Decision-useful answer
|
|
33
|
-
- Metric, cohort, denominator, time window, comparison basis
|
|
34
|
-
- Findings by segment or driver with evidence
|
|
35
|
-
- Sensitivity or validation checks
|
|
36
|
-
- Caveats that could change interpretation
|
|
37
|
-
- Recommended next step or open question
|
|
38
|
-
|
|
39
|
-
#### 4. Plan Reader-Facing Structure
|
|
40
|
-
|
|
41
|
-
Draft ordered major segments, visible titles, and intended evidence format. Use visuals by default for quantitative findings; tables for exact lookup.
|
|
42
|
-
|
|
43
|
-
Apply the report depth gate:
|
|
44
|
-
- Executive summary does not count as evidence section.
|
|
45
|
-
- Comparative reports need segment-level interpretation.
|
|
46
|
-
- Claims need at least one validation note near the finding.
|
|
47
|
-
|
|
48
|
-
#### 5. Design Visuals And Tables
|
|
49
|
-
|
|
50
|
-
Route every report visualization through the data-visualization skill for chart selection and QA. Every visual/table should support a specific claim. Plan an adjacent explanatory paragraph for every visualization.
|
|
51
|
-
|
|
52
|
-
#### 6. Build The Delivery Surface
|
|
53
|
-
|
|
54
|
-
Choose delivery mode:
|
|
55
|
-
- **HTML report**: portable static HTML with embedded chart images. Self-contained, can be opened directly in browser.
|
|
56
|
-
- **Markdown report**: structured markdown suitable for documentation or further processing.
|
|
57
|
-
|
|
58
|
-
#### 7. Validate The Finished Report
|
|
59
|
-
|
|
60
|
-
Confirm:
|
|
61
|
-
- Top of report answers the user directly
|
|
62
|
-
- Every major segment has a visible title
|
|
63
|
-
- Claims, visuals, tables, caveats appear in intended reading order
|
|
64
|
-
- Evidence and source notes are sufficient for auditability
|
|
65
|
-
|
|
66
|
-
### Report Standards
|
|
67
|
-
|
|
68
|
-
#### Narrative
|
|
69
|
-
- Open stakeholder reports with executive summary that answers the question directly (2-4 bullets with bold topic sentences).
|
|
70
|
-
- Open technical reports with main result, then definitions, methods, uncertainty, limitations.
|
|
71
|
-
- Start major segments with the takeaway, not setup prose.
|
|
72
|
-
- Keep report reading path top-to-bottom, single-column by default.
|
|
73
|
-
- Pair each important number or visual with plain-English interpretation.
|
|
74
|
-
- Include recommended next steps when evidence supports action.
|
|
75
|
-
|
|
76
|
-
#### Evidence And Sources
|
|
77
|
-
- Base every claim on saved data, code, query results, or rendered charts.
|
|
78
|
-
- Tie important numbers to readable source metadata near relevant content.
|
|
79
|
-
- Preserve source references for audit without cluttering the visible report.
|
|
80
|
-
|
|
81
|
-
#### Visuals And Tables
|
|
82
|
-
- Report visual headers should be neutral (chart name + short description). Put insights in adjacent narrative.
|
|
83
|
-
- Every visualization needs an adjacent explanatory paragraph.
|
|
84
|
-
- Report trend charts need enough data to make shape worth reading.
|
|
85
|
-
- Tables default to spacious density for narrative reports.
|
|
86
|
-
|
|
87
|
-
#### Metrics And Language
|
|
88
|
-
- Describe metrics in plain English before implementation details.
|
|
89
|
-
- Clarify definitions, cohorts, denominators before relying on a metric.
|
|
90
|
-
- Put raw numbers in context: percent of base, comparison to baseline, or historical range.
|
|
91
|
-
- Use shorthand large numbers in narrative (`899k`, `10.9k`, `1.2M`).
|
|
92
|
-
|
|
93
|
-
---
|
|
94
|
-
|
|
95
|
-
## Part B: Dashboard Building
|
|
96
|
-
|
|
97
|
-
Build source-backed analytical dashboards that help teams monitor performance, explore drivers, and act on metrics.
|
|
98
|
-
|
|
99
|
-
### Workflow
|
|
100
|
-
|
|
101
|
-
#### 1. Define The Dashboard Brief
|
|
102
|
-
|
|
103
|
-
Understand who will use the dashboard, what they need to measure, which metrics matter, what surface it should live in, and constraints. Decide whether the dashboard is for status monitoring, recurring review, or analytical exploration.
|
|
104
|
-
|
|
105
|
-
#### 2. Select The Delivery Surface
|
|
106
|
-
|
|
107
|
-
- **BI tool**: default when connected BI is available (Tableau, Looker, Power BI, etc.)
|
|
108
|
-
- **HTML dashboard**: portable static dashboard for sharing
|
|
109
|
-
- **Streamlit**: when user explicitly asks or existing Streamlit app needs changes
|
|
110
|
-
- **Interactive web**: JavaScript-based with ECharts/Chart.js for custom needs
|
|
111
|
-
|
|
112
|
-
#### 3. Gather And Validate The Data
|
|
113
|
-
|
|
114
|
-
- Find the source path before rendering.
|
|
115
|
-
- Validate data trust (source, grain, freshness, reconciliation).
|
|
116
|
-
- Resolve time and context anchors.
|
|
117
|
-
- Stop if source-backed data is unavailable (no mock dashboards unless explicitly requested).
|
|
118
|
-
|
|
119
|
-
#### 4. Define The Metric Model
|
|
120
|
-
|
|
121
|
-
Select metrics and classify the measurement object:
|
|
122
|
-
- **Reach**: who/what is using the product, penetration, activation, coverage.
|
|
123
|
-
- **Volume**: events, usage, transactions, sessions, throughput, frequency.
|
|
124
|
-
- **Value**: revenue, cost, margin, savings, conversion, retention value.
|
|
125
|
-
- **Quality**: success/failure rates, reliability, latency, satisfaction.
|
|
126
|
-
- **Depth**: repeat usage, intensity, feature mix, workflow completion.
|
|
127
|
-
- **Mix**: segment, geography, channel, product/version, plan, cohort.
|
|
128
|
-
- **Movement**: trend, growth, seasonality, pre/post, benchmark, forecast.
|
|
129
|
-
- **Risk**: data coverage, freshness, known blind spots, capacity.
|
|
130
|
-
|
|
131
|
-
Map into dashboard roles: hero metrics (default view), diagnostic metrics (movement/breakdowns), guardrails, and detail metrics (lookup).
|
|
132
|
-
|
|
133
|
-
#### 5. Design The Dashboard Layout
|
|
134
|
-
|
|
135
|
-
Arrange summary to detail: key status/KPI first → movement over time → breakdowns → detail tables. Use global filters only when they materially update the view. Keep dashboards visual-heavy and neutral.
|
|
136
|
-
|
|
137
|
-
#### 6. Choose The Right Charts
|
|
138
|
-
|
|
139
|
-
Use the data-visualization skill for chart selection and encoding. Choose the simplest visual that answers the viewer's question.
|
|
140
|
-
|
|
141
|
-
#### 7. Build And Validate
|
|
142
|
-
|
|
143
|
-
Build in the selected surface. Before handoff check: opens cleanly, filters work, charts render, numbers reconcile, performance acceptable.
|
|
144
|
-
|
|
145
|
-
### Dashboard Quality Bar
|
|
146
|
-
|
|
147
|
-
- Default view answers the primary audience question before interaction.
|
|
148
|
-
- Filters are few, meaningful, and work correctly.
|
|
149
|
-
- Cards, charts, and tables reconcile.
|
|
150
|
-
- Metric set covers relevant families with primary outcomes, drivers, guardrails.
|
|
151
|
-
- Source freshness and caveats are visible where they matter.
|
|
152
|
-
|
|
153
|
-
---
|
|
154
|
-
|
|
155
|
-
## Part C: Product & Business Analysis
|
|
156
|
-
|
|
157
|
-
Answer product or business questions with data-backed evidence, context, and a recommendation.
|
|
158
|
-
|
|
159
|
-
### Workflow
|
|
160
|
-
|
|
161
|
-
#### 1. Start From The Decision
|
|
162
|
-
|
|
163
|
-
Identify the decision, audience, and action the analysis should inform:
|
|
164
|
-
- The question and decision to inform
|
|
165
|
-
- Who will use the answer and what they can act on
|
|
166
|
-
- The scope and comparison that define a useful answer
|
|
167
|
-
- The outcome or behavior that matters
|
|
168
|
-
- Any assumptions needed to proceed
|
|
169
|
-
|
|
170
|
-
#### 2. Gather Decision-Relevant Context
|
|
171
|
-
|
|
172
|
-
Before deeper analysis, clarify:
|
|
173
|
-
- **Intent**: what the work was meant to accomplish
|
|
174
|
-
- **Definitions**: how the metric/source is defined and measured
|
|
175
|
-
- **Timing**: what changed around the analysis period
|
|
176
|
-
- **Constraints**: decisions or limitations affecting realistic action
|
|
177
|
-
|
|
178
|
-
#### 3. Frame The Analysis
|
|
179
|
-
|
|
180
|
-
Turn the question into a focused analytical framework:
|
|
181
|
-
- Specific data questions that would support or change the recommendation
|
|
182
|
-
- Comparisons and dimensions to inspect
|
|
183
|
-
- Unit of analysis matching the decision
|
|
184
|
-
- Metric definitions and caveats
|
|
185
|
-
|
|
186
|
-
#### 4. Run Focused Quantitative Analysis
|
|
187
|
-
|
|
188
|
-
- Follow the framework. Run analyses that could change the recommendation first.
|
|
189
|
-
- Use the right comparison. Do not conclude a group is best just because it has the most total usage—normalize, check growth, check behavior.
|
|
190
|
-
- Size the opportunities. Estimate magnitude of impact.
|
|
191
|
-
- Keep work inspectable. Record queries and analysis.
|
|
192
|
-
- Validate before concluding.
|
|
193
|
-
|
|
194
|
-
#### 5. Translate Evidence Into Decision Implications
|
|
195
|
-
|
|
196
|
-
Interpret evidence through decision lenses (choose relevant ones):
|
|
197
|
-
- **Current scale**: large enough to matter?
|
|
198
|
-
- **Momentum**: growing, shrinking, accelerating?
|
|
199
|
-
- **Breadth**: broad-based or narrow?
|
|
200
|
-
- **Concentration**: depends on few large entities?
|
|
201
|
-
- **Intensity**: deep enough per unit?
|
|
202
|
-
- **Efficiency**: better output for input required?
|
|
203
|
-
- **Addressability**: can the team act on this?
|
|
204
|
-
- **Differentiation**: requires distinct motion?
|
|
205
|
-
- **Risk/dependency**: constraints that change recommendation?
|
|
206
|
-
|
|
207
|
-
#### 6. Hand Off The Recommendation
|
|
208
|
-
|
|
209
|
-
Make the recommendation explicit:
|
|
210
|
-
- What they should believe or do next
|
|
211
|
-
- Why the evidence supports that
|
|
212
|
-
- Which caveats or dependencies matter
|
|
213
|
-
- What follow-up would improve confidence
|