@my-life-buddies/cli 0.13.3 → 0.15.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.
- package/README.md +74 -22
- package/dist/bin/buddy.js +29 -10
- package/dist/bin/buddy.js.map +2 -2
- package/dist/bin/core.js +1480 -611
- package/dist/bin/core.js.map +4 -4
- package/dist/bin/preview.js +324 -27
- package/dist/bin/preview.js.map +4 -4
- package/dist/web/app.css +65 -6
- package/dist/web/app.js +103 -39
- package/dist/web/diagnostics.js +184 -0
- package/dist/web/index.html +34 -34
- package/dist/web/widgets.css +59 -28
- package/dist/web/widgets.js +230 -76
- package/package.json +3 -3
- package/resources/README.md +6 -50
- package/resources/agent-template/package-lock.json +4 -4
- package/resources/agent-template/package.json +2 -2
- package/resources/buddy-creator/INSTALL.md +0 -25
- package/resources/buddy-creator/PATCHES.md +0 -53
- package/resources/buddy-creator/SKILL.md +0 -76
- package/resources/buddy-creator/THIRD_PARTY_NOTICES.md +0 -154
- package/resources/buddy-creator/agents/openai.yaml +0 -4
- package/resources/buddy-creator/assets/licenses/bail.txt +0 -26
- package/resources/buddy-creator/assets/licenses/ccount.txt +0 -26
- package/resources/buddy-creator/assets/licenses/character-entities-html4.txt +0 -26
- package/resources/buddy-creator/assets/licenses/character-entities-legacy.txt +0 -26
- package/resources/buddy-creator/assets/licenses/character-entities.txt +0 -26
- package/resources/buddy-creator/assets/licenses/character-reference-invalid.txt +0 -26
- package/resources/buddy-creator/assets/licenses/comma-separated-tokens.txt +0 -26
- package/resources/buddy-creator/assets/licenses/debug.txt +0 -24
- package/resources/buddy-creator/assets/licenses/decode-named-character-reference.txt +0 -26
- package/resources/buddy-creator/assets/licenses/dequal.txt +0 -25
- package/resources/buddy-creator/assets/licenses/devlop.txt +0 -26
- package/resources/buddy-creator/assets/licenses/escape-string-regexp.txt +0 -13
- package/resources/buddy-creator/assets/licenses/estree-util-is-identifier-name.txt +0 -26
- package/resources/buddy-creator/assets/licenses/extend.txt +0 -27
- package/resources/buddy-creator/assets/licenses/hast-util-to-jsx-runtime.txt +0 -26
- package/resources/buddy-creator/assets/licenses/hast-util-whitespace.txt +0 -26
- package/resources/buddy-creator/assets/licenses/html-url-attributes.txt +0 -25
- package/resources/buddy-creator/assets/licenses/inline-style-parser.txt +0 -13
- package/resources/buddy-creator/assets/licenses/is-alphabetical.txt +0 -26
- package/resources/buddy-creator/assets/licenses/is-alphanumerical.txt +0 -26
- package/resources/buddy-creator/assets/licenses/is-decimal.txt +0 -26
- package/resources/buddy-creator/assets/licenses/is-hexadecimal.txt +0 -26
- package/resources/buddy-creator/assets/licenses/is-plain-obj.txt +0 -13
- package/resources/buddy-creator/assets/licenses/longest-streak.txt +0 -26
- package/resources/buddy-creator/assets/licenses/markdown-table.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-find-and-replace.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-from-markdown.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-gfm-autolink-literal.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-gfm-footnote.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-gfm-strikethrough.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-gfm-table.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-gfm-task-list-item.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-gfm.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-mdx-expression.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-mdx-jsx.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-mdxjs-esm.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-phrasing.txt +0 -27
- package/resources/buddy-creator/assets/licenses/mdast-util-to-hast.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-to-markdown.txt +0 -26
- package/resources/buddy-creator/assets/licenses/mdast-util-to-string.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-core-commonmark.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-autolink-literal.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-footnote.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-strikethrough.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-table.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-tagfilter.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-extension-gfm-task-list-item.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-extension-gfm.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-factory-destination.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-factory-label.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-factory-space.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-factory-title.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-factory-whitespace.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-character.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-chunked.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-classify-character.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-combine-extensions.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-decode-numeric-character-reference.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-decode-string.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-encode.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-html-tag-name.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-normalize-identifier.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-resolve-all.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-sanitize-uri.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-subtokenize.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-symbol.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark-util-types.txt +0 -26
- package/resources/buddy-creator/assets/licenses/micromark.txt +0 -26
- package/resources/buddy-creator/assets/licenses/ms.txt +0 -25
- package/resources/buddy-creator/assets/licenses/parse-entities.txt +0 -26
- package/resources/buddy-creator/assets/licenses/phosphor-icons--react.txt +0 -25
- package/resources/buddy-creator/assets/licenses/property-information.txt +0 -26
- package/resources/buddy-creator/assets/licenses/react-dom.txt +0 -25
- package/resources/buddy-creator/assets/licenses/react-markdown.txt +0 -25
- package/resources/buddy-creator/assets/licenses/react.txt +0 -25
- package/resources/buddy-creator/assets/licenses/remark-gfm.txt +0 -26
- package/resources/buddy-creator/assets/licenses/remark-parse.txt +0 -25
- package/resources/buddy-creator/assets/licenses/remark-rehype.txt +0 -26
- package/resources/buddy-creator/assets/licenses/remark-stringify.txt +0 -25
- package/resources/buddy-creator/assets/licenses/scheduler.txt +0 -25
- package/resources/buddy-creator/assets/licenses/space-separated-tokens.txt +0 -26
- package/resources/buddy-creator/assets/licenses/stringify-entities.txt +0 -26
- package/resources/buddy-creator/assets/licenses/style-to-js.txt +0 -26
- package/resources/buddy-creator/assets/licenses/style-to-object.txt +0 -26
- package/resources/buddy-creator/assets/licenses/trim-lines.txt +0 -26
- package/resources/buddy-creator/assets/licenses/trough.txt +0 -25
- package/resources/buddy-creator/assets/licenses/types--debug.txt +0 -25
- package/resources/buddy-creator/assets/licenses/types--estree-jsx.txt +0 -25
- package/resources/buddy-creator/assets/licenses/types--estree.txt +0 -25
- package/resources/buddy-creator/assets/licenses/types--hast.txt +0 -25
- package/resources/buddy-creator/assets/licenses/types--mdast.txt +0 -25
- package/resources/buddy-creator/assets/licenses/types--ms.txt +0 -25
- package/resources/buddy-creator/assets/licenses/types--unist.txt +0 -25
- package/resources/buddy-creator/assets/licenses/ungap--structured-clone.txt +0 -19
- package/resources/buddy-creator/assets/licenses/unified.txt +0 -25
- package/resources/buddy-creator/assets/licenses/unist-util-is.txt +0 -26
- package/resources/buddy-creator/assets/licenses/unist-util-position.txt +0 -26
- package/resources/buddy-creator/assets/licenses/unist-util-stringify-position.txt +0 -26
- package/resources/buddy-creator/assets/licenses/unist-util-visit-parents.txt +0 -26
- package/resources/buddy-creator/assets/licenses/unist-util-visit.txt +0 -26
- package/resources/buddy-creator/assets/licenses/vfile-message.txt +0 -26
- package/resources/buddy-creator/assets/licenses/vfile.txt +0 -25
- package/resources/buddy-creator/assets/licenses/zwitch.txt +0 -26
- package/resources/buddy-creator/assets/preview/assets/index-B5VmkoSx.js +0 -39
- package/resources/buddy-creator/assets/preview/assets/index-DWKP6b-3.css +0 -4
- package/resources/buddy-creator/assets/preview/brand-logo.png +0 -0
- package/resources/buddy-creator/assets/preview/brand.css +0 -100
- package/resources/buddy-creator/assets/preview/index.html +0 -7
- package/resources/buddy-creator/assets/preview/reader.css +0 -165
- package/resources/buddy-creator/assets/preview/reader.js +0 -135
- package/resources/buddy-creator/assets/preview/widgets.css +0 -1
- package/resources/buddy-creator/assets/preview/widgets.js +0 -168
- package/resources/buddy-creator/assets/widget-reference/conversation.png +0 -0
- package/resources/buddy-creator/assets/widget-reference/expanded.png +0 -0
- package/resources/buddy-creator/assets/widget-v2/app.js +0 -62
- package/resources/buddy-creator/assets/widget-v2/style.css +0 -1
- package/resources/buddy-creator/assets/widget-v3/app.js +0 -65
- package/resources/buddy-creator/assets/widget-v3/style.css +0 -103
- package/resources/buddy-creator/assets/widget-v4/app.js +0 -66
- package/resources/buddy-creator/assets/widget-v4/style.css +0 -187
- package/resources/buddy-creator/references/artifact-schema.md +0 -70
- package/resources/buddy-creator/references/catalog.json +0 -401
- package/resources/buddy-creator/references/definition.md +0 -24
- package/resources/buddy-creator/references/dialogue-examples.md +0 -133
- package/resources/buddy-creator/references/host-guide.md +0 -219
- package/resources/buddy-creator/references/interview.md +0 -235
- package/resources/buddy-creator/references/knowledge.md +0 -40
- package/resources/buddy-creator/references/methods.md +0 -77
- package/resources/buddy-creator/references/opening.md +0 -14
- package/resources/buddy-creator/references/preview-panel.md +0 -66
- package/resources/buddy-creator/references/recovery.md +0 -46
- package/resources/buddy-creator/references/service.md +0 -76
- package/resources/buddy-creator/references/widgets-protocol.md +0 -83
- package/resources/buddy-creator/references/widgets.md +0 -99
- package/resources/buddy-creator/scripts/buddy.py +0 -108
- package/resources/buddy-creator/scripts/buddy_client.py +0 -67
- package/resources/buddy-creator/scripts/buddy_core.py +0 -865
- package/resources/buddy-creator/scripts/completion.py +0 -296
- package/resources/buddy-creator/scripts/interview.py +0 -215
- package/resources/buddy-creator/scripts/preview.py +0 -617
- package/resources/buddy-creator/scripts/preview_panel.py +0 -80
- package/resources/buddy-creator/scripts/sources.py +0 -239
- package/resources/buddy-creator/scripts/widget_render.py +0 -66
- package/resources/buddy-creator/scripts/widget_render_v1.py +0 -176
- package/resources/buddy-creator/scripts/widget_render_v2.py +0 -98
- package/resources/buddy-creator/scripts/widget_render_v3.py +0 -86
- package/resources/buddy-creator/scripts/widget_render_v4.py +0 -121
- package/resources/buddy-creator/scripts/widgets.py +0 -227
- package/resources/buddy-creator/version.json +0 -8
- package/resources/buddy-creator.manifest.json +0 -791
- package/resources/dada-object-avatar/SKILL.md +0 -37
- package/resources/dada-object-avatar/agents/openai.yaml +0 -4
- package/resources/dada-object-avatar/assets/examples/cat.png +0 -0
- package/resources/dada-object-avatar/assets/examples/cooking.png +0 -0
- package/resources/dada-object-avatar/assets/examples/divination.png +0 -0
- package/resources/dada-object-avatar/assets/examples/doctor.png +0 -0
- package/resources/dada-object-avatar/assets/examples/relationship.png +0 -0
- package/resources/dada-object-avatar/assets/examples/work.png +0 -0
- package/resources/dada-object-avatar/assets/preview.png +0 -0
- package/resources/dada-object-avatar/references/evaluation-rubric.md +0 -22
- package/resources/dada-object-avatar/references/examples.json +0 -8
- package/resources/dada-object-avatar/references/prompt-template.md +0 -27
- package/resources/dada-object-avatar/references/style-system.md +0 -54
- package/resources/dada-object-avatar/references/subject-design.md +0 -23
- package/resources/dada-object-avatar/references/training-guide.md +0 -14
- package/resources/dada-object-avatar/references/training-log.jsonl +0 -0
- package/resources/dada-object-avatar/references/training-record.schema.json +0 -20
- package/resources/dada-object-avatar/scripts/choose_gaze.py +0 -36
- package/resources/dada-object-avatar/scripts/record_example.py +0 -22
- package/resources/dada-object-avatar/scripts/validate_png.py +0 -52
- package/resources/dada-object-avatar.manifest.json +0 -85
package/dist/web/widgets.js
CHANGED
|
@@ -1,126 +1,280 @@
|
|
|
1
|
-
/* Client reference: my-life-buddies-ios dev
|
|
1
|
+
/* Client reference: my-life-buddies-ios dev ff1845b (2026-09-16).
|
|
2
|
+
Native point sizes share the phone's scale; Web content remains in an opaque sandbox. */
|
|
2
3
|
(() => {
|
|
3
|
-
const
|
|
4
|
-
|
|
4
|
+
const el = (tag, className = '', text) => {
|
|
5
|
+
const node = document.createElement(tag); node.className = className;
|
|
6
|
+
if (text !== undefined) node.textContent = text;
|
|
7
|
+
return node;
|
|
8
|
+
};
|
|
9
|
+
const button = (label, action, className = '') => {
|
|
10
|
+
const node = el('button', className, label); node.type = 'button'; node.addEventListener('click', action); return node;
|
|
11
|
+
};
|
|
12
|
+
const menuIcon = name => {
|
|
13
|
+
const paths = {
|
|
14
|
+
share: 'M12 15V3m-4 4 4-4 4 4M7 11H5v10h14V11h-2',
|
|
15
|
+
pin: 'm9 3 6 0-1 6 4 4v2H6v-2l4-4ZM12 15v6',
|
|
16
|
+
unpin: 'm3 3 18 18M9 3h6l-1 6 4 4v2M6 15h6m0 0v6',
|
|
17
|
+
trash: 'M4 7h16M9 7V4h6v3M6 7l1 14h10l1-14M10 11v6m4-6v6',
|
|
18
|
+
};
|
|
19
|
+
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
20
|
+
svg.setAttribute('viewBox', '0 0 24 24'); svg.setAttribute('aria-hidden', 'true');
|
|
21
|
+
const path = document.createElementNS(svg.namespaceURI, 'path'); path.setAttribute('d', paths[name]);
|
|
22
|
+
svg.append(path); return svg;
|
|
23
|
+
};
|
|
5
24
|
window.createSimulatorWidgets = ({ api, avatar }) => {
|
|
6
25
|
const shortcut = document.querySelector('#widget-shortcut');
|
|
7
26
|
const overlay = document.querySelector('#widget-overlay');
|
|
8
27
|
const phone = document.querySelector('.phone-screen');
|
|
9
|
-
|
|
10
|
-
let
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
28
|
+
const device = document.querySelector('.phone');
|
|
29
|
+
let reopenId, conversationScope;
|
|
30
|
+
let items = [], scope = '', generation = 0, ready = false, loading = false, lastRefresh = 0;
|
|
31
|
+
let failed = false, signature = '', selected, focusBefore, openRevision = 0, frameObserver;
|
|
32
|
+
let collapseTimer, closeTimer, loadTimer, documentFrame, documentToken, documentReady;
|
|
33
|
+
let phase = 'normal', choices, pill, busy = false, refreshPromise;
|
|
34
|
+
let documentLifecycle = false, canDelete = false;
|
|
35
|
+
const timers = () => { clearTimeout(loadTimer); frameObserver?.disconnect(); frameObserver = undefined; documentFrame = undefined; documentReady = undefined; };
|
|
36
|
+
const scale = () => device.clientWidth / 415;
|
|
37
|
+
const resize = new ResizeObserver(() => { phone.style.setProperty('--widget-unit', `${scale()}px`); });
|
|
38
|
+
resize.observe(device);
|
|
39
|
+
function setPhase(value) { phase = value; shortcut.dataset.phase = value; pill?.setAttribute('aria-expanded', String(value === 'choosing')); }
|
|
40
|
+
function scheduleCollapse() {
|
|
41
|
+
clearTimeout(collapseTimer);
|
|
42
|
+
if (!ready || !items.length || selected || document.hidden || phase !== 'normal') return;
|
|
43
|
+
collapseTimer = setTimeout(() => setPhase('collapsed'), 5000);
|
|
44
|
+
}
|
|
45
|
+
function closeChoices(reset = true) {
|
|
46
|
+
choices?.remove(); choices = undefined;
|
|
47
|
+
if (reset) { setPhase('normal'); scheduleCollapse(); }
|
|
48
|
+
}
|
|
49
|
+
function finishClose() {
|
|
50
|
+
overlay.hidden = true; overlay.replaceChildren(); delete overlay.dataset.state;
|
|
15
51
|
for (const child of phone.children) if (child !== overlay) child.inert = false;
|
|
16
|
-
if (
|
|
52
|
+
if (focusBefore?.isConnected) focusBefore.focus(); focusBefore = undefined; setPhase('normal'); scheduleCollapse();
|
|
53
|
+
}
|
|
54
|
+
function close(immediate = false) {
|
|
55
|
+
if (busy && !immediate) return;
|
|
56
|
+
clearTimeout(closeTimer); timers(); openRevision++; selected = undefined;
|
|
57
|
+
if (immediate || overlay.hidden) { finishClose(); return; }
|
|
58
|
+
overlay.dataset.state = 'closing';
|
|
59
|
+
closeTimer = setTimeout(finishClose, window.matchMedia('(prefers-reduced-motion:reduce)').matches ? 100 : 220);
|
|
17
60
|
}
|
|
18
|
-
function button(label, action, className = '') { const n = el('button', className, label); n.type = 'button'; n.addEventListener('click', action); return n; }
|
|
19
61
|
function render() {
|
|
20
|
-
const
|
|
21
|
-
if (
|
|
22
|
-
|
|
23
|
-
|
|
62
|
+
const next = JSON.stringify([ready, items, failed]);
|
|
63
|
+
if (next === signature) return;
|
|
64
|
+
signature = next;
|
|
65
|
+
const choosing = phase === 'choosing';
|
|
66
|
+
closeChoices(false); shortcut.replaceChildren(); shortcut.hidden = !ready || (!items.length && !failed);
|
|
24
67
|
if (shortcut.hidden) return;
|
|
25
68
|
if (!items.length) { shortcut.append(button('重新加载小挂件', () => refresh(true), 'widget-pill')); return; }
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
69
|
+
const title = items.length === 1 ? items[0].title : '全部小挂件';
|
|
70
|
+
pill = button('', () => {
|
|
71
|
+
clearTimeout(collapseTimer);
|
|
72
|
+
if (items.length === 1) { open(items[0]); return; }
|
|
73
|
+
if (choices) { closeChoices(); return; }
|
|
74
|
+
setPhase('choosing');
|
|
75
|
+
choices = el('div', 'widget-choices'); choices.setAttribute('role', 'menu'); choices.setAttribute('aria-label', '会话小挂件列表');
|
|
76
|
+
for (const item of items) {
|
|
77
|
+
const row = button('', () => { closeChoices(false); open(item); }); row.setAttribute('role', 'menuitem');
|
|
78
|
+
row.append(el('span', '', item.title), el('span', 'widget-arrow', '›')); choices.append(row);
|
|
79
|
+
}
|
|
80
|
+
shortcut.append(choices); choices.firstChild?.focus();
|
|
33
81
|
}, 'widget-pill');
|
|
82
|
+
pill.setAttribute('aria-label', title);
|
|
34
83
|
const image = avatar(); image.classList.add('widget-pill-avatar');
|
|
35
|
-
pill.append(image, el('span', 'widget-pill-title',
|
|
36
|
-
if (items.length > 1) { pill.append(el('span', 'widget-chevron', '
|
|
37
|
-
shortcut.append(pill);
|
|
84
|
+
pill.append(image, el('span', 'widget-pill-title', title));
|
|
85
|
+
if (items.length > 1) { pill.append(el('span', 'widget-chevron', '›')); pill.setAttribute('aria-haspopup', 'menu'); }
|
|
86
|
+
shortcut.append(pill); setPhase(choosing ? 'normal' : phase);
|
|
38
87
|
}
|
|
39
88
|
async function refresh(force = false) {
|
|
40
|
-
if (!ready
|
|
89
|
+
if (!ready) return;
|
|
90
|
+
if (loading) return refreshPromise;
|
|
91
|
+
if (!force && Date.now() - lastRefresh < 1500) return;
|
|
41
92
|
loading = true; const mine = generation;
|
|
42
93
|
try {
|
|
43
|
-
|
|
94
|
+
refreshPromise = api('/api/simulator/widgets');
|
|
95
|
+
const value = await refreshPromise;
|
|
44
96
|
if (mine !== generation || !ready) return;
|
|
97
|
+
const previousIDs = items.map(item => item.id).join(',');
|
|
45
98
|
items = value.widgets || []; failed = false;
|
|
46
|
-
|
|
99
|
+
documentLifecycle = value.capabilities?.documentLifecycle === true;
|
|
100
|
+
canDelete = value.capabilities?.deleteWidget === true;
|
|
101
|
+
if (selected && !items.some(item => item.id === selected.id)) close(true);
|
|
102
|
+
if (previousIDs !== items.map(item => item.id).join(',')) { setPhase('normal'); scheduleCollapse(); }
|
|
103
|
+
// Revoked ownership must also remove an already open owner menu.
|
|
104
|
+
if (selected && items.find(item => item.id === selected.id)?.role !== 'owner') {
|
|
105
|
+
overlay.querySelector('.widget-options')?.remove();
|
|
106
|
+
overlay.querySelector('.widget-confirm-backdrop')?.remove();
|
|
107
|
+
overlay.querySelector('.widget-native-share')?.remove();
|
|
108
|
+
const more = overlay.querySelector('.widget-more'); if (more) more.hidden = true;
|
|
109
|
+
}
|
|
47
110
|
} catch { if (mine === generation) failed = true; }
|
|
48
111
|
finally { if (mine === generation) { loading = false; lastRefresh = Date.now(); render(); } }
|
|
49
112
|
}
|
|
113
|
+
function notify(text, error = false) {
|
|
114
|
+
overlay.querySelector('.widget-pin-note')?.remove();
|
|
115
|
+
const note = el('div', `widget-pin-note${error ? ' is-error' : ''}`, text); note.setAttribute('role', 'status'); overlay.append(note);
|
|
116
|
+
setTimeout(() => note.remove(), 4000);
|
|
117
|
+
}
|
|
118
|
+
function showConfirmation(card, item, mine, current) {
|
|
119
|
+
const shade = el('div', 'widget-confirm-backdrop');
|
|
120
|
+
const dialog = el('section', 'widget-confirm'); dialog.setAttribute('role', 'alertdialog'); dialog.setAttribute('aria-label', '删除小挂件?');
|
|
121
|
+
dialog.append(el('h4', '', '删除小挂件?'), el('p', '', '将删除小挂件和其中的数据,所有会话里的引用及首页固定都会失效。此操作不可恢复。'));
|
|
122
|
+
const actions = el('div', 'widget-confirm-actions');
|
|
123
|
+
const cancel = button('取消', () => { if (!busy) { shade.remove(); card.querySelector('.widget-more')?.focus(); } });
|
|
124
|
+
const remove = button('删除', async () => {
|
|
125
|
+
if (busy) return;
|
|
126
|
+
busy = true; cancel.disabled = true; remove.disabled = true; remove.textContent = '正在删除…';
|
|
127
|
+
try {
|
|
128
|
+
await api(`/api/simulator/widgets/${encodeURIComponent(item.id)}`, {method:'DELETE'});
|
|
129
|
+
if (mine !== openRevision || current !== generation) return;
|
|
130
|
+
items = items.filter(value => value.id !== item.id); render(); busy = false; close();
|
|
131
|
+
} catch {
|
|
132
|
+
if (mine !== openRevision || current !== generation) return;
|
|
133
|
+
shade.remove(); notify('操作失败,请稍后重试', true);
|
|
134
|
+
} finally { if (mine === openRevision && current === generation) busy = false; }
|
|
135
|
+
}, 'widget-destructive');
|
|
136
|
+
actions.append(cancel, remove); dialog.append(actions); shade.append(dialog); card.append(shade); cancel.focus();
|
|
137
|
+
}
|
|
138
|
+
function showShare(card) {
|
|
139
|
+
// Sharing chooses real conversations in the App; the simulator never fabricates recipients.
|
|
140
|
+
const notice = el('div', 'widget-native-share');
|
|
141
|
+
notice.append(el('h4', '', '在搭搭 App 中分享'), el('p', '', '使用真机预览打开这个搭子,在小挂件的「分享」中选择聊天。'));
|
|
142
|
+
notice.append(button('打开真机预览', () => { close(true); document.querySelector('#pair-device').click(); }), button('返回小挂件', () => notice.remove()));
|
|
143
|
+
card.append(notice); notice.querySelector('button').focus();
|
|
144
|
+
}
|
|
145
|
+
function ownerMenu(card, item, mine, current) {
|
|
146
|
+
const old = card.querySelector('.widget-options'); if (old) { old.remove(); return; }
|
|
147
|
+
const currentItem = items.find(value => value.id === item.id);
|
|
148
|
+
if (currentItem?.role !== 'owner' || busy) return;
|
|
149
|
+
const menu = el('div', 'widget-options'); menu.setAttribute('role', 'menu');
|
|
150
|
+
const share = button('分享', () => { menu.remove(); showShare(card); });
|
|
151
|
+
const pin = button(currentItem.isPinned ? '从首页取消固定' : '固定到首页', async () => {
|
|
152
|
+
if (busy) return; busy = true; menu.querySelectorAll('button').forEach(node => { node.disabled = true; });
|
|
153
|
+
try {
|
|
154
|
+
await api(`/api/simulator/widgets/${encodeURIComponent(item.id)}/pin`, {method:currentItem.isPinned ? 'DELETE' : 'PUT'});
|
|
155
|
+
if (mine !== openRevision || current !== generation) return;
|
|
156
|
+
currentItem.isPinned = !currentItem.isPinned; menu.remove(); notify(currentItem.isPinned ? '已固定到首页' : '已从首页取消固定');
|
|
157
|
+
} catch {
|
|
158
|
+
if (mine === openRevision && current === generation) { menu.remove(); notify('操作失败,请稍后重试', true); }
|
|
159
|
+
} finally { if (mine === openRevision && current === generation) busy = false; }
|
|
160
|
+
});
|
|
161
|
+
const remove = button('删除小挂件', () => { menu.remove(); showConfirmation(card, item, mine, current); }, 'widget-destructive');
|
|
162
|
+
share.prepend(menuIcon('share')); pin.prepend(menuIcon(currentItem.isPinned ? 'unpin' : 'pin')); remove.prepend(menuIcon('trash'));
|
|
163
|
+
for (const row of [share, pin, ...(canDelete ? [remove] : [])]) { row.setAttribute('role', 'menuitem'); menu.append(row); }
|
|
164
|
+
card.append(menu); share.focus();
|
|
165
|
+
}
|
|
50
166
|
async function open(item) {
|
|
51
167
|
if (!item.type || !ready) return;
|
|
52
168
|
const mine = ++openRevision, current = generation;
|
|
53
169
|
if (overlay.hidden) focusBefore = document.activeElement;
|
|
54
|
-
|
|
170
|
+
clearTimeout(collapseTimer); clearTimeout(closeTimer); closeChoices(false); timers(); busy = false;
|
|
55
171
|
selected = item; document.querySelector('#message-input').blur();
|
|
56
|
-
overlay.replaceChildren(); overlay.hidden = false;
|
|
172
|
+
overlay.replaceChildren(); overlay.hidden = false; overlay.dataset.state = 'opening';
|
|
57
173
|
const card = el('section', 'widget-modal'); card.setAttribute('role', 'dialog'); card.setAttribute('aria-modal', 'true'); card.setAttribute('aria-label', item.title);
|
|
58
174
|
const header = el('header', 'widget-modal-header');
|
|
59
|
-
const dismiss = button('×', close); dismiss.setAttribute('aria-label', '关闭小挂件');
|
|
60
|
-
const more = button('···', () =>
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
await api(`/api/simulator/widgets/${encodeURIComponent(item.id)}/pin`, { method: currentItem.isPinned ? 'DELETE' : 'PUT' });
|
|
68
|
-
if (mine !== openRevision || current !== generation) return;
|
|
69
|
-
currentItem.isPinned = !currentItem.isPinned; menu.remove();
|
|
70
|
-
const note = el('div', 'widget-pin-note', currentItem.isPinned ? '已固定到首页' : '已从首页取消固定'); note.setAttribute('role', 'status'); card.append(note); setTimeout(() => note.remove(), 4000);
|
|
71
|
-
} catch (error) { if (mine === openRevision) { menu.replaceChildren(el('p', '', error.message), button('知道了', () => menu.remove())); } }
|
|
72
|
-
}));
|
|
73
|
-
menu.append(button('刷新', () => open(item))); card.append(menu);
|
|
74
|
-
}); more.setAttribute('aria-label', '小挂件更多');
|
|
75
|
-
header.append(dismiss, el('h3', '', item.title), more);
|
|
76
|
-
const body = el('div', 'widget-modal-body'); body.append(el('p', 'widget-loading', '正在打开小挂件…'));
|
|
77
|
-
card.append(header, body); overlay.append(card);
|
|
175
|
+
const dismiss = button('×', () => close()); dismiss.setAttribute('aria-label', '关闭小挂件');
|
|
176
|
+
const more = button('···', () => ownerMenu(card, item, mine, current), 'widget-more'); more.setAttribute('aria-label', '小挂件更多'); more.hidden = true;
|
|
177
|
+
const slot = el('div', 'widget-more-slot'); slot.append(more);
|
|
178
|
+
header.append(dismiss, el('h3', '', item.title), slot);
|
|
179
|
+
const body = el('div', 'widget-modal-body'); body.setAttribute('aria-busy', 'true');
|
|
180
|
+
const loadingView = el('div', 'widget-loading'); loadingView.setAttribute('role', 'status');
|
|
181
|
+
loadingView.append(el('span', 'widget-spinner'), el('p', '', '正在打开小挂件…'));
|
|
182
|
+
body.append(loadingView); card.append(header, body); overlay.append(card);
|
|
78
183
|
for (const child of phone.children) if (child !== overlay) child.inert = true;
|
|
79
184
|
dismiss.focus();
|
|
80
|
-
|
|
81
|
-
const url = previewUrl(`/api/simulator/widgets/${encodeURIComponent(item.id)}`);
|
|
82
|
-
// Probe errors in the parent; actual HTML executes only inside the opaque sandbox document.
|
|
83
|
-
const response = await fetch(url, { credentials: 'same-origin' });
|
|
84
|
-
if (!response.ok) { const error = await response.json(); throw new Error(error.error?.message || error.error || '小挂件暂时无法打开'); }
|
|
85
|
-
await response.arrayBuffer();
|
|
185
|
+
const failedLoad = () => {
|
|
86
186
|
if (mine !== openRevision || current !== generation) return;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
187
|
+
timers(); body.setAttribute('aria-busy', 'false');
|
|
188
|
+
const failure = el('div', 'widget-failure'); failure.setAttribute('role', 'status');
|
|
189
|
+
failure.append(el('span', 'widget-failure-mark', '!'), el('h4', '', '小挂件暂时无法打开'), el('p', '', '加载失败,请稍后重试'), button('重新加载', () => open(item)));
|
|
190
|
+
body.replaceChildren(failure);
|
|
191
|
+
};
|
|
192
|
+
const frame = el('iframe', 'widget-document'); frame.title = item.title; frame.setAttribute('sandbox', 'allow-scripts'); frame.referrerPolicy = 'no-referrer'; frame.style.visibility = 'hidden';
|
|
193
|
+
documentFrame = frame; documentToken = crypto.randomUUID();
|
|
194
|
+
const url = new URL(window.previewApiUrl?.(`/api/simulator/widgets/${encodeURIComponent(item.id)}`) ?? `/api/simulator/widgets/${encodeURIComponent(item.id)}`, location.href);
|
|
195
|
+
url.searchParams.set('render', documentToken); frame.src = url.href;
|
|
196
|
+
documentReady = state => {
|
|
97
197
|
if (mine !== openRevision || current !== generation) return;
|
|
98
|
-
|
|
99
|
-
|
|
198
|
+
if (state !== 'ready') { failedLoad(); return; }
|
|
199
|
+
clearTimeout(loadTimer); loadingView.remove(); frame.style.visibility = 'visible'; body.setAttribute('aria-busy', 'false');
|
|
200
|
+
};
|
|
201
|
+
frame.addEventListener('error', failedLoad);
|
|
202
|
+
// Older CLI bridges cannot send lifecycle signals. Keep their document load usable.
|
|
203
|
+
frame.addEventListener('load', () => { if (!documentLifecycle) documentReady?.('ready'); });
|
|
204
|
+
body.append(frame);
|
|
205
|
+
frameObserver = new ResizeObserver(() => {
|
|
206
|
+
const factor = scale(); if (!factor) return;
|
|
207
|
+
frame.style.width = `${body.clientWidth / factor}px`; frame.style.height = `${body.clientHeight / factor}px`;
|
|
208
|
+
frame.style.transform = `scale(${factor})`; frame.style.transformOrigin = 'top left';
|
|
209
|
+
}); frameObserver.observe(body);
|
|
210
|
+
loadTimer = setTimeout(failedLoad, 15000);
|
|
211
|
+
await refresh(true);
|
|
212
|
+
if (mine === openRevision && current === generation) more.hidden = failed || items.find(value => value.id === item.id)?.role !== 'owner';
|
|
100
213
|
}
|
|
214
|
+
window.addEventListener('message', event => {
|
|
215
|
+
if (!documentFrame || event.source !== documentFrame.contentWindow || event.data?.channel !== 'buddy-widget-document' || event.data?.render !== documentToken) return;
|
|
216
|
+
documentReady?.(event.data.state);
|
|
217
|
+
});
|
|
101
218
|
overlay.addEventListener('click', event => { if (event.target === overlay) close(); });
|
|
219
|
+
document.addEventListener('pointerdown', event => {
|
|
220
|
+
if (choices && !shortcut.contains(event.target)) closeChoices();
|
|
221
|
+
const menu = overlay.querySelector('.widget-options');
|
|
222
|
+
if (menu && !menu.contains(event.target) && !event.target.closest('.widget-more')) menu.remove();
|
|
223
|
+
});
|
|
102
224
|
document.addEventListener('keydown', event => {
|
|
103
|
-
if (event.key === 'Escape') {
|
|
225
|
+
if (event.key === 'Escape') {
|
|
226
|
+
if (busy) return;
|
|
227
|
+
const nested = overlay.querySelector('.widget-confirm-backdrop,.widget-native-share,.widget-options');
|
|
228
|
+
if (nested) { nested.remove(); overlay.querySelector('.widget-more')?.focus(); } else if (!overlay.hidden) close(); else closeChoices();
|
|
229
|
+
}
|
|
104
230
|
if (event.key === 'Tab' && !overlay.hidden) {
|
|
105
|
-
const
|
|
231
|
+
const scope = overlay.querySelector('.widget-confirm,.widget-native-share') || overlay;
|
|
232
|
+
const controls = [...scope.querySelectorAll('button:not(:disabled), iframe')].filter(node => !node.hidden && node.getClientRects().length);
|
|
233
|
+
const first = controls[0], last = controls.at(-1);
|
|
106
234
|
if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last?.focus(); }
|
|
107
235
|
else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first?.focus(); }
|
|
108
236
|
}
|
|
109
237
|
});
|
|
110
|
-
document.addEventListener('visibilitychange', () => {
|
|
238
|
+
document.addEventListener('visibilitychange', () => {
|
|
239
|
+
clearTimeout(collapseTimer); closeChoices(false);
|
|
240
|
+
if (!document.hidden) { setPhase('normal'); scheduleCollapse(); void refresh(true); }
|
|
241
|
+
});
|
|
242
|
+
window.addEventListener('pagehide', () => { resize.disconnect(); timers(); clearTimeout(collapseTimer); clearTimeout(closeTimer); });
|
|
111
243
|
return {
|
|
112
|
-
update({
|
|
244
|
+
update({active, conversationRevision, devRevision, reloading = false}) {
|
|
113
245
|
const key = `${conversationRevision || 0}:${devRevision || 0}`;
|
|
114
|
-
if (
|
|
115
|
-
|
|
246
|
+
if (conversationScope !== conversationRevision || (!active && !reloading)) reopenId = undefined;
|
|
247
|
+
else if (selected && (key !== scope || reloading)) reopenId = selected.id;
|
|
248
|
+
conversationScope = conversationRevision;
|
|
249
|
+
if (key !== scope || !active) {
|
|
250
|
+
scope = key; generation++; ready = false; items = []; failed = false; loading = false; lastRefresh = 0; busy = false; documentLifecycle = false; canDelete = false;
|
|
251
|
+
clearTimeout(collapseTimer); close(true);
|
|
252
|
+
}
|
|
253
|
+
ready = active; render();
|
|
254
|
+
const mine = generation;
|
|
255
|
+
void refresh().then(() => {
|
|
256
|
+
if (!ready || mine !== generation || !reopenId) return;
|
|
257
|
+
const item = items.find(value => value.id === reopenId);
|
|
258
|
+
reopenId = undefined;
|
|
259
|
+
if (item) void open(item);
|
|
260
|
+
});
|
|
116
261
|
},
|
|
117
|
-
reset() { generation++; ready = false; items = []; loading = false; failed = false; close(); render(); },
|
|
262
|
+
reset() { reopenId = undefined; generation++; ready = false; items = []; loading = false; failed = false; busy = false; clearTimeout(collapseTimer); close(true); render(); },
|
|
118
263
|
card(item) {
|
|
119
264
|
const card = el('div', 'widget-entry'); card.append(el('h4', '', item.title));
|
|
120
265
|
const details = el('div', 'widget-entry-details');
|
|
121
|
-
if (item.type && item.imageMediaId) {
|
|
122
|
-
|
|
266
|
+
if (item.type && item.imageMediaId) {
|
|
267
|
+
const image = el('img', 'widget-entry-photo'); image.alt = `${item.title}的照片`;
|
|
268
|
+
image.src = window.previewApiUrl?.(`/api/simulator/widgets/${encodeURIComponent(item.id)}/image?mediaId=${encodeURIComponent(item.imageMediaId)}`) ?? `/api/simulator/widgets/${encodeURIComponent(item.id)}/image?mediaId=${encodeURIComponent(item.imageMediaId)}`;
|
|
269
|
+
image.addEventListener('error', () => { image.hidden = true; }); details.append(image);
|
|
270
|
+
}
|
|
271
|
+
details.append(el('p', item.type && item.summary?.trim() ? '' : 'widget-secondary', item.type ? item.summary?.trim() || '打开查看最新内容' : '此小挂件已删除或不可用')); card.append(details);
|
|
123
272
|
if (item.type) card.append(button('去查看', () => open(item), 'widget-entry-open'));
|
|
273
|
+
const permission = {owner:'可管理、分享',editor:'可编辑',viewer:'仅支持查看'}[item.role];
|
|
274
|
+
const metadata = el('div', 'widget-entry-metadata');
|
|
275
|
+
if (item.creatorName?.trim()) metadata.append(el('span', 'widget-creator', `${item.creatorName.trim()}创建`));
|
|
276
|
+
if (permission) metadata.append(el('span', 'widget-permission', (metadata.children.length ? '|' : '') + permission));
|
|
277
|
+
if (metadata.children.length) card.append(metadata);
|
|
124
278
|
return card;
|
|
125
279
|
},
|
|
126
280
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@my-life-buddies/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "搭搭 Developer Platform 命令行工具",
|
|
6
6
|
"publishConfig": {
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"ws": "8.21.3"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@buddy/cli-core": "0.
|
|
43
|
-
"@buddy/preview": "0.
|
|
42
|
+
"@buddy/cli-core": "0.15.0",
|
|
43
|
+
"@buddy/preview": "0.15.0"
|
|
44
44
|
}
|
|
45
45
|
}
|
package/resources/README.md
CHANGED
|
@@ -1,54 +1,10 @@
|
|
|
1
|
-
# CLI
|
|
1
|
+
# CLI 分发资源
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
此目录包含工程模板和品牌资源。Creator 与 Avatar 规则、工具和参考图均由独立 npm 资源包提供,不进入 CLI 安装包。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
- Creator:`@my-life-buddies/creator-skill`,项目锁 `.buddy/creator/skill-lock.json`。
|
|
6
|
+
- Avatar:`avatar-creator-skill`,项目锁 `.buddy/meta/skill-lock.json`。仅生成头像时加载;已有图片确认和上传无需该包。
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
| --- | --- | --- |
|
|
9
|
-
| Skill 规则、Python 工具、预览资源 | 安装包内的 `resources/buddy-creator/` | Coding Agent 读取和执行;维护者随版本升级 |
|
|
10
|
-
| 来源与文件摘要 | [buddy-creator.manifest.json](buddy-creator.manifest.json) | 构建过程校验 |
|
|
11
|
-
| 云端身份绑定、初始背景、接续说明、作品与 Booklet | 开发者工程的 `.buddy/creator/` | CLI 创建绑定,Coding Agent 继续创作 |
|
|
8
|
+
`src/init/skill-package.ts` 负责两者共用的下载、完整性校验、缓存和版本锁定,各自协议由 `creator-package.ts` 与 `avatar-package.ts` 定义。安装禁用 npm 脚本,已有缓存可离线准备 Skill,平台身份操作仍需要联网。
|
|
12
9
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
CLI 只准备接续,不执行采访推理,也不把准备成功当成手册完成。Skill 返回 `creator_complete` 后,当前 Coding Agent 退出采访,按接续说明继续开发;已经明确的技术选择直接沿用,缺少必要选择时主动询问。没有常驻 CLI 进程替 Coding Agent 编写代码。操作流程见 [CLI 使用说明](../../../apps/cli/README.md#想法还模糊时先梳理需求)。
|
|
16
|
-
|
|
17
|
-
## 这份快照来自哪里
|
|
18
|
-
|
|
19
|
-
来源是 [Buddy-Creator-Skill](https://github.com/my-life-buddies/Buddy-Creator-Skill),固定 `main` 提交为 `f642ddd59e1c30a5d4d3a2e9f6a6811f61ce1f2f`,产品版本 **1.3.0**。
|
|
20
|
-
|
|
21
|
-
这次更新引入更自然的提问规则、按具体缺口记录的追问边界,以及无新增信息时的收口处理。`scripts/interview.py` 负责计数与状态,Coding Agent 根据真实回答提交 `interview.assessment`;它不是新的采访模型服务。详细字段见 [宿主协议](buddy-creator/references/host-guide.md)。
|
|
22
|
-
|
|
23
|
-
收录范围按上游安装清单确定:四个顶层文件和 `agents`、`assets`、`references`、`scripts`。Git 元数据、开发打包工具和用户作品不在其中;第三方许可证保留。
|
|
24
|
-
|
|
25
|
-
当前本地补丁包括以下接入规则;完整清单以 manifest 的 localPatches 和 [补丁说明](buddy-creator/PATCHES.md) 为准,内置版本为 1.4.0:
|
|
26
|
-
|
|
27
|
-
- `initial-context-opening`:CLI 把登记资料写入 `initial-context.json`,Skill 接收后由 Coding Agent 按已有主题准备开场。新登记的资料须由用户提供、确认或授权代定;平台快照本身不证明用户确认,旧记录还可能包含未经确认的暂拟文案。基础资料也不算采访回答或四册确认。开场使用 1.3.0 的问题与缺口绑定;缺省 gapId 和旧开场记录都能安全重试。
|
|
28
|
-
- `completion-return`:Skill 显式报告创作完成或成果待恢复,CLI 接续说明负责把当前 Coding Agent 带回开发流程。手册缺失、失效或项目暂停时不进入开发;用户只要设计时也不自动扩展任务。
|
|
29
|
-
- `small-widget-design` 与后续视觉补丁:四册后增加只读小挂件清单、两视图三态原型和设计验收;不同内容类型使用不同布局,旧版原型资源保持不变。
|
|
30
|
-
- `development-after-design-acceptance`:全部必需设计确认并通过交付校验后,完整创建任务由当前 Coding Agent 同一轮自动接回开发,不停在成果链接或追加开始确认。
|
|
31
|
-
|
|
32
|
-
manifest 的 revision 指向上游基线,localPatches 标记本地调整,文件摘要对应实际分发内容。
|
|
33
|
-
|
|
34
|
-
`cli-core/package.json.files` 显式包含 resources。构建时的 [校验脚本](../scripts/verify-creator-skill.mjs) 比对文件清单、大小和 SHA-256,不联网下载,也不执行 Python。
|
|
35
|
-
|
|
36
|
-
## 执行工具时的约定
|
|
37
|
-
|
|
38
|
-
Coding Agent 使用 Python 3.9+,带 `-B` 并设置 `PYTHONDONTWRITEBYTECODE=1`,让预览子进程也不向安装目录写字节码缓存。创作文件始终写入指定工作区。
|
|
39
|
-
|
|
40
|
-
资源缺失或损坏时,CLI 提示修复安装,不临时从网络下载另一版。Skill 可以不经下载直接使用,不代表登录和平台身份登记可以离线。
|
|
41
|
-
|
|
42
|
-
早期下载版项目会迁移未被用户修改的接续说明,并保留备份、旧 Skill 文件和作品;用户自己改过的说明不自动覆盖。迁移实现位于 [creator.ts](../src/init/creator.ts)。
|
|
43
|
-
|
|
44
|
-
1.0.0 的已有作品仍用原 workspace 接续,不重置回答、确认和进度。只打开不会迁移访谈记录;第一次新提交时按历史回答补齐内部缺口信息。Coding Agent 需要重新读取新版 Skill 和宿主协议,回答旧问题时也按新协议提交 assessment。
|
|
45
|
-
|
|
46
|
-
## 维护者怎样升级
|
|
47
|
-
|
|
48
|
-
先审核上游提交差异,再整体更新快照、来源信息和 manifest;逐项检查 localPatches 是否仍需保留。本地修订也要同步补丁说明和文件摘要,不能把修改后的资源标为未改动的上游快照。
|
|
49
|
-
|
|
50
|
-
升级后,在仓库根目录执行 `npm run check` 和 `npm run verify:package`。后者检查真实 npm 安装后资源是否完整,并在禁用资源下载的条件下验证 create、重试和同身份 direct 衔接。它验证接入流程,不代替人工评审一次完整采访的效果。
|
|
51
|
-
|
|
52
|
-
[上游访谈测试](../../../tests/fixtures/creator-upstream-interview.py) 从同一提交的 `development/test_interview.py` 原样收录,只用于测试,不进入 CLI 安装包。[测试入口](../../../tests/creator-context.test.mjs) 让它运行在实际内置资源上,同时检查我们的背景传递与旧项目兼容。
|
|
53
|
-
|
|
54
|
-
[完成交接测试](../../../tests/fixtures/creator-completion.py) 验证最后一轮、旧项目恢复、成果损坏和暂停等边界;CLI 集成测试继续验证完成后 direct 复用同一个云端身份。它们不等同于一次真实 Coding Agent 的完整创作与开发体验。
|
|
10
|
+
`tests/fixtures/` 是测试输入,不参与构建。安装包验收使用独立提供的 Avatar 测试包和公共 npm Creator 包;可通过 BUDDY_AVATAR_TEST_SKILL_ROOT 指定解包后的真实头像包执行验收。
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"name": "buddy-agent-project",
|
|
9
9
|
"version": "0.0.0",
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@my-life-buddies/buddy-runtime": "0.
|
|
11
|
+
"@my-life-buddies/buddy-runtime": "0.16.0",
|
|
12
12
|
"typebox": "1.3.7"
|
|
13
13
|
},
|
|
14
14
|
"engines": {
|
|
@@ -981,9 +981,9 @@
|
|
|
981
981
|
}
|
|
982
982
|
},
|
|
983
983
|
"node_modules/@my-life-buddies/buddy-runtime": {
|
|
984
|
-
"version": "0.
|
|
985
|
-
"resolved": "https://registry.npmjs.org/@my-life-buddies/buddy-runtime/-/buddy-runtime-0.
|
|
986
|
-
"integrity": "sha512-
|
|
984
|
+
"version": "0.16.0",
|
|
985
|
+
"resolved": "https://registry.npmjs.org/@my-life-buddies/buddy-runtime/-/buddy-runtime-0.16.0.tgz",
|
|
986
|
+
"integrity": "sha512-NkJef6s39Fs/pnxtC5q5ee8dEFMUudPcyO6a4v22xMZmaDIsFBvb/R3D1q1/bVrSCKAvhSaVe0sM9LrhuPn02w==",
|
|
987
987
|
"dependencies": {
|
|
988
988
|
"@earendil-works/pi-agent-core": "0.85.1",
|
|
989
989
|
"@earendil-works/pi-ai": "0.85.1",
|
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
"private": true,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"start": "node start.mjs"
|
|
7
|
+
"start": "node --env-file-if-exists=.env start.mjs"
|
|
8
8
|
},
|
|
9
9
|
"engines": {
|
|
10
10
|
"node": ">=24"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@my-life-buddies/buddy-runtime": "0.
|
|
13
|
+
"@my-life-buddies/buddy-runtime": "0.16.0",
|
|
14
14
|
"typebox": "1.3.7"
|
|
15
15
|
}
|
|
16
16
|
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# 安装 Buddy Creator Skill 1.4.0
|
|
2
|
-
|
|
3
|
-
把完整 ZIP 交给当前宿主 agent,告诉它:
|
|
4
|
-
|
|
5
|
-
> 请安装这个 Buddy Creator Skill,并开始帮我创作一个搭子。
|
|
6
|
-
|
|
7
|
-
本目录为 CLI 内置的 1.4.0 版本,上游基线及补丁见 [PATCHES.md](PATCHES.md)。独立安装上游包可使用[公开安装入口](https://raw.githubusercontent.com/my-life-buddies/Buddy-Creator-Skill/main/start.md);开始创作无需填写 buddyid,也无需选择宿主类型。
|
|
8
|
-
|
|
9
|
-
## 环境与安装
|
|
10
|
-
|
|
11
|
-
本包使用 **Python 3.9+ 标准库**,不需要 Node、npm、pip 或第三方 Python 包。宿主应先查找并复用自己或系统已有的兼容 Python,读取实际版本并保存其绝对路径。没有可用 Python 时需先准备该环境;不能仅检查一次 `python3` 就认定没有 Python,也不能声称完全不需要执行环境。
|
|
12
|
-
|
|
13
|
-
将 ZIP 中的 `buddy-creator` 文件夹安装到当前宿主实际支持的 Skill 目录。Codex、Claude Code、WorkBuddy 的安装入口由各自宿主处理,不要求另注册 agent 或 Expert。无法自动发现 Skill 时,可以让宿主直接读取安装目录中的 `SKILL.md` 并按协议调用。
|
|
14
|
-
|
|
15
|
-
已有同名 `buddy-creator` 时,先备份旧 Skill 文件,再替换程序、规则和预览资源。**不要删除、移动或覆盖创作者工作目录。**若发现用户项目误存于旧安装目录,应先保留该目录并将新版安装到独立位置,不能把项目当作旧程序清理。旧 `buddy-creator-no-node` 试用版可保留;安装后明确使用 `$buddy-creator`,避免混用入口。
|
|
16
|
-
|
|
17
|
-
## 开始与继续
|
|
18
|
-
|
|
19
|
-
新项目不继承其他作品;用户已经给出主题时,宿主通过 `open --context` 传入背景并接着聊,不重新介绍或询问已明确的方向。宿主在创作目录中使用实际发现的 Python 调用 `scripts/buddy.py`,按 `SKILL.md` 分配项目身份;安装目录只存程序,不存作品。创作者不需要自行拼接命令。
|
|
20
|
-
|
|
21
|
-
已有 Python 无 Node 试用版项目,可由新版调用 `open --workspace <原项目绝对路径> --no-browser` 接续,保留原话、进度与确认。此前 Node 0.x 版本的项目及 SQLite/LangGraph 检查点不自动迁移;如需参考,只导入创作者明确选择的手册或资料,不继承历史确认。
|
|
22
|
-
|
|
23
|
-
采访、修改和确认都发生在宿主主对话;浏览器在本机地址展示只读预览。宿主环境需要允许启动本机预览服务,并具有访问该地址的浏览器能力。预览资源已包含在包内,浏览器不负责运行采访模型。
|
|
24
|
-
|
|
25
|
-
本版本未宣称所有宿主和系统组合已完成实机验收。资料读取依赖宿主实际可用工具;不包含小红书账号蒸馏或 coding CLI mock handoff。
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
# BuddyCLI 本地补丁
|
|
2
|
-
|
|
3
|
-
## development-after-design-acceptance
|
|
4
|
-
|
|
5
|
-
统一 Skill、宿主协议、CLI 接续说明和实现指引的开发入口:四册确认后进入小挂件清单、原型和设计验收;以 creator_complete 与有效 ready 交付为完成信号。完整创建任务由当前 Coding Agent 同一轮自动衔接开发,不停在成果链接或增加开始确认。Booklet 交付区同步交接规则,不伪造工程进度;独立设计、流程测试和暂停仍遵守用户范围。保持现有版本、确认和交付校验协议。
|
|
6
|
-
|
|
7
|
-
## small-widget-distinct-layouts
|
|
8
|
-
|
|
9
|
-
第 4 版通过内容结构区分小挂件:日期预览、分组凭条、账本金额、成员分类与变更对照。对话卡片和展开页使用同一份数据生成不同的预览形态。新增只读 changes 布局与受限 before/after 字段,强制区分待确认建议和已生效变化。前三版保持原样,视觉变更提交新原型并使旧验收失效。
|
|
10
|
-
|
|
11
|
-
## small-widget-quiet-blue
|
|
12
|
-
|
|
13
|
-
第 3 版改为白底与可配置的单一强调色,当前旅行示例用蓝色。减少装饰图标、重复统计、胶囊标签与实色按钮,使用下划线导航、细分隔线与内容排版。前两版渲染资源保持原样;新视觉按新版本重新确认。只读交互、尺寸与字体边界不变。
|
|
14
|
-
|
|
15
|
-
## small-widget-visuals
|
|
16
|
-
|
|
17
|
-
新增第 2 版原型渲染器:按阅读任务提供时间线、事项卡、账目、物品清单与资料列表,支持主题概览、关键指标、只读状态、固定线性图标及有数据依据的比例条。对话摘要卡片与展开页共享内容层级,HTML 与 SVG 复用组件;SVG 使用浏览器支持的 foreignObject。第 1 版模板保留原始字节,旧原型恢复不会自动换样式;视觉升级提交新原型并重新确认。Booklet 页面移除共用阅读规范大卡片,规范继续由 Skill、渲染器和验收执行。
|
|
18
|
-
|
|
19
|
-
## small-widget-design
|
|
20
|
-
|
|
21
|
-
新项目在固定四册后增加只读小挂件清单、原型和设计验收,复用公开展示与真实确认协议。Booklet 新增设计页,同步两视图三态、版本依赖、自动检查、开发者验收和可用成果。原型采用受限声明式模板,禁止输入与业务写入。交付检查全部必需文件;按项失效,四册内容另有独立指纹。旧项目不自动重开,明确追加才启用。新增 widgets.py、widget_render.py 及参考文件、页面模块,不修改上游预构建 React 逻辑。面板提醒跨全部阶段沿用一次性记录。
|
|
22
|
-
|
|
23
|
-
上游基线:Buddy Creator Skill 1.3.0,commit `f642ddd59e1c30a5d4d3a2e9f6a6811f61ce1f2f`。
|
|
24
|
-
CLI 内置 Creator 版本为 `1.4.0`,上游基线记录保留上述版本与 commit。
|
|
25
|
-
保留清单中已有的 `initial-context-opening`、`completion-return` 本地改动;本次增加 `interaction-reliability` 补丁。
|
|
26
|
-
|
|
27
|
-
本补丁改善一次完整创作模拟中发现的交互可靠性问题:
|
|
28
|
-
|
|
29
|
-
- 确认失败报告具体对象、未决项、采访缺口、阶段门槛和路径字段差异。
|
|
30
|
-
- JSON 输入拒绝交互式 TTY,文件及非 TTY 管道保持支持;JSON 语法错误包含行列。
|
|
31
|
-
- 输出管道关闭时提示核对持久状态,不把丢失回执当作写入未发生。
|
|
32
|
-
- 普通读取、提交及无 creation-key 的恢复不会创建不存在的工作区。
|
|
33
|
-
- 提供绑定工作区的标准库 BuddyClient,从已保存回执生成版本引用。
|
|
34
|
-
- 蓝图允许显式引用已确认路径,验证版本后复制内容并登记依赖;原有完整对象提交继续有效。
|
|
35
|
-
|
|
36
|
-
工作区格式仍为 `buddy-creator-1`。不迁移或重写已有作品,不改变采访次数、确认授权、必需依赖、未决项或版本一致性规则。资源清单保留上游基线及本地补丁标记,按实际随包文件校验哈希;后续同步上游时应显式核对这些改动。
|
|
37
|
-
|
|
38
|
-
## 开发者平台品牌一致性
|
|
39
|
-
|
|
40
|
-
创作手册预览接入平台共用的青蓝色品牌资源,支持系统浅色/深色主题,统一 Logo、文字、边框、状态色与圆角。保留上游只读交互和内容结构;预构建样式中的固定颜色替换为平台语义变量。`assets/preview/brand.css` 和 `brand-logo.png` 由仓库 `sync:brand` 同步并单独更新校验记录。
|
|
41
|
-
|
|
42
|
-
## Booklet 阅读交互
|
|
43
|
-
|
|
44
|
-
`assets/preview/reader.css` 与 `reader.js` 提供独立的阅读层:对齐平台的青蓝色、字体、圆角、按钮、标签切换、正文间距和弹窗;从已渲染章节生成目录,支持跳转、当前位置高亮和小屏折叠。目录不读取或修改访谈状态。
|
|
45
|
-
|
|
46
|
-
预构建应用只增加 `buddy:reader-browse` 事件的订阅与清理,接到目录跳转时暂停自动跟随,继续复用上游实时更新时的阅读位置保护。复制修改引用及对象版本、确认规则、数据端点和章节内容保持上游实现。同步上游时需保留或移植这一事件桥和阅读层。
|
|
47
|
-
|
|
48
|
-
## preview-panel-reopen
|
|
49
|
-
|
|
50
|
-
- 宿主在接续、阶段切换或展示手册等自然节点查询本作品界面,区分打开、关闭与未知;服务连通性不代替界面检测。
|
|
51
|
-
- 新增标准库 `preview-panel` 命令,将实际观察与一次性提醒写入独立 preview-panel.json;用过一次提醒后,未回应、拒绝或曾同意都不再主动询问,跨接续保留。
|
|
52
|
-
- 提示一次说明查看内容与进度的用途,并给出“请帮我重新打开 Booklet 面板”的主动入口;明确请求直接恢复原作品。
|
|
53
|
-
- 面板操作不改变采访原话、计数、产物、确认或作品版本;不修改预览读写协议。状态检测与实际打开由宿主能力承担,工具只保证提醒记录与去重。
|