@mestreyoda/fabrica 0.1.9 → 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 +84 -36
- 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.10") {
|
|
111333
|
+
return "0.1.10";
|
|
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,
|
|
@@ -142596,6 +142625,18 @@ function registerTelegramBootstrapHook(api, ctx) {
|
|
|
142596
142625
|
].join("\n")
|
|
142597
142626
|
};
|
|
142598
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
|
+
});
|
|
142599
142640
|
api.on("message_received", async (event, eventCtx) => {
|
|
142600
142641
|
if (eventCtx.channelId !== "telegram") return;
|
|
142601
142642
|
const telegramConfig = readFabricaTelegramConfig(ctx.pluginConfig);
|
|
@@ -142613,6 +142654,10 @@ function registerTelegramBootstrapHook(api, ctx) {
|
|
|
142613
142654
|
}
|
|
142614
142655
|
const existingSession = await readTelegramBootstrapSession(workspaceDir, conversationId);
|
|
142615
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
|
+
}
|
|
142616
142661
|
if (existingSession?.status === "clarifying" && !sessionIsExpired) {
|
|
142617
142662
|
const clarResult = parseClarificationResponse(content, existingSession);
|
|
142618
142663
|
if (!clarResult.recognized) {
|
|
@@ -142674,7 +142719,8 @@ function registerTelegramBootstrapHook(api, ctx) {
|
|
|
142674
142719
|
ctx.logger.info(`[telegram-bootstrap] stale received session (expired) \u2014 restarting pipeline for conversation ${conversationId}`);
|
|
142675
142720
|
}
|
|
142676
142721
|
}
|
|
142677
|
-
|
|
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]);
|
|
142678
142724
|
const session = await upsertTelegramBootstrapSession(workspaceDir, {
|
|
142679
142725
|
conversationId,
|
|
142680
142726
|
...incomingRequest,
|
|
@@ -142683,7 +142729,8 @@ function registerTelegramBootstrapHook(api, ctx) {
|
|
|
142683
142729
|
channelId: conversationId
|
|
142684
142730
|
},
|
|
142685
142731
|
sourceChannel: "telegram",
|
|
142686
|
-
status: "received"
|
|
142732
|
+
status: "received",
|
|
142733
|
+
language
|
|
142687
142734
|
});
|
|
142688
142735
|
if (!parsed.stackHint) {
|
|
142689
142736
|
const pendingClarification = !parsed.projectName ? "stack_and_name" : "stack";
|
|
@@ -142692,9 +142739,10 @@ function registerTelegramBootstrapHook(api, ctx) {
|
|
|
142692
142739
|
...incomingRequest,
|
|
142693
142740
|
sourceRoute: session.sourceRoute,
|
|
142694
142741
|
status: "clarifying",
|
|
142695
|
-
pendingClarification
|
|
142742
|
+
pendingClarification,
|
|
142743
|
+
language
|
|
142696
142744
|
});
|
|
142697
|
-
await sendTelegramText(ctx, conversationId, buildClarificationMessage(parsed, pendingClarification));
|
|
142745
|
+
await sendTelegramText(ctx, conversationId, buildClarificationMessage(parsed, pendingClarification, language));
|
|
142698
142746
|
return;
|
|
142699
142747
|
}
|
|
142700
142748
|
continueBootstrap(ctx, conversationId, workspaceDir, incomingRequest, {
|