@mestreyoda/fabrica 0.1.9 → 0.1.11
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 +93 -38
- package/dist/index.js.map +2 -2
- 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.11") {
|
|
111333
|
+
return "0.1.11";
|
|
111334
111334
|
}
|
|
111335
111335
|
try {
|
|
111336
111336
|
const pkgPath = path5.join(THIS_DIR, "..", "..", "package.json");
|
|
@@ -142042,6 +142042,7 @@ import { createHash as createHash6 } from "node:crypto";
|
|
|
142042
142042
|
import fs38 from "node:fs/promises";
|
|
142043
142043
|
import path40 from "node:path";
|
|
142044
142044
|
var SESSION_TTL_MS = 10 * 6e4;
|
|
142045
|
+
var CLASSIFYING_TTL_MS = 15e3;
|
|
142045
142046
|
function sessionsDir(workspaceDir) {
|
|
142046
142047
|
return path40.join(workspaceDir, DATA_DIR, "bootstrap-sessions");
|
|
142047
142048
|
}
|
|
@@ -142066,8 +142067,9 @@ function buildBootstrapRequestFingerprint(input) {
|
|
|
142066
142067
|
function buildBootstrapRequestHash(input) {
|
|
142067
142068
|
return buildBootstrapRequestFingerprint(input);
|
|
142068
142069
|
}
|
|
142069
|
-
function nextSuppressUntil() {
|
|
142070
|
-
|
|
142070
|
+
function nextSuppressUntil(status) {
|
|
142071
|
+
const ttl = status === "classifying" ? CLASSIFYING_TTL_MS : SESSION_TTL_MS;
|
|
142072
|
+
return new Date(Date.now() + ttl).toISOString();
|
|
142071
142073
|
}
|
|
142072
142074
|
async function readTelegramBootstrapSession(workspaceDir, conversationId) {
|
|
142073
142075
|
try {
|
|
@@ -142124,12 +142126,13 @@ async function upsertTelegramBootstrapSession(workspaceDir, input) {
|
|
|
142124
142126
|
issueId: input.issueId ?? existing?.issueId ?? null,
|
|
142125
142127
|
messageThreadId: input.messageThreadId ?? existing?.messageThreadId ?? null,
|
|
142126
142128
|
projectChannelId: input.projectChannelId ?? existing?.projectChannelId ?? null,
|
|
142129
|
+
language: input.language ?? existing?.language,
|
|
142127
142130
|
status: input.status,
|
|
142128
142131
|
pendingClarification: input.pendingClarification !== void 0 ? input.pendingClarification : existing?.pendingClarification ?? null,
|
|
142129
142132
|
orphanedArtifacts: input.orphanedArtifacts !== void 0 ? input.orphanedArtifacts : existing?.orphanedArtifacts ?? null,
|
|
142130
142133
|
createdAt: existing?.createdAt ?? now2,
|
|
142131
142134
|
updatedAt: now2,
|
|
142132
|
-
suppressUntil: nextSuppressUntil(),
|
|
142135
|
+
suppressUntil: nextSuppressUntil(input.status),
|
|
142133
142136
|
error: input.error ?? null
|
|
142134
142137
|
};
|
|
142135
142138
|
await writeTelegramBootstrapSession(workspaceDir, session);
|
|
@@ -142144,6 +142147,30 @@ function shouldSuppressTelegramBootstrapReply(session, request2) {
|
|
|
142144
142147
|
}
|
|
142145
142148
|
|
|
142146
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
|
+
};
|
|
142147
142174
|
function inferProjectSlug(text) {
|
|
142148
142175
|
const slug = text.toLowerCase().normalize("NFKD").replace(/[^\w\s-]/g, "").trim().replace(/\s+/g, "-").replace(/-+/g, "-").slice(0, 64);
|
|
142149
142176
|
return slug || void 0;
|
|
@@ -142202,21 +142229,22 @@ var DmIntentSchema = external_exports.object({
|
|
|
142202
142229
|
intent: external_exports.enum(["create_project", "other"]),
|
|
142203
142230
|
confidence: external_exports.number().min(0).max(1),
|
|
142204
142231
|
stackHint: external_exports.string().nullable().optional(),
|
|
142205
|
-
projectSlug: external_exports.string().nullable().optional()
|
|
142232
|
+
projectSlug: external_exports.string().nullable().optional(),
|
|
142233
|
+
language: external_exports.enum(["pt", "en"]).optional().default("pt")
|
|
142206
142234
|
});
|
|
142207
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)?
|
|
142208
142236
|
|
|
142209
142237
|
Message: "$CONTENT"
|
|
142210
142238
|
|
|
142211
142239
|
Return ONLY valid JSON:
|
|
142212
|
-
{"intent": "create_project" | "other", "confidence": 0.0-1.0, "stackHint": "<detected stack or null>", "projectSlug": "<suggested slug or null>"}
|
|
142240
|
+
{"intent": "create_project" | "other", "confidence": 0.0-1.0, "stackHint": "<detected stack or null>", "projectSlug": "<suggested slug or null>", "language": "pt" | "en"}
|
|
142213
142241
|
|
|
142214
142242
|
Examples:
|
|
142215
|
-
- "Cria uma CLI Python que valida CPF" \u2192 {"intent":"create_project","confidence":0.95,"stackHint":"python-cli","projectSlug":"validador-cpf-cli"}
|
|
142216
|
-
- "Build me a REST API for tasks" \u2192 {"intent":"create_project","confidence":0.9,"stackHint":"fastapi","projectSlug":"task-api"}
|
|
142217
|
-
- "How's the project going?" \u2192 {"intent":"other","confidence":0.95,"stackHint":null,"projectSlug":null}
|
|
142218
|
-
- "Oi, tudo bem?" \u2192 {"intent":"other","confidence":0.99,"stackHint":null,"projectSlug":null}
|
|
142219
|
-
- "Me faz um app que converte temperaturas" \u2192 {"intent":"create_project","confidence":0.9,"stackHint":null,"projectSlug":"conversor-temperaturas"}`;
|
|
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"}`;
|
|
142220
142248
|
async function classifyDmIntent(ctx, content, workspaceDir) {
|
|
142221
142249
|
try {
|
|
142222
142250
|
const truncated = content.slice(0, MAX_CLASSIFY_LENGTH);
|
|
@@ -142283,26 +142311,23 @@ function parseClarificationResponse(text, session) {
|
|
|
142283
142311
|
}
|
|
142284
142312
|
return { recognized: false };
|
|
142285
142313
|
}
|
|
142286
|
-
function buildClarificationMessage(parsed, pendingClarification) {
|
|
142314
|
+
function buildClarificationMessage(parsed, pendingClarification, language = "pt") {
|
|
142287
142315
|
if (pendingClarification === "stack_and_name" || !parsed.stackHint && !parsed.projectName) {
|
|
142288
|
-
return
|
|
142289
|
-
|
|
142290
|
-
1. Qual stack? (Python, Node.js, Go, Java...)
|
|
142291
|
-
2. Quer dar um nome pro projeto? Se n\xE3o, eu invento um.`;
|
|
142316
|
+
return BOOTSTRAP_MESSAGES.clarifyBoth[language];
|
|
142292
142317
|
}
|
|
142293
|
-
return
|
|
142318
|
+
return BOOTSTRAP_MESSAGES.clarifyStack[language];
|
|
142294
142319
|
}
|
|
142295
142320
|
function buildFollowUpClarification(session) {
|
|
142296
|
-
|
|
142297
|
-
|
|
142298
|
-
|
|
142299
|
-
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?";
|
|
142300
142324
|
}
|
|
142301
|
-
function
|
|
142302
|
-
|
|
142303
|
-
|
|
142304
|
-
|
|
142305
|
-
|
|
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);
|
|
142306
142331
|
}
|
|
142307
142332
|
function buildTopicKickoff(projectName, idea) {
|
|
142308
142333
|
return [
|
|
@@ -142340,7 +142365,8 @@ async function classifyAndBootstrap(ctx, workspaceDir, conversationId, content)
|
|
|
142340
142365
|
await deleteTelegramBootstrapSession(workspaceDir, conversationId);
|
|
142341
142366
|
return;
|
|
142342
142367
|
}
|
|
142343
|
-
|
|
142368
|
+
const language = classification.language ?? "pt";
|
|
142369
|
+
await sendTelegramText(ctx, conversationId, BOOTSTRAP_MESSAGES.ack[language]);
|
|
142344
142370
|
const parsed = parseBootstrapRequest(content);
|
|
142345
142371
|
if (classification.stackHint && !parsed.stackHint) {
|
|
142346
142372
|
parsed.stackHint = classification.stackHint;
|
|
@@ -142374,7 +142400,8 @@ async function classifyAndBootstrap(ctx, workspaceDir, conversationId, content)
|
|
|
142374
142400
|
...incomingRequest,
|
|
142375
142401
|
sourceRoute,
|
|
142376
142402
|
sourceChannel: "telegram",
|
|
142377
|
-
status: "received"
|
|
142403
|
+
status: "received",
|
|
142404
|
+
language
|
|
142378
142405
|
});
|
|
142379
142406
|
if (!parsed.stackHint) {
|
|
142380
142407
|
const pendingClarification = !parsed.projectName ? "stack_and_name" : "stack";
|
|
@@ -142383,9 +142410,10 @@ async function classifyAndBootstrap(ctx, workspaceDir, conversationId, content)
|
|
|
142383
142410
|
...incomingRequest,
|
|
142384
142411
|
sourceRoute: session.sourceRoute,
|
|
142385
142412
|
status: "clarifying",
|
|
142386
|
-
pendingClarification
|
|
142413
|
+
pendingClarification,
|
|
142414
|
+
language
|
|
142387
142415
|
});
|
|
142388
|
-
await sendTelegramText(ctx, conversationId, buildClarificationMessage(parsed, pendingClarification));
|
|
142416
|
+
await sendTelegramText(ctx, conversationId, buildClarificationMessage(parsed, pendingClarification, language));
|
|
142389
142417
|
return;
|
|
142390
142418
|
}
|
|
142391
142419
|
continueBootstrap(ctx, conversationId, workspaceDir, incomingRequest, sourceRoute).catch((err) => {
|
|
@@ -142547,7 +142575,8 @@ Erro: ${result.error ?? "erro desconhecido"}`
|
|
|
142547
142575
|
logBootstrapWarning(ctx, `[telegram-bootstrap] immediate projectTick failed: ${error48 instanceof Error ? error48.message : String(error48)}`);
|
|
142548
142576
|
});
|
|
142549
142577
|
}
|
|
142550
|
-
|
|
142578
|
+
const sessionLang = currentSession?.language ?? "pt";
|
|
142579
|
+
await sendTelegramText(ctx, conversationId, buildDmAck(resolvedProjectName, buildTopicDeepLink(String(projectChannelId), messageThreadId), sessionLang));
|
|
142551
142580
|
await upsertTelegramBootstrapSession(workspaceDir, {
|
|
142552
142581
|
conversationId,
|
|
142553
142582
|
...incomingRequest,
|
|
@@ -142582,8 +142611,12 @@ function registerTelegramBootstrapHook(api, ctx) {
|
|
|
142582
142611
|
api.on("before_prompt_build", async (_event, eventCtx) => {
|
|
142583
142612
|
const hookCtx = eventCtx;
|
|
142584
142613
|
if (hookCtx.channelId !== "telegram") return {};
|
|
142585
|
-
const
|
|
142586
|
-
if (
|
|
142614
|
+
const sessionKey = hookCtx.sessionKey ?? "";
|
|
142615
|
+
if (sessionKey.includes(":topic:") || sessionKey.includes(":group:")) return {};
|
|
142616
|
+
const sessionKeyParts = sessionKey.split(":");
|
|
142617
|
+
const chatId = sessionKeyParts.length >= 5 ? sessionKeyParts[sessionKeyParts.length - 1] : "";
|
|
142618
|
+
const conversationId = chatId ? `telegram:${chatId}` : "";
|
|
142619
|
+
if (!conversationId) return {};
|
|
142587
142620
|
const workspaceDir = resolveWorkspaceDir(ctx.config);
|
|
142588
142621
|
if (!workspaceDir) return {};
|
|
142589
142622
|
const session = await readTelegramBootstrapSession(workspaceDir, conversationId);
|
|
@@ -142596,6 +142629,21 @@ function registerTelegramBootstrapHook(api, ctx) {
|
|
|
142596
142629
|
].join("\n")
|
|
142597
142630
|
};
|
|
142598
142631
|
});
|
|
142632
|
+
api.on("message_sending", async (event, eventCtx) => {
|
|
142633
|
+
const hookCtx = eventCtx;
|
|
142634
|
+
if (hookCtx.channelId !== "telegram") return;
|
|
142635
|
+
const sendEvent = event;
|
|
142636
|
+
const rawTo = String(sendEvent.to ?? "").trim();
|
|
142637
|
+
if (!rawTo || rawTo.startsWith("-")) return;
|
|
142638
|
+
const conversationId = rawTo.includes(":") ? rawTo : `telegram:${rawTo}`;
|
|
142639
|
+
if (conversationId.includes(":topic:")) return;
|
|
142640
|
+
const workspaceDir = resolveWorkspaceDir(ctx.config);
|
|
142641
|
+
if (!workspaceDir) return;
|
|
142642
|
+
const session = await readTelegramBootstrapSession(workspaceDir, conversationId);
|
|
142643
|
+
if (session && session.status !== "completed" && session.status !== "failed" && shouldSuppressTelegramBootstrapReply(session)) {
|
|
142644
|
+
return { cancel: true };
|
|
142645
|
+
}
|
|
142646
|
+
});
|
|
142599
142647
|
api.on("message_received", async (event, eventCtx) => {
|
|
142600
142648
|
if (eventCtx.channelId !== "telegram") return;
|
|
142601
142649
|
const telegramConfig = readFabricaTelegramConfig(ctx.pluginConfig);
|
|
@@ -142613,6 +142661,10 @@ function registerTelegramBootstrapHook(api, ctx) {
|
|
|
142613
142661
|
}
|
|
142614
142662
|
const existingSession = await readTelegramBootstrapSession(workspaceDir, conversationId);
|
|
142615
142663
|
const sessionIsExpired = existingSession != null && Date.parse(existingSession.suppressUntil) < Date.now();
|
|
142664
|
+
if (existingSession && !sessionIsExpired && existingSession.status === "classifying") {
|
|
142665
|
+
ctx.logger.info(`[telegram-bootstrap] LLM classification in progress for ${conversationId}, ignoring concurrent message`);
|
|
142666
|
+
return;
|
|
142667
|
+
}
|
|
142616
142668
|
if (existingSession?.status === "clarifying" && !sessionIsExpired) {
|
|
142617
142669
|
const clarResult = parseClarificationResponse(content, existingSession);
|
|
142618
142670
|
if (!clarResult.recognized) {
|
|
@@ -142674,7 +142726,8 @@ function registerTelegramBootstrapHook(api, ctx) {
|
|
|
142674
142726
|
ctx.logger.info(`[telegram-bootstrap] stale received session (expired) \u2014 restarting pipeline for conversation ${conversationId}`);
|
|
142675
142727
|
}
|
|
142676
142728
|
}
|
|
142677
|
-
|
|
142729
|
+
const language = /\b(cria|crie|criar|construa|desenvolva|registre|novo projeto)\b/i.test(content) ? "pt" : "en";
|
|
142730
|
+
await sendTelegramText(ctx, conversationId, BOOTSTRAP_MESSAGES.ack[language]);
|
|
142678
142731
|
const session = await upsertTelegramBootstrapSession(workspaceDir, {
|
|
142679
142732
|
conversationId,
|
|
142680
142733
|
...incomingRequest,
|
|
@@ -142683,7 +142736,8 @@ function registerTelegramBootstrapHook(api, ctx) {
|
|
|
142683
142736
|
channelId: conversationId
|
|
142684
142737
|
},
|
|
142685
142738
|
sourceChannel: "telegram",
|
|
142686
|
-
status: "received"
|
|
142739
|
+
status: "received",
|
|
142740
|
+
language
|
|
142687
142741
|
});
|
|
142688
142742
|
if (!parsed.stackHint) {
|
|
142689
142743
|
const pendingClarification = !parsed.projectName ? "stack_and_name" : "stack";
|
|
@@ -142692,9 +142746,10 @@ function registerTelegramBootstrapHook(api, ctx) {
|
|
|
142692
142746
|
...incomingRequest,
|
|
142693
142747
|
sourceRoute: session.sourceRoute,
|
|
142694
142748
|
status: "clarifying",
|
|
142695
|
-
pendingClarification
|
|
142749
|
+
pendingClarification,
|
|
142750
|
+
language
|
|
142696
142751
|
});
|
|
142697
|
-
await sendTelegramText(ctx, conversationId, buildClarificationMessage(parsed, pendingClarification));
|
|
142752
|
+
await sendTelegramText(ctx, conversationId, buildClarificationMessage(parsed, pendingClarification, language));
|
|
142698
142753
|
return;
|
|
142699
142754
|
}
|
|
142700
142755
|
continueBootstrap(ctx, conversationId, workspaceDir, incomingRequest, {
|