@my-life-buddies/buddy-creator-skill 1.6.0

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.
Files changed (159) hide show
  1. package/INSTALL.md +25 -0
  2. package/PATCHES.md +57 -0
  3. package/README.md +76 -0
  4. package/SKILL.md +78 -0
  5. package/THIRD_PARTY_NOTICES.md +154 -0
  6. package/agents/openai.yaml +4 -0
  7. package/assets/licenses/bail.txt +26 -0
  8. package/assets/licenses/ccount.txt +26 -0
  9. package/assets/licenses/character-entities-html4.txt +26 -0
  10. package/assets/licenses/character-entities-legacy.txt +26 -0
  11. package/assets/licenses/character-entities.txt +26 -0
  12. package/assets/licenses/character-reference-invalid.txt +26 -0
  13. package/assets/licenses/comma-separated-tokens.txt +26 -0
  14. package/assets/licenses/debug.txt +24 -0
  15. package/assets/licenses/decode-named-character-reference.txt +26 -0
  16. package/assets/licenses/dequal.txt +25 -0
  17. package/assets/licenses/devlop.txt +26 -0
  18. package/assets/licenses/escape-string-regexp.txt +13 -0
  19. package/assets/licenses/estree-util-is-identifier-name.txt +26 -0
  20. package/assets/licenses/extend.txt +27 -0
  21. package/assets/licenses/hast-util-to-jsx-runtime.txt +26 -0
  22. package/assets/licenses/hast-util-whitespace.txt +26 -0
  23. package/assets/licenses/html-url-attributes.txt +25 -0
  24. package/assets/licenses/inline-style-parser.txt +13 -0
  25. package/assets/licenses/is-alphabetical.txt +26 -0
  26. package/assets/licenses/is-alphanumerical.txt +26 -0
  27. package/assets/licenses/is-decimal.txt +26 -0
  28. package/assets/licenses/is-hexadecimal.txt +26 -0
  29. package/assets/licenses/is-plain-obj.txt +13 -0
  30. package/assets/licenses/longest-streak.txt +26 -0
  31. package/assets/licenses/markdown-table.txt +26 -0
  32. package/assets/licenses/mdast-util-find-and-replace.txt +26 -0
  33. package/assets/licenses/mdast-util-from-markdown.txt +26 -0
  34. package/assets/licenses/mdast-util-gfm-autolink-literal.txt +26 -0
  35. package/assets/licenses/mdast-util-gfm-footnote.txt +26 -0
  36. package/assets/licenses/mdast-util-gfm-strikethrough.txt +26 -0
  37. package/assets/licenses/mdast-util-gfm-table.txt +26 -0
  38. package/assets/licenses/mdast-util-gfm-task-list-item.txt +26 -0
  39. package/assets/licenses/mdast-util-gfm.txt +26 -0
  40. package/assets/licenses/mdast-util-mdx-expression.txt +26 -0
  41. package/assets/licenses/mdast-util-mdx-jsx.txt +26 -0
  42. package/assets/licenses/mdast-util-mdxjs-esm.txt +26 -0
  43. package/assets/licenses/mdast-util-phrasing.txt +27 -0
  44. package/assets/licenses/mdast-util-to-hast.txt +26 -0
  45. package/assets/licenses/mdast-util-to-markdown.txt +26 -0
  46. package/assets/licenses/mdast-util-to-string.txt +26 -0
  47. package/assets/licenses/micromark-core-commonmark.txt +26 -0
  48. package/assets/licenses/micromark-extension-gfm-autolink-literal.txt +26 -0
  49. package/assets/licenses/micromark-extension-gfm-footnote.txt +26 -0
  50. package/assets/licenses/micromark-extension-gfm-strikethrough.txt +26 -0
  51. package/assets/licenses/micromark-extension-gfm-table.txt +26 -0
  52. package/assets/licenses/micromark-extension-gfm-tagfilter.txt +26 -0
  53. package/assets/licenses/micromark-extension-gfm-task-list-item.txt +26 -0
  54. package/assets/licenses/micromark-extension-gfm.txt +26 -0
  55. package/assets/licenses/micromark-factory-destination.txt +26 -0
  56. package/assets/licenses/micromark-factory-label.txt +26 -0
  57. package/assets/licenses/micromark-factory-space.txt +26 -0
  58. package/assets/licenses/micromark-factory-title.txt +26 -0
  59. package/assets/licenses/micromark-factory-whitespace.txt +26 -0
  60. package/assets/licenses/micromark-util-character.txt +26 -0
  61. package/assets/licenses/micromark-util-chunked.txt +26 -0
  62. package/assets/licenses/micromark-util-classify-character.txt +26 -0
  63. package/assets/licenses/micromark-util-combine-extensions.txt +26 -0
  64. package/assets/licenses/micromark-util-decode-numeric-character-reference.txt +26 -0
  65. package/assets/licenses/micromark-util-decode-string.txt +26 -0
  66. package/assets/licenses/micromark-util-encode.txt +26 -0
  67. package/assets/licenses/micromark-util-html-tag-name.txt +26 -0
  68. package/assets/licenses/micromark-util-normalize-identifier.txt +26 -0
  69. package/assets/licenses/micromark-util-resolve-all.txt +26 -0
  70. package/assets/licenses/micromark-util-sanitize-uri.txt +26 -0
  71. package/assets/licenses/micromark-util-subtokenize.txt +26 -0
  72. package/assets/licenses/micromark-util-symbol.txt +26 -0
  73. package/assets/licenses/micromark-util-types.txt +26 -0
  74. package/assets/licenses/micromark.txt +26 -0
  75. package/assets/licenses/ms.txt +25 -0
  76. package/assets/licenses/parse-entities.txt +26 -0
  77. package/assets/licenses/phosphor-icons--react.txt +25 -0
  78. package/assets/licenses/property-information.txt +26 -0
  79. package/assets/licenses/react-dom.txt +25 -0
  80. package/assets/licenses/react-markdown.txt +25 -0
  81. package/assets/licenses/react.txt +25 -0
  82. package/assets/licenses/remark-gfm.txt +26 -0
  83. package/assets/licenses/remark-parse.txt +25 -0
  84. package/assets/licenses/remark-rehype.txt +26 -0
  85. package/assets/licenses/remark-stringify.txt +25 -0
  86. package/assets/licenses/scheduler.txt +25 -0
  87. package/assets/licenses/space-separated-tokens.txt +26 -0
  88. package/assets/licenses/stringify-entities.txt +26 -0
  89. package/assets/licenses/style-to-js.txt +26 -0
  90. package/assets/licenses/style-to-object.txt +26 -0
  91. package/assets/licenses/trim-lines.txt +26 -0
  92. package/assets/licenses/trough.txt +25 -0
  93. package/assets/licenses/types--debug.txt +25 -0
  94. package/assets/licenses/types--estree-jsx.txt +25 -0
  95. package/assets/licenses/types--estree.txt +25 -0
  96. package/assets/licenses/types--hast.txt +25 -0
  97. package/assets/licenses/types--mdast.txt +25 -0
  98. package/assets/licenses/types--ms.txt +25 -0
  99. package/assets/licenses/types--unist.txt +25 -0
  100. package/assets/licenses/ungap--structured-clone.txt +19 -0
  101. package/assets/licenses/unified.txt +25 -0
  102. package/assets/licenses/unist-util-is.txt +26 -0
  103. package/assets/licenses/unist-util-position.txt +26 -0
  104. package/assets/licenses/unist-util-stringify-position.txt +26 -0
  105. package/assets/licenses/unist-util-visit-parents.txt +26 -0
  106. package/assets/licenses/unist-util-visit.txt +26 -0
  107. package/assets/licenses/vfile-message.txt +26 -0
  108. package/assets/licenses/vfile.txt +25 -0
  109. package/assets/licenses/zwitch.txt +26 -0
  110. package/assets/preview/assets/index-B5VmkoSx.js +39 -0
  111. package/assets/preview/assets/index-DWKP6b-3.css +4 -0
  112. package/assets/preview/brand-logo.png +0 -0
  113. package/assets/preview/brand.css +100 -0
  114. package/assets/preview/index.html +7 -0
  115. package/assets/preview/reader.css +165 -0
  116. package/assets/preview/reader.js +135 -0
  117. package/assets/preview/widgets.css +1 -0
  118. package/assets/preview/widgets.js +168 -0
  119. package/assets/widget-reference/conversation.png +0 -0
  120. package/assets/widget-reference/expanded.png +0 -0
  121. package/assets/widget-v2/app.js +62 -0
  122. package/assets/widget-v2/style.css +1 -0
  123. package/assets/widget-v3/app.js +65 -0
  124. package/assets/widget-v3/style.css +103 -0
  125. package/assets/widget-v4/app.js +66 -0
  126. package/assets/widget-v4/style.css +187 -0
  127. package/package.json +37 -0
  128. package/references/artifact-schema.md +70 -0
  129. package/references/catalog.json +401 -0
  130. package/references/cli-workflow.md +15 -0
  131. package/references/definition.md +24 -0
  132. package/references/dialogue-examples.md +133 -0
  133. package/references/host-guide.md +219 -0
  134. package/references/interview.md +235 -0
  135. package/references/knowledge.md +40 -0
  136. package/references/methods-protocol.md +60 -0
  137. package/references/methods.md +98 -0
  138. package/references/opening.md +14 -0
  139. package/references/preview-panel.md +66 -0
  140. package/references/recovery.md +46 -0
  141. package/references/service.md +76 -0
  142. package/references/widgets-protocol.md +83 -0
  143. package/references/widgets.md +99 -0
  144. package/scripts/buddy.py +108 -0
  145. package/scripts/buddy_client.py +67 -0
  146. package/scripts/buddy_core.py +908 -0
  147. package/scripts/completion.py +296 -0
  148. package/scripts/interview.py +218 -0
  149. package/scripts/methods.py +181 -0
  150. package/scripts/preview.py +631 -0
  151. package/scripts/preview_panel.py +80 -0
  152. package/scripts/sources.py +239 -0
  153. package/scripts/widget_render.py +66 -0
  154. package/scripts/widget_render_v1.py +176 -0
  155. package/scripts/widget_render_v2.py +98 -0
  156. package/scripts/widget_render_v3.py +86 -0
  157. package/scripts/widget_render_v4.py +121 -0
  158. package/scripts/widgets.py +227 -0
  159. package/version.json +8 -0
