@hyperflow.fun/ghost 0.0.4 → 0.0.5
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/dist/index.js +943 -476
- package/dist/package.json +1 -1
- package/dist/skills/builtin/ask-user-questions/SKILL.md +48 -0
- package/dist/skills/builtin/event-judge/SKILL.md +51 -7
- package/dist/skills/builtin/trade-executor/SKILL.md +1 -1
- package/dist/web/dist/assets/{Chart-BgUhYrVH.js → Chart-cnNd398J.js} +1 -1
- package/dist/web/dist/assets/{Config-CMp84sNc.js → Config-Bui5kcW0.js} +1 -1
- package/dist/web/dist/assets/{Cost-BgKdnj4i.js → Cost-BDSIn5ub.js} +1 -1
- package/dist/web/dist/assets/{Cron-L4GEQwj0.js → Cron-C7gaZhMu.js} +1 -1
- package/dist/web/dist/assets/{Dashboard-D1UNPhTW.js → Dashboard-qwYsK3Gi.js} +1 -1
- package/dist/web/dist/assets/{Logs-DZkot-wQ.js → Logs-DyfS6kEe.js} +1 -1
- package/dist/web/dist/assets/{Memory-DsQackdo.js → Memory-BPMmbFbx.js} +1 -1
- package/dist/web/dist/assets/{Sessions-uqRIDn57.js → Sessions-nANl57gZ.js} +1 -1
- package/dist/web/dist/assets/{Skills-B9WQPgSe.js → Skills-BPXH_m1K.js} +1 -1
- package/dist/web/dist/assets/{Tools-Dyf8Zp-H.js → Tools-CypplonI.js} +1 -1
- package/dist/web/dist/assets/{activity-DRn1WSJo.js → activity-BLl_txfw.js} +1 -1
- package/dist/web/dist/assets/{clock-FMsaqykN.js → clock-CMLb2b5z.js} +1 -1
- package/dist/web/dist/assets/{highlighted-body-OFNGDK62-Ck5_e4wj.js → highlighted-body-OFNGDK62-CKxBaGN5.js} +1 -1
- package/dist/web/dist/assets/index-CKAK_IGv.js +59 -0
- package/dist/web/dist/assets/index-PX2emSv9.css +1 -0
- package/dist/web/dist/assets/{mermaid-GHXKKRXX-jlxJo7RH.js → mermaid-GHXKKRXX-BuHBmaw6.js} +3 -3
- package/dist/web/dist/assets/{refresh-cw-CRQa2SMT.js → refresh-cw-DHCgoaOK.js} +1 -1
- package/dist/web/dist/index.html +2 -2
- package/package.json +1 -1
- package/dist/web/dist/assets/index-CGNakXCn.css +0 -1
- package/dist/web/dist/assets/index-DNznoLXb.js +0 -54
package/dist/index.js
CHANGED
|
@@ -4094,7 +4094,6 @@ var init_schema = __esm(() => {
|
|
|
4094
4094
|
});
|
|
4095
4095
|
cronSchema = exports_external.object({
|
|
4096
4096
|
enableScheduler: exports_external.boolean().default(true),
|
|
4097
|
-
timezone: exports_external.string().default("UTC"),
|
|
4098
4097
|
maxConcurrentJobs: exports_external.coerce.number().int().positive().default(5)
|
|
4099
4098
|
});
|
|
4100
4099
|
telegramChannelSchema = exports_external.object({
|
|
@@ -4360,7 +4359,6 @@ __export(exports_paths, {
|
|
|
4360
4359
|
getEvalConfigPath: () => getEvalConfigPath,
|
|
4361
4360
|
getDbPath: () => getDbPath,
|
|
4362
4361
|
getDaemonPidPath: () => getDaemonPidPath,
|
|
4363
|
-
getCronStorePath: () => getCronStorePath,
|
|
4364
4362
|
getCredentialsPath: () => getCredentialsPath,
|
|
4365
4363
|
getConfigPath: () => getConfigPath,
|
|
4366
4364
|
getCliWorkspacePath: () => getCliWorkspacePath,
|
|
@@ -4405,9 +4403,6 @@ function getModelsConfigPath() {
|
|
|
4405
4403
|
function getEvalConfigPath() {
|
|
4406
4404
|
return join(getGhostDir(), "eval.json");
|
|
4407
4405
|
}
|
|
4408
|
-
function getCronStorePath() {
|
|
4409
|
-
return join(getWorkspaceDir(), "cron", "jobs.json");
|
|
4410
|
-
}
|
|
4411
4406
|
function getCliWorkspacePath() {
|
|
4412
4407
|
return join(getGhostDir(), "cli-workspace");
|
|
4413
4408
|
}
|
|
@@ -4513,7 +4508,6 @@ __export(exports_config, {
|
|
|
4513
4508
|
getEvalConfigPath: () => getEvalConfigPath,
|
|
4514
4509
|
getDbPath: () => getDbPath,
|
|
4515
4510
|
getDaemonPidPath: () => getDaemonPidPath,
|
|
4516
|
-
getCronStorePath: () => getCronStorePath,
|
|
4517
4511
|
getCredentialsPath: () => getCredentialsPath,
|
|
4518
4512
|
getConfigPath: () => getConfigPath,
|
|
4519
4513
|
getCliWorkspacePath: () => getCliWorkspacePath,
|
|
@@ -151269,6 +151263,34 @@ function formatOrder(order) {
|
|
|
151269
151263
|
return `${order.symbol} ${formatSide(order.side)} ${order.type} ${order.size}${priceStr}${triggerStr}`;
|
|
151270
151264
|
}
|
|
151271
151265
|
|
|
151266
|
+
// src/services/wizard-data.ts
|
|
151267
|
+
function composeOpenPositionWizard(input) {
|
|
151268
|
+
const symbol5 = input.symbol?.toUpperCase();
|
|
151269
|
+
if (!symbol5)
|
|
151270
|
+
return;
|
|
151271
|
+
if (typeof input.size !== "number" || !Number.isFinite(input.size))
|
|
151272
|
+
return;
|
|
151273
|
+
const side = input.side === "buy" || input.side === "long" ? "long" : "short";
|
|
151274
|
+
const leverage = input.leverage && input.leverage > 0 ? input.leverage : 1;
|
|
151275
|
+
const orderType = input.orderType === "limit" ? "limit" : "market";
|
|
151276
|
+
const hasEntry = typeof input.entryPrice === "number" && Number.isFinite(input.entryPrice) && input.entryPrice > 0;
|
|
151277
|
+
const entryPrice = hasEntry ? input.entryPrice : undefined;
|
|
151278
|
+
return {
|
|
151279
|
+
kind: "open_position",
|
|
151280
|
+
symbol: symbol5,
|
|
151281
|
+
side,
|
|
151282
|
+
leverage,
|
|
151283
|
+
size: input.size,
|
|
151284
|
+
orderType,
|
|
151285
|
+
entryPrice,
|
|
151286
|
+
stopLoss: input.stopLoss,
|
|
151287
|
+
takeProfit: input.takeProfit
|
|
151288
|
+
};
|
|
151289
|
+
}
|
|
151290
|
+
function composeGenericWizard(groups) {
|
|
151291
|
+
return { kind: "generic", groups };
|
|
151292
|
+
}
|
|
151293
|
+
|
|
151272
151294
|
// src/services/confirm-policy.ts
|
|
151273
151295
|
function isConfirmable(toolName) {
|
|
151274
151296
|
return CONFIRMABLE_TOOLS.has(toolName);
|
|
@@ -151313,15 +151335,25 @@ function describePlaceOrder(params) {
|
|
|
151313
151335
|
const sizeStr = size !== undefined ? `${size}` : "";
|
|
151314
151336
|
const levSuffix = leverage && leverage > 0 ? ` ${leverage}x` : "";
|
|
151315
151337
|
const sideRow = leverage && leverage > 0 ? `Side: ${side} ${leverage}x` : `Side: ${side}`;
|
|
151338
|
+
const wizard = composeOpenPositionWizard({
|
|
151339
|
+
symbol: getString(params, "symbol") ?? "",
|
|
151340
|
+
side: getString(params, "side") ?? "buy",
|
|
151341
|
+
size: getNumber(params, "size") ?? 0,
|
|
151342
|
+
leverage: getNumber(params, "leverage"),
|
|
151343
|
+
orderType: getString(params, "orderType"),
|
|
151344
|
+
entryPrice: price
|
|
151345
|
+
});
|
|
151316
151346
|
if (orderType === "limit" && price !== undefined) {
|
|
151317
151347
|
return {
|
|
151318
151348
|
title: `Place limit order: ${side} ${sizeStr} ${symbol5} @ ${formatUsd(price)}?`,
|
|
151319
|
-
bullets: [sideRow]
|
|
151349
|
+
bullets: [sideRow],
|
|
151350
|
+
wizard
|
|
151320
151351
|
};
|
|
151321
151352
|
}
|
|
151322
151353
|
return {
|
|
151323
151354
|
title: `Place market order: ${side} ${sizeStr} ${symbol5}?`,
|
|
151324
|
-
bullets: [sideRow]
|
|
151355
|
+
bullets: [sideRow],
|
|
151356
|
+
wizard
|
|
151325
151357
|
};
|
|
151326
151358
|
}
|
|
151327
151359
|
function describeBracketOrder(params) {
|
|
@@ -151329,8 +151361,9 @@ function describeBracketOrder(params) {
|
|
|
151329
151361
|
const side = sideLabel(getString(params, "side"));
|
|
151330
151362
|
const leverage = getNumber(params, "leverage");
|
|
151331
151363
|
const size = getNumber(params, "size");
|
|
151332
|
-
const
|
|
151364
|
+
const rawOrderType = getString(params, "orderType")?.toLowerCase();
|
|
151333
151365
|
const entryPrice = getNumber(params, "entryPrice") ?? getNumber(params, "price");
|
|
151366
|
+
const orderType = rawOrderType ?? (entryPrice !== undefined ? "limit" : "market");
|
|
151334
151367
|
const stopLoss = getNumber(params, "stopLoss");
|
|
151335
151368
|
const takeProfit = getNumber(params, "takeProfit");
|
|
151336
151369
|
const sizeStr = size !== undefined ? `${size}` : "";
|
|
@@ -151343,7 +151376,17 @@ function describeBracketOrder(params) {
|
|
|
151343
151376
|
bullets.push(`SL: ${formatUsdCompact(stopLoss)}`);
|
|
151344
151377
|
if (takeProfit !== undefined)
|
|
151345
151378
|
bullets.push(`TP: ${formatUsdCompact(takeProfit)}`);
|
|
151346
|
-
|
|
151379
|
+
const wizard = composeOpenPositionWizard({
|
|
151380
|
+
symbol: getString(params, "symbol") ?? "",
|
|
151381
|
+
side: getString(params, "side") ?? "buy",
|
|
151382
|
+
size: getNumber(params, "size") ?? 0,
|
|
151383
|
+
leverage: getNumber(params, "leverage"),
|
|
151384
|
+
orderType,
|
|
151385
|
+
entryPrice,
|
|
151386
|
+
stopLoss: getNumber(params, "stopLoss"),
|
|
151387
|
+
takeProfit: getNumber(params, "takeProfit")
|
|
151388
|
+
});
|
|
151389
|
+
return { title, bullets, wizard };
|
|
151347
151390
|
}
|
|
151348
151391
|
function describeSetSlTp(params) {
|
|
151349
151392
|
const symbol5 = upper(getString(params, "symbol"));
|
|
@@ -151414,14 +151457,26 @@ function describePartialClose(params) {
|
|
|
151414
151457
|
const symbol5 = upper(getString(params, "symbol"));
|
|
151415
151458
|
const pct = getNumber(params, "percentage");
|
|
151416
151459
|
const size = getNumber(params, "size");
|
|
151460
|
+
const sizeBefore = getNumber(params, "sizeBefore");
|
|
151461
|
+
const rows = [];
|
|
151462
|
+
if (pct !== undefined)
|
|
151463
|
+
rows.push({ label: "Close %", value: `${pct}%` });
|
|
151464
|
+
if (size !== undefined)
|
|
151465
|
+
rows.push({ label: "Size", value: `${size} ${symbol5}` });
|
|
151466
|
+
if (sizeBefore !== undefined && pct !== undefined) {
|
|
151467
|
+
const sizeAfter = sizeBefore * (1 - pct / 100);
|
|
151468
|
+
rows.push({ label: "Size before", value: `${sizeBefore}`, tone: "muted" });
|
|
151469
|
+
rows.push({ label: "Size after", value: `${sizeAfter}` });
|
|
151470
|
+
}
|
|
151471
|
+
const wizard = rows.length > 0 ? composeGenericWizard([{ label: `${symbol5} partial close`, rows }]) : undefined;
|
|
151417
151472
|
if (pct !== undefined) {
|
|
151418
151473
|
const pctStr = Number.isInteger(pct) ? `${pct}` : pct.toFixed(0);
|
|
151419
|
-
return { title: `Close ${pctStr}% of ${symbol5} position?`, bullets: [] };
|
|
151474
|
+
return { title: `Close ${pctStr}% of ${symbol5} position?`, bullets: [], wizard };
|
|
151420
151475
|
}
|
|
151421
151476
|
if (size !== undefined) {
|
|
151422
|
-
return { title: `Close ${size} ${symbol5} position?`, bullets: [] };
|
|
151477
|
+
return { title: `Close ${size} ${symbol5} position?`, bullets: [], wizard };
|
|
151423
151478
|
}
|
|
151424
|
-
return { title: `Close part of ${symbol5} position?`, bullets: [] };
|
|
151479
|
+
return { title: `Close part of ${symbol5} position?`, bullets: [], wizard };
|
|
151425
151480
|
}
|
|
151426
151481
|
function describeAdjustMargin(params) {
|
|
151427
151482
|
const symbol5 = upper(getString(params, "symbol"));
|
|
@@ -151429,17 +151484,26 @@ function describeAdjustMargin(params) {
|
|
|
151429
151484
|
if (amount === undefined) {
|
|
151430
151485
|
return { title: `Adjust margin on ${symbol5}?`, bullets: [] };
|
|
151431
151486
|
}
|
|
151487
|
+
const sign = amount >= 0 ? "+" : "\u2212";
|
|
151488
|
+
const rows = [
|
|
151489
|
+
{
|
|
151490
|
+
label: "Margin change",
|
|
151491
|
+
value: `${sign}${formatUsd(Math.abs(amount))}`,
|
|
151492
|
+
tone: amount >= 0 ? "reward" : "risk"
|
|
151493
|
+
}
|
|
151494
|
+
];
|
|
151495
|
+
const wizard = composeGenericWizard([{ label: `${symbol5} margin adjust`, rows }]);
|
|
151432
151496
|
if (amount >= 0) {
|
|
151433
|
-
return { title: `Add ${formatUsd(amount)} margin to ${symbol5}?`, bullets: [] };
|
|
151497
|
+
return { title: `Add ${formatUsd(amount)} margin to ${symbol5}?`, bullets: [], wizard };
|
|
151434
151498
|
}
|
|
151435
|
-
return { title: `Reduce ${formatUsd(Math.abs(amount))} margin on ${symbol5}?`, bullets: [] };
|
|
151499
|
+
return { title: `Reduce ${formatUsd(Math.abs(amount))} margin on ${symbol5}?`, bullets: [], wizard };
|
|
151436
151500
|
}
|
|
151437
151501
|
function describeConfirm(toolName, params) {
|
|
151438
151502
|
const safeParams = params && typeof params === "object" ? params : {};
|
|
151439
151503
|
const describer = CONFIRM_DESCRIBERS[toolName];
|
|
151440
151504
|
if (describer)
|
|
151441
151505
|
return describer(safeParams);
|
|
151442
|
-
return { title: `
|
|
151506
|
+
return { title: `Run ${toolName}?`, bullets: [] };
|
|
151443
151507
|
}
|
|
151444
151508
|
var CONFIRMABLE_TOOLS, CONFIRM_DESCRIBERS;
|
|
151445
151509
|
var init_confirm_policy = __esm(() => {
|
|
@@ -151487,7 +151551,7 @@ function createGhostSdkMcpServer(deps) {
|
|
|
151487
151551
|
}
|
|
151488
151552
|
if (decision.decision === "rejected") {
|
|
151489
151553
|
const reasonMsg = decision.reason && decision.reason.length > 0 ? `User declined. Reason: ${decision.reason}` : "User declined. Do not retry.";
|
|
151490
|
-
logger.debug({ tool: agentTool.name, reason: decision.reason }, "tool
|
|
151554
|
+
logger.debug({ tool: agentTool.name, reason: decision.reason }, "tool not approved");
|
|
151491
151555
|
return { content: [{ type: "text", text: reasonMsg }], isError: true };
|
|
151492
151556
|
}
|
|
151493
151557
|
}
|
|
@@ -151532,7 +151596,36 @@ var init_constants2 = __esm(() => {
|
|
|
151532
151596
|
"read_file",
|
|
151533
151597
|
"list_dir",
|
|
151534
151598
|
"web_fetch",
|
|
151535
|
-
"web_search"
|
|
151599
|
+
"web_search",
|
|
151600
|
+
"ghost_chat_history",
|
|
151601
|
+
"ghost_get_trade_history",
|
|
151602
|
+
"ghost_get_balance",
|
|
151603
|
+
"ghost_get_positions",
|
|
151604
|
+
"ghost_get_orders",
|
|
151605
|
+
"ghost_list_wallets",
|
|
151606
|
+
"ghost_get_recent_orders",
|
|
151607
|
+
"ghost_get_price",
|
|
151608
|
+
"ghost_get_funding_rates",
|
|
151609
|
+
"ghost_get_orderbook",
|
|
151610
|
+
"ghost_get_klines",
|
|
151611
|
+
"ghost_get_indicators",
|
|
151612
|
+
"ghost_get_levels",
|
|
151613
|
+
"ghost_market_overview",
|
|
151614
|
+
"ghost_pre_trade_check",
|
|
151615
|
+
"ghost_morning_briefing",
|
|
151616
|
+
"ghost_session_info",
|
|
151617
|
+
"ghost_timing_risk",
|
|
151618
|
+
"ghost_cross_exchange_funding",
|
|
151619
|
+
"ghost_liquidation_map",
|
|
151620
|
+
"ghost_get_whale_activity",
|
|
151621
|
+
"ghost_tweets_search",
|
|
151622
|
+
"ghost_news_sources",
|
|
151623
|
+
"ghost_news_search",
|
|
151624
|
+
"ghost_news_discover_rss",
|
|
151625
|
+
"ghost_watchlist_list",
|
|
151626
|
+
"ghost_alert_list",
|
|
151627
|
+
"ghost_alert_history",
|
|
151628
|
+
"ghost_check_alerts"
|
|
151536
151629
|
]);
|
|
151537
151630
|
});
|
|
151538
151631
|
|
|
@@ -156179,14 +156272,6 @@ function createClaudeCliModel(modelId) {
|
|
|
156179
156272
|
maxTokens: known?.maxTokens ?? DEFAULT_SPECS.maxTokens
|
|
156180
156273
|
};
|
|
156181
156274
|
}
|
|
156182
|
-
function getClaudeCliModels() {
|
|
156183
|
-
return [
|
|
156184
|
-
{ id: "claude-opus-4-7", name: "Claude Opus 4.7" },
|
|
156185
|
-
{ id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" },
|
|
156186
|
-
{ id: "claude-haiku-4-5", name: "Claude Haiku 4.5" },
|
|
156187
|
-
{ id: "claude-opus-4-6", name: "Claude Opus 4.6" }
|
|
156188
|
-
];
|
|
156189
|
-
}
|
|
156190
156275
|
var KNOWN_MODELS, DEFAULT_SPECS;
|
|
156191
156276
|
var init_models6 = __esm(() => {
|
|
156192
156277
|
KNOWN_MODELS = {
|
|
@@ -156485,7 +156570,7 @@ function assertValidVersions(sorted) {
|
|
|
156485
156570
|
}
|
|
156486
156571
|
}
|
|
156487
156572
|
}
|
|
156488
|
-
var baselineDbMigration, proactiveCooldownsMigration, dropProactiveCooldownsMigration, alertsKindPayloadMigration, addSettingsKvMigration, addTweetsAiRelevantMigration, addObserverStateMigration, splitAlertsMigration, addXFollowsEnabledSourceMigration, DB_MIGRATIONS, CONFIG_MIGRATIONS;
|
|
156573
|
+
var baselineDbMigration, proactiveCooldownsMigration, dropProactiveCooldownsMigration, alertsKindPayloadMigration, addSettingsKvMigration, addTweetsAiRelevantMigration, addObserverStateMigration, splitAlertsMigration, addXFollowsEnabledSourceMigration, addCronJobsMigration, DB_MIGRATIONS, CONFIG_MIGRATIONS;
|
|
156489
156574
|
var init_registry2 = __esm(() => {
|
|
156490
156575
|
baselineDbMigration = {
|
|
156491
156576
|
version: 1,
|
|
@@ -156618,6 +156703,42 @@ var init_registry2 = __esm(() => {
|
|
|
156618
156703
|
db2.run(`UPDATE x_follows SET user_disabled = 0 WHERE user_disabled IS NULL`);
|
|
156619
156704
|
}
|
|
156620
156705
|
};
|
|
156706
|
+
addCronJobsMigration = {
|
|
156707
|
+
version: 10,
|
|
156708
|
+
label: "add_cron_jobs",
|
|
156709
|
+
up: (db2) => {
|
|
156710
|
+
db2.run(`
|
|
156711
|
+
CREATE TABLE IF NOT EXISTS cron_jobs (
|
|
156712
|
+
id TEXT PRIMARY KEY,
|
|
156713
|
+
name TEXT NOT NULL,
|
|
156714
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
156715
|
+
schedule_kind TEXT NOT NULL,
|
|
156716
|
+
schedule_at_ms INTEGER,
|
|
156717
|
+
schedule_every_ms INTEGER,
|
|
156718
|
+
schedule_expr TEXT,
|
|
156719
|
+
schedule_tz TEXT,
|
|
156720
|
+
payload_kind TEXT NOT NULL DEFAULT 'agent_turn',
|
|
156721
|
+
payload_message TEXT NOT NULL,
|
|
156722
|
+
payload_deliver INTEGER NOT NULL DEFAULT 1,
|
|
156723
|
+
payload_channel TEXT,
|
|
156724
|
+
payload_to TEXT,
|
|
156725
|
+
next_run_at_ms INTEGER,
|
|
156726
|
+
last_run_at_ms INTEGER,
|
|
156727
|
+
last_status TEXT,
|
|
156728
|
+
last_error TEXT,
|
|
156729
|
+
run_history TEXT NOT NULL DEFAULT '[]',
|
|
156730
|
+
created_at_ms INTEGER NOT NULL,
|
|
156731
|
+
updated_at_ms INTEGER NOT NULL,
|
|
156732
|
+
delete_after_run INTEGER NOT NULL DEFAULT 0
|
|
156733
|
+
);
|
|
156734
|
+
`);
|
|
156735
|
+
db2.run(`CREATE UNIQUE INDEX IF NOT EXISTS idx_cron_jobs_name ON cron_jobs(name);`);
|
|
156736
|
+
db2.run(`
|
|
156737
|
+
CREATE INDEX IF NOT EXISTS idx_cron_jobs_enabled_next
|
|
156738
|
+
ON cron_jobs(enabled, next_run_at_ms) WHERE enabled = 1;
|
|
156739
|
+
`);
|
|
156740
|
+
}
|
|
156741
|
+
};
|
|
156621
156742
|
DB_MIGRATIONS = [
|
|
156622
156743
|
baselineDbMigration,
|
|
156623
156744
|
proactiveCooldownsMigration,
|
|
@@ -156627,7 +156748,8 @@ var init_registry2 = __esm(() => {
|
|
|
156627
156748
|
addTweetsAiRelevantMigration,
|
|
156628
156749
|
addObserverStateMigration,
|
|
156629
156750
|
splitAlertsMigration,
|
|
156630
|
-
addXFollowsEnabledSourceMigration
|
|
156751
|
+
addXFollowsEnabledSourceMigration,
|
|
156752
|
+
addCronJobsMigration
|
|
156631
156753
|
];
|
|
156632
156754
|
CONFIG_MIGRATIONS = [];
|
|
156633
156755
|
});
|
|
@@ -157957,6 +158079,9 @@ class ToolRegistry {
|
|
|
157957
158079
|
all() {
|
|
157958
158080
|
return [...this.tools.values()];
|
|
157959
158081
|
}
|
|
158082
|
+
taskAgentTools() {
|
|
158083
|
+
return [...this.tools.values()].filter((t2) => READ_TOOLS.has(t2.name) || TASK_AGENT_EXTRAS.has(t2.name));
|
|
158084
|
+
}
|
|
157960
158085
|
names() {
|
|
157961
158086
|
return [...this.tools.keys()];
|
|
157962
158087
|
}
|
|
@@ -158003,7 +158128,11 @@ class ToolRegistry {
|
|
|
158003
158128
|
return { ...result, content: truncated };
|
|
158004
158129
|
}
|
|
158005
158130
|
}
|
|
158006
|
-
var MAX_RESULT_CHARS = 16000;
|
|
158131
|
+
var MAX_RESULT_CHARS = 16000, TASK_AGENT_EXTRAS;
|
|
158132
|
+
var init_registry3 = __esm(() => {
|
|
158133
|
+
init_constants2();
|
|
158134
|
+
TASK_AGENT_EXTRAS = new Set(["save_memory", "cron"]);
|
|
158135
|
+
});
|
|
158007
158136
|
|
|
158008
158137
|
// src/tools/read-file.ts
|
|
158009
158138
|
import { readFileSync as readFileSync11, statSync as statSync2 } from "fs";
|
|
@@ -158630,7 +158759,7 @@ var init_web_fetch = __esm(() => {
|
|
|
158630
158759
|
// src/tools/cron.ts
|
|
158631
158760
|
class CronTool {
|
|
158632
158761
|
service;
|
|
158633
|
-
|
|
158762
|
+
tzService;
|
|
158634
158763
|
name = "cron";
|
|
158635
158764
|
label = "Cron";
|
|
158636
158765
|
description = "Schedule reminders and recurring tasks. Actions: add, list, remove.";
|
|
@@ -158638,9 +158767,9 @@ class CronTool {
|
|
|
158638
158767
|
_channel = null;
|
|
158639
158768
|
_chatId = null;
|
|
158640
158769
|
_inCron = false;
|
|
158641
|
-
constructor(service,
|
|
158770
|
+
constructor(service, tzService) {
|
|
158642
158771
|
this.service = service;
|
|
158643
|
-
this.
|
|
158772
|
+
this.tzService = tzService;
|
|
158644
158773
|
}
|
|
158645
158774
|
setOrigin(channel, chatId) {
|
|
158646
158775
|
this._channel = channel || null;
|
|
@@ -158674,7 +158803,7 @@ class CronTool {
|
|
|
158674
158803
|
if (params.every_seconds) {
|
|
158675
158804
|
schedule = { kind: "every", everyMs: params.every_seconds * 1000 };
|
|
158676
158805
|
} else if (params.cron_expr) {
|
|
158677
|
-
schedule = { kind: "cron", expr: params.cron_expr, tz: params.tz ?? this.
|
|
158806
|
+
schedule = { kind: "cron", expr: params.cron_expr, tz: params.tz ?? this.tzService.get() };
|
|
158678
158807
|
} else if (params.at) {
|
|
158679
158808
|
const atMs = new Date(params.at).getTime();
|
|
158680
158809
|
if (isNaN(atMs))
|
|
@@ -158791,11 +158920,12 @@ function createToolRegistry(_security, options) {
|
|
|
158791
158920
|
reg(new ExecTool);
|
|
158792
158921
|
reg(new WebSearchTool(options.webSearchConfig));
|
|
158793
158922
|
reg(new WebFetchTool);
|
|
158794
|
-
reg(new CronTool(options.cronService, options.
|
|
158923
|
+
reg(new CronTool(options.cronService, options.timezoneService));
|
|
158795
158924
|
reg(new SaveMemoryTool(options.memoryStore));
|
|
158796
158925
|
return registry4;
|
|
158797
158926
|
}
|
|
158798
158927
|
var init_tools = __esm(() => {
|
|
158928
|
+
init_registry3();
|
|
158799
158929
|
init_read_file();
|
|
158800
158930
|
init_write_file();
|
|
158801
158931
|
init_edit_file();
|
|
@@ -158805,6 +158935,7 @@ var init_tools = __esm(() => {
|
|
|
158805
158935
|
init_web_fetch();
|
|
158806
158936
|
init_cron();
|
|
158807
158937
|
init_save_memory();
|
|
158938
|
+
init_registry3();
|
|
158808
158939
|
init_read_file();
|
|
158809
158940
|
init_write_file();
|
|
158810
158941
|
init_edit_file();
|
|
@@ -159684,7 +159815,7 @@ class ContextBuilder {
|
|
|
159684
159815
|
return prompt.toString();
|
|
159685
159816
|
}
|
|
159686
159817
|
buildRuntimeContext(channel, chatId) {
|
|
159687
|
-
const tz = this.config.
|
|
159818
|
+
const tz = this.config.getTimezone?.() ?? "UTC";
|
|
159688
159819
|
const now = new Date;
|
|
159689
159820
|
const timeStr = now.toLocaleString("en-US", {
|
|
159690
159821
|
timeZone: tz,
|
|
@@ -168553,45 +168684,63 @@ var require_dist5 = __commonJS((exports) => {
|
|
|
168553
168684
|
exports.default = CronExpressionParser_1.CronExpressionParser;
|
|
168554
168685
|
});
|
|
168555
168686
|
|
|
168556
|
-
// src/scheduler/
|
|
168557
|
-
function
|
|
168558
|
-
|
|
168559
|
-
|
|
168560
|
-
|
|
168561
|
-
|
|
168687
|
+
// src/scheduler/storage.ts
|
|
168688
|
+
function scheduleFromRow(row) {
|
|
168689
|
+
switch (row.schedule_kind) {
|
|
168690
|
+
case "at":
|
|
168691
|
+
return { kind: "at", atMs: row.schedule_at_ms ?? undefined };
|
|
168692
|
+
case "every":
|
|
168693
|
+
return { kind: "every", everyMs: row.schedule_every_ms ?? undefined };
|
|
168694
|
+
case "cron":
|
|
168695
|
+
return {
|
|
168696
|
+
kind: "cron",
|
|
168697
|
+
expr: row.schedule_expr ?? undefined,
|
|
168698
|
+
tz: row.schedule_tz ?? undefined
|
|
168699
|
+
};
|
|
168700
|
+
default:
|
|
168701
|
+
return { kind: "cron" };
|
|
168562
168702
|
}
|
|
168563
168703
|
}
|
|
168564
|
-
|
|
168565
|
-
|
|
168566
|
-
|
|
168567
|
-
|
|
168568
|
-
|
|
168569
|
-
|
|
168570
|
-
|
|
168571
|
-
|
|
168572
|
-
|
|
168573
|
-
|
|
168574
|
-
|
|
168575
|
-
|
|
168576
|
-
message:
|
|
168577
|
-
deliver:
|
|
168704
|
+
function rowToJob(row) {
|
|
168705
|
+
let runHistory = [];
|
|
168706
|
+
try {
|
|
168707
|
+
runHistory = JSON.parse(row.run_history);
|
|
168708
|
+
} catch {}
|
|
168709
|
+
return {
|
|
168710
|
+
id: row.id,
|
|
168711
|
+
name: row.name,
|
|
168712
|
+
enabled: row.enabled === 1,
|
|
168713
|
+
schedule: scheduleFromRow(row),
|
|
168714
|
+
payload: {
|
|
168715
|
+
kind: "agent_turn",
|
|
168716
|
+
message: row.payload_message,
|
|
168717
|
+
deliver: row.payload_deliver === 1,
|
|
168718
|
+
channel: row.payload_channel ?? undefined,
|
|
168719
|
+
to: row.payload_to ?? undefined
|
|
168578
168720
|
},
|
|
168579
|
-
{
|
|
168580
|
-
|
|
168581
|
-
|
|
168582
|
-
|
|
168583
|
-
|
|
168584
|
-
|
|
168585
|
-
|
|
168586
|
-
|
|
168587
|
-
|
|
168588
|
-
|
|
168589
|
-
|
|
168590
|
-
}
|
|
168721
|
+
state: {
|
|
168722
|
+
nextRunAtMs: row.next_run_at_ms,
|
|
168723
|
+
lastRunAtMs: row.last_run_at_ms,
|
|
168724
|
+
lastStatus: row.last_status ?? null,
|
|
168725
|
+
lastError: row.last_error,
|
|
168726
|
+
runHistory
|
|
168727
|
+
},
|
|
168728
|
+
createdAtMs: row.created_at_ms,
|
|
168729
|
+
updatedAtMs: row.updated_at_ms,
|
|
168730
|
+
deleteAfterRun: row.delete_after_run === 1
|
|
168731
|
+
};
|
|
168732
|
+
}
|
|
168733
|
+
function scheduleBindings(s2) {
|
|
168734
|
+
return {
|
|
168735
|
+
schedule_kind: s2.kind,
|
|
168736
|
+
schedule_at_ms: s2.atMs ?? null,
|
|
168737
|
+
schedule_every_ms: s2.everyMs ?? null,
|
|
168738
|
+
schedule_expr: s2.expr ?? null,
|
|
168739
|
+
schedule_tz: s2.tz ?? null
|
|
168740
|
+
};
|
|
168741
|
+
}
|
|
168591
168742
|
|
|
168592
168743
|
// src/scheduler/service.ts
|
|
168593
|
-
import { existsSync as existsSync17, readFileSync as readFileSync16, writeFileSync as writeFileSync10, mkdirSync as mkdirSync13, statSync as statSync4 } from "fs";
|
|
168594
|
-
import { dirname as dirname8 } from "path";
|
|
168595
168744
|
function computeNextRun(schedule, nowMs) {
|
|
168596
168745
|
switch (schedule.kind) {
|
|
168597
168746
|
case "at":
|
|
@@ -168618,259 +168767,292 @@ function computeNextRun(schedule, nowMs) {
|
|
|
168618
168767
|
return null;
|
|
168619
168768
|
}
|
|
168620
168769
|
}
|
|
168621
|
-
|
|
168622
|
-
|
|
168623
|
-
|
|
168624
|
-
|
|
168625
|
-
|
|
168626
|
-
|
|
168627
|
-
|
|
168628
|
-
|
|
168629
|
-
|
|
168630
|
-
|
|
168631
|
-
|
|
168632
|
-
|
|
168633
|
-
|
|
168634
|
-
|
|
168635
|
-
|
|
168636
|
-
|
|
168637
|
-
|
|
168638
|
-
|
|
168639
|
-
|
|
168640
|
-
|
|
168641
|
-
|
|
168642
|
-
|
|
168643
|
-
|
|
168644
|
-
|
|
168645
|
-
|
|
168646
|
-
|
|
168770
|
+
var import_cron_parser, MAX_HISTORY = 20, MIN_INTERVAL_MS = 1e4, CronService;
|
|
168771
|
+
var init_service = __esm(() => {
|
|
168772
|
+
import_cron_parser = __toESM(require_dist5(), 1);
|
|
168773
|
+
CronService = class CronService {
|
|
168774
|
+
db;
|
|
168775
|
+
stmts;
|
|
168776
|
+
timerHandle = null;
|
|
168777
|
+
_running = false;
|
|
168778
|
+
onJob;
|
|
168779
|
+
static DEFAULT_JOB_NAMES = ["morning-briefing", "evening-recap"];
|
|
168780
|
+
constructor(db2) {
|
|
168781
|
+
this.db = db2;
|
|
168782
|
+
this.stmts = {
|
|
168783
|
+
selectAll: db2.prepare("SELECT * FROM cron_jobs"),
|
|
168784
|
+
selectById: db2.prepare("SELECT * FROM cron_jobs WHERE id = ?"),
|
|
168785
|
+
selectByName: db2.prepare("SELECT * FROM cron_jobs WHERE name = ?"),
|
|
168786
|
+
insert: db2.prepare(`
|
|
168787
|
+
INSERT INTO cron_jobs (
|
|
168788
|
+
id, name, enabled,
|
|
168789
|
+
schedule_kind, schedule_at_ms, schedule_every_ms, schedule_expr, schedule_tz,
|
|
168790
|
+
payload_kind, payload_message, payload_deliver, payload_channel, payload_to,
|
|
168791
|
+
next_run_at_ms, last_run_at_ms, last_status, last_error,
|
|
168792
|
+
run_history, created_at_ms, updated_at_ms, delete_after_run
|
|
168793
|
+
) VALUES (
|
|
168794
|
+
$id, $name, $enabled,
|
|
168795
|
+
$schedule_kind, $schedule_at_ms, $schedule_every_ms, $schedule_expr, $schedule_tz,
|
|
168796
|
+
$payload_kind, $payload_message, $payload_deliver, $payload_channel, $payload_to,
|
|
168797
|
+
$next_run_at_ms, NULL, NULL, NULL,
|
|
168798
|
+
'[]', $created_at_ms, $updated_at_ms, $delete_after_run
|
|
168799
|
+
)
|
|
168800
|
+
`),
|
|
168801
|
+
updateFull: db2.prepare(`
|
|
168802
|
+
UPDATE cron_jobs SET
|
|
168803
|
+
last_run_at_ms = $last_run_at_ms,
|
|
168804
|
+
last_status = $last_status,
|
|
168805
|
+
last_error = $last_error,
|
|
168806
|
+
next_run_at_ms = $next_run_at_ms,
|
|
168807
|
+
run_history = $run_history,
|
|
168808
|
+
enabled = $enabled,
|
|
168809
|
+
updated_at_ms = $updated_at_ms
|
|
168810
|
+
WHERE id = $id
|
|
168811
|
+
`),
|
|
168812
|
+
updateNext: db2.prepare("UPDATE cron_jobs SET next_run_at_ms = ?, updated_at_ms = ? WHERE id = ?"),
|
|
168813
|
+
updateTzAndNext: db2.prepare("UPDATE cron_jobs SET schedule_tz = ?, next_run_at_ms = ?, updated_at_ms = ? WHERE name = ?"),
|
|
168814
|
+
updateEnabled: db2.prepare("UPDATE cron_jobs SET enabled = ?, next_run_at_ms = ?, updated_at_ms = ? WHERE id = ?"),
|
|
168815
|
+
delete: db2.prepare("DELETE FROM cron_jobs WHERE id = ?")
|
|
168816
|
+
};
|
|
168817
|
+
}
|
|
168818
|
+
setOnJob(fn) {
|
|
168819
|
+
this.onJob = fn;
|
|
168820
|
+
}
|
|
168821
|
+
start(opts = {}) {
|
|
168822
|
+
this._running = true;
|
|
168823
|
+
this.seedDefaultJobs(opts.defaults ?? []);
|
|
168824
|
+
const now = Date.now();
|
|
168825
|
+
const rows = this.stmts.selectAll.all();
|
|
168826
|
+
this.db.transaction(() => {
|
|
168827
|
+
for (const row of rows) {
|
|
168828
|
+
if (row.enabled === 1 && row.next_run_at_ms !== null && row.next_run_at_ms <= now) {
|
|
168829
|
+
const schedule = scheduleFromRow(row);
|
|
168830
|
+
const next = computeNextRun(schedule, now);
|
|
168831
|
+
this.stmts.updateNext.run(next, now, row.id);
|
|
168832
|
+
} else if (row.next_run_at_ms === null && row.enabled) {
|
|
168833
|
+
const schedule = scheduleFromRow(row);
|
|
168834
|
+
const next = computeNextRun(schedule, now);
|
|
168835
|
+
this.stmts.updateNext.run(next, now, row.id);
|
|
168836
|
+
}
|
|
168837
|
+
}
|
|
168838
|
+
})();
|
|
168839
|
+
this.scheduleNextTick();
|
|
168840
|
+
}
|
|
168841
|
+
stop() {
|
|
168842
|
+
this._running = false;
|
|
168843
|
+
if (this.timerHandle) {
|
|
168844
|
+
clearTimeout(this.timerHandle);
|
|
168845
|
+
this.timerHandle = null;
|
|
168647
168846
|
}
|
|
168648
168847
|
}
|
|
168649
|
-
|
|
168650
|
-
|
|
168651
|
-
|
|
168652
|
-
|
|
168653
|
-
this._running = false;
|
|
168654
|
-
if (this.timerHandle) {
|
|
168655
|
-
clearTimeout(this.timerHandle);
|
|
168656
|
-
this.timerHandle = null;
|
|
168848
|
+
listJobs(includeDisabled = false) {
|
|
168849
|
+
const rows = this.stmts.selectAll.all();
|
|
168850
|
+
const jobs = includeDisabled ? rows.map(rowToJob) : rows.filter((r2) => r2.enabled === 1).map(rowToJob);
|
|
168851
|
+
return jobs.sort((a, b5) => (a.state.nextRunAtMs ?? Infinity) - (b5.state.nextRunAtMs ?? Infinity));
|
|
168657
168852
|
}
|
|
168658
|
-
|
|
168659
|
-
|
|
168660
|
-
|
|
168661
|
-
|
|
168662
|
-
|
|
168663
|
-
|
|
168664
|
-
|
|
168665
|
-
|
|
168666
|
-
|
|
168667
|
-
|
|
168668
|
-
|
|
168669
|
-
|
|
168670
|
-
|
|
168671
|
-
|
|
168672
|
-
|
|
168673
|
-
|
|
168674
|
-
|
|
168675
|
-
|
|
168676
|
-
|
|
168677
|
-
|
|
168678
|
-
}
|
|
168679
|
-
|
|
168680
|
-
|
|
168681
|
-
|
|
168682
|
-
|
|
168683
|
-
|
|
168684
|
-
|
|
168685
|
-
|
|
168686
|
-
|
|
168687
|
-
|
|
168688
|
-
deleteAfterRun: opts.deleteAfterRun ?? false
|
|
168689
|
-
};
|
|
168690
|
-
this.store.jobs.push(job);
|
|
168691
|
-
this.saveStore();
|
|
168692
|
-
this.armTimer();
|
|
168693
|
-
return job;
|
|
168694
|
-
}
|
|
168695
|
-
removeJob(jobId) {
|
|
168696
|
-
this.loadStore();
|
|
168697
|
-
const idx = this.store.jobs.findIndex((j9) => j9.id === jobId);
|
|
168698
|
-
if (idx === -1)
|
|
168699
|
-
return false;
|
|
168700
|
-
this.store.jobs.splice(idx, 1);
|
|
168701
|
-
this.saveStore();
|
|
168702
|
-
this.armTimer();
|
|
168703
|
-
return true;
|
|
168704
|
-
}
|
|
168705
|
-
enableJob(jobId, enabled) {
|
|
168706
|
-
this.loadStore();
|
|
168707
|
-
const job = this.store.jobs.find((j9) => j9.id === jobId);
|
|
168708
|
-
if (!job)
|
|
168709
|
-
return;
|
|
168710
|
-
job.enabled = enabled;
|
|
168711
|
-
if (enabled) {
|
|
168712
|
-
job.state.nextRunAtMs = computeNextRun(job.schedule, Date.now());
|
|
168713
|
-
} else {
|
|
168714
|
-
job.state.nextRunAtMs = null;
|
|
168853
|
+
addJob(opts) {
|
|
168854
|
+
const now = Date.now();
|
|
168855
|
+
const id = crypto.randomUUID().slice(0, 12);
|
|
168856
|
+
const sb = scheduleBindings(opts.schedule);
|
|
168857
|
+
try {
|
|
168858
|
+
this.stmts.insert.run({
|
|
168859
|
+
$id: id,
|
|
168860
|
+
$name: opts.name,
|
|
168861
|
+
$enabled: 1,
|
|
168862
|
+
...Object.fromEntries(Object.entries(sb).map(([k, v4]) => [`$${k}`, v4])),
|
|
168863
|
+
$payload_kind: "agent_turn",
|
|
168864
|
+
$payload_message: opts.message,
|
|
168865
|
+
$payload_deliver: opts.deliver ?? true ? 1 : 0,
|
|
168866
|
+
$payload_channel: opts.channel ?? null,
|
|
168867
|
+
$payload_to: opts.to ?? null,
|
|
168868
|
+
$next_run_at_ms: computeNextRun(opts.schedule, now),
|
|
168869
|
+
$created_at_ms: now,
|
|
168870
|
+
$updated_at_ms: now,
|
|
168871
|
+
$delete_after_run: opts.deleteAfterRun ?? false ? 1 : 0
|
|
168872
|
+
});
|
|
168873
|
+
} catch (err) {
|
|
168874
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
168875
|
+
if (msg.includes("UNIQUE constraint failed") || msg.includes("SQLITE_CONSTRAINT")) {
|
|
168876
|
+
throw new Error(`Cron name already exists: ${opts.name}`);
|
|
168877
|
+
}
|
|
168878
|
+
throw err;
|
|
168879
|
+
}
|
|
168880
|
+
this.scheduleNextTick();
|
|
168881
|
+
const row = this.stmts.selectById.get(id);
|
|
168882
|
+
return rowToJob(row);
|
|
168715
168883
|
}
|
|
168716
|
-
|
|
168717
|
-
|
|
168718
|
-
|
|
168719
|
-
|
|
168720
|
-
|
|
168721
|
-
|
|
168722
|
-
|
|
168723
|
-
|
|
168724
|
-
|
|
168725
|
-
|
|
168726
|
-
|
|
168727
|
-
|
|
168728
|
-
|
|
168729
|
-
|
|
168730
|
-
|
|
168731
|
-
|
|
168732
|
-
|
|
168733
|
-
|
|
168734
|
-
|
|
168735
|
-
|
|
168736
|
-
|
|
168737
|
-
|
|
168738
|
-
enabled
|
|
168739
|
-
|
|
168740
|
-
|
|
168741
|
-
}
|
|
168742
|
-
|
|
168743
|
-
|
|
168744
|
-
|
|
168745
|
-
|
|
168746
|
-
|
|
168747
|
-
|
|
168748
|
-
|
|
168749
|
-
|
|
168750
|
-
|
|
168751
|
-
|
|
168752
|
-
|
|
168753
|
-
enabled: true,
|
|
168754
|
-
schedule: spec.schedule,
|
|
168755
|
-
payload: {
|
|
168756
|
-
kind: "agent_turn",
|
|
168757
|
-
message: spec.message,
|
|
168758
|
-
deliver: spec.deliver
|
|
168759
|
-
},
|
|
168760
|
-
state: {
|
|
168761
|
-
nextRunAtMs: computeNextRun(spec.schedule, now),
|
|
168762
|
-
lastRunAtMs: null,
|
|
168763
|
-
lastStatus: null,
|
|
168764
|
-
lastError: null,
|
|
168765
|
-
runHistory: []
|
|
168766
|
-
},
|
|
168767
|
-
createdAtMs: now,
|
|
168768
|
-
updatedAtMs: now,
|
|
168769
|
-
deleteAfterRun: false
|
|
168884
|
+
removeJob(jobId) {
|
|
168885
|
+
const row = this.stmts.selectById.get(jobId);
|
|
168886
|
+
if (!row)
|
|
168887
|
+
return false;
|
|
168888
|
+
this.stmts.delete.run(jobId);
|
|
168889
|
+
this.scheduleNextTick();
|
|
168890
|
+
return true;
|
|
168891
|
+
}
|
|
168892
|
+
enableJob(jobId, enabled) {
|
|
168893
|
+
const now = Date.now();
|
|
168894
|
+
const row = this.stmts.selectById.get(jobId);
|
|
168895
|
+
if (!row)
|
|
168896
|
+
return;
|
|
168897
|
+
const nextRun = enabled ? computeNextRun(scheduleFromRow(row), now) : null;
|
|
168898
|
+
this.stmts.updateEnabled.run(enabled ? 1 : 0, nextRun, now, jobId);
|
|
168899
|
+
this.scheduleNextTick();
|
|
168900
|
+
}
|
|
168901
|
+
async runJob(jobId, force = false) {
|
|
168902
|
+
const row = this.stmts.selectById.get(jobId);
|
|
168903
|
+
if (!row)
|
|
168904
|
+
return;
|
|
168905
|
+
const job = rowToJob(row);
|
|
168906
|
+
if (!job.enabled && !force)
|
|
168907
|
+
return;
|
|
168908
|
+
await this.executeJob(job);
|
|
168909
|
+
}
|
|
168910
|
+
getJob(jobId) {
|
|
168911
|
+
const row = this.stmts.selectById.get(jobId);
|
|
168912
|
+
return row ? rowToJob(row) : undefined;
|
|
168913
|
+
}
|
|
168914
|
+
status() {
|
|
168915
|
+
const rows = this.stmts.selectAll.all();
|
|
168916
|
+
const enabled = rows.filter((r2) => r2.enabled === 1);
|
|
168917
|
+
return {
|
|
168918
|
+
enabled: this._running,
|
|
168919
|
+
jobs: enabled.length,
|
|
168920
|
+
nextTickAtMs: this.getNextTickMs()
|
|
168770
168921
|
};
|
|
168771
|
-
this.store.jobs.push(job);
|
|
168772
|
-
dirty = true;
|
|
168773
168922
|
}
|
|
168774
|
-
|
|
168775
|
-
|
|
168776
|
-
|
|
168777
|
-
|
|
168778
|
-
|
|
168779
|
-
|
|
168780
|
-
|
|
168781
|
-
|
|
168782
|
-
|
|
168783
|
-
|
|
168923
|
+
updateBuiltinJobsTimezone(tz) {
|
|
168924
|
+
const updated = [];
|
|
168925
|
+
const now = Date.now();
|
|
168926
|
+
this.db.transaction(() => {
|
|
168927
|
+
for (const name of CronService.DEFAULT_JOB_NAMES) {
|
|
168928
|
+
const row = this.stmts.selectByName.get(name);
|
|
168929
|
+
if (!row || row.schedule_kind !== "cron")
|
|
168930
|
+
continue;
|
|
168931
|
+
const nextRun = computeNextRun({ kind: "cron", expr: row.schedule_expr ?? undefined, tz }, now);
|
|
168932
|
+
this.stmts.updateTzAndNext.run(tz, nextRun, now, name);
|
|
168933
|
+
updated.push(name);
|
|
168934
|
+
}
|
|
168935
|
+
})();
|
|
168936
|
+
this.scheduleNextTick();
|
|
168937
|
+
return updated;
|
|
168938
|
+
}
|
|
168939
|
+
seedDefaultJobs(specs) {
|
|
168940
|
+
const now = Date.now();
|
|
168941
|
+
this.db.transaction(() => {
|
|
168942
|
+
for (const spec of specs) {
|
|
168943
|
+
const existing = this.stmts.selectByName.get(spec.name);
|
|
168944
|
+
if (existing)
|
|
168945
|
+
continue;
|
|
168946
|
+
const id = crypto.randomUUID().slice(0, 12);
|
|
168947
|
+
const sb = scheduleBindings(spec.schedule);
|
|
168948
|
+
this.stmts.insert.run({
|
|
168949
|
+
$id: id,
|
|
168950
|
+
$name: spec.name,
|
|
168951
|
+
$enabled: 1,
|
|
168952
|
+
...Object.fromEntries(Object.entries(sb).map(([k, v4]) => [`$${k}`, v4])),
|
|
168953
|
+
$payload_kind: "agent_turn",
|
|
168954
|
+
$payload_message: spec.message,
|
|
168955
|
+
$payload_deliver: spec.deliver ? 1 : 0,
|
|
168956
|
+
$payload_channel: null,
|
|
168957
|
+
$payload_to: null,
|
|
168958
|
+
$next_run_at_ms: computeNextRun(spec.schedule, now),
|
|
168959
|
+
$created_at_ms: now,
|
|
168960
|
+
$updated_at_ms: now,
|
|
168961
|
+
$delete_after_run: 0
|
|
168962
|
+
});
|
|
168963
|
+
}
|
|
168964
|
+
})();
|
|
168965
|
+
}
|
|
168966
|
+
async executeJob(job) {
|
|
168967
|
+
const startMs = Date.now();
|
|
168968
|
+
let status = "ok";
|
|
168969
|
+
let error45;
|
|
168970
|
+
try {
|
|
168971
|
+
if (this.onJob) {
|
|
168972
|
+
await this.onJob(job);
|
|
168973
|
+
}
|
|
168974
|
+
} catch (err) {
|
|
168975
|
+
status = "error";
|
|
168976
|
+
error45 = err instanceof Error ? err.message : String(err);
|
|
168977
|
+
}
|
|
168978
|
+
const durationMs = Date.now() - startMs;
|
|
168979
|
+
const record6 = { runAtMs: startMs, status, durationMs, error: error45 };
|
|
168980
|
+
const currentRow = this.stmts.selectById.get(job.id);
|
|
168981
|
+
let runHistory = [];
|
|
168982
|
+
if (currentRow) {
|
|
168983
|
+
try {
|
|
168984
|
+
runHistory = JSON.parse(currentRow.run_history);
|
|
168985
|
+
} catch {}
|
|
168784
168986
|
}
|
|
168785
|
-
|
|
168786
|
-
|
|
168787
|
-
|
|
168788
|
-
}
|
|
168789
|
-
const durationMs = Date.now() - startMs;
|
|
168790
|
-
const record6 = { runAtMs: startMs, status, durationMs, error: error45 };
|
|
168791
|
-
job.state.lastRunAtMs = startMs;
|
|
168792
|
-
job.state.lastStatus = status;
|
|
168793
|
-
job.state.lastError = error45 ?? null;
|
|
168794
|
-
job.state.runHistory.push(record6);
|
|
168795
|
-
if (job.state.runHistory.length > MAX_HISTORY) {
|
|
168796
|
-
job.state.runHistory = job.state.runHistory.slice(-MAX_HISTORY);
|
|
168797
|
-
}
|
|
168798
|
-
if (job.schedule.kind === "at") {
|
|
168799
|
-
if (job.deleteAfterRun) {
|
|
168800
|
-
const idx = this.store.jobs.indexOf(job);
|
|
168801
|
-
if (idx >= 0)
|
|
168802
|
-
this.store.jobs.splice(idx, 1);
|
|
168803
|
-
} else {
|
|
168804
|
-
job.enabled = false;
|
|
168805
|
-
job.state.nextRunAtMs = null;
|
|
168987
|
+
runHistory.push(record6);
|
|
168988
|
+
if (runHistory.length > MAX_HISTORY) {
|
|
168989
|
+
runHistory = runHistory.slice(-MAX_HISTORY);
|
|
168806
168990
|
}
|
|
168807
|
-
|
|
168808
|
-
|
|
168991
|
+
let nextRunAtMs;
|
|
168992
|
+
let enabled = 1;
|
|
168993
|
+
if (job.schedule.kind === "at") {
|
|
168994
|
+
if (job.deleteAfterRun) {
|
|
168995
|
+
this.stmts.delete.run(job.id);
|
|
168996
|
+
this.scheduleNextTick();
|
|
168997
|
+
return;
|
|
168998
|
+
}
|
|
168999
|
+
enabled = 0;
|
|
169000
|
+
nextRunAtMs = null;
|
|
169001
|
+
} else {
|
|
169002
|
+
const freshSchedule = currentRow ? scheduleFromRow(currentRow) : job.schedule;
|
|
169003
|
+
nextRunAtMs = computeNextRun(freshSchedule, Date.now());
|
|
169004
|
+
}
|
|
169005
|
+
this.db.transaction(() => {
|
|
169006
|
+
this.stmts.updateFull.run({
|
|
169007
|
+
$last_run_at_ms: startMs,
|
|
169008
|
+
$last_status: status,
|
|
169009
|
+
$last_error: error45 ?? null,
|
|
169010
|
+
$next_run_at_ms: nextRunAtMs,
|
|
169011
|
+
$run_history: JSON.stringify(runHistory),
|
|
169012
|
+
$enabled: enabled,
|
|
169013
|
+
$updated_at_ms: Date.now(),
|
|
169014
|
+
$id: job.id
|
|
169015
|
+
});
|
|
169016
|
+
})();
|
|
169017
|
+
this.scheduleNextTick();
|
|
168809
169018
|
}
|
|
168810
|
-
|
|
168811
|
-
|
|
168812
|
-
|
|
168813
|
-
|
|
168814
|
-
|
|
168815
|
-
|
|
168816
|
-
|
|
168817
|
-
|
|
169019
|
+
getNextTickMs() {
|
|
169020
|
+
const rows = this.stmts.selectAll.all();
|
|
169021
|
+
let earliest = null;
|
|
169022
|
+
for (const row of rows) {
|
|
169023
|
+
if (row.enabled === 1 && row.next_run_at_ms !== null) {
|
|
169024
|
+
if (earliest === null || row.next_run_at_ms < earliest) {
|
|
169025
|
+
earliest = row.next_run_at_ms;
|
|
169026
|
+
}
|
|
168818
169027
|
}
|
|
168819
169028
|
}
|
|
169029
|
+
return earliest;
|
|
168820
169030
|
}
|
|
168821
|
-
|
|
168822
|
-
|
|
168823
|
-
|
|
168824
|
-
|
|
168825
|
-
|
|
168826
|
-
this.
|
|
168827
|
-
|
|
168828
|
-
|
|
168829
|
-
|
|
168830
|
-
|
|
168831
|
-
|
|
168832
|
-
|
|
168833
|
-
const delayMs = Math.max(nextMs - Date.now(), 0);
|
|
168834
|
-
this.timerHandle = setTimeout(() => this.onTimer(), delayMs);
|
|
168835
|
-
}
|
|
168836
|
-
async onTimer() {
|
|
168837
|
-
if (!this._running)
|
|
168838
|
-
return;
|
|
168839
|
-
this.loadStore();
|
|
168840
|
-
const now = Date.now();
|
|
168841
|
-
const due = this.store.jobs.filter((j9) => j9.enabled && j9.state.nextRunAtMs !== null && j9.state.nextRunAtMs <= now);
|
|
168842
|
-
for (const job of due) {
|
|
168843
|
-
await this.executeJob(job);
|
|
169031
|
+
scheduleNextTick() {
|
|
169032
|
+
if (this.timerHandle) {
|
|
169033
|
+
clearTimeout(this.timerHandle);
|
|
169034
|
+
this.timerHandle = null;
|
|
169035
|
+
}
|
|
169036
|
+
if (!this._running)
|
|
169037
|
+
return;
|
|
169038
|
+
const nextMs = this.getNextTickMs();
|
|
169039
|
+
if (nextMs === null)
|
|
169040
|
+
return;
|
|
169041
|
+
const delayMs = Math.max(nextMs - Date.now(), 0);
|
|
169042
|
+
this.timerHandle = setTimeout(() => void this.onTimer(), delayMs);
|
|
168844
169043
|
}
|
|
168845
|
-
|
|
168846
|
-
|
|
168847
|
-
}
|
|
168848
|
-
loadStore() {
|
|
168849
|
-
if (!existsSync17(this.storePath))
|
|
168850
|
-
return;
|
|
168851
|
-
try {
|
|
168852
|
-
const stat2 = statSync4(this.storePath);
|
|
168853
|
-
const mtime = stat2.mtimeMs;
|
|
168854
|
-
if (mtime === this.lastMtime && this.store.jobs.length > 0)
|
|
169044
|
+
async onTimer() {
|
|
169045
|
+
if (!this._running)
|
|
168855
169046
|
return;
|
|
168856
|
-
const
|
|
168857
|
-
const
|
|
168858
|
-
|
|
168859
|
-
|
|
168860
|
-
|
|
168861
|
-
|
|
168862
|
-
|
|
168863
|
-
|
|
168864
|
-
|
|
168865
|
-
try {
|
|
168866
|
-
this.lastMtime = statSync4(this.storePath).mtimeMs;
|
|
168867
|
-
} catch {}
|
|
168868
|
-
}
|
|
168869
|
-
}
|
|
168870
|
-
var import_cron_parser, MAX_HISTORY = 20, MIN_INTERVAL_MS = 1e4;
|
|
168871
|
-
var init_service = __esm(() => {
|
|
168872
|
-
init_defaults();
|
|
168873
|
-
import_cron_parser = __toESM(require_dist5(), 1);
|
|
169047
|
+
const now = Date.now();
|
|
169048
|
+
const rows = this.stmts.selectAll.all();
|
|
169049
|
+
const due = rows.filter((r2) => r2.enabled === 1 && r2.next_run_at_ms !== null && r2.next_run_at_ms <= now);
|
|
169050
|
+
for (const row of due) {
|
|
169051
|
+
await this.executeJob(rowToJob(row));
|
|
169052
|
+
}
|
|
169053
|
+
this.scheduleNextTick();
|
|
169054
|
+
}
|
|
169055
|
+
};
|
|
168874
169056
|
});
|
|
168875
169057
|
|
|
168876
169058
|
// src/bus/queue.ts
|
|
@@ -169564,6 +169746,9 @@ class ApprovalManager {
|
|
|
169564
169746
|
getReason(approvalId) {
|
|
169565
169747
|
return this.pending.get(approvalId)?.reason ?? null;
|
|
169566
169748
|
}
|
|
169749
|
+
getPreview(approvalId) {
|
|
169750
|
+
return this.pending.get(approvalId)?.preview;
|
|
169751
|
+
}
|
|
169567
169752
|
getPending(sessionKey) {
|
|
169568
169753
|
const id = this.bySession.get(sessionKey);
|
|
169569
169754
|
if (!id)
|
|
@@ -169897,7 +170082,7 @@ var init_approval_events = __esm(() => {
|
|
|
169897
170082
|
});
|
|
169898
170083
|
|
|
169899
170084
|
// src/services/trading-confirm.ts
|
|
169900
|
-
function buildPreview(title, body) {
|
|
170085
|
+
function buildPreview(title, body, extras) {
|
|
169901
170086
|
const lines = (body.lines ?? []).filter((l2) => l2 !== undefined && l2 !== null);
|
|
169902
170087
|
const steps = (body.steps ?? []).filter((s2) => s2 !== undefined && s2 !== null);
|
|
169903
170088
|
const details = {};
|
|
@@ -169923,7 +170108,10 @@ function buildPreview(title, body) {
|
|
|
169923
170108
|
summary,
|
|
169924
170109
|
details,
|
|
169925
170110
|
warnings: warnings.length > 0 ? warnings : undefined,
|
|
169926
|
-
|
|
170111
|
+
symbol: extras?.symbol,
|
|
170112
|
+
direction: blob.includes("buy") || blob.includes("long") ? "long" : blob.includes("sell") || blob.includes("short") ? "short" : undefined,
|
|
170113
|
+
wizard: extras?.wizard,
|
|
170114
|
+
suggestedValue: extras?.suggestedValue
|
|
169927
170115
|
};
|
|
169928
170116
|
}
|
|
169929
170117
|
|
|
@@ -169936,8 +170124,8 @@ class DaemonConfirmService {
|
|
|
169936
170124
|
this.eventBus = eventBus;
|
|
169937
170125
|
this.orchestrator = orchestrator;
|
|
169938
170126
|
}
|
|
169939
|
-
async confirm(title, body) {
|
|
169940
|
-
const preview = buildPreview(title, body);
|
|
170127
|
+
async confirm(title, body, extras) {
|
|
170128
|
+
const preview = buildPreview(title, body, extras);
|
|
169941
170129
|
const sessionKey = `trade:${crypto.randomUUID().slice(0, 8)}`;
|
|
169942
170130
|
const preText = this.orchestrator.getCurrentTurnText();
|
|
169943
170131
|
const origin = this.orchestrator.getCurrentTurnOrigin();
|
|
@@ -180846,7 +181034,7 @@ class HyperliquidClient {
|
|
|
180846
181034
|
assetMap = new Map;
|
|
180847
181035
|
szDecimals = new Map;
|
|
180848
181036
|
maxLeverage = new Map;
|
|
180849
|
-
|
|
181037
|
+
assets = [];
|
|
180850
181038
|
metaLoaded = false;
|
|
180851
181039
|
metaInFlight = null;
|
|
180852
181040
|
dexUniverses = new Map;
|
|
@@ -180984,7 +181172,7 @@ class HyperliquidClient {
|
|
|
180984
181172
|
this.log.warn({ err: result.reason, dex: dexes[i].name }, "HIP-3 dex meta fetch failed \u2014 skipping");
|
|
180985
181173
|
}
|
|
180986
181174
|
}
|
|
180987
|
-
this.
|
|
181175
|
+
this.assets = merged.map((a) => a.isDelisted ? { symbol: a.name, isDelisted: true } : { symbol: a.name });
|
|
180988
181176
|
merged.forEach((a, idx) => {
|
|
180989
181177
|
const key = this.resolveSymbol(a.name);
|
|
180990
181178
|
this.assetMap.set(key, idx);
|
|
@@ -181000,7 +181188,10 @@ class HyperliquidClient {
|
|
|
181000
181188
|
return this.maxLeverage.get(this.resolveSymbol(symbol5));
|
|
181001
181189
|
}
|
|
181002
181190
|
getAllAssetNames() {
|
|
181003
|
-
return
|
|
181191
|
+
return this.assets.map((a) => a.symbol);
|
|
181192
|
+
}
|
|
181193
|
+
getAllAssets() {
|
|
181194
|
+
return this.assets;
|
|
181004
181195
|
}
|
|
181005
181196
|
isKnownSymbol(symbol5) {
|
|
181006
181197
|
return this.assetMap.has(this.resolveSymbol(symbol5));
|
|
@@ -181253,12 +181444,16 @@ class HyperliquidClient {
|
|
|
181253
181444
|
const decimals = this.szDecimals.get(resolved) ?? 0;
|
|
181254
181445
|
return size2.toFixed(decimals);
|
|
181255
181446
|
}
|
|
181256
|
-
formatPrice(price) {
|
|
181257
|
-
|
|
181447
|
+
formatPrice(symbol5, price) {
|
|
181448
|
+
const resolved = this.resolveSymbol(symbol5);
|
|
181449
|
+
const szDecimals = this.szDecimals.get(resolved) ?? 0;
|
|
181450
|
+
const maxDecimals = Math.max(0, 6 - szDecimals);
|
|
181451
|
+
const trimmed = parseFloat(price.toPrecision(5));
|
|
181452
|
+
return parseFloat(trimmed.toFixed(maxDecimals)).toString();
|
|
181258
181453
|
}
|
|
181259
|
-
slippagePrice(midPrice, isBuy, slippagePct) {
|
|
181454
|
+
slippagePrice(symbol5, midPrice, isBuy, slippagePct) {
|
|
181260
181455
|
const factor = isBuy ? 1 + slippagePct / 100 : 1 - slippagePct / 100;
|
|
181261
|
-
return this.formatPrice(midPrice * factor);
|
|
181456
|
+
return this.formatPrice(symbol5, midPrice * factor);
|
|
181262
181457
|
}
|
|
181263
181458
|
async placeOrder(params) {
|
|
181264
181459
|
const ex = this.requireExchange();
|
|
@@ -181274,42 +181469,42 @@ class HyperliquidClient {
|
|
|
181274
181469
|
switch (params.orderType) {
|
|
181275
181470
|
case "market": {
|
|
181276
181471
|
const ticker = await this.getTicker(params.symbol);
|
|
181277
|
-
price = this.slippagePrice(ticker.midPrice, isBuy, params.slippagePct ?? 0.5);
|
|
181472
|
+
price = this.slippagePrice(params.symbol, ticker.midPrice, isBuy, params.slippagePct ?? 0.5);
|
|
181278
181473
|
orderType = { limit: { tif: "Ioc" } };
|
|
181279
181474
|
break;
|
|
181280
181475
|
}
|
|
181281
181476
|
case "limit": {
|
|
181282
181477
|
if (!params.price)
|
|
181283
181478
|
throw new Error("Limit order requires price");
|
|
181284
|
-
price = this.formatPrice(params.price);
|
|
181479
|
+
price = this.formatPrice(params.symbol, params.price);
|
|
181285
181480
|
orderType = { limit: { tif: params.tif ?? "Gtc" } };
|
|
181286
181481
|
break;
|
|
181287
181482
|
}
|
|
181288
181483
|
case "stop_market": {
|
|
181289
181484
|
if (!params.price)
|
|
181290
181485
|
throw new Error("Stop market order requires trigger price");
|
|
181291
|
-
price = this.formatPrice(params.price);
|
|
181486
|
+
price = this.formatPrice(params.symbol, params.price);
|
|
181292
181487
|
orderType = { trigger: { isMarket: true, triggerPx: price, tpsl: "sl" } };
|
|
181293
181488
|
break;
|
|
181294
181489
|
}
|
|
181295
181490
|
case "stop_limit": {
|
|
181296
181491
|
if (!params.price)
|
|
181297
181492
|
throw new Error("Stop limit order requires trigger price");
|
|
181298
|
-
price = this.formatPrice(params.price);
|
|
181493
|
+
price = this.formatPrice(params.symbol, params.price);
|
|
181299
181494
|
orderType = { trigger: { isMarket: false, triggerPx: price, tpsl: "sl" } };
|
|
181300
181495
|
break;
|
|
181301
181496
|
}
|
|
181302
181497
|
case "take_profit": {
|
|
181303
181498
|
if (!params.price)
|
|
181304
181499
|
throw new Error("Take profit order requires trigger price");
|
|
181305
|
-
price = this.formatPrice(params.price);
|
|
181500
|
+
price = this.formatPrice(params.symbol, params.price);
|
|
181306
181501
|
orderType = { trigger: { isMarket: true, triggerPx: price, tpsl: "tp" } };
|
|
181307
181502
|
break;
|
|
181308
181503
|
}
|
|
181309
181504
|
case "take_profit_limit": {
|
|
181310
181505
|
if (!params.price)
|
|
181311
181506
|
throw new Error("Take profit limit order requires price");
|
|
181312
|
-
price = this.formatPrice(params.price);
|
|
181507
|
+
price = this.formatPrice(params.symbol, params.price);
|
|
181313
181508
|
orderType = { trigger: { isMarket: false, triggerPx: price, tpsl: "tp" } };
|
|
181314
181509
|
break;
|
|
181315
181510
|
}
|
|
@@ -182043,6 +182238,9 @@ class PaperTradingClient {
|
|
|
182043
182238
|
isKnownSymbol(symbol5) {
|
|
182044
182239
|
return this.marketClient.isKnownSymbol(symbol5);
|
|
182045
182240
|
}
|
|
182241
|
+
getAllAssets() {
|
|
182242
|
+
return this.marketClient.getAllAssets();
|
|
182243
|
+
}
|
|
182046
182244
|
getDexUniverses() {
|
|
182047
182245
|
return this.marketClient.getDexUniverses();
|
|
182048
182246
|
}
|
|
@@ -182386,7 +182584,7 @@ var init_alert_rules = __esm(() => {
|
|
|
182386
182584
|
|
|
182387
182585
|
// src/services/notifications.ts
|
|
182388
182586
|
function isKind(raw) {
|
|
182389
|
-
return raw === "price_target" || raw === "liquidation_risk" || raw === "position_closed" || raw === "tp_hit" || raw === "sl_hit" || raw === "order_filled" || raw === "order_canceled" || raw === "proactive";
|
|
182587
|
+
return raw === "price_target" || raw === "liquidation_risk" || raw === "position_closed" || raw === "tp_hit" || raw === "sl_hit" || raw === "order_filled" || raw === "order_canceled" || raw === "news" || raw === "proactive";
|
|
182390
182588
|
}
|
|
182391
182589
|
function rowToNotification(r2) {
|
|
182392
182590
|
let payload;
|
|
@@ -183057,6 +183255,23 @@ class NewsService {
|
|
|
183057
183255
|
];
|
|
183058
183256
|
return this.db.prepare(sql).all(...params).map((r2) => mapRow(r2));
|
|
183059
183257
|
}
|
|
183258
|
+
listRecentRelevant(sinceTs, limit2 = 20) {
|
|
183259
|
+
const sql = `
|
|
183260
|
+
SELECT id, source_id, external_id, url, title, snippet, image_url, coins,
|
|
183261
|
+
importance, published_at, fetched_at, expires_at, full_summary,
|
|
183262
|
+
ai_relevant, ai_duplicate_of
|
|
183263
|
+
FROM articles
|
|
183264
|
+
WHERE ai_relevant = 1
|
|
183265
|
+
AND full_summary IS NOT NULL
|
|
183266
|
+
AND ai_duplicate_of IS NULL
|
|
183267
|
+
AND dismissed_at IS NULL
|
|
183268
|
+
AND expires_at > unixepoch()
|
|
183269
|
+
AND published_at > ?
|
|
183270
|
+
ORDER BY published_at DESC, id DESC
|
|
183271
|
+
LIMIT ?
|
|
183272
|
+
`;
|
|
183273
|
+
return this.db.prepare(sql).all(sinceTs, limit2).map((r2) => mapRow(r2));
|
|
183274
|
+
}
|
|
183060
183275
|
searchArticles(opts = {}) {
|
|
183061
183276
|
const limit2 = Math.min(opts.limit ?? 50, 100);
|
|
183062
183277
|
const conditions = ["ai_duplicate_of IS NULL"];
|
|
@@ -183792,8 +184007,90 @@ class PreferenceStore {
|
|
|
183792
184007
|
else
|
|
183793
184008
|
this.set(NEWS_FILTER_PROMPT_KEY, prompt);
|
|
183794
184009
|
}
|
|
184010
|
+
getTimezone() {
|
|
184011
|
+
return this.get(USER_TIMEZONE_KEY);
|
|
184012
|
+
}
|
|
184013
|
+
setTimezone(tz) {
|
|
184014
|
+
if (tz.length === 0)
|
|
184015
|
+
this.delete(USER_TIMEZONE_KEY);
|
|
184016
|
+
else
|
|
184017
|
+
this.set(USER_TIMEZONE_KEY, tz);
|
|
184018
|
+
}
|
|
184019
|
+
}
|
|
184020
|
+
var TWEET_FILTER_PROMPT_KEY = "tweets.filter_prompt", NEWS_FILTER_PROMPT_KEY = "news.filter_prompt", USER_TIMEZONE_KEY = "user.timezone";
|
|
184021
|
+
|
|
184022
|
+
// src/scheduler/defaults.ts
|
|
184023
|
+
function detectUserTimezone() {
|
|
184024
|
+
try {
|
|
184025
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
|
|
184026
|
+
} catch {
|
|
184027
|
+
return "UTC";
|
|
184028
|
+
}
|
|
184029
|
+
}
|
|
184030
|
+
function buildBuiltInJobs(tz) {
|
|
184031
|
+
return [
|
|
184032
|
+
{
|
|
184033
|
+
name: "morning-briefing",
|
|
184034
|
+
schedule: { kind: "cron", expr: "0 8 * * *", tz },
|
|
184035
|
+
message: BRIEFING_PROMPT,
|
|
184036
|
+
deliver: true
|
|
184037
|
+
},
|
|
184038
|
+
{
|
|
184039
|
+
name: "evening-recap",
|
|
184040
|
+
schedule: { kind: "cron", expr: "0 21 * * *", tz },
|
|
184041
|
+
message: RECAP_PROMPT,
|
|
184042
|
+
deliver: true
|
|
184043
|
+
}
|
|
184044
|
+
];
|
|
183795
184045
|
}
|
|
183796
|
-
var
|
|
184046
|
+
var BRIEFING_PROMPT, RECAP_PROMPT;
|
|
184047
|
+
var init_defaults = __esm(() => {
|
|
184048
|
+
BRIEFING_PROMPT = "Run the morning briefing. Call tools to fetch the latest data: open " + "positions, recent fills / trade history, watchlist, news, and market " + "signals (funding, whale activity, fear & greed). Summarize in under 15 " + "sentences, in the language the user has been chatting in.";
|
|
184049
|
+
RECAP_PROMPT = "Run the end-of-day recap. Call tools to fetch today's trade history and " + "current open positions. Summarize today's PnL, position changes (opened, " + "closed, scaled), and one notable market note. Brief one-liner if I had no " + "activity. Reply in the language the user has been chatting in.";
|
|
184050
|
+
});
|
|
184051
|
+
|
|
184052
|
+
// src/services/timezone.ts
|
|
184053
|
+
function validateTimezone(input) {
|
|
184054
|
+
if (typeof input !== "string") {
|
|
184055
|
+
return { ok: false, error: "Timezone must be a string" };
|
|
184056
|
+
}
|
|
184057
|
+
const trimmed = input.trim();
|
|
184058
|
+
if (!trimmed) {
|
|
184059
|
+
return { ok: false, error: "Timezone cannot be empty" };
|
|
184060
|
+
}
|
|
184061
|
+
if (trimmed.includes("\x00")) {
|
|
184062
|
+
return { ok: false, error: "Timezone contains invalid characters" };
|
|
184063
|
+
}
|
|
184064
|
+
if (trimmed.length > 64) {
|
|
184065
|
+
return { ok: false, error: "Timezone exceeds maximum length" };
|
|
184066
|
+
}
|
|
184067
|
+
try {
|
|
184068
|
+
const resolved = new Intl.DateTimeFormat(undefined, { timeZone: trimmed }).resolvedOptions().timeZone;
|
|
184069
|
+
return { ok: true, tz: resolved };
|
|
184070
|
+
} catch {
|
|
184071
|
+
return { ok: false, error: "Unknown timezone" };
|
|
184072
|
+
}
|
|
184073
|
+
}
|
|
184074
|
+
function detectHostTimezone() {
|
|
184075
|
+
return detectUserTimezone();
|
|
184076
|
+
}
|
|
184077
|
+
function createTimezoneService(prefs) {
|
|
184078
|
+
return {
|
|
184079
|
+
get() {
|
|
184080
|
+
return prefs.getTimezone() ?? "UTC";
|
|
184081
|
+
},
|
|
184082
|
+
set(input) {
|
|
184083
|
+
const result = validateTimezone(input);
|
|
184084
|
+
if (!result.ok)
|
|
184085
|
+
return result;
|
|
184086
|
+
prefs.setTimezone(result.tz);
|
|
184087
|
+
return result;
|
|
184088
|
+
}
|
|
184089
|
+
};
|
|
184090
|
+
}
|
|
184091
|
+
var init_timezone = __esm(() => {
|
|
184092
|
+
init_defaults();
|
|
184093
|
+
});
|
|
183797
184094
|
|
|
183798
184095
|
// src/services/x-follows.ts
|
|
183799
184096
|
function sleep8(ms2) {
|
|
@@ -188530,7 +188827,7 @@ class Runner {
|
|
|
188530
188827
|
}
|
|
188531
188828
|
async call(opts) {
|
|
188532
188829
|
const next = this.inFlight.then(async () => {
|
|
188533
|
-
const tools = this.registry.
|
|
188830
|
+
const tools = this.registry.taskAgentTools();
|
|
188534
188831
|
this.agent.state.tools = tools;
|
|
188535
188832
|
for (const tool2 of tools) {
|
|
188536
188833
|
if (isOriginAware(tool2))
|
|
@@ -188722,7 +189019,9 @@ function emptySnapshot() {
|
|
|
188722
189019
|
openOrderIds: [],
|
|
188723
189020
|
lastRestSyncAtMs: 0,
|
|
188724
189021
|
recentCancelOids: [],
|
|
188725
|
-
recentEmittedFillIds: []
|
|
189022
|
+
recentEmittedFillIds: [],
|
|
189023
|
+
recentEmittedNewsIds: [],
|
|
189024
|
+
lastNewsScanTs: 0
|
|
188726
189025
|
};
|
|
188727
189026
|
}
|
|
188728
189027
|
|
|
@@ -188747,7 +189046,9 @@ class ObserverStateStore {
|
|
|
188747
189046
|
openOrderIds: Array.isArray(parsed.openOrderIds) ? parsed.openOrderIds : [],
|
|
188748
189047
|
lastRestSyncAtMs: typeof parsed.lastRestSyncAtMs === "number" ? parsed.lastRestSyncAtMs : 0,
|
|
188749
189048
|
recentCancelOids: Array.isArray(parsed.recentCancelOids) ? parsed.recentCancelOids.filter((o10) => typeof o10 === "string") : [],
|
|
188750
|
-
recentEmittedFillIds: Array.isArray(parsed.recentEmittedFillIds) ? parsed.recentEmittedFillIds.filter((o10) => typeof o10 === "string") : []
|
|
189049
|
+
recentEmittedFillIds: Array.isArray(parsed.recentEmittedFillIds) ? parsed.recentEmittedFillIds.filter((o10) => typeof o10 === "string") : [],
|
|
189050
|
+
recentEmittedNewsIds: Array.isArray(parsed.recentEmittedNewsIds) ? parsed.recentEmittedNewsIds.filter((o10) => typeof o10 === "string") : [],
|
|
189051
|
+
lastNewsScanTs: typeof parsed.lastNewsScanTs === "number" ? parsed.lastNewsScanTs : 0
|
|
188751
189052
|
};
|
|
188752
189053
|
} catch {
|
|
188753
189054
|
return emptySnapshot();
|
|
@@ -188760,7 +189061,7 @@ class ObserverStateStore {
|
|
|
188760
189061
|
this.write.run(KEY_SNAPSHOT, JSON.stringify(emptySnapshot()));
|
|
188761
189062
|
}
|
|
188762
189063
|
}
|
|
188763
|
-
var RECENT_CANCEL_OIDS_CAP = 500, RECENT_FILL_IDS_CAP = 500, KEY_SNAPSHOT = "snapshot";
|
|
189064
|
+
var RECENT_CANCEL_OIDS_CAP = 500, RECENT_FILL_IDS_CAP = 500, RECENT_NEWS_IDS_CAP = 200, KEY_SNAPSHOT = "snapshot";
|
|
188764
189065
|
|
|
188765
189066
|
// src/observer/detect/positions.ts
|
|
188766
189067
|
function posKey(symbol5, side) {
|
|
@@ -189048,6 +189349,36 @@ function detectCanceledOrders(input) {
|
|
|
189048
189349
|
return { events, emittedOids };
|
|
189049
189350
|
}
|
|
189050
189351
|
|
|
189352
|
+
// src/observer/detect/news.ts
|
|
189353
|
+
function detectNews(input) {
|
|
189354
|
+
const events = [];
|
|
189355
|
+
const emittedIds = [];
|
|
189356
|
+
const seenThisTick = new Set;
|
|
189357
|
+
for (const article of input.articles) {
|
|
189358
|
+
if (input.priorEmittedIds.has(article.id))
|
|
189359
|
+
continue;
|
|
189360
|
+
if (seenThisTick.has(article.id))
|
|
189361
|
+
continue;
|
|
189362
|
+
if (article.fullSummary === null)
|
|
189363
|
+
continue;
|
|
189364
|
+
events.push({
|
|
189365
|
+
type: "news",
|
|
189366
|
+
detectedAt: input.nowMs,
|
|
189367
|
+
articleId: article.id,
|
|
189368
|
+
title: article.title,
|
|
189369
|
+
summary: article.fullSummary,
|
|
189370
|
+
source: article.sourceId,
|
|
189371
|
+
url: article.url,
|
|
189372
|
+
publishedAt: article.publishedAt * 1000,
|
|
189373
|
+
importance: article.importance,
|
|
189374
|
+
coins: [...article.coins]
|
|
189375
|
+
});
|
|
189376
|
+
emittedIds.push(article.id);
|
|
189377
|
+
seenThisTick.add(article.id);
|
|
189378
|
+
}
|
|
189379
|
+
return { events, emittedIds };
|
|
189380
|
+
}
|
|
189381
|
+
|
|
189051
189382
|
// src/observer/diff.ts
|
|
189052
189383
|
function diffSnapshot(input) {
|
|
189053
189384
|
const positionsR = detectPositions({
|
|
@@ -189079,18 +189410,25 @@ function diffSnapshot(input) {
|
|
|
189079
189410
|
prices: input.prices,
|
|
189080
189411
|
nowMs: input.nowMs
|
|
189081
189412
|
});
|
|
189413
|
+
const newsR = detectNews({
|
|
189414
|
+
articles: input.articles,
|
|
189415
|
+
priorEmittedIds: new Set(input.prior.recentEmittedNewsIds),
|
|
189416
|
+
nowMs: input.nowMs
|
|
189417
|
+
});
|
|
189082
189418
|
return {
|
|
189083
189419
|
events: [
|
|
189084
189420
|
...positionsR.events,
|
|
189085
189421
|
...fillsR.events,
|
|
189086
189422
|
...fallbackEvents,
|
|
189087
189423
|
...cancelR.events,
|
|
189088
|
-
...priceTargetR.events
|
|
189424
|
+
...priceTargetR.events,
|
|
189425
|
+
...newsR.events
|
|
189089
189426
|
],
|
|
189090
189427
|
nextPositions: positionsR.nextPositions,
|
|
189091
189428
|
firedAlertIds: priceTargetR.firedIds,
|
|
189092
189429
|
emittedCancelOids: cancelR.emittedOids,
|
|
189093
|
-
emittedFillIds: fillsR.emittedFillIds
|
|
189430
|
+
emittedFillIds: fillsR.emittedFillIds,
|
|
189431
|
+
emittedNewsIds: newsR.emittedIds
|
|
189094
189432
|
};
|
|
189095
189433
|
}
|
|
189096
189434
|
var init_diff = () => {};
|
|
@@ -189206,7 +189544,8 @@ var init_judge2 = __esm(() => {
|
|
|
189206
189544
|
Type.Literal("order_canceled"),
|
|
189207
189545
|
Type.Literal("liquidation_risk"),
|
|
189208
189546
|
Type.Literal("pnl_snapshot"),
|
|
189209
|
-
Type.Literal("price_alert")
|
|
189547
|
+
Type.Literal("price_alert"),
|
|
189548
|
+
Type.Literal("news")
|
|
189210
189549
|
];
|
|
189211
189550
|
JudgeResponseSchema = Type.Object({
|
|
189212
189551
|
decision: Type.Union([Type.Literal("fire"), Type.Literal("silent")]),
|
|
@@ -194058,6 +194397,7 @@ function stripCustomTags(text) {
|
|
|
194058
194397
|
out = out.replace(/<verdict\s*[^>]*>([\s\S]*?)<\/verdict>/gi, `${SENTINEL_I_OPEN}$1${SENTINEL_I_CLOSE}`);
|
|
194059
194398
|
out = out.replace(/(\n)(\x00I_OPEN\x00(?:\uD83D\uDC02 |\uD83D\uDC3B |\u3030\uFE0F )?)/g, `$1
|
|
194060
194399
|
$2`);
|
|
194400
|
+
out = out.replace(/<ask_user_question\s*>([\s\S]*?)<\/ask_user_question>/gi, (_full, inner) => formatAskFallback(inner));
|
|
194061
194401
|
const chartHint = (attrs) => {
|
|
194062
194402
|
const symMatch = /\bsymbol\s*=\s*"([^"]+)"/i.exec(attrs);
|
|
194063
194403
|
const intMatch = /\binterval\s*=\s*"([^"]+)"/i.exec(attrs);
|
|
@@ -194078,6 +194418,43 @@ $2`);
|
|
|
194078
194418
|
out = out.replace(/<[a-zA-Z][^>]*$/g, "");
|
|
194079
194419
|
return out;
|
|
194080
194420
|
}
|
|
194421
|
+
function formatAskFallback(inner) {
|
|
194422
|
+
const questionRe = /<question>([\s\S]*?)<\/question>/gi;
|
|
194423
|
+
const titleRe = /<title>([\s\S]*?)<\/title>/i;
|
|
194424
|
+
const optionsRe = /<options>([\s\S]*?)<\/options>/i;
|
|
194425
|
+
const optionRe = /<option>([\s\S]*?)<\/option>/gi;
|
|
194426
|
+
const lines = [];
|
|
194427
|
+
let m6;
|
|
194428
|
+
let i = 1;
|
|
194429
|
+
while ((m6 = questionRe.exec(inner)) !== null) {
|
|
194430
|
+
const body = m6[1];
|
|
194431
|
+
const title = titleRe.exec(body)?.[1]?.trim();
|
|
194432
|
+
if (!title)
|
|
194433
|
+
continue;
|
|
194434
|
+
let entry = `${i}. ${title}`;
|
|
194435
|
+
const optionsBlock = optionsRe.exec(body)?.[1];
|
|
194436
|
+
if (optionsBlock) {
|
|
194437
|
+
const opts = [];
|
|
194438
|
+
optionRe.lastIndex = 0;
|
|
194439
|
+
let om2;
|
|
194440
|
+
while ((om2 = optionRe.exec(optionsBlock)) !== null) {
|
|
194441
|
+
const v4 = om2[1].trim();
|
|
194442
|
+
if (v4)
|
|
194443
|
+
opts.push(v4);
|
|
194444
|
+
}
|
|
194445
|
+
if (opts.length > 0)
|
|
194446
|
+
entry += `
|
|
194447
|
+
Options: ${opts.join(" / ")}`;
|
|
194448
|
+
}
|
|
194449
|
+
lines.push(entry);
|
|
194450
|
+
i++;
|
|
194451
|
+
}
|
|
194452
|
+
if (lines.length === 0)
|
|
194453
|
+
return "";
|
|
194454
|
+
return `
|
|
194455
|
+
${lines.join(`
|
|
194456
|
+
`)}`;
|
|
194457
|
+
}
|
|
194081
194458
|
var CHART_RE_PAIRED, CHART_RE_SELF;
|
|
194082
194459
|
var init_tags = __esm(() => {
|
|
194083
194460
|
CHART_RE_PAIRED = /<chart\s*([^>]*)>([\s\S]*?)<\/chart>/gi;
|
|
@@ -195524,6 +195901,7 @@ class ObserverLoop {
|
|
|
195524
195901
|
const currentOpenOrderIds = rest4.openOrders.map((o10) => o10.orderId);
|
|
195525
195902
|
const prices = this.deps.priceCache.snapshot();
|
|
195526
195903
|
const alertRules = this.deps.alertRules.list();
|
|
195904
|
+
const articles = rest4.positions.length === 0 ? [] : this.deps.newsService.listRecentRelevant(newsScanSinceTs(prior.lastNewsScanTs, nowMs));
|
|
195527
195905
|
const diff = diffSnapshot({
|
|
195528
195906
|
prior,
|
|
195529
195907
|
positions: rest4.positions,
|
|
@@ -195533,6 +195911,7 @@ class ObserverLoop {
|
|
|
195533
195911
|
alertRules,
|
|
195534
195912
|
prices,
|
|
195535
195913
|
liqProgressThreshold: this.deps.config.liquidationProgressThreshold,
|
|
195914
|
+
articles,
|
|
195536
195915
|
nowMs
|
|
195537
195916
|
});
|
|
195538
195917
|
for (const id of diff.firedAlertIds) {
|
|
@@ -195565,7 +195944,9 @@ class ObserverLoop {
|
|
|
195565
195944
|
openOrderIds: currentOpenOrderIds,
|
|
195566
195945
|
lastRestSyncAtMs: synced ? nowMs : prior.lastRestSyncAtMs,
|
|
195567
195946
|
recentCancelOids: mergeCancelOids(prior.recentCancelOids, diff.emittedCancelOids),
|
|
195568
|
-
recentEmittedFillIds: mergeBoundedIds(prior.recentEmittedFillIds, diff.emittedFillIds, RECENT_FILL_IDS_CAP)
|
|
195947
|
+
recentEmittedFillIds: mergeBoundedIds(prior.recentEmittedFillIds, diff.emittedFillIds, RECENT_FILL_IDS_CAP),
|
|
195948
|
+
recentEmittedNewsIds: mergeBoundedIds(prior.recentEmittedNewsIds, diff.emittedNewsIds, RECENT_NEWS_IDS_CAP),
|
|
195949
|
+
lastNewsScanTs: maxArticlePublishedAtSec(articles, prior.lastNewsScanTs)
|
|
195569
195950
|
};
|
|
195570
195951
|
const scanCounts = {
|
|
195571
195952
|
positions: rest4.positions.length,
|
|
@@ -195654,6 +196035,7 @@ class ObserverLoop {
|
|
|
195654
196035
|
alertRules: this.deps.alertRules.list(),
|
|
195655
196036
|
prices: this.deps.priceCache.snapshot(),
|
|
195656
196037
|
liqProgressThreshold: this.deps.config.liquidationProgressThreshold,
|
|
196038
|
+
articles: [],
|
|
195657
196039
|
nowMs
|
|
195658
196040
|
});
|
|
195659
196041
|
this.store.save({
|
|
@@ -195662,7 +196044,9 @@ class ObserverLoop {
|
|
|
195662
196044
|
openOrderIds: rest4.openOrders.map((o10) => o10.orderId),
|
|
195663
196045
|
lastRestSyncAtMs: syncDue ? nowMs : prior.lastRestSyncAtMs,
|
|
195664
196046
|
recentCancelOids: mergeCancelOids(prior.recentCancelOids, diff.emittedCancelOids),
|
|
195665
|
-
recentEmittedFillIds: mergeBoundedIds(prior.recentEmittedFillIds, diff.emittedFillIds, RECENT_FILL_IDS_CAP)
|
|
196047
|
+
recentEmittedFillIds: mergeBoundedIds(prior.recentEmittedFillIds, diff.emittedFillIds, RECENT_FILL_IDS_CAP),
|
|
196048
|
+
recentEmittedNewsIds: prior.recentEmittedNewsIds,
|
|
196049
|
+
lastNewsScanTs: prior.lastNewsScanTs
|
|
195666
196050
|
});
|
|
195667
196051
|
} catch (err) {
|
|
195668
196052
|
this.deps.logger.warn({ err }, "observer: baseline refresh failed under confirm gate");
|
|
@@ -195802,11 +196186,25 @@ function mapKindFromEventType(t2) {
|
|
|
195802
196186
|
return "order_canceled";
|
|
195803
196187
|
case "order_filled":
|
|
195804
196188
|
return "order_filled";
|
|
196189
|
+
case "news":
|
|
196190
|
+
return "news";
|
|
195805
196191
|
default:
|
|
195806
196192
|
return "proactive";
|
|
195807
196193
|
}
|
|
195808
196194
|
}
|
|
195809
|
-
|
|
196195
|
+
function newsScanSinceTs(lastScanTs, nowMs) {
|
|
196196
|
+
const slidingFloor = Math.floor(nowMs / 1000) - NEWS_LOOKBACK_FLOOR_SEC;
|
|
196197
|
+
return lastScanTs > slidingFloor ? lastScanTs : slidingFloor;
|
|
196198
|
+
}
|
|
196199
|
+
function maxArticlePublishedAtSec(articles, prior) {
|
|
196200
|
+
let max = prior;
|
|
196201
|
+
for (const a of articles) {
|
|
196202
|
+
if (a.publishedAt > max)
|
|
196203
|
+
max = a.publishedAt;
|
|
196204
|
+
}
|
|
196205
|
+
return max;
|
|
196206
|
+
}
|
|
196207
|
+
var RECENT_CHAT_MAX = 20, MIN_PRICE_PCT_DELTA = 0.5, MIN_COOLDOWN_MS, NEWS_LOOKBACK_FLOOR_SEC;
|
|
195810
196208
|
var init_loop = __esm(() => {
|
|
195811
196209
|
init_diff();
|
|
195812
196210
|
init_judge2();
|
|
@@ -195814,11 +196212,12 @@ var init_loop = __esm(() => {
|
|
|
195814
196212
|
init_channels();
|
|
195815
196213
|
init_types5();
|
|
195816
196214
|
MIN_COOLDOWN_MS = 60 * 60 * 1000;
|
|
196215
|
+
NEWS_LOOKBACK_FLOOR_SEC = 30 * 60;
|
|
195817
196216
|
});
|
|
195818
196217
|
|
|
195819
196218
|
// src/runtime.ts
|
|
195820
196219
|
import { join as join14 } from "path";
|
|
195821
|
-
import { existsSync as
|
|
196220
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync13, copyFileSync as copyFileSync2, readdirSync as readdirSync7 } from "fs";
|
|
195822
196221
|
async function createRuntime(options) {
|
|
195823
196222
|
const configPath = options.configPath ?? getConfigPath();
|
|
195824
196223
|
const rawConfig = loadConfig(configPath);
|
|
@@ -195858,12 +196257,14 @@ async function createRuntime(options) {
|
|
|
195858
196257
|
const skillsLoader = new SkillsLoader(workspaceDir, builtinSkillsDir);
|
|
195859
196258
|
const skillService = new SkillService(db2, skillsLoader);
|
|
195860
196259
|
skillService.syncState();
|
|
195861
|
-
const
|
|
196260
|
+
const preferenceStore = new PreferenceStore(db2, logger.child({ module: "prefs" }));
|
|
196261
|
+
const timezoneService = createTimezoneService(preferenceStore);
|
|
196262
|
+
const contextBuilder = new ContextBuilder({ workspaceDir, model: config3.model, getTimezone: () => timezoneService.get() }, memoryStore, skillsLoader);
|
|
195862
196263
|
contextBuilder.setDisabledSkillsProvider(() => skillService.getDisabledNames());
|
|
195863
|
-
const cronService = new CronService(
|
|
196264
|
+
const cronService = new CronService(db2);
|
|
195864
196265
|
const tools = createToolRegistry(security2, {
|
|
195865
196266
|
cronService,
|
|
195866
|
-
|
|
196267
|
+
timezoneService,
|
|
195867
196268
|
memoryStore,
|
|
195868
196269
|
logger: logger.child({ module: "tool" })
|
|
195869
196270
|
});
|
|
@@ -195874,7 +196275,6 @@ async function createRuntime(options) {
|
|
|
195874
196275
|
const watchlistService = new WatchlistService(db2);
|
|
195875
196276
|
const newsService = new NewsService(db2, watchlistService, credentials2, logger.child({ module: "news" }));
|
|
195876
196277
|
const tweetService = new TweetService(db2, logger.child({ module: "tweets" }));
|
|
195877
|
-
const preferenceStore = new PreferenceStore(db2, logger.child({ module: "prefs" }));
|
|
195878
196278
|
const xQueryIdCache = new XQueryIdCache;
|
|
195879
196279
|
const xFollowService = new XFollowService(db2, credentials2, xQueryIdCache, logger.child({ module: "x-follows" }));
|
|
195880
196280
|
const taIndicators = new TaIndicatorService(tradingClient);
|
|
@@ -195913,7 +196313,7 @@ async function createRuntime(options) {
|
|
|
195913
196313
|
eventBus,
|
|
195914
196314
|
logger,
|
|
195915
196315
|
customModelRegistry,
|
|
195916
|
-
confirmDeps: { getConfirmService: () => confirmServiceRef }
|
|
196316
|
+
confirmDeps: { getConfirmService: () => confirmServiceRef, approvalManager }
|
|
195917
196317
|
});
|
|
195918
196318
|
const taskAgent = createAgent({
|
|
195919
196319
|
config: config3,
|
|
@@ -195930,7 +196330,8 @@ async function createRuntime(options) {
|
|
|
195930
196330
|
logger: logger.child({ module: "task-agent" }),
|
|
195931
196331
|
customModelRegistry,
|
|
195932
196332
|
confirmDeps: { getConfirmService: () => null },
|
|
195933
|
-
bypassConfirm: true
|
|
196333
|
+
bypassConfirm: true,
|
|
196334
|
+
taskMode: true
|
|
195934
196335
|
});
|
|
195935
196336
|
const runner = new Runner(taskAgent, sessionManager, tools, logger.child({ module: "runner" }));
|
|
195936
196337
|
const rssDiscoveryService = new RssDiscoveryService(runner, logger.child({ module: "rss-discovery" }));
|
|
@@ -195997,7 +196398,7 @@ async function createRuntime(options) {
|
|
|
195997
196398
|
tools.register(t2);
|
|
195998
196399
|
contextBuilder.setTools(tools.all().map((t2) => ({ name: t2.name, description: t2.description })));
|
|
195999
196400
|
agent3.state.tools = tools.all();
|
|
196000
|
-
taskAgent.state.tools = tools.
|
|
196401
|
+
taskAgent.state.tools = tools.taskAgentTools();
|
|
196001
196402
|
setupClaudeCliProvider({
|
|
196002
196403
|
config: config3,
|
|
196003
196404
|
logger,
|
|
@@ -196037,6 +196438,7 @@ async function createRuntime(options) {
|
|
|
196037
196438
|
config: config3.observer,
|
|
196038
196439
|
tradingClient,
|
|
196039
196440
|
alertRules,
|
|
196441
|
+
newsService,
|
|
196040
196442
|
notifications,
|
|
196041
196443
|
priceCache,
|
|
196042
196444
|
approvalManager,
|
|
@@ -196082,6 +196484,7 @@ async function createRuntime(options) {
|
|
|
196082
196484
|
rssDiscoveryService,
|
|
196083
196485
|
tweetService,
|
|
196084
196486
|
preferenceStore,
|
|
196487
|
+
timezoneService,
|
|
196085
196488
|
xFollowService,
|
|
196086
196489
|
skillService,
|
|
196087
196490
|
chartSeries,
|
|
@@ -196115,16 +196518,16 @@ function getApiKey(oauthManager, credentials2, customModelRegistry) {
|
|
|
196115
196518
|
};
|
|
196116
196519
|
}
|
|
196117
196520
|
function createAgent(opts) {
|
|
196118
|
-
const initialOptions = buildAgentOptions(opts.config, opts.model, opts.security, opts.leakDetector, opts.oauthManager, opts.tools, opts.systemPrompt, opts.credentials, opts.extraReadDirs, opts.approvalManager, opts.eventBus, opts.logger, opts.customModelRegistry, opts.confirmDeps, opts.bypassConfirm ?? false);
|
|
196521
|
+
const initialOptions = buildAgentOptions(opts.config, opts.model, opts.security, opts.leakDetector, opts.oauthManager, opts.tools, opts.systemPrompt, opts.credentials, opts.extraReadDirs, opts.approvalManager, opts.eventBus, opts.logger, opts.customModelRegistry, opts.confirmDeps, opts.bypassConfirm ?? false, opts.taskMode ?? false);
|
|
196119
196522
|
return new Agent(initialOptions);
|
|
196120
196523
|
}
|
|
196121
|
-
function buildAgentOptions(config3, model, security2, leakDetector, oauthManager, tools, systemPrompt, credentials2, extraReadDirs, approvalManager, eventBus, logger, customModelRegistry, confirmDeps, bypassConfirm = false) {
|
|
196524
|
+
function buildAgentOptions(config3, model, security2, leakDetector, oauthManager, tools, systemPrompt, credentials2, extraReadDirs, approvalManager, eventBus, logger, customModelRegistry, confirmDeps, bypassConfirm = false, taskMode = false) {
|
|
196122
196525
|
const effectiveThinkingLevel = shouldForceThinkingOff({ id: model.id, baseUrl: model.baseUrl ?? "" }) ? "off" : config3.agent.thinkingLevel;
|
|
196123
196526
|
return {
|
|
196124
196527
|
initialState: {
|
|
196125
196528
|
systemPrompt,
|
|
196126
196529
|
model,
|
|
196127
|
-
tools: config3.provider === "claude-cli" ? [] : tools.all(),
|
|
196530
|
+
tools: config3.provider === "claude-cli" ? [] : taskMode ? tools.taskAgentTools() : tools.all(),
|
|
196128
196531
|
thinkingLevel: effectiveThinkingLevel
|
|
196129
196532
|
},
|
|
196130
196533
|
getApiKey: config3.provider === "claude-cli" ? async () => "claude-cli-no-key-needed" : getApiKey(oauthManager, credentials2, customModelRegistry),
|
|
@@ -196213,6 +196616,7 @@ async function runBatchedConfirm(assistantMessage, callName, callArgs, batchCach
|
|
|
196213
196616
|
let title;
|
|
196214
196617
|
const lines = [];
|
|
196215
196618
|
let steps;
|
|
196619
|
+
let extras;
|
|
196216
196620
|
if (isMulti) {
|
|
196217
196621
|
title = `Confirm ${confirmable.length} actions?`;
|
|
196218
196622
|
const stepList = [];
|
|
@@ -196223,14 +196627,22 @@ async function runBatchedConfirm(assistantMessage, callName, callArgs, batchCach
|
|
|
196223
196627
|
stepList.push(`${head}${tail}`);
|
|
196224
196628
|
}
|
|
196225
196629
|
steps = stepList;
|
|
196630
|
+
extras = undefined;
|
|
196226
196631
|
} else {
|
|
196227
196632
|
const only = confirmable[0];
|
|
196633
|
+
const args = only.args ?? {};
|
|
196634
|
+
const symbol5 = typeof args.symbol === "string" ? args.symbol : undefined;
|
|
196228
196635
|
const desc = describeConfirm(only.name, only.args);
|
|
196229
196636
|
title = desc.title;
|
|
196230
196637
|
lines.push(...desc.bullets);
|
|
196638
|
+
extras = {
|
|
196639
|
+
wizard: desc.wizard,
|
|
196640
|
+
suggestedValue: desc.suggestedValue,
|
|
196641
|
+
symbol: symbol5
|
|
196642
|
+
};
|
|
196231
196643
|
}
|
|
196232
196644
|
try {
|
|
196233
|
-
const res = await confirmService.confirm(title, { lines, steps });
|
|
196645
|
+
const res = await confirmService.confirm(title, { lines, steps }, extras);
|
|
196234
196646
|
return { decision: res.decision, reason: res.reason };
|
|
196235
196647
|
} catch (err) {
|
|
196236
196648
|
logger.warn({ err }, "confirm service threw; treating as rejected");
|
|
@@ -196379,19 +196791,19 @@ function makeTransformContext(maxTokens) {
|
|
|
196379
196791
|
}
|
|
196380
196792
|
function resolveDefaultBuiltinSkillsDir() {
|
|
196381
196793
|
const candidate = join14(import.meta.dir, "skills", "builtin");
|
|
196382
|
-
return
|
|
196794
|
+
return existsSync17(candidate) ? candidate : undefined;
|
|
196383
196795
|
}
|
|
196384
196796
|
function seedWorkspaceTemplates(workspaceDir) {
|
|
196385
196797
|
const templatesDir = join14(import.meta.dir, "templates");
|
|
196386
|
-
if (!
|
|
196798
|
+
if (!existsSync17(templatesDir))
|
|
196387
196799
|
return;
|
|
196388
196800
|
try {
|
|
196389
|
-
|
|
196801
|
+
mkdirSync13(workspaceDir, { recursive: true });
|
|
196390
196802
|
for (const entry of readdirSync7(templatesDir, { withFileTypes: true })) {
|
|
196391
196803
|
if (!entry.isFile())
|
|
196392
196804
|
continue;
|
|
196393
196805
|
const target = join14(workspaceDir, entry.name);
|
|
196394
|
-
if (!
|
|
196806
|
+
if (!existsSync17(target))
|
|
196395
196807
|
copyFileSync2(join14(templatesDir, entry.name), target);
|
|
196396
196808
|
}
|
|
196397
196809
|
} catch {}
|
|
@@ -196443,6 +196855,7 @@ var init_runtime2 = __esm(() => {
|
|
|
196443
196855
|
init_news();
|
|
196444
196856
|
init_rss_discovery();
|
|
196445
196857
|
init_tweets();
|
|
196858
|
+
init_timezone();
|
|
196446
196859
|
init_x_follows();
|
|
196447
196860
|
init_x_query_ids();
|
|
196448
196861
|
init_ta_indicators();
|
|
@@ -196626,14 +197039,6 @@ function getProviderList() {
|
|
|
196626
197039
|
});
|
|
196627
197040
|
}
|
|
196628
197041
|
}
|
|
196629
|
-
list.push({
|
|
196630
|
-
id: "claude-cli",
|
|
196631
|
-
label: "Claude Code",
|
|
196632
|
-
description: "Use Claude Code subscription (no API key)",
|
|
196633
|
-
tier: 0,
|
|
196634
|
-
tierLabel: TIER_LABELS[0] ?? "Other",
|
|
196635
|
-
supportsOAuth: false
|
|
196636
|
-
});
|
|
196637
197042
|
list.push({
|
|
196638
197043
|
id: "custom",
|
|
196639
197044
|
label: "Custom",
|
|
@@ -196664,9 +197069,6 @@ function getProviderList() {
|
|
|
196664
197069
|
return list;
|
|
196665
197070
|
}
|
|
196666
197071
|
function getModelList(providerId) {
|
|
196667
|
-
if (providerId === "claude-cli") {
|
|
196668
|
-
return getClaudeCliModels();
|
|
196669
|
-
}
|
|
196670
197072
|
try {
|
|
196671
197073
|
const raw = getModels(providerId).map((m6) => ({ id: m6.id, name: m6.name || m6.id }));
|
|
196672
197074
|
return filterModelCatalog(providerId, raw);
|
|
@@ -196677,7 +197079,6 @@ function getModelList(providerId) {
|
|
|
196677
197079
|
var OAUTH_PROVIDERS2, PROVIDER_META, TIER_LABELS;
|
|
196678
197080
|
var init_providers = __esm(() => {
|
|
196679
197081
|
init_dist();
|
|
196680
|
-
init_models6();
|
|
196681
197082
|
init_model_catalog();
|
|
196682
197083
|
OAUTH_PROVIDERS2 = new Set(["anthropic", "openai-codex", "github-copilot", "google-gemini-cli", "google-antigravity"]);
|
|
196683
197084
|
PROVIDER_META = {
|
|
@@ -196685,7 +197086,6 @@ var init_providers = __esm(() => {
|
|
|
196685
197086
|
anthropic: { label: "Anthropic", description: "Claude Sonnet & Opus (direct)", tier: 0, apiKeyUrl: "https://console.anthropic.com/settings/keys" },
|
|
196686
197087
|
openai: { label: "OpenAI", description: "GPT-4o, GPT-5 (direct)", tier: 0, apiKeyUrl: "https://platform.openai.com/api-keys" },
|
|
196687
197088
|
"openai-codex": { label: "OpenAI Codex", description: "ChatGPT subscription (OAuth, no API key)", tier: 0 },
|
|
196688
|
-
"claude-cli": { label: "Claude Code", description: "Use Claude Code subscription (no API key)", tier: 0 },
|
|
196689
197089
|
google: { label: "Google Gemini", description: "Gemini 2.0 Flash & Pro", tier: 0, apiKeyUrl: "https://aistudio.google.com/app/apikey" },
|
|
196690
197090
|
"google-gemini-cli": { label: "Google Gemini CLI", description: "Gemini via CLI auth", tier: 0 },
|
|
196691
197091
|
xai: { label: "xAI", description: "Grok 3 & 4", tier: 0, apiKeyUrl: "https://console.x.ai" },
|
|
@@ -196722,17 +197122,15 @@ __export(exports_cli_providers, {
|
|
|
196722
197122
|
listModels: () => listModels
|
|
196723
197123
|
});
|
|
196724
197124
|
function requiresApiKey(provider) {
|
|
196725
|
-
|
|
196726
|
-
return false;
|
|
196727
|
-
if (provider.supportsOAuth)
|
|
196728
|
-
return false;
|
|
196729
|
-
return true;
|
|
197125
|
+
return !provider.supportsOAuth;
|
|
196730
197126
|
}
|
|
196731
197127
|
function listProviders() {
|
|
196732
197128
|
const builtIn = getProviderList().map((p) => ({
|
|
196733
197129
|
id: p.id,
|
|
196734
197130
|
label: p.label,
|
|
196735
197131
|
description: p.description,
|
|
197132
|
+
tier: p.tier,
|
|
197133
|
+
tierLabel: p.tierLabel,
|
|
196736
197134
|
requiresApiKey: requiresApiKey(p),
|
|
196737
197135
|
supportsOAuth: p.supportsOAuth,
|
|
196738
197136
|
apiKeyUrl: p.apiKeyUrl ?? null
|
|
@@ -196743,6 +197141,8 @@ function listProviders() {
|
|
|
196743
197141
|
id: name,
|
|
196744
197142
|
label: name,
|
|
196745
197143
|
description: "Custom provider (from ~/.ghost/models.json)",
|
|
197144
|
+
tier: 4,
|
|
197145
|
+
tierLabel: "\uD83D\uDD27 Custom",
|
|
196746
197146
|
requiresApiKey: true,
|
|
196747
197147
|
supportsOAuth: false,
|
|
196748
197148
|
apiKeyUrl: null,
|
|
@@ -198796,11 +199196,11 @@ ${je2}${r2.trimStart()}`), s2 = 3 + ne(r2.trimStart()).length);
|
|
|
198796
199196
|
});
|
|
198797
199197
|
|
|
198798
199198
|
// src/services/os/utils.ts
|
|
198799
|
-
import { accessSync, constants, existsSync as
|
|
199199
|
+
import { accessSync, constants, existsSync as existsSync18, mkdirSync as mkdirSync14, realpathSync as realpathSync2 } from "fs";
|
|
198800
199200
|
import { join as join15 } from "path";
|
|
198801
199201
|
import { homedir as homedir3 } from "os";
|
|
198802
199202
|
function isExecutable(filePath) {
|
|
198803
|
-
if (!
|
|
199203
|
+
if (!existsSync18(filePath))
|
|
198804
199204
|
return false;
|
|
198805
199205
|
try {
|
|
198806
199206
|
accessSync(filePath, constants.X_OK);
|
|
@@ -198847,8 +199247,8 @@ function resolveBunPath() {
|
|
|
198847
199247
|
return candidates[0];
|
|
198848
199248
|
}
|
|
198849
199249
|
function ensureLogDir(dir) {
|
|
198850
|
-
if (!
|
|
198851
|
-
|
|
199250
|
+
if (!existsSync18(dir)) {
|
|
199251
|
+
mkdirSync14(dir, { recursive: true });
|
|
198852
199252
|
}
|
|
198853
199253
|
}
|
|
198854
199254
|
function defaultLogDir() {
|
|
@@ -198914,7 +199314,7 @@ __export(exports_launchd, {
|
|
|
198914
199314
|
LaunchdController: () => LaunchdController
|
|
198915
199315
|
});
|
|
198916
199316
|
import { spawnSync } from "child_process";
|
|
198917
|
-
import { existsSync as
|
|
199317
|
+
import { existsSync as existsSync19, unlinkSync as unlinkSync6, writeFileSync as writeFileSync10, rmSync as rmSync5 } from "fs";
|
|
198918
199318
|
import { join as join16 } from "path";
|
|
198919
199319
|
import { homedir as homedir4 } from "os";
|
|
198920
199320
|
function plistPath() {
|
|
@@ -198964,7 +199364,7 @@ class LaunchdController {
|
|
|
198964
199364
|
stderrLog,
|
|
198965
199365
|
env: opts.env ?? {}
|
|
198966
199366
|
});
|
|
198967
|
-
|
|
199367
|
+
writeFileSync10(definitionPath, plist, { encoding: "utf8", mode: 420 });
|
|
198968
199368
|
const domain2 = guiDomain();
|
|
198969
199369
|
const uid = process.getuid?.() ?? 0;
|
|
198970
199370
|
const serviceTarget = `${domain2}/${LABEL}`;
|
|
@@ -199014,12 +199414,12 @@ class LaunchdController {
|
|
|
199014
199414
|
const domain2 = guiDomain();
|
|
199015
199415
|
const definition = plistPath();
|
|
199016
199416
|
launchctl(["bootout", domain2, definition]);
|
|
199017
|
-
if (
|
|
199417
|
+
if (existsSync19(definition)) {
|
|
199018
199418
|
unlinkSync6(definition);
|
|
199019
199419
|
}
|
|
199020
199420
|
if (opts.purgeLogs) {
|
|
199021
199421
|
const logDir = defaultLogDir();
|
|
199022
|
-
if (
|
|
199422
|
+
if (existsSync19(logDir)) {
|
|
199023
199423
|
rmSync5(logDir, { recursive: true, force: true });
|
|
199024
199424
|
}
|
|
199025
199425
|
}
|
|
@@ -199103,8 +199503,8 @@ __export(exports_systemd, {
|
|
|
199103
199503
|
SystemdController: () => SystemdController
|
|
199104
199504
|
});
|
|
199105
199505
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
199106
|
-
import { copyFileSync as copyFileSync3, existsSync as
|
|
199107
|
-
import { dirname as
|
|
199506
|
+
import { copyFileSync as copyFileSync3, existsSync as existsSync20, mkdirSync as mkdirSync15, rmSync as rmSync6, unlinkSync as unlinkSync7, writeFileSync as writeFileSync11 } from "fs";
|
|
199507
|
+
import { dirname as dirname8, join as join17 } from "path";
|
|
199108
199508
|
import { homedir as homedir5 } from "os";
|
|
199109
199509
|
function unitPath() {
|
|
199110
199510
|
return join17(homedir5(), ".config", "systemd", "user", SERVICE_NAME);
|
|
@@ -199148,11 +199548,11 @@ class SystemdController {
|
|
|
199148
199548
|
assertSystemdAvailable();
|
|
199149
199549
|
ensureLogDir(opts.logDir);
|
|
199150
199550
|
const path4 = unitPath();
|
|
199151
|
-
const dir =
|
|
199152
|
-
if (!
|
|
199153
|
-
|
|
199551
|
+
const dir = dirname8(path4);
|
|
199552
|
+
if (!existsSync20(dir)) {
|
|
199553
|
+
mkdirSync15(dir, { recursive: true });
|
|
199154
199554
|
}
|
|
199155
|
-
if (
|
|
199555
|
+
if (existsSync20(path4)) {
|
|
199156
199556
|
copyFileSync3(path4, `${path4}.bak`);
|
|
199157
199557
|
}
|
|
199158
199558
|
const unit = buildUnit({
|
|
@@ -199165,7 +199565,7 @@ class SystemdController {
|
|
|
199165
199565
|
GHOST_LOG_DIR: opts.logDir
|
|
199166
199566
|
}
|
|
199167
199567
|
});
|
|
199168
|
-
|
|
199568
|
+
writeFileSync11(path4, unit, "utf8");
|
|
199169
199569
|
const reload = systemctlStrict("daemon-reload");
|
|
199170
199570
|
if (!reload.ok) {
|
|
199171
199571
|
const msg = `daemon-reload failed: ${reload.stderr || reload.stdout}`;
|
|
@@ -199211,7 +199611,7 @@ class SystemdController {
|
|
|
199211
199611
|
}
|
|
199212
199612
|
for (const file3 of [path4, `${path4}.bak`]) {
|
|
199213
199613
|
try {
|
|
199214
|
-
if (
|
|
199614
|
+
if (existsSync20(file3)) {
|
|
199215
199615
|
unlinkSync7(file3);
|
|
199216
199616
|
}
|
|
199217
199617
|
} catch {
|
|
@@ -199222,7 +199622,7 @@ class SystemdController {
|
|
|
199222
199622
|
if (opts.purgeLogs) {
|
|
199223
199623
|
const logDir = defaultLogDir();
|
|
199224
199624
|
try {
|
|
199225
|
-
if (
|
|
199625
|
+
if (existsSync20(logDir)) {
|
|
199226
199626
|
rmSync6(logDir, { recursive: true, force: true });
|
|
199227
199627
|
}
|
|
199228
199628
|
} catch {
|
|
@@ -199240,7 +199640,7 @@ class SystemdController {
|
|
|
199240
199640
|
if (stdout === "active") {
|
|
199241
199641
|
return "running";
|
|
199242
199642
|
}
|
|
199243
|
-
if (
|
|
199643
|
+
if (existsSync20(unitPath())) {
|
|
199244
199644
|
return "stopped";
|
|
199245
199645
|
}
|
|
199246
199646
|
return "not-installed";
|
|
@@ -199262,7 +199662,7 @@ __export(exports_schtasks, {
|
|
|
199262
199662
|
});
|
|
199263
199663
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
199264
199664
|
import { Buffer as Buffer2 } from "buffer";
|
|
199265
|
-
import { existsSync as
|
|
199665
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync16, writeFileSync as writeFileSync12, rmSync as rmSync7 } from "fs";
|
|
199266
199666
|
import { join as join18 } from "path";
|
|
199267
199667
|
import { homedir as homedir6, tmpdir } from "os";
|
|
199268
199668
|
function launcherPath() {
|
|
@@ -199404,7 +199804,7 @@ function buildScheduledTaskXml(invisibleVbs, userId) {
|
|
|
199404
199804
|
function writeTaskXml(xml) {
|
|
199405
199805
|
const xmlPath = join18(tmpdir(), `ghost-task-${process.pid}.xml`);
|
|
199406
199806
|
const bom = Buffer2.from([255, 254]);
|
|
199407
|
-
|
|
199807
|
+
writeFileSync12(xmlPath, Buffer2.concat([bom, Buffer2.from(xml, "utf16le")]));
|
|
199408
199808
|
return xmlPath;
|
|
199409
199809
|
}
|
|
199410
199810
|
function killOrphanedSupervisorChain() {
|
|
@@ -199438,17 +199838,17 @@ class SchtasksController {
|
|
|
199438
199838
|
}
|
|
199439
199839
|
ensureLogDir(opts.logDir);
|
|
199440
199840
|
const stateDir = join18(homedir6(), ".ghost", "state");
|
|
199441
|
-
if (!
|
|
199442
|
-
|
|
199841
|
+
if (!existsSync21(stateDir)) {
|
|
199842
|
+
mkdirSync16(stateDir, { recursive: true });
|
|
199443
199843
|
}
|
|
199444
199844
|
const legacy = legacyStartupPath();
|
|
199445
|
-
if (
|
|
199845
|
+
if (existsSync21(legacy)) {
|
|
199446
199846
|
rmSync7(legacy, RM_RETRY_OPTS);
|
|
199447
199847
|
}
|
|
199448
199848
|
const launcher = launcherPath();
|
|
199449
|
-
|
|
199849
|
+
writeFileSync12(launcher, buildLauncherCmd(opts.bunPath, opts.execPath, opts.env), { encoding: "utf8" });
|
|
199450
199850
|
const invisibleVbs = invisibleLauncherPath();
|
|
199451
|
-
|
|
199851
|
+
writeFileSync12(invisibleVbs, buildInvisibleVbs(launcher), { encoding: "utf8" });
|
|
199452
199852
|
const create4 = createScheduledTask(invisibleVbs, taskUser);
|
|
199453
199853
|
if (create4.status !== 0) {
|
|
199454
199854
|
return {
|
|
@@ -199493,20 +199893,20 @@ class SchtasksController {
|
|
|
199493
199893
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
199494
199894
|
schtasks(["/Delete", "/F", "/TN", TASK_NAME]);
|
|
199495
199895
|
const launcher = launcherPath();
|
|
199496
|
-
if (
|
|
199896
|
+
if (existsSync21(launcher)) {
|
|
199497
199897
|
rmSync7(launcher, RM_RETRY_OPTS);
|
|
199498
199898
|
}
|
|
199499
199899
|
const invisibleVbs = invisibleLauncherPath();
|
|
199500
|
-
if (
|
|
199900
|
+
if (existsSync21(invisibleVbs)) {
|
|
199501
199901
|
rmSync7(invisibleVbs, RM_RETRY_OPTS);
|
|
199502
199902
|
}
|
|
199503
199903
|
const legacy = legacyStartupPath();
|
|
199504
|
-
if (
|
|
199904
|
+
if (existsSync21(legacy)) {
|
|
199505
199905
|
rmSync7(legacy, RM_RETRY_OPTS);
|
|
199506
199906
|
}
|
|
199507
199907
|
if (opts.purgeLogs) {
|
|
199508
199908
|
const logDir = defaultLogDir();
|
|
199509
|
-
if (
|
|
199909
|
+
if (existsSync21(logDir)) {
|
|
199510
199910
|
rmSync7(logDir, { recursive: true, ...RM_RETRY_OPTS });
|
|
199511
199911
|
}
|
|
199512
199912
|
}
|
|
@@ -212398,7 +212798,7 @@ function handleHealth() {
|
|
|
212398
212798
|
}
|
|
212399
212799
|
|
|
212400
212800
|
// src/gateway/static.ts
|
|
212401
|
-
import { existsSync as
|
|
212801
|
+
import { existsSync as existsSync22 } from "fs";
|
|
212402
212802
|
import { join as join20, extname as extname3 } from "path";
|
|
212403
212803
|
function mime2(path4) {
|
|
212404
212804
|
return MIME[extname3(path4).toLowerCase()] ?? "application/octet-stream";
|
|
@@ -212406,7 +212806,7 @@ function mime2(path4) {
|
|
|
212406
212806
|
function resolveWebDist(candidates) {
|
|
212407
212807
|
const list = candidates ?? defaultWebDistCandidates();
|
|
212408
212808
|
for (const c4 of list) {
|
|
212409
|
-
if (
|
|
212809
|
+
if (existsSync22(join20(c4, "index.html")))
|
|
212410
212810
|
return c4;
|
|
212411
212811
|
}
|
|
212412
212812
|
return null;
|
|
@@ -212661,7 +213061,7 @@ function semverGt(a, b5) {
|
|
|
212661
213061
|
}
|
|
212662
213062
|
|
|
212663
213063
|
// src/update/version.ts
|
|
212664
|
-
import { readFileSync as
|
|
213064
|
+
import { readFileSync as readFileSync16, existsSync as existsSync23 } from "fs";
|
|
212665
213065
|
import { join as join21 } from "path";
|
|
212666
213066
|
function resolvePackageJsonPath(candidates) {
|
|
212667
213067
|
const list = candidates ?? [
|
|
@@ -212670,7 +213070,7 @@ function resolvePackageJsonPath(candidates) {
|
|
|
212670
213070
|
join21(process.cwd(), "package.json")
|
|
212671
213071
|
];
|
|
212672
213072
|
for (const p2 of list) {
|
|
212673
|
-
if (
|
|
213073
|
+
if (existsSync23(p2))
|
|
212674
213074
|
return p2;
|
|
212675
213075
|
}
|
|
212676
213076
|
return null;
|
|
@@ -212692,7 +213092,7 @@ function getCurrentVersion(pkgPath) {
|
|
|
212692
213092
|
if (!resolved)
|
|
212693
213093
|
return UNKNOWN_VERSION;
|
|
212694
213094
|
try {
|
|
212695
|
-
const pkg = JSON.parse(
|
|
213095
|
+
const pkg = JSON.parse(readFileSync16(resolved, "utf-8"));
|
|
212696
213096
|
if (pkg.version && pkg.version.length > 0)
|
|
212697
213097
|
return pkg.version;
|
|
212698
213098
|
} catch {}
|
|
@@ -212749,14 +213149,14 @@ var init_status = __esm(() => {
|
|
|
212749
213149
|
});
|
|
212750
213150
|
|
|
212751
213151
|
// src/gateway/memory.ts
|
|
212752
|
-
import { readFileSync as
|
|
213152
|
+
import { readFileSync as readFileSync17, existsSync as existsSync24 } from "fs";
|
|
212753
213153
|
function registerMemoryMethods(register, deps) {
|
|
212754
213154
|
register("memory.get", async () => {
|
|
212755
213155
|
const memory = deps.memoryStore.readLongTerm();
|
|
212756
213156
|
let history = "";
|
|
212757
|
-
if (
|
|
213157
|
+
if (existsSync24(deps.memoryStore.historyFile)) {
|
|
212758
213158
|
try {
|
|
212759
|
-
history =
|
|
213159
|
+
history = readFileSync17(deps.memoryStore.historyFile, "utf-8");
|
|
212760
213160
|
} catch {}
|
|
212761
213161
|
}
|
|
212762
213162
|
return { memory, history };
|
|
@@ -212919,6 +213319,22 @@ function registerCronMethods(register, deps) {
|
|
|
212919
213319
|
});
|
|
212920
213320
|
}
|
|
212921
213321
|
|
|
213322
|
+
// src/gateway/config.ts
|
|
213323
|
+
function registerConfigMethods(register, deps) {
|
|
213324
|
+
register("config.timezone.get", async () => ({
|
|
213325
|
+
tz: deps.timezoneService.get()
|
|
213326
|
+
}));
|
|
213327
|
+
register("config.timezone.set", async (_ctx, payload) => {
|
|
213328
|
+
const p2 = payload;
|
|
213329
|
+
const result = deps.timezoneService.set(p2.tz);
|
|
213330
|
+
if (!result.ok) {
|
|
213331
|
+
return { ok: false, error: result.error };
|
|
213332
|
+
}
|
|
213333
|
+
const updatedJobs = deps.cronService.updateBuiltinJobsTimezone(result.tz);
|
|
213334
|
+
return { ok: true, tz: result.tz, updatedJobs };
|
|
213335
|
+
});
|
|
213336
|
+
}
|
|
213337
|
+
|
|
212922
213338
|
// src/gateway/route-orchestrator-error.ts
|
|
212923
213339
|
function routeOrchestratorError(runId, classified, emit) {
|
|
212924
213340
|
if (classified.type === "TOOL_BLOCKED") {
|
|
@@ -214902,11 +215318,12 @@ class TokensSnapshotService {
|
|
|
214902
215318
|
this.priceCache = priceCache;
|
|
214903
215319
|
}
|
|
214904
215320
|
build() {
|
|
214905
|
-
const
|
|
215321
|
+
const assets = this.client.getAllAssets();
|
|
214906
215322
|
const prices = {};
|
|
214907
215323
|
const prevDayPrices = {};
|
|
214908
215324
|
const maxLeverages = {};
|
|
214909
|
-
|
|
215325
|
+
const tokens = [];
|
|
215326
|
+
for (const { symbol: symbol5, isDelisted } of assets) {
|
|
214910
215327
|
const entry = this.priceCache.get(symbol5, 30000);
|
|
214911
215328
|
if (entry) {
|
|
214912
215329
|
prices[symbol5] = entry.price;
|
|
@@ -214916,8 +215333,9 @@ class TokensSnapshotService {
|
|
|
214916
215333
|
const lev = this.client.getMaxLeverage(symbol5);
|
|
214917
215334
|
if (typeof lev === "number" && lev > 0)
|
|
214918
215335
|
maxLeverages[symbol5] = lev;
|
|
215336
|
+
tokens.push(isDelisted ? { symbol: symbol5, isDelisted: true } : { symbol: symbol5 });
|
|
214919
215337
|
}
|
|
214920
|
-
tokens.sort();
|
|
215338
|
+
tokens.sort((a, b5) => a.symbol.localeCompare(b5.symbol));
|
|
214921
215339
|
return { tokens, prices, prevDayPrices, maxLeverages };
|
|
214922
215340
|
}
|
|
214923
215341
|
}
|
|
@@ -215045,6 +215463,10 @@ function createGateway(gatewayConfig, deps) {
|
|
|
215045
215463
|
registerToolsMethods(registry4.register.bind(registry4), { tools: deps.tools });
|
|
215046
215464
|
registerSessionsMethods(registry4.register.bind(registry4), { sessionManager: deps.sessionManager });
|
|
215047
215465
|
registerCronMethods(registry4.register.bind(registry4), { cronService: deps.cronService });
|
|
215466
|
+
registerConfigMethods(registry4.register.bind(registry4), {
|
|
215467
|
+
timezoneService: deps.timezoneService,
|
|
215468
|
+
cronService: deps.cronService
|
|
215469
|
+
});
|
|
215048
215470
|
const tokensSnapshot = new TokensSnapshotService(deps.tradingClient, deps.priceCache);
|
|
215049
215471
|
registerTradingMethods(registry4.register.bind(registry4), { tradingClient: deps.tradingClient, walletStore: deps.walletStore, alertRules: deps.alertRules, notifications: deps.notifications, newsService: deps.newsService, rssDiscovery: deps.rssDiscoveryService, tweetService: deps.tweetService, xFollowService: deps.xFollowService, preferenceStore: deps.preferenceStore, watchlist: deps.watchlistService, logger: deps.logger, tokensSnapshot, priceCache: deps.priceCache });
|
|
215050
215472
|
registerApprovalMethods(registry4.register.bind(registry4), { approvalManager: deps.approvalManager });
|
|
@@ -216077,6 +216499,7 @@ async function startDaemon(options) {
|
|
|
216077
216499
|
tweetService,
|
|
216078
216500
|
xFollowService,
|
|
216079
216501
|
preferenceStore,
|
|
216502
|
+
timezoneService,
|
|
216080
216503
|
security: security2,
|
|
216081
216504
|
leakDetector,
|
|
216082
216505
|
skillService,
|
|
@@ -216122,6 +216545,7 @@ async function startDaemon(options) {
|
|
|
216122
216545
|
tools,
|
|
216123
216546
|
sessionManager,
|
|
216124
216547
|
cronService,
|
|
216548
|
+
timezoneService,
|
|
216125
216549
|
configPath,
|
|
216126
216550
|
channels: runtime.channelManager.listChannels().map((ch2) => ({ name: ch2.name })),
|
|
216127
216551
|
tradingClient,
|
|
@@ -216163,7 +216587,7 @@ async function startDaemon(options) {
|
|
|
216163
216587
|
}));
|
|
216164
216588
|
runtime.channelManager.startAllChannels();
|
|
216165
216589
|
if (config3.cron.enableScheduler) {
|
|
216166
|
-
cronService.start();
|
|
216590
|
+
cronService.start({ defaults: buildBuiltInJobs(timezoneService.get()) });
|
|
216167
216591
|
}
|
|
216168
216592
|
const runner = new BackgroundJobRunner({
|
|
216169
216593
|
taskAgent: runtime.taskAgent,
|
|
@@ -216206,6 +216630,7 @@ var init_daemon = __esm(() => {
|
|
|
216206
216630
|
init_plugin();
|
|
216207
216631
|
init_types5();
|
|
216208
216632
|
init_pairing_events();
|
|
216633
|
+
init_defaults();
|
|
216209
216634
|
});
|
|
216210
216635
|
|
|
216211
216636
|
// node_modules/colorette/index.cjs
|
|
@@ -218831,7 +219256,7 @@ __export(exports_uninstall, {
|
|
|
218831
219256
|
WIN_HANDLE_RELEASE_MS: () => WIN_HANDLE_RELEASE_MS,
|
|
218832
219257
|
SIGKILL_DELAY_MS: () => SIGKILL_DELAY_MS
|
|
218833
219258
|
});
|
|
218834
|
-
import { existsSync as fsExistsSync, readFileSync as
|
|
219259
|
+
import { existsSync as fsExistsSync, readFileSync as readFileSync19, writeFileSync as writeFileSync14, unlinkSync as unlinkSync9, rmSync as fsRmSync } from "fs";
|
|
218835
219260
|
import { join as join22 } from "path";
|
|
218836
219261
|
import { homedir as homedir7 } from "os";
|
|
218837
219262
|
async function runUninstall(deps) {
|
|
@@ -219157,8 +219582,8 @@ async function runUninstallCli() {
|
|
|
219157
219582
|
return !isCancel(r2) && r2 === true;
|
|
219158
219583
|
},
|
|
219159
219584
|
existsSync: fsExistsSync,
|
|
219160
|
-
readFile: (p2) =>
|
|
219161
|
-
writeFile: (p2, content) =>
|
|
219585
|
+
readFile: (p2) => readFileSync19(p2, "utf8"),
|
|
219586
|
+
writeFile: (p2, content) => writeFileSync14(p2, content, "utf8"),
|
|
219162
219587
|
unlink: (p2) => unlinkSync9(p2),
|
|
219163
219588
|
rmSync: (p2) => fsRmSync(p2, { recursive: true, force: true, maxRetries: 10, retryDelay: 200 }),
|
|
219164
219589
|
spawn: (cmd, args) => {
|
|
@@ -219614,7 +220039,7 @@ init_cli_providers();
|
|
|
219614
220039
|
|
|
219615
220040
|
// src/onboard/wizard.ts
|
|
219616
220041
|
init_dist8();
|
|
219617
|
-
import { existsSync as
|
|
220042
|
+
import { existsSync as existsSync27 } from "fs";
|
|
219618
220043
|
init_providers();
|
|
219619
220044
|
init_oauth3();
|
|
219620
220045
|
init_secrets();
|
|
@@ -219628,7 +220053,7 @@ init_dist8();
|
|
|
219628
220053
|
init_dist8();
|
|
219629
220054
|
init_utils8();
|
|
219630
220055
|
init_logs();
|
|
219631
|
-
import { existsSync as
|
|
220056
|
+
import { existsSync as existsSync25 } from "fs";
|
|
219632
220057
|
|
|
219633
220058
|
// src/onboard/steps/service.ts
|
|
219634
220059
|
async function runServiceStep(deps) {
|
|
@@ -219723,7 +220148,7 @@ async function finalizeOnboard(opts) {
|
|
|
219723
220148
|
}
|
|
219724
220149
|
const execPath = resolveGhostExecPath();
|
|
219725
220150
|
const bunPath = resolveBunPath();
|
|
219726
|
-
if (!
|
|
220151
|
+
if (!existsSync25(execPath)) {
|
|
219727
220152
|
O2.warn(`Ghost executable not found at ${execPath}. Service may fail to start.`);
|
|
219728
220153
|
}
|
|
219729
220154
|
const result = await runServiceStep({
|
|
@@ -219799,22 +220224,22 @@ async function startForegroundDaemon(logger) {
|
|
|
219799
220224
|
init_models_config();
|
|
219800
220225
|
import {
|
|
219801
220226
|
chmodSync,
|
|
219802
|
-
existsSync as
|
|
219803
|
-
mkdirSync as
|
|
219804
|
-
readFileSync as
|
|
220227
|
+
existsSync as existsSync26,
|
|
220228
|
+
mkdirSync as mkdirSync17,
|
|
220229
|
+
readFileSync as readFileSync18,
|
|
219805
220230
|
renameSync as renameSync4,
|
|
219806
220231
|
unlinkSync as unlinkSync8,
|
|
219807
|
-
writeFileSync as
|
|
220232
|
+
writeFileSync as writeFileSync13
|
|
219808
220233
|
} from "fs";
|
|
219809
|
-
import { dirname as
|
|
220234
|
+
import { dirname as dirname9 } from "path";
|
|
219810
220235
|
var MODELS_FILE_MODE = 384;
|
|
219811
220236
|
var MODELS_DIR_MODE = 448;
|
|
219812
220237
|
function readModelsConfig(path4) {
|
|
219813
|
-
if (!
|
|
220238
|
+
if (!existsSync26(path4))
|
|
219814
220239
|
return { kind: "missing" };
|
|
219815
220240
|
let raw;
|
|
219816
220241
|
try {
|
|
219817
|
-
raw =
|
|
220242
|
+
raw = readFileSync18(path4, "utf-8");
|
|
219818
220243
|
} catch (err) {
|
|
219819
220244
|
return { kind: "malformed", reason: describeError2(err) };
|
|
219820
220245
|
}
|
|
@@ -219875,15 +220300,15 @@ function upsertModel(current, incoming) {
|
|
|
219875
220300
|
return next;
|
|
219876
220301
|
}
|
|
219877
220302
|
function writeAtomic(path4, contents) {
|
|
219878
|
-
|
|
220303
|
+
mkdirSync17(dirname9(path4), { recursive: true, mode: MODELS_DIR_MODE });
|
|
219879
220304
|
const tmp = `${path4}.tmp-${process.pid}-${Date.now()}`;
|
|
219880
220305
|
try {
|
|
219881
|
-
|
|
220306
|
+
writeFileSync13(tmp, contents, { mode: MODELS_FILE_MODE });
|
|
219882
220307
|
chmodSync(tmp, MODELS_FILE_MODE);
|
|
219883
220308
|
renameSync4(tmp, path4);
|
|
219884
220309
|
} catch (err) {
|
|
219885
220310
|
try {
|
|
219886
|
-
if (
|
|
220311
|
+
if (existsSync26(tmp))
|
|
219887
220312
|
unlinkSync8(tmp);
|
|
219888
220313
|
} catch {}
|
|
219889
220314
|
throw err;
|
|
@@ -219909,6 +220334,22 @@ function applyUpdateModeChanges(existing, overlay) {
|
|
|
219909
220334
|
}
|
|
219910
220335
|
|
|
219911
220336
|
// src/onboard/wizard.ts
|
|
220337
|
+
init_timezone();
|
|
220338
|
+
init_database();
|
|
220339
|
+
init_db();
|
|
220340
|
+
init_registry2();
|
|
220341
|
+
async function persistTimezone(tz, logger) {
|
|
220342
|
+
try {
|
|
220343
|
+
const db2 = initDatabase(getDbPath());
|
|
220344
|
+
await runDbMigrations(db2, DB_MIGRATIONS);
|
|
220345
|
+
const prefs = new PreferenceStore(db2, logger.child({ module: "prefs" }));
|
|
220346
|
+
const tzService = createTimezoneService(prefs);
|
|
220347
|
+
tzService.set(tz);
|
|
220348
|
+
db2.close();
|
|
220349
|
+
} catch (err) {
|
|
220350
|
+
logger.warn({ err }, "onboard: failed to persist timezone");
|
|
220351
|
+
}
|
|
220352
|
+
}
|
|
219912
220353
|
function validateCustomProviderName(name) {
|
|
219913
220354
|
if (!name)
|
|
219914
220355
|
return "Provider name is required.";
|
|
@@ -219923,31 +220364,7 @@ function validateCustomProviderName(name) {
|
|
|
219923
220364
|
function isLocalBaseUrl(url3) {
|
|
219924
220365
|
return /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?(\/|$)/u.test(url3);
|
|
219925
220366
|
}
|
|
219926
|
-
|
|
219927
|
-
const which = Bun.spawnSync({ cmd: ["which", binaryPath] });
|
|
219928
|
-
if (which.exitCode !== 0) {
|
|
219929
|
-
return { ok: false, error: `Claude Code not found at "${binaryPath}". Install: curl -fsSL https://claude.ai/install.sh | bash` };
|
|
219930
|
-
}
|
|
219931
|
-
const versionProc = Bun.spawnSync({ cmd: [binaryPath, "--version"] });
|
|
219932
|
-
const version3 = versionProc.stdout.toString().trim();
|
|
219933
|
-
const authProc = Bun.spawnSync({ cmd: [binaryPath, "auth", "status", "--json"] });
|
|
219934
|
-
if (authProc.exitCode !== 0) {
|
|
219935
|
-
return { ok: false, version: version3, error: "Not authenticated. Run: claude login" };
|
|
219936
|
-
}
|
|
219937
|
-
try {
|
|
219938
|
-
const auth = JSON.parse(authProc.stdout.toString());
|
|
219939
|
-
const authenticated = auth.authenticated ?? auth.loggedIn ?? false;
|
|
219940
|
-
if (!authenticated) {
|
|
219941
|
-
return { ok: false, version: version3, error: "Not authenticated. Run: claude login" };
|
|
219942
|
-
}
|
|
219943
|
-
return { ok: true, version: version3, authStatus: auth.plan ?? auth.subscription ?? "authenticated" };
|
|
219944
|
-
} catch {
|
|
219945
|
-
return { ok: true, version: version3, authStatus: "authenticated" };
|
|
219946
|
-
}
|
|
219947
|
-
}
|
|
219948
|
-
function providerRequiresApiKey(providerId, supportsOAuth) {
|
|
219949
|
-
if (providerId === "claude-cli")
|
|
219950
|
-
return false;
|
|
220367
|
+
function providerRequiresApiKey(_providerId, supportsOAuth) {
|
|
219951
220368
|
if (supportsOAuth)
|
|
219952
220369
|
return false;
|
|
219953
220370
|
return true;
|
|
@@ -219975,6 +220392,8 @@ async function runHeadless(headless, daemonOptions) {
|
|
|
219975
220392
|
if (daemonOptions.paper)
|
|
219976
220393
|
customConfig.paper = daemonOptions.paper;
|
|
219977
220394
|
saveConfig(customConfig, configPath);
|
|
220395
|
+
const tzForCustom = resolveHeadlessTz(daemonOptions.logger);
|
|
220396
|
+
await persistTimezone(tzForCustom, daemonOptions.logger);
|
|
219978
220397
|
console.log(`[ghost] Custom provider: ${headless.provider} (from models.json)`);
|
|
219979
220398
|
console.log(`[ghost] Model: ${modelTrimmed}`);
|
|
219980
220399
|
if (daemonOptions?.paper) {
|
|
@@ -220050,8 +220469,11 @@ async function runHeadless(headless, daemonOptions) {
|
|
|
220050
220469
|
await credentials2.set("api_key", apiKey);
|
|
220051
220470
|
}
|
|
220052
220471
|
saveConfig(config3, configPath);
|
|
220472
|
+
const tz = resolveHeadlessTz(daemonOptions.logger);
|
|
220473
|
+
await persistTimezone(tz, daemonOptions.logger);
|
|
220053
220474
|
console.log(`[ghost] Provider: ${providerInfo.label} (${headless.provider})`);
|
|
220054
220475
|
console.log(`[ghost] Model: ${model}`);
|
|
220476
|
+
console.log(`[ghost] Timezone: ${tz}`);
|
|
220055
220477
|
if (daemonOptions?.paper) {
|
|
220056
220478
|
console.log(`[ghost] Mode: Paper trading (${daemonOptions.paper.initialBalance ?? 1e4} USDC)`);
|
|
220057
220479
|
}
|
|
@@ -220059,6 +220481,18 @@ async function runHeadless(headless, daemonOptions) {
|
|
|
220059
220481
|
console.log("[ghost] Config saved. Run 'ghost onboard --service' to register the auto-start service, or 'ghost daemon' to start manually.");
|
|
220060
220482
|
console.log("[ghost] Onboard complete!");
|
|
220061
220483
|
}
|
|
220484
|
+
function resolveHeadlessTz(logger) {
|
|
220485
|
+
const envTz = process.env["GHOST_TIMEZONE"];
|
|
220486
|
+
if (envTz) {
|
|
220487
|
+
const result = validateTimezone(envTz);
|
|
220488
|
+
if (!result.ok) {
|
|
220489
|
+
console.error(`[ghost] GHOST_TIMEZONE="${envTz}" is invalid: ${result.error}`);
|
|
220490
|
+
process.exit(1);
|
|
220491
|
+
}
|
|
220492
|
+
return result.tz;
|
|
220493
|
+
}
|
|
220494
|
+
return detectHostTimezone();
|
|
220495
|
+
}
|
|
220062
220496
|
async function runWizard(daemonOptions) {
|
|
220063
220497
|
if (daemonOptions.headless) {
|
|
220064
220498
|
const { headless, ...rest4 } = daemonOptions;
|
|
@@ -220071,7 +220505,7 @@ async function runWizard(daemonOptions) {
|
|
|
220071
220505
|
const credentials2 = new CredentialStore(getCredentialsPath(), secretStore, daemonOptions.logger.child({ module: "credentials" }));
|
|
220072
220506
|
let config3 = configSchema.parse({});
|
|
220073
220507
|
let mode = "full";
|
|
220074
|
-
if (
|
|
220508
|
+
if (existsSync27(configPath)) {
|
|
220075
220509
|
const modeAnswer = await _t({
|
|
220076
220510
|
message: "Existing config found. What would you like to do?",
|
|
220077
220511
|
options: [
|
|
@@ -220090,7 +220524,7 @@ async function runWizard(daemonOptions) {
|
|
|
220090
220524
|
This wizard will configure your agent in under 60 seconds.`);
|
|
220091
220525
|
if (mode === "full" && !daemonOptions.paper) {
|
|
220092
220526
|
const tradingMode = await _t({
|
|
220093
|
-
message: "Step 1/
|
|
220527
|
+
message: "Step 1/5 \u2014 Select trading mode",
|
|
220094
220528
|
options: [
|
|
220095
220529
|
{ value: "paper", label: "Paper trading (simulated, safe to explore)", hint: "10,000 USDC starting balance" },
|
|
220096
220530
|
{ value: "live", label: "Live trading (real funds on Hyperliquid)" }
|
|
@@ -220108,11 +220542,11 @@ This wizard will configure your agent in under 60 seconds.`);
|
|
|
220108
220542
|
const providers = getProviderList();
|
|
220109
220543
|
const providerOptions = providers.map((p2) => ({
|
|
220110
220544
|
value: p2.id,
|
|
220111
|
-
label: p2.label
|
|
220545
|
+
label: `${p2.label} \u2014 ${p2.tierLabel}`,
|
|
220112
220546
|
hint: p2.description
|
|
220113
220547
|
}));
|
|
220114
220548
|
const providerId = await _t({
|
|
220115
|
-
message: "Step 2/
|
|
220549
|
+
message: "Step 2/5 \u2014 Select your AI provider",
|
|
220116
220550
|
options: providerOptions
|
|
220117
220551
|
});
|
|
220118
220552
|
if (q(providerId)) {
|
|
@@ -220123,18 +220557,6 @@ This wizard will configure your agent in under 60 seconds.`);
|
|
|
220123
220557
|
let authMethod = "apikey";
|
|
220124
220558
|
let customProviderName = "";
|
|
220125
220559
|
let customApiKey = "";
|
|
220126
|
-
if (providerId === "claude-cli") {
|
|
220127
|
-
const s1 = fe2();
|
|
220128
|
-
s1.start("Validating Claude Code...");
|
|
220129
|
-
const validation2 = await validateClaudeCli("claude");
|
|
220130
|
-
if (!validation2.ok) {
|
|
220131
|
-
s1.stop(`\u2717 ${validation2.error}`);
|
|
220132
|
-
pt("Fix the issue above and try again.");
|
|
220133
|
-
process.exit(1);
|
|
220134
|
-
}
|
|
220135
|
-
s1.stop(`\u2713 Claude Code ${validation2.version ?? ""} (${validation2.authStatus})`);
|
|
220136
|
-
authMethod = "skip";
|
|
220137
|
-
}
|
|
220138
220560
|
if (providerId === "custom") {
|
|
220139
220561
|
const nameAnswer = await Ot({
|
|
220140
220562
|
message: "Provider name (identifier for ~/.ghost/models.json)",
|
|
@@ -220181,7 +220603,7 @@ This wizard will configure your agent in under 60 seconds.`);
|
|
|
220181
220603
|
{ value: "__custom__", label: "Custom model ID (type manually)" }
|
|
220182
220604
|
];
|
|
220183
220605
|
const selected = await _t({
|
|
220184
|
-
message: "Step 3/
|
|
220606
|
+
message: "Step 3/5 \u2014 Select your default model",
|
|
220185
220607
|
options: modelOptions
|
|
220186
220608
|
});
|
|
220187
220609
|
if (q(selected)) {
|
|
@@ -220200,7 +220622,7 @@ This wizard will configure your agent in under 60 seconds.`);
|
|
|
220200
220622
|
}
|
|
220201
220623
|
} else {
|
|
220202
220624
|
const manual = await Ot({
|
|
220203
|
-
message: "Step 3/
|
|
220625
|
+
message: "Step 3/5 \u2014 Enter model ID",
|
|
220204
220626
|
placeholder: "e.g. claude-sonnet-4-6"
|
|
220205
220627
|
});
|
|
220206
220628
|
if (q(manual)) {
|
|
@@ -220213,7 +220635,7 @@ This wizard will configure your agent in under 60 seconds.`);
|
|
|
220213
220635
|
let apiKey = "";
|
|
220214
220636
|
if (providerInfo?.supportsOAuth && authMethod !== "skip") {
|
|
220215
220637
|
const auth = await _t({
|
|
220216
|
-
message: "Step 4/
|
|
220638
|
+
message: "Step 4/5 \u2014 How do you want to authenticate?",
|
|
220217
220639
|
options: [
|
|
220218
220640
|
{ value: "oauth", label: "OAuth Login (authenticate in browser)", hint: "recommended" },
|
|
220219
220641
|
{ value: "apikey", label: "API Key (paste your key)" },
|
|
@@ -220249,7 +220671,7 @@ This wizard will configure your agent in under 60 seconds.`);
|
|
|
220249
220671
|
const keyUrl = providerInfo?.apiKeyUrl ? `
|
|
220250
220672
|
Get your key at: ${providerInfo.apiKeyUrl}` : "";
|
|
220251
220673
|
const key = await Ot({
|
|
220252
|
-
message: `Step 4/
|
|
220674
|
+
message: `Step 4/5 \u2014 Paste your ${providerInfo?.label ?? providerId} API key${keyUrl}`,
|
|
220253
220675
|
placeholder: "sk-...",
|
|
220254
220676
|
validate: (v4) => !v4 || v4.length >= 5 ? undefined : "API key seems too short"
|
|
220255
220677
|
});
|
|
@@ -220259,7 +220681,7 @@ This wizard will configure your agent in under 60 seconds.`);
|
|
|
220259
220681
|
}
|
|
220260
220682
|
apiKey = key;
|
|
220261
220683
|
}
|
|
220262
|
-
if (authMethod === "skip" && providerId !== "
|
|
220684
|
+
if (authMethod === "skip" && providerId !== "custom") {
|
|
220263
220685
|
O2.warn("No API key set. Export GHOST_API_KEY before running ghost daemon.");
|
|
220264
220686
|
}
|
|
220265
220687
|
if (mode === "update") {
|
|
@@ -220317,14 +220739,59 @@ This wizard will configure your agent in under 60 seconds.`);
|
|
|
220317
220739
|
config3.paper = daemonOptions.paper;
|
|
220318
220740
|
}
|
|
220319
220741
|
saveConfig(config3, configPath);
|
|
220742
|
+
const chosenTz = await promptTimezone();
|
|
220743
|
+
await persistTimezone(chosenTz, daemonOptions.logger);
|
|
220320
220744
|
O2.success("Configuration saved.");
|
|
220321
220745
|
if (providerId === "custom") {
|
|
220322
220746
|
O2.info(`Custom provider "${customProviderName}" written to ${getModelsConfigPath()}`);
|
|
220323
220747
|
}
|
|
220748
|
+
O2.info(`Timezone: ${chosenTz}`);
|
|
220324
220749
|
O2.info("Tip: connect channels from the dashboard after starting the daemon.");
|
|
220325
220750
|
console.log("");
|
|
220326
220751
|
await finalizeOnboard({ interactive: true, logger: daemonOptions.logger });
|
|
220327
220752
|
}
|
|
220753
|
+
function listSupportedTimezones() {
|
|
220754
|
+
const fn = Intl.supportedValuesOf;
|
|
220755
|
+
if (typeof fn !== "function")
|
|
220756
|
+
return [];
|
|
220757
|
+
return [...fn("timeZone")].sort();
|
|
220758
|
+
}
|
|
220759
|
+
async function promptTimezone() {
|
|
220760
|
+
const detected = detectHostTimezone();
|
|
220761
|
+
const allZones = listSupportedTimezones();
|
|
220762
|
+
if (allZones.length === 0) {
|
|
220763
|
+
const entered = await Ot({
|
|
220764
|
+
message: "Step 5/5 \u2014 IANA timezone (e.g. America/New_York):",
|
|
220765
|
+
initialValue: detected,
|
|
220766
|
+
validate(value2) {
|
|
220767
|
+
const v4 = validateTimezone(value2);
|
|
220768
|
+
return v4.ok ? undefined : v4.error;
|
|
220769
|
+
}
|
|
220770
|
+
});
|
|
220771
|
+
if (q(entered)) {
|
|
220772
|
+
pt("Setup cancelled.");
|
|
220773
|
+
process.exit(0);
|
|
220774
|
+
}
|
|
220775
|
+
const result = validateTimezone(entered);
|
|
220776
|
+
return result.ok ? result.tz : detected;
|
|
220777
|
+
}
|
|
220778
|
+
const initialValue = allZones.includes(detected) ? detected : allZones[0];
|
|
220779
|
+
const choice = await Ae2({
|
|
220780
|
+
message: "Step 5/5 \u2014 Select your timezone (type to filter)",
|
|
220781
|
+
placeholder: "e.g. berlin, new_york, utc",
|
|
220782
|
+
options: allZones.map((tz) => ({
|
|
220783
|
+
value: tz,
|
|
220784
|
+
label: tz === detected ? `${tz} (detected)` : tz
|
|
220785
|
+
})),
|
|
220786
|
+
initialValue,
|
|
220787
|
+
maxItems: 10
|
|
220788
|
+
});
|
|
220789
|
+
if (q(choice)) {
|
|
220790
|
+
pt("Setup cancelled.");
|
|
220791
|
+
process.exit(0);
|
|
220792
|
+
}
|
|
220793
|
+
return choice;
|
|
220794
|
+
}
|
|
220328
220795
|
// src/index.ts
|
|
220329
220796
|
init_errors2();
|
|
220330
220797
|
init_logger();
|
|
@@ -220555,14 +221022,14 @@ async function runSkills(subArgs, opts) {
|
|
|
220555
221022
|
const configPath = opts.config ?? getPath();
|
|
220556
221023
|
const config3 = loadConfig2(configPath);
|
|
220557
221024
|
const workspaceDir = getWorkspaceDir2();
|
|
220558
|
-
const { existsSync:
|
|
221025
|
+
const { existsSync: existsSync28 } = await import("fs");
|
|
220559
221026
|
const { join: join23 } = await import("path");
|
|
220560
221027
|
let builtinDir;
|
|
220561
221028
|
if (config3.skills.builtinSkillsDir) {
|
|
220562
221029
|
builtinDir = expandHome2(config3.skills.builtinSkillsDir);
|
|
220563
221030
|
} else {
|
|
220564
221031
|
const candidate = join23(import.meta.dir, "skills", "builtin");
|
|
220565
|
-
if (
|
|
221032
|
+
if (existsSync28(candidate))
|
|
220566
221033
|
builtinDir = candidate;
|
|
220567
221034
|
}
|
|
220568
221035
|
const loader2 = new SkillsLoader2(workspaceDir, builtinDir);
|