"""Sync only the current handbook's installation step to a verified publication."""
import hashlib
import json
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
OUT = ROOT / 'docs/workshop-quality-r13-20261110'
PUBLICATION = ROOT / 'docs/ksf-workshop-skill-20261110-r13-r2'
KEY_EVIDENCE_FEEDBACK = '''反馈关键分析依据信息:涉及数据判断时,只呈现直接支撑结论或会改变建议的来源、分析对象与时间范围、实际有效样本,并用代表原话、产品对照或关键统计解释依据与判断的关系;比例注明n/N及口径,复用资料与本轮新增采集分开,关键反例和适用限制紧邻结论。未取得的依据如实标明,不补造数字。完整采集明细、逐条处理记录和工具日志按Skill保留供追溯,无需在对话中展开;本节核心报告与成果仍须完整交付。'''
def sha(path):
return hashlib.sha256(path.read_bytes()).hexdigest()
def dump(path, value):
path.write_text(json.dumps(value, ensure_ascii=False, indent=2) + '\n', encoding='utf8')
def configure_install(data):
if data['release'].get('entryMode') == 'fmode-enterprise-agent':
raise ValueError('This handbook uses website onboarding; attendee installation is retired.')
receipt = json.loads((PUBLICATION / 'online-release-receipt.json').read_bytes())
assert receipt['ok'] and receipt['publicResourcesPublished']
assert receipt['workshopVersion'] == 'r13'
archive = receipt['archive']
assert sha(PUBLICATION / 'publish' / archive['path']) == archive['sha256']
prompt = (PUBLICATION / '员工安装正文.txt').read_text('utf8').strip()
assert receipt['guideUrl'] in prompt
data['release'].update(
version='r13', installVersion='r13', guide=receipt['guideUrl'],
installReleaseId=receipt['releaseId'],
deploymentStatus='manual-local-skill-published')
step = next(s for s in data['steps'] if s['id'] == 'install')
step['prompt'] = prompt
step['deliverables'][0] = '工作坊Skill正式r13的安装或核验结果(45个公开文件)'
return receipt
def configure_website_entry(data):
data['release'].update(entryMode='fmode-enterprise-agent', skillManagedBy='organizer')
group = next(g for g in data['groups'] if g['id'] == 'prepare')
group.update(title='进入工作坊,明确本组课题',
description='登录企业网站,在本组独立会话中使用统一的工作坊智能体。')
step = next(s for s in data['steps'] if s['id'] == 'install')
step.clear()
step.update(
id='install', group='prepare', kind='introduction', number='00', title='使用说明',
introduction='本手册采用 fmode 企业网站的统一智能体。工作坊 Skill 和相关工具由组织方统一配置;学员无需安装 Skill,也无需复制安装提示词。',
usage=[
{'title': '登录并进入智能体', 'text': '打开组织方提供的 fmode 企业网站入口,登录后进入指定的工作坊智能体。'},
{'title': '保留本组独立会话', 'text': '各组使用同一个智能体入口,每组保留独立会话。先说明小组名称和研究课题,后续在本组会话中接续,避免混入其他小组的成果。'},
{'title': '从 01 开始逐节推进', 'text': '复制各节提示词发送给智能体,回答必要的业务问题,检查本节产出后再进入下一节。不同小组按各自课题与证据展开研究。'},
{'title': '核对报告与成果', 'text': '每节检查完整报告和关键分析依据;保存后核对成果编号、回读内容和本组归属。若保存未成功,让智能体明确说明。'},
{'title': '确认方案后生成示意图', 'text': '最终方案经本组明确确认后,再由智能体调用 image 技能(image 2.6)生成示意图,并与对应方案一起保存。'}
],
checks=['已找到组织方指定的工作坊智能体。', '本组使用独立会话,课题和小组名称清楚。'],
prompt='')
for index, item in enumerate(data['steps']):
item['number'] = f'{index:02d}'
def configure_evidence_feedback(data):
if KEY_EVIDENCE_FEEDBACK not in data['common']:
data['common'] += '\n\n' + KEY_EVIDENCE_FEEDBACK
for step in data['steps']:
if step['id'] != 'install' and step.get('prompt') and KEY_EVIDENCE_FEEDBACK not in step['prompt']:
step['prompt'] += '\n\n' + KEY_EVIDENCE_FEEDBACK
def render_manual(data, prompts):
manual = OUT / 'manual'
content = 'window.WORKSHOP_MANUAL_DATA = ' + json.dumps(data, ensure_ascii=False, indent=2) + ';\n'
(manual / 'content.js').write_text(content, encoding='utf8')
js = (manual / 'manual.js').read_text('utf8')
start = js.index(' const promptMap = ')
end = js.index('\n', start)
mapping = {s['id']: s['fullPrompt'] for s in prompts['steps']}
js = js[:start] + ' const promptMap = ' + json.dumps(mapping, ensure_ascii=False) + ';' + js[end:]
(manual / 'manual.js').write_text(js, encoding='utf8')
standalone_js = js.replace('href="../${escape(step.example)}"', 'href="${escape(step.example)}"').replace('href="../参考学习与类型对应.html"', 'href="参考学习与类型对应.html"')
h = (manual / 'index.html').read_text('utf8')
css = (manual / 'manual.css').read_text('utf8')
standalone = h.replace('', '').replace('', '').replace('', '')
standalone = standalone.replace('href="../index.html"', 'href="index.html"').replace('href="../案例报告合集.html"', 'href="案例报告合集.html"')
safe = lambda text: text.replace('', '