@thesashadev/girl-agent 0.1.12 → 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 +12 -0
- package/dist/cli.js +511 -29
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
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
|
+
|
|
3
15
|
## 0.1.12
|
|
4
16
|
|
|
5
17
|
Дата: 2026-05-08
|
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,
|
|
@@ -3168,8 +3383,8 @@ phoneAvailable=false \u043A\u043E\u0433\u0434\u0430: \u0441\u043F\u0438\u0442, \
|
|
|
3168
3383
|
}
|
|
3169
3384
|
async function loadOrGenerateDailyLife(llm, cfg, now = /* @__PURE__ */ new Date(), conflict = null) {
|
|
3170
3385
|
const dateLocal = localDateStr(cfg.tz, now);
|
|
3171
|
-
const
|
|
3172
|
-
const existing = await readMd(cfg.slug,
|
|
3386
|
+
const path7 = `daily-life/${dateLocal}.md`;
|
|
3387
|
+
const existing = await readMd(cfg.slug, path7);
|
|
3173
3388
|
if (existing) {
|
|
3174
3389
|
try {
|
|
3175
3390
|
const m = existing.match(/<!--daily:(.+?)-->/s);
|
|
@@ -3201,7 +3416,7 @@ async function loadOrGenerateDailyLife(llm, cfg, now = /* @__PURE__ */ new Date(
|
|
|
3201
3416
|
dl = { dateLocal, vibe: "\u043E\u0431\u044B\u0447\u043D\u044B\u0439 \u0434\u0435\u043D\u044C", blocks: [], events: [], wants: [] };
|
|
3202
3417
|
}
|
|
3203
3418
|
const human = renderDailyLifeHuman(dl);
|
|
3204
|
-
await writeMd(cfg.slug,
|
|
3419
|
+
await writeMd(cfg.slug, path7, `${human}
|
|
3205
3420
|
|
|
3206
3421
|
<!--daily:${JSON.stringify(dl)}-->
|
|
3207
3422
|
`);
|
|
@@ -3431,9 +3646,9 @@ async function ensureDefaults(cfg) {
|
|
|
3431
3646
|
["time/promises.md", "# promises\n"],
|
|
3432
3647
|
["memory/uncertain.md", "# uncertain\n"]
|
|
3433
3648
|
];
|
|
3434
|
-
await Promise.all(defaults.map(async ([
|
|
3435
|
-
const current = await readMd(cfg.slug,
|
|
3436
|
-
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");
|
|
3437
3652
|
}));
|
|
3438
3653
|
}
|
|
3439
3654
|
async function loadRealismContext(cfg, incoming) {
|
|
@@ -5969,9 +6184,201 @@ function profileSummary(cfg) {
|
|
|
5969
6184
|
|
|
5970
6185
|
// src/server.ts
|
|
5971
6186
|
init_esm_shims();
|
|
5972
|
-
import
|
|
5973
|
-
import
|
|
6187
|
+
import fs5 from "fs/promises";
|
|
6188
|
+
import path6 from "path";
|
|
5974
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
|
|
5975
6382
|
var SERVER_HELP = `
|
|
5976
6383
|
girl-agent server \u2014 automation / ops mode (no TTY required)
|
|
5977
6384
|
|
|
@@ -6065,7 +6472,7 @@ async function runServer(rawArgv) {
|
|
|
6065
6472
|
}
|
|
6066
6473
|
async function persistAndMaybeStart(cfg, args) {
|
|
6067
6474
|
await writeConfig(cfg);
|
|
6068
|
-
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)}
|
|
6069
6476
|
`);
|
|
6070
6477
|
if (cfg.llm.apiKey || findPreset(cfg.llm.presetId)?.apiKeyRequired === false) {
|
|
6071
6478
|
try {
|
|
@@ -6091,6 +6498,22 @@ async function persistAndMaybeStart(cfg, args) {
|
|
|
6091
6498
|
await startRuntime(cfg, args);
|
|
6092
6499
|
}
|
|
6093
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
|
+
}
|
|
6094
6517
|
const rt = new Runtime(cfg);
|
|
6095
6518
|
await rt.start();
|
|
6096
6519
|
const wantsHeadless = !!(args.headless || args.jsonEvents);
|
|
@@ -6163,10 +6586,10 @@ function configFromEnv() {
|
|
|
6163
6586
|
};
|
|
6164
6587
|
}
|
|
6165
6588
|
async function loadConfigFile(file) {
|
|
6166
|
-
const abs =
|
|
6589
|
+
const abs = path6.isAbsolute(file) ? file : path6.join(process.cwd(), file);
|
|
6167
6590
|
let raw;
|
|
6168
6591
|
try {
|
|
6169
|
-
raw = await
|
|
6592
|
+
raw = await fs5.readFile(abs, "utf-8");
|
|
6170
6593
|
} catch (e) {
|
|
6171
6594
|
process.stderr.write(`[server] \u043D\u0435 \u043C\u043E\u0433\u0443 \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0442\u044C ${abs}: ${e?.message ?? e}
|
|
6172
6595
|
`);
|
|
@@ -6360,11 +6783,11 @@ required flags \u0434\u043B\u044F headless setup (--name --age --stage --api-pre
|
|
|
6360
6783
|
--mode=bot|userbot
|
|
6361
6784
|
--token=<bot_token> \u0434\u043B\u044F bot
|
|
6362
6785
|
--api-id=<n> --api-hash=<h> --phone=<+7\u2026> \u0434\u043B\u044F userbot
|
|
6363
|
-
--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|...
|
|
6364
6787
|
--base-url=<url> \u0434\u043B\u044F custom
|
|
6365
6788
|
--proto=openai|anthropic \u0434\u043B\u044F custom
|
|
6366
6789
|
--model=<model>
|
|
6367
|
-
--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)
|
|
6368
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)
|
|
6369
6792
|
--age=<n>
|
|
6370
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
|
|
@@ -6382,6 +6805,10 @@ required flags \u0434\u043B\u044F headless setup (--name --age --stage --api-pre
|
|
|
6382
6805
|
--list \u043F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u043F\u0440\u043E\u0444\u0438\u043B\u0438
|
|
6383
6806
|
--help
|
|
6384
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
|
+
|
|
6385
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
|
|
6386
6813
|
`;
|
|
6387
6814
|
async function main() {
|
|
@@ -6424,7 +6851,8 @@ async function main() {
|
|
|
6424
6851
|
"print-config",
|
|
6425
6852
|
"print-systemd",
|
|
6426
6853
|
"print-docker",
|
|
6427
|
-
"no-start"
|
|
6854
|
+
"no-start",
|
|
6855
|
+
"verbose"
|
|
6428
6856
|
],
|
|
6429
6857
|
alias: { h: "help" }
|
|
6430
6858
|
});
|
|
@@ -6434,11 +6862,15 @@ async function main() {
|
|
|
6434
6862
|
await runServer(argv);
|
|
6435
6863
|
return;
|
|
6436
6864
|
}
|
|
6865
|
+
if (positional[0] === "update") {
|
|
6866
|
+
await runUpdate(!!argv.verbose);
|
|
6867
|
+
return;
|
|
6868
|
+
}
|
|
6437
6869
|
if (argv.help) {
|
|
6438
6870
|
process.stdout.write(HELP);
|
|
6439
6871
|
return;
|
|
6440
6872
|
}
|
|
6441
|
-
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");
|
|
6442
6874
|
if (!isHeadless) {
|
|
6443
6875
|
const stdin = process.stdin;
|
|
6444
6876
|
const stdout = process.stdout;
|
|
@@ -6619,7 +7051,57 @@ function personaNotesForGeneration2(cfg) {
|
|
|
6619
7051
|
].filter(Boolean);
|
|
6620
7052
|
return parts.join("\n\n");
|
|
6621
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
|
+
}
|
|
6622
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
|
+
}
|
|
6623
7105
|
const rt = new Runtime(cfg);
|
|
6624
7106
|
await rt.start();
|
|
6625
7107
|
if (opts.jsonEvents) {
|