@mestreyoda/fabrica 0.1.13 → 0.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +128 -43
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -111329,8 +111329,8 @@ import fsSync from "node:fs";
|
|
|
111329
111329
|
import path5 from "node:path";
|
|
111330
111330
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
111331
111331
|
function getCurrentVersion() {
|
|
111332
|
-
if ("0.1.
|
|
111333
|
-
return "0.1.
|
|
111332
|
+
if ("0.1.15") {
|
|
111333
|
+
return "0.1.15";
|
|
111334
111334
|
}
|
|
111335
111335
|
try {
|
|
111336
111336
|
const pkgPath = path5.join(THIS_DIR, "..", "..", "package.json");
|
|
@@ -142208,8 +142208,6 @@ function registerAttachmentHook(api, ctx) {
|
|
|
142208
142208
|
|
|
142209
142209
|
// lib/dispatch/telegram-bootstrap-hook.ts
|
|
142210
142210
|
import { homedir as homedir3 } from "node:os";
|
|
142211
|
-
init_runtime_paths();
|
|
142212
|
-
init_extract_json();
|
|
142213
142211
|
init_zod();
|
|
142214
142212
|
|
|
142215
142213
|
// lib/dispatch/telegram-bootstrap-session.ts
|
|
@@ -142244,14 +142242,14 @@ function buildBootstrapRequestHash(input) {
|
|
|
142244
142242
|
return buildBootstrapRequestFingerprint(input);
|
|
142245
142243
|
}
|
|
142246
142244
|
function nextSuppressUntil(status) {
|
|
142247
|
-
const ttl = status === "classifying" ? CLASSIFYING_TTL_MS : SESSION_TTL_MS;
|
|
142245
|
+
const ttl = status === "classifying" || status === "pending_classify" ? CLASSIFYING_TTL_MS : SESSION_TTL_MS;
|
|
142248
142246
|
return new Date(Date.now() + ttl).toISOString();
|
|
142249
142247
|
}
|
|
142250
142248
|
async function readTelegramBootstrapSession(workspaceDir, conversationId) {
|
|
142251
142249
|
try {
|
|
142252
142250
|
const raw = await fs38.readFile(sessionPath(workspaceDir, conversationId), "utf-8");
|
|
142253
142251
|
const session = JSON.parse(raw);
|
|
142254
|
-
if ((session.status === "clarifying" || session.status === "classifying") && Date.parse(session.suppressUntil) < Date.now()) {
|
|
142252
|
+
if ((session.status === "clarifying" || session.status === "classifying" || session.status === "pending_classify") && Date.parse(session.suppressUntil) < Date.now()) {
|
|
142255
142253
|
await fs38.unlink(sessionPath(workspaceDir, conversationId)).catch(() => {
|
|
142256
142254
|
});
|
|
142257
142255
|
return null;
|
|
@@ -142324,6 +142322,7 @@ function shouldSuppressTelegramBootstrapReply(session, request2) {
|
|
|
142324
142322
|
|
|
142325
142323
|
// lib/dispatch/telegram-bootstrap-hook.ts
|
|
142326
142324
|
var BOOTSTRAP_TIMEOUT_MS = 5 * 6e4;
|
|
142325
|
+
var LAYER3_CONFIDENCE_THRESHOLD = 0.6;
|
|
142327
142326
|
var BOOTSTRAP_MESSAGES = {
|
|
142328
142327
|
ack: {
|
|
142329
142328
|
pt: "Recebi! Vou analisar e come\xE7ar a montar o projeto...",
|
|
@@ -142341,6 +142340,10 @@ var BOOTSTRAP_MESSAGES = {
|
|
|
142341
142340
|
pt: "N\xE3o consegui identificar a stack. Pode me dizer qual linguagem/framework voc\xEA quer usar? Ex: Python, Node.js, Go, Java...",
|
|
142342
142341
|
en: "Couldn't identify the stack. Can you tell me which language/framework you'd like to use? e.g., Python, Node.js, Go, Java..."
|
|
142343
142342
|
},
|
|
142343
|
+
clarifyName: {
|
|
142344
|
+
pt: "Como voc\xEA quer chamar o projeto? Se preferir, posso escolher um nome.",
|
|
142345
|
+
en: "What do you want to name the project? If you prefer, I can pick one."
|
|
142346
|
+
},
|
|
142344
142347
|
registered: {
|
|
142345
142348
|
pt: (name, link) => `Projeto "${name}" registrado.
|
|
142346
142349
|
Vou continuar o fluxo em ${link}`,
|
|
@@ -142349,13 +142352,18 @@ I'll continue the flow at ${link}`
|
|
|
142349
142352
|
}
|
|
142350
142353
|
};
|
|
142351
142354
|
function inferProjectSlug(text) {
|
|
142352
|
-
|
|
142355
|
+
let cleaned = text.replace(/^(create|build|crie|cria|criar|fazer?|quero|i need|i want)\s+(uma|um|me\s+a?|an|a)?\s*/i, "").replace(/\s+(that|which|que|para|for|pra)\s+.*/i, "").trim();
|
|
142356
|
+
if (!cleaned) cleaned = text;
|
|
142357
|
+
const slug = cleaned.toLowerCase().normalize("NFKD").replace(/[^\w\s-]/g, "").trim().replace(/\s+/g, "-").replace(/-+/g, "-").slice(0, 64);
|
|
142353
142358
|
return slug || void 0;
|
|
142354
142359
|
}
|
|
142355
142360
|
function normalizeText3(value) {
|
|
142356
142361
|
const trimmed = value?.trim();
|
|
142357
142362
|
return trimmed ? trimmed : void 0;
|
|
142358
142363
|
}
|
|
142364
|
+
function normalizeUserResponse(text) {
|
|
142365
|
+
return text.trim().replace(/[.,!?;:\u2026]+$/, "").toLowerCase();
|
|
142366
|
+
}
|
|
142359
142367
|
function detectStackHint(text) {
|
|
142360
142368
|
const lower2 = text.toLowerCase();
|
|
142361
142369
|
if (/\b(nextjs|next\.js)\b/.test(lower2)) return "nextjs";
|
|
@@ -142422,26 +142430,31 @@ Examples:
|
|
|
142422
142430
|
- "How's the project going?" \u2192 {"intent":"other","confidence":0.95,"stackHint":null,"projectSlug":null,"language":"en"}
|
|
142423
142431
|
- "Oi, tudo bem?" \u2192 {"intent":"other","confidence":0.99,"stackHint":null,"projectSlug":null,"language":"pt"}
|
|
142424
142432
|
- "Me faz um app que converte temperaturas" \u2192 {"intent":"create_project","confidence":0.9,"stackHint":null,"projectSlug":"conversor-temperaturas","language":"pt"}`;
|
|
142425
|
-
async function classifyDmIntent(ctx, content,
|
|
142433
|
+
async function classifyDmIntent(ctx, content, _workspaceDir) {
|
|
142426
142434
|
try {
|
|
142435
|
+
const runtime = ctx.runtime;
|
|
142436
|
+
if (!runtime?.subagent?.run) return null;
|
|
142427
142437
|
const truncated = content.slice(0, MAX_CLASSIFY_LENGTH);
|
|
142428
142438
|
const prompt = CLASSIFY_PROMPT_TEMPLATE.replace("$CONTENT", truncated.replace(/"/g, '\\"'));
|
|
142429
|
-
const
|
|
142430
|
-
const
|
|
142431
|
-
|
|
142432
|
-
|
|
142433
|
-
|
|
142434
|
-
|
|
142435
|
-
|
|
142436
|
-
|
|
142437
|
-
|
|
142438
|
-
|
|
142439
|
-
|
|
142440
|
-
const
|
|
142439
|
+
const sessionKey = `dm-classify-${Date.now()}`;
|
|
142440
|
+
const { runId } = await runtime.subagent.run({
|
|
142441
|
+
sessionKey,
|
|
142442
|
+
message: prompt,
|
|
142443
|
+
extraSystemPrompt: "You are a JSON classifier. Return ONLY valid JSON, no markdown fences.",
|
|
142444
|
+
lane: "subagent",
|
|
142445
|
+
deliver: false,
|
|
142446
|
+
idempotencyKey: sessionKey
|
|
142447
|
+
});
|
|
142448
|
+
const waitResult = await runtime.subagent.waitForRun({ runId, timeoutMs: 15e3 });
|
|
142449
|
+
if (waitResult.status !== "ok") return null;
|
|
142450
|
+
const messages = await runtime.subagent.getSessionMessages({ sessionKey });
|
|
142451
|
+
const lastAssistant = messages?.filter((m2) => m2.role === "assistant").pop();
|
|
142452
|
+
const text = lastAssistant?.content ?? "";
|
|
142453
|
+
if (!text.trim()) return null;
|
|
142454
|
+
const jsonStr = text.replace(/^```(json)?/gm, "").replace(/```$/gm, "").trim();
|
|
142441
142455
|
const intentData = JSON.parse(jsonStr);
|
|
142442
142456
|
const validated = DmIntentSchema.safeParse(intentData);
|
|
142443
|
-
|
|
142444
|
-
return validated.data;
|
|
142457
|
+
return validated.success ? validated.data : null;
|
|
142445
142458
|
} catch {
|
|
142446
142459
|
return null;
|
|
142447
142460
|
}
|
|
@@ -142454,6 +142467,21 @@ function isBootstrapCandidate(text) {
|
|
|
142454
142467
|
return createCue && softwareCue;
|
|
142455
142468
|
}
|
|
142456
142469
|
function parseClarificationResponse(text, session) {
|
|
142470
|
+
if (session.pendingClarification === "name") {
|
|
142471
|
+
const trimmed = text.trim();
|
|
142472
|
+
const autoPatterns = /^(escolha|pick one|tanto faz|you choose|pode escolher|auto|skip)$/i;
|
|
142473
|
+
if (autoPatterns.test(normalizeUserResponse(text))) {
|
|
142474
|
+
return { recognized: true, projectName: inferProjectSlug(session.rawIdea) ?? `project-${Date.now()}`, stackHint: session.stackHint ?? void 0 };
|
|
142475
|
+
}
|
|
142476
|
+
const nameField = parseField(text, ["project name", "nome do projeto", "nome", "name"]);
|
|
142477
|
+
if (nameField) {
|
|
142478
|
+
return { recognized: true, projectName: nameField, stackHint: session.stackHint ?? void 0 };
|
|
142479
|
+
}
|
|
142480
|
+
if (trimmed.length > 0 && trimmed.length <= 64) {
|
|
142481
|
+
return { recognized: true, projectName: trimmed, stackHint: session.stackHint ?? void 0 };
|
|
142482
|
+
}
|
|
142483
|
+
return { recognized: false };
|
|
142484
|
+
}
|
|
142457
142485
|
const stackField = parseField(text, ["stack", "framework", "linguagem", "language"]);
|
|
142458
142486
|
if (stackField) {
|
|
142459
142487
|
return { recognized: true, stackHint: detectStackHint(stackField) ?? stackField };
|
|
@@ -142462,7 +142490,7 @@ function parseClarificationResponse(text, session) {
|
|
|
142462
142490
|
if (detectedStack) {
|
|
142463
142491
|
return { recognized: true, stackHint: detectedStack };
|
|
142464
142492
|
}
|
|
142465
|
-
const lower2 = text
|
|
142493
|
+
const lower2 = normalizeUserResponse(text);
|
|
142466
142494
|
const bareStackMap = {
|
|
142467
142495
|
python: "python-cli",
|
|
142468
142496
|
py: "python-cli",
|
|
@@ -142489,16 +142517,14 @@ function parseClarificationResponse(text, session) {
|
|
|
142489
142517
|
return { recognized: false };
|
|
142490
142518
|
}
|
|
142491
142519
|
function buildClarificationMessage(parsed, pendingClarification, language = "pt") {
|
|
142520
|
+
if (pendingClarification === "name") {
|
|
142521
|
+
return BOOTSTRAP_MESSAGES.clarifyName[language];
|
|
142522
|
+
}
|
|
142492
142523
|
if (pendingClarification === "stack_and_name" || !parsed.stackHint && !parsed.projectName) {
|
|
142493
142524
|
return BOOTSTRAP_MESSAGES.clarifyBoth[language];
|
|
142494
142525
|
}
|
|
142495
142526
|
return BOOTSTRAP_MESSAGES.clarifyStack[language];
|
|
142496
142527
|
}
|
|
142497
|
-
function buildFollowUpClarification(session) {
|
|
142498
|
-
const lang = session.language ?? "pt";
|
|
142499
|
-
if (!session.stackHint) return BOOTSTRAP_MESSAGES.clarifyStackFollowUp[lang];
|
|
142500
|
-
return lang === "en" ? "Can you give me more details about what you want to build?" : "Pode me dar mais detalhes sobre o que voc\xEA quer construir?";
|
|
142501
|
-
}
|
|
142502
142528
|
function buildTopicDeepLink(chatId, topicId) {
|
|
142503
142529
|
const stripped = chatId.replace(/^-100/, "");
|
|
142504
142530
|
return `https://t.me/c/${stripped}/${topicId}`;
|
|
@@ -142534,8 +142560,14 @@ function logBootstrapWarning(ctx, message) {
|
|
|
142534
142560
|
}
|
|
142535
142561
|
}
|
|
142536
142562
|
async function classifyAndBootstrap(ctx, workspaceDir, conversationId, content) {
|
|
142563
|
+
await upsertTelegramBootstrapSession(workspaceDir, {
|
|
142564
|
+
conversationId,
|
|
142565
|
+
rawIdea: content,
|
|
142566
|
+
sourceRoute: { channel: "telegram", channelId: conversationId },
|
|
142567
|
+
status: "classifying"
|
|
142568
|
+
});
|
|
142537
142569
|
const classification = await classifyDmIntent(ctx, content, workspaceDir);
|
|
142538
|
-
if (!classification || classification.intent !== "create_project" || classification.confidence <
|
|
142570
|
+
if (!classification || classification.intent !== "create_project" || classification.confidence < LAYER3_CONFIDENCE_THRESHOLD) {
|
|
142539
142571
|
if (!classification) {
|
|
142540
142572
|
logBootstrapWarning(ctx, `[telegram-bootstrap] LLM classify failed, falling back (conversation: ${conversationId})`);
|
|
142541
142573
|
}
|
|
@@ -142623,7 +142655,6 @@ async function continueBootstrap(ctx, conversationId, workspaceDir, request2, so
|
|
|
142623
142655
|
);
|
|
142624
142656
|
return;
|
|
142625
142657
|
}
|
|
142626
|
-
const projectName = request2.projectName ?? void 0;
|
|
142627
142658
|
const stackHint = request2.stackHint;
|
|
142628
142659
|
if (!stackHint) {
|
|
142629
142660
|
const existingSession = await readTelegramBootstrapSession(workspaceDir, conversationId);
|
|
@@ -142643,7 +142674,38 @@ async function continueBootstrap(ctx, conversationId, workspaceDir, request2, so
|
|
|
142643
142674
|
));
|
|
142644
142675
|
return;
|
|
142645
142676
|
}
|
|
142646
|
-
|
|
142677
|
+
if (!request2.projectName) {
|
|
142678
|
+
const inferredSlug = inferProjectSlug(request2.rawIdea);
|
|
142679
|
+
if (inferredSlug) {
|
|
142680
|
+
request2.projectName = inferredSlug;
|
|
142681
|
+
} else {
|
|
142682
|
+
const existingSession = await readTelegramBootstrapSession(workspaceDir, conversationId);
|
|
142683
|
+
if (existingSession?.pendingClarification === "name") {
|
|
142684
|
+
request2.projectName = `project-${Date.now()}`;
|
|
142685
|
+
} else {
|
|
142686
|
+
const lang = existingSession?.language ?? "pt";
|
|
142687
|
+
await upsertTelegramBootstrapSession(workspaceDir, {
|
|
142688
|
+
conversationId,
|
|
142689
|
+
rawIdea: request2.rawIdea,
|
|
142690
|
+
stackHint: request2.stackHint ?? void 0,
|
|
142691
|
+
status: "clarifying",
|
|
142692
|
+
pendingClarification: "name",
|
|
142693
|
+
language: lang
|
|
142694
|
+
});
|
|
142695
|
+
await sendTelegramText(
|
|
142696
|
+
ctx,
|
|
142697
|
+
conversationId,
|
|
142698
|
+
buildClarificationMessage(
|
|
142699
|
+
{ rawIdea: request2.rawIdea, projectName: void 0, stackHint: request2.stackHint ?? void 0 },
|
|
142700
|
+
"name",
|
|
142701
|
+
lang
|
|
142702
|
+
)
|
|
142703
|
+
);
|
|
142704
|
+
return;
|
|
142705
|
+
}
|
|
142706
|
+
}
|
|
142707
|
+
}
|
|
142708
|
+
const candidateSlug = inferProjectSlug(request2.projectName ?? request2.rawIdea);
|
|
142647
142709
|
if (candidateSlug) {
|
|
142648
142710
|
const projects = await readProjects(workspaceDir).catch(() => null);
|
|
142649
142711
|
if (projects?.projects?.[candidateSlug]) {
|
|
@@ -142692,7 +142754,7 @@ async function continueBootstrap(ctx, conversationId, workspaceDir, request2, so
|
|
|
142692
142754
|
metadata: {
|
|
142693
142755
|
source: "telegram-dm-bootstrap",
|
|
142694
142756
|
factory_change: false,
|
|
142695
|
-
project_name: projectName ?? null,
|
|
142757
|
+
project_name: request2.projectName ?? null,
|
|
142696
142758
|
repo_url: request2.repoUrl ?? null,
|
|
142697
142759
|
repo_path: request2.repoPath ?? null,
|
|
142698
142760
|
stack_hint: stackHint,
|
|
@@ -142749,7 +142811,7 @@ Erro: ${result.error ?? "erro desconhecido"}`
|
|
|
142749
142811
|
);
|
|
142750
142812
|
return;
|
|
142751
142813
|
}
|
|
142752
|
-
const resolvedProjectName = result.payload.metadata.project_name ?? result.payload.metadata.project_slug ?? projectName ?? "projeto";
|
|
142814
|
+
const resolvedProjectName = result.payload.metadata.project_name ?? result.payload.metadata.project_slug ?? request2.projectName ?? "projeto";
|
|
142753
142815
|
const projectChannelId = result.payload.metadata.channel_id ?? telegramConfig.projectsForumChatId;
|
|
142754
142816
|
const messageThreadId = result.payload.metadata.message_thread_id;
|
|
142755
142817
|
const projectSlug = result.payload.metadata.project_slug ?? result.payload.scaffold?.project_slug ?? null;
|
|
@@ -142872,7 +142934,7 @@ function registerTelegramBootstrapHook(api, ctx) {
|
|
|
142872
142934
|
}
|
|
142873
142935
|
const existingSession = await readTelegramBootstrapSession(workspaceDir, conversationId);
|
|
142874
142936
|
const sessionIsExpired = existingSession != null && Date.parse(existingSession.suppressUntil) < Date.now();
|
|
142875
|
-
if (existingSession && !sessionIsExpired && existingSession.status === "classifying") {
|
|
142937
|
+
if (existingSession && !sessionIsExpired && (existingSession.status === "classifying" || existingSession.status === "pending_classify")) {
|
|
142876
142938
|
ctx.logger.info(`[telegram-bootstrap] LLM classification in progress for ${conversationId}, ignoring concurrent message`);
|
|
142877
142939
|
return;
|
|
142878
142940
|
}
|
|
@@ -142880,7 +142942,11 @@ function registerTelegramBootstrapHook(api, ctx) {
|
|
|
142880
142942
|
const clarResult = parseClarificationResponse(content, existingSession);
|
|
142881
142943
|
if (!clarResult.recognized) {
|
|
142882
142944
|
ctx.logger.info(`[telegram-bootstrap] clarification response not recognized, re-asking (conversation: ${conversationId})`);
|
|
142883
|
-
await sendTelegramText(ctx, conversationId,
|
|
142945
|
+
await sendTelegramText(ctx, conversationId, buildClarificationMessage(
|
|
142946
|
+
{ rawIdea: existingSession.rawIdea, stackHint: existingSession.stackHint ?? void 0, projectName: existingSession.projectName ?? void 0 },
|
|
142947
|
+
existingSession.pendingClarification ?? void 0,
|
|
142948
|
+
existingSession.language ?? "pt"
|
|
142949
|
+
));
|
|
142884
142950
|
return;
|
|
142885
142951
|
}
|
|
142886
142952
|
const mergedRequest = {
|
|
@@ -142903,7 +142969,7 @@ function registerTelegramBootstrapHook(api, ctx) {
|
|
|
142903
142969
|
conversationId,
|
|
142904
142970
|
rawIdea: content,
|
|
142905
142971
|
sourceRoute: { channel: "telegram", channelId: conversationId },
|
|
142906
|
-
status: "
|
|
142972
|
+
status: "pending_classify"
|
|
142907
142973
|
});
|
|
142908
142974
|
classifyAndBootstrap(ctx, workspaceDir, conversationId, content).catch((err) => {
|
|
142909
142975
|
logBootstrapWarning(ctx, `[telegram-bootstrap] LLM classify error: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -142912,22 +142978,22 @@ function registerTelegramBootstrapHook(api, ctx) {
|
|
|
142912
142978
|
return;
|
|
142913
142979
|
}
|
|
142914
142980
|
const parsed = parseBootstrapRequest(content);
|
|
142915
|
-
const
|
|
142981
|
+
const preClassifyRequest = {
|
|
142916
142982
|
rawIdea: parsed.rawIdea,
|
|
142917
142983
|
projectName: parsed.projectName ?? null,
|
|
142918
142984
|
stackHint: parsed.stackHint ?? null,
|
|
142919
142985
|
repoUrl: parsed.repoUrl ?? null,
|
|
142920
142986
|
repoPath: parsed.repoPath ?? null
|
|
142921
142987
|
};
|
|
142922
|
-
const
|
|
142923
|
-
const
|
|
142924
|
-
if (
|
|
142925
|
-
if (
|
|
142988
|
+
const preClassifyHash = buildBootstrapRequestHash(preClassifyRequest);
|
|
142989
|
+
const sessionForHashPreClassify = await readTelegramBootstrapSession(workspaceDir, conversationId);
|
|
142990
|
+
if (sessionForHashPreClassify?.requestHash === preClassifyHash) {
|
|
142991
|
+
if (sessionForHashPreClassify.status === "completed") {
|
|
142926
142992
|
ctx.logger.info(`[telegram-bootstrap] duplicate completed DM ignored for conversation ${conversationId}`);
|
|
142927
142993
|
return;
|
|
142928
142994
|
}
|
|
142929
|
-
const isExpiredReceived =
|
|
142930
|
-
if (
|
|
142995
|
+
const isExpiredReceived = sessionForHashPreClassify.status === "received" && Date.parse(sessionForHashPreClassify.suppressUntil) < Date.now();
|
|
142996
|
+
if (sessionForHashPreClassify.status !== "failed" && !isExpiredReceived) {
|
|
142931
142997
|
ctx.logger.info(`[telegram-bootstrap] duplicate in-flight DM ignored for conversation ${conversationId}`);
|
|
142932
142998
|
return;
|
|
142933
142999
|
}
|
|
@@ -142935,6 +143001,25 @@ function registerTelegramBootstrapHook(api, ctx) {
|
|
|
142935
143001
|
ctx.logger.info(`[telegram-bootstrap] stale received session (expired) \u2014 restarting pipeline for conversation ${conversationId}`);
|
|
142936
143002
|
}
|
|
142937
143003
|
}
|
|
143004
|
+
if (!parsed.projectName && ctx.runtime?.subagent?.run) {
|
|
143005
|
+
await upsertTelegramBootstrapSession(workspaceDir, {
|
|
143006
|
+
conversationId,
|
|
143007
|
+
rawIdea: parsed.rawIdea,
|
|
143008
|
+
sourceRoute: { channel: "telegram", channelId: conversationId },
|
|
143009
|
+
status: "pending_classify"
|
|
143010
|
+
});
|
|
143011
|
+
const classification = await classifyDmIntent(ctx, content, workspaceDir);
|
|
143012
|
+
if (classification?.projectSlug) {
|
|
143013
|
+
parsed.projectName = classification.projectSlug;
|
|
143014
|
+
}
|
|
143015
|
+
}
|
|
143016
|
+
const incomingRequest = {
|
|
143017
|
+
rawIdea: parsed.rawIdea,
|
|
143018
|
+
projectName: parsed.projectName ?? null,
|
|
143019
|
+
stackHint: parsed.stackHint ?? null,
|
|
143020
|
+
repoUrl: parsed.repoUrl ?? null,
|
|
143021
|
+
repoPath: parsed.repoPath ?? null
|
|
143022
|
+
};
|
|
142938
143023
|
const language = /\b(cria|crie|criar|construa|desenvolva|registre|novo projeto)\b/i.test(content) ? "pt" : "en";
|
|
142939
143024
|
await sendTelegramText(ctx, conversationId, BOOTSTRAP_MESSAGES.ack[language]);
|
|
142940
143025
|
const session = await upsertTelegramBootstrapSession(workspaceDir, {
|