@thesashadev/girl-agent 0.1.12 → 0.1.14
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 +512 -29
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.14
|
|
4
|
+
|
|
5
|
+
Дата: 2026-05-08
|
|
6
|
+
|
|
7
|
+
- Merge pull request #59 from TheSashaDev/devin/1778231542-oauth-fixed-port
|
|
8
|
+
- fix: update OAuth client credentials and add client_secret to token requests
|
|
9
|
+
- fix: use fixed port 3000 for OAuth callback
|
|
10
|
+
|
|
11
|
+
## 0.1.13
|
|
12
|
+
|
|
13
|
+
Дата: 2026-05-08
|
|
14
|
+
|
|
15
|
+
- Merge pull request #56 from TheSashaDev/devin/1778220196-data-migration-system
|
|
16
|
+
- feat: GirlAI OAuth login and token refresh support
|
|
17
|
+
- feat: add GirlAI API preset and recommended status for LLM providers
|
|
18
|
+
- feat: extend migration system with LLM support and auto-run on startup
|
|
19
|
+
- fix: robust version lookup for bundled output, fix AGENTS.md auto-run claim
|
|
20
|
+
- fix: remove unused import, dynamic version from package.json, use static listProfiles
|
|
21
|
+
- feat: AGENTS.md + update command with migration system
|
|
22
|
+
|
|
3
23
|
## 0.1.12
|
|
4
24
|
|
|
5
25
|
Дата: 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,151 @@ 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 = "oac_dcce490e74a452a9ed20";
|
|
1074
|
+
var CLIENT_SECRET = "abnfSGmeisM7SFdMn_c1MwFYAHaqzgs7";
|
|
1075
|
+
var CALLBACK_PORT = 3e3;
|
|
1076
|
+
var REDIRECT_URI = `http://localhost:${CALLBACK_PORT}/callback`;
|
|
1077
|
+
async function runOAuthFlow(log) {
|
|
1078
|
+
const state = crypto.randomBytes(16).toString("hex");
|
|
1079
|
+
const { waitForCode, close } = await startCallbackServer(state);
|
|
1080
|
+
const authorizeParams = new URLSearchParams({
|
|
1081
|
+
client_id: CLIENT_ID,
|
|
1082
|
+
redirect_uri: REDIRECT_URI,
|
|
1083
|
+
response_type: "code",
|
|
1084
|
+
state
|
|
1085
|
+
});
|
|
1086
|
+
const url = `${AUTHORIZE_URL}?${authorizeParams}`;
|
|
1087
|
+
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}`);
|
|
1088
|
+
openBrowser(url);
|
|
1089
|
+
let code;
|
|
1090
|
+
try {
|
|
1091
|
+
code = await waitForCode;
|
|
1092
|
+
} finally {
|
|
1093
|
+
close();
|
|
1094
|
+
}
|
|
1095
|
+
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...");
|
|
1096
|
+
return exchangeCode(code, REDIRECT_URI);
|
|
1097
|
+
}
|
|
1098
|
+
async function exchangeCode(code, redirectUri = REDIRECT_URI) {
|
|
1099
|
+
const body = new URLSearchParams({
|
|
1100
|
+
grant_type: "authorization_code",
|
|
1101
|
+
code,
|
|
1102
|
+
client_id: CLIENT_ID,
|
|
1103
|
+
client_secret: CLIENT_SECRET,
|
|
1104
|
+
redirect_uri: redirectUri
|
|
1105
|
+
});
|
|
1106
|
+
const res = await fetch(TOKEN_URL, {
|
|
1107
|
+
method: "POST",
|
|
1108
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
1109
|
+
body: body.toString()
|
|
1110
|
+
});
|
|
1111
|
+
if (!res.ok) {
|
|
1112
|
+
const text = await res.text();
|
|
1113
|
+
throw new Error(`OAuth token exchange failed (${res.status}): ${text}`);
|
|
1114
|
+
}
|
|
1115
|
+
const data = await res.json();
|
|
1116
|
+
return {
|
|
1117
|
+
accessToken: data.access_token,
|
|
1118
|
+
refreshToken: data.refresh_token,
|
|
1119
|
+
expiresAt: Date.now() + data.expires_in * 1e3
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
async function refreshAccessToken(refreshToken) {
|
|
1123
|
+
const body = new URLSearchParams({
|
|
1124
|
+
grant_type: "refresh_token",
|
|
1125
|
+
refresh_token: refreshToken,
|
|
1126
|
+
client_id: CLIENT_ID,
|
|
1127
|
+
client_secret: CLIENT_SECRET
|
|
1128
|
+
});
|
|
1129
|
+
const res = await fetch(TOKEN_URL, {
|
|
1130
|
+
method: "POST",
|
|
1131
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
1132
|
+
body: body.toString()
|
|
1133
|
+
});
|
|
1134
|
+
if (!res.ok) {
|
|
1135
|
+
const text = await res.text();
|
|
1136
|
+
throw new Error(`OAuth token refresh failed (${res.status}): ${text}`);
|
|
1137
|
+
}
|
|
1138
|
+
const data = await res.json();
|
|
1139
|
+
return {
|
|
1140
|
+
accessToken: data.access_token,
|
|
1141
|
+
refreshToken: data.refresh_token,
|
|
1142
|
+
expiresAt: Date.now() + data.expires_in * 1e3
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
function isTokenExpired(expiresAt) {
|
|
1146
|
+
return Date.now() >= expiresAt - 6e4;
|
|
1147
|
+
}
|
|
1148
|
+
function startCallbackServer(expectedState) {
|
|
1149
|
+
return new Promise((resolveSetup) => {
|
|
1150
|
+
let resolveCode;
|
|
1151
|
+
let rejectCode;
|
|
1152
|
+
const waitForCode = new Promise((res, rej) => {
|
|
1153
|
+
resolveCode = res;
|
|
1154
|
+
rejectCode = rej;
|
|
1155
|
+
});
|
|
1156
|
+
const timeout = setTimeout(() => {
|
|
1157
|
+
rejectCode(new Error("OAuth callback timeout (5 minutes)"));
|
|
1158
|
+
server.close();
|
|
1159
|
+
}, 5 * 60 * 1e3);
|
|
1160
|
+
const server = http.createServer((req, res) => {
|
|
1161
|
+
const url = new URL(req.url ?? "/", `http://localhost`);
|
|
1162
|
+
if (url.pathname !== "/callback") {
|
|
1163
|
+
res.writeHead(404);
|
|
1164
|
+
res.end("not found");
|
|
1165
|
+
return;
|
|
1166
|
+
}
|
|
1167
|
+
const code = url.searchParams.get("code");
|
|
1168
|
+
const state = url.searchParams.get("state");
|
|
1169
|
+
const error = url.searchParams.get("error");
|
|
1170
|
+
if (error) {
|
|
1171
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
1172
|
+
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>");
|
|
1173
|
+
clearTimeout(timeout);
|
|
1174
|
+
rejectCode(new Error(`OAuth denied: ${error}`));
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1177
|
+
if (!code || state !== expectedState) {
|
|
1178
|
+
res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
|
|
1179
|
+
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>");
|
|
1180
|
+
return;
|
|
1181
|
+
}
|
|
1182
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
1183
|
+
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>");
|
|
1184
|
+
clearTimeout(timeout);
|
|
1185
|
+
resolveCode(code);
|
|
1186
|
+
});
|
|
1187
|
+
server.listen(CALLBACK_PORT, "127.0.0.1", () => {
|
|
1188
|
+
resolveSetup({
|
|
1189
|
+
waitForCode,
|
|
1190
|
+
close: () => server.close()
|
|
1191
|
+
});
|
|
1192
|
+
});
|
|
1193
|
+
});
|
|
1194
|
+
}
|
|
1195
|
+
function openBrowser(url) {
|
|
1196
|
+
const platform = process.platform;
|
|
1197
|
+
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}"`;
|
|
1198
|
+
exec(cmd, (err) => {
|
|
1199
|
+
if (err) {
|
|
1200
|
+
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:
|
|
1201
|
+
${url}
|
|
1202
|
+
`);
|
|
1203
|
+
}
|
|
1204
|
+
});
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
// src/llm/index.ts
|
|
1051
1208
|
var LLM_TIMEOUT_MS = 12e4;
|
|
1052
1209
|
var LLM_MAX_RETRIES = 1;
|
|
1053
1210
|
var OpenAILike = class {
|
|
@@ -1070,7 +1227,24 @@ var OpenAILike = class {
|
|
|
1070
1227
|
cfg;
|
|
1071
1228
|
client;
|
|
1072
1229
|
fetchClient;
|
|
1230
|
+
async ensureFreshToken() {
|
|
1231
|
+
if (!this.cfg.oauthRefreshToken || !this.cfg.oauthExpiresAt) return;
|
|
1232
|
+
if (!isTokenExpired(this.cfg.oauthExpiresAt)) return;
|
|
1233
|
+
try {
|
|
1234
|
+
const tokens = await refreshAccessToken(this.cfg.oauthRefreshToken);
|
|
1235
|
+
this.cfg.apiKey = tokens.accessToken;
|
|
1236
|
+
this.cfg.oauthRefreshToken = tokens.refreshToken;
|
|
1237
|
+
this.cfg.oauthExpiresAt = tokens.expiresAt;
|
|
1238
|
+
const key = tokens.accessToken;
|
|
1239
|
+
this.client = new OpenAI({ apiKey: key, baseURL: normalizeBaseURL(this.cfg.baseURL), timeout: LLM_TIMEOUT_MS, maxRetries: LLM_MAX_RETRIES });
|
|
1240
|
+
this.fetchClient = new OpenAI({ apiKey: key, baseURL: normalizeBaseURL(this.cfg.baseURL), timeout: LLM_TIMEOUT_MS, maxRetries: LLM_MAX_RETRIES, fetch: compatibleFetch });
|
|
1241
|
+
} catch (err) {
|
|
1242
|
+
process.stderr.write(`[oauth] token refresh failed: ${err instanceof Error ? err.message : err}
|
|
1243
|
+
`);
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1073
1246
|
async chat(messages, opts = {}) {
|
|
1247
|
+
await this.ensureFreshToken();
|
|
1074
1248
|
const params = {
|
|
1075
1249
|
model: this.cfg.model,
|
|
1076
1250
|
messages: openAIMessages(messages),
|
|
@@ -1559,14 +1733,14 @@ var DEFAULT_PROXY = "https://tgproxy.girl-agent.com";
|
|
|
1559
1733
|
function proxyUrl() {
|
|
1560
1734
|
return process.env.GIRL_AGENT_AUTH_PROXY ?? DEFAULT_PROXY;
|
|
1561
1735
|
}
|
|
1562
|
-
async function post(
|
|
1563
|
-
const res = await fetch(`${proxyUrl()}${
|
|
1736
|
+
async function post(path7, body) {
|
|
1737
|
+
const res = await fetch(`${proxyUrl()}${path7}`, {
|
|
1564
1738
|
method: "POST",
|
|
1565
1739
|
headers: { "Content-Type": "application/json" },
|
|
1566
1740
|
body: JSON.stringify(body)
|
|
1567
1741
|
});
|
|
1568
1742
|
const data = await res.json();
|
|
1569
|
-
if (!res.ok) throw new Error(data.error ?? `proxy ${
|
|
1743
|
+
if (!res.ok) throw new Error(data.error ?? `proxy ${path7} failed (${res.status})`);
|
|
1570
1744
|
return data;
|
|
1571
1745
|
}
|
|
1572
1746
|
function remoteSendCode(phone) {
|
|
@@ -1813,6 +1987,9 @@ function Wizard({ initial, onDone }) {
|
|
|
1813
1987
|
const [llmBaseURL, setLlmBaseURL] = useState(initial?.llm?.baseURL ?? "");
|
|
1814
1988
|
const [llmModel, setLlmModel] = useState(initial?.llm?.model ?? "");
|
|
1815
1989
|
const [llmKey, setLlmKey] = useState(initial?.llm?.apiKey ?? "");
|
|
1990
|
+
const [oauthRefreshToken, setOauthRefreshToken] = useState(initial?.llm?.oauthRefreshToken ?? "");
|
|
1991
|
+
const [oauthExpiresAt, setOauthExpiresAt] = useState(initial?.llm?.oauthExpiresAt ?? 0);
|
|
1992
|
+
const [oauthStatus, setOauthStatus] = useState("");
|
|
1816
1993
|
const [nationality, setNationality] = useState(initial?.nationality ?? "RU");
|
|
1817
1994
|
const [name, setName] = useState(initial?.name ?? "");
|
|
1818
1995
|
const [ageStr, setAgeStr] = useState(initial?.age ? String(initial.age) : "");
|
|
@@ -2035,7 +2212,7 @@ function Wizard({ initial, onDone }) {
|
|
|
2035
2212
|
SelectInput,
|
|
2036
2213
|
{
|
|
2037
2214
|
limit: 10,
|
|
2038
|
-
items: LLM_PRESETS.map((p) => ({ label: `${p.name}${p.hint ? ` \xB7 ${p.hint}` : ""}`, value: p.id })),
|
|
2215
|
+
items: LLM_PRESETS.map((p) => ({ label: `${p.name}${p.recommended ? " \u2605" : ""}${p.hint ? ` \xB7 ${p.hint}` : ""}`, value: p.id })),
|
|
2039
2216
|
onSelect: (it) => {
|
|
2040
2217
|
const preset = findPreset(it.value);
|
|
2041
2218
|
setLlmPresetId(preset.id);
|
|
@@ -2044,11 +2221,43 @@ function Wizard({ initial, onDone }) {
|
|
|
2044
2221
|
setLlmModel(preset.defaultModel);
|
|
2045
2222
|
setLlmKey(preset.defaultApiKey ?? "");
|
|
2046
2223
|
if (preset.custom) setStep("api-base");
|
|
2224
|
+
else if (preset.oauth) setStep("api-auth-method");
|
|
2047
2225
|
else setStep("api-model");
|
|
2048
2226
|
}
|
|
2049
2227
|
}
|
|
2050
2228
|
)));
|
|
2051
2229
|
}
|
|
2230
|
+
if (step === "api-auth-method") {
|
|
2231
|
+
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(
|
|
2232
|
+
SelectInput,
|
|
2233
|
+
{
|
|
2234
|
+
items: [
|
|
2235
|
+
{ label: "\u{1F511} \u0412\u043E\u0439\u0442\u0438 \u0447\u0435\u0440\u0435\u0437 GirlAI \u0430\u043A\u043A\u0430\u0443\u043D\u0442 (OAuth)", value: "oauth" },
|
|
2236
|
+
{ label: "\u{1F4CB} \u0412\u0432\u0435\u0441\u0442\u0438 API \u043A\u043B\u044E\u0447 \u0432\u0440\u0443\u0447\u043D\u0443\u044E", value: "apikey" }
|
|
2237
|
+
],
|
|
2238
|
+
onSelect: (it) => {
|
|
2239
|
+
if (it.value === "oauth") {
|
|
2240
|
+
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...");
|
|
2241
|
+
setStep("api-oauth");
|
|
2242
|
+
runOAuthFlow((msg) => setOauthStatus(msg)).then((tokens) => {
|
|
2243
|
+
setLlmKey(tokens.accessToken);
|
|
2244
|
+
setOauthRefreshToken(tokens.refreshToken);
|
|
2245
|
+
setOauthExpiresAt(tokens.expiresAt);
|
|
2246
|
+
setStep("api-model");
|
|
2247
|
+
}).catch((err) => {
|
|
2248
|
+
setError(err.message);
|
|
2249
|
+
setStep("api-auth-method");
|
|
2250
|
+
});
|
|
2251
|
+
} else {
|
|
2252
|
+
setStep("api-model");
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
)));
|
|
2257
|
+
}
|
|
2258
|
+
if (step === "api-oauth") {
|
|
2259
|
+
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"));
|
|
2260
|
+
}
|
|
2052
2261
|
if (step === "api-base") {
|
|
2053
2262
|
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
2263
|
}
|
|
@@ -2530,7 +2739,14 @@ function Wizard({ initial, onDone }) {
|
|
|
2530
2739
|
tz: tz || defaultTzForNationality(nationality),
|
|
2531
2740
|
mode,
|
|
2532
2741
|
stage: overrides.stage ?? stage,
|
|
2533
|
-
llm: {
|
|
2742
|
+
llm: {
|
|
2743
|
+
presetId: llmPresetId,
|
|
2744
|
+
proto: llmProto,
|
|
2745
|
+
baseURL: llmBaseURL,
|
|
2746
|
+
apiKey: llmKey,
|
|
2747
|
+
model: llmModel,
|
|
2748
|
+
...oauthRefreshToken ? { oauthRefreshToken, oauthExpiresAt } : {}
|
|
2749
|
+
},
|
|
2534
2750
|
telegram: mode === "bot" ? { botToken } : { apiId: Number(apiId), apiHash, phone, sessionString },
|
|
2535
2751
|
mcp: overrides.mcp ?? pickedMcp.map((id) => ({ id, secrets: mcpSecrets[id] ?? {} })),
|
|
2536
2752
|
privacy,
|
|
@@ -3168,8 +3384,8 @@ phoneAvailable=false \u043A\u043E\u0433\u0434\u0430: \u0441\u043F\u0438\u0442, \
|
|
|
3168
3384
|
}
|
|
3169
3385
|
async function loadOrGenerateDailyLife(llm, cfg, now = /* @__PURE__ */ new Date(), conflict = null) {
|
|
3170
3386
|
const dateLocal = localDateStr(cfg.tz, now);
|
|
3171
|
-
const
|
|
3172
|
-
const existing = await readMd(cfg.slug,
|
|
3387
|
+
const path7 = `daily-life/${dateLocal}.md`;
|
|
3388
|
+
const existing = await readMd(cfg.slug, path7);
|
|
3173
3389
|
if (existing) {
|
|
3174
3390
|
try {
|
|
3175
3391
|
const m = existing.match(/<!--daily:(.+?)-->/s);
|
|
@@ -3201,7 +3417,7 @@ async function loadOrGenerateDailyLife(llm, cfg, now = /* @__PURE__ */ new Date(
|
|
|
3201
3417
|
dl = { dateLocal, vibe: "\u043E\u0431\u044B\u0447\u043D\u044B\u0439 \u0434\u0435\u043D\u044C", blocks: [], events: [], wants: [] };
|
|
3202
3418
|
}
|
|
3203
3419
|
const human = renderDailyLifeHuman(dl);
|
|
3204
|
-
await writeMd(cfg.slug,
|
|
3420
|
+
await writeMd(cfg.slug, path7, `${human}
|
|
3205
3421
|
|
|
3206
3422
|
<!--daily:${JSON.stringify(dl)}-->
|
|
3207
3423
|
`);
|
|
@@ -3431,9 +3647,9 @@ async function ensureDefaults(cfg) {
|
|
|
3431
3647
|
["time/promises.md", "# promises\n"],
|
|
3432
3648
|
["memory/uncertain.md", "# uncertain\n"]
|
|
3433
3649
|
];
|
|
3434
|
-
await Promise.all(defaults.map(async ([
|
|
3435
|
-
const current = await readMd(cfg.slug,
|
|
3436
|
-
if (!current.trim()) await writeMd(cfg.slug,
|
|
3650
|
+
await Promise.all(defaults.map(async ([path7, content]) => {
|
|
3651
|
+
const current = await readMd(cfg.slug, path7);
|
|
3652
|
+
if (!current.trim()) await writeMd(cfg.slug, path7, content + "\n");
|
|
3437
3653
|
}));
|
|
3438
3654
|
}
|
|
3439
3655
|
async function loadRealismContext(cfg, incoming) {
|
|
@@ -5969,9 +6185,201 @@ function profileSummary(cfg) {
|
|
|
5969
6185
|
|
|
5970
6186
|
// src/server.ts
|
|
5971
6187
|
init_esm_shims();
|
|
5972
|
-
import
|
|
5973
|
-
import
|
|
6188
|
+
import fs5 from "fs/promises";
|
|
6189
|
+
import path6 from "path";
|
|
5974
6190
|
import os from "os";
|
|
6191
|
+
|
|
6192
|
+
// src/migrations/index.ts
|
|
6193
|
+
init_esm_shims();
|
|
6194
|
+
import { promises as fs4 } from "fs";
|
|
6195
|
+
import path5 from "path";
|
|
6196
|
+
import { readFileSync } from "fs";
|
|
6197
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
6198
|
+
|
|
6199
|
+
// src/migrations/0112-add-use-wss-default.ts
|
|
6200
|
+
init_esm_shims();
|
|
6201
|
+
var migration0112 = {
|
|
6202
|
+
id: "0112-add-use-wss-default",
|
|
6203
|
+
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",
|
|
6204
|
+
async migrate(ctx) {
|
|
6205
|
+
if (ctx.config.telegram.useWSS === void 0 || ctx.config.telegram.useWSS === false) {
|
|
6206
|
+
ctx.config.telegram.useWSS = true;
|
|
6207
|
+
}
|
|
6208
|
+
return ctx.config;
|
|
6209
|
+
}
|
|
6210
|
+
};
|
|
6211
|
+
|
|
6212
|
+
// src/migrations/0113-ensure-communication-md.ts
|
|
6213
|
+
init_esm_shims();
|
|
6214
|
+
var migration0113 = {
|
|
6215
|
+
id: "0113-ensure-communication-md",
|
|
6216
|
+
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",
|
|
6217
|
+
needsLLM: true,
|
|
6218
|
+
async migrate(ctx) {
|
|
6219
|
+
const { config, llm, log } = ctx;
|
|
6220
|
+
const existing = await readMd(config.slug, "communication.md");
|
|
6221
|
+
if (existing.trim()) return config;
|
|
6222
|
+
if (!llm) {
|
|
6223
|
+
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");
|
|
6224
|
+
return config;
|
|
6225
|
+
}
|
|
6226
|
+
const persona = await readMd(config.slug, "persona.md");
|
|
6227
|
+
if (!persona.trim()) {
|
|
6228
|
+
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");
|
|
6229
|
+
return config;
|
|
6230
|
+
}
|
|
6231
|
+
log("\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u0443\u0435\u043C communication.md \u0447\u0435\u0440\u0435\u0437 AI...");
|
|
6232
|
+
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:
|
|
6233
|
+
|
|
6234
|
+
# \u041F\u0440\u0435\u0434\u043F\u043E\u0447\u0442\u0435\u043D\u0438\u044F \u0432 \u043E\u0431\u0449\u0435\u043D\u0438\u0438
|
|
6235
|
+
## \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)
|
|
6236
|
+
## \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)
|
|
6237
|
+
## \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)
|
|
6238
|
+
## \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
|
|
6239
|
+
## \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
|
|
6240
|
+
|
|
6241
|
+
\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.
|
|
6242
|
+
|
|
6243
|
+
persona.md:
|
|
6244
|
+
${persona}`;
|
|
6245
|
+
const response = await llm.chat([
|
|
6246
|
+
{ 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." },
|
|
6247
|
+
{ role: "user", content: prompt }
|
|
6248
|
+
]);
|
|
6249
|
+
if (response?.trim()) {
|
|
6250
|
+
await writeMd(config.slug, "communication.md", response);
|
|
6251
|
+
log("communication.md \u0441\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u043D");
|
|
6252
|
+
}
|
|
6253
|
+
return config;
|
|
6254
|
+
}
|
|
6255
|
+
};
|
|
6256
|
+
|
|
6257
|
+
// src/migrations/index.ts
|
|
6258
|
+
var MIGRATIONS_FILE = () => path5.join(DATA_ROOT, ".migrations.json");
|
|
6259
|
+
async function readMigrationState() {
|
|
6260
|
+
try {
|
|
6261
|
+
const raw = await fs4.readFile(MIGRATIONS_FILE(), "utf8");
|
|
6262
|
+
return JSON.parse(raw);
|
|
6263
|
+
} catch {
|
|
6264
|
+
return { appliedMigrations: [], lastRunVersion: "0.0.0", lastRunAt: "" };
|
|
6265
|
+
}
|
|
6266
|
+
}
|
|
6267
|
+
async function writeMigrationState(state) {
|
|
6268
|
+
await fs4.mkdir(DATA_ROOT, { recursive: true });
|
|
6269
|
+
await fs4.writeFile(MIGRATIONS_FILE(), JSON.stringify(state, null, 2), "utf8");
|
|
6270
|
+
}
|
|
6271
|
+
var ALL_MIGRATIONS = [
|
|
6272
|
+
migration0112,
|
|
6273
|
+
migration0113
|
|
6274
|
+
];
|
|
6275
|
+
async function pendingMigrations() {
|
|
6276
|
+
const state = await readMigrationState();
|
|
6277
|
+
return ALL_MIGRATIONS.filter((m) => !state.appliedMigrations.includes(m.id));
|
|
6278
|
+
}
|
|
6279
|
+
async function runMigrations(opts) {
|
|
6280
|
+
const pending = await pendingMigrations();
|
|
6281
|
+
const log = opts?.verbose ? (msg) => process.stderr.write(msg + "\n") : () => {
|
|
6282
|
+
};
|
|
6283
|
+
if (pending.length === 0) {
|
|
6284
|
+
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.");
|
|
6285
|
+
return { profilesUpdated: 0, migrationsApplied: [], warnings: [], errors: [] };
|
|
6286
|
+
}
|
|
6287
|
+
const profiles = await listProfiles();
|
|
6288
|
+
const state = await readMigrationState();
|
|
6289
|
+
const result = { profilesUpdated: 0, migrationsApplied: [], warnings: [], errors: [] };
|
|
6290
|
+
for (const migration of pending) {
|
|
6291
|
+
log(`
|
|
6292
|
+
[migration] ${migration.id}: ${migration.description}`);
|
|
6293
|
+
let profilesAffected = 0;
|
|
6294
|
+
for (const slug of profiles) {
|
|
6295
|
+
const cfg = await readConfig(slug);
|
|
6296
|
+
if (!cfg) {
|
|
6297
|
+
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`);
|
|
6298
|
+
continue;
|
|
6299
|
+
}
|
|
6300
|
+
if (migration.needsInput?.length) {
|
|
6301
|
+
const missing = migration.needsInput.filter((field) => {
|
|
6302
|
+
const val = cfg[field.key];
|
|
6303
|
+
return val === void 0 || val === null || val === "";
|
|
6304
|
+
});
|
|
6305
|
+
if (missing.length > 0) {
|
|
6306
|
+
result.warnings.push({
|
|
6307
|
+
migrationId: migration.id,
|
|
6308
|
+
description: migration.description,
|
|
6309
|
+
missingInputs: missing
|
|
6310
|
+
});
|
|
6311
|
+
log(` \u26A0 ${slug}: \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044F \u0432\u0432\u043E\u0434: ${missing.map((f) => f.label).join(", ")}`);
|
|
6312
|
+
}
|
|
6313
|
+
}
|
|
6314
|
+
let llm;
|
|
6315
|
+
if (migration.needsLLM && opts?.llmFactory) {
|
|
6316
|
+
try {
|
|
6317
|
+
llm = opts.llmFactory(cfg);
|
|
6318
|
+
} catch (e) {
|
|
6319
|
+
log(` ${slug}: \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043E\u0437\u0434\u0430\u0442\u044C LLM: ${e.message}`);
|
|
6320
|
+
}
|
|
6321
|
+
}
|
|
6322
|
+
try {
|
|
6323
|
+
const updated = await migration.migrate({
|
|
6324
|
+
profilePath: profileDir(slug),
|
|
6325
|
+
config: cfg,
|
|
6326
|
+
llm,
|
|
6327
|
+
log: (msg) => log(` ${slug}: ${msg}`)
|
|
6328
|
+
});
|
|
6329
|
+
await writeConfig(updated);
|
|
6330
|
+
profilesAffected++;
|
|
6331
|
+
log(` ${slug}: \u043E\u043A`);
|
|
6332
|
+
} catch (e) {
|
|
6333
|
+
const errMsg = e instanceof Error ? e.message : String(e);
|
|
6334
|
+
log(` ${slug}: \u043E\u0448\u0438\u0431\u043A\u0430 \u2014 ${errMsg}`);
|
|
6335
|
+
result.errors.push({ profile: slug, migration: migration.id, error: errMsg });
|
|
6336
|
+
}
|
|
6337
|
+
}
|
|
6338
|
+
state.appliedMigrations.push(migration.id);
|
|
6339
|
+
result.migrationsApplied.push(migration.id);
|
|
6340
|
+
result.profilesUpdated = Math.max(result.profilesUpdated, profilesAffected);
|
|
6341
|
+
log(` \u043F\u0440\u0438\u043C\u0435\u043D\u0435\u043D\u043E \u043A ${profilesAffected} \u043F\u0440\u043E\u0444\u0438\u043B\u044F\u043C`);
|
|
6342
|
+
}
|
|
6343
|
+
state.lastRunVersion = currentVersion();
|
|
6344
|
+
state.lastRunAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6345
|
+
await writeMigrationState(state);
|
|
6346
|
+
return result;
|
|
6347
|
+
}
|
|
6348
|
+
async function checkForPendingMigrations() {
|
|
6349
|
+
const pending = await pendingMigrations();
|
|
6350
|
+
return pending.length > 0;
|
|
6351
|
+
}
|
|
6352
|
+
function formatUpdateWarnings(warnings) {
|
|
6353
|
+
if (!warnings.length) return "";
|
|
6354
|
+
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:"];
|
|
6355
|
+
for (const w of warnings) {
|
|
6356
|
+
for (const field of w.missingInputs) {
|
|
6357
|
+
const secret = field.secret ? " (\u0441\u0435\u043A\u0440\u0435\u0442)" : "";
|
|
6358
|
+
lines.push(` \u2022 ${field.label}${secret} \u2014 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044F \u0434\u043B\u044F: ${w.description}`);
|
|
6359
|
+
}
|
|
6360
|
+
}
|
|
6361
|
+
return lines.join("\n");
|
|
6362
|
+
}
|
|
6363
|
+
function currentVersion() {
|
|
6364
|
+
try {
|
|
6365
|
+
const here = fileURLToPath2(import.meta.url);
|
|
6366
|
+
let dir = path5.dirname(here);
|
|
6367
|
+
for (let i = 0; i < 5; i++) {
|
|
6368
|
+
const candidate = path5.join(dir, "package.json");
|
|
6369
|
+
try {
|
|
6370
|
+
const pkg = JSON.parse(readFileSync(candidate, "utf8"));
|
|
6371
|
+
if (pkg.name === "@thesashadev/girl-agent" && pkg.version) return pkg.version;
|
|
6372
|
+
} catch {
|
|
6373
|
+
}
|
|
6374
|
+
dir = path5.dirname(dir);
|
|
6375
|
+
}
|
|
6376
|
+
return "unknown";
|
|
6377
|
+
} catch {
|
|
6378
|
+
return "unknown";
|
|
6379
|
+
}
|
|
6380
|
+
}
|
|
6381
|
+
|
|
6382
|
+
// src/server.ts
|
|
5975
6383
|
var SERVER_HELP = `
|
|
5976
6384
|
girl-agent server \u2014 automation / ops mode (no TTY required)
|
|
5977
6385
|
|
|
@@ -6065,7 +6473,7 @@ async function runServer(rawArgv) {
|
|
|
6065
6473
|
}
|
|
6066
6474
|
async function persistAndMaybeStart(cfg, args) {
|
|
6067
6475
|
await writeConfig(cfg);
|
|
6068
|
-
process.stderr.write(`[server] \u043F\u0440\u043E\u0444\u0438\u043B\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0451\u043D: ${
|
|
6476
|
+
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
6477
|
`);
|
|
6070
6478
|
if (cfg.llm.apiKey || findPreset(cfg.llm.presetId)?.apiKeyRequired === false) {
|
|
6071
6479
|
try {
|
|
@@ -6091,6 +6499,22 @@ async function persistAndMaybeStart(cfg, args) {
|
|
|
6091
6499
|
await startRuntime(cfg, args);
|
|
6092
6500
|
}
|
|
6093
6501
|
async function startRuntime(cfg, args) {
|
|
6502
|
+
if (await checkForPendingMigrations()) {
|
|
6503
|
+
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");
|
|
6504
|
+
const result = await runMigrations({
|
|
6505
|
+
verbose: true,
|
|
6506
|
+
llmFactory: (c) => {
|
|
6507
|
+
try {
|
|
6508
|
+
return makeLLM(c.llm);
|
|
6509
|
+
} catch {
|
|
6510
|
+
return void 0;
|
|
6511
|
+
}
|
|
6512
|
+
}
|
|
6513
|
+
});
|
|
6514
|
+
if (result.warnings.length) {
|
|
6515
|
+
process.stderr.write(formatUpdateWarnings(result.warnings) + "\n");
|
|
6516
|
+
}
|
|
6517
|
+
}
|
|
6094
6518
|
const rt = new Runtime(cfg);
|
|
6095
6519
|
await rt.start();
|
|
6096
6520
|
const wantsHeadless = !!(args.headless || args.jsonEvents);
|
|
@@ -6163,10 +6587,10 @@ function configFromEnv() {
|
|
|
6163
6587
|
};
|
|
6164
6588
|
}
|
|
6165
6589
|
async function loadConfigFile(file) {
|
|
6166
|
-
const abs =
|
|
6590
|
+
const abs = path6.isAbsolute(file) ? file : path6.join(process.cwd(), file);
|
|
6167
6591
|
let raw;
|
|
6168
6592
|
try {
|
|
6169
|
-
raw = await
|
|
6593
|
+
raw = await fs5.readFile(abs, "utf-8");
|
|
6170
6594
|
} catch (e) {
|
|
6171
6595
|
process.stderr.write(`[server] \u043D\u0435 \u043C\u043E\u0433\u0443 \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0442\u044C ${abs}: ${e?.message ?? e}
|
|
6172
6596
|
`);
|
|
@@ -6360,11 +6784,11 @@ required flags \u0434\u043B\u044F headless setup (--name --age --stage --api-pre
|
|
|
6360
6784
|
--mode=bot|userbot
|
|
6361
6785
|
--token=<bot_token> \u0434\u043B\u044F bot
|
|
6362
6786
|
--api-id=<n> --api-hash=<h> --phone=<+7\u2026> \u0434\u043B\u044F userbot
|
|
6363
|
-
--api-preset=<id> openai|anthropic|openrouter|groq|deepseek|...
|
|
6787
|
+
--api-preset=<id> girlai|claudehub (\u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0443\u0435\u043C\u044B\u0435) | openai|anthropic|openrouter|groq|deepseek|...
|
|
6364
6788
|
--base-url=<url> \u0434\u043B\u044F custom
|
|
6365
6789
|
--proto=openai|anthropic \u0434\u043B\u044F custom
|
|
6366
6790
|
--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
|
|
6791
|
+
--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
6792
|
--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
6793
|
--age=<n>
|
|
6370
6794
|
--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 +6806,10 @@ required flags \u0434\u043B\u044F headless setup (--name --age --stage --api-pre
|
|
|
6382
6806
|
--list \u043F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u043F\u0440\u043E\u0444\u0438\u043B\u0438
|
|
6383
6807
|
--help
|
|
6384
6808
|
|
|
6809
|
+
update:
|
|
6810
|
+
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
|
|
6811
|
+
npx girl-agent update --verbose # \u0441 \u043F\u043E\u0434\u0440\u043E\u0431\u043D\u044B\u043C \u0432\u044B\u0432\u043E\u0434\u043E\u043C
|
|
6812
|
+
|
|
6385
6813
|
\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
6814
|
`;
|
|
6387
6815
|
async function main() {
|
|
@@ -6424,7 +6852,8 @@ async function main() {
|
|
|
6424
6852
|
"print-config",
|
|
6425
6853
|
"print-systemd",
|
|
6426
6854
|
"print-docker",
|
|
6427
|
-
"no-start"
|
|
6855
|
+
"no-start",
|
|
6856
|
+
"verbose"
|
|
6428
6857
|
],
|
|
6429
6858
|
alias: { h: "help" }
|
|
6430
6859
|
});
|
|
@@ -6434,11 +6863,15 @@ async function main() {
|
|
|
6434
6863
|
await runServer(argv);
|
|
6435
6864
|
return;
|
|
6436
6865
|
}
|
|
6866
|
+
if (positional[0] === "update") {
|
|
6867
|
+
await runUpdate(!!argv.verbose);
|
|
6868
|
+
return;
|
|
6869
|
+
}
|
|
6437
6870
|
if (argv.help) {
|
|
6438
6871
|
process.stdout.write(HELP);
|
|
6439
6872
|
return;
|
|
6440
6873
|
}
|
|
6441
|
-
const isHeadless = !!(argv["json-events"] || argv.headless || argv.list || argv.help);
|
|
6874
|
+
const isHeadless = !!(argv["json-events"] || argv.headless || argv.list || argv.help || positional[0] === "update");
|
|
6442
6875
|
if (!isHeadless) {
|
|
6443
6876
|
const stdin = process.stdin;
|
|
6444
6877
|
const stdout = process.stdout;
|
|
@@ -6619,7 +7052,57 @@ function personaNotesForGeneration2(cfg) {
|
|
|
6619
7052
|
].filter(Boolean);
|
|
6620
7053
|
return parts.join("\n\n");
|
|
6621
7054
|
}
|
|
7055
|
+
async function runUpdate(verbose) {
|
|
7056
|
+
const profiles = await listProfiles();
|
|
7057
|
+
if (!profiles.length) {
|
|
7058
|
+
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");
|
|
7059
|
+
return;
|
|
7060
|
+
}
|
|
7061
|
+
process.stdout.write(`\u043D\u0430\u0439\u0434\u0435\u043D\u043E \u043F\u0440\u043E\u0444\u0438\u043B\u0435\u0439: ${profiles.length}
|
|
7062
|
+
\u0437\u0430\u043F\u0443\u0441\u043A \u043C\u0438\u0433\u0440\u0430\u0446\u0438\u0439...
|
|
7063
|
+
`);
|
|
7064
|
+
const result = await runMigrations({ verbose });
|
|
7065
|
+
if (!result.migrationsApplied.length) {
|
|
7066
|
+
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");
|
|
7067
|
+
return;
|
|
7068
|
+
}
|
|
7069
|
+
process.stdout.write(`
|
|
7070
|
+
\u0433\u043E\u0442\u043E\u0432\u043E:
|
|
7071
|
+
`);
|
|
7072
|
+
process.stdout.write(` \u043C\u0438\u0433\u0440\u0430\u0446\u0438\u0439 \u043F\u0440\u0438\u043C\u0435\u043D\u0435\u043D\u043E: ${result.migrationsApplied.length}
|
|
7073
|
+
`);
|
|
7074
|
+
for (const id of result.migrationsApplied) {
|
|
7075
|
+
process.stdout.write(` - ${id}
|
|
7076
|
+
`);
|
|
7077
|
+
}
|
|
7078
|
+
process.stdout.write(` \u043F\u0440\u043E\u0444\u0438\u043B\u0435\u0439 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u043E: ${result.profilesUpdated}
|
|
7079
|
+
`);
|
|
7080
|
+
if (result.errors.length) {
|
|
7081
|
+
process.stdout.write(` \u043E\u0448\u0438\u0431\u043E\u043A: ${result.errors.length}
|
|
7082
|
+
`);
|
|
7083
|
+
for (const e of result.errors) {
|
|
7084
|
+
process.stdout.write(` ${e.profile} @ ${e.migration}: ${e.error}
|
|
7085
|
+
`);
|
|
7086
|
+
}
|
|
7087
|
+
}
|
|
7088
|
+
}
|
|
6622
7089
|
async function runRuntime(cfg, opts = {}) {
|
|
7090
|
+
if (await checkForPendingMigrations()) {
|
|
7091
|
+
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");
|
|
7092
|
+
const result = await runMigrations({
|
|
7093
|
+
verbose: true,
|
|
7094
|
+
llmFactory: (c) => {
|
|
7095
|
+
try {
|
|
7096
|
+
return makeLLM(c.llm);
|
|
7097
|
+
} catch {
|
|
7098
|
+
return void 0;
|
|
7099
|
+
}
|
|
7100
|
+
}
|
|
7101
|
+
});
|
|
7102
|
+
if (result.warnings.length) {
|
|
7103
|
+
process.stderr.write(formatUpdateWarnings(result.warnings) + "\n");
|
|
7104
|
+
}
|
|
7105
|
+
}
|
|
6623
7106
|
const rt = new Runtime(cfg);
|
|
6624
7107
|
await rt.start();
|
|
6625
7108
|
if (opts.jsonEvents) {
|