@bike4mind/cli 0.1.4 → 0.1.5-feat-automate-cli-publishing.16903
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/README.md +58 -1
- package/bin/bike4mind-cli.mjs +21 -0
- package/dist/{artifactExtractor-JZD2HZ6K.js → artifactExtractor-Y5UYA5XK.js} +1 -1
- package/dist/{chunk-EVPT4ARN.js → chunk-G2XBD676.js} +1 -1
- package/dist/{chunk-VVV7WLJ6.js → chunk-PG4BD2XZ.js} +50 -1
- package/dist/{chunk-FNZZAMET.js → chunk-PMPXEVZQ.js} +2 -2
- package/dist/{chunk-ZT7Z4QVD.js → chunk-PYV7BIVP.js} +2 -2
- package/dist/{chunk-43ZKBRTE.js → chunk-ZJBAQHHQ.js} +2 -2
- package/dist/{create-42PUCFSO.js → create-2BDFUWVK.js} +3 -3
- package/dist/index.js +2072 -189
- package/dist/{llmMarkdownGenerator-KV37M3II.js → llmMarkdownGenerator-SPSSOLJI.js} +1 -1
- package/dist/{markdownGenerator-XVTS6PUQ.js → markdownGenerator-ZBS2ID6T.js} +1 -1
- package/dist/{mementoService-ZGZR3QN6.js → mementoService-RHDGBSB3.js} +3 -3
- package/dist/{src-DPL74BDD.js → src-3SNCFJQX.js} +2 -2
- package/dist/{src-2BQJS6GJ.js → src-FPGIEUD3.js} +1 -1
- package/dist/{subtractCredits-3GIBRYWF.js → subtractCredits-D7M2BCM2.js} +3 -3
- package/package.json +10 -7
package/dist/index.js
CHANGED
|
@@ -4,9 +4,9 @@ import {
|
|
|
4
4
|
getEffectiveApiKey,
|
|
5
5
|
getOpenWeatherKey,
|
|
6
6
|
getSerperKey
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-ZJBAQHHQ.js";
|
|
8
|
+
import "./chunk-PMPXEVZQ.js";
|
|
9
|
+
import "./chunk-PYV7BIVP.js";
|
|
10
10
|
import {
|
|
11
11
|
BFLImageService,
|
|
12
12
|
BaseStorage,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
OpenAIBackend,
|
|
16
16
|
OpenAIImageService,
|
|
17
17
|
XAIImageService
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-G2XBD676.js";
|
|
19
19
|
import {
|
|
20
20
|
Logger
|
|
21
21
|
} from "./chunk-CC67R4RB.js";
|
|
@@ -72,7 +72,7 @@ import {
|
|
|
72
72
|
XAI_IMAGE_MODELS,
|
|
73
73
|
b4mLLMTools,
|
|
74
74
|
getMcpProviderMetadata
|
|
75
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-PG4BD2XZ.js";
|
|
76
76
|
import {
|
|
77
77
|
__require
|
|
78
78
|
} from "./chunk-PDX44BCA.js";
|
|
@@ -3636,8 +3636,8 @@ async function processAndStoreImages(images, context) {
|
|
|
3636
3636
|
const buffer = await downloadImage(image);
|
|
3637
3637
|
const fileType = await fileTypeFromBuffer2(buffer);
|
|
3638
3638
|
const filename = `${uuidv45()}.${fileType?.ext}`;
|
|
3639
|
-
const
|
|
3640
|
-
return
|
|
3639
|
+
const path11 = await context.imageGenerateStorage.upload(buffer, filename, {});
|
|
3640
|
+
return path11;
|
|
3641
3641
|
}));
|
|
3642
3642
|
}
|
|
3643
3643
|
async function updateQuestAndReturnMarkdown(storedImageUrls, context) {
|
|
@@ -4112,15 +4112,126 @@ var mermaidChartTool = {
|
|
|
4112
4112
|
};
|
|
4113
4113
|
|
|
4114
4114
|
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/currentDateTime/index.js
|
|
4115
|
+
var parseDate = (dateStr) => {
|
|
4116
|
+
const match = dateStr.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
|
4117
|
+
if (!match) {
|
|
4118
|
+
throw new Error(`Invalid date format: ${dateStr}. Please use YYYY-MM-DD format.`);
|
|
4119
|
+
}
|
|
4120
|
+
const [, year, month, day] = match;
|
|
4121
|
+
return new Date(parseInt(year), parseInt(month) - 1, parseInt(day));
|
|
4122
|
+
};
|
|
4123
|
+
var getDayOfYear = (date) => {
|
|
4124
|
+
const start = new Date(date.getFullYear(), 0, 0);
|
|
4125
|
+
const diff = date.getTime() - start.getTime();
|
|
4126
|
+
const oneDay = 1e3 * 60 * 60 * 24;
|
|
4127
|
+
return Math.floor(diff / oneDay);
|
|
4128
|
+
};
|
|
4129
|
+
var getWeekNumber = (date) => {
|
|
4130
|
+
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
|
|
4131
|
+
const dayNum = d.getUTCDay() || 7;
|
|
4132
|
+
d.setUTCDate(d.getUTCDate() + 4 - dayNum);
|
|
4133
|
+
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
|
|
4134
|
+
return Math.ceil(((d.getTime() - yearStart.getTime()) / 864e5 + 1) / 7);
|
|
4135
|
+
};
|
|
4136
|
+
var getJulianDayNumber = (date) => {
|
|
4137
|
+
const year = date.getFullYear();
|
|
4138
|
+
const month = date.getMonth() + 1;
|
|
4139
|
+
const day = date.getDate();
|
|
4140
|
+
const a = Math.floor((14 - month) / 12);
|
|
4141
|
+
const y = year + 4800 - a;
|
|
4142
|
+
const m = month + 12 * a - 3;
|
|
4143
|
+
return day + Math.floor((153 * m + 2) / 5) + 365 * y + Math.floor(y / 4) - Math.floor(y / 100) + Math.floor(y / 400) - 32045;
|
|
4144
|
+
};
|
|
4145
|
+
var daysBetween = (date1, date2) => {
|
|
4146
|
+
const oneDay = 1e3 * 60 * 60 * 24;
|
|
4147
|
+
const diffTime = date2.getTime() - date1.getTime();
|
|
4148
|
+
return Math.round(diffTime / oneDay);
|
|
4149
|
+
};
|
|
4150
|
+
var getDayOfWeekName = (date) => {
|
|
4151
|
+
const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
4152
|
+
return days[date.getDay()];
|
|
4153
|
+
};
|
|
4154
|
+
var isLeapYear = (year) => {
|
|
4155
|
+
return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
|
|
4156
|
+
};
|
|
4115
4157
|
var getCurrentDateTime = async (parameters = {}) => {
|
|
4116
|
-
const { timezone: timezone2 = "UTC", format = "human", includeTimezone = true, includeWeekday = true } = parameters;
|
|
4158
|
+
const { timezone: timezone2 = "UTC", format = "human", includeTimezone = true, includeWeekday = true, calculate_until, calculate_since, historical_date } = parameters;
|
|
4117
4159
|
try {
|
|
4118
4160
|
const now = /* @__PURE__ */ new Date();
|
|
4119
4161
|
try {
|
|
4120
4162
|
Intl.DateTimeFormat(void 0, { timeZone: timezone2 });
|
|
4121
|
-
} catch
|
|
4163
|
+
} catch {
|
|
4122
4164
|
throw new Error(`Invalid timezone: ${timezone2}. Please use IANA timezone format (e.g., "America/New_York", "Europe/London")`);
|
|
4123
4165
|
}
|
|
4166
|
+
if (historical_date) {
|
|
4167
|
+
const histDate = parseDate(historical_date);
|
|
4168
|
+
const dayName = getDayOfWeekName(histDate);
|
|
4169
|
+
const formattedDate = histDate.toLocaleDateString("en-US", {
|
|
4170
|
+
year: "numeric",
|
|
4171
|
+
month: "long",
|
|
4172
|
+
day: "numeric"
|
|
4173
|
+
});
|
|
4174
|
+
const julianDay = getJulianDayNumber(histDate);
|
|
4175
|
+
const dayOfYear = getDayOfYear(histDate);
|
|
4176
|
+
const weekNum = getWeekNumber(histDate);
|
|
4177
|
+
const leap = isLeapYear(histDate.getFullYear());
|
|
4178
|
+
return `${formattedDate} was a ${dayName}.
|
|
4179
|
+
Day of year: ${dayOfYear}/${leap ? 366 : 365}
|
|
4180
|
+
Week number: ${weekNum}
|
|
4181
|
+
Julian Day Number: ${julianDay}`;
|
|
4182
|
+
}
|
|
4183
|
+
if (calculate_until) {
|
|
4184
|
+
const targetDate = parseDate(calculate_until);
|
|
4185
|
+
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
4186
|
+
const days = daysBetween(today, targetDate);
|
|
4187
|
+
if (days < 0) {
|
|
4188
|
+
return `${calculate_until} was ${Math.abs(days)} days ago.`;
|
|
4189
|
+
} else if (days === 0) {
|
|
4190
|
+
return `${calculate_until} is today!`;
|
|
4191
|
+
} else {
|
|
4192
|
+
const weeks = Math.floor(days / 7);
|
|
4193
|
+
const remainingDays = days % 7;
|
|
4194
|
+
let result = `${days} days until ${calculate_until}`;
|
|
4195
|
+
if (weeks > 0) {
|
|
4196
|
+
result += ` (${weeks} week${weeks > 1 ? "s" : ""}`;
|
|
4197
|
+
if (remainingDays > 0) {
|
|
4198
|
+
result += ` and ${remainingDays} day${remainingDays > 1 ? "s" : ""}`;
|
|
4199
|
+
}
|
|
4200
|
+
result += ")";
|
|
4201
|
+
}
|
|
4202
|
+
return result;
|
|
4203
|
+
}
|
|
4204
|
+
}
|
|
4205
|
+
if (calculate_since) {
|
|
4206
|
+
const startDate = parseDate(calculate_since);
|
|
4207
|
+
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
4208
|
+
const days = daysBetween(startDate, today);
|
|
4209
|
+
if (days < 0) {
|
|
4210
|
+
return `${calculate_since} is ${Math.abs(days)} days in the future.`;
|
|
4211
|
+
} else if (days === 0) {
|
|
4212
|
+
return `${calculate_since} is today!`;
|
|
4213
|
+
} else {
|
|
4214
|
+
const years = Math.floor(days / 365.25);
|
|
4215
|
+
const remainingDays = Math.round(days % 365.25);
|
|
4216
|
+
const weeks = Math.floor(remainingDays / 7);
|
|
4217
|
+
const daysLeft = remainingDays % 7;
|
|
4218
|
+
let result = `${days.toLocaleString()} days since ${calculate_since}`;
|
|
4219
|
+
if (years > 0) {
|
|
4220
|
+
result += ` (${years} year${years > 1 ? "s" : ""}`;
|
|
4221
|
+
if (remainingDays > 0) {
|
|
4222
|
+
result += `, ${remainingDays} day${remainingDays > 1 ? "s" : ""}`;
|
|
4223
|
+
}
|
|
4224
|
+
result += ")";
|
|
4225
|
+
} else if (weeks > 0) {
|
|
4226
|
+
result += ` (${weeks} week${weeks > 1 ? "s" : ""}`;
|
|
4227
|
+
if (daysLeft > 0) {
|
|
4228
|
+
result += ` and ${daysLeft} day${daysLeft > 1 ? "s" : ""}`;
|
|
4229
|
+
}
|
|
4230
|
+
result += ")";
|
|
4231
|
+
}
|
|
4232
|
+
return result;
|
|
4233
|
+
}
|
|
4234
|
+
}
|
|
4124
4235
|
const formatOptions = {
|
|
4125
4236
|
timeZone: timezone2,
|
|
4126
4237
|
year: "numeric",
|
|
@@ -4132,7 +4243,23 @@ var getCurrentDateTime = async (parameters = {}) => {
|
|
|
4132
4243
|
...includeTimezone && { timeZoneName: "short" }
|
|
4133
4244
|
};
|
|
4134
4245
|
switch (format) {
|
|
4135
|
-
case "
|
|
4246
|
+
case "unix":
|
|
4247
|
+
return `Unix timestamp: ${Math.floor(now.getTime() / 1e3)}`;
|
|
4248
|
+
case "day_of_year": {
|
|
4249
|
+
const dayOfYear = getDayOfYear(now);
|
|
4250
|
+
const totalDays = isLeapYear(now.getFullYear()) ? 366 : 365;
|
|
4251
|
+
const daysRemaining = totalDays - dayOfYear;
|
|
4252
|
+
return `Day ${dayOfYear} of ${totalDays} (${daysRemaining} days remaining in ${now.getFullYear()})`;
|
|
4253
|
+
}
|
|
4254
|
+
case "week_number": {
|
|
4255
|
+
const weekNum = getWeekNumber(now);
|
|
4256
|
+
return `Week ${weekNum} of ${now.getFullYear()} (ISO week number)`;
|
|
4257
|
+
}
|
|
4258
|
+
case "julian_day": {
|
|
4259
|
+
const julianDay = getJulianDayNumber(now);
|
|
4260
|
+
return `Julian Day Number: ${julianDay}`;
|
|
4261
|
+
}
|
|
4262
|
+
case "iso": {
|
|
4136
4263
|
const offset = now.getTimezoneOffset() * 6e4;
|
|
4137
4264
|
const localISOTime = new Date(now.getTime() - offset).toISOString();
|
|
4138
4265
|
const formatter = new Intl.DateTimeFormat("en", {
|
|
@@ -4143,10 +4270,12 @@ var getCurrentDateTime = async (parameters = {}) => {
|
|
|
4143
4270
|
const timeZonePart = parts.find((part) => part.type === "timeZoneName");
|
|
4144
4271
|
const timezoneOffset = timeZonePart?.value || "Z";
|
|
4145
4272
|
return `${localISOTime.slice(0, -1)}${timezoneOffset === "GMT" ? "Z" : timezoneOffset}`;
|
|
4146
|
-
|
|
4273
|
+
}
|
|
4274
|
+
case "human": {
|
|
4147
4275
|
const humanFormat = new Intl.DateTimeFormat("en-US", formatOptions);
|
|
4148
4276
|
return humanFormat.format(now);
|
|
4149
|
-
|
|
4277
|
+
}
|
|
4278
|
+
case "detailed": {
|
|
4150
4279
|
const detailedFormat = new Intl.DateTimeFormat("en-US", {
|
|
4151
4280
|
timeZone: timezone2,
|
|
4152
4281
|
weekday: "long",
|
|
@@ -4158,9 +4287,15 @@ var getCurrentDateTime = async (parameters = {}) => {
|
|
|
4158
4287
|
timeZoneName: "long"
|
|
4159
4288
|
});
|
|
4160
4289
|
const formatted = detailedFormat.format(now);
|
|
4161
|
-
|
|
4290
|
+
const dayOfYear = getDayOfYear(now);
|
|
4291
|
+
const weekNum = getWeekNumber(now);
|
|
4292
|
+
const julianDay = getJulianDayNumber(now);
|
|
4293
|
+
const totalDays = isLeapYear(now.getFullYear()) ? 366 : 365;
|
|
4294
|
+
return `It's currently ${formatted}
|
|
4295
|
+
Day ${dayOfYear} of ${totalDays} | Week ${weekNum} | Julian Day ${julianDay}`;
|
|
4296
|
+
}
|
|
4162
4297
|
default:
|
|
4163
|
-
throw new Error(`Unsupported format: ${format}. Supported formats are: iso, human, detailed`);
|
|
4298
|
+
throw new Error(`Unsupported format: ${format}. Supported formats are: iso, human, detailed, unix, day_of_year, week_number, julian_day`);
|
|
4164
4299
|
}
|
|
4165
4300
|
} catch (error) {
|
|
4166
4301
|
if (error instanceof Error) {
|
|
@@ -4186,7 +4321,7 @@ var currentDateTimeTool = {
|
|
|
4186
4321
|
},
|
|
4187
4322
|
toolSchema: {
|
|
4188
4323
|
name: "current_datetime",
|
|
4189
|
-
description: "Get the current date and time
|
|
4324
|
+
description: "Get the current date and time with advanced features. Supports multiple output formats, date calculations (days until/since), historical day lookups, and IANA timezone identifiers.",
|
|
4190
4325
|
parameters: {
|
|
4191
4326
|
type: "object",
|
|
4192
4327
|
properties: {
|
|
@@ -4196,8 +4331,8 @@ var currentDateTimeTool = {
|
|
|
4196
4331
|
},
|
|
4197
4332
|
format: {
|
|
4198
4333
|
type: "string",
|
|
4199
|
-
description: "Output format
|
|
4200
|
-
enum: ["iso", "human", "detailed"]
|
|
4334
|
+
description: "Output format: iso (ISO 8601), human (readable), detailed (with extra info), unix (Unix timestamp), day_of_year (1-366), week_number (ISO week), julian_day (astronomical)",
|
|
4335
|
+
enum: ["iso", "human", "detailed", "unix", "day_of_year", "week_number", "julian_day"]
|
|
4201
4336
|
},
|
|
4202
4337
|
includeTimezone: {
|
|
4203
4338
|
type: "boolean",
|
|
@@ -4206,6 +4341,18 @@ var currentDateTimeTool = {
|
|
|
4206
4341
|
includeWeekday: {
|
|
4207
4342
|
type: "boolean",
|
|
4208
4343
|
description: "Whether to include the day of the week in the output. Defaults to true."
|
|
4344
|
+
},
|
|
4345
|
+
calculate_until: {
|
|
4346
|
+
type: "string",
|
|
4347
|
+
description: 'Calculate days until a future date. Use YYYY-MM-DD format. Example: "2025-12-25" for Christmas countdown.'
|
|
4348
|
+
},
|
|
4349
|
+
calculate_since: {
|
|
4350
|
+
type: "string",
|
|
4351
|
+
description: 'Calculate days since a past date. Use YYYY-MM-DD format. Example: "1990-01-15" for "how long since my birthday".'
|
|
4352
|
+
},
|
|
4353
|
+
historical_date: {
|
|
4354
|
+
type: "string",
|
|
4355
|
+
description: 'Get information about any historical date including day of week, day of year, week number, and Julian Day. Use YYYY-MM-DD format. Example: "1776-07-04".'
|
|
4209
4356
|
}
|
|
4210
4357
|
},
|
|
4211
4358
|
additionalProperties: false,
|
|
@@ -4674,8 +4821,8 @@ async function processAndStoreImage(imageUrl, context) {
|
|
|
4674
4821
|
const buffer = await downloadImage2(imageUrl);
|
|
4675
4822
|
const fileType = await fileTypeFromBuffer3(buffer);
|
|
4676
4823
|
const filename = `${uuidv46()}.${fileType?.ext}`;
|
|
4677
|
-
const
|
|
4678
|
-
return
|
|
4824
|
+
const path11 = await context.imageGenerateStorage.upload(buffer, filename, {});
|
|
4825
|
+
return path11;
|
|
4679
4826
|
}
|
|
4680
4827
|
async function updateQuestAndReturnMarkdown2(storedImagePath, context) {
|
|
4681
4828
|
await context.onFinish?.("edit_image", storedImagePath);
|
|
@@ -5136,121 +5283,1376 @@ function sanitizeJsonString(jsonStr) {
|
|
|
5136
5283
|
default:
|
|
5137
5284
|
result += char;
|
|
5138
5285
|
}
|
|
5139
|
-
} else {
|
|
5140
|
-
result += char;
|
|
5286
|
+
} else {
|
|
5287
|
+
result += char;
|
|
5288
|
+
}
|
|
5289
|
+
i++;
|
|
5290
|
+
}
|
|
5291
|
+
return result;
|
|
5292
|
+
}
|
|
5293
|
+
function parseTransformationResult(llmResponse) {
|
|
5294
|
+
if (!llmResponse || !llmResponse.trim()) {
|
|
5295
|
+
throw new Error("LLM returned an empty response. This may be due to content filtering, rate limiting, or a timeout. Please try again.");
|
|
5296
|
+
}
|
|
5297
|
+
const jsonMatch = llmResponse.match(/```json\s*\n([\s\S]*?)\n```/) || llmResponse.match(/```\s*\n([\s\S]*?)\n```/);
|
|
5298
|
+
let jsonStr = jsonMatch ? jsonMatch[1] : llmResponse;
|
|
5299
|
+
jsonStr = jsonStr.trim();
|
|
5300
|
+
if (!jsonStr) {
|
|
5301
|
+
throw new Error("Could not extract valid JSON from LLM response. The response may have been truncated or malformed.");
|
|
5302
|
+
}
|
|
5303
|
+
jsonStr = sanitizeJsonString(jsonStr);
|
|
5304
|
+
try {
|
|
5305
|
+
const result = JSON.parse(jsonStr);
|
|
5306
|
+
if (!result.title || !result.content) {
|
|
5307
|
+
throw new Error("Missing required fields: title and content");
|
|
5308
|
+
}
|
|
5309
|
+
return {
|
|
5310
|
+
title: result.title,
|
|
5311
|
+
content: result.content,
|
|
5312
|
+
summary: result.summary || "",
|
|
5313
|
+
suggestedTags: result.suggestedTags || []
|
|
5314
|
+
};
|
|
5315
|
+
} catch (error) {
|
|
5316
|
+
console.error("Failed to parse transformation result:", { error, response: llmResponse });
|
|
5317
|
+
throw new Error("Failed to parse transformation result from LLM");
|
|
5318
|
+
}
|
|
5319
|
+
}
|
|
5320
|
+
var blogDraftTool = {
|
|
5321
|
+
name: "blog_draft",
|
|
5322
|
+
implementation: (context) => ({
|
|
5323
|
+
toolFn: async (value) => {
|
|
5324
|
+
const params = value;
|
|
5325
|
+
const { logger: logger2, llm } = context;
|
|
5326
|
+
const outputFormat = params.outputFormat || "blog";
|
|
5327
|
+
logger2.info("Drafting blog content", {
|
|
5328
|
+
userId: context.userId,
|
|
5329
|
+
outputFormat,
|
|
5330
|
+
hasVoiceGuide: !!params.voiceGuide,
|
|
5331
|
+
hasAdditionalInstructions: !!params.additionalInstructions
|
|
5332
|
+
});
|
|
5333
|
+
try {
|
|
5334
|
+
const systemPrompt = buildTransformationPrompt({
|
|
5335
|
+
voiceGuide: params.voiceGuide,
|
|
5336
|
+
outputFormat,
|
|
5337
|
+
additionalInstructions: params.additionalInstructions
|
|
5338
|
+
});
|
|
5339
|
+
const modelToUse = context.model || "claude-sonnet-4-5-20250929";
|
|
5340
|
+
logger2.info("Using model for blog draft:", { model: modelToUse });
|
|
5341
|
+
let llmResponse = "";
|
|
5342
|
+
await llm.complete(modelToUse, [
|
|
5343
|
+
{ role: "system", content: systemPrompt },
|
|
5344
|
+
{
|
|
5345
|
+
role: "user",
|
|
5346
|
+
content: `Transform this content:
|
|
5347
|
+
|
|
5348
|
+
${params.sourceContent}`
|
|
5349
|
+
}
|
|
5350
|
+
], {
|
|
5351
|
+
temperature: 0.7,
|
|
5352
|
+
stream: false
|
|
5353
|
+
}, async (texts) => {
|
|
5354
|
+
llmResponse = texts.filter((t) => t !== null && t !== void 0).join("");
|
|
5355
|
+
});
|
|
5356
|
+
logger2.info("Blog draft complete", { responseLength: llmResponse.length });
|
|
5357
|
+
const result = parseTransformationResult(llmResponse);
|
|
5358
|
+
logger2.info("Blog draft created successfully", {
|
|
5359
|
+
title: result.title,
|
|
5360
|
+
contentLength: result.content.length,
|
|
5361
|
+
tagsCount: result.suggestedTags.length
|
|
5362
|
+
});
|
|
5363
|
+
return `\u2728 Blog draft created successfully!
|
|
5364
|
+
|
|
5365
|
+
\`\`\`json
|
|
5366
|
+
${JSON.stringify(result, null, 2)}
|
|
5367
|
+
\`\`\`
|
|
5368
|
+
|
|
5369
|
+
\u{1F4CB} The preview card will appear below for you to review and edit before publishing.
|
|
5370
|
+
`;
|
|
5371
|
+
} catch (error) {
|
|
5372
|
+
logger2.error("Blog draft creation failed:", error);
|
|
5373
|
+
throw error;
|
|
5374
|
+
}
|
|
5375
|
+
},
|
|
5376
|
+
toolSchema: {
|
|
5377
|
+
name: "blog_draft",
|
|
5378
|
+
description: '\u{1F3AF} PRIMARY TOOL FOR BLOGGING: Use this tool when user wants to publish conversation/content to their blog. Transforms raw content into structured blog post format. ALWAYS use this for phrases like "publish to my blog", "blog this conversation", "create a blog post". Returns JSON that frontend automatically renders as preview card. This is the FIRST STEP - user will review/edit before final publish. DO NOT skip this step.',
|
|
5379
|
+
parameters: {
|
|
5380
|
+
type: "object",
|
|
5381
|
+
properties: {
|
|
5382
|
+
sourceContent: {
|
|
5383
|
+
type: "string",
|
|
5384
|
+
description: "The content to transform into a blog draft. This can be conversation history, article text, notes, etc. Include all relevant context."
|
|
5385
|
+
},
|
|
5386
|
+
voiceGuide: {
|
|
5387
|
+
type: "string",
|
|
5388
|
+
description: "Optional voice/style guide content (markdown text) to apply. This should contain writing style instructions and patterns."
|
|
5389
|
+
},
|
|
5390
|
+
outputFormat: {
|
|
5391
|
+
type: "string",
|
|
5392
|
+
enum: ["blog", "linkedin", "twitter", "newsletter"],
|
|
5393
|
+
description: 'Output format to generate. Currently only "blog" is fully supported. Others are coming soon.'
|
|
5394
|
+
},
|
|
5395
|
+
additionalInstructions: {
|
|
5396
|
+
type: "string",
|
|
5397
|
+
description: 'Optional additional instructions for the draft. Examples: "Make it more technical", "Add code examples", "Focus on business impact"'
|
|
5398
|
+
}
|
|
5399
|
+
},
|
|
5400
|
+
required: ["sourceContent", "outputFormat"]
|
|
5401
|
+
}
|
|
5402
|
+
}
|
|
5403
|
+
})
|
|
5404
|
+
};
|
|
5405
|
+
|
|
5406
|
+
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/wikipediaOnThisDay/index.js
|
|
5407
|
+
var parseMonthDay = (dateStr) => {
|
|
5408
|
+
if (!dateStr) {
|
|
5409
|
+
const now = /* @__PURE__ */ new Date();
|
|
5410
|
+
return {
|
|
5411
|
+
month: String(now.getMonth() + 1).padStart(2, "0"),
|
|
5412
|
+
day: String(now.getDate()).padStart(2, "0")
|
|
5413
|
+
};
|
|
5414
|
+
}
|
|
5415
|
+
const mmddMatch = dateStr.match(/^(\d{1,2})-(\d{1,2})$/);
|
|
5416
|
+
if (mmddMatch) {
|
|
5417
|
+
return {
|
|
5418
|
+
month: mmddMatch[1].padStart(2, "0"),
|
|
5419
|
+
day: mmddMatch[2].padStart(2, "0")
|
|
5420
|
+
};
|
|
5421
|
+
}
|
|
5422
|
+
const fullMatch = dateStr.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/);
|
|
5423
|
+
if (fullMatch) {
|
|
5424
|
+
return {
|
|
5425
|
+
month: fullMatch[2].padStart(2, "0"),
|
|
5426
|
+
day: fullMatch[3].padStart(2, "0")
|
|
5427
|
+
};
|
|
5428
|
+
}
|
|
5429
|
+
throw new Error(`Invalid date format: ${dateStr}. Use MM-DD or YYYY-MM-DD format.`);
|
|
5430
|
+
};
|
|
5431
|
+
var formatEvent = (event) => {
|
|
5432
|
+
return `${event.year}: ${event.text}`;
|
|
5433
|
+
};
|
|
5434
|
+
var filterEvents = (events, yearFilter, decadeFilter) => {
|
|
5435
|
+
if (yearFilter !== void 0) {
|
|
5436
|
+
return events.filter((e) => e.year === yearFilter);
|
|
5437
|
+
}
|
|
5438
|
+
if (decadeFilter !== void 0) {
|
|
5439
|
+
const decadeStart = decadeFilter;
|
|
5440
|
+
const decadeEnd = decadeFilter + 9;
|
|
5441
|
+
return events.filter((e) => e.year >= decadeStart && e.year <= decadeEnd);
|
|
5442
|
+
}
|
|
5443
|
+
return events;
|
|
5444
|
+
};
|
|
5445
|
+
var getWikipediaOnThisDay = async (parameters = {}) => {
|
|
5446
|
+
const { date, type = "selected", limit = 10, year_filter, decade_filter } = parameters;
|
|
5447
|
+
try {
|
|
5448
|
+
const { month, day } = parseMonthDay(date);
|
|
5449
|
+
const url = `https://en.wikipedia.org/api/rest_v1/feed/onthisday/${type}/${month}/${day}`;
|
|
5450
|
+
const response = await fetch(url, {
|
|
5451
|
+
headers: {
|
|
5452
|
+
Accept: "application/json",
|
|
5453
|
+
"User-Agent": "Bike4Mind/1.0 (https://bike4mind.com; contact@bike4mind.com)"
|
|
5454
|
+
}
|
|
5455
|
+
});
|
|
5456
|
+
if (!response.ok) {
|
|
5457
|
+
if (response.status === 404) {
|
|
5458
|
+
throw new Error(`No data available for ${month}-${day}. The date may be invalid.`);
|
|
5459
|
+
}
|
|
5460
|
+
throw new Error(`Wikipedia API error: ${response.status} ${response.statusText}`);
|
|
5461
|
+
}
|
|
5462
|
+
const data = await response.json();
|
|
5463
|
+
const dateLabel = `${parseInt(month)}/${parseInt(day)}`;
|
|
5464
|
+
const results = [];
|
|
5465
|
+
if (type === "all") {
|
|
5466
|
+
if (data.selected?.length) {
|
|
5467
|
+
results.push("**Notable Events:**");
|
|
5468
|
+
const events = filterEvents(data.selected, year_filter, decade_filter).slice(0, Math.ceil(limit / 3));
|
|
5469
|
+
events.forEach((e) => results.push(`- ${formatEvent(e)}`));
|
|
5470
|
+
}
|
|
5471
|
+
if (data.births?.length) {
|
|
5472
|
+
results.push("\n**Notable Births:**");
|
|
5473
|
+
const births = filterEvents(data.births, year_filter, decade_filter).slice(0, Math.ceil(limit / 3));
|
|
5474
|
+
births.forEach((e) => results.push(`- ${formatEvent(e)}`));
|
|
5475
|
+
}
|
|
5476
|
+
if (data.deaths?.length) {
|
|
5477
|
+
results.push("\n**Notable Deaths:**");
|
|
5478
|
+
const deaths = filterEvents(data.deaths, year_filter, decade_filter).slice(0, Math.ceil(limit / 3));
|
|
5479
|
+
deaths.forEach((e) => results.push(`- ${formatEvent(e)}`));
|
|
5480
|
+
}
|
|
5481
|
+
} else if (type === "holidays") {
|
|
5482
|
+
if (data.holidays?.length) {
|
|
5483
|
+
results.push(`**Holidays and Observances on ${dateLabel}:**`);
|
|
5484
|
+
data.holidays.slice(0, limit).forEach((h) => {
|
|
5485
|
+
results.push(`- ${h.text}`);
|
|
5486
|
+
});
|
|
5487
|
+
} else {
|
|
5488
|
+
results.push(`No holidays found for ${dateLabel}.`);
|
|
5489
|
+
}
|
|
5490
|
+
} else {
|
|
5491
|
+
const typeLabels = {
|
|
5492
|
+
selected: "Selected Historical Events",
|
|
5493
|
+
births: "Notable Births",
|
|
5494
|
+
deaths: "Notable Deaths",
|
|
5495
|
+
events: "Historical Events"
|
|
5496
|
+
};
|
|
5497
|
+
const eventData = data[type];
|
|
5498
|
+
if (eventData?.length) {
|
|
5499
|
+
const filtered = filterEvents(eventData, year_filter, decade_filter);
|
|
5500
|
+
const limited = filtered.slice(0, limit);
|
|
5501
|
+
if (limited.length === 0) {
|
|
5502
|
+
const filterDesc = year_filter ? `in ${year_filter}` : decade_filter ? `in the ${decade_filter}s` : "";
|
|
5503
|
+
results.push(`No ${typeLabels[type].toLowerCase()} found for ${dateLabel} ${filterDesc}.`);
|
|
5504
|
+
} else {
|
|
5505
|
+
results.push(`**${typeLabels[type]} on ${dateLabel}:**`);
|
|
5506
|
+
limited.forEach((e) => results.push(`- ${formatEvent(e)}`));
|
|
5507
|
+
if (filtered.length > limit) {
|
|
5508
|
+
results.push(`
|
|
5509
|
+
_...and ${filtered.length - limit} more_`);
|
|
5510
|
+
}
|
|
5511
|
+
}
|
|
5512
|
+
} else {
|
|
5513
|
+
results.push(`No ${typeLabels[type]?.toLowerCase() || "data"} found for ${dateLabel}.`);
|
|
5514
|
+
}
|
|
5515
|
+
}
|
|
5516
|
+
return results.join("\n");
|
|
5517
|
+
} catch (error) {
|
|
5518
|
+
if (error instanceof Error) {
|
|
5519
|
+
throw error;
|
|
5520
|
+
}
|
|
5521
|
+
throw new Error(`Failed to fetch Wikipedia data: ${String(error)}`);
|
|
5522
|
+
}
|
|
5523
|
+
};
|
|
5524
|
+
var wikipediaOnThisDayTool = {
|
|
5525
|
+
name: "wikipedia_on_this_day",
|
|
5526
|
+
implementation: (context) => ({
|
|
5527
|
+
toolFn: async (value) => {
|
|
5528
|
+
const params = value;
|
|
5529
|
+
context.logger.log("\u{1F4C5} WikipediaOnThisDay: Starting execution", params);
|
|
5530
|
+
try {
|
|
5531
|
+
const result = await getWikipediaOnThisDay(params);
|
|
5532
|
+
context.logger.log("\u2705 WikipediaOnThisDay: Execution completed");
|
|
5533
|
+
return result;
|
|
5534
|
+
} catch (error) {
|
|
5535
|
+
context.logger.error("\u274C WikipediaOnThisDay: Execution failed", error);
|
|
5536
|
+
throw error;
|
|
5537
|
+
}
|
|
5538
|
+
},
|
|
5539
|
+
toolSchema: {
|
|
5540
|
+
name: "wikipedia_on_this_day",
|
|
5541
|
+
description: 'Get historical events, births, deaths, and holidays that occurred on a specific date from Wikipedia. Great for "On This Day" features, historical context, and anniversary lookups.',
|
|
5542
|
+
parameters: {
|
|
5543
|
+
type: "object",
|
|
5544
|
+
properties: {
|
|
5545
|
+
date: {
|
|
5546
|
+
type: "string",
|
|
5547
|
+
description: 'The date to look up. Use MM-DD format (e.g., "12-25" for Christmas) or YYYY-MM-DD format. Defaults to today if not specified.'
|
|
5548
|
+
},
|
|
5549
|
+
type: {
|
|
5550
|
+
type: "string",
|
|
5551
|
+
description: 'Type of historical data to retrieve: "selected" (curated notable events), "births" (famous people born), "deaths" (famous people who died), "events" (all historical events), "holidays" (holidays and observances), or "all" (mix of everything).',
|
|
5552
|
+
enum: ["all", "selected", "births", "deaths", "events", "holidays"]
|
|
5553
|
+
},
|
|
5554
|
+
limit: {
|
|
5555
|
+
type: "number",
|
|
5556
|
+
description: "Maximum number of results to return. Defaults to 10."
|
|
5557
|
+
},
|
|
5558
|
+
year_filter: {
|
|
5559
|
+
type: "number",
|
|
5560
|
+
description: "Filter to only show events from a specific year. Example: 1969 to see only events from 1969."
|
|
5561
|
+
},
|
|
5562
|
+
decade_filter: {
|
|
5563
|
+
type: "number",
|
|
5564
|
+
description: "Filter to only show events from a specific decade. Example: 1960 to see events from 1960-1969."
|
|
5565
|
+
}
|
|
5566
|
+
},
|
|
5567
|
+
additionalProperties: false,
|
|
5568
|
+
required: []
|
|
5569
|
+
}
|
|
5570
|
+
}
|
|
5571
|
+
})
|
|
5572
|
+
};
|
|
5573
|
+
|
|
5574
|
+
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/moonPhase/index.js
|
|
5575
|
+
var PHASE_NAMES = [
|
|
5576
|
+
"New Moon",
|
|
5577
|
+
"Waxing Crescent",
|
|
5578
|
+
"First Quarter",
|
|
5579
|
+
"Waxing Gibbous",
|
|
5580
|
+
"Full Moon",
|
|
5581
|
+
"Waning Gibbous",
|
|
5582
|
+
"Last Quarter",
|
|
5583
|
+
"Waning Crescent"
|
|
5584
|
+
];
|
|
5585
|
+
var PHASE_EMOJIS = ["\u{1F311}", "\u{1F312}", "\u{1F313}", "\u{1F314}", "\u{1F315}", "\u{1F316}", "\u{1F317}", "\u{1F318}"];
|
|
5586
|
+
var FULL_MOON_NAMES = {
|
|
5587
|
+
1: "Wolf Moon",
|
|
5588
|
+
2: "Snow Moon",
|
|
5589
|
+
3: "Worm Moon",
|
|
5590
|
+
4: "Pink Moon",
|
|
5591
|
+
5: "Flower Moon",
|
|
5592
|
+
6: "Strawberry Moon",
|
|
5593
|
+
7: "Buck Moon",
|
|
5594
|
+
8: "Sturgeon Moon",
|
|
5595
|
+
9: "Harvest Moon",
|
|
5596
|
+
// or Corn Moon - Harvest Moon is the full moon closest to autumn equinox
|
|
5597
|
+
10: "Hunter's Moon",
|
|
5598
|
+
11: "Beaver Moon",
|
|
5599
|
+
12: "Cold Moon"
|
|
5600
|
+
};
|
|
5601
|
+
var getJulianDate = (date) => {
|
|
5602
|
+
const year = date.getFullYear();
|
|
5603
|
+
const month = date.getMonth() + 1;
|
|
5604
|
+
const day = date.getDate() + date.getHours() / 24 + date.getMinutes() / 1440 + date.getSeconds() / 86400;
|
|
5605
|
+
let y = year;
|
|
5606
|
+
let m = month;
|
|
5607
|
+
if (m <= 2) {
|
|
5608
|
+
y -= 1;
|
|
5609
|
+
m += 12;
|
|
5610
|
+
}
|
|
5611
|
+
const a = Math.floor(y / 100);
|
|
5612
|
+
const b = 2 - a + Math.floor(a / 4);
|
|
5613
|
+
return Math.floor(365.25 * (y + 4716)) + Math.floor(30.6001 * (m + 1)) + day + b - 1524.5;
|
|
5614
|
+
};
|
|
5615
|
+
var getMoonAge = (date) => {
|
|
5616
|
+
const SYNODIC_MONTH = 29.53059;
|
|
5617
|
+
const knownNewMoon = new Date(Date.UTC(2e3, 0, 6, 18, 14, 0));
|
|
5618
|
+
const knownNewMoonJD = getJulianDate(knownNewMoon);
|
|
5619
|
+
const currentJD = getJulianDate(date);
|
|
5620
|
+
const daysSinceKnownNewMoon = currentJD - knownNewMoonJD;
|
|
5621
|
+
let moonAge = daysSinceKnownNewMoon % SYNODIC_MONTH;
|
|
5622
|
+
if (moonAge < 0)
|
|
5623
|
+
moonAge += SYNODIC_MONTH;
|
|
5624
|
+
return moonAge;
|
|
5625
|
+
};
|
|
5626
|
+
var getPhaseIndex = (moonAge) => {
|
|
5627
|
+
const SYNODIC_MONTH = 29.53059;
|
|
5628
|
+
const phaseLength = SYNODIC_MONTH / 8;
|
|
5629
|
+
return Math.floor((moonAge + phaseLength / 2) % SYNODIC_MONTH / phaseLength);
|
|
5630
|
+
};
|
|
5631
|
+
var getIllumination = (moonAge) => {
|
|
5632
|
+
const SYNODIC_MONTH = 29.53059;
|
|
5633
|
+
const phase = moonAge / SYNODIC_MONTH * 2 * Math.PI;
|
|
5634
|
+
const illumination = (1 - Math.cos(phase)) / 2 * 100;
|
|
5635
|
+
return Math.round(illumination * 10) / 10;
|
|
5636
|
+
};
|
|
5637
|
+
var daysUntilPhase = (moonAge, targetPhaseDay) => {
|
|
5638
|
+
const SYNODIC_MONTH = 29.53059;
|
|
5639
|
+
let days = targetPhaseDay - moonAge;
|
|
5640
|
+
if (days < 0)
|
|
5641
|
+
days += SYNODIC_MONTH;
|
|
5642
|
+
return Math.round(days * 10) / 10;
|
|
5643
|
+
};
|
|
5644
|
+
var getNextPhaseDate = (date, targetPhaseDay) => {
|
|
5645
|
+
const moonAge = getMoonAge(date);
|
|
5646
|
+
const daysToAdd = daysUntilPhase(moonAge, targetPhaseDay);
|
|
5647
|
+
const nextDate = new Date(date.getTime() + daysToAdd * 24 * 60 * 60 * 1e3);
|
|
5648
|
+
return nextDate;
|
|
5649
|
+
};
|
|
5650
|
+
var parseDate2 = (dateStr) => {
|
|
5651
|
+
if (!dateStr) {
|
|
5652
|
+
return /* @__PURE__ */ new Date();
|
|
5653
|
+
}
|
|
5654
|
+
const match = dateStr.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
|
5655
|
+
if (!match) {
|
|
5656
|
+
throw new Error(`Invalid date format: ${dateStr}. Please use YYYY-MM-DD format.`);
|
|
5657
|
+
}
|
|
5658
|
+
const [, year, month, day] = match;
|
|
5659
|
+
return new Date(parseInt(year), parseInt(month) - 1, parseInt(day), 12, 0, 0);
|
|
5660
|
+
};
|
|
5661
|
+
var getMoonPhase = async (parameters = {}) => {
|
|
5662
|
+
const { date: dateStr, timezone: timezone2 = "UTC" } = parameters;
|
|
5663
|
+
try {
|
|
5664
|
+
try {
|
|
5665
|
+
Intl.DateTimeFormat(void 0, { timeZone: timezone2 });
|
|
5666
|
+
} catch {
|
|
5667
|
+
throw new Error(`Invalid timezone: ${timezone2}. Please use IANA timezone format (e.g., "America/New_York", "Europe/London")`);
|
|
5668
|
+
}
|
|
5669
|
+
const date = parseDate2(dateStr);
|
|
5670
|
+
const moonAge = getMoonAge(date);
|
|
5671
|
+
const phaseIndex = getPhaseIndex(moonAge);
|
|
5672
|
+
const phaseName = PHASE_NAMES[phaseIndex];
|
|
5673
|
+
const phaseEmoji = PHASE_EMOJIS[phaseIndex];
|
|
5674
|
+
const illumination = getIllumination(moonAge);
|
|
5675
|
+
const SYNODIC_MONTH = 29.53059;
|
|
5676
|
+
const daysToNewMoon = daysUntilPhase(moonAge, 0);
|
|
5677
|
+
const daysToFullMoon = daysUntilPhase(moonAge, SYNODIC_MONTH / 2);
|
|
5678
|
+
const daysToFirstQuarter = daysUntilPhase(moonAge, SYNODIC_MONTH / 4);
|
|
5679
|
+
const daysToLastQuarter = daysUntilPhase(moonAge, 3 * SYNODIC_MONTH / 4);
|
|
5680
|
+
const month = date.getMonth() + 1;
|
|
5681
|
+
const traditionalName = FULL_MOON_NAMES[month];
|
|
5682
|
+
const dateFormatter = new Intl.DateTimeFormat("en-US", {
|
|
5683
|
+
timeZone: timezone2,
|
|
5684
|
+
weekday: "long",
|
|
5685
|
+
year: "numeric",
|
|
5686
|
+
month: "long",
|
|
5687
|
+
day: "numeric"
|
|
5688
|
+
});
|
|
5689
|
+
const results = [];
|
|
5690
|
+
results.push(`${phaseEmoji} **${phaseName}**`);
|
|
5691
|
+
results.push("");
|
|
5692
|
+
results.push(`**Date:** ${dateFormatter.format(date)}`);
|
|
5693
|
+
results.push(`**Moon Age:** ${moonAge.toFixed(1)} days into lunar cycle`);
|
|
5694
|
+
results.push(`**Illumination:** ${illumination}%`);
|
|
5695
|
+
if (phaseIndex === 4) {
|
|
5696
|
+
results.push(`**Traditional Name:** ${traditionalName}`);
|
|
5697
|
+
}
|
|
5698
|
+
results.push("");
|
|
5699
|
+
results.push("**Upcoming Phases:**");
|
|
5700
|
+
if (daysToNewMoon > 0.5) {
|
|
5701
|
+
const nextNewMoon = getNextPhaseDate(date, 0);
|
|
5702
|
+
results.push(`- \u{1F311} New Moon: in ${daysToNewMoon.toFixed(1)} days (${nextNewMoon.toLocaleDateString("en-US", { month: "short", day: "numeric" })})`);
|
|
5703
|
+
}
|
|
5704
|
+
if (daysToFirstQuarter > 0.5 && daysToFirstQuarter < SYNODIC_MONTH - 1) {
|
|
5705
|
+
const nextFirst = getNextPhaseDate(date, SYNODIC_MONTH / 4);
|
|
5706
|
+
results.push(`- \u{1F313} First Quarter: in ${daysToFirstQuarter.toFixed(1)} days (${nextFirst.toLocaleDateString("en-US", { month: "short", day: "numeric" })})`);
|
|
5707
|
+
}
|
|
5708
|
+
if (daysToFullMoon > 0.5) {
|
|
5709
|
+
const nextFull = getNextPhaseDate(date, SYNODIC_MONTH / 2);
|
|
5710
|
+
const nextMonth = nextFull.getMonth() + 1;
|
|
5711
|
+
results.push(`- \u{1F315} Full Moon (${FULL_MOON_NAMES[nextMonth]}): in ${daysToFullMoon.toFixed(1)} days (${nextFull.toLocaleDateString("en-US", { month: "short", day: "numeric" })})`);
|
|
5712
|
+
}
|
|
5713
|
+
if (daysToLastQuarter > 0.5 && daysToLastQuarter < SYNODIC_MONTH - 1) {
|
|
5714
|
+
const nextLast = getNextPhaseDate(date, 3 * SYNODIC_MONTH / 4);
|
|
5715
|
+
results.push(`- \u{1F317} Last Quarter: in ${daysToLastQuarter.toFixed(1)} days (${nextLast.toLocaleDateString("en-US", { month: "short", day: "numeric" })})`);
|
|
5716
|
+
}
|
|
5717
|
+
results.push("");
|
|
5718
|
+
results.push(`_Lunar cycle: ${SYNODIC_MONTH.toFixed(2)} days (synodic month)_`);
|
|
5719
|
+
return results.join("\n");
|
|
5720
|
+
} catch (error) {
|
|
5721
|
+
if (error instanceof Error) {
|
|
5722
|
+
throw error;
|
|
5723
|
+
}
|
|
5724
|
+
throw new Error(`Failed to calculate moon phase: ${String(error)}`);
|
|
5725
|
+
}
|
|
5726
|
+
};
|
|
5727
|
+
var moonPhaseTool = {
|
|
5728
|
+
name: "moon_phase",
|
|
5729
|
+
implementation: (context) => ({
|
|
5730
|
+
toolFn: async (value) => {
|
|
5731
|
+
const params = value;
|
|
5732
|
+
context.logger.log("\u{1F319} MoonPhase: Starting execution", params);
|
|
5733
|
+
try {
|
|
5734
|
+
const result = await getMoonPhase(params);
|
|
5735
|
+
context.logger.log("\u2705 MoonPhase: Execution completed");
|
|
5736
|
+
return result;
|
|
5737
|
+
} catch (error) {
|
|
5738
|
+
context.logger.error("\u274C MoonPhase: Execution failed", error);
|
|
5739
|
+
throw error;
|
|
5740
|
+
}
|
|
5741
|
+
},
|
|
5742
|
+
toolSchema: {
|
|
5743
|
+
name: "moon_phase",
|
|
5744
|
+
description: "Get the current moon phase with illumination percentage, moon age, traditional moon names, and upcoming lunar phase predictions. Uses astronomical calculations for accuracy.",
|
|
5745
|
+
parameters: {
|
|
5746
|
+
type: "object",
|
|
5747
|
+
properties: {
|
|
5748
|
+
date: {
|
|
5749
|
+
type: "string",
|
|
5750
|
+
description: "The date to check moon phase for. Use YYYY-MM-DD format. Defaults to today if not specified."
|
|
5751
|
+
},
|
|
5752
|
+
timezone: {
|
|
5753
|
+
type: "string",
|
|
5754
|
+
description: 'IANA timezone identifier (e.g., "America/New_York"). Used for date display. Defaults to UTC.'
|
|
5755
|
+
}
|
|
5756
|
+
},
|
|
5757
|
+
additionalProperties: false,
|
|
5758
|
+
required: []
|
|
5759
|
+
}
|
|
5760
|
+
}
|
|
5761
|
+
})
|
|
5762
|
+
};
|
|
5763
|
+
|
|
5764
|
+
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/sunriseSunset/index.js
|
|
5765
|
+
var toRadians = (degrees) => degrees * (Math.PI / 180);
|
|
5766
|
+
var toDegrees = (radians) => radians * (180 / Math.PI);
|
|
5767
|
+
var getJulianDay = (date) => {
|
|
5768
|
+
const year = date.getFullYear();
|
|
5769
|
+
const month = date.getMonth() + 1;
|
|
5770
|
+
const day = date.getDate();
|
|
5771
|
+
const a = Math.floor((14 - month) / 12);
|
|
5772
|
+
const y = year + 4800 - a;
|
|
5773
|
+
const m = month + 12 * a - 3;
|
|
5774
|
+
return day + Math.floor((153 * m + 2) / 5) + 365 * y + Math.floor(y / 4) - Math.floor(y / 100) + Math.floor(y / 400) - 32045;
|
|
5775
|
+
};
|
|
5776
|
+
var getJulianCentury = (julianDay) => {
|
|
5777
|
+
return (julianDay - 2451545) / 36525;
|
|
5778
|
+
};
|
|
5779
|
+
var getSunMeanLongitude = (julianCentury) => {
|
|
5780
|
+
let L0 = 280.46646 + julianCentury * (36000.76983 + 3032e-7 * julianCentury);
|
|
5781
|
+
while (L0 > 360)
|
|
5782
|
+
L0 -= 360;
|
|
5783
|
+
while (L0 < 0)
|
|
5784
|
+
L0 += 360;
|
|
5785
|
+
return L0;
|
|
5786
|
+
};
|
|
5787
|
+
var getSunMeanAnomaly = (julianCentury) => {
|
|
5788
|
+
return 357.52911 + julianCentury * (35999.05029 - 1537e-7 * julianCentury);
|
|
5789
|
+
};
|
|
5790
|
+
var getEccentricity = (julianCentury) => {
|
|
5791
|
+
return 0.016708634 - julianCentury * (42037e-9 + 1267e-10 * julianCentury);
|
|
5792
|
+
};
|
|
5793
|
+
var getSunEquationOfCenter = (julianCentury, meanAnomaly) => {
|
|
5794
|
+
const M = toRadians(meanAnomaly);
|
|
5795
|
+
return Math.sin(M) * (1.914602 - julianCentury * (4817e-6 + 14e-6 * julianCentury)) + Math.sin(2 * M) * (0.019993 - 101e-6 * julianCentury) + Math.sin(3 * M) * 289e-6;
|
|
5796
|
+
};
|
|
5797
|
+
var getSunTrueLongitude = (meanLongitude, equationOfCenter) => {
|
|
5798
|
+
return meanLongitude + equationOfCenter;
|
|
5799
|
+
};
|
|
5800
|
+
var getSunApparentLongitude = (trueLongitude, julianCentury) => {
|
|
5801
|
+
const omega = 125.04 - 1934.136 * julianCentury;
|
|
5802
|
+
return trueLongitude - 569e-5 - 478e-5 * Math.sin(toRadians(omega));
|
|
5803
|
+
};
|
|
5804
|
+
var getMeanObliquity = (julianCentury) => {
|
|
5805
|
+
const seconds = 21.448 - julianCentury * (46.815 + julianCentury * (59e-5 - julianCentury * 1813e-6));
|
|
5806
|
+
return 23 + (26 + seconds / 60) / 60;
|
|
5807
|
+
};
|
|
5808
|
+
var getObliquityCorrection = (julianCentury, meanObliquity) => {
|
|
5809
|
+
const omega = 125.04 - 1934.136 * julianCentury;
|
|
5810
|
+
return meanObliquity + 256e-5 * Math.cos(toRadians(omega));
|
|
5811
|
+
};
|
|
5812
|
+
var getSunDeclination = (obliquityCorrection, apparentLongitude) => {
|
|
5813
|
+
return toDegrees(Math.asin(Math.sin(toRadians(obliquityCorrection)) * Math.sin(toRadians(apparentLongitude))));
|
|
5814
|
+
};
|
|
5815
|
+
var getEquationOfTime = (julianCentury, meanLongitude, eccentricity, meanAnomaly, obliquityCorrection) => {
|
|
5816
|
+
const y = Math.tan(toRadians(obliquityCorrection / 2)) ** 2;
|
|
5817
|
+
const L0 = toRadians(meanLongitude);
|
|
5818
|
+
const e = eccentricity;
|
|
5819
|
+
const M = toRadians(meanAnomaly);
|
|
5820
|
+
const EoT = y * Math.sin(2 * L0) - 2 * e * Math.sin(M) + 4 * e * y * Math.sin(M) * Math.cos(2 * L0) - 0.5 * y * y * Math.sin(4 * L0) - 1.25 * e * e * Math.sin(2 * M);
|
|
5821
|
+
return toDegrees(EoT) * 4;
|
|
5822
|
+
};
|
|
5823
|
+
var getHourAngle = (latitude, declination, zenith) => {
|
|
5824
|
+
const latRad = toRadians(latitude);
|
|
5825
|
+
const decRad = toRadians(declination);
|
|
5826
|
+
const zenithRad = toRadians(zenith);
|
|
5827
|
+
const cosHA = Math.cos(zenithRad) / (Math.cos(latRad) * Math.cos(decRad)) - Math.tan(latRad) * Math.tan(decRad);
|
|
5828
|
+
if (cosHA > 1 || cosHA < -1) {
|
|
5829
|
+
return null;
|
|
5830
|
+
}
|
|
5831
|
+
return toDegrees(Math.acos(cosHA));
|
|
5832
|
+
};
|
|
5833
|
+
var getSolarNoon = (longitude, equationOfTime) => {
|
|
5834
|
+
return 720 - 4 * longitude - equationOfTime;
|
|
5835
|
+
};
|
|
5836
|
+
var minutesToTime = (minutes, timezone2) => {
|
|
5837
|
+
const date = /* @__PURE__ */ new Date();
|
|
5838
|
+
date.setUTCHours(0, 0, 0, 0);
|
|
5839
|
+
date.setUTCMinutes(Math.round(minutes));
|
|
5840
|
+
return date.toLocaleTimeString("en-US", {
|
|
5841
|
+
timeZone: timezone2,
|
|
5842
|
+
hour: "numeric",
|
|
5843
|
+
minute: "2-digit"
|
|
5844
|
+
});
|
|
5845
|
+
};
|
|
5846
|
+
var formatDuration = (minutes) => {
|
|
5847
|
+
const hours = Math.floor(minutes / 60);
|
|
5848
|
+
const mins = Math.round(minutes % 60);
|
|
5849
|
+
return `${hours}h ${mins}m`;
|
|
5850
|
+
};
|
|
5851
|
+
var parseDate3 = (dateStr) => {
|
|
5852
|
+
if (!dateStr) {
|
|
5853
|
+
return /* @__PURE__ */ new Date();
|
|
5854
|
+
}
|
|
5855
|
+
const match = dateStr.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
|
5856
|
+
if (!match) {
|
|
5857
|
+
throw new Error(`Invalid date format: ${dateStr}. Please use YYYY-MM-DD format.`);
|
|
5858
|
+
}
|
|
5859
|
+
const [, year, month, day] = match;
|
|
5860
|
+
return new Date(parseInt(year), parseInt(month) - 1, parseInt(day), 12, 0, 0);
|
|
5861
|
+
};
|
|
5862
|
+
var ZENITH = {
|
|
5863
|
+
OFFICIAL: 90.833,
|
|
5864
|
+
// Sunrise/sunset (accounting for refraction)
|
|
5865
|
+
CIVIL: 96,
|
|
5866
|
+
// Civil twilight (6 degrees below horizon)
|
|
5867
|
+
NAUTICAL: 102,
|
|
5868
|
+
// Nautical twilight (12 degrees below horizon)
|
|
5869
|
+
ASTRONOMICAL: 108,
|
|
5870
|
+
// Astronomical twilight (18 degrees below horizon)
|
|
5871
|
+
GOLDEN_HOUR: 84
|
|
5872
|
+
// Golden hour (approximate)
|
|
5873
|
+
};
|
|
5874
|
+
var getSunriseSunset = async (parameters) => {
|
|
5875
|
+
const { latitude, longitude, date: dateStr, timezone: timezone2 = "UTC" } = parameters;
|
|
5876
|
+
if (latitude === void 0 || latitude === null) {
|
|
5877
|
+
throw new Error("Latitude is required. Please provide a value between -90 and 90.");
|
|
5878
|
+
}
|
|
5879
|
+
if (longitude === void 0 || longitude === null) {
|
|
5880
|
+
throw new Error("Longitude is required. Please provide a value between -180 and 180.");
|
|
5881
|
+
}
|
|
5882
|
+
if (latitude < -90 || latitude > 90) {
|
|
5883
|
+
throw new Error(`Invalid latitude: ${latitude}. Must be between -90 and 90.`);
|
|
5884
|
+
}
|
|
5885
|
+
if (longitude < -180 || longitude > 180) {
|
|
5886
|
+
throw new Error(`Invalid longitude: ${longitude}. Must be between -180 and 180.`);
|
|
5887
|
+
}
|
|
5888
|
+
try {
|
|
5889
|
+
Intl.DateTimeFormat(void 0, { timeZone: timezone2 });
|
|
5890
|
+
} catch {
|
|
5891
|
+
throw new Error(`Invalid timezone: ${timezone2}. Please use IANA timezone format (e.g., "America/New_York", "Europe/London")`);
|
|
5892
|
+
}
|
|
5893
|
+
const date = parseDate3(dateStr);
|
|
5894
|
+
const julianDay = getJulianDay(date);
|
|
5895
|
+
const julianCentury = getJulianCentury(julianDay);
|
|
5896
|
+
const meanLongitude = getSunMeanLongitude(julianCentury);
|
|
5897
|
+
const meanAnomaly = getSunMeanAnomaly(julianCentury);
|
|
5898
|
+
const eccentricity = getEccentricity(julianCentury);
|
|
5899
|
+
const equationOfCenter = getSunEquationOfCenter(julianCentury, meanAnomaly);
|
|
5900
|
+
const trueLongitude = getSunTrueLongitude(meanLongitude, equationOfCenter);
|
|
5901
|
+
const apparentLongitude = getSunApparentLongitude(trueLongitude, julianCentury);
|
|
5902
|
+
const meanObliquity = getMeanObliquity(julianCentury);
|
|
5903
|
+
const obliquityCorrection = getObliquityCorrection(julianCentury, meanObliquity);
|
|
5904
|
+
const declination = getSunDeclination(obliquityCorrection, apparentLongitude);
|
|
5905
|
+
const equationOfTime = getEquationOfTime(julianCentury, meanLongitude, eccentricity, meanAnomaly, obliquityCorrection);
|
|
5906
|
+
const solarNoon = getSolarNoon(longitude, equationOfTime);
|
|
5907
|
+
const calculateTime = (zenith, isSunrise) => {
|
|
5908
|
+
const hourAngle = getHourAngle(latitude, declination, zenith);
|
|
5909
|
+
if (hourAngle === null)
|
|
5910
|
+
return null;
|
|
5911
|
+
const minutes = solarNoon + (isSunrise ? -hourAngle : hourAngle) * 4;
|
|
5912
|
+
return minutesToTime(minutes, timezone2);
|
|
5913
|
+
};
|
|
5914
|
+
const sunrise = calculateTime(ZENITH.OFFICIAL, true);
|
|
5915
|
+
const sunset = calculateTime(ZENITH.OFFICIAL, false);
|
|
5916
|
+
const civilDawn = calculateTime(ZENITH.CIVIL, true);
|
|
5917
|
+
const civilDusk = calculateTime(ZENITH.CIVIL, false);
|
|
5918
|
+
const nauticalDawn = calculateTime(ZENITH.NAUTICAL, true);
|
|
5919
|
+
const nauticalDusk = calculateTime(ZENITH.NAUTICAL, false);
|
|
5920
|
+
const astroDawn = calculateTime(ZENITH.ASTRONOMICAL, true);
|
|
5921
|
+
const astroDusk = calculateTime(ZENITH.ASTRONOMICAL, false);
|
|
5922
|
+
const goldenHourMorningEnd = calculateTime(ZENITH.GOLDEN_HOUR, true);
|
|
5923
|
+
const goldenHourEveningStart = calculateTime(ZENITH.GOLDEN_HOUR, false);
|
|
5924
|
+
const sunriseHA = getHourAngle(latitude, declination, ZENITH.OFFICIAL);
|
|
5925
|
+
const dayLength = sunriseHA !== null ? sunriseHA * 8 : null;
|
|
5926
|
+
const yesterdayDate = new Date(date);
|
|
5927
|
+
yesterdayDate.setDate(yesterdayDate.getDate() - 1);
|
|
5928
|
+
const yesterdayJD = getJulianDay(yesterdayDate);
|
|
5929
|
+
const yesterdayJC = getJulianCentury(yesterdayJD);
|
|
5930
|
+
const yesterdayML = getSunMeanLongitude(yesterdayJC);
|
|
5931
|
+
const yesterdayMA = getSunMeanAnomaly(yesterdayJC);
|
|
5932
|
+
const yesterdayEOC = getSunEquationOfCenter(yesterdayJC, yesterdayMA);
|
|
5933
|
+
const yesterdayTL = getSunTrueLongitude(yesterdayML, yesterdayEOC);
|
|
5934
|
+
const yesterdayAL = getSunApparentLongitude(yesterdayTL, yesterdayJC);
|
|
5935
|
+
const yesterdayMO = getMeanObliquity(yesterdayJC);
|
|
5936
|
+
const yesterdayOC = getObliquityCorrection(yesterdayJC, yesterdayMO);
|
|
5937
|
+
const yesterdayDec = getSunDeclination(yesterdayOC, yesterdayAL);
|
|
5938
|
+
const yesterdayHA = getHourAngle(latitude, yesterdayDec, ZENITH.OFFICIAL);
|
|
5939
|
+
const yesterdayDayLength = yesterdayHA !== null ? yesterdayHA * 8 : null;
|
|
5940
|
+
let dayLengthChange = null;
|
|
5941
|
+
let changingDirection = null;
|
|
5942
|
+
if (dayLength !== null && yesterdayDayLength !== null) {
|
|
5943
|
+
dayLengthChange = dayLength - yesterdayDayLength;
|
|
5944
|
+
changingDirection = dayLengthChange > 0 ? "longer" : "shorter";
|
|
5945
|
+
}
|
|
5946
|
+
const dateFormatter = new Intl.DateTimeFormat("en-US", {
|
|
5947
|
+
timeZone: timezone2,
|
|
5948
|
+
weekday: "long",
|
|
5949
|
+
year: "numeric",
|
|
5950
|
+
month: "long",
|
|
5951
|
+
day: "numeric"
|
|
5952
|
+
});
|
|
5953
|
+
const results = [];
|
|
5954
|
+
results.push(`**Sun Times for ${dateFormatter.format(date)}**`);
|
|
5955
|
+
results.push(`\u{1F4CD} Location: ${Math.abs(latitude).toFixed(4)}\xB0${latitude >= 0 ? "N" : "S"}, ${Math.abs(longitude).toFixed(4)}\xB0${longitude >= 0 ? "E" : "W"}`);
|
|
5956
|
+
results.push("");
|
|
5957
|
+
if (!sunrise || !sunset) {
|
|
5958
|
+
if (declination > 0 && latitude > 66.5) {
|
|
5959
|
+
results.push("\u2600\uFE0F **Midnight Sun** - The sun does not set at this latitude today.");
|
|
5960
|
+
} else if (declination < 0 && latitude < -66.5) {
|
|
5961
|
+
results.push("\u2600\uFE0F **Midnight Sun** - The sun does not set at this latitude today.");
|
|
5962
|
+
} else if (declination < 0 && latitude > 66.5) {
|
|
5963
|
+
results.push("\u{1F311} **Polar Night** - The sun does not rise at this latitude today.");
|
|
5964
|
+
} else if (declination > 0 && latitude < -66.5) {
|
|
5965
|
+
results.push("\u{1F311} **Polar Night** - The sun does not rise at this latitude today.");
|
|
5966
|
+
}
|
|
5967
|
+
return results.join("\n");
|
|
5968
|
+
}
|
|
5969
|
+
results.push("**Main Events:**");
|
|
5970
|
+
results.push(`- \u{1F305} Sunrise: ${sunrise}`);
|
|
5971
|
+
results.push(`- \u2600\uFE0F Solar Noon: ${minutesToTime(solarNoon, timezone2)}`);
|
|
5972
|
+
results.push(`- \u{1F307} Sunset: ${sunset}`);
|
|
5973
|
+
if (dayLength !== null) {
|
|
5974
|
+
results.push(`- \u23F1\uFE0F Day Length: ${formatDuration(dayLength)}`);
|
|
5975
|
+
if (dayLengthChange !== null && Math.abs(dayLengthChange) >= 0.1) {
|
|
5976
|
+
const changeSeconds = Math.round(Math.abs(dayLengthChange) * 60);
|
|
5977
|
+
results.push(` _(Days are getting ${changingDirection} by ~${Math.floor(changeSeconds / 60)}m ${changeSeconds % 60}s)_`);
|
|
5978
|
+
}
|
|
5979
|
+
}
|
|
5980
|
+
results.push("");
|
|
5981
|
+
results.push("**Twilight Periods:**");
|
|
5982
|
+
if (astroDawn)
|
|
5983
|
+
results.push(`- \u{1F30C} Astronomical Dawn: ${astroDawn}`);
|
|
5984
|
+
if (nauticalDawn)
|
|
5985
|
+
results.push(`- \u{1F30A} Nautical Dawn: ${nauticalDawn}`);
|
|
5986
|
+
if (civilDawn)
|
|
5987
|
+
results.push(`- \u{1F3D9}\uFE0F Civil Dawn: ${civilDawn}`);
|
|
5988
|
+
if (civilDusk)
|
|
5989
|
+
results.push(`- \u{1F3D9}\uFE0F Civil Dusk: ${civilDusk}`);
|
|
5990
|
+
if (nauticalDusk)
|
|
5991
|
+
results.push(`- \u{1F30A} Nautical Dusk: ${nauticalDusk}`);
|
|
5992
|
+
if (astroDusk)
|
|
5993
|
+
results.push(`- \u{1F30C} Astronomical Dusk: ${astroDusk}`);
|
|
5994
|
+
results.push("");
|
|
5995
|
+
results.push("**Golden Hour (Photography):**");
|
|
5996
|
+
if (sunrise && goldenHourMorningEnd) {
|
|
5997
|
+
results.push(`- \u{1F4F8} Morning: ${sunrise} - ${goldenHourMorningEnd}`);
|
|
5998
|
+
}
|
|
5999
|
+
if (goldenHourEveningStart && sunset) {
|
|
6000
|
+
results.push(`- \u{1F4F8} Evening: ${goldenHourEveningStart} - ${sunset}`);
|
|
6001
|
+
}
|
|
6002
|
+
return results.join("\n");
|
|
6003
|
+
};
|
|
6004
|
+
var sunriseSunsetTool = {
|
|
6005
|
+
name: "sunrise_sunset",
|
|
6006
|
+
implementation: (context) => ({
|
|
6007
|
+
toolFn: async (value) => {
|
|
6008
|
+
const params = value;
|
|
6009
|
+
context.logger.log("\u{1F305} SunriseSunset: Starting execution", params);
|
|
6010
|
+
try {
|
|
6011
|
+
const result = await getSunriseSunset(params);
|
|
6012
|
+
context.logger.log("\u2705 SunriseSunset: Execution completed");
|
|
6013
|
+
return result;
|
|
6014
|
+
} catch (error) {
|
|
6015
|
+
context.logger.error("\u274C SunriseSunset: Execution failed", error);
|
|
6016
|
+
throw error;
|
|
6017
|
+
}
|
|
6018
|
+
},
|
|
6019
|
+
toolSchema: {
|
|
6020
|
+
name: "sunrise_sunset",
|
|
6021
|
+
description: "Calculate sunrise, sunset, twilight times, golden hour, and day length for any location. Uses NOAA solar calculations for accuracy. Also shows how day length is changing (getting longer or shorter).",
|
|
6022
|
+
parameters: {
|
|
6023
|
+
type: "object",
|
|
6024
|
+
properties: {
|
|
6025
|
+
latitude: {
|
|
6026
|
+
type: "number",
|
|
6027
|
+
description: "Latitude in decimal degrees (-90 to 90). Positive for North, negative for South. Example: 40.7128 for New York City."
|
|
6028
|
+
},
|
|
6029
|
+
longitude: {
|
|
6030
|
+
type: "number",
|
|
6031
|
+
description: "Longitude in decimal degrees (-180 to 180). Positive for East, negative for West. Example: -74.0060 for New York City."
|
|
6032
|
+
},
|
|
6033
|
+
date: {
|
|
6034
|
+
type: "string",
|
|
6035
|
+
description: "The date to calculate for. Use YYYY-MM-DD format. Defaults to today if not specified."
|
|
6036
|
+
},
|
|
6037
|
+
timezone: {
|
|
6038
|
+
type: "string",
|
|
6039
|
+
description: 'IANA timezone identifier for time display (e.g., "America/New_York"). Defaults to UTC.'
|
|
6040
|
+
}
|
|
6041
|
+
},
|
|
6042
|
+
additionalProperties: false,
|
|
6043
|
+
required: ["latitude", "longitude"]
|
|
6044
|
+
}
|
|
6045
|
+
}
|
|
6046
|
+
})
|
|
6047
|
+
};
|
|
6048
|
+
|
|
6049
|
+
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/issTracker/index.js
|
|
6050
|
+
var getLocationDescription = (lat, lon) => {
|
|
6051
|
+
if (lat > 66.5)
|
|
6052
|
+
return "Arctic region";
|
|
6053
|
+
if (lat < -66.5)
|
|
6054
|
+
return "Antarctic region";
|
|
6055
|
+
const ewDir = lon >= 0 ? "Eastern" : "Western";
|
|
6056
|
+
if (lon >= -80 && lon <= 0 && lat >= 0 && lat <= 60 || lon >= -80 && lon <= 0 && lat >= -60 && lat < 0) {
|
|
6057
|
+
return "Atlantic Ocean";
|
|
6058
|
+
}
|
|
6059
|
+
if (lon >= 100 && lon <= 180 || lon >= -180 && lon <= -100) {
|
|
6060
|
+
if (lat >= -60 && lat <= 60)
|
|
6061
|
+
return "Pacific Ocean";
|
|
6062
|
+
}
|
|
6063
|
+
if (lon >= 40 && lon <= 100 && lat >= -40 && lat <= 30) {
|
|
6064
|
+
return "Indian Ocean";
|
|
6065
|
+
}
|
|
6066
|
+
if (lat >= 25 && lat <= 50 && lon >= -130 && lon <= -60)
|
|
6067
|
+
return "North America";
|
|
6068
|
+
if (lat >= -55 && lat < 15 && lon >= -80 && lon <= -35)
|
|
6069
|
+
return "South America";
|
|
6070
|
+
if (lat >= 35 && lat <= 72 && lon >= -10 && lon <= 40)
|
|
6071
|
+
return "Europe";
|
|
6072
|
+
if (lat >= -35 && lat <= 37 && lon >= -20 && lon <= 55)
|
|
6073
|
+
return "Africa";
|
|
6074
|
+
if (lat >= 10 && lat <= 55 && lon >= 60 && lon <= 145)
|
|
6075
|
+
return "Asia";
|
|
6076
|
+
if (lat >= -50 && lat <= -10 && lon >= 110 && lon <= 180)
|
|
6077
|
+
return "Australia/Oceania";
|
|
6078
|
+
return `${ewDir} Hemisphere`;
|
|
6079
|
+
};
|
|
6080
|
+
var calculateDistance = (lat1, lon1, lat2, lon2) => {
|
|
6081
|
+
const R = 6371;
|
|
6082
|
+
const dLat = (lat2 - lat1) * (Math.PI / 180);
|
|
6083
|
+
const dLon = (lon2 - lon1) * (Math.PI / 180);
|
|
6084
|
+
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(lat1 * (Math.PI / 180)) * Math.cos(lat2 * (Math.PI / 180)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
|
|
6085
|
+
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
6086
|
+
return R * c;
|
|
6087
|
+
};
|
|
6088
|
+
var getISSData = async (parameters) => {
|
|
6089
|
+
const { operation, latitude, longitude } = parameters;
|
|
6090
|
+
const results = [];
|
|
6091
|
+
try {
|
|
6092
|
+
if (operation === "current_position") {
|
|
6093
|
+
const response = await fetch("http://api.open-notify.org/iss-now.json");
|
|
6094
|
+
if (!response.ok) {
|
|
6095
|
+
throw new Error(`ISS API error: ${response.status} ${response.statusText}`);
|
|
6096
|
+
}
|
|
6097
|
+
const data = await response.json();
|
|
6098
|
+
if (data.message !== "success") {
|
|
6099
|
+
throw new Error("Failed to get ISS position from API");
|
|
6100
|
+
}
|
|
6101
|
+
const issLat = parseFloat(data.iss_position.latitude);
|
|
6102
|
+
const issLon = parseFloat(data.iss_position.longitude);
|
|
6103
|
+
const timestamp = new Date(data.timestamp * 1e3);
|
|
6104
|
+
results.push("\u{1F6F0}\uFE0F **International Space Station - Current Position**");
|
|
6105
|
+
results.push("");
|
|
6106
|
+
results.push(`**Coordinates:**`);
|
|
6107
|
+
results.push(`- Latitude: ${issLat.toFixed(4)}\xB0 ${issLat >= 0 ? "N" : "S"}`);
|
|
6108
|
+
results.push(`- Longitude: ${issLon.toFixed(4)}\xB0 ${issLon >= 0 ? "E" : "W"}`);
|
|
6109
|
+
results.push("");
|
|
6110
|
+
results.push(`**Location:** Currently over ${getLocationDescription(issLat, issLon)}`);
|
|
6111
|
+
results.push(`**Timestamp:** ${timestamp.toUTCString()}`);
|
|
6112
|
+
results.push("");
|
|
6113
|
+
results.push("**ISS Facts:**");
|
|
6114
|
+
results.push("- Altitude: ~420 km (260 miles) above Earth");
|
|
6115
|
+
results.push("- Speed: ~28,000 km/h (17,500 mph)");
|
|
6116
|
+
results.push("- Orbits Earth every ~90 minutes");
|
|
6117
|
+
results.push("- Visible from Earth at dawn/dusk when sunlit");
|
|
6118
|
+
if (latitude !== void 0 && longitude !== void 0) {
|
|
6119
|
+
const distance = calculateDistance(latitude, longitude, issLat, issLon);
|
|
6120
|
+
results.push("");
|
|
6121
|
+
results.push("**Distance from Your Location:**");
|
|
6122
|
+
results.push(`- Ground distance: ${Math.round(distance).toLocaleString()} km (${Math.round(distance * 0.621371).toLocaleString()} miles)`);
|
|
6123
|
+
if (distance < 2e3) {
|
|
6124
|
+
results.push("- \u2B50 The ISS may be visible from your location if conditions are right!");
|
|
6125
|
+
}
|
|
6126
|
+
}
|
|
6127
|
+
results.push("");
|
|
6128
|
+
results.push("_Track the ISS in real-time: https://spotthestation.nasa.gov/_");
|
|
6129
|
+
} else if (operation === "crew") {
|
|
6130
|
+
const response = await fetch("http://api.open-notify.org/astros.json");
|
|
6131
|
+
if (!response.ok) {
|
|
6132
|
+
throw new Error(`Astronauts API error: ${response.status} ${response.statusText}`);
|
|
6133
|
+
}
|
|
6134
|
+
const data = await response.json();
|
|
6135
|
+
if (data.message !== "success") {
|
|
6136
|
+
throw new Error("Failed to get astronaut data from API");
|
|
6137
|
+
}
|
|
6138
|
+
const craftGroups = {};
|
|
6139
|
+
for (const person of data.people) {
|
|
6140
|
+
if (!craftGroups[person.craft]) {
|
|
6141
|
+
craftGroups[person.craft] = [];
|
|
6142
|
+
}
|
|
6143
|
+
craftGroups[person.craft].push(person.name);
|
|
6144
|
+
}
|
|
6145
|
+
results.push("\u{1F468}\u200D\u{1F680} **People Currently in Space**");
|
|
6146
|
+
results.push("");
|
|
6147
|
+
results.push(`**Total:** ${data.number} astronauts/cosmonauts`);
|
|
6148
|
+
results.push("");
|
|
6149
|
+
for (const [craft, crew] of Object.entries(craftGroups)) {
|
|
6150
|
+
const emoji = craft === "ISS" ? "\u{1F6F0}\uFE0F" : craft.includes("Shenzhou") ? "\u{1F1E8}\u{1F1F3}" : "\u{1F680}";
|
|
6151
|
+
results.push(`**${emoji} ${craft}** (${crew.length} crew):`);
|
|
6152
|
+
crew.forEach((name) => results.push(`- ${name}`));
|
|
6153
|
+
results.push("");
|
|
6154
|
+
}
|
|
6155
|
+
results.push("_Data from NASA Open Notify API_");
|
|
6156
|
+
} else {
|
|
6157
|
+
throw new Error(`Unknown operation: ${operation}. Supported operations: current_position, crew`);
|
|
6158
|
+
}
|
|
6159
|
+
return results.join("\n");
|
|
6160
|
+
} catch (error) {
|
|
6161
|
+
if (error instanceof Error) {
|
|
6162
|
+
throw error;
|
|
6163
|
+
}
|
|
6164
|
+
throw new Error(`Failed to fetch ISS data: ${String(error)}`);
|
|
6165
|
+
}
|
|
6166
|
+
};
|
|
6167
|
+
var issTrackerTool = {
|
|
6168
|
+
name: "iss_tracker",
|
|
6169
|
+
implementation: (context) => ({
|
|
6170
|
+
toolFn: async (value) => {
|
|
6171
|
+
const params = value;
|
|
6172
|
+
context.logger.log("\u{1F6F0}\uFE0F ISSTracker: Starting execution", params);
|
|
6173
|
+
try {
|
|
6174
|
+
const result = await getISSData(params);
|
|
6175
|
+
context.logger.log("\u2705 ISSTracker: Execution completed");
|
|
6176
|
+
return result;
|
|
6177
|
+
} catch (error) {
|
|
6178
|
+
context.logger.error("\u274C ISSTracker: Execution failed", error);
|
|
6179
|
+
throw error;
|
|
6180
|
+
}
|
|
6181
|
+
},
|
|
6182
|
+
toolSchema: {
|
|
6183
|
+
name: "iss_tracker",
|
|
6184
|
+
description: "Track the International Space Station in real-time. Get current position, or see who is currently in space (on ISS and other spacecraft).",
|
|
6185
|
+
parameters: {
|
|
6186
|
+
type: "object",
|
|
6187
|
+
properties: {
|
|
6188
|
+
operation: {
|
|
6189
|
+
type: "string",
|
|
6190
|
+
description: 'What information to retrieve: "current_position" for ISS location, "crew" for people currently in space.',
|
|
6191
|
+
enum: ["current_position", "crew"]
|
|
6192
|
+
},
|
|
6193
|
+
latitude: {
|
|
6194
|
+
type: "number",
|
|
6195
|
+
description: "Your latitude (optional). If provided with longitude, will show distance from your location to ISS. Example: 40.7128 for NYC."
|
|
6196
|
+
},
|
|
6197
|
+
longitude: {
|
|
6198
|
+
type: "number",
|
|
6199
|
+
description: "Your longitude (optional). If provided with latitude, will show distance from your location to ISS. Example: -74.0060 for NYC."
|
|
6200
|
+
}
|
|
6201
|
+
},
|
|
6202
|
+
additionalProperties: false,
|
|
6203
|
+
required: ["operation"]
|
|
6204
|
+
}
|
|
6205
|
+
}
|
|
6206
|
+
})
|
|
6207
|
+
};
|
|
6208
|
+
|
|
6209
|
+
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/planetVisibility/index.js
|
|
6210
|
+
var PLANETS = [
|
|
6211
|
+
{
|
|
6212
|
+
name: "Mercury",
|
|
6213
|
+
symbol: "\u263F",
|
|
6214
|
+
a: 0.38709927,
|
|
6215
|
+
e: 0.20563593,
|
|
6216
|
+
i: 7.00497902,
|
|
6217
|
+
L: 252.2503235,
|
|
6218
|
+
longPeri: 77.45779628,
|
|
6219
|
+
longNode: 48.33076593,
|
|
6220
|
+
aRate: 37e-8,
|
|
6221
|
+
eRate: 1906e-8,
|
|
6222
|
+
iRate: -594749e-8,
|
|
6223
|
+
LRate: 149472.67411175,
|
|
6224
|
+
longPeriRate: 0.16047689,
|
|
6225
|
+
longNodeRate: -0.12534081,
|
|
6226
|
+
maxMagnitude: -1.9,
|
|
6227
|
+
color: "gray"
|
|
6228
|
+
},
|
|
6229
|
+
{
|
|
6230
|
+
name: "Venus",
|
|
6231
|
+
symbol: "\u2640",
|
|
6232
|
+
a: 0.72333566,
|
|
6233
|
+
e: 677672e-8,
|
|
6234
|
+
i: 3.39467605,
|
|
6235
|
+
L: 181.9790995,
|
|
6236
|
+
longPeri: 131.60246718,
|
|
6237
|
+
longNode: 76.67984255,
|
|
6238
|
+
aRate: 39e-7,
|
|
6239
|
+
eRate: -4107e-8,
|
|
6240
|
+
iRate: -7889e-7,
|
|
6241
|
+
LRate: 58517.81538729,
|
|
6242
|
+
longPeriRate: 268329e-8,
|
|
6243
|
+
longNodeRate: -0.27769418,
|
|
6244
|
+
maxMagnitude: -4.6,
|
|
6245
|
+
color: "white"
|
|
6246
|
+
},
|
|
6247
|
+
{
|
|
6248
|
+
name: "Mars",
|
|
6249
|
+
symbol: "\u2642",
|
|
6250
|
+
a: 1.52371034,
|
|
6251
|
+
e: 0.0933941,
|
|
6252
|
+
i: 1.84969142,
|
|
6253
|
+
L: -4.55343205,
|
|
6254
|
+
longPeri: -23.94362959,
|
|
6255
|
+
longNode: 49.55953891,
|
|
6256
|
+
aRate: 1847e-8,
|
|
6257
|
+
eRate: 7882e-8,
|
|
6258
|
+
iRate: -813131e-8,
|
|
6259
|
+
LRate: 19140.30268499,
|
|
6260
|
+
longPeriRate: 0.44441088,
|
|
6261
|
+
longNodeRate: -0.29257343,
|
|
6262
|
+
maxMagnitude: -2.9,
|
|
6263
|
+
color: "red"
|
|
6264
|
+
},
|
|
6265
|
+
{
|
|
6266
|
+
name: "Jupiter",
|
|
6267
|
+
symbol: "\u2643",
|
|
6268
|
+
a: 5.202887,
|
|
6269
|
+
e: 0.04838624,
|
|
6270
|
+
i: 1.30439695,
|
|
6271
|
+
L: 34.39644051,
|
|
6272
|
+
longPeri: 14.72847983,
|
|
6273
|
+
longNode: 100.47390909,
|
|
6274
|
+
aRate: -11607e-8,
|
|
6275
|
+
eRate: -13253e-8,
|
|
6276
|
+
iRate: -183714e-8,
|
|
6277
|
+
LRate: 3034.74612775,
|
|
6278
|
+
longPeriRate: 0.21252668,
|
|
6279
|
+
longNodeRate: 0.20469106,
|
|
6280
|
+
maxMagnitude: -2.9,
|
|
6281
|
+
color: "orange"
|
|
6282
|
+
},
|
|
6283
|
+
{
|
|
6284
|
+
name: "Saturn",
|
|
6285
|
+
symbol: "\u2644",
|
|
6286
|
+
a: 9.53667594,
|
|
6287
|
+
e: 0.05386179,
|
|
6288
|
+
i: 2.48599187,
|
|
6289
|
+
L: 49.95424423,
|
|
6290
|
+
longPeri: 92.59887831,
|
|
6291
|
+
longNode: 113.66242448,
|
|
6292
|
+
aRate: -12506e-7,
|
|
6293
|
+
eRate: -50991e-8,
|
|
6294
|
+
iRate: 193609e-8,
|
|
6295
|
+
LRate: 1222.49362201,
|
|
6296
|
+
longPeriRate: -0.41897216,
|
|
6297
|
+
longNodeRate: -0.28867794,
|
|
6298
|
+
maxMagnitude: -0.5,
|
|
6299
|
+
color: "gold"
|
|
6300
|
+
}
|
|
6301
|
+
];
|
|
6302
|
+
var EARTH = {
|
|
6303
|
+
a: 1.00000261,
|
|
6304
|
+
e: 0.01671123,
|
|
6305
|
+
i: -1531e-8,
|
|
6306
|
+
L: 100.46457166,
|
|
6307
|
+
longPeri: 102.93768193,
|
|
6308
|
+
longNode: 0,
|
|
6309
|
+
aRate: 562e-8,
|
|
6310
|
+
eRate: -4392e-8,
|
|
6311
|
+
iRate: -0.01294668,
|
|
6312
|
+
LRate: 35999.37244981,
|
|
6313
|
+
longPeriRate: 0.32327364,
|
|
6314
|
+
longNodeRate: 0
|
|
6315
|
+
};
|
|
6316
|
+
var toRadians2 = (deg) => deg * (Math.PI / 180);
|
|
6317
|
+
var toDegrees2 = (rad) => rad * (180 / Math.PI);
|
|
6318
|
+
var normalizeAngle = (deg) => (deg % 360 + 360) % 360;
|
|
6319
|
+
var getJulianDay2 = (date) => {
|
|
6320
|
+
const year = date.getFullYear();
|
|
6321
|
+
const month = date.getMonth() + 1;
|
|
6322
|
+
const day = date.getDate() + date.getHours() / 24;
|
|
6323
|
+
const a = Math.floor((14 - month) / 12);
|
|
6324
|
+
const y = year + 4800 - a;
|
|
6325
|
+
const m = month + 12 * a - 3;
|
|
6326
|
+
return day + Math.floor((153 * m + 2) / 5) + 365 * y + Math.floor(y / 4) - Math.floor(y / 100) + Math.floor(y / 400) - 32045;
|
|
6327
|
+
};
|
|
6328
|
+
var getJulianCenturies = (jd) => (jd - 2451545) / 36525;
|
|
6329
|
+
var getHeliocentricCoords = (planet, T) => {
|
|
6330
|
+
const a = planet.a + planet.aRate * T;
|
|
6331
|
+
const e = planet.e + planet.eRate * T;
|
|
6332
|
+
const i = toRadians2(planet.i + planet.iRate * T);
|
|
6333
|
+
const L = normalizeAngle(planet.L + planet.LRate * T);
|
|
6334
|
+
const longPeri = normalizeAngle(planet.longPeri + planet.longPeriRate * T);
|
|
6335
|
+
const longNode = toRadians2(planet.longNode + planet.longNodeRate * T);
|
|
6336
|
+
const M = toRadians2(normalizeAngle(L - longPeri));
|
|
6337
|
+
let E = M;
|
|
6338
|
+
for (let iter = 0; iter < 10; iter++) {
|
|
6339
|
+
E = M + e * Math.sin(E);
|
|
6340
|
+
}
|
|
6341
|
+
const xv = a * (Math.cos(E) - e);
|
|
6342
|
+
const yv = a * Math.sqrt(1 - e * e) * Math.sin(E);
|
|
6343
|
+
const r = Math.sqrt(xv * xv + yv * yv);
|
|
6344
|
+
const v = Math.atan2(yv, xv);
|
|
6345
|
+
const omega = toRadians2(longPeri) - longNode;
|
|
6346
|
+
const cosOmega = Math.cos(omega + v);
|
|
6347
|
+
const sinOmega = Math.sin(omega + v);
|
|
6348
|
+
const cosI = Math.cos(i);
|
|
6349
|
+
const sinI = Math.sin(i);
|
|
6350
|
+
const cosNode = Math.cos(longNode);
|
|
6351
|
+
const sinNode = Math.sin(longNode);
|
|
6352
|
+
const x = r * (cosNode * cosOmega - sinNode * sinOmega * cosI);
|
|
6353
|
+
const y = r * (sinNode * cosOmega + cosNode * sinOmega * cosI);
|
|
6354
|
+
const z143 = r * sinOmega * sinI;
|
|
6355
|
+
return { x, y, z: z143, r };
|
|
6356
|
+
};
|
|
6357
|
+
var getGeocentricEcliptic = (planet, earth) => {
|
|
6358
|
+
const dx = planet.x - earth.x;
|
|
6359
|
+
const dy = planet.y - earth.y;
|
|
6360
|
+
const dz = planet.z - earth.z;
|
|
6361
|
+
const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
6362
|
+
const lon = normalizeAngle(toDegrees2(Math.atan2(dy, dx)));
|
|
6363
|
+
const lat = toDegrees2(Math.asin(dz / dist));
|
|
6364
|
+
return { lon, lat, dist };
|
|
6365
|
+
};
|
|
6366
|
+
var eclipticToEquatorial = (lon, lat, obliquity) => {
|
|
6367
|
+
const lonRad = toRadians2(lon);
|
|
6368
|
+
const latRad = toRadians2(lat);
|
|
6369
|
+
const oblRad = toRadians2(obliquity);
|
|
6370
|
+
const sinDec = Math.sin(latRad) * Math.cos(oblRad) + Math.cos(latRad) * Math.sin(oblRad) * Math.sin(lonRad);
|
|
6371
|
+
const dec = toDegrees2(Math.asin(sinDec));
|
|
6372
|
+
const y = Math.sin(lonRad) * Math.cos(oblRad) - Math.tan(latRad) * Math.sin(oblRad);
|
|
6373
|
+
const x = Math.cos(lonRad);
|
|
6374
|
+
const ra = normalizeAngle(toDegrees2(Math.atan2(y, x)));
|
|
6375
|
+
return { ra, dec };
|
|
6376
|
+
};
|
|
6377
|
+
var getLocalSiderealTime = (jd, longitude) => {
|
|
6378
|
+
const T = (jd - 2451545) / 36525;
|
|
6379
|
+
let GST = 280.46061837 + 360.98564736629 * (jd - 2451545) + 387933e-9 * T * T;
|
|
6380
|
+
GST = normalizeAngle(GST);
|
|
6381
|
+
return normalizeAngle(GST + longitude);
|
|
6382
|
+
};
|
|
6383
|
+
var getAltAz = (ra, dec, lat, lst) => {
|
|
6384
|
+
const ha = toRadians2(normalizeAngle(lst - ra));
|
|
6385
|
+
const decRad = toRadians2(dec);
|
|
6386
|
+
const latRad = toRadians2(lat);
|
|
6387
|
+
const sinAlt = Math.sin(decRad) * Math.sin(latRad) + Math.cos(decRad) * Math.cos(latRad) * Math.cos(ha);
|
|
6388
|
+
const alt = toDegrees2(Math.asin(sinAlt));
|
|
6389
|
+
const cosA = (Math.sin(decRad) - Math.sin(latRad) * sinAlt) / (Math.cos(latRad) * Math.cos(toRadians2(alt)));
|
|
6390
|
+
let az = toDegrees2(Math.acos(Math.max(-1, Math.min(1, cosA))));
|
|
6391
|
+
if (Math.sin(ha) > 0)
|
|
6392
|
+
az = 360 - az;
|
|
6393
|
+
return { alt, az };
|
|
6394
|
+
};
|
|
6395
|
+
var getRiseSetTimes = (ra, dec, lat, lon, jd) => {
|
|
6396
|
+
const latRad = toRadians2(lat);
|
|
6397
|
+
const decRad = toRadians2(dec);
|
|
6398
|
+
const h0 = toRadians2(-0.5667);
|
|
6399
|
+
const cosH = (Math.sin(h0) - Math.sin(latRad) * Math.sin(decRad)) / (Math.cos(latRad) * Math.cos(decRad));
|
|
6400
|
+
const lst0 = getLocalSiderealTime(Math.floor(jd) + 0.5, lon);
|
|
6401
|
+
let transitTime = (ra - lst0) / 15;
|
|
6402
|
+
if (transitTime < 0)
|
|
6403
|
+
transitTime += 24;
|
|
6404
|
+
if (transitTime > 24)
|
|
6405
|
+
transitTime -= 24;
|
|
6406
|
+
if (cosH > 1) {
|
|
6407
|
+
return { rises: false, sets: false, transitTime };
|
|
6408
|
+
} else if (cosH < -1) {
|
|
6409
|
+
return { rises: true, sets: true, transitTime };
|
|
6410
|
+
}
|
|
6411
|
+
const H = toDegrees2(Math.acos(cosH)) / 15;
|
|
6412
|
+
let riseTime = transitTime - H;
|
|
6413
|
+
let setTime = transitTime + H;
|
|
6414
|
+
if (riseTime < 0)
|
|
6415
|
+
riseTime += 24;
|
|
6416
|
+
if (setTime > 24)
|
|
6417
|
+
setTime -= 24;
|
|
6418
|
+
return { rises: true, sets: true, riseTime, setTime, transitTime };
|
|
6419
|
+
};
|
|
6420
|
+
var getElongation = (planetLon, sunLon) => {
|
|
6421
|
+
let elong = planetLon - sunLon;
|
|
6422
|
+
if (elong > 180)
|
|
6423
|
+
elong -= 360;
|
|
6424
|
+
if (elong < -180)
|
|
6425
|
+
elong += 360;
|
|
6426
|
+
return elong;
|
|
6427
|
+
};
|
|
6428
|
+
var formatTime = (hours, timezone2) => {
|
|
6429
|
+
const h = Math.floor(hours);
|
|
6430
|
+
const m = Math.round((hours - h) * 60);
|
|
6431
|
+
const date = /* @__PURE__ */ new Date();
|
|
6432
|
+
date.setUTCHours(h, m, 0, 0);
|
|
6433
|
+
return date.toLocaleTimeString("en-US", { timeZone: timezone2, hour: "numeric", minute: "2-digit" });
|
|
6434
|
+
};
|
|
6435
|
+
var getDirection = (az) => {
|
|
6436
|
+
const directions = [
|
|
6437
|
+
"N",
|
|
6438
|
+
"NNE",
|
|
6439
|
+
"NE",
|
|
6440
|
+
"ENE",
|
|
6441
|
+
"E",
|
|
6442
|
+
"ESE",
|
|
6443
|
+
"SE",
|
|
6444
|
+
"SSE",
|
|
6445
|
+
"S",
|
|
6446
|
+
"SSW",
|
|
6447
|
+
"SW",
|
|
6448
|
+
"WSW",
|
|
6449
|
+
"W",
|
|
6450
|
+
"WNW",
|
|
6451
|
+
"NW",
|
|
6452
|
+
"NNW"
|
|
6453
|
+
];
|
|
6454
|
+
const index = Math.round(az / 22.5) % 16;
|
|
6455
|
+
return directions[index];
|
|
6456
|
+
};
|
|
6457
|
+
var getVisibilityDescription = (elongation, altitude, isSuperior) => {
|
|
6458
|
+
const absElong = Math.abs(elongation);
|
|
6459
|
+
if (altitude < 0) {
|
|
6460
|
+
return { quality: "Not visible", description: "Below horizon" };
|
|
6461
|
+
}
|
|
6462
|
+
if (altitude < 10) {
|
|
6463
|
+
return { quality: "Poor", description: "Very low in sky, atmospheric interference" };
|
|
6464
|
+
}
|
|
6465
|
+
if (isSuperior) {
|
|
6466
|
+
if (absElong > 120) {
|
|
6467
|
+
return { quality: "Excellent", description: "Near opposition, visible most of the night" };
|
|
6468
|
+
} else if (absElong > 90) {
|
|
6469
|
+
return { quality: "Good", description: "Well placed for evening/morning viewing" };
|
|
6470
|
+
} else if (absElong > 45) {
|
|
6471
|
+
return { quality: "Fair", description: "Visible but not optimally placed" };
|
|
6472
|
+
} else {
|
|
6473
|
+
return { quality: "Poor", description: "Too close to Sun" };
|
|
6474
|
+
}
|
|
6475
|
+
} else {
|
|
6476
|
+
if (absElong > 40) {
|
|
6477
|
+
return { quality: "Excellent", description: "Near greatest elongation" };
|
|
6478
|
+
} else if (absElong > 20) {
|
|
6479
|
+
return { quality: "Good", description: "Well separated from Sun" };
|
|
6480
|
+
} else if (absElong > 10) {
|
|
6481
|
+
return { quality: "Fair", description: "Low in twilight" };
|
|
6482
|
+
} else {
|
|
6483
|
+
return { quality: "Poor", description: "Too close to Sun" };
|
|
6484
|
+
}
|
|
6485
|
+
}
|
|
6486
|
+
};
|
|
6487
|
+
var getPlanetVisibility = async (parameters) => {
|
|
6488
|
+
const { latitude, longitude, date: dateStr, timezone: timezone2 = "UTC" } = parameters;
|
|
6489
|
+
if (latitude === void 0 || latitude === null) {
|
|
6490
|
+
throw new Error("Latitude is required. Please provide a value between -90 and 90.");
|
|
6491
|
+
}
|
|
6492
|
+
if (longitude === void 0 || longitude === null) {
|
|
6493
|
+
throw new Error("Longitude is required. Please provide a value between -180 and 180.");
|
|
6494
|
+
}
|
|
6495
|
+
if (latitude < -90 || latitude > 90) {
|
|
6496
|
+
throw new Error(`Invalid latitude: ${latitude}. Must be between -90 and 90.`);
|
|
6497
|
+
}
|
|
6498
|
+
if (longitude < -180 || longitude > 180) {
|
|
6499
|
+
throw new Error(`Invalid longitude: ${longitude}. Must be between -180 and 180.`);
|
|
6500
|
+
}
|
|
6501
|
+
try {
|
|
6502
|
+
Intl.DateTimeFormat(void 0, { timeZone: timezone2 });
|
|
6503
|
+
} catch {
|
|
6504
|
+
throw new Error(`Invalid timezone: ${timezone2}. Please use IANA timezone format.`);
|
|
6505
|
+
}
|
|
6506
|
+
let date;
|
|
6507
|
+
if (dateStr) {
|
|
6508
|
+
const match = dateStr.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
|
6509
|
+
if (!match)
|
|
6510
|
+
throw new Error(`Invalid date format: ${dateStr}. Use YYYY-MM-DD.`);
|
|
6511
|
+
date = new Date(parseInt(match[1]), parseInt(match[2]) - 1, parseInt(match[3]), 12, 0, 0);
|
|
6512
|
+
} else {
|
|
6513
|
+
date = /* @__PURE__ */ new Date();
|
|
6514
|
+
}
|
|
6515
|
+
const jd = getJulianDay2(date);
|
|
6516
|
+
const T = getJulianCenturies(jd);
|
|
6517
|
+
const obliquity = 23.439 - 36e-8 * (jd - 2451545);
|
|
6518
|
+
const earthHelio = getHeliocentricCoords(EARTH, T);
|
|
6519
|
+
const sunLon = normalizeAngle(toDegrees2(Math.atan2(-earthHelio.y, -earthHelio.x)));
|
|
6520
|
+
const results = [];
|
|
6521
|
+
const dateFormatter = new Intl.DateTimeFormat("en-US", {
|
|
6522
|
+
timeZone: timezone2,
|
|
6523
|
+
weekday: "long",
|
|
6524
|
+
year: "numeric",
|
|
6525
|
+
month: "long",
|
|
6526
|
+
day: "numeric"
|
|
6527
|
+
});
|
|
6528
|
+
results.push(`\u{1FA90} **Planet Visibility for ${dateFormatter.format(date)}**`);
|
|
6529
|
+
results.push(`\u{1F4CD} ${Math.abs(latitude).toFixed(2)}\xB0${latitude >= 0 ? "N" : "S"}, ${Math.abs(longitude).toFixed(2)}\xB0${longitude >= 0 ? "E" : "W"}`);
|
|
6530
|
+
results.push("");
|
|
6531
|
+
const planetData = [];
|
|
6532
|
+
for (const planet of PLANETS) {
|
|
6533
|
+
const helio = getHeliocentricCoords(planet, T);
|
|
6534
|
+
const geo = getGeocentricEcliptic(helio, earthHelio);
|
|
6535
|
+
const equatorial = eclipticToEquatorial(geo.lon, geo.lat, obliquity);
|
|
6536
|
+
const lst = getLocalSiderealTime(jd, longitude);
|
|
6537
|
+
const altAz = getAltAz(equatorial.ra, equatorial.dec, latitude, lst);
|
|
6538
|
+
const elongation = getElongation(geo.lon, sunLon);
|
|
6539
|
+
const isSuperior = planet.a > 1;
|
|
6540
|
+
const visibility = getVisibilityDescription(elongation, altAz.alt, isSuperior);
|
|
6541
|
+
const riseSet = getRiseSetTimes(equatorial.ra, equatorial.dec, latitude, longitude, jd);
|
|
6542
|
+
planetData.push({
|
|
6543
|
+
name: planet.name,
|
|
6544
|
+
symbol: planet.symbol,
|
|
6545
|
+
color: planet.color,
|
|
6546
|
+
altitude: altAz.alt,
|
|
6547
|
+
azimuth: altAz.az,
|
|
6548
|
+
elongation,
|
|
6549
|
+
visibility,
|
|
6550
|
+
riseSet,
|
|
6551
|
+
isSuperior
|
|
6552
|
+
});
|
|
6553
|
+
}
|
|
6554
|
+
const visiblePlanets = planetData.filter((p) => p.visibility.quality !== "Not visible" && p.visibility.quality !== "Poor");
|
|
6555
|
+
const notVisiblePlanets = planetData.filter((p) => p.visibility.quality === "Not visible" || p.visibility.quality === "Poor");
|
|
6556
|
+
if (visiblePlanets.length > 0) {
|
|
6557
|
+
results.push("**Currently Visible Planets:**");
|
|
6558
|
+
results.push("");
|
|
6559
|
+
for (const p of visiblePlanets.sort((a, b) => b.altitude - a.altitude)) {
|
|
6560
|
+
const emoji = p.name === "Jupiter" ? "\u{1F7E0}" : p.name === "Saturn" ? "\u{1F7E1}" : p.name === "Mars" ? "\u{1F534}" : p.name === "Venus" ? "\u26AA" : "\u26AB";
|
|
6561
|
+
results.push(`${emoji} **${p.name}** ${p.symbol}`);
|
|
6562
|
+
results.push(` Visibility: ${p.visibility.quality} - ${p.visibility.description}`);
|
|
6563
|
+
if (p.altitude > 0) {
|
|
6564
|
+
results.push(` Current position: ${p.altitude.toFixed(1)}\xB0 altitude, ${getDirection(p.azimuth)} (${p.azimuth.toFixed(0)}\xB0)`);
|
|
6565
|
+
}
|
|
6566
|
+
if (p.riseSet.riseTime !== void 0) {
|
|
6567
|
+
results.push(` Rises: ${formatTime(p.riseSet.riseTime, timezone2)} | Transit: ${formatTime(p.riseSet.transitTime, timezone2)} | Sets: ${formatTime(p.riseSet.setTime, timezone2)}`);
|
|
6568
|
+
}
|
|
6569
|
+
if (p.isSuperior) {
|
|
6570
|
+
if (Math.abs(p.elongation) > 150) {
|
|
6571
|
+
results.push(` \u2B50 Near opposition! Best time to observe - visible all night`);
|
|
6572
|
+
} else if (p.elongation > 90) {
|
|
6573
|
+
results.push(` Evening sky - visible after sunset`);
|
|
6574
|
+
} else if (p.elongation < -90) {
|
|
6575
|
+
results.push(` Morning sky - visible before sunrise`);
|
|
6576
|
+
}
|
|
6577
|
+
} else {
|
|
6578
|
+
if (p.elongation > 0) {
|
|
6579
|
+
results.push(` Evening star - look west after sunset`);
|
|
6580
|
+
} else {
|
|
6581
|
+
results.push(` Morning star - look east before sunrise`);
|
|
6582
|
+
}
|
|
6583
|
+
}
|
|
6584
|
+
results.push("");
|
|
6585
|
+
}
|
|
6586
|
+
} else {
|
|
6587
|
+
results.push("_No planets are well-positioned for viewing tonight._");
|
|
6588
|
+
results.push("");
|
|
6589
|
+
}
|
|
6590
|
+
const conjunctions = [];
|
|
6591
|
+
for (let i = 0; i < planetData.length; i++) {
|
|
6592
|
+
for (let j = i + 1; j < planetData.length; j++) {
|
|
6593
|
+
const p1 = planetData[i];
|
|
6594
|
+
const p2 = planetData[j];
|
|
6595
|
+
const separation = Math.sqrt(Math.pow(p1.altitude - p2.altitude, 2) + Math.pow((p1.azimuth - p2.azimuth) * Math.cos(toRadians2(p1.altitude)), 2));
|
|
6596
|
+
if (separation < 10 && p1.altitude > 0 && p2.altitude > 0) {
|
|
6597
|
+
conjunctions.push(`${p1.name} and ${p2.name} are close together (${separation.toFixed(1)}\xB0 apart)`);
|
|
6598
|
+
}
|
|
5141
6599
|
}
|
|
5142
|
-
i++;
|
|
5143
|
-
}
|
|
5144
|
-
return result;
|
|
5145
|
-
}
|
|
5146
|
-
function parseTransformationResult(llmResponse) {
|
|
5147
|
-
if (!llmResponse || !llmResponse.trim()) {
|
|
5148
|
-
throw new Error("LLM returned an empty response. This may be due to content filtering, rate limiting, or a timeout. Please try again.");
|
|
5149
6600
|
}
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
throw new Error("Could not extract valid JSON from LLM response. The response may have been truncated or malformed.");
|
|
6601
|
+
if (conjunctions.length > 0) {
|
|
6602
|
+
results.push("**Planetary Conjunctions:**");
|
|
6603
|
+
conjunctions.forEach((c) => results.push(`- ${c}`));
|
|
6604
|
+
results.push("");
|
|
5155
6605
|
}
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
const
|
|
5159
|
-
|
|
5160
|
-
throw new Error("Missing required fields: title and content");
|
|
6606
|
+
if (notVisiblePlanets.length > 0) {
|
|
6607
|
+
results.push("**Not Currently Visible:**");
|
|
6608
|
+
for (const p of notVisiblePlanets) {
|
|
6609
|
+
results.push(`- ${p.symbol} ${p.name}: ${p.visibility.description}`);
|
|
5161
6610
|
}
|
|
5162
|
-
return {
|
|
5163
|
-
title: result.title,
|
|
5164
|
-
content: result.content,
|
|
5165
|
-
summary: result.summary || "",
|
|
5166
|
-
suggestedTags: result.suggestedTags || []
|
|
5167
|
-
};
|
|
5168
|
-
} catch (error) {
|
|
5169
|
-
console.error("Failed to parse transformation result:", { error, response: llmResponse });
|
|
5170
|
-
throw new Error("Failed to parse transformation result from LLM");
|
|
5171
6611
|
}
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
|
|
6612
|
+
results.push("");
|
|
6613
|
+
results.push("_Naked-eye planets: Mercury, Venus, Mars, Jupiter, Saturn_");
|
|
6614
|
+
return results.join("\n");
|
|
6615
|
+
};
|
|
6616
|
+
var planetVisibilityTool = {
|
|
6617
|
+
name: "planet_visibility",
|
|
5175
6618
|
implementation: (context) => ({
|
|
5176
6619
|
toolFn: async (value) => {
|
|
5177
6620
|
const params = value;
|
|
5178
|
-
|
|
5179
|
-
const outputFormat = params.outputFormat || "blog";
|
|
5180
|
-
logger.info("Drafting blog content", {
|
|
5181
|
-
userId: context.userId,
|
|
5182
|
-
outputFormat,
|
|
5183
|
-
hasVoiceGuide: !!params.voiceGuide,
|
|
5184
|
-
hasAdditionalInstructions: !!params.additionalInstructions
|
|
5185
|
-
});
|
|
6621
|
+
context.logger.log("\u{1FA90} PlanetVisibility: Starting execution", params);
|
|
5186
6622
|
try {
|
|
5187
|
-
const
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
additionalInstructions: params.additionalInstructions
|
|
5191
|
-
});
|
|
5192
|
-
const modelToUse = context.model || "claude-sonnet-4-5-20250929";
|
|
5193
|
-
logger.info("Using model for blog draft:", { model: modelToUse });
|
|
5194
|
-
let llmResponse = "";
|
|
5195
|
-
await llm.complete(modelToUse, [
|
|
5196
|
-
{ role: "system", content: systemPrompt },
|
|
5197
|
-
{
|
|
5198
|
-
role: "user",
|
|
5199
|
-
content: `Transform this content:
|
|
5200
|
-
|
|
5201
|
-
${params.sourceContent}`
|
|
5202
|
-
}
|
|
5203
|
-
], {
|
|
5204
|
-
temperature: 0.7,
|
|
5205
|
-
stream: false
|
|
5206
|
-
}, async (texts) => {
|
|
5207
|
-
llmResponse = texts.filter((t) => t !== null && t !== void 0).join("");
|
|
5208
|
-
});
|
|
5209
|
-
logger.info("Blog draft complete", { responseLength: llmResponse.length });
|
|
5210
|
-
const result = parseTransformationResult(llmResponse);
|
|
5211
|
-
logger.info("Blog draft created successfully", {
|
|
5212
|
-
title: result.title,
|
|
5213
|
-
contentLength: result.content.length,
|
|
5214
|
-
tagsCount: result.suggestedTags.length
|
|
5215
|
-
});
|
|
5216
|
-
return `\u2728 Blog draft created successfully!
|
|
5217
|
-
|
|
5218
|
-
\`\`\`json
|
|
5219
|
-
${JSON.stringify(result, null, 2)}
|
|
5220
|
-
\`\`\`
|
|
5221
|
-
|
|
5222
|
-
\u{1F4CB} The preview card will appear below for you to review and edit before publishing.
|
|
5223
|
-
`;
|
|
6623
|
+
const result = await getPlanetVisibility(params);
|
|
6624
|
+
context.logger.log("\u2705 PlanetVisibility: Execution completed");
|
|
6625
|
+
return result;
|
|
5224
6626
|
} catch (error) {
|
|
5225
|
-
logger.error("
|
|
6627
|
+
context.logger.error("\u274C PlanetVisibility: Execution failed", error);
|
|
5226
6628
|
throw error;
|
|
5227
6629
|
}
|
|
5228
6630
|
},
|
|
5229
6631
|
toolSchema: {
|
|
5230
|
-
name: "
|
|
5231
|
-
description:
|
|
6632
|
+
name: "planet_visibility",
|
|
6633
|
+
description: "Get visibility information for the 5 naked-eye planets (Mercury, Venus, Mars, Jupiter, Saturn). Shows which planets are visible tonight, their positions, rise/set times, and any planetary conjunctions.",
|
|
5232
6634
|
parameters: {
|
|
5233
6635
|
type: "object",
|
|
5234
6636
|
properties: {
|
|
5235
|
-
|
|
5236
|
-
type: "
|
|
5237
|
-
description: "
|
|
6637
|
+
latitude: {
|
|
6638
|
+
type: "number",
|
|
6639
|
+
description: "Latitude in decimal degrees (-90 to 90). Example: 40.7128 for New York City."
|
|
5238
6640
|
},
|
|
5239
|
-
|
|
5240
|
-
type: "
|
|
5241
|
-
description: "
|
|
6641
|
+
longitude: {
|
|
6642
|
+
type: "number",
|
|
6643
|
+
description: "Longitude in decimal degrees (-180 to 180). Example: -74.0060 for New York City."
|
|
5242
6644
|
},
|
|
5243
|
-
|
|
6645
|
+
date: {
|
|
5244
6646
|
type: "string",
|
|
5245
|
-
|
|
5246
|
-
description: 'Output format to generate. Currently only "blog" is fully supported. Others are coming soon.'
|
|
6647
|
+
description: "The date to check. Use YYYY-MM-DD format. Defaults to today if not specified."
|
|
5247
6648
|
},
|
|
5248
|
-
|
|
6649
|
+
timezone: {
|
|
5249
6650
|
type: "string",
|
|
5250
|
-
description: '
|
|
6651
|
+
description: 'IANA timezone identifier for time display (e.g., "America/New_York"). Defaults to UTC.'
|
|
5251
6652
|
}
|
|
5252
6653
|
},
|
|
5253
|
-
|
|
6654
|
+
additionalProperties: false,
|
|
6655
|
+
required: ["latitude", "longitude"]
|
|
5254
6656
|
}
|
|
5255
6657
|
}
|
|
5256
6658
|
})
|
|
@@ -5849,17 +7251,23 @@ var tools = {
|
|
|
5849
7251
|
blog_publish: blogPublishTool,
|
|
5850
7252
|
blog_edit: blogEditTool,
|
|
5851
7253
|
blog_draft: blogDraftTool,
|
|
7254
|
+
// Time Machine & Night Sky tools
|
|
7255
|
+
wikipedia_on_this_day: wikipediaOnThisDayTool,
|
|
7256
|
+
moon_phase: moonPhaseTool,
|
|
7257
|
+
sunrise_sunset: sunriseSunsetTool,
|
|
7258
|
+
iss_tracker: issTrackerTool,
|
|
7259
|
+
planet_visibility: planetVisibilityTool,
|
|
5852
7260
|
file_read: fileReadTool,
|
|
5853
7261
|
create_file: createFileTool,
|
|
5854
7262
|
glob_files: globFilesTool,
|
|
5855
7263
|
grep_search: grepSearchTool,
|
|
5856
7264
|
delete_file: deleteFileTool
|
|
5857
7265
|
};
|
|
5858
|
-
var generateTools = (userId, user,
|
|
7266
|
+
var generateTools = (userId, user, logger2, { db }, storage, imageGenerateStorage, statusUpdate, onStart, onFinish, llm, config, model) => {
|
|
5859
7267
|
const context = {
|
|
5860
7268
|
userId,
|
|
5861
7269
|
user,
|
|
5862
|
-
logger,
|
|
7270
|
+
logger: logger2,
|
|
5863
7271
|
db,
|
|
5864
7272
|
storage,
|
|
5865
7273
|
imageGenerateStorage,
|
|
@@ -5874,8 +7282,19 @@ var generateTools = (userId, user, logger, { db }, storage, imageGenerateStorage
|
|
|
5874
7282
|
[key]: tool.implementation(context, config[key])
|
|
5875
7283
|
}), {});
|
|
5876
7284
|
};
|
|
7285
|
+
var ATLASSIAN_RECONNECT_MESSAGE = "\u26A0\uFE0F Your Atlassian connection has expired.\n\nPlease reconnect your Atlassian account in Settings > Connected Apps to continue using Confluence and Jira tools.";
|
|
5877
7286
|
var generateMcpTools = async (mcpData) => {
|
|
5878
|
-
|
|
7287
|
+
let tools2;
|
|
7288
|
+
try {
|
|
7289
|
+
tools2 = await mcpData.getTools();
|
|
7290
|
+
} catch (error) {
|
|
7291
|
+
const errorName = error instanceof Error ? error.name : "";
|
|
7292
|
+
if (errorName === "AtlassianReconnectRequiredError") {
|
|
7293
|
+
console.warn(`Atlassian reconnection required during getTools for ${mcpData.serverName}`);
|
|
7294
|
+
return [];
|
|
7295
|
+
}
|
|
7296
|
+
throw error;
|
|
7297
|
+
}
|
|
5879
7298
|
const toolList = Array.isArray(tools2) ? tools2 : tools2?.tools || [];
|
|
5880
7299
|
if (!Array.isArray(tools2)) {
|
|
5881
7300
|
console.warn(`MCP server ${mcpData.serverName} returned unexpected tools payload:`, JSON.stringify(tools2));
|
|
@@ -5916,13 +7335,12 @@ var generateMcpTools = async (mcpData) => {
|
|
|
5916
7335
|
} catch (error) {
|
|
5917
7336
|
const serverName2 = mcpData.serverName?.toLowerCase();
|
|
5918
7337
|
if (serverName2 === "atlassian") {
|
|
7338
|
+
const errorName = error instanceof Error ? error.name : "";
|
|
5919
7339
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5920
|
-
const isTokenError = errorMessage.includes("401") || errorMessage.includes("403") || errorMessage.includes("unauthorized") || errorMessage.includes("expired");
|
|
7340
|
+
const isTokenError = errorName === "AtlassianReconnectRequiredError" || errorMessage.includes("401") || errorMessage.includes("403") || errorMessage.includes("unauthorized") || errorMessage.includes("expired");
|
|
5921
7341
|
if (isTokenError) {
|
|
5922
7342
|
console.warn(`Atlassian token may be expired for tool ${name}, error:`, errorMessage);
|
|
5923
|
-
return
|
|
5924
|
-
|
|
5925
|
-
The access token may have expired. Please disconnect and reconnect your Atlassian account in Settings > Connected Apps.`;
|
|
7343
|
+
return ATLASSIAN_RECONNECT_MESSAGE;
|
|
5926
7344
|
}
|
|
5927
7345
|
}
|
|
5928
7346
|
throw error;
|
|
@@ -6102,7 +7520,7 @@ async function generateFileDeletePreview(args) {
|
|
|
6102
7520
|
if (!existsSync4(args.path)) {
|
|
6103
7521
|
return `[File does not exist: ${args.path}]`;
|
|
6104
7522
|
}
|
|
6105
|
-
const stats = await import("fs/promises").then((
|
|
7523
|
+
const stats = await import("fs/promises").then((fs9) => fs9.stat(args.path));
|
|
6106
7524
|
return `[File will be deleted]
|
|
6107
7525
|
|
|
6108
7526
|
Path: ${args.path}
|
|
@@ -6118,21 +7536,21 @@ var NoOpStorage = class extends BaseStorage {
|
|
|
6118
7536
|
async upload(input, destination, options) {
|
|
6119
7537
|
return `/tmp/${destination}`;
|
|
6120
7538
|
}
|
|
6121
|
-
async download(
|
|
7539
|
+
async download(path11) {
|
|
6122
7540
|
throw new Error("Download not supported in CLI");
|
|
6123
7541
|
}
|
|
6124
|
-
async delete(
|
|
7542
|
+
async delete(path11) {
|
|
6125
7543
|
}
|
|
6126
|
-
async getSignedUrl(
|
|
6127
|
-
return `/tmp/${
|
|
7544
|
+
async getSignedUrl(path11) {
|
|
7545
|
+
return `/tmp/${path11}`;
|
|
6128
7546
|
}
|
|
6129
|
-
getPublicUrl(
|
|
6130
|
-
return `/tmp/${
|
|
7547
|
+
getPublicUrl(path11) {
|
|
7548
|
+
return `/tmp/${path11}`;
|
|
6131
7549
|
}
|
|
6132
|
-
async getPreview(
|
|
6133
|
-
return `/tmp/${
|
|
7550
|
+
async getPreview(path11) {
|
|
7551
|
+
return `/tmp/${path11}`;
|
|
6134
7552
|
}
|
|
6135
|
-
async getMetadata(
|
|
7553
|
+
async getMetadata(path11) {
|
|
6136
7554
|
return { size: 0, contentType: "application/octet-stream" };
|
|
6137
7555
|
}
|
|
6138
7556
|
};
|
|
@@ -6205,7 +7623,7 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
|
|
|
6205
7623
|
};
|
|
6206
7624
|
}
|
|
6207
7625
|
function generateCliTools(userId, llm, model, permissionManager, showPermissionPrompt, agentContext, toolApiKeys) {
|
|
6208
|
-
const
|
|
7626
|
+
const logger2 = new CliLogger();
|
|
6209
7627
|
const storage = new NoOpStorage();
|
|
6210
7628
|
const user = {
|
|
6211
7629
|
_id: userId,
|
|
@@ -6276,7 +7694,7 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
|
|
|
6276
7694
|
const toolsMap = generateTools(
|
|
6277
7695
|
userId,
|
|
6278
7696
|
user,
|
|
6279
|
-
|
|
7697
|
+
logger2,
|
|
6280
7698
|
dbAdapters,
|
|
6281
7699
|
storage,
|
|
6282
7700
|
storage,
|
|
@@ -6457,10 +7875,265 @@ function getEnvironmentName(configApiConfig) {
|
|
|
6457
7875
|
return "Bike4Mind";
|
|
6458
7876
|
}
|
|
6459
7877
|
|
|
7878
|
+
// src/utils/Logger.ts
|
|
7879
|
+
import fs8 from "fs/promises";
|
|
7880
|
+
import path9 from "path";
|
|
7881
|
+
import os from "os";
|
|
7882
|
+
var Logger2 = class _Logger {
|
|
7883
|
+
constructor() {
|
|
7884
|
+
this.logFilePath = null;
|
|
7885
|
+
this.sessionId = null;
|
|
7886
|
+
this.fileLoggingEnabled = true;
|
|
7887
|
+
this.consoleVerbose = false;
|
|
7888
|
+
}
|
|
7889
|
+
static {
|
|
7890
|
+
this.instance = null;
|
|
7891
|
+
}
|
|
7892
|
+
static getInstance() {
|
|
7893
|
+
if (!_Logger.instance) {
|
|
7894
|
+
_Logger.instance = new _Logger();
|
|
7895
|
+
}
|
|
7896
|
+
return _Logger.instance;
|
|
7897
|
+
}
|
|
7898
|
+
/**
|
|
7899
|
+
* Initialize the logger with a session ID
|
|
7900
|
+
*/
|
|
7901
|
+
async initialize(sessionId) {
|
|
7902
|
+
this.sessionId = sessionId;
|
|
7903
|
+
const debugDir = path9.join(os.homedir(), ".bike4mind", "debug");
|
|
7904
|
+
await fs8.mkdir(debugDir, { recursive: true });
|
|
7905
|
+
this.logFilePath = path9.join(debugDir, `${sessionId}.txt`);
|
|
7906
|
+
await this.writeToFile("INFO", "=== CLI SESSION START ===");
|
|
7907
|
+
}
|
|
7908
|
+
/**
|
|
7909
|
+
* Set whether verbose console logging is enabled
|
|
7910
|
+
*/
|
|
7911
|
+
setVerbose(enabled) {
|
|
7912
|
+
this.consoleVerbose = enabled;
|
|
7913
|
+
}
|
|
7914
|
+
/**
|
|
7915
|
+
* Set whether file logging is enabled
|
|
7916
|
+
*/
|
|
7917
|
+
setFileLoggingEnabled(enabled) {
|
|
7918
|
+
this.fileLoggingEnabled = enabled;
|
|
7919
|
+
}
|
|
7920
|
+
/**
|
|
7921
|
+
* DEBUG level - verbose-only console, always file
|
|
7922
|
+
*/
|
|
7923
|
+
debug(message) {
|
|
7924
|
+
this.writeToFile("DEBUG", message).catch(() => {
|
|
7925
|
+
});
|
|
7926
|
+
if (this.consoleVerbose) {
|
|
7927
|
+
console.log(message);
|
|
7928
|
+
}
|
|
7929
|
+
}
|
|
7930
|
+
/**
|
|
7931
|
+
* INFO level - always shown to user
|
|
7932
|
+
*/
|
|
7933
|
+
info(message) {
|
|
7934
|
+
this.writeToFile("INFO", message).catch(() => {
|
|
7935
|
+
});
|
|
7936
|
+
console.log(message);
|
|
7937
|
+
}
|
|
7938
|
+
/**
|
|
7939
|
+
* WARN level - always shown to user
|
|
7940
|
+
*/
|
|
7941
|
+
warn(message) {
|
|
7942
|
+
this.writeToFile("WARN", message).catch(() => {
|
|
7943
|
+
});
|
|
7944
|
+
console.warn(message);
|
|
7945
|
+
}
|
|
7946
|
+
/**
|
|
7947
|
+
* ERROR level - always shown to user
|
|
7948
|
+
*/
|
|
7949
|
+
error(message, err) {
|
|
7950
|
+
this.writeToFile("ERROR", message).catch(() => {
|
|
7951
|
+
});
|
|
7952
|
+
if (err) {
|
|
7953
|
+
this.logErrorDetailsToFile(err).catch(() => {
|
|
7954
|
+
});
|
|
7955
|
+
}
|
|
7956
|
+
console.error(message);
|
|
7957
|
+
}
|
|
7958
|
+
/**
|
|
7959
|
+
* Write log entry to file
|
|
7960
|
+
*/
|
|
7961
|
+
async writeToFile(level, message) {
|
|
7962
|
+
if (!this.fileLoggingEnabled || !this.logFilePath) {
|
|
7963
|
+
return;
|
|
7964
|
+
}
|
|
7965
|
+
try {
|
|
7966
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").substring(0, 19);
|
|
7967
|
+
const logEntry = `[${timestamp}] [${level}] ${message}
|
|
7968
|
+
`;
|
|
7969
|
+
await fs8.appendFile(this.logFilePath, logEntry, "utf-8");
|
|
7970
|
+
} catch (error) {
|
|
7971
|
+
console.error("File logging failed:", error);
|
|
7972
|
+
}
|
|
7973
|
+
}
|
|
7974
|
+
/**
|
|
7975
|
+
* Log error details to file
|
|
7976
|
+
*/
|
|
7977
|
+
async logErrorDetailsToFile(err) {
|
|
7978
|
+
if (!this.fileLoggingEnabled || !this.logFilePath) {
|
|
7979
|
+
return;
|
|
7980
|
+
}
|
|
7981
|
+
try {
|
|
7982
|
+
if (err && typeof err === "object" && "response" in err && err.response) {
|
|
7983
|
+
const response = err.response;
|
|
7984
|
+
const config = err && typeof err === "object" && "config" in err ? err.config : void 0;
|
|
7985
|
+
await this.writeToFile("ERROR", ` Status: ${response.status} ${response.statusText || ""}`);
|
|
7986
|
+
await this.writeToFile("ERROR", ` URL: ${config?.url || "unknown"}`);
|
|
7987
|
+
await this.writeToFile("ERROR", ` Headers: ${this.safeStringify(response.headers)}`);
|
|
7988
|
+
if (response.data) {
|
|
7989
|
+
const errorText = this.extractErrorMessage(response.data);
|
|
7990
|
+
if (errorText.trim().startsWith("<!DOCTYPE") || errorText.trim().startsWith("<html")) {
|
|
7991
|
+
await this.writeToFile("ERROR", ` Response Type: HTML Error Page`);
|
|
7992
|
+
const parsedError = this.parseHtmlError(errorText);
|
|
7993
|
+
if (parsedError) {
|
|
7994
|
+
await this.writeToFile("ERROR", ` Error Message: ${parsedError}`);
|
|
7995
|
+
}
|
|
7996
|
+
await this.writeToFile("ERROR", ` Raw HTML: ${this.truncate(errorText, 1e3)}`);
|
|
7997
|
+
} else {
|
|
7998
|
+
const preview = this.truncate(errorText, 500);
|
|
7999
|
+
await this.writeToFile("ERROR", ` Response: ${preview}`);
|
|
8000
|
+
}
|
|
8001
|
+
} else {
|
|
8002
|
+
await this.writeToFile("ERROR", ` Response: (no data)`);
|
|
8003
|
+
}
|
|
8004
|
+
}
|
|
8005
|
+
if (err && typeof err === "object" && "stack" in err && typeof err.stack === "string") {
|
|
8006
|
+
const stackLines = err.stack.split("\n").slice(0, 5).join("\n ");
|
|
8007
|
+
await this.writeToFile("ERROR", ` Stack: ${stackLines}`);
|
|
8008
|
+
} else if (err && typeof err === "object" && "message" in err && typeof err.message === "string") {
|
|
8009
|
+
await this.writeToFile("ERROR", ` Message: ${err.message}`);
|
|
8010
|
+
}
|
|
8011
|
+
} catch (error) {
|
|
8012
|
+
}
|
|
8013
|
+
}
|
|
8014
|
+
/**
|
|
8015
|
+
* Safely stringify object, handling circular references
|
|
8016
|
+
*/
|
|
8017
|
+
safeStringify(obj) {
|
|
8018
|
+
try {
|
|
8019
|
+
return JSON.stringify(obj);
|
|
8020
|
+
} catch (error) {
|
|
8021
|
+
if (error instanceof Error && error.message.includes("circular")) {
|
|
8022
|
+
try {
|
|
8023
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
8024
|
+
return JSON.stringify(obj, (key, value) => {
|
|
8025
|
+
if (typeof value === "object" && value !== null) {
|
|
8026
|
+
if (seen.has(value)) {
|
|
8027
|
+
return "[Circular]";
|
|
8028
|
+
}
|
|
8029
|
+
seen.add(value);
|
|
8030
|
+
}
|
|
8031
|
+
return value;
|
|
8032
|
+
});
|
|
8033
|
+
} catch {
|
|
8034
|
+
return "[Unable to stringify]";
|
|
8035
|
+
}
|
|
8036
|
+
}
|
|
8037
|
+
return "[Stringify error]";
|
|
8038
|
+
}
|
|
8039
|
+
}
|
|
8040
|
+
/**
|
|
8041
|
+
* Extract readable text from error response data
|
|
8042
|
+
*/
|
|
8043
|
+
extractErrorMessage(data) {
|
|
8044
|
+
if (Buffer.isBuffer(data)) {
|
|
8045
|
+
return data.toString("utf-8");
|
|
8046
|
+
}
|
|
8047
|
+
if (typeof data === "string") {
|
|
8048
|
+
return data;
|
|
8049
|
+
}
|
|
8050
|
+
if (data && typeof data === "object" && "_readableState" in data && data._readableState && typeof data._readableState === "object" && "buffer" in data._readableState && Array.isArray(data._readableState.buffer) && data._readableState.buffer.length > 0) {
|
|
8051
|
+
const chunks = [];
|
|
8052
|
+
for (const chunk of data._readableState.buffer) {
|
|
8053
|
+
if (chunk && typeof chunk === "object" && "type" in chunk && chunk.type === "Buffer" && "data" in chunk && Array.isArray(chunk.data)) {
|
|
8054
|
+
chunks.push(Buffer.from(chunk.data));
|
|
8055
|
+
} else if (Buffer.isBuffer(chunk)) {
|
|
8056
|
+
chunks.push(chunk);
|
|
8057
|
+
} else if (chunk && typeof chunk === "object" && "data" in chunk) {
|
|
8058
|
+
if (Buffer.isBuffer(chunk.data)) {
|
|
8059
|
+
chunks.push(chunk.data);
|
|
8060
|
+
} else if (Array.isArray(chunk.data)) {
|
|
8061
|
+
chunks.push(Buffer.from(chunk.data));
|
|
8062
|
+
}
|
|
8063
|
+
}
|
|
8064
|
+
}
|
|
8065
|
+
if (chunks.length > 0) {
|
|
8066
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
8067
|
+
}
|
|
8068
|
+
}
|
|
8069
|
+
return this.safeStringify(data);
|
|
8070
|
+
}
|
|
8071
|
+
/**
|
|
8072
|
+
* Parse HTML error page to extract error message
|
|
8073
|
+
*/
|
|
8074
|
+
parseHtmlError(html) {
|
|
8075
|
+
const titleMatch = html.match(/<title>(.*?)<\/title>/i);
|
|
8076
|
+
const h1Match = html.match(/<h1>(.*?)<\/h1>/i);
|
|
8077
|
+
const bodyMatch = html.match(/<body[^>]*>(.*?)<\/body>/is);
|
|
8078
|
+
if (titleMatch && titleMatch[1] !== "Error") {
|
|
8079
|
+
return titleMatch[1].trim();
|
|
8080
|
+
}
|
|
8081
|
+
if (h1Match) {
|
|
8082
|
+
return h1Match[1].trim();
|
|
8083
|
+
}
|
|
8084
|
+
if (bodyMatch) {
|
|
8085
|
+
const text = bodyMatch[1].replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
8086
|
+
return text.substring(0, 200);
|
|
8087
|
+
}
|
|
8088
|
+
return null;
|
|
8089
|
+
}
|
|
8090
|
+
/**
|
|
8091
|
+
* Truncate string to max length with ellipsis
|
|
8092
|
+
*/
|
|
8093
|
+
truncate(str, maxLength) {
|
|
8094
|
+
if (str.length <= maxLength) {
|
|
8095
|
+
return str;
|
|
8096
|
+
}
|
|
8097
|
+
return str.substring(0, maxLength) + "... [truncated]";
|
|
8098
|
+
}
|
|
8099
|
+
/**
|
|
8100
|
+
* Format bytes to human-readable size
|
|
8101
|
+
*/
|
|
8102
|
+
formatBytes(bytes) {
|
|
8103
|
+
if (bytes === 0) return "0 B";
|
|
8104
|
+
const k = 1024;
|
|
8105
|
+
const sizes = ["B", "KB", "MB", "GB"];
|
|
8106
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
8107
|
+
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + " " + sizes[i];
|
|
8108
|
+
}
|
|
8109
|
+
/**
|
|
8110
|
+
* Clean up old debug logs (older than 30 days)
|
|
8111
|
+
*/
|
|
8112
|
+
async cleanupOldLogs() {
|
|
8113
|
+
if (!this.fileLoggingEnabled) return;
|
|
8114
|
+
try {
|
|
8115
|
+
const debugDir = path9.join(os.homedir(), ".bike4mind", "debug");
|
|
8116
|
+
const files = await fs8.readdir(debugDir);
|
|
8117
|
+
const now = Date.now();
|
|
8118
|
+
const thirtyDaysAgo = now - 30 * 24 * 60 * 60 * 1e3;
|
|
8119
|
+
for (const file of files) {
|
|
8120
|
+
const filePath = path9.join(debugDir, file);
|
|
8121
|
+
const stats = await fs8.stat(filePath);
|
|
8122
|
+
if (stats.mtime.getTime() < thirtyDaysAgo) {
|
|
8123
|
+
await fs8.unlink(filePath);
|
|
8124
|
+
}
|
|
8125
|
+
}
|
|
8126
|
+
} catch (error) {
|
|
8127
|
+
console.error("Failed to cleanup old logs:", error);
|
|
8128
|
+
}
|
|
8129
|
+
}
|
|
8130
|
+
};
|
|
8131
|
+
var logger = Logger2.getInstance();
|
|
8132
|
+
|
|
6460
8133
|
// ../../b4m-core/packages/mcp/dist/src/client.js
|
|
6461
8134
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
6462
8135
|
import { Client as Client2 } from "@modelcontextprotocol/sdk/client/index.js";
|
|
6463
|
-
import
|
|
8136
|
+
import path10 from "path";
|
|
6464
8137
|
import { existsSync as existsSync5, readdirSync } from "fs";
|
|
6465
8138
|
var MCPClient = class {
|
|
6466
8139
|
// Note: This class handles MCP server communication with repository filtering
|
|
@@ -6486,16 +8159,16 @@ var MCPClient = class {
|
|
|
6486
8159
|
const root = process.env.INIT_CWD || process.cwd();
|
|
6487
8160
|
const candidatePaths = [
|
|
6488
8161
|
// When running from SST Lambda with node_modules structure (copyFiles)
|
|
6489
|
-
|
|
8162
|
+
path10.join(root, `node_modules/@bike4mind/mcp/dist/src/${this.serverName}/index.js`),
|
|
6490
8163
|
// When running from SST Lambda deployed environment (/var/task)
|
|
6491
|
-
|
|
8164
|
+
path10.join(root, `b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
6492
8165
|
// When running from SST Lambda (.sst/artifacts/mcpHandler-dev), navigate to monorepo root (3 levels up)
|
|
6493
|
-
|
|
8166
|
+
path10.join(root, `../../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
6494
8167
|
// When running from packages/client (Next.js app), navigate to monorepo root (2 levels up)
|
|
6495
|
-
|
|
8168
|
+
path10.join(root, `../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
6496
8169
|
// Original paths (backward compatibility)
|
|
6497
|
-
|
|
6498
|
-
|
|
8170
|
+
path10.join(root, `/b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
8171
|
+
path10.join(root, "core", "mcp", "servers", this.serverName, "dist", "index.js")
|
|
6499
8172
|
];
|
|
6500
8173
|
const serverScriptPath = candidatePaths.find((p) => existsSync5(p));
|
|
6501
8174
|
if (!serverScriptPath) {
|
|
@@ -6595,18 +8268,18 @@ var McpManager = class {
|
|
|
6595
8268
|
async initialize() {
|
|
6596
8269
|
const enabledServers = this.config.mcpServers.filter((s) => s.enabled);
|
|
6597
8270
|
if (enabledServers.length === 0) {
|
|
6598
|
-
|
|
8271
|
+
logger.info("\u{1F4E1} No MCP servers enabled");
|
|
6599
8272
|
return;
|
|
6600
8273
|
}
|
|
6601
|
-
|
|
8274
|
+
logger.info(`\u{1F4E1} Initializing ${enabledServers.length} MCP server(s)...`);
|
|
6602
8275
|
const results = await Promise.allSettled(enabledServers.map((serverConfig) => this.connectServer(serverConfig)));
|
|
6603
8276
|
const successful = results.filter((r) => r.status === "fulfilled").length;
|
|
6604
8277
|
const failed = results.filter((r) => r.status === "rejected").length;
|
|
6605
8278
|
if (successful > 0) {
|
|
6606
|
-
|
|
8279
|
+
logger.info(`\u2705 Connected to ${successful} MCP server(s)`);
|
|
6607
8280
|
}
|
|
6608
8281
|
if (failed > 0) {
|
|
6609
|
-
|
|
8282
|
+
logger.warn(`\u26A0\uFE0F Failed to connect to ${failed} MCP server(s)`);
|
|
6610
8283
|
}
|
|
6611
8284
|
}
|
|
6612
8285
|
/**
|
|
@@ -6614,7 +8287,7 @@ var McpManager = class {
|
|
|
6614
8287
|
*/
|
|
6615
8288
|
async connectServer(serverConfig) {
|
|
6616
8289
|
try {
|
|
6617
|
-
|
|
8290
|
+
logger.debug(`\u{1F504} Connecting to ${serverConfig.name}...`);
|
|
6618
8291
|
const envVariables = Object.entries(serverConfig.env).map(([key, value]) => ({
|
|
6619
8292
|
key,
|
|
6620
8293
|
value
|
|
@@ -6635,9 +8308,9 @@ var McpManager = class {
|
|
|
6635
8308
|
client,
|
|
6636
8309
|
tools: tools2
|
|
6637
8310
|
});
|
|
6638
|
-
|
|
8311
|
+
logger.info(`\u2705 Connected to ${serverConfig.name} (${tools2.length} tools)`);
|
|
6639
8312
|
} catch (error) {
|
|
6640
|
-
|
|
8313
|
+
logger.error(`\u274C Failed to connect to ${serverConfig.name}:`, error);
|
|
6641
8314
|
throw error;
|
|
6642
8315
|
}
|
|
6643
8316
|
}
|
|
@@ -6667,13 +8340,13 @@ var McpManager = class {
|
|
|
6667
8340
|
if (this.servers.size === 0) {
|
|
6668
8341
|
return;
|
|
6669
8342
|
}
|
|
6670
|
-
|
|
8343
|
+
logger.debug(`\u{1F50C} Disconnecting from ${this.servers.size} MCP server(s)...`);
|
|
6671
8344
|
const disconnectPromises = Array.from(this.servers.values()).map(async (server) => {
|
|
6672
8345
|
try {
|
|
6673
8346
|
await server.client.disconnect();
|
|
6674
|
-
|
|
8347
|
+
logger.debug(`\u2705 Disconnected from ${server.name}`);
|
|
6675
8348
|
} catch (error) {
|
|
6676
|
-
|
|
8349
|
+
logger.error(`\u26A0\uFE0F Error disconnecting from ${server.name}:`, error);
|
|
6677
8350
|
}
|
|
6678
8351
|
});
|
|
6679
8352
|
await Promise.allSettled(disconnectPromises);
|
|
@@ -6695,6 +8368,7 @@ var McpManager = class {
|
|
|
6695
8368
|
|
|
6696
8369
|
// src/llm/ServerLlmBackend.ts
|
|
6697
8370
|
import { createParser } from "eventsource-parser";
|
|
8371
|
+
import { isAxiosError } from "axios";
|
|
6698
8372
|
function stripThinkingBlocks(text) {
|
|
6699
8373
|
return text.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
|
|
6700
8374
|
}
|
|
@@ -6709,12 +8383,12 @@ var ServerLlmBackend = class {
|
|
|
6709
8383
|
* Parses SSE stream and invokes callback for each event
|
|
6710
8384
|
*/
|
|
6711
8385
|
async complete(model, messages, options, callback) {
|
|
6712
|
-
|
|
8386
|
+
logger.debug(`[ServerLlmBackend] Starting complete() with model: ${model}`);
|
|
6713
8387
|
return new Promise(async (resolve, reject) => {
|
|
6714
8388
|
try {
|
|
6715
|
-
|
|
8389
|
+
logger.debug("[ServerLlmBackend] Making streaming request...");
|
|
6716
8390
|
const response = await this.makeStreamingRequest(model, messages, options);
|
|
6717
|
-
|
|
8391
|
+
logger.debug("[ServerLlmBackend] Got response, setting up SSE parser");
|
|
6718
8392
|
let eventCount = 0;
|
|
6719
8393
|
let accumulatedText = "";
|
|
6720
8394
|
let lastUsageInfo = {};
|
|
@@ -6723,28 +8397,28 @@ var ServerLlmBackend = class {
|
|
|
6723
8397
|
const parser = createParser({
|
|
6724
8398
|
onEvent: (event) => {
|
|
6725
8399
|
eventCount++;
|
|
6726
|
-
|
|
8400
|
+
logger.debug(`[ServerLlmBackend] SSE event #${eventCount}, data: ${event.data?.substring(0, 100)}`);
|
|
6727
8401
|
const data = event.data;
|
|
6728
8402
|
if (data === "[DONE]") {
|
|
6729
8403
|
receivedDone = true;
|
|
6730
|
-
|
|
8404
|
+
logger.debug(`[ServerLlmBackend] Received [DONE], accumulated text length: ${accumulatedText.length}`);
|
|
6731
8405
|
const cleanedText = stripThinkingBlocks(accumulatedText);
|
|
6732
8406
|
if (toolsUsed.length > 0) {
|
|
6733
8407
|
const info = {
|
|
6734
8408
|
toolsUsed,
|
|
6735
8409
|
...lastUsageInfo
|
|
6736
8410
|
};
|
|
6737
|
-
|
|
8411
|
+
logger.debug("[ServerLlmBackend] Calling callback with tools, will wait for completion");
|
|
6738
8412
|
callback([cleanedText], info).catch((err) => {
|
|
6739
|
-
|
|
8413
|
+
logger.error("[ServerLlmBackend] Callback error:", err);
|
|
6740
8414
|
reject(err);
|
|
6741
8415
|
}).then(() => {
|
|
6742
|
-
|
|
8416
|
+
logger.debug("[ServerLlmBackend] Callback completed, resolving");
|
|
6743
8417
|
resolve();
|
|
6744
8418
|
});
|
|
6745
8419
|
} else if (cleanedText) {
|
|
6746
8420
|
callback([cleanedText], lastUsageInfo).catch((err) => {
|
|
6747
|
-
|
|
8421
|
+
logger.error("[ServerLlmBackend] Callback error:", err);
|
|
6748
8422
|
reject(err);
|
|
6749
8423
|
}).then(() => resolve());
|
|
6750
8424
|
} else {
|
|
@@ -6754,9 +8428,9 @@ var ServerLlmBackend = class {
|
|
|
6754
8428
|
}
|
|
6755
8429
|
try {
|
|
6756
8430
|
const parsed = JSON.parse(data);
|
|
6757
|
-
|
|
8431
|
+
logger.debug(`[ServerLlmBackend] Parsed event type: ${parsed.type}`);
|
|
6758
8432
|
if (parsed.type === "error") {
|
|
6759
|
-
|
|
8433
|
+
logger.error("[ServerLlmBackend] Error event:", parsed);
|
|
6760
8434
|
reject(new Error(parsed.message || "Server error"));
|
|
6761
8435
|
return;
|
|
6762
8436
|
}
|
|
@@ -6769,9 +8443,20 @@ var ServerLlmBackend = class {
|
|
|
6769
8443
|
outputTokens: parsed.usage.outputTokens
|
|
6770
8444
|
};
|
|
6771
8445
|
}
|
|
6772
|
-
|
|
8446
|
+
logger.debug(`[ServerLlmBackend] Accumulated text length: ${accumulatedText.length}`);
|
|
6773
8447
|
} else if (parsed.type === "tool_use") {
|
|
6774
|
-
|
|
8448
|
+
logger.debug(`[ServerLlmBackend] Tool use event, tools: ${parsed.tools?.length}`);
|
|
8449
|
+
if (parsed.tools && parsed.tools.length > 0) {
|
|
8450
|
+
for (const tool of parsed.tools) {
|
|
8451
|
+
logger.debug(`TOOL REQUEST: ${tool.name}`);
|
|
8452
|
+
try {
|
|
8453
|
+
const paramsStr = JSON.stringify(tool.input);
|
|
8454
|
+
logger.debug(` Params: ${paramsStr}`);
|
|
8455
|
+
} catch {
|
|
8456
|
+
logger.debug(` Params: [Unable to stringify]`);
|
|
8457
|
+
}
|
|
8458
|
+
}
|
|
8459
|
+
}
|
|
6775
8460
|
const textChunk = parsed.text || "";
|
|
6776
8461
|
if (textChunk) {
|
|
6777
8462
|
accumulatedText += textChunk;
|
|
@@ -6787,7 +8472,7 @@ var ServerLlmBackend = class {
|
|
|
6787
8472
|
}
|
|
6788
8473
|
}
|
|
6789
8474
|
} catch (parseError) {
|
|
6790
|
-
|
|
8475
|
+
logger.error("[ServerLlmBackend] Failed to parse SSE event:", parseError);
|
|
6791
8476
|
}
|
|
6792
8477
|
}
|
|
6793
8478
|
});
|
|
@@ -6796,16 +8481,72 @@ var ServerLlmBackend = class {
|
|
|
6796
8481
|
});
|
|
6797
8482
|
response.data.on("end", () => {
|
|
6798
8483
|
if (!receivedDone) {
|
|
6799
|
-
|
|
8484
|
+
logger.debug("[ServerLlmBackend] Stream ended without [DONE], resolving anyway");
|
|
6800
8485
|
resolve();
|
|
6801
8486
|
} else {
|
|
6802
|
-
|
|
8487
|
+
logger.debug("[ServerLlmBackend] Stream ended, [DONE] handler will resolve");
|
|
6803
8488
|
}
|
|
6804
8489
|
});
|
|
6805
8490
|
response.data.on("error", (error) => {
|
|
6806
8491
|
reject(error);
|
|
6807
8492
|
});
|
|
6808
8493
|
} catch (error) {
|
|
8494
|
+
logger.error("LLM completion failed", error);
|
|
8495
|
+
if (isAxiosError(error)) {
|
|
8496
|
+
logger.debug(
|
|
8497
|
+
`[ServerLlmBackend] Axios error details: ${JSON.stringify({
|
|
8498
|
+
status: error.response?.status,
|
|
8499
|
+
statusText: error.response?.statusText,
|
|
8500
|
+
url: error.config?.url,
|
|
8501
|
+
method: error.config?.method
|
|
8502
|
+
})}`
|
|
8503
|
+
);
|
|
8504
|
+
if (error.response?.status === 403 && error.response.data) {
|
|
8505
|
+
let errorDetails = "";
|
|
8506
|
+
try {
|
|
8507
|
+
let responseText = "";
|
|
8508
|
+
const stream = error.response.data;
|
|
8509
|
+
if (Buffer.isBuffer(stream)) {
|
|
8510
|
+
responseText = stream.toString("utf-8");
|
|
8511
|
+
} else if (stream?._readableState?.buffer?.length > 0) {
|
|
8512
|
+
const chunks = [];
|
|
8513
|
+
for (const chunk of stream._readableState.buffer) {
|
|
8514
|
+
if (chunk?.data) {
|
|
8515
|
+
chunks.push(Buffer.from(chunk.data));
|
|
8516
|
+
}
|
|
8517
|
+
}
|
|
8518
|
+
responseText = Buffer.concat(chunks).toString("utf-8");
|
|
8519
|
+
} else if (typeof stream === "string") {
|
|
8520
|
+
responseText = stream;
|
|
8521
|
+
}
|
|
8522
|
+
logger.debug(`[ServerLlmBackend] Response preview: ${responseText.substring(0, 200)}`);
|
|
8523
|
+
if (responseText.includes("<!DOCTYPE") || responseText.includes("<html")) {
|
|
8524
|
+
const titleMatch = responseText.match(/<title>(.*?)<\/title>/i);
|
|
8525
|
+
const h1Match = responseText.match(/<h1>(.*?)<\/h1>/i);
|
|
8526
|
+
if (titleMatch && titleMatch[1] !== "Error") {
|
|
8527
|
+
errorDetails = titleMatch[1].trim();
|
|
8528
|
+
} else if (h1Match) {
|
|
8529
|
+
errorDetails = h1Match[1].trim();
|
|
8530
|
+
}
|
|
8531
|
+
} else if (responseText) {
|
|
8532
|
+
errorDetails = responseText.substring(0, 100).trim();
|
|
8533
|
+
}
|
|
8534
|
+
} catch (extractError) {
|
|
8535
|
+
logger.error("[ServerLlmBackend] Error extracting response:", extractError);
|
|
8536
|
+
}
|
|
8537
|
+
const errorMsg = errorDetails ? `403 Forbidden: ${errorDetails}` : "403 Forbidden - Request blocked by server. Check debug logs at ~/.bike4mind/debug/";
|
|
8538
|
+
reject(new Error(errorMsg));
|
|
8539
|
+
return;
|
|
8540
|
+
}
|
|
8541
|
+
if (error.response) {
|
|
8542
|
+
reject(
|
|
8543
|
+
new Error(
|
|
8544
|
+
`Request failed with status ${error.response.status}: ${error.response.statusText || "Unknown error"}`
|
|
8545
|
+
)
|
|
8546
|
+
);
|
|
8547
|
+
return;
|
|
8548
|
+
}
|
|
8549
|
+
}
|
|
6809
8550
|
if (error instanceof Error) {
|
|
6810
8551
|
if (error.message.includes("Authentication expired") || error.message.includes("Authentication failed")) {
|
|
6811
8552
|
reject(error);
|
|
@@ -6851,28 +8592,28 @@ var ServerLlmBackend = class {
|
|
|
6851
8592
|
* Uses axios with responseType 'stream' for SSE
|
|
6852
8593
|
*/
|
|
6853
8594
|
async makeStreamingRequest(model, messages, options) {
|
|
6854
|
-
const axiosInstance = this.apiClient.
|
|
6855
|
-
|
|
6856
|
-
|
|
6857
|
-
|
|
6858
|
-
|
|
6859
|
-
|
|
6860
|
-
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
|
|
6864
|
-
temperature: options.temperature,
|
|
6865
|
-
maxTokens: options.maxTokens,
|
|
6866
|
-
stream: true,
|
|
6867
|
-
// Always use streaming for SSE
|
|
6868
|
-
tools: options.tools || []
|
|
6869
|
-
}
|
|
6870
|
-
},
|
|
6871
|
-
{
|
|
6872
|
-
responseType: "stream"
|
|
6873
|
-
// Auth header is automatically injected by ApiClient interceptor
|
|
8595
|
+
const axiosInstance = this.apiClient.getAxiosInstance();
|
|
8596
|
+
const requestBody = {
|
|
8597
|
+
model,
|
|
8598
|
+
messages,
|
|
8599
|
+
options: {
|
|
8600
|
+
temperature: options.temperature,
|
|
8601
|
+
maxTokens: options.maxTokens,
|
|
8602
|
+
stream: true,
|
|
8603
|
+
// Always use streaming for SSE
|
|
8604
|
+
tools: options.tools || []
|
|
6874
8605
|
}
|
|
6875
|
-
|
|
8606
|
+
};
|
|
8607
|
+
const bodyStr = JSON.stringify(requestBody);
|
|
8608
|
+
const bodySize = Buffer.byteLength(bodyStr, "utf-8");
|
|
8609
|
+
logger.debug(`\u2192 POST ${this.completionsEndpoint}`);
|
|
8610
|
+
logger.debug(` Body: ${logger.formatBytes(bodySize)}`);
|
|
8611
|
+
logger.debug(` Preview: ${bodyStr.substring(0, 200)}`);
|
|
8612
|
+
const response = await axiosInstance.post(this.completionsEndpoint, requestBody, {
|
|
8613
|
+
responseType: "stream"
|
|
8614
|
+
// Auth header is automatically injected by ApiClient interceptor
|
|
8615
|
+
});
|
|
8616
|
+
logger.debug(`\u2190 ${response.status} ${response.statusText}`);
|
|
6876
8617
|
return response;
|
|
6877
8618
|
}
|
|
6878
8619
|
};
|
|
@@ -6903,14 +8644,21 @@ var ApiClient = class {
|
|
|
6903
8644
|
(response) => response,
|
|
6904
8645
|
async (error) => {
|
|
6905
8646
|
const originalRequest = error.config;
|
|
8647
|
+
if (error.response?.status === 401) {
|
|
8648
|
+
logger.error("401 Unauthorized", error);
|
|
8649
|
+
} else if (error.response?.status === 403) {
|
|
8650
|
+
logger.error("403 Forbidden", error);
|
|
8651
|
+
}
|
|
6906
8652
|
if (error.response?.status === 401 && !originalRequest._retry) {
|
|
6907
8653
|
originalRequest._retry = true;
|
|
8654
|
+
logger.debug("AUTH: Attempting token refresh");
|
|
6908
8655
|
try {
|
|
6909
8656
|
const tokens = await this.configStore.getAuthTokens();
|
|
6910
8657
|
if (!tokens) {
|
|
6911
8658
|
throw new Error("Not authenticated");
|
|
6912
8659
|
}
|
|
6913
8660
|
const newTokens = await this.oauthClient.refreshToken(tokens.refreshToken);
|
|
8661
|
+
logger.debug("AUTH: Token refresh successful");
|
|
6914
8662
|
const expiresAt = new Date(Date.now() + newTokens.expires_in * 1e3).toISOString();
|
|
6915
8663
|
await this.configStore.setAuthTokens({
|
|
6916
8664
|
accessToken: newTokens.access_token,
|
|
@@ -6920,6 +8668,7 @@ var ApiClient = class {
|
|
|
6920
8668
|
// Preserve userId
|
|
6921
8669
|
});
|
|
6922
8670
|
originalRequest.headers.Authorization = `Bearer ${newTokens.access_token}`;
|
|
8671
|
+
logger.debug("AUTH: Retrying request with new token");
|
|
6923
8672
|
return this.client(originalRequest);
|
|
6924
8673
|
} catch (refreshError) {
|
|
6925
8674
|
console.error(
|
|
@@ -6927,11 +8676,13 @@ var ApiClient = class {
|
|
|
6927
8676
|
refreshError instanceof Error ? refreshError.message : "Unknown error"
|
|
6928
8677
|
);
|
|
6929
8678
|
console.log("Please run `b4m login` again to re-authenticate.");
|
|
8679
|
+
logger.error("AUTH: Token refresh failed", refreshError);
|
|
6930
8680
|
await this.configStore.clearAuthTokens();
|
|
6931
8681
|
throw new Error("Authentication expired. Please run `b4m login` again.");
|
|
6932
8682
|
}
|
|
6933
8683
|
}
|
|
6934
8684
|
if (error.response?.status === 401 && originalRequest._retry) {
|
|
8685
|
+
logger.debug("AUTH: Token refresh retry failed - clearing tokens");
|
|
6935
8686
|
await this.configStore.clearAuthTokens();
|
|
6936
8687
|
throw new Error("Authentication failed. Please run /login to authenticate.");
|
|
6937
8688
|
}
|
|
@@ -6967,6 +8718,12 @@ var ApiClient = class {
|
|
|
6967
8718
|
const response = await this.client.delete(url, config);
|
|
6968
8719
|
return response.data;
|
|
6969
8720
|
}
|
|
8721
|
+
/**
|
|
8722
|
+
* Get the underlying axios instance for advanced use cases (e.g., streaming)
|
|
8723
|
+
*/
|
|
8724
|
+
getAxiosInstance() {
|
|
8725
|
+
return this.client;
|
|
8726
|
+
}
|
|
6970
8727
|
/**
|
|
6971
8728
|
* Check if user is authenticated
|
|
6972
8729
|
*/
|
|
@@ -6989,6 +8746,123 @@ var ApiClient = class {
|
|
|
6989
8746
|
}
|
|
6990
8747
|
};
|
|
6991
8748
|
|
|
8749
|
+
// package.json
|
|
8750
|
+
var package_default = {
|
|
8751
|
+
name: "@bike4mind/cli",
|
|
8752
|
+
version: "0.1.5-feat-automate-cli-publishing.16903+b709a6e8f",
|
|
8753
|
+
type: "module",
|
|
8754
|
+
description: "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
8755
|
+
license: "UNLICENSED",
|
|
8756
|
+
author: "Bike4Mind",
|
|
8757
|
+
repository: {
|
|
8758
|
+
type: "git",
|
|
8759
|
+
url: "git+https://github.com/bike4mind/lumina5.git"
|
|
8760
|
+
},
|
|
8761
|
+
homepage: "https://github.com/bike4mind/lumina5#readme",
|
|
8762
|
+
bugs: "https://github.com/bike4mind/lumina5/issues",
|
|
8763
|
+
keywords: [
|
|
8764
|
+
"cli",
|
|
8765
|
+
"ai",
|
|
8766
|
+
"bike4mind",
|
|
8767
|
+
"agent",
|
|
8768
|
+
"mcp",
|
|
8769
|
+
"react-agent"
|
|
8770
|
+
],
|
|
8771
|
+
bin: {
|
|
8772
|
+
b4m: "./bin/bike4mind-cli.mjs",
|
|
8773
|
+
bike4mind: "./bin/bike4mind-cli.mjs"
|
|
8774
|
+
},
|
|
8775
|
+
files: [
|
|
8776
|
+
"dist",
|
|
8777
|
+
"bin"
|
|
8778
|
+
],
|
|
8779
|
+
scripts: {
|
|
8780
|
+
dev: "tsx src/index.tsx",
|
|
8781
|
+
build: "tsup",
|
|
8782
|
+
typecheck: "tsc --noEmit",
|
|
8783
|
+
start: "node dist/index.js",
|
|
8784
|
+
prepublishOnly: "pnpm build"
|
|
8785
|
+
},
|
|
8786
|
+
dependencies: {
|
|
8787
|
+
"@anthropic-ai/sdk": "^0.22.0",
|
|
8788
|
+
"@aws-sdk/client-apigatewaymanagementapi": "3.654.0",
|
|
8789
|
+
"@aws-sdk/client-bedrock-runtime": "3.654.0",
|
|
8790
|
+
"@aws-sdk/client-lambda": "3.654.0",
|
|
8791
|
+
"@aws-sdk/client-s3": "3.654.0",
|
|
8792
|
+
"@aws-sdk/client-sqs": "3.654.0",
|
|
8793
|
+
"@aws-sdk/client-transcribe": "3.654.0",
|
|
8794
|
+
"@aws-sdk/credential-provider-node": "3.654.0",
|
|
8795
|
+
"@aws-sdk/node-http-handler": "^3.374.0",
|
|
8796
|
+
"@aws-sdk/s3-request-presigner": "3.654.0",
|
|
8797
|
+
"@casl/ability": "^6.5.0",
|
|
8798
|
+
"@google/genai": "^1.27.0",
|
|
8799
|
+
"@google/generative-ai": "^0.21.0",
|
|
8800
|
+
"@joplin/turndown-plugin-gfm": "^1.0.62",
|
|
8801
|
+
"@mendable/firecrawl-js": "^1.29.3",
|
|
8802
|
+
"@modelcontextprotocol/sdk": "^1.7.0",
|
|
8803
|
+
"@octokit/rest": "^22.0.0",
|
|
8804
|
+
"@opensearch-project/opensearch": "2.11.0",
|
|
8805
|
+
"async-mutex": "^0.5.0",
|
|
8806
|
+
axios: "^1.13.2",
|
|
8807
|
+
bcryptjs: "^2.4.3",
|
|
8808
|
+
cheerio: "1.0.0-rc.12",
|
|
8809
|
+
"csv-parse": "^5.5.6",
|
|
8810
|
+
dayjs: "^1.11.13",
|
|
8811
|
+
diff: "^8.0.2",
|
|
8812
|
+
dotenv: "^16.3.1",
|
|
8813
|
+
"eventsource-parser": "^3.0.6",
|
|
8814
|
+
"file-type": "^18.7.0",
|
|
8815
|
+
"fuse.js": "^7.1.0",
|
|
8816
|
+
ink: "^6.5.1",
|
|
8817
|
+
"ink-select-input": "^6.2.0",
|
|
8818
|
+
"ink-spinner": "^5.0.0",
|
|
8819
|
+
"ink-text-input": "^6.0.0",
|
|
8820
|
+
jsonwebtoken: "^9.0.2",
|
|
8821
|
+
lodash: "^4.17.21",
|
|
8822
|
+
mammoth: "^1.11.0",
|
|
8823
|
+
marked: "^15.0.11",
|
|
8824
|
+
mathjs: "^14.2.0",
|
|
8825
|
+
"mime-types": "^2.1.35",
|
|
8826
|
+
mongoose: "^8.8.3",
|
|
8827
|
+
ollama: "^0.5.12",
|
|
8828
|
+
open: "^11.0.0",
|
|
8829
|
+
openai: "^5.12.2",
|
|
8830
|
+
"p-limit": "^6.2.0",
|
|
8831
|
+
qrcode: "^1.5.4",
|
|
8832
|
+
react: "^19.2.3",
|
|
8833
|
+
sharp: "^0.32.6",
|
|
8834
|
+
speakeasy: "^2.0.0",
|
|
8835
|
+
tiktoken: "^1.0.16",
|
|
8836
|
+
turndown: "^7.2.0",
|
|
8837
|
+
unpdf: "^0.10.0",
|
|
8838
|
+
uuid: "^9.0.1",
|
|
8839
|
+
voyageai: "^0.0.4",
|
|
8840
|
+
xlsx: "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
|
|
8841
|
+
yargs: "^17.7.2",
|
|
8842
|
+
yauzl: "^3.1.3",
|
|
8843
|
+
zod: "^3.25.76",
|
|
8844
|
+
"zod-validation-error": "^1.5.0",
|
|
8845
|
+
zustand: "^4.5.4"
|
|
8846
|
+
},
|
|
8847
|
+
devDependencies: {
|
|
8848
|
+
"@bike4mind/agents": "0.1.0",
|
|
8849
|
+
"@bike4mind/common": "2.35.1-feat-automate-cli-publishing.16903+b709a6e8f",
|
|
8850
|
+
"@bike4mind/mcp": "1.19.3-feat-automate-cli-publishing.16903+b709a6e8f",
|
|
8851
|
+
"@bike4mind/services": "2.28.1-feat-automate-cli-publishing.16903+b709a6e8f",
|
|
8852
|
+
"@bike4mind/utils": "2.0.1-feat-automate-cli-publishing.16903+b709a6e8f",
|
|
8853
|
+
"@types/diff": "^5.0.9",
|
|
8854
|
+
"@types/jsonwebtoken": "^9.0.4",
|
|
8855
|
+
"@types/node": "^22.9.0",
|
|
8856
|
+
"@types/react": "^19.2.7",
|
|
8857
|
+
"@types/uuid": "^9.0.7",
|
|
8858
|
+
"@types/yargs": "^17.0.32",
|
|
8859
|
+
tsup: "^8.5.1",
|
|
8860
|
+
tsx: "^4.21.0",
|
|
8861
|
+
typescript: "^5.9.3"
|
|
8862
|
+
},
|
|
8863
|
+
gitHead: "b709a6e8ff6c4b9c1b3ce3ab0d3c548c7feb7cb4"
|
|
8864
|
+
};
|
|
8865
|
+
|
|
6992
8866
|
// src/index.tsx
|
|
6993
8867
|
process.removeAllListeners("warning");
|
|
6994
8868
|
process.on("warning", (warning) => {
|
|
@@ -7022,14 +8896,14 @@ function CliApp() {
|
|
|
7022
8896
|
if (state.session) {
|
|
7023
8897
|
cleanupTasks.push(
|
|
7024
8898
|
state.sessionStore.save(state.session).catch((err) => {
|
|
7025
|
-
|
|
8899
|
+
logger.debug(`[CLEANUP] Session save error: ${err.message}`);
|
|
7026
8900
|
})
|
|
7027
8901
|
);
|
|
7028
8902
|
}
|
|
7029
8903
|
if (state.mcpManager) {
|
|
7030
8904
|
cleanupTasks.push(
|
|
7031
8905
|
state.mcpManager.disconnect().catch((err) => {
|
|
7032
|
-
|
|
8906
|
+
logger.debug(`[CLEANUP] MCP disconnect error: ${err.message}`);
|
|
7033
8907
|
})
|
|
7034
8908
|
);
|
|
7035
8909
|
}
|
|
@@ -7049,12 +8923,12 @@ function CliApp() {
|
|
|
7049
8923
|
if (key.ctrl && input === "c") {
|
|
7050
8924
|
const now = Date.now();
|
|
7051
8925
|
if (exitTimestamp && now - exitTimestamp < EXIT_TIMEOUT_MS) {
|
|
7052
|
-
|
|
8926
|
+
logger.debug("[EXIT Second Ctrl+C - cleaning up and exiting...");
|
|
7053
8927
|
performCleanup().then(() => {
|
|
7054
8928
|
exit();
|
|
7055
8929
|
});
|
|
7056
8930
|
} else {
|
|
7057
|
-
|
|
8931
|
+
logger.debug("[EXIT First Ctrl+C - press again to exit");
|
|
7058
8932
|
exitTimestamp = now;
|
|
7059
8933
|
setExitRequested(true);
|
|
7060
8934
|
setTimeout(() => {
|
|
@@ -7150,6 +9024,14 @@ function CliApp() {
|
|
|
7150
9024
|
toolCallCount: 0
|
|
7151
9025
|
}
|
|
7152
9026
|
};
|
|
9027
|
+
await logger.initialize(newSession.id);
|
|
9028
|
+
logger.setVerbose(process.env.B4M_VERBOSE === "1");
|
|
9029
|
+
logger.info(`API: ${apiBaseURL}`);
|
|
9030
|
+
logger.info(`Environment: ${envName}`);
|
|
9031
|
+
logger.info(`Model: ${modelInfo.id}`);
|
|
9032
|
+
logger.debug("=== Session Configuration Complete ===");
|
|
9033
|
+
logger.cleanupOldLogs().catch(() => {
|
|
9034
|
+
});
|
|
7153
9035
|
const silentLogger = {
|
|
7154
9036
|
log: () => {
|
|
7155
9037
|
},
|
|
@@ -7372,7 +9254,7 @@ Tool Permissions:
|
|
|
7372
9254
|
break;
|
|
7373
9255
|
case "exit":
|
|
7374
9256
|
case "quit":
|
|
7375
|
-
|
|
9257
|
+
logger.debug("[EXIT /exit command - cleaning up and exiting...");
|
|
7376
9258
|
await performCleanup();
|
|
7377
9259
|
exit();
|
|
7378
9260
|
break;
|
|
@@ -7585,7 +9467,8 @@ var BANNER = `
|
|
|
7585
9467
|
\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D
|
|
7586
9468
|
`;
|
|
7587
9469
|
console.log("\x1B[36m\x1B[1m%s\x1B[0m", BANNER);
|
|
7588
|
-
console.log(
|
|
9470
|
+
console.log(`\x1B[2m v${package_default.version} - AI-Powered CLI\x1B[0m
|
|
9471
|
+
`);
|
|
7589
9472
|
var isDevMode = import.meta.url.includes("/src/") || process.env.NODE_ENV === "development";
|
|
7590
9473
|
if (isDevMode) {
|
|
7591
9474
|
console.log("\u{1F527} Running in development mode (using TypeScript source)\n");
|