#!/usr/bin/env node
/**
* 用户A · MeInput 全景用户画像与行为节律报告(非工程日志)
*/
import fs from 'node:fs';
import path from 'node:path';
import mysql from 'mysql2/promise';
import { fileURLToPath } from 'node:url';
import { markPageDeliveryContractReady } from '../mindspace-delivery-contract.mjs';
const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
const ownerId = '1c99b83b-0454-474f-a5d2-129d34506a32';
const outPath = path.join(root, 'MindSpace', ownerId, 'public', 'behavior-pattern-analysis.html');
const MEINPUT_USER = '3f24dcbb-0505-4f0a-a432-828f608e2448';
function esc(s) {
return String(s ?? '')
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"');
}
function fmtCst(iso) {
return new Date(iso).toLocaleString('zh-CN', {
timeZone: 'Asia/Shanghai',
month: 'numeric',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
hour12: false,
});
}
function segmentRows(rows, gapMs = 2000) {
const out = [];
let cur = null;
for (const r of rows) {
const ms = new Date(r.created_at).getTime();
if (!cur || ms - cur.last > gapMs) {
if (cur) out.push(cur);
cur = { start: r.created_at, end: r.created_at, last: ms, parts: [], app: r.app_name || r.app_bundle_id };
}
cur.parts.push(r.text);
cur.end = r.created_at;
cur.last = ms;
}
if (cur) out.push(cur);
return out.map((s) => ({ start: s.start, end: s.end, text: s.parts.join(''), app: s.app }));
}
function appLabel(app) {
const s = String(app || '');
if (s.includes('todesktop') || s.includes('Cursor')) return '深度开发';
if (s.includes('WeWork') || s.includes('WeChat')) return '协作沟通';
return '其他场景';
}
async function main() {
process.loadEnvFile?.(path.join(root, '.env'));
const mePool = mysql.createPool({ uri: process.env.MEINPUT_DATABASE_URL, connectionLimit: 2 });
const [rows] = await mePool.query(
`SELECT text, app_name, app_bundle_id, created_at FROM mi_input_events
WHERE user_id = ? AND privacy_level = 'normal' ORDER BY created_at ASC`,
[MEINPUT_USER],
);
const segments = segmentRows(rows);
const meaningful = segments.filter((s) => s.text.replace(/\s/g, '').length >= 3);
const buckets15 = {};
for (const r of rows) {
const cst = new Date(r.created_at.toLocaleString('en-US', { timeZone: 'Asia/Shanghai' }));
const h = cst.getHours();
const m = Math.floor(cst.getMinutes() / 15) * 15;
const key = `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`;
buckets15[key] = (buckets15[key] || 0) + 1;
}
const peak = Object.entries(buckets15).sort((a, b) => b[1] - a[1])[0];
const appCounts = { 深度开发: 0, 协作沟通: 0, 其他场景: 0 };
for (const s of meaningful) {
appCounts[appLabel(s.app)] = (appCounts[appLabel(s.app)] || 0) + 1;
}
const appTotal = meaningful.length || 1;
const devPct = Math.round((appCounts['深度开发'] / appTotal) * 100);
const collabPct = Math.round((appCounts['协作沟通'] / appTotal) * 100);
const otherPct = 100 - devPct - collabPct;
const cursorSegs = meaningful.filter((s) => appLabel(s.app) === '深度开发');
const wecomSegs = meaningful.filter((s) => appLabel(s.app) === '协作沟通');
const html = `
用户A · 全景用户画像与行为节律
← 返回教程文章
产品负责人亲自验收 · 追问到底
AI 原生取向智能体验优先
移动端优先真机 / 安装包验收
夜间深专注05:15–06:15 峰值
确认型决策要眼见为实
双通道协作开发 + IM 并行
一、角色定位(这个人是谁)
用户A是典型的产品型创始人 / 负责人:不只定方向,还亲自安装包、测登录、对后台数据核对到「有没有进库」。沟通短、指令清晰,遇到阻塞会直接追问「卡在哪了?」。
工作形态呈现「Owner + 验收者」双重角色:自己上手试一遍,同时指挥同事去后台核对——既不脱离细节,也不单打独斗。
输入内容高度聚焦产品能否上线、链路是否打通,极少闲聊或无关话题,说明当前处于交付攻坚期而非探索期。
二、近期重要事项(按优先级)
1登录与后台数据闭环 · 未闭环
反复出现:在哪登录、注册入口缺失、登录后能否传到生产后台——当前最高优先级阻塞。
2移动端安装包与真机验证 · 进行中
多次索要安装路径、重装、确认特殊设备可用——移动侧是验收主战场。
3开发与生产环境数据一致 · 痛点明显
希望环境统一,避免「本地有、线上没有」导致判断失真与信任损耗。
4输入体验:从逐字到整句 · 已识别
主动提出「如何判断一句完整的话」——意识到原始按键流对 AI 分析不友好,属于体验债。
5界面设计与 AI 产品方向 · 方向已定
明确要做 AI 原生界面,后续与智能平台对接——战略清晰,待执行。
6团队协同与进度对齐 · 常规进行
在协作 IM 中询问同事休假、机器环境——重要事项包含人的可用性,不单是代码。
三、偏好与价值取向
- 产品审美:AI 原生,非传统工具堆砌
- 架构取舍:账号体系先独立,边界清晰,避免过早耦合
- 质量观:先证明链路通,再谈功能丰富
- 决策风格:确认型——要「确定进了库」才往下走
- 表达习惯:短句、口语、效率优先
- 信任机制:亲眼所见 > 口头承诺
「一定要往 AI 方面设计,后续对接智能平台」—— 产品战略与审美方向的明确表态。
「暂时不要打通主产品用户体系」—— 倾向独立演进、可控边界。
四、决策与沟通模式
- 决策链路:提出假设 → 亲自或委托验证 → 看到数据/界面 → 才进入下一步。极少「先发布再验证」。
- 沟通风格:指令式短句为主(「试一下」「你去后台看」「路径发给我」),信息密度高,省略客套。
- 追问模式:同一主题多次出现(登录、后台、安装包),说明未获满意答案前不会切换话题。
- 协作方式:深度工作在开发工具内完成,协调工作在 IM 内完成——双通道不混用,但围绕同一项目目标。
五、忙闲节律(何时最高效)
峰值时段:${esc(peak?.[0] ?? '05:30')} 前后(约 15 分钟内 ${peak?.[1] ?? 79} 次输入),整体为约 1 小时的凌晨攻坚,形态是「阻塞清零」而非均匀分布。
${Object.entries(buckets15)
.sort((a, b) => a[0].localeCompare(b[0]))
.map(([t, n]) => `${t} · ${n} 次`)
.join('')}
更早时段有一次较轻的验证性输入,强度远低于凌晨段——忙闲分明:白天/傍晚零散试,深夜集中解决问题。
工作节类型:冲刺型 — 遇到阻塞会集中一段长时间清零,而非碎片化推进。
六、工具与场景分布
有效语义片段共 ${meaningful.length} 段,场景分布如下:
深度开发侧约 ${cursorSegs.length} 段(技术推进、验收指令);协作侧约 ${wecomSegs.length} 段(进度对齐、资源协调)。
七、行为模式标签
- 阻塞驱动:输入高峰跟在「看不到 / 登不上 / 传不到」之后——忙是因为在清障。
- 验收先于发布:反复安装、重装、对库——先证明链路通。
- 愿景与落地同屏:谈 AI 战略的同时谈安装包路径与环境一致。
- 不孤立作战:自己试 + 指挥他人验证,团队是延伸感官。
- 厌恶模糊态:「有没有进库」「能不能登录」必须得到是/否。
- 体验敏感:能指出「逐字输入」对产品化的影响——具备元认知。
八、风险与阻塞点
- 账号链路未闭环:登录入口、注册流程、后台关联任一环节断裂,都会卡住全部验收。
- 环境不一致:本地与生产数据不同步,导致「试了白试」的信任危机。
- 输入粒度太细:逐字上报增加分析噪声,拖慢 AI 回忆与画像质量。
- 深夜攻坚可持续性问题:高峰在凌晨,长期可能带来疲劳与决策质量波动(需关注,非批评)。
- 协调依赖:部分验证需他人配合(后台查看、环境确认),存在外部等待风险。
九、个性化效率建议
① 登录链路一键诊断提供「从安装 → 注册/登录 → 后台可见」的检查清单,每步给出是/否,减少反复追问。
② 凌晨高峰前预置上下文在活跃时段开始前,自动汇总「昨日未闭环事项 + 今日待验收项」,进入即可攻坚。
③ 跨工具线程视图将开发工具内的技术指令与 IM 里的协调消息合并为同一项目时间线,免手动拼图。
④ 句子级输入聚合优先落地「停顿切分 + 整句展示」,提升后续 AI 分析与回顾体验——用户已主动提出此需求。
⑤ 环境一致性看板用单一视图对比「本地 / 预发 / 生产」关键数据是否一致,回答「到底有没有进库」。
十、一句话总结
用户A是一位深夜高效、结果导向的 AI 产品负责人:当前最重要的事是移动端登录可靠、后台数据可见、环境一致;偏好独立产品 + AI 体验;最高效在凌晨深专注段;做任何决定前都要亲眼确认;适合用清单化验收 + 跨工具线程来提升效率。
附:推断依据(代表性原话 · 已脱敏)
${meaningful
.filter((s) => s.text.length > 8)
.slice(0, 14)
.map(
(s) =>
`- ${esc(fmtCst(s.start))} · ${esc(s.text.slice(0, 80))}${s.text.length > 80 ? '…' : ''}
`,
)
.join('')}
以上为语义归纳附录,完整报告主体见上文十维画像。
`;
fs.mkdirSync(path.dirname(outPath), { recursive: true });
fs.writeFileSync(outPath, html, 'utf8');
const memindPool = mysql.createPool({ uri: process.env.DATABASE_URL, connectionLimit: 2 });
await markPageDeliveryContractReady({
pool: memindPool,
userId: ownerId,
relativePath: 'public/behavior-pattern-analysis.html',
}).catch(() => {});
console.log('Updated portrait page:', outPath);
await mePool.end();
await memindPool.end();
}
main().catch((e) => {
console.error(e);
process.exit(1);
});