@gurulu/cli 1.2.2 → 1.3.0

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/bin.js CHANGED
@@ -25118,7 +25118,7 @@ function sleep(ms) {
25118
25118
  // src/wizard/run.ts
25119
25119
  import { existsSync as existsSync9, mkdirSync as mkdirSync2, writeFileSync as writeFileSync8 } from "node:fs";
25120
25120
  import { dirname as dirname3 } from "node:path";
25121
- import * as p3 from "@clack/prompts";
25121
+ import * as p4 from "@clack/prompts";
25122
25122
 
25123
25123
  // src/commands/pull.ts
25124
25124
  import { writeFileSync as writeFileSync3 } from "node:fs";
@@ -25262,6 +25262,17 @@ var pullCmd = defineCommand({
25262
25262
  // src/lib/detect.ts
25263
25263
  import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
25264
25264
  import { dirname as dirname2, join as join5, parse } from "node:path";
25265
+ var LLM_DEP_MAP = {
25266
+ openai: "openai",
25267
+ "@anthropic-ai/sdk": "anthropic",
25268
+ "@langchain/core": "langchain",
25269
+ langchain: "langchain",
25270
+ "@google/generative-ai": "google-genai",
25271
+ ai: "vercel-ai",
25272
+ "cohere-ai": "cohere",
25273
+ "@mistralai/mistralai": "mistral",
25274
+ ollama: "ollama"
25275
+ };
25265
25276
  function readPackageJson(dir) {
25266
25277
  const p = join5(dir, "package.json");
25267
25278
  if (!existsSync4(p))
@@ -25347,6 +25358,14 @@ function frameworkRuntime(fw) {
25347
25358
  return "unknown";
25348
25359
  }
25349
25360
  }
25361
+ function detectLlmFrameworks(pkg) {
25362
+ const found = new Set;
25363
+ for (const [dep, fw] of Object.entries(LLM_DEP_MAP)) {
25364
+ if (hasDep(pkg, dep))
25365
+ found.add(fw);
25366
+ }
25367
+ return [...found];
25368
+ }
25350
25369
  function detectProject(dir) {
25351
25370
  const pkg = readPackageJson(dir);
25352
25371
  const framework = detectFramework(pkg, dir);
@@ -25356,7 +25375,8 @@ function detectProject(dir) {
25356
25375
  framework,
25357
25376
  runtime: frameworkRuntime(framework),
25358
25377
  packageManager: detectPackageManager(dir),
25359
- packageJson: pkg
25378
+ packageJson: pkg,
25379
+ llmFrameworks: detectLlmFrameworks(pkg)
25360
25380
  };
25361
25381
  }
25362
25382
 
@@ -26133,8 +26153,77 @@ function gatherContext(opts) {
26133
26153
  return { files, capped, totalBytes };
26134
26154
  }
26135
26155
 
26136
- // src/wizard/plan.ts
26156
+ // src/wizard/features.ts
26137
26157
  import * as p2 from "@clack/prompts";
26158
+ function availableFeatures(detected) {
26159
+ const isBrowser = frameworkRuntime(detected.framework) !== "node";
26160
+ const feats = [];
26161
+ feats.push({
26162
+ key: "error",
26163
+ label: "Hata takibi",
26164
+ detail: "Tarayıcı JS hatalarını otomatik yakala (js_error)",
26165
+ enableHint: isBrowser ? "gurulu.init({ ..., autocapture: { js_error: true } })" : "Sunucu hatalarında: gurulu.track('js_error', { message, error_type })",
26166
+ recommended: isBrowser
26167
+ });
26168
+ if (detected.llmFrameworks.length > 0) {
26169
+ feats.push({
26170
+ key: "llm",
26171
+ label: `LLM analizi (${detected.llmFrameworks.join(", ")} tespit edildi)`,
26172
+ detail: "AI çağrı maliyeti/latency/hata/model performansı",
26173
+ enableHint: "import { wrapOpenAI } from '@gurulu/node'; const client = wrapOpenAI(openai);",
26174
+ recommended: true
26175
+ });
26176
+ }
26177
+ if (isBrowser) {
26178
+ feats.push({
26179
+ key: "activation",
26180
+ label: "Activation (popup · tur · A/B test · kişiselleştirme)",
26181
+ detail: "Dashboard'dan yayınla, SDK render etsin (Action Layer)",
26182
+ enableHint: "import { runActivation } from '@gurulu/web/activate'; runActivation(gurulu);",
26183
+ recommended: false
26184
+ });
26185
+ }
26186
+ return feats;
26187
+ }
26188
+ async function runFeatures(client, detected, opts) {
26189
+ const avail = availableFeatures(detected);
26190
+ if (avail.length === 0 || !opts.authed)
26191
+ return { selected: [], registered: false };
26192
+ let selectedKeys;
26193
+ if (opts.yes) {
26194
+ selectedKeys = avail.filter((f3) => f3.recommended).map((f3) => f3.key);
26195
+ } else {
26196
+ const choice = await p2.multiselect({
26197
+ message: "Hangi özellikleri kuralım? (event'ler registry'ye otomatik eklenir)",
26198
+ options: avail.map((f3) => ({ value: f3.key, label: f3.label, hint: f3.detail })),
26199
+ initialValues: avail.filter((f3) => f3.recommended).map((f3) => f3.key),
26200
+ required: false
26201
+ });
26202
+ if (p2.isCancel(choice))
26203
+ return { selected: [], registered: false };
26204
+ selectedKeys = choice;
26205
+ }
26206
+ if (selectedKeys.length === 0)
26207
+ return { selected: [], registered: false };
26208
+ const selected = avail.filter((f3) => selectedKeys.includes(f3.key));
26209
+ const s2 = p2.spinner();
26210
+ s2.start("Özellikler registry'ye kuruluyor…");
26211
+ try {
26212
+ await client.post("/features/register", { features: selectedKeys });
26213
+ s2.stop(c3.neon(`✓ ${selected.length} özellik kuruldu`));
26214
+ } catch {
26215
+ s2.stop("Özellik kurulumu atlandı (gateway hatası) — sonra: gurulu doctor", 1);
26216
+ return { selected, registered: false };
26217
+ }
26218
+ p2.note(selected.map((f3) => `${c3.bold(f3.label)}
26219
+ ${c3.dim(f3.enableHint)}`).join(`
26220
+
26221
+ `), "Etkinleştirme");
26222
+ return { selected, registered: true };
26223
+ }
26224
+
26225
+ // src/wizard/plan.ts
26226
+ import * as p3 from "@clack/prompts";
26138
26227
  async function fetchPlan(client, context, input) {
26139
26228
  if (context.files.length === 0)
26140
26229
  return null;
@@ -26179,12 +26268,12 @@ function formatPlan(plan) {
26179
26268
  `).trimEnd();
26180
26269
  }
26181
26270
  async function renderPlan(plan) {
26182
- p2.note(formatPlan(plan), plan.summary);
26271
+ p3.note(formatPlan(plan), plan.summary);
26183
26272
  const newCount = plan.events.filter((e2) => !e2.existing).length;
26184
- const ok = await p2.confirm({
26273
+ const ok = await p3.confirm({
26185
26274
  message: `${plan.events.length} event (${newCount} yeni) — bu planı uygula?`
26186
26275
  });
26187
- if (p2.isCancel(ok) || !ok)
26276
+ if (p3.isCancel(ok) || !ok)
26188
26277
  return null;
26189
26278
  return plan.events;
26190
26279
  }
@@ -26199,8 +26288,8 @@ import { promisify } from "node:util";
26199
26288
 
26200
26289
  // src/wizard/guard.ts
26201
26290
  import { basename, isAbsolute, relative as relative2, resolve } from "node:path";
26202
- function resolveInCwd(p3, cwd) {
26203
- return isAbsolute(p3) ? p3 : resolve(cwd, p3);
26291
+ function resolveInCwd(p4, cwd) {
26292
+ return isAbsolute(p4) ? p4 : resolve(cwd, p4);
26204
26293
  }
26205
26294
  function isAdditiveEdit(find, replace) {
26206
26295
  if (find.length === 0)
@@ -26277,8 +26366,8 @@ function isAllowedBash(cmd) {
26277
26366
  }
26278
26367
  return { ok: false, reason: `allowlist dışı binary: ${bin}` };
26279
26368
  }
26280
- function isAllowedPath(p3, cwd) {
26281
- const abs = isAbsolute(p3) ? p3 : resolve(cwd, p3);
26369
+ function isAllowedPath(p4, cwd) {
26370
+ const abs = isAbsolute(p4) ? p4 : resolve(cwd, p4);
26282
26371
  const rel = relative2(cwd, abs);
26283
26372
  if (rel === "" || rel.startsWith("..") || isAbsolute(rel)) {
26284
26373
  return { ok: false, reason: "cwd dışı yol" };
@@ -26542,16 +26631,16 @@ var FRAMEWORKS = [
26542
26631
  "node-server"
26543
26632
  ];
26544
26633
  function bail() {
26545
- p3.cancel("İptal edildi.");
26634
+ p4.cancel("İptal edildi.");
26546
26635
  process.exit(0);
26547
26636
  }
26548
26637
  async function runWizard(opts) {
26549
26638
  if (process.stdout.isTTY)
26550
26639
  process.stdout.write(banner());
26551
- p3.intro(c3.dim("otonom kurulum başlıyor — auth → workspace → install → wire"));
26640
+ p4.intro(c3.dim("otonom kurulum başlıyor — auth → workspace → install → wire"));
26552
26641
  const TOTAL = 6;
26553
26642
  const phase = (n2, label) => {
26554
- p3.log.step(`${c3.dim(`[${n2}/${TOTAL}]`)} ${c3.bold(label)}`);
26643
+ p4.log.step(`${c3.dim(`[${n2}/${TOTAL}]`)} ${c3.bold(label)}`);
26555
26644
  };
26556
26645
  phase(1, "Kimlik doğrulama");
26557
26646
  const auth = await ensureAuth({
@@ -26568,18 +26657,18 @@ async function runWizard(opts) {
26568
26657
  if (opts.framework && FRAMEWORKS.includes(opts.framework)) {
26569
26658
  framework = opts.framework;
26570
26659
  } else if (!opts.yes) {
26571
- const ok = await p3.confirm({
26660
+ const ok = await p4.confirm({
26572
26661
  message: `Saptanan: ${detected.framework} (${detected.packageManager}). Doğru mu?`
26573
26662
  });
26574
- if (p3.isCancel(ok))
26663
+ if (p4.isCancel(ok))
26575
26664
  bail();
26576
26665
  if (!ok) {
26577
- const choice = await p3.select({
26666
+ const choice = await p4.select({
26578
26667
  message: "Framework seç",
26579
26668
  options: FRAMEWORKS.map((f3) => ({ value: f3, label: f3 })),
26580
26669
  initialValue: detected.framework
26581
26670
  });
26582
- if (p3.isCancel(choice))
26671
+ if (p4.isCancel(choice))
26583
26672
  bail();
26584
26673
  framework = choice;
26585
26674
  }
@@ -26599,17 +26688,21 @@ async function runWizard(opts) {
26599
26688
  if (approved)
26600
26689
  approvedEvents = approved;
26601
26690
  } else {
26602
- p3.log.info("AI planı yok — autocapture + sektör paketi (deterministik floor).");
26691
+ p4.log.info("AI planı yok — autocapture + sektör paketi (deterministik floor).");
26603
26692
  }
26604
26693
  }
26694
+ let featuresResult = { selected: [], registered: false };
26695
+ if (authed) {
26696
+ featuresResult = await runFeatures(client, project, { yes: opts.yes, authed });
26697
+ }
26605
26698
  phase(4, "SDK kurulumu");
26606
26699
  let installed = false;
26607
26700
  if (opts.noInstall) {
26608
- p3.log.info(`SDK kurulumu atlandı — elle: ${plan.installCommand}`);
26701
+ p4.log.info(`SDK kurulumu atlandı — elle: ${plan.installCommand}`);
26609
26702
  } else if (!detected.hasPackageJson) {
26610
- p3.log.warn("package.json yok — script tag ile kur: https://cdn.gurulu.io/t.js");
26703
+ p4.log.warn("package.json yok — script tag ile kur: https://cdn.gurulu.io/t.js");
26611
26704
  } else {
26612
- const s2 = p3.spinner();
26705
+ const s2 = p4.spinner();
26613
26706
  s2.start(`${plan.sdk} kuruluyor (${plan.installCommand})…`);
26614
26707
  const res = await execInstall(plan, { cwd: opts.cwd });
26615
26708
  if (res.ok) {
@@ -26636,7 +26729,7 @@ async function runWizard(opts) {
26636
26729
  if (auth.apiKey.startsWith("sk_")) {
26637
26730
  vars.push({ key: k2.key, value: auth.apiKey });
26638
26731
  } else {
26639
- p3.log.warn("GURULU_SECRET_KEY atlandı (login token workspace sk_ anahtarı değil). Dashboard → Settings → API Keys'ten server key oluşturup .env'e elle ekle.");
26732
+ p4.log.warn("GURULU_SECRET_KEY atlandı (login token workspace sk_ anahtarı değil). Dashboard → Settings → API Keys'ten server key oluşturup .env'e elle ekle.");
26640
26733
  }
26641
26734
  }
26642
26735
  }
@@ -26656,7 +26749,7 @@ async function runWizard(opts) {
26656
26749
  }
26657
26750
  let registeredCount = 0;
26658
26751
  if (approvedEvents.length > 0) {
26659
- const s2 = p3.spinner();
26752
+ const s2 = p4.spinner();
26660
26753
  s2.start("Yeni eventler registry kuyruguna oneriliyor…");
26661
26754
  const res = await registerNewEvents(client, approvedEvents);
26662
26755
  registeredCount = res.registered.length;
@@ -26665,29 +26758,29 @@ async function runWizard(opts) {
26665
26758
  let wiredCount = 0;
26666
26759
  if (approvedEvents.length > 0) {
26667
26760
  if (opts.noAi) {
26668
- p3.log.message(`Capture — şu çağrıları ekle:
26761
+ p4.log.message(`Capture — şu çağrıları ekle:
26669
26762
  ${captureGuide(approvedEvents, identifyHint, isNode)}`);
26670
26763
  } else {
26671
26764
  const wireFiles = gatherContext({ cwd: opts.cwd }).files.map((f3) => f3.path);
26672
26765
  const snapshots = new Map;
26673
- const s2 = p3.spinner();
26766
+ const s2 = p4.spinner();
26674
26767
  s2.start("AI capture wiring (kod düzenleniyor)…");
26675
26768
  const outcome = await runWireAgent(client, { cwd: opts.cwd, events: approvedEvents, identifyHint, files: wireFiles }, snapshots);
26676
26769
  s2.stop(`wire: ${outcome.changedFiles.length} dosya / ${outcome.steps} adım (${outcome.stoppedReason})`);
26677
26770
  if (outcome.changedFiles.length > 0) {
26678
- p3.log.message(formatWireDiff(opts.cwd, snapshots));
26679
- const keep = opts.yes ? true : await p3.confirm({
26771
+ p4.log.message(formatWireDiff(opts.cwd, snapshots));
26772
+ const keep = opts.yes ? true : await p4.confirm({
26680
26773
  message: `${outcome.changedFiles.length} dosyadaki wire değişikliklerini tut?`
26681
26774
  });
26682
- if (p3.isCancel(keep) || !keep) {
26775
+ if (p4.isCancel(keep) || !keep) {
26683
26776
  restoreSnapshots(opts.cwd, snapshots);
26684
- p3.log.info("Wire geri alındı — capture snippet rehberi:");
26685
- p3.log.message(captureGuide(approvedEvents, identifyHint, isNode));
26777
+ p4.log.info("Wire geri alındı — capture snippet rehberi:");
26778
+ p4.log.message(captureGuide(approvedEvents, identifyHint, isNode));
26686
26779
  } else {
26687
26780
  wiredCount = outcome.changedFiles.length;
26688
26781
  }
26689
26782
  } else {
26690
- p3.log.message(`Capture (AI gömemedi → snippet-göster) — şu çağrıları ekle:
26783
+ p4.log.message(`Capture (AI gömemedi → snippet-göster) — şu çağrıları ekle:
26691
26784
  ${captureGuide(approvedEvents, identifyHint, isNode)}`);
26692
26785
  }
26693
26786
  }
@@ -26706,15 +26799,18 @@ ${captureGuide(approvedEvents, identifyHint, isNode)}`);
26706
26799
  if (wiredCount > 0)
26707
26800
  lines.push(`✓ ${wiredCount} dosya AI ile capture wire edildi`);
26708
26801
  }
26802
+ if (featuresResult.registered && featuresResult.selected.length > 0) {
26803
+ lines.push(`✓ özellikler: ${featuresResult.selected.map((f3) => f3.key).join(", ")} kuruldu`);
26804
+ }
26709
26805
  lines.push(`✓ .gurulu/config.json${pulled ? " + registry pull" : ""}`);
26710
- p3.note(lines.join(`
26806
+ p4.note(lines.join(`
26711
26807
  `), c3.neon("✦ Değişiklikler"));
26712
26808
  if (inj.strategy !== "prepend-entry" || inj.reason === "no-entry") {
26713
- p3.log.info(`Wire: ${inj.wireHint ?? plan.placementHint}`);
26809
+ p4.log.info(`Wire: ${inj.wireHint ?? plan.placementHint}`);
26714
26810
  if (inj.strategy === "manual")
26715
- p3.log.message(plan.initSnippet);
26811
+ p4.log.message(plan.initSnippet);
26716
26812
  }
26717
- p3.outro(`${c3.neon("\uD83E\uDD89 Hazır!")} ${c3.dim("Doğrula:")} ${c3.bold("gurulu doctor")} ${c3.dim("·")} ${c3.dim("Dashboard:")} ${c3.cyan("https://dashboard.gurulu.io/app?onboard=done")}`);
26813
+ p4.outro(`${c3.neon("\uD83E\uDD89 Hazır!")} ${c3.dim("Doğrula:")} ${c3.bold("gurulu doctor")} ${c3.dim("·")} ${c3.dim("Dashboard:")} ${c3.cyan("https://dashboard.gurulu.io/app?onboard=done")}`);
26718
26814
  }
26719
26815
  async function resolveWorkspace(client, authWorkspaceId, opts) {
26720
26816
  if (opts.writeKey) {
@@ -26737,7 +26833,7 @@ async function resolveWorkspace(client, authWorkspaceId, opts) {
26737
26833
  selected = CREATE;
26738
26834
  } else {
26739
26835
  const initial = list.find((w2) => w2.workspace_id === authWorkspaceId)?.workspace_id ?? list[0]?.workspace_id ?? CREATE;
26740
- const choice = await p3.select({
26836
+ const choice = await p4.select({
26741
26837
  message: "Workspace seç",
26742
26838
  options: [
26743
26839
  ...list.map((w2) => ({ value: w2.workspace_id, label: w2.name, hint: w2.slug })),
@@ -26745,26 +26841,26 @@ async function resolveWorkspace(client, authWorkspaceId, opts) {
26745
26841
  ],
26746
26842
  initialValue: initial
26747
26843
  });
26748
- if (p3.isCancel(choice))
26844
+ if (p4.isCancel(choice))
26749
26845
  bail();
26750
26846
  selected = choice;
26751
26847
  }
26752
26848
  if (selected === CREATE) {
26753
- const name = await p3.text({
26849
+ const name = await p4.text({
26754
26850
  message: "Workspace adı",
26755
26851
  placeholder: "My App",
26756
26852
  validate: (v2) => v2.trim() ? undefined : "gerekli"
26757
26853
  });
26758
- if (p3.isCancel(name))
26854
+ if (p4.isCancel(name))
26759
26855
  bail();
26760
- const domain = await p3.text({
26856
+ const domain = await p4.text({
26761
26857
  message: "Domain",
26762
26858
  placeholder: "example.com",
26763
26859
  validate: (v2) => v2.trim().length >= 3 ? undefined : "geçerli domain gerekli"
26764
26860
  });
26765
- if (p3.isCancel(domain))
26861
+ if (p4.isCancel(domain))
26766
26862
  bail();
26767
- const s2 = p3.spinner();
26863
+ const s2 = p4.spinner();
26768
26864
  s2.start("Workspace oluşturuluyor…");
26769
26865
  const created = await client.createWorkspace({
26770
26866
  name: String(name).trim(),
@@ -27089,7 +27185,7 @@ import { execFile as execFile2 } from "node:child_process";
27089
27185
  import { existsSync as existsSync11, readFileSync as readFileSync11, rmSync, writeFileSync as writeFileSync10 } from "node:fs";
27090
27186
  import { join as join10 } from "node:path";
27091
27187
  import { promisify as promisify2 } from "node:util";
27092
- import * as p4 from "@clack/prompts";
27188
+ import * as p5 from "@clack/prompts";
27093
27189
  var pexec2 = promisify2(execFile2);
27094
27190
  var ENV_FILES = [".env.local", ".env"];
27095
27191
  var GURULU_PREFIXES = ["GURULU_", "NEXT_PUBLIC_GURULU", "VITE_GURULU"];
@@ -27116,23 +27212,23 @@ var uninstallCmd = defineCommand({
27116
27212
  const config = readProjectConfig(cwd);
27117
27213
  const detected = detectProject(cwd);
27118
27214
  const pkg = config?.sdk_preference === "node" ? "@gurulu/node" : "@gurulu/web";
27119
- p4.intro("Gurulu uninstall");
27120
- p4.note([
27215
+ p5.intro("Gurulu uninstall");
27216
+ p5.note([
27121
27217
  `• SDK kaldır: ${pkg} (${detected.packageManager})`,
27122
27218
  `• env temizle: ${ENV_FILES.join(", ")} (GURULU_* anahtarları)`,
27123
27219
  "• .gurulu/ dizinini sil"
27124
27220
  ].join(`
27125
27221
  `), "Şunlar yapılacak");
27126
27222
  if (!args.yes) {
27127
- const ok = await p4.confirm({ message: "Devam edilsin mi?" });
27128
- if (p4.isCancel(ok) || !ok) {
27129
- p4.cancel("İptal.");
27223
+ const ok = await p5.confirm({ message: "Devam edilsin mi?" });
27224
+ if (p5.isCancel(ok) || !ok) {
27225
+ p5.cancel("İptal.");
27130
27226
  process.exit(0);
27131
27227
  }
27132
27228
  }
27133
27229
  if (!args["no-deps"] && detected.hasPackageJson) {
27134
27230
  const { bin, args: a2 } = removeCmd(detected.packageManager, pkg);
27135
- const s2 = p4.spinner();
27231
+ const s2 = p5.spinner();
27136
27232
  s2.start(`${pkg} kaldırılıyor…`);
27137
27233
  try {
27138
27234
  await pexec2(bin, a2, { cwd, timeout: 120000 });
@@ -27155,7 +27251,7 @@ var uninstallCmd = defineCommand({
27155
27251
  const guruluDir = join10(cwd, ".gurulu");
27156
27252
  if (existsSync11(guruluDir))
27157
27253
  rmSync(guruluDir, { recursive: true, force: true });
27158
- p4.outro(`Kaldırıldı. env: ${cleaned.join(", ") || "değişiklik yok"} · .gurulu silindi. (Koddaki init/track çağrılarını elle çıkar.)`);
27254
+ p5.outro(`Kaldırıldı. env: ${cleaned.join(", ") || "değişiklik yok"} · .gurulu silindi. (Koddaki init/track çağrılarını elle çıkar.)`);
27159
27255
  }
27160
27256
  });
27161
27257
 
package/dist/index.js CHANGED
@@ -24695,7 +24695,7 @@ function sleep(ms) {
24695
24695
  // src/wizard/run.ts
24696
24696
  import { existsSync as existsSync9, mkdirSync as mkdirSync2, writeFileSync as writeFileSync8 } from "node:fs";
24697
24697
  import { dirname as dirname3 } from "node:path";
24698
- import * as p3 from "@clack/prompts";
24698
+ import * as p4 from "@clack/prompts";
24699
24699
 
24700
24700
  // src/commands/pull.ts
24701
24701
  import { writeFileSync as writeFileSync3 } from "node:fs";
@@ -24839,6 +24839,17 @@ var pullCmd = defineCommand({
24839
24839
  // src/lib/detect.ts
24840
24840
  import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
24841
24841
  import { dirname as dirname2, join as join5, parse } from "node:path";
24842
+ var LLM_DEP_MAP = {
24843
+ openai: "openai",
24844
+ "@anthropic-ai/sdk": "anthropic",
24845
+ "@langchain/core": "langchain",
24846
+ langchain: "langchain",
24847
+ "@google/generative-ai": "google-genai",
24848
+ ai: "vercel-ai",
24849
+ "cohere-ai": "cohere",
24850
+ "@mistralai/mistralai": "mistral",
24851
+ ollama: "ollama"
24852
+ };
24842
24853
  function readPackageJson(dir) {
24843
24854
  const p = join5(dir, "package.json");
24844
24855
  if (!existsSync4(p))
@@ -24924,6 +24935,14 @@ function frameworkRuntime(fw) {
24924
24935
  return "unknown";
24925
24936
  }
24926
24937
  }
24938
+ function detectLlmFrameworks(pkg) {
24939
+ const found = new Set;
24940
+ for (const [dep, fw] of Object.entries(LLM_DEP_MAP)) {
24941
+ if (hasDep(pkg, dep))
24942
+ found.add(fw);
24943
+ }
24944
+ return [...found];
24945
+ }
24927
24946
  function detectProject(dir) {
24928
24947
  const pkg = readPackageJson(dir);
24929
24948
  const framework = detectFramework(pkg, dir);
@@ -24933,7 +24952,8 @@ function detectProject(dir) {
24933
24952
  framework,
24934
24953
  runtime: frameworkRuntime(framework),
24935
24954
  packageManager: detectPackageManager(dir),
24936
- packageJson: pkg
24955
+ packageJson: pkg,
24956
+ llmFrameworks: detectLlmFrameworks(pkg)
24937
24957
  };
24938
24958
  }
24939
24959
 
@@ -25710,8 +25730,77 @@ function gatherContext(opts) {
25710
25730
  return { files, capped, totalBytes };
25711
25731
  }
25712
25732
 
25713
- // src/wizard/plan.ts
25733
+ // src/wizard/features.ts
25714
25734
  import * as p2 from "@clack/prompts";
25735
+ function availableFeatures(detected) {
25736
+ const isBrowser = frameworkRuntime(detected.framework) !== "node";
25737
+ const feats = [];
25738
+ feats.push({
25739
+ key: "error",
25740
+ label: "Hata takibi",
25741
+ detail: "Tarayıcı JS hatalarını otomatik yakala (js_error)",
25742
+ enableHint: isBrowser ? "gurulu.init({ ..., autocapture: { js_error: true } })" : "Sunucu hatalarında: gurulu.track('js_error', { message, error_type })",
25743
+ recommended: isBrowser
25744
+ });
25745
+ if (detected.llmFrameworks.length > 0) {
25746
+ feats.push({
25747
+ key: "llm",
25748
+ label: `LLM analizi (${detected.llmFrameworks.join(", ")} tespit edildi)`,
25749
+ detail: "AI çağrı maliyeti/latency/hata/model performansı",
25750
+ enableHint: "import { wrapOpenAI } from '@gurulu/node'; const client = wrapOpenAI(openai);",
25751
+ recommended: true
25752
+ });
25753
+ }
25754
+ if (isBrowser) {
25755
+ feats.push({
25756
+ key: "activation",
25757
+ label: "Activation (popup · tur · A/B test · kişiselleştirme)",
25758
+ detail: "Dashboard'dan yayınla, SDK render etsin (Action Layer)",
25759
+ enableHint: "import { runActivation } from '@gurulu/web/activate'; runActivation(gurulu);",
25760
+ recommended: false
25761
+ });
25762
+ }
25763
+ return feats;
25764
+ }
25765
+ async function runFeatures(client, detected, opts) {
25766
+ const avail = availableFeatures(detected);
25767
+ if (avail.length === 0 || !opts.authed)
25768
+ return { selected: [], registered: false };
25769
+ let selectedKeys;
25770
+ if (opts.yes) {
25771
+ selectedKeys = avail.filter((f3) => f3.recommended).map((f3) => f3.key);
25772
+ } else {
25773
+ const choice = await p2.multiselect({
25774
+ message: "Hangi özellikleri kuralım? (event'ler registry'ye otomatik eklenir)",
25775
+ options: avail.map((f3) => ({ value: f3.key, label: f3.label, hint: f3.detail })),
25776
+ initialValues: avail.filter((f3) => f3.recommended).map((f3) => f3.key),
25777
+ required: false
25778
+ });
25779
+ if (p2.isCancel(choice))
25780
+ return { selected: [], registered: false };
25781
+ selectedKeys = choice;
25782
+ }
25783
+ if (selectedKeys.length === 0)
25784
+ return { selected: [], registered: false };
25785
+ const selected = avail.filter((f3) => selectedKeys.includes(f3.key));
25786
+ const s2 = p2.spinner();
25787
+ s2.start("Özellikler registry'ye kuruluyor…");
25788
+ try {
25789
+ await client.post("/features/register", { features: selectedKeys });
25790
+ s2.stop(c3.neon(`✓ ${selected.length} özellik kuruldu`));
25791
+ } catch {
25792
+ s2.stop("Özellik kurulumu atlandı (gateway hatası) — sonra: gurulu doctor", 1);
25793
+ return { selected, registered: false };
25794
+ }
25795
+ p2.note(selected.map((f3) => `${c3.bold(f3.label)}
25796
+ ${c3.dim(f3.enableHint)}`).join(`
25797
+
25798
+ `), "Etkinleştirme");
25799
+ return { selected, registered: true };
25800
+ }
25801
+
25802
+ // src/wizard/plan.ts
25803
+ import * as p3 from "@clack/prompts";
25715
25804
  async function fetchPlan(client, context, input) {
25716
25805
  if (context.files.length === 0)
25717
25806
  return null;
@@ -25756,12 +25845,12 @@ function formatPlan(plan) {
25756
25845
  `).trimEnd();
25757
25846
  }
25758
25847
  async function renderPlan(plan) {
25759
- p2.note(formatPlan(plan), plan.summary);
25848
+ p3.note(formatPlan(plan), plan.summary);
25760
25849
  const newCount = plan.events.filter((e2) => !e2.existing).length;
25761
- const ok = await p2.confirm({
25850
+ const ok = await p3.confirm({
25762
25851
  message: `${plan.events.length} event (${newCount} yeni) — bu planı uygula?`
25763
25852
  });
25764
- if (p2.isCancel(ok) || !ok)
25853
+ if (p3.isCancel(ok) || !ok)
25765
25854
  return null;
25766
25855
  return plan.events;
25767
25856
  }
@@ -25776,8 +25865,8 @@ import { promisify } from "node:util";
25776
25865
 
25777
25866
  // src/wizard/guard.ts
25778
25867
  import { basename, isAbsolute, relative as relative2, resolve } from "node:path";
25779
- function resolveInCwd(p3, cwd) {
25780
- return isAbsolute(p3) ? p3 : resolve(cwd, p3);
25868
+ function resolveInCwd(p4, cwd) {
25869
+ return isAbsolute(p4) ? p4 : resolve(cwd, p4);
25781
25870
  }
25782
25871
  function isAdditiveEdit(find, replace) {
25783
25872
  if (find.length === 0)
@@ -25854,8 +25943,8 @@ function isAllowedBash(cmd) {
25854
25943
  }
25855
25944
  return { ok: false, reason: `allowlist dışı binary: ${bin}` };
25856
25945
  }
25857
- function isAllowedPath(p3, cwd) {
25858
- const abs = isAbsolute(p3) ? p3 : resolve(cwd, p3);
25946
+ function isAllowedPath(p4, cwd) {
25947
+ const abs = isAbsolute(p4) ? p4 : resolve(cwd, p4);
25859
25948
  const rel = relative2(cwd, abs);
25860
25949
  if (rel === "" || rel.startsWith("..") || isAbsolute(rel)) {
25861
25950
  return { ok: false, reason: "cwd dışı yol" };
@@ -26119,16 +26208,16 @@ var FRAMEWORKS = [
26119
26208
  "node-server"
26120
26209
  ];
26121
26210
  function bail() {
26122
- p3.cancel("İptal edildi.");
26211
+ p4.cancel("İptal edildi.");
26123
26212
  process.exit(0);
26124
26213
  }
26125
26214
  async function runWizard(opts) {
26126
26215
  if (process.stdout.isTTY)
26127
26216
  process.stdout.write(banner());
26128
- p3.intro(c3.dim("otonom kurulum başlıyor — auth → workspace → install → wire"));
26217
+ p4.intro(c3.dim("otonom kurulum başlıyor — auth → workspace → install → wire"));
26129
26218
  const TOTAL = 6;
26130
26219
  const phase = (n2, label) => {
26131
- p3.log.step(`${c3.dim(`[${n2}/${TOTAL}]`)} ${c3.bold(label)}`);
26220
+ p4.log.step(`${c3.dim(`[${n2}/${TOTAL}]`)} ${c3.bold(label)}`);
26132
26221
  };
26133
26222
  phase(1, "Kimlik doğrulama");
26134
26223
  const auth = await ensureAuth({
@@ -26145,18 +26234,18 @@ async function runWizard(opts) {
26145
26234
  if (opts.framework && FRAMEWORKS.includes(opts.framework)) {
26146
26235
  framework = opts.framework;
26147
26236
  } else if (!opts.yes) {
26148
- const ok = await p3.confirm({
26237
+ const ok = await p4.confirm({
26149
26238
  message: `Saptanan: ${detected.framework} (${detected.packageManager}). Doğru mu?`
26150
26239
  });
26151
- if (p3.isCancel(ok))
26240
+ if (p4.isCancel(ok))
26152
26241
  bail();
26153
26242
  if (!ok) {
26154
- const choice = await p3.select({
26243
+ const choice = await p4.select({
26155
26244
  message: "Framework seç",
26156
26245
  options: FRAMEWORKS.map((f3) => ({ value: f3, label: f3 })),
26157
26246
  initialValue: detected.framework
26158
26247
  });
26159
- if (p3.isCancel(choice))
26248
+ if (p4.isCancel(choice))
26160
26249
  bail();
26161
26250
  framework = choice;
26162
26251
  }
@@ -26176,17 +26265,21 @@ async function runWizard(opts) {
26176
26265
  if (approved)
26177
26266
  approvedEvents = approved;
26178
26267
  } else {
26179
- p3.log.info("AI planı yok — autocapture + sektör paketi (deterministik floor).");
26268
+ p4.log.info("AI planı yok — autocapture + sektör paketi (deterministik floor).");
26180
26269
  }
26181
26270
  }
26271
+ let featuresResult = { selected: [], registered: false };
26272
+ if (authed) {
26273
+ featuresResult = await runFeatures(client, project, { yes: opts.yes, authed });
26274
+ }
26182
26275
  phase(4, "SDK kurulumu");
26183
26276
  let installed = false;
26184
26277
  if (opts.noInstall) {
26185
- p3.log.info(`SDK kurulumu atlandı — elle: ${plan.installCommand}`);
26278
+ p4.log.info(`SDK kurulumu atlandı — elle: ${plan.installCommand}`);
26186
26279
  } else if (!detected.hasPackageJson) {
26187
- p3.log.warn("package.json yok — script tag ile kur: https://cdn.gurulu.io/t.js");
26280
+ p4.log.warn("package.json yok — script tag ile kur: https://cdn.gurulu.io/t.js");
26188
26281
  } else {
26189
- const s2 = p3.spinner();
26282
+ const s2 = p4.spinner();
26190
26283
  s2.start(`${plan.sdk} kuruluyor (${plan.installCommand})…`);
26191
26284
  const res = await execInstall(plan, { cwd: opts.cwd });
26192
26285
  if (res.ok) {
@@ -26213,7 +26306,7 @@ async function runWizard(opts) {
26213
26306
  if (auth.apiKey.startsWith("sk_")) {
26214
26307
  vars.push({ key: k2.key, value: auth.apiKey });
26215
26308
  } else {
26216
- p3.log.warn("GURULU_SECRET_KEY atlandı (login token workspace sk_ anahtarı değil). Dashboard → Settings → API Keys'ten server key oluşturup .env'e elle ekle.");
26309
+ p4.log.warn("GURULU_SECRET_KEY atlandı (login token workspace sk_ anahtarı değil). Dashboard → Settings → API Keys'ten server key oluşturup .env'e elle ekle.");
26217
26310
  }
26218
26311
  }
26219
26312
  }
@@ -26233,7 +26326,7 @@ async function runWizard(opts) {
26233
26326
  }
26234
26327
  let registeredCount = 0;
26235
26328
  if (approvedEvents.length > 0) {
26236
- const s2 = p3.spinner();
26329
+ const s2 = p4.spinner();
26237
26330
  s2.start("Yeni eventler registry kuyruguna oneriliyor…");
26238
26331
  const res = await registerNewEvents(client, approvedEvents);
26239
26332
  registeredCount = res.registered.length;
@@ -26242,29 +26335,29 @@ async function runWizard(opts) {
26242
26335
  let wiredCount = 0;
26243
26336
  if (approvedEvents.length > 0) {
26244
26337
  if (opts.noAi) {
26245
- p3.log.message(`Capture — şu çağrıları ekle:
26338
+ p4.log.message(`Capture — şu çağrıları ekle:
26246
26339
  ${captureGuide(approvedEvents, identifyHint, isNode)}`);
26247
26340
  } else {
26248
26341
  const wireFiles = gatherContext({ cwd: opts.cwd }).files.map((f3) => f3.path);
26249
26342
  const snapshots = new Map;
26250
- const s2 = p3.spinner();
26343
+ const s2 = p4.spinner();
26251
26344
  s2.start("AI capture wiring (kod düzenleniyor)…");
26252
26345
  const outcome = await runWireAgent(client, { cwd: opts.cwd, events: approvedEvents, identifyHint, files: wireFiles }, snapshots);
26253
26346
  s2.stop(`wire: ${outcome.changedFiles.length} dosya / ${outcome.steps} adım (${outcome.stoppedReason})`);
26254
26347
  if (outcome.changedFiles.length > 0) {
26255
- p3.log.message(formatWireDiff(opts.cwd, snapshots));
26256
- const keep = opts.yes ? true : await p3.confirm({
26348
+ p4.log.message(formatWireDiff(opts.cwd, snapshots));
26349
+ const keep = opts.yes ? true : await p4.confirm({
26257
26350
  message: `${outcome.changedFiles.length} dosyadaki wire değişikliklerini tut?`
26258
26351
  });
26259
- if (p3.isCancel(keep) || !keep) {
26352
+ if (p4.isCancel(keep) || !keep) {
26260
26353
  restoreSnapshots(opts.cwd, snapshots);
26261
- p3.log.info("Wire geri alındı — capture snippet rehberi:");
26262
- p3.log.message(captureGuide(approvedEvents, identifyHint, isNode));
26354
+ p4.log.info("Wire geri alındı — capture snippet rehberi:");
26355
+ p4.log.message(captureGuide(approvedEvents, identifyHint, isNode));
26263
26356
  } else {
26264
26357
  wiredCount = outcome.changedFiles.length;
26265
26358
  }
26266
26359
  } else {
26267
- p3.log.message(`Capture (AI gömemedi → snippet-göster) — şu çağrıları ekle:
26360
+ p4.log.message(`Capture (AI gömemedi → snippet-göster) — şu çağrıları ekle:
26268
26361
  ${captureGuide(approvedEvents, identifyHint, isNode)}`);
26269
26362
  }
26270
26363
  }
@@ -26283,15 +26376,18 @@ ${captureGuide(approvedEvents, identifyHint, isNode)}`);
26283
26376
  if (wiredCount > 0)
26284
26377
  lines.push(`✓ ${wiredCount} dosya AI ile capture wire edildi`);
26285
26378
  }
26379
+ if (featuresResult.registered && featuresResult.selected.length > 0) {
26380
+ lines.push(`✓ özellikler: ${featuresResult.selected.map((f3) => f3.key).join(", ")} kuruldu`);
26381
+ }
26286
26382
  lines.push(`✓ .gurulu/config.json${pulled ? " + registry pull" : ""}`);
26287
- p3.note(lines.join(`
26383
+ p4.note(lines.join(`
26288
26384
  `), c3.neon("✦ Değişiklikler"));
26289
26385
  if (inj.strategy !== "prepend-entry" || inj.reason === "no-entry") {
26290
- p3.log.info(`Wire: ${inj.wireHint ?? plan.placementHint}`);
26386
+ p4.log.info(`Wire: ${inj.wireHint ?? plan.placementHint}`);
26291
26387
  if (inj.strategy === "manual")
26292
- p3.log.message(plan.initSnippet);
26388
+ p4.log.message(plan.initSnippet);
26293
26389
  }
26294
- p3.outro(`${c3.neon("\uD83E\uDD89 Hazır!")} ${c3.dim("Doğrula:")} ${c3.bold("gurulu doctor")} ${c3.dim("·")} ${c3.dim("Dashboard:")} ${c3.cyan("https://dashboard.gurulu.io/app?onboard=done")}`);
26390
+ p4.outro(`${c3.neon("\uD83E\uDD89 Hazır!")} ${c3.dim("Doğrula:")} ${c3.bold("gurulu doctor")} ${c3.dim("·")} ${c3.dim("Dashboard:")} ${c3.cyan("https://dashboard.gurulu.io/app?onboard=done")}`);
26295
26391
  }
26296
26392
  async function resolveWorkspace(client, authWorkspaceId, opts) {
26297
26393
  if (opts.writeKey) {
@@ -26314,7 +26410,7 @@ async function resolveWorkspace(client, authWorkspaceId, opts) {
26314
26410
  selected = CREATE;
26315
26411
  } else {
26316
26412
  const initial = list.find((w2) => w2.workspace_id === authWorkspaceId)?.workspace_id ?? list[0]?.workspace_id ?? CREATE;
26317
- const choice = await p3.select({
26413
+ const choice = await p4.select({
26318
26414
  message: "Workspace seç",
26319
26415
  options: [
26320
26416
  ...list.map((w2) => ({ value: w2.workspace_id, label: w2.name, hint: w2.slug })),
@@ -26322,26 +26418,26 @@ async function resolveWorkspace(client, authWorkspaceId, opts) {
26322
26418
  ],
26323
26419
  initialValue: initial
26324
26420
  });
26325
- if (p3.isCancel(choice))
26421
+ if (p4.isCancel(choice))
26326
26422
  bail();
26327
26423
  selected = choice;
26328
26424
  }
26329
26425
  if (selected === CREATE) {
26330
- const name = await p3.text({
26426
+ const name = await p4.text({
26331
26427
  message: "Workspace adı",
26332
26428
  placeholder: "My App",
26333
26429
  validate: (v2) => v2.trim() ? undefined : "gerekli"
26334
26430
  });
26335
- if (p3.isCancel(name))
26431
+ if (p4.isCancel(name))
26336
26432
  bail();
26337
- const domain = await p3.text({
26433
+ const domain = await p4.text({
26338
26434
  message: "Domain",
26339
26435
  placeholder: "example.com",
26340
26436
  validate: (v2) => v2.trim().length >= 3 ? undefined : "geçerli domain gerekli"
26341
26437
  });
26342
- if (p3.isCancel(domain))
26438
+ if (p4.isCancel(domain))
26343
26439
  bail();
26344
- const s2 = p3.spinner();
26440
+ const s2 = p4.spinner();
26345
26441
  s2.start("Workspace oluşturuluyor…");
26346
26442
  const created = await client.createWorkspace({
26347
26443
  name: String(name).trim(),
@@ -26666,7 +26762,7 @@ import { execFile as execFile2 } from "node:child_process";
26666
26762
  import { existsSync as existsSync11, readFileSync as readFileSync11, rmSync, writeFileSync as writeFileSync10 } from "node:fs";
26667
26763
  import { join as join10 } from "node:path";
26668
26764
  import { promisify as promisify2 } from "node:util";
26669
- import * as p4 from "@clack/prompts";
26765
+ import * as p5 from "@clack/prompts";
26670
26766
  var pexec2 = promisify2(execFile2);
26671
26767
  var ENV_FILES = [".env.local", ".env"];
26672
26768
  var GURULU_PREFIXES = ["GURULU_", "NEXT_PUBLIC_GURULU", "VITE_GURULU"];
@@ -26693,23 +26789,23 @@ var uninstallCmd = defineCommand({
26693
26789
  const config = readProjectConfig(cwd);
26694
26790
  const detected = detectProject(cwd);
26695
26791
  const pkg = config?.sdk_preference === "node" ? "@gurulu/node" : "@gurulu/web";
26696
- p4.intro("Gurulu uninstall");
26697
- p4.note([
26792
+ p5.intro("Gurulu uninstall");
26793
+ p5.note([
26698
26794
  `• SDK kaldır: ${pkg} (${detected.packageManager})`,
26699
26795
  `• env temizle: ${ENV_FILES.join(", ")} (GURULU_* anahtarları)`,
26700
26796
  "• .gurulu/ dizinini sil"
26701
26797
  ].join(`
26702
26798
  `), "Şunlar yapılacak");
26703
26799
  if (!args.yes) {
26704
- const ok = await p4.confirm({ message: "Devam edilsin mi?" });
26705
- if (p4.isCancel(ok) || !ok) {
26706
- p4.cancel("İptal.");
26800
+ const ok = await p5.confirm({ message: "Devam edilsin mi?" });
26801
+ if (p5.isCancel(ok) || !ok) {
26802
+ p5.cancel("İptal.");
26707
26803
  process.exit(0);
26708
26804
  }
26709
26805
  }
26710
26806
  if (!args["no-deps"] && detected.hasPackageJson) {
26711
26807
  const { bin, args: a2 } = removeCmd(detected.packageManager, pkg);
26712
- const s2 = p4.spinner();
26808
+ const s2 = p5.spinner();
26713
26809
  s2.start(`${pkg} kaldırılıyor…`);
26714
26810
  try {
26715
26811
  await pexec2(bin, a2, { cwd, timeout: 120000 });
@@ -26732,7 +26828,7 @@ var uninstallCmd = defineCommand({
26732
26828
  const guruluDir = join10(cwd, ".gurulu");
26733
26829
  if (existsSync11(guruluDir))
26734
26830
  rmSync(guruluDir, { recursive: true, force: true });
26735
- p4.outro(`Kaldırıldı. env: ${cleaned.join(", ") || "değişiklik yok"} · .gurulu silindi. (Koddaki init/track çağrılarını elle çıkar.)`);
26831
+ p5.outro(`Kaldırıldı. env: ${cleaned.join(", ") || "değişiklik yok"} · .gurulu silindi. (Koddaki init/track çağrılarını elle çıkar.)`);
26736
26832
  }
26737
26833
  });
26738
26834
 
@@ -1,5 +1,6 @@
1
1
  export type Framework = 'next' | 'react' | 'vue' | 'nuxt' | 'svelte' | 'astro' | 'vite' | 'express' | 'fastify' | 'hono' | 'koa' | 'node-server' | 'unknown';
2
2
  export type Runtime = 'browser' | 'node' | 'unknown';
3
+ export type LlmFramework = 'openai' | 'anthropic' | 'langchain' | 'google-genai' | 'vercel-ai' | 'cohere' | 'mistral' | 'ollama';
3
4
  export type PackageManager = 'bun' | 'pnpm' | 'yarn' | 'npm';
4
5
  export interface DetectedProject {
5
6
  dir: string;
@@ -8,6 +9,8 @@ export interface DetectedProject {
8
9
  runtime: Runtime;
9
10
  packageManager: PackageManager;
10
11
  packageJson: PackageJsonShape | null;
12
+ /** M46 (K31) — tespit edilen LLM/AI bağımlılıkları (boş = yok). */
13
+ llmFrameworks: LlmFramework[];
11
14
  }
12
15
  interface PackageJsonShape {
13
16
  name?: string;
@@ -22,6 +25,8 @@ interface PackageJsonShape {
22
25
  export declare function detectPackageManager(dir: string): PackageManager;
23
26
  export declare function detectFramework(pkg: PackageJsonShape | null, dir: string): Framework;
24
27
  export declare function frameworkRuntime(fw: Framework): Runtime;
28
+ /** package.json dependencies içinde LLM/AI SDK'larını tespit eder (dedup). */
29
+ export declare function detectLlmFrameworks(pkg: PackageJsonShape | null): LlmFramework[];
25
30
  export declare function detectProject(dir: string): DetectedProject;
26
31
  export {};
27
32
  //# sourceMappingURL=detect.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../src/lib/detect.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,OAAO,GACP,KAAK,GACL,MAAM,GACN,QAAQ,GACR,OAAO,GACP,MAAM,GACN,SAAS,GACT,SAAS,GACT,MAAM,GACN,KAAK,GACL,aAAa,GACb,SAAS,CAAC;AAEd,MAAM,MAAM,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;AAErD,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAE7D,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,cAAc,CAAC;IAC/B,WAAW,EAAE,gBAAgB,GAAG,IAAI,CAAC;CACtC;AAED,UAAU,gBAAgB;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAiBD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAchE;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAkBpF;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO,CAmBvD;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAW1D"}
1
+ {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../src/lib/detect.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,OAAO,GACP,KAAK,GACL,MAAM,GACN,QAAQ,GACR,OAAO,GACP,MAAM,GACN,SAAS,GACT,SAAS,GACT,MAAM,GACN,KAAK,GACL,aAAa,GACb,SAAS,CAAC;AAEd,MAAM,MAAM,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;AAGrD,MAAM,MAAM,YAAY,GACpB,QAAQ,GACR,WAAW,GACX,WAAW,GACX,cAAc,GACd,WAAW,GACX,QAAQ,GACR,SAAS,GACT,QAAQ,CAAC;AAeb,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAE7D,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,cAAc,CAAC;IAC/B,WAAW,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACrC,mEAAmE;IACnE,aAAa,EAAE,YAAY,EAAE,CAAC;CAC/B;AAED,UAAU,gBAAgB;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAiBD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAchE;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAmBpF;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO,CAmBvD;AAED,8EAA8E;AAC9E,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI,GAAG,YAAY,EAAE,CAMhF;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAY1D"}
@@ -1,6 +1,17 @@
1
1
  // src/lib/detect.ts
2
2
  import { existsSync, readFileSync } from "node:fs";
3
3
  import { dirname, join, parse } from "node:path";
4
+ var LLM_DEP_MAP = {
5
+ openai: "openai",
6
+ "@anthropic-ai/sdk": "anthropic",
7
+ "@langchain/core": "langchain",
8
+ langchain: "langchain",
9
+ "@google/generative-ai": "google-genai",
10
+ ai: "vercel-ai",
11
+ "cohere-ai": "cohere",
12
+ "@mistralai/mistralai": "mistral",
13
+ ollama: "ollama"
14
+ };
4
15
  function readPackageJson(dir) {
5
16
  const p = join(dir, "package.json");
6
17
  if (!existsSync(p))
@@ -86,6 +97,14 @@ function frameworkRuntime(fw) {
86
97
  return "unknown";
87
98
  }
88
99
  }
100
+ function detectLlmFrameworks(pkg) {
101
+ const found = new Set;
102
+ for (const [dep, fw] of Object.entries(LLM_DEP_MAP)) {
103
+ if (hasDep(pkg, dep))
104
+ found.add(fw);
105
+ }
106
+ return [...found];
107
+ }
89
108
  function detectProject(dir) {
90
109
  const pkg = readPackageJson(dir);
91
110
  const framework = detectFramework(pkg, dir);
@@ -95,12 +114,14 @@ function detectProject(dir) {
95
114
  framework,
96
115
  runtime: frameworkRuntime(framework),
97
116
  packageManager: detectPackageManager(dir),
98
- packageJson: pkg
117
+ packageJson: pkg,
118
+ llmFrameworks: detectLlmFrameworks(pkg)
99
119
  };
100
120
  }
101
121
  export {
102
122
  frameworkRuntime,
103
123
  detectProject,
104
124
  detectPackageManager,
125
+ detectLlmFrameworks,
105
126
  detectFramework
106
127
  };
@@ -0,0 +1,28 @@
1
+ import type { ApiClient } from '../lib/api.ts';
2
+ import { type DetectedProject } from '../lib/detect.ts';
3
+ export type FeatureKey = 'error' | 'llm' | 'activation';
4
+ export interface FeatureOption {
5
+ key: FeatureKey;
6
+ label: string;
7
+ /** multiselect hint (kısa). */
8
+ detail: string;
9
+ /** kurulumdan sonra gösterilen "nasıl açılır" snippet'i. */
10
+ enableHint: string;
11
+ /** öneri (pre-checked). */
12
+ recommended: boolean;
13
+ }
14
+ /** Tespite göre kurulabilir özellikler. */
15
+ export declare function availableFeatures(detected: DetectedProject): FeatureOption[];
16
+ export interface FeaturesResult {
17
+ selected: FeatureOption[];
18
+ registered: boolean;
19
+ }
20
+ /**
21
+ * Özellikleri sun + seç + gateway'e kaydet. authed değilse atlar (registration
22
+ * apiKey gerektirir). `--yes` → önerilenler otomatik.
23
+ */
24
+ export declare function runFeatures(client: ApiClient, detected: DetectedProject, opts: {
25
+ yes?: boolean;
26
+ authed: boolean;
27
+ }): Promise<FeaturesResult>;
28
+ //# sourceMappingURL=features.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features.d.ts","sourceRoot":"","sources":["../../src/wizard/features.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,KAAK,eAAe,EAAoB,MAAM,kBAAkB,CAAC;AAG1E,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,KAAK,GAAG,YAAY,CAAC;AAExD,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,UAAU,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,UAAU,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,2CAA2C;AAC3C,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,eAAe,GAAG,aAAa,EAAE,CAsC5E;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,SAAS,EACjB,QAAQ,EAAE,eAAe,EACzB,IAAI,EAAE;IAAE,GAAG,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GACvC,OAAO,CAAC,cAAc,CAAC,CAqCzB"}
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/wizard/run.ts"],"names":[],"mappings":"AAgCA,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,4CAA4C;IAC5C,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAsBD,wBAAsB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAwNlE"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/wizard/run.ts"],"names":[],"mappings":"AAiCA,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,4CAA4C;IAC5C,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAsBD,wBAAsB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAkOlE"}
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@gurulu/cli",
3
- "version": "1.2.2",
3
+ "version": "1.3.0",
4
4
  "private": false,
5
5
  "license": "BUSL-1.1",
6
6
  "publishConfig": {
7
7
  "access": "public"
8
8
  },
9
9
  "type": "module",
10
- "description": "Gurulu CLI. init / pull / push / validate / doctor registry as code, local schema sync.",
10
+ "description": "Gurulu CLI. init / pull / push / validate / doctor \u2014 registry as code, local schema sync.",
11
11
  "homepage": "https://gurulu.io",
12
12
  "repository": {
13
13
  "type": "git",