@hyperflow.fun/ghost 0.0.4 → 0.0.6
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 +926 -479
- 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
|
}
|
|
@@ -181691,9 +181886,7 @@ class PaperEngine {
|
|
|
181691
181886
|
}
|
|
181692
181887
|
async executeMarketOrder(symbol5, params, isMaker = false) {
|
|
181693
181888
|
const ticker = await this.marketClient.getTicker(symbol5);
|
|
181694
|
-
const
|
|
181695
|
-
const slippageMul = params.side === "buy" ? 1 + slippage / 100 : 1 - slippage / 100;
|
|
181696
|
-
const fillPrice = isMaker ? ticker.midPrice : ticker.midPrice * slippageMul;
|
|
181889
|
+
const fillPrice = ticker.midPrice;
|
|
181697
181890
|
return this.db.transaction(() => {
|
|
181698
181891
|
const existing = this.db.query("SELECT * FROM paper_positions WHERE symbol = ?").get(symbol5);
|
|
181699
181892
|
const isBuy = params.side === "buy";
|
|
@@ -182043,6 +182236,9 @@ class PaperTradingClient {
|
|
|
182043
182236
|
isKnownSymbol(symbol5) {
|
|
182044
182237
|
return this.marketClient.isKnownSymbol(symbol5);
|
|
182045
182238
|
}
|
|
182239
|
+
getAllAssets() {
|
|
182240
|
+
return this.marketClient.getAllAssets();
|
|
182241
|
+
}
|
|
182046
182242
|
getDexUniverses() {
|
|
182047
182243
|
return this.marketClient.getDexUniverses();
|
|
182048
182244
|
}
|
|
@@ -182386,7 +182582,7 @@ var init_alert_rules = __esm(() => {
|
|
|
182386
182582
|
|
|
182387
182583
|
// src/services/notifications.ts
|
|
182388
182584
|
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";
|
|
182585
|
+
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
182586
|
}
|
|
182391
182587
|
function rowToNotification(r2) {
|
|
182392
182588
|
let payload;
|
|
@@ -183057,6 +183253,23 @@ class NewsService {
|
|
|
183057
183253
|
];
|
|
183058
183254
|
return this.db.prepare(sql).all(...params).map((r2) => mapRow(r2));
|
|
183059
183255
|
}
|
|
183256
|
+
listRecentRelevant(sinceTs, limit2 = 20) {
|
|
183257
|
+
const sql = `
|
|
183258
|
+
SELECT id, source_id, external_id, url, title, snippet, image_url, coins,
|
|
183259
|
+
importance, published_at, fetched_at, expires_at, full_summary,
|
|
183260
|
+
ai_relevant, ai_duplicate_of
|
|
183261
|
+
FROM articles
|
|
183262
|
+
WHERE ai_relevant = 1
|
|
183263
|
+
AND full_summary IS NOT NULL
|
|
183264
|
+
AND ai_duplicate_of IS NULL
|
|
183265
|
+
AND dismissed_at IS NULL
|
|
183266
|
+
AND expires_at > unixepoch()
|
|
183267
|
+
AND published_at > ?
|
|
183268
|
+
ORDER BY published_at DESC, id DESC
|
|
183269
|
+
LIMIT ?
|
|
183270
|
+
`;
|
|
183271
|
+
return this.db.prepare(sql).all(sinceTs, limit2).map((r2) => mapRow(r2));
|
|
183272
|
+
}
|
|
183060
183273
|
searchArticles(opts = {}) {
|
|
183061
183274
|
const limit2 = Math.min(opts.limit ?? 50, 100);
|
|
183062
183275
|
const conditions = ["ai_duplicate_of IS NULL"];
|
|
@@ -183792,8 +184005,90 @@ class PreferenceStore {
|
|
|
183792
184005
|
else
|
|
183793
184006
|
this.set(NEWS_FILTER_PROMPT_KEY, prompt);
|
|
183794
184007
|
}
|
|
184008
|
+
getTimezone() {
|
|
184009
|
+
return this.get(USER_TIMEZONE_KEY);
|
|
184010
|
+
}
|
|
184011
|
+
setTimezone(tz) {
|
|
184012
|
+
if (tz.length === 0)
|
|
184013
|
+
this.delete(USER_TIMEZONE_KEY);
|
|
184014
|
+
else
|
|
184015
|
+
this.set(USER_TIMEZONE_KEY, tz);
|
|
184016
|
+
}
|
|
184017
|
+
}
|
|
184018
|
+
var TWEET_FILTER_PROMPT_KEY = "tweets.filter_prompt", NEWS_FILTER_PROMPT_KEY = "news.filter_prompt", USER_TIMEZONE_KEY = "user.timezone";
|
|
184019
|
+
|
|
184020
|
+
// src/scheduler/defaults.ts
|
|
184021
|
+
function detectUserTimezone() {
|
|
184022
|
+
try {
|
|
184023
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
|
|
184024
|
+
} catch {
|
|
184025
|
+
return "UTC";
|
|
184026
|
+
}
|
|
184027
|
+
}
|
|
184028
|
+
function buildBuiltInJobs(tz) {
|
|
184029
|
+
return [
|
|
184030
|
+
{
|
|
184031
|
+
name: "morning-briefing",
|
|
184032
|
+
schedule: { kind: "cron", expr: "0 8 * * *", tz },
|
|
184033
|
+
message: BRIEFING_PROMPT,
|
|
184034
|
+
deliver: true
|
|
184035
|
+
},
|
|
184036
|
+
{
|
|
184037
|
+
name: "evening-recap",
|
|
184038
|
+
schedule: { kind: "cron", expr: "0 21 * * *", tz },
|
|
184039
|
+
message: RECAP_PROMPT,
|
|
184040
|
+
deliver: true
|
|
184041
|
+
}
|
|
184042
|
+
];
|
|
183795
184043
|
}
|
|
183796
|
-
var
|
|
184044
|
+
var BRIEFING_PROMPT, RECAP_PROMPT;
|
|
184045
|
+
var init_defaults = __esm(() => {
|
|
184046
|
+
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.";
|
|
184047
|
+
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.";
|
|
184048
|
+
});
|
|
184049
|
+
|
|
184050
|
+
// src/services/timezone.ts
|
|
184051
|
+
function validateTimezone(input) {
|
|
184052
|
+
if (typeof input !== "string") {
|
|
184053
|
+
return { ok: false, error: "Timezone must be a string" };
|
|
184054
|
+
}
|
|
184055
|
+
const trimmed = input.trim();
|
|
184056
|
+
if (!trimmed) {
|
|
184057
|
+
return { ok: false, error: "Timezone cannot be empty" };
|
|
184058
|
+
}
|
|
184059
|
+
if (trimmed.includes("\x00")) {
|
|
184060
|
+
return { ok: false, error: "Timezone contains invalid characters" };
|
|
184061
|
+
}
|
|
184062
|
+
if (trimmed.length > 64) {
|
|
184063
|
+
return { ok: false, error: "Timezone exceeds maximum length" };
|
|
184064
|
+
}
|
|
184065
|
+
try {
|
|
184066
|
+
const resolved = new Intl.DateTimeFormat(undefined, { timeZone: trimmed }).resolvedOptions().timeZone;
|
|
184067
|
+
return { ok: true, tz: resolved };
|
|
184068
|
+
} catch {
|
|
184069
|
+
return { ok: false, error: "Unknown timezone" };
|
|
184070
|
+
}
|
|
184071
|
+
}
|
|
184072
|
+
function detectHostTimezone() {
|
|
184073
|
+
return detectUserTimezone();
|
|
184074
|
+
}
|
|
184075
|
+
function createTimezoneService(prefs) {
|
|
184076
|
+
return {
|
|
184077
|
+
get() {
|
|
184078
|
+
return prefs.getTimezone() ?? "UTC";
|
|
184079
|
+
},
|
|
184080
|
+
set(input) {
|
|
184081
|
+
const result = validateTimezone(input);
|
|
184082
|
+
if (!result.ok)
|
|
184083
|
+
return result;
|
|
184084
|
+
prefs.setTimezone(result.tz);
|
|
184085
|
+
return result;
|
|
184086
|
+
}
|
|
184087
|
+
};
|
|
184088
|
+
}
|
|
184089
|
+
var init_timezone = __esm(() => {
|
|
184090
|
+
init_defaults();
|
|
184091
|
+
});
|
|
183797
184092
|
|
|
183798
184093
|
// src/services/x-follows.ts
|
|
183799
184094
|
function sleep8(ms2) {
|
|
@@ -188530,7 +188825,7 @@ class Runner {
|
|
|
188530
188825
|
}
|
|
188531
188826
|
async call(opts) {
|
|
188532
188827
|
const next = this.inFlight.then(async () => {
|
|
188533
|
-
const tools = this.registry.
|
|
188828
|
+
const tools = this.registry.taskAgentTools();
|
|
188534
188829
|
this.agent.state.tools = tools;
|
|
188535
188830
|
for (const tool2 of tools) {
|
|
188536
188831
|
if (isOriginAware(tool2))
|
|
@@ -188722,7 +189017,9 @@ function emptySnapshot() {
|
|
|
188722
189017
|
openOrderIds: [],
|
|
188723
189018
|
lastRestSyncAtMs: 0,
|
|
188724
189019
|
recentCancelOids: [],
|
|
188725
|
-
recentEmittedFillIds: []
|
|
189020
|
+
recentEmittedFillIds: [],
|
|
189021
|
+
recentEmittedNewsIds: [],
|
|
189022
|
+
lastNewsScanTs: 0
|
|
188726
189023
|
};
|
|
188727
189024
|
}
|
|
188728
189025
|
|
|
@@ -188747,7 +189044,9 @@ class ObserverStateStore {
|
|
|
188747
189044
|
openOrderIds: Array.isArray(parsed.openOrderIds) ? parsed.openOrderIds : [],
|
|
188748
189045
|
lastRestSyncAtMs: typeof parsed.lastRestSyncAtMs === "number" ? parsed.lastRestSyncAtMs : 0,
|
|
188749
189046
|
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") : []
|
|
189047
|
+
recentEmittedFillIds: Array.isArray(parsed.recentEmittedFillIds) ? parsed.recentEmittedFillIds.filter((o10) => typeof o10 === "string") : [],
|
|
189048
|
+
recentEmittedNewsIds: Array.isArray(parsed.recentEmittedNewsIds) ? parsed.recentEmittedNewsIds.filter((o10) => typeof o10 === "string") : [],
|
|
189049
|
+
lastNewsScanTs: typeof parsed.lastNewsScanTs === "number" ? parsed.lastNewsScanTs : 0
|
|
188751
189050
|
};
|
|
188752
189051
|
} catch {
|
|
188753
189052
|
return emptySnapshot();
|
|
@@ -188760,7 +189059,7 @@ class ObserverStateStore {
|
|
|
188760
189059
|
this.write.run(KEY_SNAPSHOT, JSON.stringify(emptySnapshot()));
|
|
188761
189060
|
}
|
|
188762
189061
|
}
|
|
188763
|
-
var RECENT_CANCEL_OIDS_CAP = 500, RECENT_FILL_IDS_CAP = 500, KEY_SNAPSHOT = "snapshot";
|
|
189062
|
+
var RECENT_CANCEL_OIDS_CAP = 500, RECENT_FILL_IDS_CAP = 500, RECENT_NEWS_IDS_CAP = 200, KEY_SNAPSHOT = "snapshot";
|
|
188764
189063
|
|
|
188765
189064
|
// src/observer/detect/positions.ts
|
|
188766
189065
|
function posKey(symbol5, side) {
|
|
@@ -189048,6 +189347,36 @@ function detectCanceledOrders(input) {
|
|
|
189048
189347
|
return { events, emittedOids };
|
|
189049
189348
|
}
|
|
189050
189349
|
|
|
189350
|
+
// src/observer/detect/news.ts
|
|
189351
|
+
function detectNews(input) {
|
|
189352
|
+
const events = [];
|
|
189353
|
+
const emittedIds = [];
|
|
189354
|
+
const seenThisTick = new Set;
|
|
189355
|
+
for (const article of input.articles) {
|
|
189356
|
+
if (input.priorEmittedIds.has(article.id))
|
|
189357
|
+
continue;
|
|
189358
|
+
if (seenThisTick.has(article.id))
|
|
189359
|
+
continue;
|
|
189360
|
+
if (article.fullSummary === null)
|
|
189361
|
+
continue;
|
|
189362
|
+
events.push({
|
|
189363
|
+
type: "news",
|
|
189364
|
+
detectedAt: input.nowMs,
|
|
189365
|
+
articleId: article.id,
|
|
189366
|
+
title: article.title,
|
|
189367
|
+
summary: article.fullSummary,
|
|
189368
|
+
source: article.sourceId,
|
|
189369
|
+
url: article.url,
|
|
189370
|
+
publishedAt: article.publishedAt * 1000,
|
|
189371
|
+
importance: article.importance,
|
|
189372
|
+
coins: [...article.coins]
|
|
189373
|
+
});
|
|
189374
|
+
emittedIds.push(article.id);
|
|
189375
|
+
seenThisTick.add(article.id);
|
|
189376
|
+
}
|
|
189377
|
+
return { events, emittedIds };
|
|
189378
|
+
}
|
|
189379
|
+
|
|
189051
189380
|
// src/observer/diff.ts
|
|
189052
189381
|
function diffSnapshot(input) {
|
|
189053
189382
|
const positionsR = detectPositions({
|
|
@@ -189079,18 +189408,25 @@ function diffSnapshot(input) {
|
|
|
189079
189408
|
prices: input.prices,
|
|
189080
189409
|
nowMs: input.nowMs
|
|
189081
189410
|
});
|
|
189411
|
+
const newsR = detectNews({
|
|
189412
|
+
articles: input.articles,
|
|
189413
|
+
priorEmittedIds: new Set(input.prior.recentEmittedNewsIds),
|
|
189414
|
+
nowMs: input.nowMs
|
|
189415
|
+
});
|
|
189082
189416
|
return {
|
|
189083
189417
|
events: [
|
|
189084
189418
|
...positionsR.events,
|
|
189085
189419
|
...fillsR.events,
|
|
189086
189420
|
...fallbackEvents,
|
|
189087
189421
|
...cancelR.events,
|
|
189088
|
-
...priceTargetR.events
|
|
189422
|
+
...priceTargetR.events,
|
|
189423
|
+
...newsR.events
|
|
189089
189424
|
],
|
|
189090
189425
|
nextPositions: positionsR.nextPositions,
|
|
189091
189426
|
firedAlertIds: priceTargetR.firedIds,
|
|
189092
189427
|
emittedCancelOids: cancelR.emittedOids,
|
|
189093
|
-
emittedFillIds: fillsR.emittedFillIds
|
|
189428
|
+
emittedFillIds: fillsR.emittedFillIds,
|
|
189429
|
+
emittedNewsIds: newsR.emittedIds
|
|
189094
189430
|
};
|
|
189095
189431
|
}
|
|
189096
189432
|
var init_diff = () => {};
|
|
@@ -189206,7 +189542,8 @@ var init_judge2 = __esm(() => {
|
|
|
189206
189542
|
Type.Literal("order_canceled"),
|
|
189207
189543
|
Type.Literal("liquidation_risk"),
|
|
189208
189544
|
Type.Literal("pnl_snapshot"),
|
|
189209
|
-
Type.Literal("price_alert")
|
|
189545
|
+
Type.Literal("price_alert"),
|
|
189546
|
+
Type.Literal("news")
|
|
189210
189547
|
];
|
|
189211
189548
|
JudgeResponseSchema = Type.Object({
|
|
189212
189549
|
decision: Type.Union([Type.Literal("fire"), Type.Literal("silent")]),
|
|
@@ -194058,6 +194395,7 @@ function stripCustomTags(text) {
|
|
|
194058
194395
|
out = out.replace(/<verdict\s*[^>]*>([\s\S]*?)<\/verdict>/gi, `${SENTINEL_I_OPEN}$1${SENTINEL_I_CLOSE}`);
|
|
194059
194396
|
out = out.replace(/(\n)(\x00I_OPEN\x00(?:\uD83D\uDC02 |\uD83D\uDC3B |\u3030\uFE0F )?)/g, `$1
|
|
194060
194397
|
$2`);
|
|
194398
|
+
out = out.replace(/<ask_user_question\s*>([\s\S]*?)<\/ask_user_question>/gi, (_full, inner) => formatAskFallback(inner));
|
|
194061
194399
|
const chartHint = (attrs) => {
|
|
194062
194400
|
const symMatch = /\bsymbol\s*=\s*"([^"]+)"/i.exec(attrs);
|
|
194063
194401
|
const intMatch = /\binterval\s*=\s*"([^"]+)"/i.exec(attrs);
|
|
@@ -194078,6 +194416,25 @@ $2`);
|
|
|
194078
194416
|
out = out.replace(/<[a-zA-Z][^>]*$/g, "");
|
|
194079
194417
|
return out;
|
|
194080
194418
|
}
|
|
194419
|
+
function formatAskFallback(inner) {
|
|
194420
|
+
const questionRe = /<question>([\s\S]*?)<\/question>/gi;
|
|
194421
|
+
const titleRe = /<title>([\s\S]*?)<\/title>/i;
|
|
194422
|
+
const lines = [];
|
|
194423
|
+
let m6;
|
|
194424
|
+
let i = 1;
|
|
194425
|
+
while ((m6 = questionRe.exec(inner)) !== null) {
|
|
194426
|
+
const title = titleRe.exec(m6[1])?.[1]?.trim();
|
|
194427
|
+
if (!title)
|
|
194428
|
+
continue;
|
|
194429
|
+
lines.push(`${i}. ${title}`);
|
|
194430
|
+
i++;
|
|
194431
|
+
}
|
|
194432
|
+
if (lines.length === 0)
|
|
194433
|
+
return "";
|
|
194434
|
+
return `
|
|
194435
|
+
${lines.join(`
|
|
194436
|
+
`)}`;
|
|
194437
|
+
}
|
|
194081
194438
|
var CHART_RE_PAIRED, CHART_RE_SELF;
|
|
194082
194439
|
var init_tags = __esm(() => {
|
|
194083
194440
|
CHART_RE_PAIRED = /<chart\s*([^>]*)>([\s\S]*?)<\/chart>/gi;
|
|
@@ -195524,6 +195881,7 @@ class ObserverLoop {
|
|
|
195524
195881
|
const currentOpenOrderIds = rest4.openOrders.map((o10) => o10.orderId);
|
|
195525
195882
|
const prices = this.deps.priceCache.snapshot();
|
|
195526
195883
|
const alertRules = this.deps.alertRules.list();
|
|
195884
|
+
const articles = rest4.positions.length === 0 ? [] : this.deps.newsService.listRecentRelevant(newsScanSinceTs(prior.lastNewsScanTs, nowMs));
|
|
195527
195885
|
const diff = diffSnapshot({
|
|
195528
195886
|
prior,
|
|
195529
195887
|
positions: rest4.positions,
|
|
@@ -195533,6 +195891,7 @@ class ObserverLoop {
|
|
|
195533
195891
|
alertRules,
|
|
195534
195892
|
prices,
|
|
195535
195893
|
liqProgressThreshold: this.deps.config.liquidationProgressThreshold,
|
|
195894
|
+
articles,
|
|
195536
195895
|
nowMs
|
|
195537
195896
|
});
|
|
195538
195897
|
for (const id of diff.firedAlertIds) {
|
|
@@ -195565,7 +195924,9 @@ class ObserverLoop {
|
|
|
195565
195924
|
openOrderIds: currentOpenOrderIds,
|
|
195566
195925
|
lastRestSyncAtMs: synced ? nowMs : prior.lastRestSyncAtMs,
|
|
195567
195926
|
recentCancelOids: mergeCancelOids(prior.recentCancelOids, diff.emittedCancelOids),
|
|
195568
|
-
recentEmittedFillIds: mergeBoundedIds(prior.recentEmittedFillIds, diff.emittedFillIds, RECENT_FILL_IDS_CAP)
|
|
195927
|
+
recentEmittedFillIds: mergeBoundedIds(prior.recentEmittedFillIds, diff.emittedFillIds, RECENT_FILL_IDS_CAP),
|
|
195928
|
+
recentEmittedNewsIds: mergeBoundedIds(prior.recentEmittedNewsIds, diff.emittedNewsIds, RECENT_NEWS_IDS_CAP),
|
|
195929
|
+
lastNewsScanTs: maxArticlePublishedAtSec(articles, prior.lastNewsScanTs)
|
|
195569
195930
|
};
|
|
195570
195931
|
const scanCounts = {
|
|
195571
195932
|
positions: rest4.positions.length,
|
|
@@ -195654,6 +196015,7 @@ class ObserverLoop {
|
|
|
195654
196015
|
alertRules: this.deps.alertRules.list(),
|
|
195655
196016
|
prices: this.deps.priceCache.snapshot(),
|
|
195656
196017
|
liqProgressThreshold: this.deps.config.liquidationProgressThreshold,
|
|
196018
|
+
articles: [],
|
|
195657
196019
|
nowMs
|
|
195658
196020
|
});
|
|
195659
196021
|
this.store.save({
|
|
@@ -195662,7 +196024,9 @@ class ObserverLoop {
|
|
|
195662
196024
|
openOrderIds: rest4.openOrders.map((o10) => o10.orderId),
|
|
195663
196025
|
lastRestSyncAtMs: syncDue ? nowMs : prior.lastRestSyncAtMs,
|
|
195664
196026
|
recentCancelOids: mergeCancelOids(prior.recentCancelOids, diff.emittedCancelOids),
|
|
195665
|
-
recentEmittedFillIds: mergeBoundedIds(prior.recentEmittedFillIds, diff.emittedFillIds, RECENT_FILL_IDS_CAP)
|
|
196027
|
+
recentEmittedFillIds: mergeBoundedIds(prior.recentEmittedFillIds, diff.emittedFillIds, RECENT_FILL_IDS_CAP),
|
|
196028
|
+
recentEmittedNewsIds: prior.recentEmittedNewsIds,
|
|
196029
|
+
lastNewsScanTs: prior.lastNewsScanTs
|
|
195666
196030
|
});
|
|
195667
196031
|
} catch (err) {
|
|
195668
196032
|
this.deps.logger.warn({ err }, "observer: baseline refresh failed under confirm gate");
|
|
@@ -195802,11 +196166,25 @@ function mapKindFromEventType(t2) {
|
|
|
195802
196166
|
return "order_canceled";
|
|
195803
196167
|
case "order_filled":
|
|
195804
196168
|
return "order_filled";
|
|
196169
|
+
case "news":
|
|
196170
|
+
return "news";
|
|
195805
196171
|
default:
|
|
195806
196172
|
return "proactive";
|
|
195807
196173
|
}
|
|
195808
196174
|
}
|
|
195809
|
-
|
|
196175
|
+
function newsScanSinceTs(lastScanTs, nowMs) {
|
|
196176
|
+
const slidingFloor = Math.floor(nowMs / 1000) - NEWS_LOOKBACK_FLOOR_SEC;
|
|
196177
|
+
return lastScanTs > slidingFloor ? lastScanTs : slidingFloor;
|
|
196178
|
+
}
|
|
196179
|
+
function maxArticlePublishedAtSec(articles, prior) {
|
|
196180
|
+
let max = prior;
|
|
196181
|
+
for (const a of articles) {
|
|
196182
|
+
if (a.publishedAt > max)
|
|
196183
|
+
max = a.publishedAt;
|
|
196184
|
+
}
|
|
196185
|
+
return max;
|
|
196186
|
+
}
|
|
196187
|
+
var RECENT_CHAT_MAX = 20, MIN_PRICE_PCT_DELTA = 0.5, MIN_COOLDOWN_MS, NEWS_LOOKBACK_FLOOR_SEC;
|
|
195810
196188
|
var init_loop = __esm(() => {
|
|
195811
196189
|
init_diff();
|
|
195812
196190
|
init_judge2();
|
|
@@ -195814,11 +196192,12 @@ var init_loop = __esm(() => {
|
|
|
195814
196192
|
init_channels();
|
|
195815
196193
|
init_types5();
|
|
195816
196194
|
MIN_COOLDOWN_MS = 60 * 60 * 1000;
|
|
196195
|
+
NEWS_LOOKBACK_FLOOR_SEC = 30 * 60;
|
|
195817
196196
|
});
|
|
195818
196197
|
|
|
195819
196198
|
// src/runtime.ts
|
|
195820
196199
|
import { join as join14 } from "path";
|
|
195821
|
-
import { existsSync as
|
|
196200
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync13, copyFileSync as copyFileSync2, readdirSync as readdirSync7 } from "fs";
|
|
195822
196201
|
async function createRuntime(options) {
|
|
195823
196202
|
const configPath = options.configPath ?? getConfigPath();
|
|
195824
196203
|
const rawConfig = loadConfig(configPath);
|
|
@@ -195858,12 +196237,14 @@ async function createRuntime(options) {
|
|
|
195858
196237
|
const skillsLoader = new SkillsLoader(workspaceDir, builtinSkillsDir);
|
|
195859
196238
|
const skillService = new SkillService(db2, skillsLoader);
|
|
195860
196239
|
skillService.syncState();
|
|
195861
|
-
const
|
|
196240
|
+
const preferenceStore = new PreferenceStore(db2, logger.child({ module: "prefs" }));
|
|
196241
|
+
const timezoneService = createTimezoneService(preferenceStore);
|
|
196242
|
+
const contextBuilder = new ContextBuilder({ workspaceDir, model: config3.model, getTimezone: () => timezoneService.get() }, memoryStore, skillsLoader);
|
|
195862
196243
|
contextBuilder.setDisabledSkillsProvider(() => skillService.getDisabledNames());
|
|
195863
|
-
const cronService = new CronService(
|
|
196244
|
+
const cronService = new CronService(db2);
|
|
195864
196245
|
const tools = createToolRegistry(security2, {
|
|
195865
196246
|
cronService,
|
|
195866
|
-
|
|
196247
|
+
timezoneService,
|
|
195867
196248
|
memoryStore,
|
|
195868
196249
|
logger: logger.child({ module: "tool" })
|
|
195869
196250
|
});
|
|
@@ -195874,7 +196255,6 @@ async function createRuntime(options) {
|
|
|
195874
196255
|
const watchlistService = new WatchlistService(db2);
|
|
195875
196256
|
const newsService = new NewsService(db2, watchlistService, credentials2, logger.child({ module: "news" }));
|
|
195876
196257
|
const tweetService = new TweetService(db2, logger.child({ module: "tweets" }));
|
|
195877
|
-
const preferenceStore = new PreferenceStore(db2, logger.child({ module: "prefs" }));
|
|
195878
196258
|
const xQueryIdCache = new XQueryIdCache;
|
|
195879
196259
|
const xFollowService = new XFollowService(db2, credentials2, xQueryIdCache, logger.child({ module: "x-follows" }));
|
|
195880
196260
|
const taIndicators = new TaIndicatorService(tradingClient);
|
|
@@ -195913,7 +196293,7 @@ async function createRuntime(options) {
|
|
|
195913
196293
|
eventBus,
|
|
195914
196294
|
logger,
|
|
195915
196295
|
customModelRegistry,
|
|
195916
|
-
confirmDeps: { getConfirmService: () => confirmServiceRef }
|
|
196296
|
+
confirmDeps: { getConfirmService: () => confirmServiceRef, approvalManager }
|
|
195917
196297
|
});
|
|
195918
196298
|
const taskAgent = createAgent({
|
|
195919
196299
|
config: config3,
|
|
@@ -195930,7 +196310,8 @@ async function createRuntime(options) {
|
|
|
195930
196310
|
logger: logger.child({ module: "task-agent" }),
|
|
195931
196311
|
customModelRegistry,
|
|
195932
196312
|
confirmDeps: { getConfirmService: () => null },
|
|
195933
|
-
bypassConfirm: true
|
|
196313
|
+
bypassConfirm: true,
|
|
196314
|
+
taskMode: true
|
|
195934
196315
|
});
|
|
195935
196316
|
const runner = new Runner(taskAgent, sessionManager, tools, logger.child({ module: "runner" }));
|
|
195936
196317
|
const rssDiscoveryService = new RssDiscoveryService(runner, logger.child({ module: "rss-discovery" }));
|
|
@@ -195997,7 +196378,7 @@ async function createRuntime(options) {
|
|
|
195997
196378
|
tools.register(t2);
|
|
195998
196379
|
contextBuilder.setTools(tools.all().map((t2) => ({ name: t2.name, description: t2.description })));
|
|
195999
196380
|
agent3.state.tools = tools.all();
|
|
196000
|
-
taskAgent.state.tools = tools.
|
|
196381
|
+
taskAgent.state.tools = tools.taskAgentTools();
|
|
196001
196382
|
setupClaudeCliProvider({
|
|
196002
196383
|
config: config3,
|
|
196003
196384
|
logger,
|
|
@@ -196037,6 +196418,7 @@ async function createRuntime(options) {
|
|
|
196037
196418
|
config: config3.observer,
|
|
196038
196419
|
tradingClient,
|
|
196039
196420
|
alertRules,
|
|
196421
|
+
newsService,
|
|
196040
196422
|
notifications,
|
|
196041
196423
|
priceCache,
|
|
196042
196424
|
approvalManager,
|
|
@@ -196082,6 +196464,7 @@ async function createRuntime(options) {
|
|
|
196082
196464
|
rssDiscoveryService,
|
|
196083
196465
|
tweetService,
|
|
196084
196466
|
preferenceStore,
|
|
196467
|
+
timezoneService,
|
|
196085
196468
|
xFollowService,
|
|
196086
196469
|
skillService,
|
|
196087
196470
|
chartSeries,
|
|
@@ -196115,16 +196498,16 @@ function getApiKey(oauthManager, credentials2, customModelRegistry) {
|
|
|
196115
196498
|
};
|
|
196116
196499
|
}
|
|
196117
196500
|
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);
|
|
196501
|
+
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
196502
|
return new Agent(initialOptions);
|
|
196120
196503
|
}
|
|
196121
|
-
function buildAgentOptions(config3, model, security2, leakDetector, oauthManager, tools, systemPrompt, credentials2, extraReadDirs, approvalManager, eventBus, logger, customModelRegistry, confirmDeps, bypassConfirm = false) {
|
|
196504
|
+
function buildAgentOptions(config3, model, security2, leakDetector, oauthManager, tools, systemPrompt, credentials2, extraReadDirs, approvalManager, eventBus, logger, customModelRegistry, confirmDeps, bypassConfirm = false, taskMode = false) {
|
|
196122
196505
|
const effectiveThinkingLevel = shouldForceThinkingOff({ id: model.id, baseUrl: model.baseUrl ?? "" }) ? "off" : config3.agent.thinkingLevel;
|
|
196123
196506
|
return {
|
|
196124
196507
|
initialState: {
|
|
196125
196508
|
systemPrompt,
|
|
196126
196509
|
model,
|
|
196127
|
-
tools: config3.provider === "claude-cli" ? [] : tools.all(),
|
|
196510
|
+
tools: config3.provider === "claude-cli" ? [] : taskMode ? tools.taskAgentTools() : tools.all(),
|
|
196128
196511
|
thinkingLevel: effectiveThinkingLevel
|
|
196129
196512
|
},
|
|
196130
196513
|
getApiKey: config3.provider === "claude-cli" ? async () => "claude-cli-no-key-needed" : getApiKey(oauthManager, credentials2, customModelRegistry),
|
|
@@ -196213,6 +196596,7 @@ async function runBatchedConfirm(assistantMessage, callName, callArgs, batchCach
|
|
|
196213
196596
|
let title;
|
|
196214
196597
|
const lines = [];
|
|
196215
196598
|
let steps;
|
|
196599
|
+
let extras;
|
|
196216
196600
|
if (isMulti) {
|
|
196217
196601
|
title = `Confirm ${confirmable.length} actions?`;
|
|
196218
196602
|
const stepList = [];
|
|
@@ -196223,14 +196607,22 @@ async function runBatchedConfirm(assistantMessage, callName, callArgs, batchCach
|
|
|
196223
196607
|
stepList.push(`${head}${tail}`);
|
|
196224
196608
|
}
|
|
196225
196609
|
steps = stepList;
|
|
196610
|
+
extras = undefined;
|
|
196226
196611
|
} else {
|
|
196227
196612
|
const only = confirmable[0];
|
|
196613
|
+
const args = only.args ?? {};
|
|
196614
|
+
const symbol5 = typeof args.symbol === "string" ? args.symbol : undefined;
|
|
196228
196615
|
const desc = describeConfirm(only.name, only.args);
|
|
196229
196616
|
title = desc.title;
|
|
196230
196617
|
lines.push(...desc.bullets);
|
|
196618
|
+
extras = {
|
|
196619
|
+
wizard: desc.wizard,
|
|
196620
|
+
suggestedValue: desc.suggestedValue,
|
|
196621
|
+
symbol: symbol5
|
|
196622
|
+
};
|
|
196231
196623
|
}
|
|
196232
196624
|
try {
|
|
196233
|
-
const res = await confirmService.confirm(title, { lines, steps });
|
|
196625
|
+
const res = await confirmService.confirm(title, { lines, steps }, extras);
|
|
196234
196626
|
return { decision: res.decision, reason: res.reason };
|
|
196235
196627
|
} catch (err) {
|
|
196236
196628
|
logger.warn({ err }, "confirm service threw; treating as rejected");
|
|
@@ -196379,19 +196771,19 @@ function makeTransformContext(maxTokens) {
|
|
|
196379
196771
|
}
|
|
196380
196772
|
function resolveDefaultBuiltinSkillsDir() {
|
|
196381
196773
|
const candidate = join14(import.meta.dir, "skills", "builtin");
|
|
196382
|
-
return
|
|
196774
|
+
return existsSync17(candidate) ? candidate : undefined;
|
|
196383
196775
|
}
|
|
196384
196776
|
function seedWorkspaceTemplates(workspaceDir) {
|
|
196385
196777
|
const templatesDir = join14(import.meta.dir, "templates");
|
|
196386
|
-
if (!
|
|
196778
|
+
if (!existsSync17(templatesDir))
|
|
196387
196779
|
return;
|
|
196388
196780
|
try {
|
|
196389
|
-
|
|
196781
|
+
mkdirSync13(workspaceDir, { recursive: true });
|
|
196390
196782
|
for (const entry of readdirSync7(templatesDir, { withFileTypes: true })) {
|
|
196391
196783
|
if (!entry.isFile())
|
|
196392
196784
|
continue;
|
|
196393
196785
|
const target = join14(workspaceDir, entry.name);
|
|
196394
|
-
if (!
|
|
196786
|
+
if (!existsSync17(target))
|
|
196395
196787
|
copyFileSync2(join14(templatesDir, entry.name), target);
|
|
196396
196788
|
}
|
|
196397
196789
|
} catch {}
|
|
@@ -196443,6 +196835,7 @@ var init_runtime2 = __esm(() => {
|
|
|
196443
196835
|
init_news();
|
|
196444
196836
|
init_rss_discovery();
|
|
196445
196837
|
init_tweets();
|
|
196838
|
+
init_timezone();
|
|
196446
196839
|
init_x_follows();
|
|
196447
196840
|
init_x_query_ids();
|
|
196448
196841
|
init_ta_indicators();
|
|
@@ -196626,14 +197019,6 @@ function getProviderList() {
|
|
|
196626
197019
|
});
|
|
196627
197020
|
}
|
|
196628
197021
|
}
|
|
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
197022
|
list.push({
|
|
196638
197023
|
id: "custom",
|
|
196639
197024
|
label: "Custom",
|
|
@@ -196664,9 +197049,6 @@ function getProviderList() {
|
|
|
196664
197049
|
return list;
|
|
196665
197050
|
}
|
|
196666
197051
|
function getModelList(providerId) {
|
|
196667
|
-
if (providerId === "claude-cli") {
|
|
196668
|
-
return getClaudeCliModels();
|
|
196669
|
-
}
|
|
196670
197052
|
try {
|
|
196671
197053
|
const raw = getModels(providerId).map((m6) => ({ id: m6.id, name: m6.name || m6.id }));
|
|
196672
197054
|
return filterModelCatalog(providerId, raw);
|
|
@@ -196677,7 +197059,6 @@ function getModelList(providerId) {
|
|
|
196677
197059
|
var OAUTH_PROVIDERS2, PROVIDER_META, TIER_LABELS;
|
|
196678
197060
|
var init_providers = __esm(() => {
|
|
196679
197061
|
init_dist();
|
|
196680
|
-
init_models6();
|
|
196681
197062
|
init_model_catalog();
|
|
196682
197063
|
OAUTH_PROVIDERS2 = new Set(["anthropic", "openai-codex", "github-copilot", "google-gemini-cli", "google-antigravity"]);
|
|
196683
197064
|
PROVIDER_META = {
|
|
@@ -196685,7 +197066,6 @@ var init_providers = __esm(() => {
|
|
|
196685
197066
|
anthropic: { label: "Anthropic", description: "Claude Sonnet & Opus (direct)", tier: 0, apiKeyUrl: "https://console.anthropic.com/settings/keys" },
|
|
196686
197067
|
openai: { label: "OpenAI", description: "GPT-4o, GPT-5 (direct)", tier: 0, apiKeyUrl: "https://platform.openai.com/api-keys" },
|
|
196687
197068
|
"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
197069
|
google: { label: "Google Gemini", description: "Gemini 2.0 Flash & Pro", tier: 0, apiKeyUrl: "https://aistudio.google.com/app/apikey" },
|
|
196690
197070
|
"google-gemini-cli": { label: "Google Gemini CLI", description: "Gemini via CLI auth", tier: 0 },
|
|
196691
197071
|
xai: { label: "xAI", description: "Grok 3 & 4", tier: 0, apiKeyUrl: "https://console.x.ai" },
|
|
@@ -196722,17 +197102,15 @@ __export(exports_cli_providers, {
|
|
|
196722
197102
|
listModels: () => listModels
|
|
196723
197103
|
});
|
|
196724
197104
|
function requiresApiKey(provider) {
|
|
196725
|
-
|
|
196726
|
-
return false;
|
|
196727
|
-
if (provider.supportsOAuth)
|
|
196728
|
-
return false;
|
|
196729
|
-
return true;
|
|
197105
|
+
return !provider.supportsOAuth;
|
|
196730
197106
|
}
|
|
196731
197107
|
function listProviders() {
|
|
196732
197108
|
const builtIn = getProviderList().map((p) => ({
|
|
196733
197109
|
id: p.id,
|
|
196734
197110
|
label: p.label,
|
|
196735
197111
|
description: p.description,
|
|
197112
|
+
tier: p.tier,
|
|
197113
|
+
tierLabel: p.tierLabel,
|
|
196736
197114
|
requiresApiKey: requiresApiKey(p),
|
|
196737
197115
|
supportsOAuth: p.supportsOAuth,
|
|
196738
197116
|
apiKeyUrl: p.apiKeyUrl ?? null
|
|
@@ -196743,6 +197121,8 @@ function listProviders() {
|
|
|
196743
197121
|
id: name,
|
|
196744
197122
|
label: name,
|
|
196745
197123
|
description: "Custom provider (from ~/.ghost/models.json)",
|
|
197124
|
+
tier: 4,
|
|
197125
|
+
tierLabel: "\uD83D\uDD27 Custom",
|
|
196746
197126
|
requiresApiKey: true,
|
|
196747
197127
|
supportsOAuth: false,
|
|
196748
197128
|
apiKeyUrl: null,
|
|
@@ -198796,11 +199176,11 @@ ${je2}${r2.trimStart()}`), s2 = 3 + ne(r2.trimStart()).length);
|
|
|
198796
199176
|
});
|
|
198797
199177
|
|
|
198798
199178
|
// src/services/os/utils.ts
|
|
198799
|
-
import { accessSync, constants, existsSync as
|
|
199179
|
+
import { accessSync, constants, existsSync as existsSync18, mkdirSync as mkdirSync14, realpathSync as realpathSync2 } from "fs";
|
|
198800
199180
|
import { join as join15 } from "path";
|
|
198801
199181
|
import { homedir as homedir3 } from "os";
|
|
198802
199182
|
function isExecutable(filePath) {
|
|
198803
|
-
if (!
|
|
199183
|
+
if (!existsSync18(filePath))
|
|
198804
199184
|
return false;
|
|
198805
199185
|
try {
|
|
198806
199186
|
accessSync(filePath, constants.X_OK);
|
|
@@ -198847,8 +199227,8 @@ function resolveBunPath() {
|
|
|
198847
199227
|
return candidates[0];
|
|
198848
199228
|
}
|
|
198849
199229
|
function ensureLogDir(dir) {
|
|
198850
|
-
if (!
|
|
198851
|
-
|
|
199230
|
+
if (!existsSync18(dir)) {
|
|
199231
|
+
mkdirSync14(dir, { recursive: true });
|
|
198852
199232
|
}
|
|
198853
199233
|
}
|
|
198854
199234
|
function defaultLogDir() {
|
|
@@ -198914,7 +199294,7 @@ __export(exports_launchd, {
|
|
|
198914
199294
|
LaunchdController: () => LaunchdController
|
|
198915
199295
|
});
|
|
198916
199296
|
import { spawnSync } from "child_process";
|
|
198917
|
-
import { existsSync as
|
|
199297
|
+
import { existsSync as existsSync19, unlinkSync as unlinkSync6, writeFileSync as writeFileSync10, rmSync as rmSync5 } from "fs";
|
|
198918
199298
|
import { join as join16 } from "path";
|
|
198919
199299
|
import { homedir as homedir4 } from "os";
|
|
198920
199300
|
function plistPath() {
|
|
@@ -198964,7 +199344,7 @@ class LaunchdController {
|
|
|
198964
199344
|
stderrLog,
|
|
198965
199345
|
env: opts.env ?? {}
|
|
198966
199346
|
});
|
|
198967
|
-
|
|
199347
|
+
writeFileSync10(definitionPath, plist, { encoding: "utf8", mode: 420 });
|
|
198968
199348
|
const domain2 = guiDomain();
|
|
198969
199349
|
const uid = process.getuid?.() ?? 0;
|
|
198970
199350
|
const serviceTarget = `${domain2}/${LABEL}`;
|
|
@@ -199014,12 +199394,12 @@ class LaunchdController {
|
|
|
199014
199394
|
const domain2 = guiDomain();
|
|
199015
199395
|
const definition = plistPath();
|
|
199016
199396
|
launchctl(["bootout", domain2, definition]);
|
|
199017
|
-
if (
|
|
199397
|
+
if (existsSync19(definition)) {
|
|
199018
199398
|
unlinkSync6(definition);
|
|
199019
199399
|
}
|
|
199020
199400
|
if (opts.purgeLogs) {
|
|
199021
199401
|
const logDir = defaultLogDir();
|
|
199022
|
-
if (
|
|
199402
|
+
if (existsSync19(logDir)) {
|
|
199023
199403
|
rmSync5(logDir, { recursive: true, force: true });
|
|
199024
199404
|
}
|
|
199025
199405
|
}
|
|
@@ -199103,8 +199483,8 @@ __export(exports_systemd, {
|
|
|
199103
199483
|
SystemdController: () => SystemdController
|
|
199104
199484
|
});
|
|
199105
199485
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
199106
|
-
import { copyFileSync as copyFileSync3, existsSync as
|
|
199107
|
-
import { dirname as
|
|
199486
|
+
import { copyFileSync as copyFileSync3, existsSync as existsSync20, mkdirSync as mkdirSync15, rmSync as rmSync6, unlinkSync as unlinkSync7, writeFileSync as writeFileSync11 } from "fs";
|
|
199487
|
+
import { dirname as dirname8, join as join17 } from "path";
|
|
199108
199488
|
import { homedir as homedir5 } from "os";
|
|
199109
199489
|
function unitPath() {
|
|
199110
199490
|
return join17(homedir5(), ".config", "systemd", "user", SERVICE_NAME);
|
|
@@ -199148,11 +199528,11 @@ class SystemdController {
|
|
|
199148
199528
|
assertSystemdAvailable();
|
|
199149
199529
|
ensureLogDir(opts.logDir);
|
|
199150
199530
|
const path4 = unitPath();
|
|
199151
|
-
const dir =
|
|
199152
|
-
if (!
|
|
199153
|
-
|
|
199531
|
+
const dir = dirname8(path4);
|
|
199532
|
+
if (!existsSync20(dir)) {
|
|
199533
|
+
mkdirSync15(dir, { recursive: true });
|
|
199154
199534
|
}
|
|
199155
|
-
if (
|
|
199535
|
+
if (existsSync20(path4)) {
|
|
199156
199536
|
copyFileSync3(path4, `${path4}.bak`);
|
|
199157
199537
|
}
|
|
199158
199538
|
const unit = buildUnit({
|
|
@@ -199165,7 +199545,7 @@ class SystemdController {
|
|
|
199165
199545
|
GHOST_LOG_DIR: opts.logDir
|
|
199166
199546
|
}
|
|
199167
199547
|
});
|
|
199168
|
-
|
|
199548
|
+
writeFileSync11(path4, unit, "utf8");
|
|
199169
199549
|
const reload = systemctlStrict("daemon-reload");
|
|
199170
199550
|
if (!reload.ok) {
|
|
199171
199551
|
const msg = `daemon-reload failed: ${reload.stderr || reload.stdout}`;
|
|
@@ -199211,7 +199591,7 @@ class SystemdController {
|
|
|
199211
199591
|
}
|
|
199212
199592
|
for (const file3 of [path4, `${path4}.bak`]) {
|
|
199213
199593
|
try {
|
|
199214
|
-
if (
|
|
199594
|
+
if (existsSync20(file3)) {
|
|
199215
199595
|
unlinkSync7(file3);
|
|
199216
199596
|
}
|
|
199217
199597
|
} catch {
|
|
@@ -199222,7 +199602,7 @@ class SystemdController {
|
|
|
199222
199602
|
if (opts.purgeLogs) {
|
|
199223
199603
|
const logDir = defaultLogDir();
|
|
199224
199604
|
try {
|
|
199225
|
-
if (
|
|
199605
|
+
if (existsSync20(logDir)) {
|
|
199226
199606
|
rmSync6(logDir, { recursive: true, force: true });
|
|
199227
199607
|
}
|
|
199228
199608
|
} catch {
|
|
@@ -199240,7 +199620,7 @@ class SystemdController {
|
|
|
199240
199620
|
if (stdout === "active") {
|
|
199241
199621
|
return "running";
|
|
199242
199622
|
}
|
|
199243
|
-
if (
|
|
199623
|
+
if (existsSync20(unitPath())) {
|
|
199244
199624
|
return "stopped";
|
|
199245
199625
|
}
|
|
199246
199626
|
return "not-installed";
|
|
@@ -199262,7 +199642,7 @@ __export(exports_schtasks, {
|
|
|
199262
199642
|
});
|
|
199263
199643
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
199264
199644
|
import { Buffer as Buffer2 } from "buffer";
|
|
199265
|
-
import { existsSync as
|
|
199645
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync16, writeFileSync as writeFileSync12, rmSync as rmSync7 } from "fs";
|
|
199266
199646
|
import { join as join18 } from "path";
|
|
199267
199647
|
import { homedir as homedir6, tmpdir } from "os";
|
|
199268
199648
|
function launcherPath() {
|
|
@@ -199404,7 +199784,7 @@ function buildScheduledTaskXml(invisibleVbs, userId) {
|
|
|
199404
199784
|
function writeTaskXml(xml) {
|
|
199405
199785
|
const xmlPath = join18(tmpdir(), `ghost-task-${process.pid}.xml`);
|
|
199406
199786
|
const bom = Buffer2.from([255, 254]);
|
|
199407
|
-
|
|
199787
|
+
writeFileSync12(xmlPath, Buffer2.concat([bom, Buffer2.from(xml, "utf16le")]));
|
|
199408
199788
|
return xmlPath;
|
|
199409
199789
|
}
|
|
199410
199790
|
function killOrphanedSupervisorChain() {
|
|
@@ -199438,17 +199818,17 @@ class SchtasksController {
|
|
|
199438
199818
|
}
|
|
199439
199819
|
ensureLogDir(opts.logDir);
|
|
199440
199820
|
const stateDir = join18(homedir6(), ".ghost", "state");
|
|
199441
|
-
if (!
|
|
199442
|
-
|
|
199821
|
+
if (!existsSync21(stateDir)) {
|
|
199822
|
+
mkdirSync16(stateDir, { recursive: true });
|
|
199443
199823
|
}
|
|
199444
199824
|
const legacy = legacyStartupPath();
|
|
199445
|
-
if (
|
|
199825
|
+
if (existsSync21(legacy)) {
|
|
199446
199826
|
rmSync7(legacy, RM_RETRY_OPTS);
|
|
199447
199827
|
}
|
|
199448
199828
|
const launcher = launcherPath();
|
|
199449
|
-
|
|
199829
|
+
writeFileSync12(launcher, buildLauncherCmd(opts.bunPath, opts.execPath, opts.env), { encoding: "utf8" });
|
|
199450
199830
|
const invisibleVbs = invisibleLauncherPath();
|
|
199451
|
-
|
|
199831
|
+
writeFileSync12(invisibleVbs, buildInvisibleVbs(launcher), { encoding: "utf8" });
|
|
199452
199832
|
const create4 = createScheduledTask(invisibleVbs, taskUser);
|
|
199453
199833
|
if (create4.status !== 0) {
|
|
199454
199834
|
return {
|
|
@@ -199493,20 +199873,20 @@ class SchtasksController {
|
|
|
199493
199873
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
199494
199874
|
schtasks(["/Delete", "/F", "/TN", TASK_NAME]);
|
|
199495
199875
|
const launcher = launcherPath();
|
|
199496
|
-
if (
|
|
199876
|
+
if (existsSync21(launcher)) {
|
|
199497
199877
|
rmSync7(launcher, RM_RETRY_OPTS);
|
|
199498
199878
|
}
|
|
199499
199879
|
const invisibleVbs = invisibleLauncherPath();
|
|
199500
|
-
if (
|
|
199880
|
+
if (existsSync21(invisibleVbs)) {
|
|
199501
199881
|
rmSync7(invisibleVbs, RM_RETRY_OPTS);
|
|
199502
199882
|
}
|
|
199503
199883
|
const legacy = legacyStartupPath();
|
|
199504
|
-
if (
|
|
199884
|
+
if (existsSync21(legacy)) {
|
|
199505
199885
|
rmSync7(legacy, RM_RETRY_OPTS);
|
|
199506
199886
|
}
|
|
199507
199887
|
if (opts.purgeLogs) {
|
|
199508
199888
|
const logDir = defaultLogDir();
|
|
199509
|
-
if (
|
|
199889
|
+
if (existsSync21(logDir)) {
|
|
199510
199890
|
rmSync7(logDir, { recursive: true, ...RM_RETRY_OPTS });
|
|
199511
199891
|
}
|
|
199512
199892
|
}
|
|
@@ -212398,7 +212778,7 @@ function handleHealth() {
|
|
|
212398
212778
|
}
|
|
212399
212779
|
|
|
212400
212780
|
// src/gateway/static.ts
|
|
212401
|
-
import { existsSync as
|
|
212781
|
+
import { existsSync as existsSync22 } from "fs";
|
|
212402
212782
|
import { join as join20, extname as extname3 } from "path";
|
|
212403
212783
|
function mime2(path4) {
|
|
212404
212784
|
return MIME[extname3(path4).toLowerCase()] ?? "application/octet-stream";
|
|
@@ -212406,7 +212786,7 @@ function mime2(path4) {
|
|
|
212406
212786
|
function resolveWebDist(candidates) {
|
|
212407
212787
|
const list = candidates ?? defaultWebDistCandidates();
|
|
212408
212788
|
for (const c4 of list) {
|
|
212409
|
-
if (
|
|
212789
|
+
if (existsSync22(join20(c4, "index.html")))
|
|
212410
212790
|
return c4;
|
|
212411
212791
|
}
|
|
212412
212792
|
return null;
|
|
@@ -212661,7 +213041,7 @@ function semverGt(a, b5) {
|
|
|
212661
213041
|
}
|
|
212662
213042
|
|
|
212663
213043
|
// src/update/version.ts
|
|
212664
|
-
import { readFileSync as
|
|
213044
|
+
import { readFileSync as readFileSync16, existsSync as existsSync23 } from "fs";
|
|
212665
213045
|
import { join as join21 } from "path";
|
|
212666
213046
|
function resolvePackageJsonPath(candidates) {
|
|
212667
213047
|
const list = candidates ?? [
|
|
@@ -212670,7 +213050,7 @@ function resolvePackageJsonPath(candidates) {
|
|
|
212670
213050
|
join21(process.cwd(), "package.json")
|
|
212671
213051
|
];
|
|
212672
213052
|
for (const p2 of list) {
|
|
212673
|
-
if (
|
|
213053
|
+
if (existsSync23(p2))
|
|
212674
213054
|
return p2;
|
|
212675
213055
|
}
|
|
212676
213056
|
return null;
|
|
@@ -212692,7 +213072,7 @@ function getCurrentVersion(pkgPath) {
|
|
|
212692
213072
|
if (!resolved)
|
|
212693
213073
|
return UNKNOWN_VERSION;
|
|
212694
213074
|
try {
|
|
212695
|
-
const pkg = JSON.parse(
|
|
213075
|
+
const pkg = JSON.parse(readFileSync16(resolved, "utf-8"));
|
|
212696
213076
|
if (pkg.version && pkg.version.length > 0)
|
|
212697
213077
|
return pkg.version;
|
|
212698
213078
|
} catch {}
|
|
@@ -212749,14 +213129,14 @@ var init_status = __esm(() => {
|
|
|
212749
213129
|
});
|
|
212750
213130
|
|
|
212751
213131
|
// src/gateway/memory.ts
|
|
212752
|
-
import { readFileSync as
|
|
213132
|
+
import { readFileSync as readFileSync17, existsSync as existsSync24 } from "fs";
|
|
212753
213133
|
function registerMemoryMethods(register, deps) {
|
|
212754
213134
|
register("memory.get", async () => {
|
|
212755
213135
|
const memory = deps.memoryStore.readLongTerm();
|
|
212756
213136
|
let history = "";
|
|
212757
|
-
if (
|
|
213137
|
+
if (existsSync24(deps.memoryStore.historyFile)) {
|
|
212758
213138
|
try {
|
|
212759
|
-
history =
|
|
213139
|
+
history = readFileSync17(deps.memoryStore.historyFile, "utf-8");
|
|
212760
213140
|
} catch {}
|
|
212761
213141
|
}
|
|
212762
213142
|
return { memory, history };
|
|
@@ -212919,6 +213299,22 @@ function registerCronMethods(register, deps) {
|
|
|
212919
213299
|
});
|
|
212920
213300
|
}
|
|
212921
213301
|
|
|
213302
|
+
// src/gateway/config.ts
|
|
213303
|
+
function registerConfigMethods(register, deps) {
|
|
213304
|
+
register("config.timezone.get", async () => ({
|
|
213305
|
+
tz: deps.timezoneService.get()
|
|
213306
|
+
}));
|
|
213307
|
+
register("config.timezone.set", async (_ctx, payload) => {
|
|
213308
|
+
const p2 = payload;
|
|
213309
|
+
const result = deps.timezoneService.set(p2.tz);
|
|
213310
|
+
if (!result.ok) {
|
|
213311
|
+
return { ok: false, error: result.error };
|
|
213312
|
+
}
|
|
213313
|
+
const updatedJobs = deps.cronService.updateBuiltinJobsTimezone(result.tz);
|
|
213314
|
+
return { ok: true, tz: result.tz, updatedJobs };
|
|
213315
|
+
});
|
|
213316
|
+
}
|
|
213317
|
+
|
|
212922
213318
|
// src/gateway/route-orchestrator-error.ts
|
|
212923
213319
|
function routeOrchestratorError(runId, classified, emit) {
|
|
212924
213320
|
if (classified.type === "TOOL_BLOCKED") {
|
|
@@ -214902,11 +215298,12 @@ class TokensSnapshotService {
|
|
|
214902
215298
|
this.priceCache = priceCache;
|
|
214903
215299
|
}
|
|
214904
215300
|
build() {
|
|
214905
|
-
const
|
|
215301
|
+
const assets = this.client.getAllAssets();
|
|
214906
215302
|
const prices = {};
|
|
214907
215303
|
const prevDayPrices = {};
|
|
214908
215304
|
const maxLeverages = {};
|
|
214909
|
-
|
|
215305
|
+
const tokens = [];
|
|
215306
|
+
for (const { symbol: symbol5, isDelisted } of assets) {
|
|
214910
215307
|
const entry = this.priceCache.get(symbol5, 30000);
|
|
214911
215308
|
if (entry) {
|
|
214912
215309
|
prices[symbol5] = entry.price;
|
|
@@ -214916,8 +215313,9 @@ class TokensSnapshotService {
|
|
|
214916
215313
|
const lev = this.client.getMaxLeverage(symbol5);
|
|
214917
215314
|
if (typeof lev === "number" && lev > 0)
|
|
214918
215315
|
maxLeverages[symbol5] = lev;
|
|
215316
|
+
tokens.push(isDelisted ? { symbol: symbol5, isDelisted: true } : { symbol: symbol5 });
|
|
214919
215317
|
}
|
|
214920
|
-
tokens.sort();
|
|
215318
|
+
tokens.sort((a, b5) => a.symbol.localeCompare(b5.symbol));
|
|
214921
215319
|
return { tokens, prices, prevDayPrices, maxLeverages };
|
|
214922
215320
|
}
|
|
214923
215321
|
}
|
|
@@ -215045,6 +215443,10 @@ function createGateway(gatewayConfig, deps) {
|
|
|
215045
215443
|
registerToolsMethods(registry4.register.bind(registry4), { tools: deps.tools });
|
|
215046
215444
|
registerSessionsMethods(registry4.register.bind(registry4), { sessionManager: deps.sessionManager });
|
|
215047
215445
|
registerCronMethods(registry4.register.bind(registry4), { cronService: deps.cronService });
|
|
215446
|
+
registerConfigMethods(registry4.register.bind(registry4), {
|
|
215447
|
+
timezoneService: deps.timezoneService,
|
|
215448
|
+
cronService: deps.cronService
|
|
215449
|
+
});
|
|
215048
215450
|
const tokensSnapshot = new TokensSnapshotService(deps.tradingClient, deps.priceCache);
|
|
215049
215451
|
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
215452
|
registerApprovalMethods(registry4.register.bind(registry4), { approvalManager: deps.approvalManager });
|
|
@@ -216077,6 +216479,7 @@ async function startDaemon(options) {
|
|
|
216077
216479
|
tweetService,
|
|
216078
216480
|
xFollowService,
|
|
216079
216481
|
preferenceStore,
|
|
216482
|
+
timezoneService,
|
|
216080
216483
|
security: security2,
|
|
216081
216484
|
leakDetector,
|
|
216082
216485
|
skillService,
|
|
@@ -216122,6 +216525,7 @@ async function startDaemon(options) {
|
|
|
216122
216525
|
tools,
|
|
216123
216526
|
sessionManager,
|
|
216124
216527
|
cronService,
|
|
216528
|
+
timezoneService,
|
|
216125
216529
|
configPath,
|
|
216126
216530
|
channels: runtime.channelManager.listChannels().map((ch2) => ({ name: ch2.name })),
|
|
216127
216531
|
tradingClient,
|
|
@@ -216163,7 +216567,7 @@ async function startDaemon(options) {
|
|
|
216163
216567
|
}));
|
|
216164
216568
|
runtime.channelManager.startAllChannels();
|
|
216165
216569
|
if (config3.cron.enableScheduler) {
|
|
216166
|
-
cronService.start();
|
|
216570
|
+
cronService.start({ defaults: buildBuiltInJobs(timezoneService.get()) });
|
|
216167
216571
|
}
|
|
216168
216572
|
const runner = new BackgroundJobRunner({
|
|
216169
216573
|
taskAgent: runtime.taskAgent,
|
|
@@ -216206,6 +216610,7 @@ var init_daemon = __esm(() => {
|
|
|
216206
216610
|
init_plugin();
|
|
216207
216611
|
init_types5();
|
|
216208
216612
|
init_pairing_events();
|
|
216613
|
+
init_defaults();
|
|
216209
216614
|
});
|
|
216210
216615
|
|
|
216211
216616
|
// node_modules/colorette/index.cjs
|
|
@@ -218831,7 +219236,7 @@ __export(exports_uninstall, {
|
|
|
218831
219236
|
WIN_HANDLE_RELEASE_MS: () => WIN_HANDLE_RELEASE_MS,
|
|
218832
219237
|
SIGKILL_DELAY_MS: () => SIGKILL_DELAY_MS
|
|
218833
219238
|
});
|
|
218834
|
-
import { existsSync as fsExistsSync, readFileSync as
|
|
219239
|
+
import { existsSync as fsExistsSync, readFileSync as readFileSync19, writeFileSync as writeFileSync14, unlinkSync as unlinkSync9, rmSync as fsRmSync } from "fs";
|
|
218835
219240
|
import { join as join22 } from "path";
|
|
218836
219241
|
import { homedir as homedir7 } from "os";
|
|
218837
219242
|
async function runUninstall(deps) {
|
|
@@ -219157,8 +219562,8 @@ async function runUninstallCli() {
|
|
|
219157
219562
|
return !isCancel(r2) && r2 === true;
|
|
219158
219563
|
},
|
|
219159
219564
|
existsSync: fsExistsSync,
|
|
219160
|
-
readFile: (p2) =>
|
|
219161
|
-
writeFile: (p2, content) =>
|
|
219565
|
+
readFile: (p2) => readFileSync19(p2, "utf8"),
|
|
219566
|
+
writeFile: (p2, content) => writeFileSync14(p2, content, "utf8"),
|
|
219162
219567
|
unlink: (p2) => unlinkSync9(p2),
|
|
219163
219568
|
rmSync: (p2) => fsRmSync(p2, { recursive: true, force: true, maxRetries: 10, retryDelay: 200 }),
|
|
219164
219569
|
spawn: (cmd, args) => {
|
|
@@ -219614,7 +220019,7 @@ init_cli_providers();
|
|
|
219614
220019
|
|
|
219615
220020
|
// src/onboard/wizard.ts
|
|
219616
220021
|
init_dist8();
|
|
219617
|
-
import { existsSync as
|
|
220022
|
+
import { existsSync as existsSync27 } from "fs";
|
|
219618
220023
|
init_providers();
|
|
219619
220024
|
init_oauth3();
|
|
219620
220025
|
init_secrets();
|
|
@@ -219628,7 +220033,7 @@ init_dist8();
|
|
|
219628
220033
|
init_dist8();
|
|
219629
220034
|
init_utils8();
|
|
219630
220035
|
init_logs();
|
|
219631
|
-
import { existsSync as
|
|
220036
|
+
import { existsSync as existsSync25 } from "fs";
|
|
219632
220037
|
|
|
219633
220038
|
// src/onboard/steps/service.ts
|
|
219634
220039
|
async function runServiceStep(deps) {
|
|
@@ -219723,7 +220128,7 @@ async function finalizeOnboard(opts) {
|
|
|
219723
220128
|
}
|
|
219724
220129
|
const execPath = resolveGhostExecPath();
|
|
219725
220130
|
const bunPath = resolveBunPath();
|
|
219726
|
-
if (!
|
|
220131
|
+
if (!existsSync25(execPath)) {
|
|
219727
220132
|
O2.warn(`Ghost executable not found at ${execPath}. Service may fail to start.`);
|
|
219728
220133
|
}
|
|
219729
220134
|
const result = await runServiceStep({
|
|
@@ -219799,22 +220204,22 @@ async function startForegroundDaemon(logger) {
|
|
|
219799
220204
|
init_models_config();
|
|
219800
220205
|
import {
|
|
219801
220206
|
chmodSync,
|
|
219802
|
-
existsSync as
|
|
219803
|
-
mkdirSync as
|
|
219804
|
-
readFileSync as
|
|
220207
|
+
existsSync as existsSync26,
|
|
220208
|
+
mkdirSync as mkdirSync17,
|
|
220209
|
+
readFileSync as readFileSync18,
|
|
219805
220210
|
renameSync as renameSync4,
|
|
219806
220211
|
unlinkSync as unlinkSync8,
|
|
219807
|
-
writeFileSync as
|
|
220212
|
+
writeFileSync as writeFileSync13
|
|
219808
220213
|
} from "fs";
|
|
219809
|
-
import { dirname as
|
|
220214
|
+
import { dirname as dirname9 } from "path";
|
|
219810
220215
|
var MODELS_FILE_MODE = 384;
|
|
219811
220216
|
var MODELS_DIR_MODE = 448;
|
|
219812
220217
|
function readModelsConfig(path4) {
|
|
219813
|
-
if (!
|
|
220218
|
+
if (!existsSync26(path4))
|
|
219814
220219
|
return { kind: "missing" };
|
|
219815
220220
|
let raw;
|
|
219816
220221
|
try {
|
|
219817
|
-
raw =
|
|
220222
|
+
raw = readFileSync18(path4, "utf-8");
|
|
219818
220223
|
} catch (err) {
|
|
219819
220224
|
return { kind: "malformed", reason: describeError2(err) };
|
|
219820
220225
|
}
|
|
@@ -219875,15 +220280,15 @@ function upsertModel(current, incoming) {
|
|
|
219875
220280
|
return next;
|
|
219876
220281
|
}
|
|
219877
220282
|
function writeAtomic(path4, contents) {
|
|
219878
|
-
|
|
220283
|
+
mkdirSync17(dirname9(path4), { recursive: true, mode: MODELS_DIR_MODE });
|
|
219879
220284
|
const tmp = `${path4}.tmp-${process.pid}-${Date.now()}`;
|
|
219880
220285
|
try {
|
|
219881
|
-
|
|
220286
|
+
writeFileSync13(tmp, contents, { mode: MODELS_FILE_MODE });
|
|
219882
220287
|
chmodSync(tmp, MODELS_FILE_MODE);
|
|
219883
220288
|
renameSync4(tmp, path4);
|
|
219884
220289
|
} catch (err) {
|
|
219885
220290
|
try {
|
|
219886
|
-
if (
|
|
220291
|
+
if (existsSync26(tmp))
|
|
219887
220292
|
unlinkSync8(tmp);
|
|
219888
220293
|
} catch {}
|
|
219889
220294
|
throw err;
|
|
@@ -219909,6 +220314,22 @@ function applyUpdateModeChanges(existing, overlay) {
|
|
|
219909
220314
|
}
|
|
219910
220315
|
|
|
219911
220316
|
// src/onboard/wizard.ts
|
|
220317
|
+
init_timezone();
|
|
220318
|
+
init_database();
|
|
220319
|
+
init_db();
|
|
220320
|
+
init_registry2();
|
|
220321
|
+
async function persistTimezone(tz, logger) {
|
|
220322
|
+
try {
|
|
220323
|
+
const db2 = initDatabase(getDbPath());
|
|
220324
|
+
await runDbMigrations(db2, DB_MIGRATIONS);
|
|
220325
|
+
const prefs = new PreferenceStore(db2, logger.child({ module: "prefs" }));
|
|
220326
|
+
const tzService = createTimezoneService(prefs);
|
|
220327
|
+
tzService.set(tz);
|
|
220328
|
+
db2.close();
|
|
220329
|
+
} catch (err) {
|
|
220330
|
+
logger.warn({ err }, "onboard: failed to persist timezone");
|
|
220331
|
+
}
|
|
220332
|
+
}
|
|
219912
220333
|
function validateCustomProviderName(name) {
|
|
219913
220334
|
if (!name)
|
|
219914
220335
|
return "Provider name is required.";
|
|
@@ -219923,31 +220344,7 @@ function validateCustomProviderName(name) {
|
|
|
219923
220344
|
function isLocalBaseUrl(url3) {
|
|
219924
220345
|
return /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?(\/|$)/u.test(url3);
|
|
219925
220346
|
}
|
|
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;
|
|
220347
|
+
function providerRequiresApiKey(_providerId, supportsOAuth) {
|
|
219951
220348
|
if (supportsOAuth)
|
|
219952
220349
|
return false;
|
|
219953
220350
|
return true;
|
|
@@ -219975,6 +220372,8 @@ async function runHeadless(headless, daemonOptions) {
|
|
|
219975
220372
|
if (daemonOptions.paper)
|
|
219976
220373
|
customConfig.paper = daemonOptions.paper;
|
|
219977
220374
|
saveConfig(customConfig, configPath);
|
|
220375
|
+
const tzForCustom = resolveHeadlessTz(daemonOptions.logger);
|
|
220376
|
+
await persistTimezone(tzForCustom, daemonOptions.logger);
|
|
219978
220377
|
console.log(`[ghost] Custom provider: ${headless.provider} (from models.json)`);
|
|
219979
220378
|
console.log(`[ghost] Model: ${modelTrimmed}`);
|
|
219980
220379
|
if (daemonOptions?.paper) {
|
|
@@ -220050,8 +220449,11 @@ async function runHeadless(headless, daemonOptions) {
|
|
|
220050
220449
|
await credentials2.set("api_key", apiKey);
|
|
220051
220450
|
}
|
|
220052
220451
|
saveConfig(config3, configPath);
|
|
220452
|
+
const tz = resolveHeadlessTz(daemonOptions.logger);
|
|
220453
|
+
await persistTimezone(tz, daemonOptions.logger);
|
|
220053
220454
|
console.log(`[ghost] Provider: ${providerInfo.label} (${headless.provider})`);
|
|
220054
220455
|
console.log(`[ghost] Model: ${model}`);
|
|
220456
|
+
console.log(`[ghost] Timezone: ${tz}`);
|
|
220055
220457
|
if (daemonOptions?.paper) {
|
|
220056
220458
|
console.log(`[ghost] Mode: Paper trading (${daemonOptions.paper.initialBalance ?? 1e4} USDC)`);
|
|
220057
220459
|
}
|
|
@@ -220059,6 +220461,18 @@ async function runHeadless(headless, daemonOptions) {
|
|
|
220059
220461
|
console.log("[ghost] Config saved. Run 'ghost onboard --service' to register the auto-start service, or 'ghost daemon' to start manually.");
|
|
220060
220462
|
console.log("[ghost] Onboard complete!");
|
|
220061
220463
|
}
|
|
220464
|
+
function resolveHeadlessTz(logger) {
|
|
220465
|
+
const envTz = process.env["GHOST_TIMEZONE"];
|
|
220466
|
+
if (envTz) {
|
|
220467
|
+
const result = validateTimezone(envTz);
|
|
220468
|
+
if (!result.ok) {
|
|
220469
|
+
console.error(`[ghost] GHOST_TIMEZONE="${envTz}" is invalid: ${result.error}`);
|
|
220470
|
+
process.exit(1);
|
|
220471
|
+
}
|
|
220472
|
+
return result.tz;
|
|
220473
|
+
}
|
|
220474
|
+
return detectHostTimezone();
|
|
220475
|
+
}
|
|
220062
220476
|
async function runWizard(daemonOptions) {
|
|
220063
220477
|
if (daemonOptions.headless) {
|
|
220064
220478
|
const { headless, ...rest4 } = daemonOptions;
|
|
@@ -220071,7 +220485,7 @@ async function runWizard(daemonOptions) {
|
|
|
220071
220485
|
const credentials2 = new CredentialStore(getCredentialsPath(), secretStore, daemonOptions.logger.child({ module: "credentials" }));
|
|
220072
220486
|
let config3 = configSchema.parse({});
|
|
220073
220487
|
let mode = "full";
|
|
220074
|
-
if (
|
|
220488
|
+
if (existsSync27(configPath)) {
|
|
220075
220489
|
const modeAnswer = await _t({
|
|
220076
220490
|
message: "Existing config found. What would you like to do?",
|
|
220077
220491
|
options: [
|
|
@@ -220090,7 +220504,7 @@ async function runWizard(daemonOptions) {
|
|
|
220090
220504
|
This wizard will configure your agent in under 60 seconds.`);
|
|
220091
220505
|
if (mode === "full" && !daemonOptions.paper) {
|
|
220092
220506
|
const tradingMode = await _t({
|
|
220093
|
-
message: "Step 1/
|
|
220507
|
+
message: "Step 1/5 \u2014 Select trading mode",
|
|
220094
220508
|
options: [
|
|
220095
220509
|
{ value: "paper", label: "Paper trading (simulated, safe to explore)", hint: "10,000 USDC starting balance" },
|
|
220096
220510
|
{ value: "live", label: "Live trading (real funds on Hyperliquid)" }
|
|
@@ -220108,11 +220522,11 @@ This wizard will configure your agent in under 60 seconds.`);
|
|
|
220108
220522
|
const providers = getProviderList();
|
|
220109
220523
|
const providerOptions = providers.map((p2) => ({
|
|
220110
220524
|
value: p2.id,
|
|
220111
|
-
label: p2.label
|
|
220525
|
+
label: `${p2.label} \u2014 ${p2.tierLabel}`,
|
|
220112
220526
|
hint: p2.description
|
|
220113
220527
|
}));
|
|
220114
220528
|
const providerId = await _t({
|
|
220115
|
-
message: "Step 2/
|
|
220529
|
+
message: "Step 2/5 \u2014 Select your AI provider",
|
|
220116
220530
|
options: providerOptions
|
|
220117
220531
|
});
|
|
220118
220532
|
if (q(providerId)) {
|
|
@@ -220123,18 +220537,6 @@ This wizard will configure your agent in under 60 seconds.`);
|
|
|
220123
220537
|
let authMethod = "apikey";
|
|
220124
220538
|
let customProviderName = "";
|
|
220125
220539
|
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
220540
|
if (providerId === "custom") {
|
|
220139
220541
|
const nameAnswer = await Ot({
|
|
220140
220542
|
message: "Provider name (identifier for ~/.ghost/models.json)",
|
|
@@ -220181,7 +220583,7 @@ This wizard will configure your agent in under 60 seconds.`);
|
|
|
220181
220583
|
{ value: "__custom__", label: "Custom model ID (type manually)" }
|
|
220182
220584
|
];
|
|
220183
220585
|
const selected = await _t({
|
|
220184
|
-
message: "Step 3/
|
|
220586
|
+
message: "Step 3/5 \u2014 Select your default model",
|
|
220185
220587
|
options: modelOptions
|
|
220186
220588
|
});
|
|
220187
220589
|
if (q(selected)) {
|
|
@@ -220200,7 +220602,7 @@ This wizard will configure your agent in under 60 seconds.`);
|
|
|
220200
220602
|
}
|
|
220201
220603
|
} else {
|
|
220202
220604
|
const manual = await Ot({
|
|
220203
|
-
message: "Step 3/
|
|
220605
|
+
message: "Step 3/5 \u2014 Enter model ID",
|
|
220204
220606
|
placeholder: "e.g. claude-sonnet-4-6"
|
|
220205
220607
|
});
|
|
220206
220608
|
if (q(manual)) {
|
|
@@ -220213,7 +220615,7 @@ This wizard will configure your agent in under 60 seconds.`);
|
|
|
220213
220615
|
let apiKey = "";
|
|
220214
220616
|
if (providerInfo?.supportsOAuth && authMethod !== "skip") {
|
|
220215
220617
|
const auth = await _t({
|
|
220216
|
-
message: "Step 4/
|
|
220618
|
+
message: "Step 4/5 \u2014 How do you want to authenticate?",
|
|
220217
220619
|
options: [
|
|
220218
220620
|
{ value: "oauth", label: "OAuth Login (authenticate in browser)", hint: "recommended" },
|
|
220219
220621
|
{ value: "apikey", label: "API Key (paste your key)" },
|
|
@@ -220249,7 +220651,7 @@ This wizard will configure your agent in under 60 seconds.`);
|
|
|
220249
220651
|
const keyUrl = providerInfo?.apiKeyUrl ? `
|
|
220250
220652
|
Get your key at: ${providerInfo.apiKeyUrl}` : "";
|
|
220251
220653
|
const key = await Ot({
|
|
220252
|
-
message: `Step 4/
|
|
220654
|
+
message: `Step 4/5 \u2014 Paste your ${providerInfo?.label ?? providerId} API key${keyUrl}`,
|
|
220253
220655
|
placeholder: "sk-...",
|
|
220254
220656
|
validate: (v4) => !v4 || v4.length >= 5 ? undefined : "API key seems too short"
|
|
220255
220657
|
});
|
|
@@ -220259,7 +220661,7 @@ This wizard will configure your agent in under 60 seconds.`);
|
|
|
220259
220661
|
}
|
|
220260
220662
|
apiKey = key;
|
|
220261
220663
|
}
|
|
220262
|
-
if (authMethod === "skip" && providerId !== "
|
|
220664
|
+
if (authMethod === "skip" && providerId !== "custom") {
|
|
220263
220665
|
O2.warn("No API key set. Export GHOST_API_KEY before running ghost daemon.");
|
|
220264
220666
|
}
|
|
220265
220667
|
if (mode === "update") {
|
|
@@ -220317,14 +220719,59 @@ This wizard will configure your agent in under 60 seconds.`);
|
|
|
220317
220719
|
config3.paper = daemonOptions.paper;
|
|
220318
220720
|
}
|
|
220319
220721
|
saveConfig(config3, configPath);
|
|
220722
|
+
const chosenTz = await promptTimezone();
|
|
220723
|
+
await persistTimezone(chosenTz, daemonOptions.logger);
|
|
220320
220724
|
O2.success("Configuration saved.");
|
|
220321
220725
|
if (providerId === "custom") {
|
|
220322
220726
|
O2.info(`Custom provider "${customProviderName}" written to ${getModelsConfigPath()}`);
|
|
220323
220727
|
}
|
|
220728
|
+
O2.info(`Timezone: ${chosenTz}`);
|
|
220324
220729
|
O2.info("Tip: connect channels from the dashboard after starting the daemon.");
|
|
220325
220730
|
console.log("");
|
|
220326
220731
|
await finalizeOnboard({ interactive: true, logger: daemonOptions.logger });
|
|
220327
220732
|
}
|
|
220733
|
+
function listSupportedTimezones() {
|
|
220734
|
+
const fn = Intl.supportedValuesOf;
|
|
220735
|
+
if (typeof fn !== "function")
|
|
220736
|
+
return [];
|
|
220737
|
+
return [...fn("timeZone")].sort();
|
|
220738
|
+
}
|
|
220739
|
+
async function promptTimezone() {
|
|
220740
|
+
const detected = detectHostTimezone();
|
|
220741
|
+
const allZones = listSupportedTimezones();
|
|
220742
|
+
if (allZones.length === 0) {
|
|
220743
|
+
const entered = await Ot({
|
|
220744
|
+
message: "Step 5/5 \u2014 IANA timezone (e.g. America/New_York):",
|
|
220745
|
+
initialValue: detected,
|
|
220746
|
+
validate(value2) {
|
|
220747
|
+
const v4 = validateTimezone(value2);
|
|
220748
|
+
return v4.ok ? undefined : v4.error;
|
|
220749
|
+
}
|
|
220750
|
+
});
|
|
220751
|
+
if (q(entered)) {
|
|
220752
|
+
pt("Setup cancelled.");
|
|
220753
|
+
process.exit(0);
|
|
220754
|
+
}
|
|
220755
|
+
const result = validateTimezone(entered);
|
|
220756
|
+
return result.ok ? result.tz : detected;
|
|
220757
|
+
}
|
|
220758
|
+
const initialValue = allZones.includes(detected) ? detected : allZones[0];
|
|
220759
|
+
const choice = await Ae2({
|
|
220760
|
+
message: "Step 5/5 \u2014 Select your timezone (type to filter)",
|
|
220761
|
+
placeholder: "e.g. berlin, new_york, utc",
|
|
220762
|
+
options: allZones.map((tz) => ({
|
|
220763
|
+
value: tz,
|
|
220764
|
+
label: tz === detected ? `${tz} (detected)` : tz
|
|
220765
|
+
})),
|
|
220766
|
+
initialValue,
|
|
220767
|
+
maxItems: 10
|
|
220768
|
+
});
|
|
220769
|
+
if (q(choice)) {
|
|
220770
|
+
pt("Setup cancelled.");
|
|
220771
|
+
process.exit(0);
|
|
220772
|
+
}
|
|
220773
|
+
return choice;
|
|
220774
|
+
}
|
|
220328
220775
|
// src/index.ts
|
|
220329
220776
|
init_errors2();
|
|
220330
220777
|
init_logger();
|
|
@@ -220555,14 +221002,14 @@ async function runSkills(subArgs, opts) {
|
|
|
220555
221002
|
const configPath = opts.config ?? getPath();
|
|
220556
221003
|
const config3 = loadConfig2(configPath);
|
|
220557
221004
|
const workspaceDir = getWorkspaceDir2();
|
|
220558
|
-
const { existsSync:
|
|
221005
|
+
const { existsSync: existsSync28 } = await import("fs");
|
|
220559
221006
|
const { join: join23 } = await import("path");
|
|
220560
221007
|
let builtinDir;
|
|
220561
221008
|
if (config3.skills.builtinSkillsDir) {
|
|
220562
221009
|
builtinDir = expandHome2(config3.skills.builtinSkillsDir);
|
|
220563
221010
|
} else {
|
|
220564
221011
|
const candidate = join23(import.meta.dir, "skills", "builtin");
|
|
220565
|
-
if (
|
|
221012
|
+
if (existsSync28(candidate))
|
|
220566
221013
|
builtinDir = candidate;
|
|
220567
221014
|
}
|
|
220568
221015
|
const loader2 = new SkillsLoader2(workspaceDir, builtinDir);
|