@thesashadev/girl-agent 0.1.11 → 0.1.13
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/CHANGELOG.md +20 -0
- package/dist/cli.js +516 -31
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.13
|
|
4
|
+
|
|
5
|
+
Дата: 2026-05-08
|
|
6
|
+
|
|
7
|
+
- Merge pull request #56 from TheSashaDev/devin/1778220196-data-migration-system
|
|
8
|
+
- feat: GirlAI OAuth login and token refresh support
|
|
9
|
+
- feat: add GirlAI API preset and recommended status for LLM providers
|
|
10
|
+
- feat: extend migration system with LLM support and auto-run on startup
|
|
11
|
+
- fix: robust version lookup for bundled output, fix AGENTS.md auto-run claim
|
|
12
|
+
- fix: remove unused import, dynamic version from package.json, use static listProfiles
|
|
13
|
+
- feat: AGENTS.md + update command with migration system
|
|
14
|
+
|
|
15
|
+
## 0.1.12
|
|
16
|
+
|
|
17
|
+
Дата: 2026-05-08
|
|
18
|
+
|
|
19
|
+
- Merge pull request #58 from k1gs/fix/daily-life-sleep-schedule-11930283897782997721
|
|
20
|
+
- fix: use dynamic sleep schedule in daily-life prompt generator
|
|
21
|
+
- fix: update daily-life prompt to support dynamic sleep schedules
|
|
22
|
+
|
|
3
23
|
## 0.1.11
|
|
4
24
|
|
|
5
25
|
Дата: 2026-05-07
|
package/dist/cli.js
CHANGED
|
@@ -376,6 +376,27 @@ import BigText from "ink-big-text";
|
|
|
376
376
|
// src/presets/llm.ts
|
|
377
377
|
init_esm_shims();
|
|
378
378
|
var LLM_PRESETS = [
|
|
379
|
+
{
|
|
380
|
+
id: "girlai",
|
|
381
|
+
name: "GirlAI",
|
|
382
|
+
proto: "openai",
|
|
383
|
+
baseURL: "https://api.girl-agent.com/v1",
|
|
384
|
+
defaultModel: "GirlAI-test",
|
|
385
|
+
models: ["GirlAI-test"],
|
|
386
|
+
recommended: true,
|
|
387
|
+
oauth: true,
|
|
388
|
+
hint: "\u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0443\u0435\u043C\u044B\u0439 \xB7 OpenAI-compatible gateway (\u0420\u0424, \u043E\u043F\u043B\u0430\u0442\u0430)"
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
id: "claudehub",
|
|
392
|
+
name: "ClaudeHub",
|
|
393
|
+
proto: "anthropic",
|
|
394
|
+
baseURL: "https://api.claudehub.fun",
|
|
395
|
+
defaultModel: "claude-sonnet-4.6",
|
|
396
|
+
models: ["claude-opus-4.7", "claude-opus-4.6", "claude-opus-4.5", "claude-sonnet-4.6", "claude-sonnet-4.5", "claude-haiku-4.5", "gpt-5.5", "gpt-5.4"],
|
|
397
|
+
recommended: true,
|
|
398
|
+
hint: "\u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0443\u0435\u043C\u044B\u0439 \xB7 ClaudeHub proxy for Anthropic & OpenAI (\u0420\u0424, \u0421\u0411\u041F, \u043A\u0440\u0438\u043F\u0442\u0430)"
|
|
399
|
+
},
|
|
379
400
|
{
|
|
380
401
|
id: "openai",
|
|
381
402
|
name: "OpenAI",
|
|
@@ -514,15 +535,6 @@ var LLM_PRESETS = [
|
|
|
514
535
|
defaultModel: "llama-3.3-70b",
|
|
515
536
|
models: ["llama-3.3-70b", "llama-4-scout-17b-16e-instruct", "qwen-3-32b"]
|
|
516
537
|
},
|
|
517
|
-
{
|
|
518
|
-
id: "claudehub",
|
|
519
|
-
name: "ClaudeHub",
|
|
520
|
-
proto: "anthropic",
|
|
521
|
-
baseURL: "https://api.claudehub.fun",
|
|
522
|
-
defaultModel: "claude-sonnet-4.6",
|
|
523
|
-
models: ["claude-opus-4.7", "claude-opus-4.6", "claude-opus-4.5", "claude-sonnet-4.6", "claude-sonnet-4.5", "claude-haiku-4.5", "gpt-5.5", "gpt-5.4"],
|
|
524
|
-
hint: "ClaudeHub proxy for Anthropic & OpenAI (\u0420\u0424, \u0421\u0411\u041F, \u043A\u0440\u0438\u043F\u0442\u0430)"
|
|
525
|
-
},
|
|
526
538
|
{
|
|
527
539
|
id: "custom-openai",
|
|
528
540
|
name: "Custom (OpenAI-compatible)",
|
|
@@ -1048,6 +1060,150 @@ async function writeAgenda(slug, items) {
|
|
|
1048
1060
|
init_esm_shims();
|
|
1049
1061
|
import OpenAI from "openai";
|
|
1050
1062
|
import Anthropic from "@anthropic-ai/sdk";
|
|
1063
|
+
|
|
1064
|
+
// src/oauth/girlai.ts
|
|
1065
|
+
init_esm_shims();
|
|
1066
|
+
import http from "http";
|
|
1067
|
+
import crypto from "crypto";
|
|
1068
|
+
import { exec } from "child_process";
|
|
1069
|
+
var GIRLAI_BASE = "https://api.girl-agent.com";
|
|
1070
|
+
var AUTHORIZE_URL = `${GIRLAI_BASE}/oauth/authorize`;
|
|
1071
|
+
var TOKEN_URL = `${GIRLAI_BASE}/oauth/token`;
|
|
1072
|
+
var REVOKE_URL = `${GIRLAI_BASE}/oauth/revoke`;
|
|
1073
|
+
var CLIENT_ID = "girl-agent-cli";
|
|
1074
|
+
async function runOAuthFlow(log) {
|
|
1075
|
+
const state = crypto.randomBytes(16).toString("hex");
|
|
1076
|
+
const { port, waitForCode, close } = await startCallbackServer(state);
|
|
1077
|
+
const redirectUri = `http://localhost:${port}/callback`;
|
|
1078
|
+
const authorizeParams = new URLSearchParams({
|
|
1079
|
+
client_id: CLIENT_ID,
|
|
1080
|
+
redirect_uri: redirectUri,
|
|
1081
|
+
response_type: "code",
|
|
1082
|
+
state
|
|
1083
|
+
});
|
|
1084
|
+
const url = `${AUTHORIZE_URL}?${authorizeParams}`;
|
|
1085
|
+
log(`\u043E\u0442\u043A\u0440\u044B\u0432\u0430\u044E \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0434\u043B\u044F \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438: ${url}`);
|
|
1086
|
+
openBrowser(url);
|
|
1087
|
+
let code;
|
|
1088
|
+
try {
|
|
1089
|
+
code = await waitForCode;
|
|
1090
|
+
} finally {
|
|
1091
|
+
close();
|
|
1092
|
+
}
|
|
1093
|
+
log("\u043A\u043E\u0434 \u043F\u043E\u043B\u0443\u0447\u0435\u043D, \u043E\u0431\u043C\u0435\u043D\u0438\u0432\u0430\u044E \u043D\u0430 \u0442\u043E\u043A\u0435\u043D...");
|
|
1094
|
+
return exchangeCode(code, redirectUri);
|
|
1095
|
+
}
|
|
1096
|
+
async function exchangeCode(code, redirectUri) {
|
|
1097
|
+
const body = new URLSearchParams({
|
|
1098
|
+
grant_type: "authorization_code",
|
|
1099
|
+
code,
|
|
1100
|
+
client_id: CLIENT_ID,
|
|
1101
|
+
redirect_uri: redirectUri
|
|
1102
|
+
});
|
|
1103
|
+
const res = await fetch(TOKEN_URL, {
|
|
1104
|
+
method: "POST",
|
|
1105
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
1106
|
+
body: body.toString()
|
|
1107
|
+
});
|
|
1108
|
+
if (!res.ok) {
|
|
1109
|
+
const text = await res.text();
|
|
1110
|
+
throw new Error(`OAuth token exchange failed (${res.status}): ${text}`);
|
|
1111
|
+
}
|
|
1112
|
+
const data = await res.json();
|
|
1113
|
+
return {
|
|
1114
|
+
accessToken: data.access_token,
|
|
1115
|
+
refreshToken: data.refresh_token,
|
|
1116
|
+
expiresAt: Date.now() + data.expires_in * 1e3
|
|
1117
|
+
};
|
|
1118
|
+
}
|
|
1119
|
+
async function refreshAccessToken(refreshToken) {
|
|
1120
|
+
const body = new URLSearchParams({
|
|
1121
|
+
grant_type: "refresh_token",
|
|
1122
|
+
refresh_token: refreshToken,
|
|
1123
|
+
client_id: CLIENT_ID
|
|
1124
|
+
});
|
|
1125
|
+
const res = await fetch(TOKEN_URL, {
|
|
1126
|
+
method: "POST",
|
|
1127
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
1128
|
+
body: body.toString()
|
|
1129
|
+
});
|
|
1130
|
+
if (!res.ok) {
|
|
1131
|
+
const text = await res.text();
|
|
1132
|
+
throw new Error(`OAuth token refresh failed (${res.status}): ${text}`);
|
|
1133
|
+
}
|
|
1134
|
+
const data = await res.json();
|
|
1135
|
+
return {
|
|
1136
|
+
accessToken: data.access_token,
|
|
1137
|
+
refreshToken: data.refresh_token,
|
|
1138
|
+
expiresAt: Date.now() + data.expires_in * 1e3
|
|
1139
|
+
};
|
|
1140
|
+
}
|
|
1141
|
+
function isTokenExpired(expiresAt) {
|
|
1142
|
+
return Date.now() >= expiresAt - 6e4;
|
|
1143
|
+
}
|
|
1144
|
+
function startCallbackServer(expectedState) {
|
|
1145
|
+
return new Promise((resolveSetup) => {
|
|
1146
|
+
let resolveCode;
|
|
1147
|
+
let rejectCode;
|
|
1148
|
+
const waitForCode = new Promise((res, rej) => {
|
|
1149
|
+
resolveCode = res;
|
|
1150
|
+
rejectCode = rej;
|
|
1151
|
+
});
|
|
1152
|
+
const timeout = setTimeout(() => {
|
|
1153
|
+
rejectCode(new Error("OAuth callback timeout (5 minutes)"));
|
|
1154
|
+
server.close();
|
|
1155
|
+
}, 5 * 60 * 1e3);
|
|
1156
|
+
const server = http.createServer((req, res) => {
|
|
1157
|
+
const url = new URL(req.url ?? "/", `http://localhost`);
|
|
1158
|
+
if (url.pathname !== "/callback") {
|
|
1159
|
+
res.writeHead(404);
|
|
1160
|
+
res.end("not found");
|
|
1161
|
+
return;
|
|
1162
|
+
}
|
|
1163
|
+
const code = url.searchParams.get("code");
|
|
1164
|
+
const state = url.searchParams.get("state");
|
|
1165
|
+
const error = url.searchParams.get("error");
|
|
1166
|
+
if (error) {
|
|
1167
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
1168
|
+
res.end("<h2>\u0410\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044F \u043E\u0442\u043A\u043B\u043E\u043D\u0435\u043D\u0430</h2><p>\u041C\u043E\u0436\u0435\u0448\u044C \u0437\u0430\u043A\u0440\u044B\u0442\u044C \u044D\u0442\u0443 \u0432\u043A\u043B\u0430\u0434\u043A\u0443.</p>");
|
|
1169
|
+
clearTimeout(timeout);
|
|
1170
|
+
rejectCode(new Error(`OAuth denied: ${error}`));
|
|
1171
|
+
return;
|
|
1172
|
+
}
|
|
1173
|
+
if (!code || state !== expectedState) {
|
|
1174
|
+
res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
|
|
1175
|
+
res.end("<h2>\u041E\u0448\u0438\u0431\u043A\u0430</h2><p>\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 state \u0438\u043B\u0438 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 code.</p>");
|
|
1176
|
+
return;
|
|
1177
|
+
}
|
|
1178
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
1179
|
+
res.end("<h2>\u0410\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044F \u0443\u0441\u043F\u0435\u0448\u043D\u0430!</h2><p>\u041C\u043E\u0436\u0435\u0448\u044C \u0437\u0430\u043A\u0440\u044B\u0442\u044C \u044D\u0442\u0443 \u0432\u043A\u043B\u0430\u0434\u043A\u0443 \u0438 \u0432\u0435\u0440\u043D\u0443\u0442\u044C\u0441\u044F \u0432 \u0442\u0435\u0440\u043C\u0438\u043D\u0430\u043B.</p>");
|
|
1180
|
+
clearTimeout(timeout);
|
|
1181
|
+
resolveCode(code);
|
|
1182
|
+
});
|
|
1183
|
+
server.listen(0, "127.0.0.1", () => {
|
|
1184
|
+
const addr = server.address();
|
|
1185
|
+
const port = typeof addr === "object" && addr ? addr.port : 0;
|
|
1186
|
+
resolveSetup({
|
|
1187
|
+
port,
|
|
1188
|
+
waitForCode,
|
|
1189
|
+
close: () => server.close()
|
|
1190
|
+
});
|
|
1191
|
+
});
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1194
|
+
function openBrowser(url) {
|
|
1195
|
+
const platform = process.platform;
|
|
1196
|
+
const cmd = platform === "darwin" ? `open "${url}"` : platform === "win32" ? `start "" "${url}"` : `xdg-open "${url}" 2>/dev/null || sensible-browser "${url}" 2>/dev/null || echo "\u043E\u0442\u043A\u0440\u043E\u0439 \u0432\u0440\u0443\u0447\u043D\u0443\u044E: ${url}"`;
|
|
1197
|
+
exec(cmd, (err) => {
|
|
1198
|
+
if (err) {
|
|
1199
|
+
process.stderr.write(`[girlai-oauth] \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043E\u0442\u043A\u0440\u044B\u0442\u044C \u0431\u0440\u0430\u0443\u0437\u0435\u0440, \u043E\u0442\u043A\u0440\u043E\u0439 \u0432\u0440\u0443\u0447\u043D\u0443\u044E:
|
|
1200
|
+
${url}
|
|
1201
|
+
`);
|
|
1202
|
+
}
|
|
1203
|
+
});
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
// src/llm/index.ts
|
|
1051
1207
|
var LLM_TIMEOUT_MS = 12e4;
|
|
1052
1208
|
var LLM_MAX_RETRIES = 1;
|
|
1053
1209
|
var OpenAILike = class {
|
|
@@ -1070,7 +1226,24 @@ var OpenAILike = class {
|
|
|
1070
1226
|
cfg;
|
|
1071
1227
|
client;
|
|
1072
1228
|
fetchClient;
|
|
1229
|
+
async ensureFreshToken() {
|
|
1230
|
+
if (!this.cfg.oauthRefreshToken || !this.cfg.oauthExpiresAt) return;
|
|
1231
|
+
if (!isTokenExpired(this.cfg.oauthExpiresAt)) return;
|
|
1232
|
+
try {
|
|
1233
|
+
const tokens = await refreshAccessToken(this.cfg.oauthRefreshToken);
|
|
1234
|
+
this.cfg.apiKey = tokens.accessToken;
|
|
1235
|
+
this.cfg.oauthRefreshToken = tokens.refreshToken;
|
|
1236
|
+
this.cfg.oauthExpiresAt = tokens.expiresAt;
|
|
1237
|
+
const key = tokens.accessToken;
|
|
1238
|
+
this.client = new OpenAI({ apiKey: key, baseURL: normalizeBaseURL(this.cfg.baseURL), timeout: LLM_TIMEOUT_MS, maxRetries: LLM_MAX_RETRIES });
|
|
1239
|
+
this.fetchClient = new OpenAI({ apiKey: key, baseURL: normalizeBaseURL(this.cfg.baseURL), timeout: LLM_TIMEOUT_MS, maxRetries: LLM_MAX_RETRIES, fetch: compatibleFetch });
|
|
1240
|
+
} catch (err) {
|
|
1241
|
+
process.stderr.write(`[oauth] token refresh failed: ${err instanceof Error ? err.message : err}
|
|
1242
|
+
`);
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1073
1245
|
async chat(messages, opts = {}) {
|
|
1246
|
+
await this.ensureFreshToken();
|
|
1074
1247
|
const params = {
|
|
1075
1248
|
model: this.cfg.model,
|
|
1076
1249
|
messages: openAIMessages(messages),
|
|
@@ -1559,14 +1732,14 @@ var DEFAULT_PROXY = "https://tgproxy.girl-agent.com";
|
|
|
1559
1732
|
function proxyUrl() {
|
|
1560
1733
|
return process.env.GIRL_AGENT_AUTH_PROXY ?? DEFAULT_PROXY;
|
|
1561
1734
|
}
|
|
1562
|
-
async function post(
|
|
1563
|
-
const res = await fetch(`${proxyUrl()}${
|
|
1735
|
+
async function post(path7, body) {
|
|
1736
|
+
const res = await fetch(`${proxyUrl()}${path7}`, {
|
|
1564
1737
|
method: "POST",
|
|
1565
1738
|
headers: { "Content-Type": "application/json" },
|
|
1566
1739
|
body: JSON.stringify(body)
|
|
1567
1740
|
});
|
|
1568
1741
|
const data = await res.json();
|
|
1569
|
-
if (!res.ok) throw new Error(data.error ?? `proxy ${
|
|
1742
|
+
if (!res.ok) throw new Error(data.error ?? `proxy ${path7} failed (${res.status})`);
|
|
1570
1743
|
return data;
|
|
1571
1744
|
}
|
|
1572
1745
|
function remoteSendCode(phone) {
|
|
@@ -1813,6 +1986,9 @@ function Wizard({ initial, onDone }) {
|
|
|
1813
1986
|
const [llmBaseURL, setLlmBaseURL] = useState(initial?.llm?.baseURL ?? "");
|
|
1814
1987
|
const [llmModel, setLlmModel] = useState(initial?.llm?.model ?? "");
|
|
1815
1988
|
const [llmKey, setLlmKey] = useState(initial?.llm?.apiKey ?? "");
|
|
1989
|
+
const [oauthRefreshToken, setOauthRefreshToken] = useState(initial?.llm?.oauthRefreshToken ?? "");
|
|
1990
|
+
const [oauthExpiresAt, setOauthExpiresAt] = useState(initial?.llm?.oauthExpiresAt ?? 0);
|
|
1991
|
+
const [oauthStatus, setOauthStatus] = useState("");
|
|
1816
1992
|
const [nationality, setNationality] = useState(initial?.nationality ?? "RU");
|
|
1817
1993
|
const [name, setName] = useState(initial?.name ?? "");
|
|
1818
1994
|
const [ageStr, setAgeStr] = useState(initial?.age ? String(initial.age) : "");
|
|
@@ -2035,7 +2211,7 @@ function Wizard({ initial, onDone }) {
|
|
|
2035
2211
|
SelectInput,
|
|
2036
2212
|
{
|
|
2037
2213
|
limit: 10,
|
|
2038
|
-
items: LLM_PRESETS.map((p) => ({ label: `${p.name}${p.hint ? ` \xB7 ${p.hint}` : ""}`, value: p.id })),
|
|
2214
|
+
items: LLM_PRESETS.map((p) => ({ label: `${p.name}${p.recommended ? " \u2605" : ""}${p.hint ? ` \xB7 ${p.hint}` : ""}`, value: p.id })),
|
|
2039
2215
|
onSelect: (it) => {
|
|
2040
2216
|
const preset = findPreset(it.value);
|
|
2041
2217
|
setLlmPresetId(preset.id);
|
|
@@ -2044,11 +2220,43 @@ function Wizard({ initial, onDone }) {
|
|
|
2044
2220
|
setLlmModel(preset.defaultModel);
|
|
2045
2221
|
setLlmKey(preset.defaultApiKey ?? "");
|
|
2046
2222
|
if (preset.custom) setStep("api-base");
|
|
2223
|
+
else if (preset.oauth) setStep("api-auth-method");
|
|
2047
2224
|
else setStep("api-model");
|
|
2048
2225
|
}
|
|
2049
2226
|
}
|
|
2050
2227
|
)));
|
|
2051
2228
|
}
|
|
2229
|
+
if (step === "api-auth-method") {
|
|
2230
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React.createElement(Header, { sub: "\u0441\u043F\u043E\u0441\u043E\u0431 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438 (GirlAI)" }), /* @__PURE__ */ React.createElement(Bar, { step: 2, total: 9 }), /* @__PURE__ */ React.createElement(Box, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React.createElement(
|
|
2231
|
+
SelectInput,
|
|
2232
|
+
{
|
|
2233
|
+
items: [
|
|
2234
|
+
{ label: "\u{1F511} \u0412\u043E\u0439\u0442\u0438 \u0447\u0435\u0440\u0435\u0437 GirlAI \u0430\u043A\u043A\u0430\u0443\u043D\u0442 (OAuth)", value: "oauth" },
|
|
2235
|
+
{ label: "\u{1F4CB} \u0412\u0432\u0435\u0441\u0442\u0438 API \u043A\u043B\u044E\u0447 \u0432\u0440\u0443\u0447\u043D\u0443\u044E", value: "apikey" }
|
|
2236
|
+
],
|
|
2237
|
+
onSelect: (it) => {
|
|
2238
|
+
if (it.value === "oauth") {
|
|
2239
|
+
setOauthStatus("\u043E\u0442\u043A\u0440\u044B\u0432\u0430\u044E \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0434\u043B\u044F \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438...");
|
|
2240
|
+
setStep("api-oauth");
|
|
2241
|
+
runOAuthFlow((msg) => setOauthStatus(msg)).then((tokens) => {
|
|
2242
|
+
setLlmKey(tokens.accessToken);
|
|
2243
|
+
setOauthRefreshToken(tokens.refreshToken);
|
|
2244
|
+
setOauthExpiresAt(tokens.expiresAt);
|
|
2245
|
+
setStep("api-model");
|
|
2246
|
+
}).catch((err) => {
|
|
2247
|
+
setError(err.message);
|
|
2248
|
+
setStep("api-auth-method");
|
|
2249
|
+
});
|
|
2250
|
+
} else {
|
|
2251
|
+
setStep("api-model");
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
)));
|
|
2256
|
+
}
|
|
2257
|
+
if (step === "api-oauth") {
|
|
2258
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React.createElement(Header, { sub: "\u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044F GirlAI" }), /* @__PURE__ */ React.createElement(Bar, { step: 2, total: 9 }), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Spinner, { type: "dots" }), /* @__PURE__ */ React.createElement(Text, null, " ", oauthStatus || "\u043E\u0436\u0438\u0434\u0430\u044E \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044E \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435...")), error && /* @__PURE__ */ React.createElement(Text, { color: "red" }, error), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "\u0432\u043E\u0439\u0434\u0438 \u0432 \u0430\u043A\u043A\u0430\u0443\u043D\u0442 \u0432 \u043E\u0442\u043A\u0440\u044B\u0432\u0448\u0435\u043C\u0441\u044F \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u0438 \u0440\u0430\u0437\u0440\u0435\u0448\u0438 \u0434\u043E\u0441\u0442\u0443\u043F"));
|
|
2259
|
+
}
|
|
2052
2260
|
if (step === "api-base") {
|
|
2053
2261
|
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React.createElement(Header, { sub: "base URL \u0434\u043B\u044F custom API" }), /* @__PURE__ */ React.createElement(Bar, { step: 2, total: 9 }), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, null, "Base URL: "), /* @__PURE__ */ React.createElement(TextInput, { value: llmBaseURL, onChange: setLlmBaseURL, onSubmit: () => setStep("api-model") })));
|
|
2054
2262
|
}
|
|
@@ -2530,7 +2738,14 @@ function Wizard({ initial, onDone }) {
|
|
|
2530
2738
|
tz: tz || defaultTzForNationality(nationality),
|
|
2531
2739
|
mode,
|
|
2532
2740
|
stage: overrides.stage ?? stage,
|
|
2533
|
-
llm: {
|
|
2741
|
+
llm: {
|
|
2742
|
+
presetId: llmPresetId,
|
|
2743
|
+
proto: llmProto,
|
|
2744
|
+
baseURL: llmBaseURL,
|
|
2745
|
+
apiKey: llmKey,
|
|
2746
|
+
model: llmModel,
|
|
2747
|
+
...oauthRefreshToken ? { oauthRefreshToken, oauthExpiresAt } : {}
|
|
2748
|
+
},
|
|
2534
2749
|
telegram: mode === "bot" ? { botToken } : { apiId: Number(apiId), apiHash, phone, sessionString },
|
|
2535
2750
|
mcp: overrides.mcp ?? pickedMcp.map((id) => ({ id, secrets: mcpSecrets[id] ?? {} })),
|
|
2536
2751
|
privacy,
|
|
@@ -3140,13 +3355,16 @@ ${cfg.busySchedule.map((s) => `- ${s.label}: ${s.from}-${s.to}${s.days ? ` (${s.
|
|
|
3140
3355
|
\u041F\u0435\u0440\u0441\u043E\u043D\u0430 (\u0432\u044B\u0436\u0438\u043C\u043A\u0430):
|
|
3141
3356
|
${persona.slice(0, 1200)}
|
|
3142
3357
|
|
|
3358
|
+
\u041E\u0411\u0420\u0410\u0422\u0418 \u0412\u041D\u0418\u041C\u0410\u041D\u0418\u0415 \u043D\u0430 \u0435\u0451 \u0433\u0440\u0430\u0444\u0438\u043A \u0441\u043D\u0430. \u041E\u043D\u0430 \u043B\u043E\u0436\u0438\u0442\u0441\u044F \u0441\u043F\u0430\u0442\u044C \u0432 ${cfg.sleepFrom}:00 \u0438 \u043F\u0440\u043E\u0441\u044B\u043F\u0430\u0435\u0442\u0441\u044F \u0432 ${cfg.sleepTo}:00.
|
|
3359
|
+
\u0420\u0430\u0441\u043F\u0438\u0441\u0430\u043D\u0438\u0435 (blocks) \u0434\u043E\u043B\u0436\u043D\u043E \u043F\u043E\u043A\u0440\u044B\u0432\u0430\u0442\u044C \u0422\u041E\u041B\u042C\u041A\u041E \u0435\u0451 \u0430\u043A\u0442\u0438\u0432\u043D\u043E\u0435 \u0432\u0440\u0435\u043C\u044F \u0431\u043E\u0434\u0440\u0441\u0442\u0432\u043E\u0432\u0430\u043D\u0438\u044F (\u0432\u0441\u0435 \u0447\u0430\u0441\u044B \u0441\u0443\u0442\u043E\u043A, \u043A\u0440\u043E\u043C\u0435 \u0432\u0440\u0435\u043C\u0435\u043D\u0438 \u0441\u043D\u0430).
|
|
3360
|
+
|
|
3143
3361
|
\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u0443\u0439 STRICT JSON \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0443:
|
|
3144
3362
|
{
|
|
3145
3363
|
"vibe": "1 \u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0435\u043D\u0438\u0435, \u043A\u0430\u043A \u043E\u043D\u0430 \u043E\u0449\u0443\u0449\u0430\u0435\u0442 \u0441\u0435\u0431\u044F \u0441\u0435\u0433\u043E\u0434\u043D\u044F (\u0432\u044F\u043B\u043E/\u0443\u0441\u0442\u0430\u043B\u0430/\u043E\u0442\u0434\u043E\u0445\u043D\u0443\u043B\u0430/\u0437\u043B\u0430\u044F/\u0432 \u043C\u043E\u043C\u0435\u043D\u0442\u0435)",
|
|
3146
3364
|
"weather": "\u0433\u043E\u0440\u043E\u0434+\u043F\u043E\u0433\u043E\u0434\u0430, \u043A\u043E\u0440\u043E\u0442\u043A\u043E\u0439 \u0441\u0442\u0440\u043E\u043A\u043E\u0439 \u043F\u043E \u0435\u0451 \u0440\u0435\u0433\u0438\u043E\u043D\u0443",
|
|
3147
3365
|
"blocks": [
|
|
3148
|
-
{ "fromHour":
|
|
3149
|
-
... (\u0432\u0441\u0435\u0433\u043E 6-9 \u0431\u043B\u043E\u043A\u043E\u0432, \u043F\u043E\u043A\u0440\u044B\u0442\u044C \u0432\u0435\
|
|
3366
|
+
{ "fromHour": ${cfg.sleepTo}, "toHour": ${cfg.sleepTo === 23 ? 0 : cfg.sleepTo + 1}, "activity": "\u043F\u0440\u043E\u0441\u044B\u043F\u0430\u0435\u0442\u0441\u044F, \u043B\u0435\u043D\u0438\u0442\u0441\u044F, \u0441\u043A\u0440\u043E\u043B\u043B\u0438\u0442 \u0442\u0433 \u0432 \u043A\u0440\u043E\u0432\u0430\u0442\u0438", "mood": "\u043D\u0435 \u0432\u044B\u0441\u043F\u0430\u043B\u0430\u0441\u044C", "social": "alone", "phoneAvailable": true },
|
|
3367
|
+
... (\u0432\u0441\u0435\u0433\u043E 6-9 \u0431\u043B\u043E\u043A\u043E\u0432, \u043F\u043E\u043A\u0440\u044B\u0442\u044C \u0432\u0441\u0451 \u0432\u0440\u0435\u043C\u044F \u0435\u0451 \u0431\u043E\u0434\u0440\u0441\u0442\u0432\u043E\u0432\u0430\u043D\u0438\u044F; \u0432\u043A\u043B\u044E\u0447\u0438 \u0443\u0447\u0451\u0431\u0443/\u0440\u0430\u0431\u043E\u0442\u0443 \u0435\u0441\u043B\u0438 \u043F\u043E persona \u0430\u043A\u0442\u0443\u0430\u043B\u044C\u043D\u043E, \u043E\u0431\u0435\u0434, \u0442\u0440\u0435\u043D\u0438\u0440\u043E\u0432\u043A\u0443 \u0438\u043B\u0438 \u043D\u0435\u0442, \u0432\u0440\u0435\u043C\u044F \u0441 \u043F\u043E\u0434\u0440\u0443\u0433\u043E\u0439/\u043E\u0434\u043D\u0430/\u0441 \u0441\u0435\u043C\u044C\u0451\u0439)
|
|
3150
3368
|
],
|
|
3151
3369
|
"events": ["2-3 \u0441\u043B\u0443\u0447\u0430\u0439\u043D\u044B\u0445 \u043C\u0438\u043D\u0438-\u0441\u043E\u0431\u044B\u0442\u0438\u044F \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0441\u0435\u0433\u043E\u0434\u043D\u044F \u043F\u0440\u043E\u0438\u0441\u0445\u043E\u0434\u044F\u0442 (\u043F\u0440\u0435\u043F\u043E\u0434\u0448\u0430 \u043D\u0430\u043E\u0440\u0430\u043B\u0430 / \u0432 \u043A\u0430\u0444\u0435 \u043E\u0448\u0438\u0431\u043B\u0438\u0441\u044C \u0441 \u0437\u0430\u043A\u0430\u0437\u043E\u043C / \u043F\u043E\u0434\u0440\u0443\u0433\u0430 \u043F\u043E\u0437\u0432\u0430\u043B\u0430 \u043D\u0430 \u0442\u0443\u0441\u0443 / \u0440\u0430\u0437\u0431\u043E\u043B\u0435\u043B\u0430\u0441\u044C \u0433\u043E\u043B\u043E\u0432\u0430)"],
|
|
3152
3370
|
"wants": ["2-4 \u0435\u0451 \u0441\u0435\u0433\u043E\u0434\u043D\u044F\u0448\u043D\u0438\u0445 \u0432\u043D\u0443\u0442\u0440\u0435\u043D\u043D\u0438\u0445 \u0436\u0435\u043B\u0430\u043D\u0438\u044F (\u0432\u044B\u0441\u043F\u0430\u0442\u044C\u0441\u044F / \u043D\u043E\u0432\u044B\u0439 \u043A\u0430\u0440\u0434\u0438\u0433\u0430\u043D \u043F\u043E\u0441\u043C\u043E\u0442\u0440\u0435\u0442\u044C / \u0443\u0432\u0438\u0434\u0435\u0442\u044C\u0441\u044F \u0441 \u041C\u0430\u0448\u0435\u0439 / \u043D\u0435 \u043E\u0431\u0449\u0430\u0442\u044C\u0441\u044F \u043D\u0438 \u0441 \u043A\u0435\u043C \u0447\u0430\u0441)"]
|
|
@@ -3165,8 +3383,8 @@ phoneAvailable=false \u043A\u043E\u0433\u0434\u0430: \u0441\u043F\u0438\u0442, \
|
|
|
3165
3383
|
}
|
|
3166
3384
|
async function loadOrGenerateDailyLife(llm, cfg, now = /* @__PURE__ */ new Date(), conflict = null) {
|
|
3167
3385
|
const dateLocal = localDateStr(cfg.tz, now);
|
|
3168
|
-
const
|
|
3169
|
-
const existing = await readMd(cfg.slug,
|
|
3386
|
+
const path7 = `daily-life/${dateLocal}.md`;
|
|
3387
|
+
const existing = await readMd(cfg.slug, path7);
|
|
3170
3388
|
if (existing) {
|
|
3171
3389
|
try {
|
|
3172
3390
|
const m = existing.match(/<!--daily:(.+?)-->/s);
|
|
@@ -3198,7 +3416,7 @@ async function loadOrGenerateDailyLife(llm, cfg, now = /* @__PURE__ */ new Date(
|
|
|
3198
3416
|
dl = { dateLocal, vibe: "\u043E\u0431\u044B\u0447\u043D\u044B\u0439 \u0434\u0435\u043D\u044C", blocks: [], events: [], wants: [] };
|
|
3199
3417
|
}
|
|
3200
3418
|
const human = renderDailyLifeHuman(dl);
|
|
3201
|
-
await writeMd(cfg.slug,
|
|
3419
|
+
await writeMd(cfg.slug, path7, `${human}
|
|
3202
3420
|
|
|
3203
3421
|
<!--daily:${JSON.stringify(dl)}-->
|
|
3204
3422
|
`);
|
|
@@ -3428,9 +3646,9 @@ async function ensureDefaults(cfg) {
|
|
|
3428
3646
|
["time/promises.md", "# promises\n"],
|
|
3429
3647
|
["memory/uncertain.md", "# uncertain\n"]
|
|
3430
3648
|
];
|
|
3431
|
-
await Promise.all(defaults.map(async ([
|
|
3432
|
-
const current = await readMd(cfg.slug,
|
|
3433
|
-
if (!current.trim()) await writeMd(cfg.slug,
|
|
3649
|
+
await Promise.all(defaults.map(async ([path7, content]) => {
|
|
3650
|
+
const current = await readMd(cfg.slug, path7);
|
|
3651
|
+
if (!current.trim()) await writeMd(cfg.slug, path7, content + "\n");
|
|
3434
3652
|
}));
|
|
3435
3653
|
}
|
|
3436
3654
|
async function loadRealismContext(cfg, incoming) {
|
|
@@ -5966,9 +6184,201 @@ function profileSummary(cfg) {
|
|
|
5966
6184
|
|
|
5967
6185
|
// src/server.ts
|
|
5968
6186
|
init_esm_shims();
|
|
5969
|
-
import
|
|
5970
|
-
import
|
|
6187
|
+
import fs5 from "fs/promises";
|
|
6188
|
+
import path6 from "path";
|
|
5971
6189
|
import os from "os";
|
|
6190
|
+
|
|
6191
|
+
// src/migrations/index.ts
|
|
6192
|
+
init_esm_shims();
|
|
6193
|
+
import { promises as fs4 } from "fs";
|
|
6194
|
+
import path5 from "path";
|
|
6195
|
+
import { readFileSync } from "fs";
|
|
6196
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
6197
|
+
|
|
6198
|
+
// src/migrations/0112-add-use-wss-default.ts
|
|
6199
|
+
init_esm_shims();
|
|
6200
|
+
var migration0112 = {
|
|
6201
|
+
id: "0112-add-use-wss-default",
|
|
6202
|
+
description: "\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C WSS \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E \u0432 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u0445 \u043F\u0440\u043E\u0444\u0438\u043B\u044F\u0445",
|
|
6203
|
+
async migrate(ctx) {
|
|
6204
|
+
if (ctx.config.telegram.useWSS === void 0 || ctx.config.telegram.useWSS === false) {
|
|
6205
|
+
ctx.config.telegram.useWSS = true;
|
|
6206
|
+
}
|
|
6207
|
+
return ctx.config;
|
|
6208
|
+
}
|
|
6209
|
+
};
|
|
6210
|
+
|
|
6211
|
+
// src/migrations/0113-ensure-communication-md.ts
|
|
6212
|
+
init_esm_shims();
|
|
6213
|
+
var migration0113 = {
|
|
6214
|
+
id: "0113-ensure-communication-md",
|
|
6215
|
+
description: "\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C communication.md \u0447\u0435\u0440\u0435\u0437 AI \u0435\u0441\u043B\u0438 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442",
|
|
6216
|
+
needsLLM: true,
|
|
6217
|
+
async migrate(ctx) {
|
|
6218
|
+
const { config, llm, log } = ctx;
|
|
6219
|
+
const existing = await readMd(config.slug, "communication.md");
|
|
6220
|
+
if (existing.trim()) return config;
|
|
6221
|
+
if (!llm) {
|
|
6222
|
+
log("communication.md \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442, \u043D\u043E LLM \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D \u2014 \u043F\u0440\u043E\u043F\u0443\u0441\u043A");
|
|
6223
|
+
return config;
|
|
6224
|
+
}
|
|
6225
|
+
const persona = await readMd(config.slug, "persona.md");
|
|
6226
|
+
if (!persona.trim()) {
|
|
6227
|
+
log("persona.md \u0442\u043E\u0436\u0435 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u2014 \u043F\u0440\u043E\u043F\u0443\u0441\u043A \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 communication.md");
|
|
6228
|
+
return config;
|
|
6229
|
+
}
|
|
6230
|
+
log("\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u0443\u0435\u043C communication.md \u0447\u0435\u0440\u0435\u0437 AI...");
|
|
6231
|
+
const prompt = `\u041D\u0430 \u043E\u0441\u043D\u043E\u0432\u0435 persona.md \u043D\u0438\u0436\u0435 \u0441\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u0443\u0439 communication.md \u2014 \u043F\u0440\u0435\u0434\u043F\u043E\u0447\u0442\u0435\u043D\u0438\u044F \u0432 \u043E\u0431\u0449\u0435\u043D\u0438\u0438 ${config.name}, ${config.age} \u043B\u0435\u0442. \u0421\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0430:
|
|
6232
|
+
|
|
6233
|
+
# \u041F\u0440\u0435\u0434\u043F\u043E\u0447\u0442\u0435\u043D\u0438\u044F \u0432 \u043E\u0431\u0449\u0435\u043D\u0438\u0438
|
|
6234
|
+
## \u041A\u043E\u0433\u0434\u0430 \u043F\u0438\u0448\u0435\u0442 (\u0430\u043A\u0442\u0438\u0432\u043D\u044B\u0435 \u0447\u0430\u0441\u044B, \u0447\u0430\u0441\u0442\u043E\u0442\u0430)
|
|
6235
|
+
## \u0421\u0442\u0438\u043B\u044C \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0439 (\u0434\u043B\u0438\u043D\u0430, \u044D\u043C\u043E\u0434\u0437\u0438, \u0441\u0442\u0438\u043A\u0435\u0440\u044B, \u0432\u043E\u0439\u0441\u044B)
|
|
6236
|
+
## \u0427\u0442\u043E \u0431\u0435\u0441\u0438\u0442 \u0432 \u043F\u0435\u0440\u0435\u043F\u0438\u0441\u043A\u0435 (\u043A\u043E\u043D\u043A\u0440\u0435\u0442\u043D\u044B\u0435 \u0442\u0440\u0438\u0433\u0433\u0435\u0440\u044B)
|
|
6237
|
+
## \u0422\u0435\u043C\u044B \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0437\u0430\u0445\u043E\u0434\u044F\u0442 / \u043D\u0435 \u0437\u0430\u0445\u043E\u0434\u044F\u0442
|
|
6238
|
+
## \u0420\u0435\u0430\u043A\u0446\u0438\u044F \u043D\u0430 \u0433\u043E\u043B\u043E\u0441\u043E\u0432\u044B\u0435 / \u0432\u0438\u0434\u0435\u043E / \u0444\u043E\u0442\u043E
|
|
6239
|
+
|
|
6240
|
+
\u041F\u0438\u0448\u0438 \u043E\u0442 \u0442\u0440\u0435\u0442\u044C\u0435\u0433\u043E \u043B\u0438\u0446\u0430, \u043A\u0440\u0430\u0442\u043A\u043E, \u0431\u0435\u0437 \u044D\u043C\u043E\u0434\u0437\u0438. \u041D\u0435 \u0431\u043E\u043B\u0435\u0435 250 \u0441\u043B\u043E\u0432.
|
|
6241
|
+
|
|
6242
|
+
persona.md:
|
|
6243
|
+
${persona}`;
|
|
6244
|
+
const response = await llm.chat([
|
|
6245
|
+
{ role: "system", content: "\u0422\u044B \u0433\u0435\u043D\u0435\u0440\u0438\u0440\u0443\u0435\u0448\u044C \u0444\u0430\u0439\u043B\u044B \u043F\u0440\u043E\u0444\u0438\u043B\u044F \u043F\u0435\u0440\u0441\u043E\u043D\u0430\u0436\u0430 \u0434\u043B\u044F \u0440\u043E\u043B\u0435\u0432\u043E\u0439 \u0438\u0433\u0440\u044B." },
|
|
6246
|
+
{ role: "user", content: prompt }
|
|
6247
|
+
]);
|
|
6248
|
+
if (response?.trim()) {
|
|
6249
|
+
await writeMd(config.slug, "communication.md", response);
|
|
6250
|
+
log("communication.md \u0441\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u043D");
|
|
6251
|
+
}
|
|
6252
|
+
return config;
|
|
6253
|
+
}
|
|
6254
|
+
};
|
|
6255
|
+
|
|
6256
|
+
// src/migrations/index.ts
|
|
6257
|
+
var MIGRATIONS_FILE = () => path5.join(DATA_ROOT, ".migrations.json");
|
|
6258
|
+
async function readMigrationState() {
|
|
6259
|
+
try {
|
|
6260
|
+
const raw = await fs4.readFile(MIGRATIONS_FILE(), "utf8");
|
|
6261
|
+
return JSON.parse(raw);
|
|
6262
|
+
} catch {
|
|
6263
|
+
return { appliedMigrations: [], lastRunVersion: "0.0.0", lastRunAt: "" };
|
|
6264
|
+
}
|
|
6265
|
+
}
|
|
6266
|
+
async function writeMigrationState(state) {
|
|
6267
|
+
await fs4.mkdir(DATA_ROOT, { recursive: true });
|
|
6268
|
+
await fs4.writeFile(MIGRATIONS_FILE(), JSON.stringify(state, null, 2), "utf8");
|
|
6269
|
+
}
|
|
6270
|
+
var ALL_MIGRATIONS = [
|
|
6271
|
+
migration0112,
|
|
6272
|
+
migration0113
|
|
6273
|
+
];
|
|
6274
|
+
async function pendingMigrations() {
|
|
6275
|
+
const state = await readMigrationState();
|
|
6276
|
+
return ALL_MIGRATIONS.filter((m) => !state.appliedMigrations.includes(m.id));
|
|
6277
|
+
}
|
|
6278
|
+
async function runMigrations(opts) {
|
|
6279
|
+
const pending = await pendingMigrations();
|
|
6280
|
+
const log = opts?.verbose ? (msg) => process.stderr.write(msg + "\n") : () => {
|
|
6281
|
+
};
|
|
6282
|
+
if (pending.length === 0) {
|
|
6283
|
+
log("\u0432\u0441\u0435 \u043C\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0443\u0436\u0435 \u043F\u0440\u0438\u043C\u0435\u043D\u0435\u043D\u044B, \u0434\u0430\u043D\u043D\u044B\u0435 \u0430\u043A\u0442\u0443\u0430\u043B\u044C\u043D\u044B.");
|
|
6284
|
+
return { profilesUpdated: 0, migrationsApplied: [], warnings: [], errors: [] };
|
|
6285
|
+
}
|
|
6286
|
+
const profiles = await listProfiles();
|
|
6287
|
+
const state = await readMigrationState();
|
|
6288
|
+
const result = { profilesUpdated: 0, migrationsApplied: [], warnings: [], errors: [] };
|
|
6289
|
+
for (const migration of pending) {
|
|
6290
|
+
log(`
|
|
6291
|
+
[migration] ${migration.id}: ${migration.description}`);
|
|
6292
|
+
let profilesAffected = 0;
|
|
6293
|
+
for (const slug of profiles) {
|
|
6294
|
+
const cfg = await readConfig(slug);
|
|
6295
|
+
if (!cfg) {
|
|
6296
|
+
log(` \u043F\u0440\u043E\u043F\u0443\u0441\u043A ${slug}: \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0442\u044C config.json`);
|
|
6297
|
+
continue;
|
|
6298
|
+
}
|
|
6299
|
+
if (migration.needsInput?.length) {
|
|
6300
|
+
const missing = migration.needsInput.filter((field) => {
|
|
6301
|
+
const val = cfg[field.key];
|
|
6302
|
+
return val === void 0 || val === null || val === "";
|
|
6303
|
+
});
|
|
6304
|
+
if (missing.length > 0) {
|
|
6305
|
+
result.warnings.push({
|
|
6306
|
+
migrationId: migration.id,
|
|
6307
|
+
description: migration.description,
|
|
6308
|
+
missingInputs: missing
|
|
6309
|
+
});
|
|
6310
|
+
log(` \u26A0 ${slug}: \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044F \u0432\u0432\u043E\u0434: ${missing.map((f) => f.label).join(", ")}`);
|
|
6311
|
+
}
|
|
6312
|
+
}
|
|
6313
|
+
let llm;
|
|
6314
|
+
if (migration.needsLLM && opts?.llmFactory) {
|
|
6315
|
+
try {
|
|
6316
|
+
llm = opts.llmFactory(cfg);
|
|
6317
|
+
} catch (e) {
|
|
6318
|
+
log(` ${slug}: \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043E\u0437\u0434\u0430\u0442\u044C LLM: ${e.message}`);
|
|
6319
|
+
}
|
|
6320
|
+
}
|
|
6321
|
+
try {
|
|
6322
|
+
const updated = await migration.migrate({
|
|
6323
|
+
profilePath: profileDir(slug),
|
|
6324
|
+
config: cfg,
|
|
6325
|
+
llm,
|
|
6326
|
+
log: (msg) => log(` ${slug}: ${msg}`)
|
|
6327
|
+
});
|
|
6328
|
+
await writeConfig(updated);
|
|
6329
|
+
profilesAffected++;
|
|
6330
|
+
log(` ${slug}: \u043E\u043A`);
|
|
6331
|
+
} catch (e) {
|
|
6332
|
+
const errMsg = e instanceof Error ? e.message : String(e);
|
|
6333
|
+
log(` ${slug}: \u043E\u0448\u0438\u0431\u043A\u0430 \u2014 ${errMsg}`);
|
|
6334
|
+
result.errors.push({ profile: slug, migration: migration.id, error: errMsg });
|
|
6335
|
+
}
|
|
6336
|
+
}
|
|
6337
|
+
state.appliedMigrations.push(migration.id);
|
|
6338
|
+
result.migrationsApplied.push(migration.id);
|
|
6339
|
+
result.profilesUpdated = Math.max(result.profilesUpdated, profilesAffected);
|
|
6340
|
+
log(` \u043F\u0440\u0438\u043C\u0435\u043D\u0435\u043D\u043E \u043A ${profilesAffected} \u043F\u0440\u043E\u0444\u0438\u043B\u044F\u043C`);
|
|
6341
|
+
}
|
|
6342
|
+
state.lastRunVersion = currentVersion();
|
|
6343
|
+
state.lastRunAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6344
|
+
await writeMigrationState(state);
|
|
6345
|
+
return result;
|
|
6346
|
+
}
|
|
6347
|
+
async function checkForPendingMigrations() {
|
|
6348
|
+
const pending = await pendingMigrations();
|
|
6349
|
+
return pending.length > 0;
|
|
6350
|
+
}
|
|
6351
|
+
function formatUpdateWarnings(warnings) {
|
|
6352
|
+
if (!warnings.length) return "";
|
|
6353
|
+
const lines = ["[updater] \u26A0 \u0434\u043B\u044F \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0438\u044F \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E:"];
|
|
6354
|
+
for (const w of warnings) {
|
|
6355
|
+
for (const field of w.missingInputs) {
|
|
6356
|
+
const secret = field.secret ? " (\u0441\u0435\u043A\u0440\u0435\u0442)" : "";
|
|
6357
|
+
lines.push(` \u2022 ${field.label}${secret} \u2014 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044F \u0434\u043B\u044F: ${w.description}`);
|
|
6358
|
+
}
|
|
6359
|
+
}
|
|
6360
|
+
return lines.join("\n");
|
|
6361
|
+
}
|
|
6362
|
+
function currentVersion() {
|
|
6363
|
+
try {
|
|
6364
|
+
const here = fileURLToPath2(import.meta.url);
|
|
6365
|
+
let dir = path5.dirname(here);
|
|
6366
|
+
for (let i = 0; i < 5; i++) {
|
|
6367
|
+
const candidate = path5.join(dir, "package.json");
|
|
6368
|
+
try {
|
|
6369
|
+
const pkg = JSON.parse(readFileSync(candidate, "utf8"));
|
|
6370
|
+
if (pkg.name === "@thesashadev/girl-agent" && pkg.version) return pkg.version;
|
|
6371
|
+
} catch {
|
|
6372
|
+
}
|
|
6373
|
+
dir = path5.dirname(dir);
|
|
6374
|
+
}
|
|
6375
|
+
return "unknown";
|
|
6376
|
+
} catch {
|
|
6377
|
+
return "unknown";
|
|
6378
|
+
}
|
|
6379
|
+
}
|
|
6380
|
+
|
|
6381
|
+
// src/server.ts
|
|
5972
6382
|
var SERVER_HELP = `
|
|
5973
6383
|
girl-agent server \u2014 automation / ops mode (no TTY required)
|
|
5974
6384
|
|
|
@@ -6062,7 +6472,7 @@ async function runServer(rawArgv) {
|
|
|
6062
6472
|
}
|
|
6063
6473
|
async function persistAndMaybeStart(cfg, args) {
|
|
6064
6474
|
await writeConfig(cfg);
|
|
6065
|
-
process.stderr.write(`[server] \u043F\u0440\u043E\u0444\u0438\u043B\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0451\u043D: ${
|
|
6475
|
+
process.stderr.write(`[server] \u043F\u0440\u043E\u0444\u0438\u043B\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0451\u043D: ${path6.join(DATA_ROOT, cfg.slug)}
|
|
6066
6476
|
`);
|
|
6067
6477
|
if (cfg.llm.apiKey || findPreset(cfg.llm.presetId)?.apiKeyRequired === false) {
|
|
6068
6478
|
try {
|
|
@@ -6088,6 +6498,22 @@ async function persistAndMaybeStart(cfg, args) {
|
|
|
6088
6498
|
await startRuntime(cfg, args);
|
|
6089
6499
|
}
|
|
6090
6500
|
async function startRuntime(cfg, args) {
|
|
6501
|
+
if (await checkForPendingMigrations()) {
|
|
6502
|
+
process.stderr.write("[updater] \u043E\u0431\u043D\u0430\u0440\u0443\u0436\u0435\u043D\u044B pending-\u043C\u0438\u0433\u0440\u0430\u0446\u0438\u0438, \u0437\u0430\u043F\u0443\u0441\u043A...\n");
|
|
6503
|
+
const result = await runMigrations({
|
|
6504
|
+
verbose: true,
|
|
6505
|
+
llmFactory: (c) => {
|
|
6506
|
+
try {
|
|
6507
|
+
return makeLLM(c.llm);
|
|
6508
|
+
} catch {
|
|
6509
|
+
return void 0;
|
|
6510
|
+
}
|
|
6511
|
+
}
|
|
6512
|
+
});
|
|
6513
|
+
if (result.warnings.length) {
|
|
6514
|
+
process.stderr.write(formatUpdateWarnings(result.warnings) + "\n");
|
|
6515
|
+
}
|
|
6516
|
+
}
|
|
6091
6517
|
const rt = new Runtime(cfg);
|
|
6092
6518
|
await rt.start();
|
|
6093
6519
|
const wantsHeadless = !!(args.headless || args.jsonEvents);
|
|
@@ -6160,10 +6586,10 @@ function configFromEnv() {
|
|
|
6160
6586
|
};
|
|
6161
6587
|
}
|
|
6162
6588
|
async function loadConfigFile(file) {
|
|
6163
|
-
const abs =
|
|
6589
|
+
const abs = path6.isAbsolute(file) ? file : path6.join(process.cwd(), file);
|
|
6164
6590
|
let raw;
|
|
6165
6591
|
try {
|
|
6166
|
-
raw = await
|
|
6592
|
+
raw = await fs5.readFile(abs, "utf-8");
|
|
6167
6593
|
} catch (e) {
|
|
6168
6594
|
process.stderr.write(`[server] \u043D\u0435 \u043C\u043E\u0433\u0443 \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0442\u044C ${abs}: ${e?.message ?? e}
|
|
6169
6595
|
`);
|
|
@@ -6357,11 +6783,11 @@ required flags \u0434\u043B\u044F headless setup (--name --age --stage --api-pre
|
|
|
6357
6783
|
--mode=bot|userbot
|
|
6358
6784
|
--token=<bot_token> \u0434\u043B\u044F bot
|
|
6359
6785
|
--api-id=<n> --api-hash=<h> --phone=<+7\u2026> \u0434\u043B\u044F userbot
|
|
6360
|
-
--api-preset=<id> openai|anthropic|openrouter|groq|deepseek|...
|
|
6786
|
+
--api-preset=<id> girlai|claudehub (\u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0443\u0435\u043C\u044B\u0435) | openai|anthropic|openrouter|groq|deepseek|...
|
|
6361
6787
|
--base-url=<url> \u0434\u043B\u044F custom
|
|
6362
6788
|
--proto=openai|anthropic \u0434\u043B\u044F custom
|
|
6363
6789
|
--model=<model>
|
|
6364
|
-
--api-key=<key> \u043D\u0435 \u043D\u0443\u0436\u0435\u043D \u0434\u043B\u044F \u043B\u043E\u043A\u0430\u043B\u044C\u043D\u044B\u0445 LM Studio/Ollama
|
|
6790
|
+
--api-key=<key> \u043D\u0435 \u043D\u0443\u0436\u0435\u043D \u0434\u043B\u044F \u043B\u043E\u043A\u0430\u043B\u044C\u043D\u044B\u0445 LM Studio/Ollama; \u0434\u043B\u044F GirlAI \u043C\u043E\u0436\u043D\u043E \u0432\u043C\u0435\u0441\u0442\u043E \u043A\u043B\u044E\u0447\u0430 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C OAuth (\u0442\u043E\u043B\u044C\u043A\u043E \u0432 TUI \u0432\u0438\u0437\u0430\u0440\u0434\u0435)
|
|
6365
6791
|
--name=<\u0438\u043C\u044F> \u043A\u043E\u043D\u043A\u0440\u0435\u0442\u043D\u043E\u0435 \u0438\u043C\u044F; \u0435\u0441\u043B\u0438 \u043F\u0440\u043E\u043F\u0443\u0441\u0442\u0438\u0442\u044C \u2014 \u0441\u043B\u0443\u0447\u0430\u0439\u043D\u043E\u0435 \u0438\u0437 \u043F\u0443\u043B\u0430 \u043F\u043E nationality (\u0442\u0443\u0440\u043D\u0438\u0440 \u0432\u044B\u0431\u043E\u0440\u0430 \u0438\u043C\u0451\u043D \u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D \u0422\u041E\u041B\u042C\u041A\u041E \u0432 TUI \u0432\u0438\u0437\u0430\u0440\u0434\u0435)
|
|
6366
6792
|
--age=<n>
|
|
6367
6793
|
--persona-notes=<text> \u0434\u043E\u043F. \u043F\u043E\u0436\u0435\u043B\u0430\u043D\u0438\u044F \u043A persona/speech/communication \u043F\u0435\u0440\u0435\u0434 \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0435\u0439
|
|
@@ -6379,6 +6805,10 @@ required flags \u0434\u043B\u044F headless setup (--name --age --stage --api-pre
|
|
|
6379
6805
|
--list \u043F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u043F\u0440\u043E\u0444\u0438\u043B\u0438
|
|
6380
6806
|
--help
|
|
6381
6807
|
|
|
6808
|
+
update:
|
|
6809
|
+
npx girl-agent update # \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u0434\u0430\u043D\u043D\u044B\u0435 (\u043C\u0438\u0433\u0440\u0430\u0446\u0438\u0438) \u0434\u043E \u0442\u0435\u043A\u0443\u0449\u0435\u0439 \u0432\u0435\u0440\u0441\u0438\u0438
|
|
6810
|
+
npx girl-agent update --verbose # \u0441 \u043F\u043E\u0434\u0440\u043E\u0431\u043D\u044B\u043C \u0432\u044B\u0432\u043E\u0434\u043E\u043C
|
|
6811
|
+
|
|
6382
6812
|
\u043A\u043E\u043C\u0430\u043D\u0434\u044B \u0432 \u0440\u0430\u0431\u043E\u0442\u0430\u044E\u0449\u0435\u043C \u0434\u0430\u0448\u0431\u043E\u0440\u0434\u0435: :status :reset :stage <id|num> :pause :resume :cringe :persona :log :quit
|
|
6383
6813
|
`;
|
|
6384
6814
|
async function main() {
|
|
@@ -6421,7 +6851,8 @@ async function main() {
|
|
|
6421
6851
|
"print-config",
|
|
6422
6852
|
"print-systemd",
|
|
6423
6853
|
"print-docker",
|
|
6424
|
-
"no-start"
|
|
6854
|
+
"no-start",
|
|
6855
|
+
"verbose"
|
|
6425
6856
|
],
|
|
6426
6857
|
alias: { h: "help" }
|
|
6427
6858
|
});
|
|
@@ -6431,11 +6862,15 @@ async function main() {
|
|
|
6431
6862
|
await runServer(argv);
|
|
6432
6863
|
return;
|
|
6433
6864
|
}
|
|
6865
|
+
if (positional[0] === "update") {
|
|
6866
|
+
await runUpdate(!!argv.verbose);
|
|
6867
|
+
return;
|
|
6868
|
+
}
|
|
6434
6869
|
if (argv.help) {
|
|
6435
6870
|
process.stdout.write(HELP);
|
|
6436
6871
|
return;
|
|
6437
6872
|
}
|
|
6438
|
-
const isHeadless = !!(argv["json-events"] || argv.headless || argv.list || argv.help);
|
|
6873
|
+
const isHeadless = !!(argv["json-events"] || argv.headless || argv.list || argv.help || positional[0] === "update");
|
|
6439
6874
|
if (!isHeadless) {
|
|
6440
6875
|
const stdin = process.stdin;
|
|
6441
6876
|
const stdout = process.stdout;
|
|
@@ -6616,7 +7051,57 @@ function personaNotesForGeneration2(cfg) {
|
|
|
6616
7051
|
].filter(Boolean);
|
|
6617
7052
|
return parts.join("\n\n");
|
|
6618
7053
|
}
|
|
7054
|
+
async function runUpdate(verbose) {
|
|
7055
|
+
const profiles = await listProfiles();
|
|
7056
|
+
if (!profiles.length) {
|
|
7057
|
+
process.stdout.write("\u043D\u0435\u0442 \u043F\u0440\u043E\u0444\u0438\u043B\u0435\u0439 \u2014 \u043D\u0435\u0447\u0435\u0433\u043E \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0442\u044C.\n");
|
|
7058
|
+
return;
|
|
7059
|
+
}
|
|
7060
|
+
process.stdout.write(`\u043D\u0430\u0439\u0434\u0435\u043D\u043E \u043F\u0440\u043E\u0444\u0438\u043B\u0435\u0439: ${profiles.length}
|
|
7061
|
+
\u0437\u0430\u043F\u0443\u0441\u043A \u043C\u0438\u0433\u0440\u0430\u0446\u0438\u0439...
|
|
7062
|
+
`);
|
|
7063
|
+
const result = await runMigrations({ verbose });
|
|
7064
|
+
if (!result.migrationsApplied.length) {
|
|
7065
|
+
process.stdout.write("\u0432\u0441\u0435 \u0434\u0430\u043D\u043D\u044B\u0435 \u0430\u043A\u0442\u0443\u0430\u043B\u044C\u043D\u044B, \u043C\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u043D\u0435 \u043D\u0443\u0436\u043D\u044B.\n");
|
|
7066
|
+
return;
|
|
7067
|
+
}
|
|
7068
|
+
process.stdout.write(`
|
|
7069
|
+
\u0433\u043E\u0442\u043E\u0432\u043E:
|
|
7070
|
+
`);
|
|
7071
|
+
process.stdout.write(` \u043C\u0438\u0433\u0440\u0430\u0446\u0438\u0439 \u043F\u0440\u0438\u043C\u0435\u043D\u0435\u043D\u043E: ${result.migrationsApplied.length}
|
|
7072
|
+
`);
|
|
7073
|
+
for (const id of result.migrationsApplied) {
|
|
7074
|
+
process.stdout.write(` - ${id}
|
|
7075
|
+
`);
|
|
7076
|
+
}
|
|
7077
|
+
process.stdout.write(` \u043F\u0440\u043E\u0444\u0438\u043B\u0435\u0439 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u043E: ${result.profilesUpdated}
|
|
7078
|
+
`);
|
|
7079
|
+
if (result.errors.length) {
|
|
7080
|
+
process.stdout.write(` \u043E\u0448\u0438\u0431\u043E\u043A: ${result.errors.length}
|
|
7081
|
+
`);
|
|
7082
|
+
for (const e of result.errors) {
|
|
7083
|
+
process.stdout.write(` ${e.profile} @ ${e.migration}: ${e.error}
|
|
7084
|
+
`);
|
|
7085
|
+
}
|
|
7086
|
+
}
|
|
7087
|
+
}
|
|
6619
7088
|
async function runRuntime(cfg, opts = {}) {
|
|
7089
|
+
if (await checkForPendingMigrations()) {
|
|
7090
|
+
process.stderr.write("[updater] \u043E\u0431\u043D\u0430\u0440\u0443\u0436\u0435\u043D\u044B pending-\u043C\u0438\u0433\u0440\u0430\u0446\u0438\u0438, \u0437\u0430\u043F\u0443\u0441\u043A...\n");
|
|
7091
|
+
const result = await runMigrations({
|
|
7092
|
+
verbose: true,
|
|
7093
|
+
llmFactory: (c) => {
|
|
7094
|
+
try {
|
|
7095
|
+
return makeLLM(c.llm);
|
|
7096
|
+
} catch {
|
|
7097
|
+
return void 0;
|
|
7098
|
+
}
|
|
7099
|
+
}
|
|
7100
|
+
});
|
|
7101
|
+
if (result.warnings.length) {
|
|
7102
|
+
process.stderr.write(formatUpdateWarnings(result.warnings) + "\n");
|
|
7103
|
+
}
|
|
7104
|
+
}
|
|
6620
7105
|
const rt = new Runtime(cfg);
|
|
6621
7106
|
await rt.start();
|
|
6622
7107
|
if (opts.jsonEvents) {
|