@my-life-buddies/cli 0.10.0 → 0.13.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 +26 -12
- package/dist/bin/buddy.js +68 -12
- package/dist/bin/buddy.js.map +3 -3
- package/dist/bin/core.js +1077 -454
- package/dist/bin/core.js.map +4 -4
- package/dist/bin/preview.js +164 -2
- package/dist/bin/preview.js.map +4 -4
- package/dist/web/app.css +38 -0
- package/dist/web/app.js +103 -12
- package/dist/web/index.html +1 -1
- package/dist/web/widgets.js +4 -3
- package/package.json +3 -3
- package/resources/dada-object-avatar/SKILL.md +37 -0
- package/resources/dada-object-avatar/agents/openai.yaml +4 -0
- 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 +22 -0
- package/resources/dada-object-avatar/references/examples.json +8 -0
- package/resources/dada-object-avatar/references/prompt-template.md +27 -0
- package/resources/dada-object-avatar/references/style-system.md +54 -0
- package/resources/dada-object-avatar/references/subject-design.md +23 -0
- package/resources/dada-object-avatar/references/training-guide.md +14 -0
- package/resources/dada-object-avatar/references/training-log.jsonl +0 -0
- package/resources/dada-object-avatar/references/training-record.schema.json +20 -0
- package/resources/dada-object-avatar/scripts/choose_gaze.py +36 -0
- package/resources/dada-object-avatar/scripts/record_example.py +22 -0
- package/resources/dada-object-avatar/scripts/validate_png.py +52 -0
- package/resources/dada-object-avatar.manifest.json +85 -0
package/dist/bin/preview.js
CHANGED
|
@@ -43,6 +43,7 @@ var PreviewController = class {
|
|
|
43
43
|
#simulator;
|
|
44
44
|
#startController;
|
|
45
45
|
#startPromise;
|
|
46
|
+
#stopPromise;
|
|
46
47
|
#messages = [];
|
|
47
48
|
#simulatorState = Object.freeze({ messages: Object.freeze([]) });
|
|
48
49
|
#lastActiveRunId;
|
|
@@ -140,7 +141,17 @@ var PreviewController = class {
|
|
|
140
141
|
this.#startPromise = startPromise;
|
|
141
142
|
return startPromise;
|
|
142
143
|
}
|
|
143
|
-
|
|
144
|
+
stop() {
|
|
145
|
+
if (this.#stopPromise) return this.#stopPromise;
|
|
146
|
+
const stopping = this.#stop();
|
|
147
|
+
this.#stopPromise = stopping;
|
|
148
|
+
const clear = () => {
|
|
149
|
+
if (this.#stopPromise === stopping) this.#stopPromise = void 0;
|
|
150
|
+
};
|
|
151
|
+
void stopping.then(clear, clear);
|
|
152
|
+
return stopping;
|
|
153
|
+
}
|
|
154
|
+
async #stop() {
|
|
144
155
|
if (this.#state.phase === "idle") return this.#state;
|
|
145
156
|
if (this.#state.phase === "stopping") return this.#state;
|
|
146
157
|
this.#setState({ phase: "stopping" });
|
|
@@ -1371,7 +1382,18 @@ var MlbSimulatorClient = class {
|
|
|
1371
1382
|
const signal = AbortSignal.any([AbortSignal.timeout(3e4), ...options.signal ? [options.signal] : []]);
|
|
1372
1383
|
const details = parsePreviewBuddyDetails(await this.#request("GET", `/app/buddies/${encodeURIComponent(this.#buddyId)}`, { signal }), this.#buddyId);
|
|
1373
1384
|
this.#privateId = details.privateId ?? void 0;
|
|
1374
|
-
return details;
|
|
1385
|
+
if (!details.avatar) return details;
|
|
1386
|
+
let avatarPreview = null;
|
|
1387
|
+
try {
|
|
1388
|
+
const url = new URL(details.avatar, this.#baseUrl);
|
|
1389
|
+
if (url.origin !== this.#baseUrl.origin || url.username || url.password || !url.pathname.startsWith("/media/")) throw new Error("Unsupported avatar URL");
|
|
1390
|
+
const image = await this.#widgetResource(url.href, false);
|
|
1391
|
+
const contentType = image.contentType.split(";", 1)[0].trim().toLowerCase();
|
|
1392
|
+
if (!["image/png", "image/jpeg", "image/webp"].includes(contentType)) throw new Error("Unsupported avatar type");
|
|
1393
|
+
avatarPreview = `data:${contentType};base64,${Buffer.from(image.body).toString("base64")}`;
|
|
1394
|
+
} catch {
|
|
1395
|
+
}
|
|
1396
|
+
return Object.freeze({ ...details, avatarPreview });
|
|
1375
1397
|
}
|
|
1376
1398
|
async widgets() {
|
|
1377
1399
|
this.#assertResetComplete();
|
|
@@ -1662,9 +1684,149 @@ var MlbSimulatorClient = class {
|
|
|
1662
1684
|
return value;
|
|
1663
1685
|
}
|
|
1664
1686
|
};
|
|
1687
|
+
|
|
1688
|
+
// apps/preview/src/bridge.ts
|
|
1689
|
+
import { hostname } from "node:os";
|
|
1690
|
+
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
1691
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
1692
|
+
async function connectPreviewBridge(options) {
|
|
1693
|
+
const connectionId = randomBytes2(32).toString("base64url");
|
|
1694
|
+
const shutdown = new AbortController();
|
|
1695
|
+
const signal = AbortSignal.any([options.signal, shutdown.signal]);
|
|
1696
|
+
const running = /* @__PURE__ */ new Map();
|
|
1697
|
+
const replies = /* @__PURE__ */ new Map();
|
|
1698
|
+
const completed = /* @__PURE__ */ new Set();
|
|
1699
|
+
let lastContact = Date.now();
|
|
1700
|
+
let stopping;
|
|
1701
|
+
let interrupted = false;
|
|
1702
|
+
async function call(path, token, payload, requestSignal = signal) {
|
|
1703
|
+
const response = await fetch(new URL(path, options.webUrl), {
|
|
1704
|
+
method: "POST",
|
|
1705
|
+
redirect: "error",
|
|
1706
|
+
signal: AbortSignal.any([requestSignal, AbortSignal.timeout(4e3)]),
|
|
1707
|
+
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
|
|
1708
|
+
body: JSON.stringify(payload ?? {})
|
|
1709
|
+
});
|
|
1710
|
+
const value = await response.json();
|
|
1711
|
+
if (!response.ok) throw Object.assign(new Error(value.error || "\u540E\u53F0\u8FDE\u63A5\u5931\u8D25"), { status: response.status });
|
|
1712
|
+
return value;
|
|
1713
|
+
}
|
|
1714
|
+
const attach = async () => {
|
|
1715
|
+
const result = await call("api/preview/connect", await options.token(), {
|
|
1716
|
+
connectionId,
|
|
1717
|
+
buddyId: options.buddyId,
|
|
1718
|
+
projectRoot: options.controller.projectRoot,
|
|
1719
|
+
machineName: hostname(),
|
|
1720
|
+
platformOrigin: options.platformOrigin
|
|
1721
|
+
});
|
|
1722
|
+
lastContact = Date.now();
|
|
1723
|
+
return result;
|
|
1724
|
+
};
|
|
1725
|
+
const bootstrap = await fetch(options.localServer.bootstrapUrl, { redirect: "manual", signal });
|
|
1726
|
+
const cookie = bootstrap.headers.get("set-cookie")?.split(";", 1)[0];
|
|
1727
|
+
if (bootstrap.status !== 303 || !cookie) throw new Error("\u672C\u5730\u8C03\u8BD5\u670D\u52A1\u521D\u59CB\u5316\u5931\u8D25");
|
|
1728
|
+
const initial = await attach();
|
|
1729
|
+
if (initial.reused) return { reused: true, completion: Promise.resolve(), async close() {
|
|
1730
|
+
} };
|
|
1731
|
+
const watchdog = setInterval(() => {
|
|
1732
|
+
if (Date.now() - lastContact < 1e4 || stopping || interrupted) return;
|
|
1733
|
+
interrupted = true;
|
|
1734
|
+
stopping = options.controller.stop();
|
|
1735
|
+
void stopping.catch(() => shutdown.abort());
|
|
1736
|
+
options.onStatus?.("\u540E\u53F0\u8FDE\u63A5\u5DF2\u65AD\u5F00\uFF0C\u6B63\u5728\u505C\u6B62 DEV\uFF1B\u8FDE\u63A5\u6062\u590D\u540E\u53EF\u5728\u540E\u53F0\u91CD\u65B0\u542F\u52A8\u3002");
|
|
1737
|
+
}, 500);
|
|
1738
|
+
watchdog.unref();
|
|
1739
|
+
async function execute(command) {
|
|
1740
|
+
try {
|
|
1741
|
+
if (!command.path.startsWith("/api/") || command.path === "/api/events" || command.path.includes("..")) throw new Error("\u8C03\u8BD5\u8DEF\u5F84\u65E0\u6548");
|
|
1742
|
+
const target = new URL(command.path, options.localServer.origin);
|
|
1743
|
+
if (target.origin !== options.localServer.origin.origin) throw new Error("\u8C03\u8BD5\u8DEF\u5F84\u65E0\u6548");
|
|
1744
|
+
if ((await options.controller.project()).buddyId !== options.buddyId) throw new Error("\u5DE5\u7A0B buddyId \u5DF2\u6539\u53D8\uFF0C\u8BF7\u9000\u51FA CLI \u540E\u91CD\u65B0\u8FDE\u63A5\u5BF9\u5E94\u642D\u5B50");
|
|
1745
|
+
signal.throwIfAborted();
|
|
1746
|
+
if (interrupted) throw new Error("\u672C\u5730\u8FDE\u63A5\u5DF2\u4E2D\u65AD");
|
|
1747
|
+
const response = await fetch(target, {
|
|
1748
|
+
method: command.method,
|
|
1749
|
+
redirect: "error",
|
|
1750
|
+
signal: AbortSignal.any([signal, AbortSignal.timeout(28e3)]),
|
|
1751
|
+
headers: { Cookie: cookie, ...command.body ? { "Content-Type": "application/json" } : {} },
|
|
1752
|
+
...command.body ? { body: command.body } : {}
|
|
1753
|
+
});
|
|
1754
|
+
const chunks = [];
|
|
1755
|
+
let size = 0;
|
|
1756
|
+
for await (const chunk of response.body ?? []) {
|
|
1757
|
+
size += chunk.length;
|
|
1758
|
+
if (size > 8 * 1024 * 1024) throw new Error("\u8C03\u8BD5\u54CD\u5E94\u8FC7\u5927");
|
|
1759
|
+
chunks.push(Buffer.from(chunk));
|
|
1760
|
+
}
|
|
1761
|
+
replies.set(command.id, { id: command.id, status: response.status, contentType: response.headers.get("content-type") ?? "application/json", body: Buffer.concat(chunks).toString("base64") });
|
|
1762
|
+
} catch {
|
|
1763
|
+
replies.set(command.id, { id: command.id, status: 502, contentType: "application/json", body: Buffer.from(JSON.stringify({ error: { code: "PREVIEW_LOCAL_FAILED", message: "\u672C\u5730\u8C03\u8BD5\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u7EC8\u7AEF\u53CA\u5DE5\u7A0B buddyId" } })).toString("base64") });
|
|
1764
|
+
} finally {
|
|
1765
|
+
running.delete(command.id);
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
const completion = (async () => {
|
|
1769
|
+
try {
|
|
1770
|
+
while (!signal.aborted) {
|
|
1771
|
+
try {
|
|
1772
|
+
if (stopping) {
|
|
1773
|
+
await stopping;
|
|
1774
|
+
stopping = void 0;
|
|
1775
|
+
}
|
|
1776
|
+
const result = await call("api/preview/poll", connectionId, { replies: [...replies.values()].slice(0, 1) });
|
|
1777
|
+
lastContact = Date.now();
|
|
1778
|
+
const recovered = interrupted;
|
|
1779
|
+
if (stopping) {
|
|
1780
|
+
await stopping;
|
|
1781
|
+
stopping = void 0;
|
|
1782
|
+
}
|
|
1783
|
+
if (recovered) {
|
|
1784
|
+
interrupted = false;
|
|
1785
|
+
options.onStatus?.("\u5DF2\u91CD\u65B0\u8FDE\u63A5\u540E\u53F0\uFF0C\u8BF7\u5728\u5F00\u53D1\u8C03\u8BD5\u9875\u542F\u52A8 DEV\u3002");
|
|
1786
|
+
}
|
|
1787
|
+
for (const id of result.acknowledged ?? []) {
|
|
1788
|
+
replies.delete(id);
|
|
1789
|
+
completed.add(id);
|
|
1790
|
+
}
|
|
1791
|
+
while (completed.size > 256) completed.delete(completed.values().next().value);
|
|
1792
|
+
for (const command of result.commands ?? []) {
|
|
1793
|
+
if (recovered && !running.has(command.id) && !replies.has(command.id) && !completed.has(command.id)) {
|
|
1794
|
+
replies.set(command.id, { id: command.id, status: 409, contentType: "application/json", body: Buffer.from(JSON.stringify({ error: { code: "PREVIEW_RECONNECTED", message: "\u672C\u5730\u8FDE\u63A5\u5DF2\u6062\u590D\uFF0C\u8BF7\u91CD\u65B0\u64CD\u4F5C" } })).toString("base64") });
|
|
1795
|
+
}
|
|
1796
|
+
if (!running.has(command.id) && !replies.has(command.id) && !completed.has(command.id) && running.size < 32) running.set(command.id, execute(command));
|
|
1797
|
+
}
|
|
1798
|
+
} catch (cause) {
|
|
1799
|
+
if (signal.aborted) break;
|
|
1800
|
+
const status = cause.status;
|
|
1801
|
+
if (status === 410) {
|
|
1802
|
+
await options.controller.stop();
|
|
1803
|
+
if ((await attach()).reused) throw new Error("\u5F53\u524D\u5DE5\u7A0B\u5DF2\u6709\u5176\u4ED6 CLI \u8FDE\u63A5\uFF0C\u8BF7\u91CD\u65B0\u8FD0\u884C preview \u6253\u5F00\u540E\u53F0");
|
|
1804
|
+
} else if (status && status >= 400 && status < 500 && status !== 429) throw cause;
|
|
1805
|
+
}
|
|
1806
|
+
await delay(replies.size ? 20 : 500, void 0, { signal }).catch(() => void 0);
|
|
1807
|
+
}
|
|
1808
|
+
} finally {
|
|
1809
|
+
clearInterval(watchdog);
|
|
1810
|
+
}
|
|
1811
|
+
})();
|
|
1812
|
+
void completion.catch(() => void 0);
|
|
1813
|
+
return {
|
|
1814
|
+
reused: false,
|
|
1815
|
+
completion,
|
|
1816
|
+
async close() {
|
|
1817
|
+
shutdown.abort();
|
|
1818
|
+
await completion.catch(() => void 0);
|
|
1819
|
+
await Promise.allSettled(running.values());
|
|
1820
|
+
await stopping;
|
|
1821
|
+
await options.controller.stop();
|
|
1822
|
+
await call("api/preview/disconnect", connectionId, {}, AbortSignal.timeout(2e3)).catch(() => void 0);
|
|
1823
|
+
}
|
|
1824
|
+
};
|
|
1825
|
+
}
|
|
1665
1826
|
export {
|
|
1666
1827
|
MlbSimulatorClient,
|
|
1667
1828
|
PreviewController,
|
|
1829
|
+
connectPreviewBridge,
|
|
1668
1830
|
createBuddyPreviewUrl,
|
|
1669
1831
|
startPreviewControlServer
|
|
1670
1832
|
};
|