@@ -0,0 +1,181 @@
1
+ """Evidence-bound, adaptive method interviews. No model or inferred consent."""
2
+ import copy
3
+ import re
4
+
5
+ from buddy_core import book_ids, confirmed, digest, evidence, invalidate, require, text
6
+
7
+ DIMENSIONS = ('decisions', 'actions', 'adaptation', 'boundaries')
8
+
9
+
10
+ def enabled(state):
11
+ return state.get('methodInterview', {}).get('version') == 1
12
+
13
+
14
+ def active(state, target_id):
15
+ return not enabled(state) or target_id in state['methodInterview']['targets']
16
+
17
+
18
+ def object_id(target_id):
19
+ return 'hypothesis.H' + str(int(target_id[1:])) if target_id.startswith('H') else 'scenario.' + target_id
20
+
21
+
22
+ def handled(state, target_id):
23
+ key = object_id(target_id)
24
+ return any(confirmed(state, key, decision) for decision in
25
+ (('accepted', 'rejected') if target_id.startswith('H') else ('confirmed',)))
26
+
27
+
28
+ def fingerprint(state):
29
+ """Booklet drafts are outputs, so cannot invalidate their own assessment."""
30
+ artifacts = {key: item['hash'] for key, item in state['artifacts'].items()
31
+ if item['stage'] in {'definition', 'knowledge'} or item['kind'] in {'hypothesis', 'scenario'}}
32
+ confirmations = sorted((c['objectId'], c['hash'], c['decision']) for c in state['confirmations']
33
+ if c['objectId'] in artifacts and not c.get('invalidatedBy'))
34
+ targets = state['methodInterview']['targets']
35
+ return digest({'artifacts': artifacts, 'confirmations': confirmations, 'plan': targets,
36
+ 'targets': {key: state['targets'][key] for key in targets},
37
+ 'gaps': {key: gap for key, gap in state.get('interview', {}).get('gaps', {}).items()
38
+ if gap['targetId'] in targets}})
39
+
40
+
41
+ def conclusion(state):
42
+ record = state.get('methodInterview', {}).get('conclusion')
43
+ return record if record and record['fingerprint'] == fingerprint(state) else None
44
+
45
+
46
+ def stopped(state):
47
+ # User stop survives stale evidence; only an explicit resume lifts it.
48
+ return state.get('methodInterview', {}).get('conclusion', {}).get('status') == 'user_stopped'
49
+
50
+
51
+ def pending(state):
52
+ items = []
53
+ for key, card in state['methodInterview']['targets'].items():
54
+ if not handled(state, key):
55
+ items.append(key + ' ' + card['title'] + ':尚未有效校准')
56
+ artifact = state['artifacts'].get(object_id(key), {})
57
+ items.extend(key + ':' + gap for gap in artifact.get('unresolved', []))
58
+ items.extend(key + ':' + gap for gap in state['targets'][key]['gaps'])
59
+ items.extend(gap['targetId'] + ':' + gap['description']
60
+ for gap in state.get('interview', {}).get('gaps', {}).values()
61
+ if gap['targetId'] in state['methodInterview']['targets'] and gap['status'] != 'resolved'
62
+ and not handled(state, gap['targetId']))
63
+ return list(dict.fromkeys(items))
64
+
65
+
66
+ def prepare(state, patch, inp, intent):
67
+ from buddy_core import catalog
68
+ if patch is None:
69
+ return
70
+ require(isinstance(patch, dict) and not set(patch) - {'register', 'conclude', 'resume'},
71
+ 'METHOD_SCHEMA', 'methods 使用 register/conclude/resume。')
72
+ require(state['stage'] == 'methods', 'STAGE_SCOPE', '方法计划在方法阶段调整。')
73
+ if not enabled(state):
74
+ # Adopt unfinished legacy work without throwing away IDs, answers or limits.
75
+ cards = catalog()['cards']
76
+ targets = {key: copy.deepcopy(card) for key, card in cards.items()
77
+ if card['stage'] == 'methods' and (state['targets'][key]['status'] != 'unstarted'
78
+ or object_id(key) in state['artifacts'] or state['targets'][key]['answerInputIds'])}
79
+ state['methodInterview'] = {'version': 1, 'targets': targets, 'history': []}
80
+ invalidate(state, book_ids('methods'), inp['id'])
81
+ plan = state['methodInterview']
82
+ resume = patch.get('resume')
83
+ if resume is not None:
84
+ require(isinstance(resume, dict) and set(resume) == {'reason', 'evidence'} and text(resume['reason'])
85
+ and intent in {'resume', 'revision'}, 'METHOD_RESUME', '续谈需本轮明确请求、理由及 resume/revision。')
86
+ evidence(state, resume['evidence'], inp['id'])
87
+ previous = plan.pop('conclusion', None)
88
+ plan['history'].append({'resume': copy.deepcopy(resume), 'previous': previous, 'inputId': inp['id']})
89
+ invalidate(state, book_ids('methods'), inp['id'])
90
+ registrations = patch.get('register', [])
91
+ require(isinstance(registrations, list), 'METHOD_SCHEMA', 'register 使用数组。')
92
+ require(not registrations or not plan.get('conclusion'), 'METHOD_CLOSED', '方法访谈已收口,明确续谈后才新增目标。')
93
+ for proposal in registrations:
94
+ require(isinstance(proposal, dict) and set(proposal) == {'id', 'title', 'purpose', 'evidence'}
95
+ and all(text(proposal.get(k)) for k in ('id', 'title', 'purpose')),
96
+ 'METHOD_TARGET', '目标使用 id/title/purpose/evidence,说明新增案例解决什么不同问题。')
97
+ key = proposal['id']
98
+ require(re.fullmatch(r'[HME](?:0[1-9]|[1-9][0-9]+)', key), 'METHOD_TARGET', '目标使用 H01/M01/E01 起的连续数字编号。')
99
+ evidence(state, proposal['evidence'])
100
+ require(proposal['evidence'], 'EVIDENCE_REQUIRED', '新增方法或案例必须有依据及明确目的。')
101
+ template = copy.deepcopy(catalog()['cards'][key[0] + '01'])
102
+ template.update(title=proposal['title'], minimum=proposal['purpose'], purpose=proposal['purpose'], evidence=proposal['evidence'])
103
+ old = plan['targets'].get(key)
104
+ if old:
105
+ require(old == template, 'METHOD_TARGET_IMMUTABLE', '沿用目标编号和目的;新增表述不能重置次数。')
106
+ continue
107
+ normalized = re.sub(r'\s+', '', proposal['purpose'])
108
+ require(not any(re.sub(r'\s+', '', c.get('purpose', c['minimum'])) == normalized for c in plan['targets'].values()),
109
+ 'DUPLICATE_METHOD_TARGET', '同一缺口沿用原目标,不得换编号重复采访。')
110
+ plan['targets'][key] = template
111
+ state['targets'].setdefault(key, {'id': key, 'status': 'unstarted', 'summary': '', 'gaps': [], 'evidence': [], 'answerInputIds': []})
112
+ invalidate(state, book_ids('methods'), inp['id'])
113
+
114
+
115
+ def finish(state, patch, inp):
116
+ if not patch or 'conclude' not in patch:
117
+ return
118
+ import interview
119
+ record = patch['conclude']
120
+ require(isinstance(record, dict) and set(record) == {'status', 'summary', 'coverage', 'unresolved', 'evidence'}
121
+ and record['status'] in {'sufficient', 'user_stopped'} and text(record['summary'])
122
+ and isinstance(record['unresolved'], list) and all(text(item) for item in record['unresolved'])
123
+ and isinstance(record['coverage'], dict), 'METHOD_CONCLUSION', '收口需要 status/summary/coverage/unresolved/evidence。')
124
+ evidence(state, record['evidence'], inp['id'] if record['status'] == 'user_stopped' else None)
125
+ require(record['evidence'], 'EVIDENCE_REQUIRED', '收口须有真实依据,不能以数量达标代替判断。')
126
+ if record['status'] == 'sufficient':
127
+ require(not stopped(state), 'METHOD_STOPPED', '用户叫停不能自动改成内容充分。')
128
+ require(set(record['coverage']) == set(DIMENSIONS), 'METHOD_COVERAGE', '说明判断、行动、调整、边界四个维度是否充分或为何不适用。')
129
+ for value in record['coverage'].values():
130
+ require(isinstance(value, dict) and set(value) == {'status', 'reason', 'evidence'}
131
+ and value['status'] in {'covered', 'not_applicable'} and text(value['reason']),
132
+ 'METHOD_COVERAGE', '每个维度使用 status=covered/not_applicable、reason、evidence。')
133
+ evidence(state, value['evidence'])
134
+ require(value['evidence'] and all(ref['type'] == 'artifact' and
135
+ (confirmed(state, ref['id']) or confirmed(state, ref['id'], 'accepted')) for ref in value['evidence']),
136
+ 'METHOD_COVERAGE', '覆盖判断必须引用实际已确认内容,不引用未验证推导。')
137
+ require(any(a['kind'] == 'hypothesis' and confirmed(state, a['id'], 'accepted') for a in state['artifacts'].values())
138
+ and any(key.startswith('scenario.M') and confirmed(state, key) for key in state['artifacts']),
139
+ 'METHOD_EVIDENCE', '充分收口至少需要认可的方法及用户校准的基础案例。')
140
+ require(not pending(state) and not record['unresolved'] and not interview.blockers(state, 'methods'),
141
+ 'METHOD_INCOMPLETE', '仍有未校准目标或关键缺口,不能标记充分。')
142
+ else:
143
+ require(not record['coverage'], 'METHOD_CONCLUSION', '用户叫停不代替充分性判断;coverage 留空。')
144
+ saved = copy.deepcopy(record)
145
+ saved['unresolved'] = list(dict.fromkeys(saved['unresolved'] + pending(state)))
146
+ if record['status'] == 'user_stopped':
147
+ saved['unresolved'].insert(0, '访谈由创作者主动结束,整体覆盖尚未判定充分;仅采用已确认的方法与案例。')
148
+ saved.update(inputId=inp['id'], fingerprint=fingerprint(state))
149
+ previous = state['methodInterview'].get('conclusion')
150
+ if previous:
151
+ state['methodInterview']['history'].append(previous)
152
+ state['methodInterview']['conclusion'] = saved
153
+ invalidate(state, book_ids('methods'), inp['id'])
154
+
155
+
156
+ def gates(state):
157
+ record = conclusion(state)
158
+ return [{'label': '方法访谈已按覆盖充分或创作者主动结束收口', 'pass': bool(record)}]
159
+
160
+
161
+ def scoped_stop(state):
162
+ record = conclusion(state)
163
+ return bool(record and record['status'] == 'user_stopped')
164
+
165
+
166
+ def scope_chapter(state, artifact):
167
+ """Keep limitations in the shown, hashed, confirmed and exported version."""
168
+ record = conclusion(state)
169
+ if not record:
170
+ return
171
+ artifact['data']['methodConclusion'] = digest(record)
172
+ if record['status'] == 'user_stopped':
173
+ artifact['unresolved'] = list(dict.fromkeys(artifact['unresolved'] + record['unresolved']))
174
+ note = '\n\n### 本版方法范围与待补\n\n' + record['summary'] + '\n\n' + '\n'.join('- ' + item for item in artifact['unresolved'])
175
+ if not artifact['markdown'].endswith(note):
176
+ artifact['markdown'] += note
177
+
178
+
179
+ def chapter_scoped(state, artifact):
180
+ record = conclusion(state)
181
+ return bool(record and artifact.get('data', {}).get('methodConclusion') == digest(record))