@mestreyoda/fabrica 0.1.8 → 0.1.10
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 +206 -26
- 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.10") {
|
|
111333
|
+
return "0.1.10";
|
|
111334
111334
|
}
|
|
111335
111335
|
try {
|
|
111336
111336
|
const pkgPath = path5.join(THIS_DIR, "..", "..", "package.json");
|
|
@@ -142032,6 +142032,9 @@ function registerAttachmentHook(api, ctx) {
|
|
|
142032
142032
|
|
|
142033
142033
|
// lib/dispatch/telegram-bootstrap-hook.ts
|
|
142034
142034
|
import { homedir as homedir3 } from "node:os";
|
|
142035
|
+
init_runtime_paths();
|
|
142036
|
+
init_extract_json();
|
|
142037
|
+
init_zod();
|
|
142035
142038
|
|
|
142036
142039
|
// lib/dispatch/telegram-bootstrap-session.ts
|
|
142037
142040
|
init_migrate_layout();
|
|
@@ -142039,6 +142042,7 @@ import { createHash as createHash6 } from "node:crypto";
|
|
|
142039
142042
|
import fs38 from "node:fs/promises";
|
|
142040
142043
|
import path40 from "node:path";
|
|
142041
142044
|
var SESSION_TTL_MS = 10 * 6e4;
|
|
142045
|
+
var CLASSIFYING_TTL_MS = 15e3;
|
|
142042
142046
|
function sessionsDir(workspaceDir) {
|
|
142043
142047
|
return path40.join(workspaceDir, DATA_DIR, "bootstrap-sessions");
|
|
142044
142048
|
}
|
|
@@ -142063,14 +142067,15 @@ function buildBootstrapRequestFingerprint(input) {
|
|
|
142063
142067
|
function buildBootstrapRequestHash(input) {
|
|
142064
142068
|
return buildBootstrapRequestFingerprint(input);
|
|
142065
142069
|
}
|
|
142066
|
-
function nextSuppressUntil() {
|
|
142067
|
-
|
|
142070
|
+
function nextSuppressUntil(status) {
|
|
142071
|
+
const ttl = status === "classifying" ? CLASSIFYING_TTL_MS : SESSION_TTL_MS;
|
|
142072
|
+
return new Date(Date.now() + ttl).toISOString();
|
|
142068
142073
|
}
|
|
142069
142074
|
async function readTelegramBootstrapSession(workspaceDir, conversationId) {
|
|
142070
142075
|
try {
|
|
142071
142076
|
const raw = await fs38.readFile(sessionPath(workspaceDir, conversationId), "utf-8");
|
|
142072
142077
|
const session = JSON.parse(raw);
|
|
142073
|
-
if (session.status === "clarifying" && Date.parse(session.suppressUntil) < Date.now()) {
|
|
142078
|
+
if ((session.status === "clarifying" || session.status === "classifying") && Date.parse(session.suppressUntil) < Date.now()) {
|
|
142074
142079
|
await fs38.unlink(sessionPath(workspaceDir, conversationId)).catch(() => {
|
|
142075
142080
|
});
|
|
142076
142081
|
return null;
|
|
@@ -142081,6 +142086,10 @@ async function readTelegramBootstrapSession(workspaceDir, conversationId) {
|
|
|
142081
142086
|
throw error48;
|
|
142082
142087
|
}
|
|
142083
142088
|
}
|
|
142089
|
+
async function deleteTelegramBootstrapSession(workspaceDir, conversationId) {
|
|
142090
|
+
await fs38.unlink(sessionPath(workspaceDir, conversationId)).catch(() => {
|
|
142091
|
+
});
|
|
142092
|
+
}
|
|
142084
142093
|
async function writeTelegramBootstrapSession(workspaceDir, session) {
|
|
142085
142094
|
const dir = sessionsDir(workspaceDir);
|
|
142086
142095
|
await fs38.mkdir(dir, { recursive: true });
|
|
@@ -142117,12 +142126,13 @@ async function upsertTelegramBootstrapSession(workspaceDir, input) {
|
|
|
142117
142126
|
issueId: input.issueId ?? existing?.issueId ?? null,
|
|
142118
142127
|
messageThreadId: input.messageThreadId ?? existing?.messageThreadId ?? null,
|
|
142119
142128
|
projectChannelId: input.projectChannelId ?? existing?.projectChannelId ?? null,
|
|
142129
|
+
language: input.language ?? existing?.language,
|
|
142120
142130
|
status: input.status,
|
|
142121
142131
|
pendingClarification: input.pendingClarification !== void 0 ? input.pendingClarification : existing?.pendingClarification ?? null,
|
|
142122
142132
|
orphanedArtifacts: input.orphanedArtifacts !== void 0 ? input.orphanedArtifacts : existing?.orphanedArtifacts ?? null,
|
|
142123
142133
|
createdAt: existing?.createdAt ?? now2,
|
|
142124
142134
|
updatedAt: now2,
|
|
142125
|
-
suppressUntil: nextSuppressUntil(),
|
|
142135
|
+
suppressUntil: nextSuppressUntil(input.status),
|
|
142126
142136
|
error: input.error ?? null
|
|
142127
142137
|
};
|
|
142128
142138
|
await writeTelegramBootstrapSession(workspaceDir, session);
|
|
@@ -142137,6 +142147,30 @@ function shouldSuppressTelegramBootstrapReply(session, request2) {
|
|
|
142137
142147
|
}
|
|
142138
142148
|
|
|
142139
142149
|
// lib/dispatch/telegram-bootstrap-hook.ts
|
|
142150
|
+
var BOOTSTRAP_MESSAGES = {
|
|
142151
|
+
ack: {
|
|
142152
|
+
pt: "Recebi! Vou analisar e come\xE7ar a montar o projeto...",
|
|
142153
|
+
en: "Got it! I'll analyze your request and start setting up the project..."
|
|
142154
|
+
},
|
|
142155
|
+
clarifyStack: {
|
|
142156
|
+
pt: "Qual stack voc\xEA quer usar? (Python, Node.js, Go, Java...)",
|
|
142157
|
+
en: "Which stack do you want to use? (Python, Node.js, Go, Java...)"
|
|
142158
|
+
},
|
|
142159
|
+
clarifyBoth: {
|
|
142160
|
+
pt: "Beleza! S\xF3 preciso de duas coisas pra criar:\n\n1. Qual stack? (Python, Node.js, Go, Java...)\n2. Quer dar um nome pro projeto? Se n\xE3o, eu invento um.",
|
|
142161
|
+
en: "Great! I just need two things:\n\n1. Which stack? (Python, Node.js, Go, Java...)\n2. Want to name the project? If not, I'll pick one."
|
|
142162
|
+
},
|
|
142163
|
+
clarifyStackFollowUp: {
|
|
142164
|
+
pt: "N\xE3o consegui identificar a stack. Pode me dizer qual linguagem/framework voc\xEA quer usar? Ex: Python, Node.js, Go, Java...",
|
|
142165
|
+
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..."
|
|
142166
|
+
},
|
|
142167
|
+
registered: {
|
|
142168
|
+
pt: (name, link) => `Projeto "${name}" registrado.
|
|
142169
|
+
Vou continuar o fluxo em ${link}`,
|
|
142170
|
+
en: (name, link) => `Project "${name}" registered.
|
|
142171
|
+
I'll continue the flow at ${link}`
|
|
142172
|
+
}
|
|
142173
|
+
};
|
|
142140
142174
|
function inferProjectSlug(text) {
|
|
142141
142175
|
const slug = text.toLowerCase().normalize("NFKD").replace(/[^\w\s-]/g, "").trim().replace(/\s+/g, "-").replace(/-+/g, "-").slice(0, 64);
|
|
142142
142176
|
return slug || void 0;
|
|
@@ -142184,6 +142218,57 @@ function parseBootstrapRequest(text) {
|
|
|
142184
142218
|
stackHint
|
|
142185
142219
|
};
|
|
142186
142220
|
}
|
|
142221
|
+
var MAX_CLASSIFY_LENGTH = 500;
|
|
142222
|
+
function isAmbiguousCandidate(text) {
|
|
142223
|
+
const lower2 = text.toLowerCase();
|
|
142224
|
+
if (lower2.length <= 20 || lower2.length > MAX_CLASSIFY_LENGTH) return false;
|
|
142225
|
+
const softwareCue = /\b(projeto|project|cli|api|app|aplicativo|servi[cç]o|library|biblioteca|repo|reposit[oó]rio|tool|ferramenta|sistema|system|bot|script|programa|program)\b/.test(lower2);
|
|
142226
|
+
return softwareCue;
|
|
142227
|
+
}
|
|
142228
|
+
var DmIntentSchema = external_exports.object({
|
|
142229
|
+
intent: external_exports.enum(["create_project", "other"]),
|
|
142230
|
+
confidence: external_exports.number().min(0).max(1),
|
|
142231
|
+
stackHint: external_exports.string().nullable().optional(),
|
|
142232
|
+
projectSlug: external_exports.string().nullable().optional(),
|
|
142233
|
+
language: external_exports.enum(["pt", "en"]).optional().default("pt")
|
|
142234
|
+
});
|
|
142235
|
+
var CLASSIFY_PROMPT_TEMPLATE = `Classify this Telegram DM. Is the user asking to create/build a new software project, or is it something else (question, greeting, status check)?
|
|
142236
|
+
|
|
142237
|
+
Message: "$CONTENT"
|
|
142238
|
+
|
|
142239
|
+
Return ONLY valid JSON:
|
|
142240
|
+
{"intent": "create_project" | "other", "confidence": 0.0-1.0, "stackHint": "<detected stack or null>", "projectSlug": "<suggested slug or null>", "language": "pt" | "en"}
|
|
142241
|
+
|
|
142242
|
+
Examples:
|
|
142243
|
+
- "Cria uma CLI Python que valida CPF" \u2192 {"intent":"create_project","confidence":0.95,"stackHint":"python-cli","projectSlug":"validador-cpf-cli","language":"pt"}
|
|
142244
|
+
- "Build me a REST API for tasks" \u2192 {"intent":"create_project","confidence":0.9,"stackHint":"fastapi","projectSlug":"task-api","language":"en"}
|
|
142245
|
+
- "How's the project going?" \u2192 {"intent":"other","confidence":0.95,"stackHint":null,"projectSlug":null,"language":"en"}
|
|
142246
|
+
- "Oi, tudo bem?" \u2192 {"intent":"other","confidence":0.99,"stackHint":null,"projectSlug":null,"language":"pt"}
|
|
142247
|
+
- "Me faz um app que converte temperaturas" \u2192 {"intent":"create_project","confidence":0.9,"stackHint":null,"projectSlug":"conversor-temperaturas","language":"pt"}`;
|
|
142248
|
+
async function classifyDmIntent(ctx, content, workspaceDir) {
|
|
142249
|
+
try {
|
|
142250
|
+
const truncated = content.slice(0, MAX_CLASSIFY_LENGTH);
|
|
142251
|
+
const prompt = CLASSIFY_PROMPT_TEMPLATE.replace("$CONTENT", truncated.replace(/"/g, '\\"'));
|
|
142252
|
+
const cliPath = resolveOpenClawCli({ homeDir: homedir3(), workspaceDir });
|
|
142253
|
+
const sessionId = `dm-classify-${Date.now()}`;
|
|
142254
|
+
const result = await ctx.runCommand(
|
|
142255
|
+
[cliPath, "agent", "--local", "-m", prompt, "--session-id", sessionId, "--json"],
|
|
142256
|
+
{ timeoutMs: 15e3 }
|
|
142257
|
+
);
|
|
142258
|
+
const stdout = result.stdout ?? "";
|
|
142259
|
+
if (!stdout.trim()) return null;
|
|
142260
|
+
const parsed = extractJsonFromStdout(stdout);
|
|
142261
|
+
if (!parsed) return null;
|
|
142262
|
+
const text = parsed?.payloads?.[0]?.text;
|
|
142263
|
+
const jsonStr = text ? text.replace(/^```(json)?/gm, "").replace(/```$/gm, "").trim() : JSON.stringify(parsed);
|
|
142264
|
+
const intentData = JSON.parse(jsonStr);
|
|
142265
|
+
const validated = DmIntentSchema.safeParse(intentData);
|
|
142266
|
+
if (!validated.success) return null;
|
|
142267
|
+
return validated.data;
|
|
142268
|
+
} catch {
|
|
142269
|
+
return null;
|
|
142270
|
+
}
|
|
142271
|
+
}
|
|
142187
142272
|
function isBootstrapCandidate(text) {
|
|
142188
142273
|
const lower2 = text.toLowerCase();
|
|
142189
142274
|
if (/^\s*(project name|nome do projeto|repository url|repo url|stack)\s*:/im.test(text)) return true;
|
|
@@ -142226,26 +142311,23 @@ function parseClarificationResponse(text, session) {
|
|
|
142226
142311
|
}
|
|
142227
142312
|
return { recognized: false };
|
|
142228
142313
|
}
|
|
142229
|
-
function buildClarificationMessage(parsed, pendingClarification) {
|
|
142314
|
+
function buildClarificationMessage(parsed, pendingClarification, language = "pt") {
|
|
142230
142315
|
if (pendingClarification === "stack_and_name" || !parsed.stackHint && !parsed.projectName) {
|
|
142231
|
-
return
|
|
142232
|
-
|
|
142233
|
-
1. Qual stack? (Python, Node.js, Go, Java...)
|
|
142234
|
-
2. Quer dar um nome pro projeto? Se n\xE3o, eu invento um.`;
|
|
142316
|
+
return BOOTSTRAP_MESSAGES.clarifyBoth[language];
|
|
142235
142317
|
}
|
|
142236
|
-
return
|
|
142318
|
+
return BOOTSTRAP_MESSAGES.clarifyStack[language];
|
|
142237
142319
|
}
|
|
142238
142320
|
function buildFollowUpClarification(session) {
|
|
142239
|
-
|
|
142240
|
-
|
|
142241
|
-
|
|
142242
|
-
return `Pode me dar mais detalhes sobre o que voc\xEA quer construir?`;
|
|
142321
|
+
const lang = session.language ?? "pt";
|
|
142322
|
+
if (!session.stackHint) return BOOTSTRAP_MESSAGES.clarifyStackFollowUp[lang];
|
|
142323
|
+
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?";
|
|
142243
142324
|
}
|
|
142244
|
-
function
|
|
142245
|
-
|
|
142246
|
-
|
|
142247
|
-
|
|
142248
|
-
|
|
142325
|
+
function buildTopicDeepLink(chatId, topicId) {
|
|
142326
|
+
const stripped = chatId.replace(/^-100/, "");
|
|
142327
|
+
return `https://t.me/c/${stripped}/${topicId}`;
|
|
142328
|
+
}
|
|
142329
|
+
function buildDmAck(projectName, topicLink, language = "pt") {
|
|
142330
|
+
return BOOTSTRAP_MESSAGES.registered[language](projectName, topicLink);
|
|
142249
142331
|
}
|
|
142250
142332
|
function buildTopicKickoff(projectName, idea) {
|
|
142251
142333
|
return [
|
|
@@ -142274,6 +142356,70 @@ function logBootstrapWarning(ctx, message) {
|
|
|
142274
142356
|
ctx.logger.info(message);
|
|
142275
142357
|
}
|
|
142276
142358
|
}
|
|
142359
|
+
async function classifyAndBootstrap(ctx, workspaceDir, conversationId, content) {
|
|
142360
|
+
const classification = await classifyDmIntent(ctx, content, workspaceDir);
|
|
142361
|
+
if (!classification || classification.intent !== "create_project" || classification.confidence < 0.7) {
|
|
142362
|
+
if (!classification) {
|
|
142363
|
+
logBootstrapWarning(ctx, `[telegram-bootstrap] LLM classify failed, falling back (conversation: ${conversationId})`);
|
|
142364
|
+
}
|
|
142365
|
+
await deleteTelegramBootstrapSession(workspaceDir, conversationId);
|
|
142366
|
+
return;
|
|
142367
|
+
}
|
|
142368
|
+
const language = classification.language ?? "pt";
|
|
142369
|
+
await sendTelegramText(ctx, conversationId, BOOTSTRAP_MESSAGES.ack[language]);
|
|
142370
|
+
const parsed = parseBootstrapRequest(content);
|
|
142371
|
+
if (classification.stackHint && !parsed.stackHint) {
|
|
142372
|
+
parsed.stackHint = classification.stackHint;
|
|
142373
|
+
}
|
|
142374
|
+
if (classification.projectSlug && !parsed.projectName) {
|
|
142375
|
+
parsed.projectName = classification.projectSlug;
|
|
142376
|
+
}
|
|
142377
|
+
const incomingRequest = {
|
|
142378
|
+
rawIdea: parsed.rawIdea,
|
|
142379
|
+
projectName: parsed.projectName ?? null,
|
|
142380
|
+
stackHint: parsed.stackHint ?? null,
|
|
142381
|
+
repoUrl: parsed.repoUrl ?? null,
|
|
142382
|
+
repoPath: parsed.repoPath ?? null
|
|
142383
|
+
};
|
|
142384
|
+
const incomingRequestHash = buildBootstrapRequestHash(incomingRequest);
|
|
142385
|
+
const sessionForHash = await readTelegramBootstrapSession(workspaceDir, conversationId);
|
|
142386
|
+
if (sessionForHash?.requestHash === incomingRequestHash) {
|
|
142387
|
+
if (sessionForHash.status === "completed") {
|
|
142388
|
+
ctx.logger.info(`[telegram-bootstrap] duplicate completed DM ignored (LLM path) for conversation ${conversationId}`);
|
|
142389
|
+
return;
|
|
142390
|
+
}
|
|
142391
|
+
const isExpiredReceived = sessionForHash.status === "received" && Date.parse(sessionForHash.suppressUntil) < Date.now();
|
|
142392
|
+
if (sessionForHash.status !== "failed" && sessionForHash.status !== "classifying" && !isExpiredReceived) {
|
|
142393
|
+
ctx.logger.info(`[telegram-bootstrap] duplicate in-flight DM ignored (LLM path) for conversation ${conversationId}`);
|
|
142394
|
+
return;
|
|
142395
|
+
}
|
|
142396
|
+
}
|
|
142397
|
+
const sourceRoute = { channel: "telegram", channelId: conversationId };
|
|
142398
|
+
const session = await upsertTelegramBootstrapSession(workspaceDir, {
|
|
142399
|
+
conversationId,
|
|
142400
|
+
...incomingRequest,
|
|
142401
|
+
sourceRoute,
|
|
142402
|
+
sourceChannel: "telegram",
|
|
142403
|
+
status: "received",
|
|
142404
|
+
language
|
|
142405
|
+
});
|
|
142406
|
+
if (!parsed.stackHint) {
|
|
142407
|
+
const pendingClarification = !parsed.projectName ? "stack_and_name" : "stack";
|
|
142408
|
+
await upsertTelegramBootstrapSession(workspaceDir, {
|
|
142409
|
+
conversationId,
|
|
142410
|
+
...incomingRequest,
|
|
142411
|
+
sourceRoute: session.sourceRoute,
|
|
142412
|
+
status: "clarifying",
|
|
142413
|
+
pendingClarification,
|
|
142414
|
+
language
|
|
142415
|
+
});
|
|
142416
|
+
await sendTelegramText(ctx, conversationId, buildClarificationMessage(parsed, pendingClarification, language));
|
|
142417
|
+
return;
|
|
142418
|
+
}
|
|
142419
|
+
continueBootstrap(ctx, conversationId, workspaceDir, incomingRequest, sourceRoute).catch((err) => {
|
|
142420
|
+
logBootstrapWarning(ctx, `[telegram-bootstrap] unhandled pipeline error (LLM path): ${err instanceof Error ? err.message : String(err)}`);
|
|
142421
|
+
});
|
|
142422
|
+
}
|
|
142277
142423
|
async function continueBootstrap(ctx, conversationId, workspaceDir, request2, sourceRoute) {
|
|
142278
142424
|
const telegramConfig = readFabricaTelegramConfig(ctx.pluginConfig);
|
|
142279
142425
|
if (!telegramConfig.projectsForumChatId) {
|
|
@@ -142429,7 +142575,8 @@ Erro: ${result.error ?? "erro desconhecido"}`
|
|
|
142429
142575
|
logBootstrapWarning(ctx, `[telegram-bootstrap] immediate projectTick failed: ${error48 instanceof Error ? error48.message : String(error48)}`);
|
|
142430
142576
|
});
|
|
142431
142577
|
}
|
|
142432
|
-
|
|
142578
|
+
const sessionLang = currentSession?.language ?? "pt";
|
|
142579
|
+
await sendTelegramText(ctx, conversationId, buildDmAck(resolvedProjectName, buildTopicDeepLink(String(projectChannelId), messageThreadId), sessionLang));
|
|
142433
142580
|
await upsertTelegramBootstrapSession(workspaceDir, {
|
|
142434
142581
|
conversationId,
|
|
142435
142582
|
...incomingRequest,
|
|
@@ -142478,6 +142625,18 @@ function registerTelegramBootstrapHook(api, ctx) {
|
|
|
142478
142625
|
].join("\n")
|
|
142479
142626
|
};
|
|
142480
142627
|
});
|
|
142628
|
+
api.on("message_sending", async (_event, eventCtx) => {
|
|
142629
|
+
const hookCtx = eventCtx;
|
|
142630
|
+
if (hookCtx.channelId !== "telegram") return;
|
|
142631
|
+
const conversationId = String(hookCtx.conversationId ?? "").trim();
|
|
142632
|
+
if (!conversationId || conversationId.includes(":topic:") || conversationId.startsWith("-")) return;
|
|
142633
|
+
const workspaceDir = resolveWorkspaceDir(ctx.config);
|
|
142634
|
+
if (!workspaceDir) return;
|
|
142635
|
+
const session = await readTelegramBootstrapSession(workspaceDir, conversationId);
|
|
142636
|
+
if (session && session.status !== "completed" && session.status !== "failed" && shouldSuppressTelegramBootstrapReply(session)) {
|
|
142637
|
+
return { cancel: true };
|
|
142638
|
+
}
|
|
142639
|
+
});
|
|
142481
142640
|
api.on("message_received", async (event, eventCtx) => {
|
|
142482
142641
|
if (eventCtx.channelId !== "telegram") return;
|
|
142483
142642
|
const telegramConfig = readFabricaTelegramConfig(ctx.pluginConfig);
|
|
@@ -142495,6 +142654,10 @@ function registerTelegramBootstrapHook(api, ctx) {
|
|
|
142495
142654
|
}
|
|
142496
142655
|
const existingSession = await readTelegramBootstrapSession(workspaceDir, conversationId);
|
|
142497
142656
|
const sessionIsExpired = existingSession != null && Date.parse(existingSession.suppressUntil) < Date.now();
|
|
142657
|
+
if (existingSession && !sessionIsExpired && existingSession.status === "classifying") {
|
|
142658
|
+
ctx.logger.info(`[telegram-bootstrap] LLM classification in progress for ${conversationId}, ignoring concurrent message`);
|
|
142659
|
+
return;
|
|
142660
|
+
}
|
|
142498
142661
|
if (existingSession?.status === "clarifying" && !sessionIsExpired) {
|
|
142499
142662
|
const clarResult = parseClarificationResponse(content, existingSession);
|
|
142500
142663
|
if (!clarResult.recognized) {
|
|
@@ -142518,7 +142681,20 @@ function registerTelegramBootstrapHook(api, ctx) {
|
|
|
142518
142681
|
});
|
|
142519
142682
|
return;
|
|
142520
142683
|
}
|
|
142521
|
-
if (!isBootstrapCandidate(content))
|
|
142684
|
+
if (!isBootstrapCandidate(content)) {
|
|
142685
|
+
if (isAmbiguousCandidate(content)) {
|
|
142686
|
+
await upsertTelegramBootstrapSession(workspaceDir, {
|
|
142687
|
+
conversationId,
|
|
142688
|
+
rawIdea: content,
|
|
142689
|
+
sourceRoute: { channel: "telegram", channelId: conversationId },
|
|
142690
|
+
status: "classifying"
|
|
142691
|
+
});
|
|
142692
|
+
classifyAndBootstrap(ctx, workspaceDir, conversationId, content).catch((err) => {
|
|
142693
|
+
logBootstrapWarning(ctx, `[telegram-bootstrap] LLM classify error: ${err instanceof Error ? err.message : String(err)}`);
|
|
142694
|
+
});
|
|
142695
|
+
}
|
|
142696
|
+
return;
|
|
142697
|
+
}
|
|
142522
142698
|
const parsed = parseBootstrapRequest(content);
|
|
142523
142699
|
const incomingRequest = {
|
|
142524
142700
|
rawIdea: parsed.rawIdea,
|
|
@@ -142543,6 +142719,8 @@ function registerTelegramBootstrapHook(api, ctx) {
|
|
|
142543
142719
|
ctx.logger.info(`[telegram-bootstrap] stale received session (expired) \u2014 restarting pipeline for conversation ${conversationId}`);
|
|
142544
142720
|
}
|
|
142545
142721
|
}
|
|
142722
|
+
const language = /\b(cria|crie|criar|construa|desenvolva|registre|novo projeto)\b/i.test(content) ? "pt" : "en";
|
|
142723
|
+
await sendTelegramText(ctx, conversationId, BOOTSTRAP_MESSAGES.ack[language]);
|
|
142546
142724
|
const session = await upsertTelegramBootstrapSession(workspaceDir, {
|
|
142547
142725
|
conversationId,
|
|
142548
142726
|
...incomingRequest,
|
|
@@ -142551,7 +142729,8 @@ function registerTelegramBootstrapHook(api, ctx) {
|
|
|
142551
142729
|
channelId: conversationId
|
|
142552
142730
|
},
|
|
142553
142731
|
sourceChannel: "telegram",
|
|
142554
|
-
status: "received"
|
|
142732
|
+
status: "received",
|
|
142733
|
+
language
|
|
142555
142734
|
});
|
|
142556
142735
|
if (!parsed.stackHint) {
|
|
142557
142736
|
const pendingClarification = !parsed.projectName ? "stack_and_name" : "stack";
|
|
@@ -142560,9 +142739,10 @@ function registerTelegramBootstrapHook(api, ctx) {
|
|
|
142560
142739
|
...incomingRequest,
|
|
142561
142740
|
sourceRoute: session.sourceRoute,
|
|
142562
142741
|
status: "clarifying",
|
|
142563
|
-
pendingClarification
|
|
142742
|
+
pendingClarification,
|
|
142743
|
+
language
|
|
142564
142744
|
});
|
|
142565
|
-
await sendTelegramText(ctx, conversationId, buildClarificationMessage(parsed, pendingClarification));
|
|
142745
|
+
await sendTelegramText(ctx, conversationId, buildClarificationMessage(parsed, pendingClarification, language));
|
|
142566
142746
|
return;
|
|
142567
142747
|
}
|
|
142568
142748
|
continueBootstrap(ctx, conversationId, workspaceDir, incomingRequest, {
|