@gurulu/cli 1.2.2 → 1.4.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
 
@@ -25690,15 +25710,19 @@ function sdkFor(framework) {
25690
25710
  return "@gurulu/web";
25691
25711
  }
25692
25712
  }
25693
- function snippetWeb(workspaceKey) {
25713
+ function autocaptureLine(jsError, indent) {
25714
+ return jsError ? `
25715
+ ${indent}autocapture: { js_error: true }, // hata takibi açık` : "";
25716
+ }
25717
+ function snippetWeb(workspaceKey, jsError = false) {
25694
25718
  return `import gurulu from '@gurulu/web';
25695
25719
 
25696
25720
  gurulu.init({
25697
25721
  workspaceKey: process.env.NEXT_PUBLIC_GURULU_WORKSPACE ?? '${workspaceKey}',
25698
- endpoint: process.env.NEXT_PUBLIC_GURULU_ENDPOINT, // optional, defaults to https://ingest.gurulu.io
25722
+ endpoint: process.env.NEXT_PUBLIC_GURULU_ENDPOINT, // optional, defaults to https://ingest.gurulu.io${autocaptureLine(jsError, " ")}
25699
25723
  });`;
25700
25724
  }
25701
- function snippetNext(workspaceKey) {
25725
+ function snippetNext(workspaceKey, jsError = false) {
25702
25726
  return `// src/app/gurulu-provider.tsx
25703
25727
  'use client';
25704
25728
  import { useEffect } from 'react';
@@ -25708,7 +25732,7 @@ export function GuruluProvider({ children }: { children: React.ReactNode }) {
25708
25732
  useEffect(() => {
25709
25733
  gurulu.init({
25710
25734
  workspaceKey: process.env.NEXT_PUBLIC_GURULU_WORKSPACE ?? '${workspaceKey}',
25711
- endpoint: process.env.NEXT_PUBLIC_GURULU_ENDPOINT,
25735
+ endpoint: process.env.NEXT_PUBLIC_GURULU_ENDPOINT,${autocaptureLine(jsError, " ")}
25712
25736
  });
25713
25737
  }, []);
25714
25738
  return <>{children}</>;
@@ -25787,7 +25811,7 @@ function placementHintFor(framework) {
25787
25811
  return "Initialize the SDK at your app entry point.";
25788
25812
  }
25789
25813
  }
25790
- function initSnippetFor(framework, sdk, workspaceKey) {
25814
+ function initSnippetFor(framework, sdk, workspaceKey, jsError = false) {
25791
25815
  if (sdk === "@gurulu/node") {
25792
25816
  if (framework === "express")
25793
25817
  return snippetExpress();
@@ -25796,8 +25820,8 @@ function initSnippetFor(framework, sdk, workspaceKey) {
25796
25820
  return snippetNode();
25797
25821
  }
25798
25822
  if (framework === "next")
25799
- return snippetNext(workspaceKey);
25800
- return snippetWeb(workspaceKey);
25823
+ return snippetNext(workspaceKey, jsError);
25824
+ return snippetWeb(workspaceKey, jsError);
25801
25825
  }
25802
25826
  function envKeysFor(sdk, framework) {
25803
25827
  if (sdk === "@gurulu/node") {
@@ -25823,7 +25847,7 @@ function buildInstallPlan(detected, ctx = {}) {
25823
25847
  sdk,
25824
25848
  packageManager: detected.packageManager,
25825
25849
  installCommand: installCmdFor(detected.packageManager, sdk),
25826
- initSnippet: initSnippetFor(detected.framework, sdk, workspaceKey),
25850
+ initSnippet: initSnippetFor(detected.framework, sdk, workspaceKey, ctx.autocaptureJsError),
25827
25851
  envKeys: envKeysFor(sdk, detected.framework),
25828
25852
  placementHint: placementHintFor(detected.framework),
25829
25853
  framework: detected.framework
@@ -26133,8 +26157,77 @@ function gatherContext(opts) {
26133
26157
  return { files, capped, totalBytes };
26134
26158
  }
26135
26159
 
26136
- // src/wizard/plan.ts
26160
+ // src/wizard/features.ts
26137
26161
  import * as p2 from "@clack/prompts";
26162
+ function availableFeatures(detected) {
26163
+ const isBrowser = frameworkRuntime(detected.framework) !== "node";
26164
+ const feats = [];
26165
+ feats.push({
26166
+ key: "error",
26167
+ label: "Hata takibi",
26168
+ detail: "Tarayıcı JS hatalarını otomatik yakala (js_error)",
26169
+ enableHint: isBrowser ? "gurulu.init({ ..., autocapture: { js_error: true } })" : "Sunucu hatalarında: gurulu.track('js_error', { message, error_type })",
26170
+ recommended: isBrowser
26171
+ });
26172
+ if (detected.llmFrameworks.length > 0) {
26173
+ feats.push({
26174
+ key: "llm",
26175
+ label: `LLM analizi (${detected.llmFrameworks.join(", ")} tespit edildi)`,
26176
+ detail: "AI çağrı maliyeti/latency/hata/model performansı",
26177
+ enableHint: "import { wrapOpenAI } from '@gurulu/node'; const client = wrapOpenAI(openai);",
26178
+ recommended: true
26179
+ });
26180
+ }
26181
+ if (isBrowser) {
26182
+ feats.push({
26183
+ key: "activation",
26184
+ label: "Activation (popup · tur · A/B test · kişiselleştirme)",
26185
+ detail: "Dashboard'dan yayınla, SDK render etsin (Action Layer)",
26186
+ enableHint: "import { runActivation } from '@gurulu/web/activate'; runActivation(gurulu);",
26187
+ recommended: false
26188
+ });
26189
+ }
26190
+ return feats;
26191
+ }
26192
+ async function runFeatures(client, detected, opts) {
26193
+ const avail = availableFeatures(detected);
26194
+ if (avail.length === 0 || !opts.authed)
26195
+ return { selected: [], registered: false };
26196
+ let selectedKeys;
26197
+ if (opts.yes) {
26198
+ selectedKeys = avail.filter((f3) => f3.recommended).map((f3) => f3.key);
26199
+ } else {
26200
+ const choice = await p2.multiselect({
26201
+ message: "Hangi özellikleri kuralım? (event'ler registry'ye otomatik eklenir)",
26202
+ options: avail.map((f3) => ({ value: f3.key, label: f3.label, hint: f3.detail })),
26203
+ initialValues: avail.filter((f3) => f3.recommended).map((f3) => f3.key),
26204
+ required: false
26205
+ });
26206
+ if (p2.isCancel(choice))
26207
+ return { selected: [], registered: false };
26208
+ selectedKeys = choice;
26209
+ }
26210
+ if (selectedKeys.length === 0)
26211
+ return { selected: [], registered: false };
26212
+ const selected = avail.filter((f3) => selectedKeys.includes(f3.key));
26213
+ const s2 = p2.spinner();
26214
+ s2.start("Özellikler registry'ye kuruluyor…");
26215
+ try {
26216
+ await client.post("/features/register", { features: selectedKeys });
26217
+ s2.stop(c3.neon(`✓ ${selected.length} özellik kuruldu`));
26218
+ } catch {
26219
+ s2.stop("Özellik kurulumu atlandı (gateway hatası) — sonra: gurulu doctor", 1);
26220
+ return { selected, registered: false };
26221
+ }
26222
+ p2.note(selected.map((f3) => `${c3.bold(f3.label)}
26223
+ ${c3.dim(f3.enableHint)}`).join(`
26224
+
26225
+ `), "Etkinleştirme");
26226
+ return { selected, registered: true };
26227
+ }
26228
+
26229
+ // src/wizard/plan.ts
26230
+ import * as p3 from "@clack/prompts";
26138
26231
  async function fetchPlan(client, context, input) {
26139
26232
  if (context.files.length === 0)
26140
26233
  return null;
@@ -26179,12 +26272,12 @@ function formatPlan(plan) {
26179
26272
  `).trimEnd();
26180
26273
  }
26181
26274
  async function renderPlan(plan) {
26182
- p2.note(formatPlan(plan), plan.summary);
26275
+ p3.note(formatPlan(plan), plan.summary);
26183
26276
  const newCount = plan.events.filter((e2) => !e2.existing).length;
26184
- const ok = await p2.confirm({
26277
+ const ok = await p3.confirm({
26185
26278
  message: `${plan.events.length} event (${newCount} yeni) — bu planı uygula?`
26186
26279
  });
26187
- if (p2.isCancel(ok) || !ok)
26280
+ if (p3.isCancel(ok) || !ok)
26188
26281
  return null;
26189
26282
  return plan.events;
26190
26283
  }
@@ -26199,8 +26292,8 @@ import { promisify } from "node:util";
26199
26292
 
26200
26293
  // src/wizard/guard.ts
26201
26294
  import { basename, isAbsolute, relative as relative2, resolve } from "node:path";
26202
- function resolveInCwd(p3, cwd) {
26203
- return isAbsolute(p3) ? p3 : resolve(cwd, p3);
26295
+ function resolveInCwd(p4, cwd) {
26296
+ return isAbsolute(p4) ? p4 : resolve(cwd, p4);
26204
26297
  }
26205
26298
  function isAdditiveEdit(find, replace) {
26206
26299
  if (find.length === 0)
@@ -26277,8 +26370,8 @@ function isAllowedBash(cmd) {
26277
26370
  }
26278
26371
  return { ok: false, reason: `allowlist dışı binary: ${bin}` };
26279
26372
  }
26280
- function isAllowedPath(p3, cwd) {
26281
- const abs = isAbsolute(p3) ? p3 : resolve(cwd, p3);
26373
+ function isAllowedPath(p4, cwd) {
26374
+ const abs = isAbsolute(p4) ? p4 : resolve(cwd, p4);
26282
26375
  const rel = relative2(cwd, abs);
26283
26376
  if (rel === "" || rel.startsWith("..") || isAbsolute(rel)) {
26284
26377
  return { ok: false, reason: "cwd dışı yol" };
@@ -26389,11 +26482,14 @@ ${stderr}`.trim().slice(0, MAX_OBS);
26389
26482
  }
26390
26483
  function buildWireSystemPrompt() {
26391
26484
  return [
26392
- "You are Gurulu's capture wire agent. Add the approved analytics events to the user's code.",
26485
+ "You are Gurulu's capture wire agent. Add the approved analytics events to the user's code,",
26486
+ "plus any additional wiring tasks given (e.g. wrapping an LLM client, mounting a provider).",
26393
26487
  "Tools (one JSON action per turn): read{path} | edit{path,find,replace} | bash{cmd} | done{summary}.",
26394
26488
  "HARD RULES:",
26395
26489
  "- ADDITIVE-ONLY: every edit `replace` MUST contain `find` verbatim — you may only ADD code,",
26396
- " never delete or rewrite existing code. Edits violating this are rejected.",
26490
+ ' never delete or rewrite existing code. Edits violating this are rejected. To "wrap" an existing',
26491
+ " expression, keep the original verbatim inside the new wrapper (e.g. find `new OpenAI(cfg)` →",
26492
+ " replace `wrapOpenAI(new OpenAI(cfg))`), and add the import additively.",
26397
26493
  "- `find` must be an EXACT, UNIQUE snippet copied from a file you have read (read before edit).",
26398
26494
  "- Use the exact provided event_key (snake_case). Wire gurulu.track(...) at the right place and",
26399
26495
  " gurulu.identify(...) at the auth point if given.",
@@ -26401,21 +26497,23 @@ function buildWireSystemPrompt() {
26401
26497
  " `pnpm run lint`) or a checker binary (`tsc --noEmit`, `biome check`, `eslint .`). Installing or",
26402
26498
  " fetching packages (`npm install`, `npx`, `bunx`, `pnpm dlx`, `add`, `exec`) is REJECTED by the guard.",
26403
26499
  "- After wiring, run the project typecheck/build to verify; if it breaks, fix additively.",
26404
- "- When all events are wired and verify passes, emit done{summary}. Keep edits minimal."
26500
+ "- When all events AND additional tasks are done and verify passes, emit done{summary}. Keep edits minimal."
26405
26501
  ].join(`
26406
26502
  `);
26407
26503
  }
26408
- function buildWireUserPrompt(events, identifyHint, files) {
26409
- const evLines = events.map((e2) => `- ${e2.event_key} (${e2.event_type})${e2.capture_hint ? ` @ ${e2.capture_hint}` : ""}: ${e2.reason}`).join(`
26504
+ function buildWireUserPrompt(events, identifyHint, files, extraTasks = []) {
26505
+ const sections = [];
26506
+ if (events.length > 0) {
26507
+ const evLines = events.map((e2) => `- ${e2.event_key} (${e2.event_type})${e2.capture_hint ? ` @ ${e2.capture_hint}` : ""}: ${e2.reason}`).join(`
26410
26508
  `);
26411
- return [
26412
- "Wire these events into the codebase:",
26413
- evLines,
26414
- identifyHint ? `identify() at: ${identifyHint}` : "No identify hint.",
26415
- "",
26416
- `Project files (read the relevant ones): ${files.join(", ")}`,
26417
- "Start by reading the files you need, then edit additively."
26418
- ].join(`
26509
+ sections.push("Wire these events into the codebase:", evLines, identifyHint ? `identify() at: ${identifyHint}` : "No identify hint.");
26510
+ }
26511
+ if (extraTasks.length > 0) {
26512
+ sections.push("Additional wiring tasks:", extraTasks.map((t2, i2) => `${i2 + 1}. ${t2}`).join(`
26513
+ `));
26514
+ }
26515
+ sections.push("", `Project files (read the relevant ones): ${files.join(", ")}`, "Start by reading the files you need, then edit additively.");
26516
+ return sections.join(`
26419
26517
  `);
26420
26518
  }
26421
26519
 
@@ -26424,7 +26522,10 @@ var MAX_STEPS = 25;
26424
26522
  async function runWireAgent(client, input, snapshots) {
26425
26523
  const messages = [
26426
26524
  { role: "system", content: buildWireSystemPrompt() },
26427
- { role: "user", content: buildWireUserPrompt(input.events, input.identifyHint, input.files) }
26525
+ {
26526
+ role: "user",
26527
+ content: buildWireUserPrompt(input.events, input.identifyHint, input.files, input.extraTasks ?? [])
26528
+ }
26428
26529
  ];
26429
26530
  const edits = [];
26430
26531
  const changed = new Set;
@@ -26542,16 +26643,16 @@ var FRAMEWORKS = [
26542
26643
  "node-server"
26543
26644
  ];
26544
26645
  function bail() {
26545
- p3.cancel("İptal edildi.");
26646
+ p4.cancel("İptal edildi.");
26546
26647
  process.exit(0);
26547
26648
  }
26548
26649
  async function runWizard(opts) {
26549
26650
  if (process.stdout.isTTY)
26550
26651
  process.stdout.write(banner());
26551
- p3.intro(c3.dim("otonom kurulum başlıyor — auth → workspace → install → wire"));
26652
+ p4.intro(c3.dim("otonom kurulum başlıyor — auth → workspace → install → wire"));
26552
26653
  const TOTAL = 6;
26553
26654
  const phase = (n2, label) => {
26554
- p3.log.step(`${c3.dim(`[${n2}/${TOTAL}]`)} ${c3.bold(label)}`);
26655
+ p4.log.step(`${c3.dim(`[${n2}/${TOTAL}]`)} ${c3.bold(label)}`);
26555
26656
  };
26556
26657
  phase(1, "Kimlik doğrulama");
26557
26658
  const auth = await ensureAuth({
@@ -26568,25 +26669,23 @@ async function runWizard(opts) {
26568
26669
  if (opts.framework && FRAMEWORKS.includes(opts.framework)) {
26569
26670
  framework = opts.framework;
26570
26671
  } else if (!opts.yes) {
26571
- const ok = await p3.confirm({
26672
+ const ok = await p4.confirm({
26572
26673
  message: `Saptanan: ${detected.framework} (${detected.packageManager}). Doğru mu?`
26573
26674
  });
26574
- if (p3.isCancel(ok))
26675
+ if (p4.isCancel(ok))
26575
26676
  bail();
26576
26677
  if (!ok) {
26577
- const choice = await p3.select({
26678
+ const choice = await p4.select({
26578
26679
  message: "Framework seç",
26579
26680
  options: FRAMEWORKS.map((f3) => ({ value: f3, label: f3 })),
26580
26681
  initialValue: detected.framework
26581
26682
  });
26582
- if (p3.isCancel(choice))
26683
+ if (p4.isCancel(choice))
26583
26684
  bail();
26584
26685
  framework = choice;
26585
26686
  }
26586
26687
  }
26587
26688
  const project = { ...detected, framework };
26588
- const plan = buildInstallPlan(project, { writeKey, workspaceId });
26589
- const isNode = plan.sdk === "@gurulu/node";
26590
26689
  const authed = Boolean(auth.apiKey);
26591
26690
  let approvedEvents = [];
26592
26691
  let identifyHint = null;
@@ -26599,17 +26698,28 @@ async function runWizard(opts) {
26599
26698
  if (approved)
26600
26699
  approvedEvents = approved;
26601
26700
  } else {
26602
- p3.log.info("AI planı yok — autocapture + sektör paketi (deterministik floor).");
26701
+ p4.log.info("AI planı yok — autocapture + sektör paketi (deterministik floor).");
26603
26702
  }
26604
26703
  }
26704
+ let featuresResult = { selected: [], registered: false };
26705
+ if (authed) {
26706
+ featuresResult = await runFeatures(client, project, { yes: opts.yes, authed });
26707
+ }
26708
+ const errorSelected = featuresResult.selected.some((f3) => f3.key === "error");
26709
+ const plan = buildInstallPlan(project, {
26710
+ writeKey,
26711
+ workspaceId,
26712
+ autocaptureJsError: errorSelected
26713
+ });
26714
+ const isNode = plan.sdk === "@gurulu/node";
26605
26715
  phase(4, "SDK kurulumu");
26606
26716
  let installed = false;
26607
26717
  if (opts.noInstall) {
26608
- p3.log.info(`SDK kurulumu atlandı — elle: ${plan.installCommand}`);
26718
+ p4.log.info(`SDK kurulumu atlandı — elle: ${plan.installCommand}`);
26609
26719
  } else if (!detected.hasPackageJson) {
26610
- p3.log.warn("package.json yok — script tag ile kur: https://cdn.gurulu.io/t.js");
26720
+ p4.log.warn("package.json yok — script tag ile kur: https://cdn.gurulu.io/t.js");
26611
26721
  } else {
26612
- const s2 = p3.spinner();
26722
+ const s2 = p4.spinner();
26613
26723
  s2.start(`${plan.sdk} kuruluyor (${plan.installCommand})…`);
26614
26724
  const res = await execInstall(plan, { cwd: opts.cwd });
26615
26725
  if (res.ok) {
@@ -26627,6 +26737,14 @@ async function runWizard(opts) {
26627
26737
  snippet: plan.initSnippet,
26628
26738
  placementHint: plan.placementHint
26629
26739
  });
26740
+ const extraTasks = [];
26741
+ const llmSelected = featuresResult.selected.some((f3) => f3.key === "llm");
26742
+ if (llmSelected && detected.llmFrameworks.length > 0) {
26743
+ extraTasks.push(`Wrap the project's LLM client(s) [${detected.llmFrameworks.join(", ")}] with @gurulu/node so ` + "every call is auto-captured. Find where the OpenAI/Anthropic client is instantiated and wrap " + "it in place additively: `import { wrapOpenAI } from '@gurulu/node';` then " + "`const client = wrapOpenAI(new OpenAI({...}))` (use wrapAnthropic for Anthropic SDK). " + "Keep the original instantiation verbatim inside the wrapper.");
26744
+ }
26745
+ if (inj.strategy === "create-module" && inj.file && (project.framework === "next" || project.framework === "nuxt")) {
26746
+ extraTasks.push(project.framework === "next" ? `Mount the Gurulu provider created at \`${inj.file}\` into the app root. Edit app/layout.tsx ` + "(App Router) or pages/_app.tsx (Pages Router) to import { GuruluProvider } from that module " + "and wrap the children additively: `<GuruluProvider>{children}</GuruluProvider>`." : `Register the Nuxt plugin created at \`${inj.file}\` so it loads on the client. If it is under ` + "plugins/ Nuxt auto-registers it; otherwise add it to the plugins array in nuxt.config.ts additively.");
26747
+ }
26630
26748
  const envFile = isNode ? ".env" : ".env.local";
26631
26749
  const vars = [];
26632
26750
  for (const k2 of plan.envKeys) {
@@ -26636,7 +26754,7 @@ async function runWizard(opts) {
26636
26754
  if (auth.apiKey.startsWith("sk_")) {
26637
26755
  vars.push({ key: k2.key, value: auth.apiKey });
26638
26756
  } 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.");
26757
+ 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
26758
  }
26641
26759
  }
26642
26760
  }
@@ -26656,38 +26774,45 @@ async function runWizard(opts) {
26656
26774
  }
26657
26775
  let registeredCount = 0;
26658
26776
  if (approvedEvents.length > 0) {
26659
- const s2 = p3.spinner();
26777
+ const s2 = p4.spinner();
26660
26778
  s2.start("Yeni eventler registry kuyruguna oneriliyor…");
26661
26779
  const res = await registerNewEvents(client, approvedEvents);
26662
26780
  registeredCount = res.registered.length;
26663
26781
  s2.stop(`${res.registered.length} yeni event verification queue'ya eklendi${res.failed.length > 0 ? ` (${res.failed.length} başarısız)` : ""}`);
26664
26782
  }
26665
26783
  let wiredCount = 0;
26666
- if (approvedEvents.length > 0) {
26784
+ const hasWireWork = approvedEvents.length > 0 || extraTasks.length > 0;
26785
+ if (hasWireWork) {
26667
26786
  if (opts.noAi) {
26668
- p3.log.message(`Capture şu çağrıları ekle:
26787
+ if (approvedEvents.length > 0) {
26788
+ p4.log.message(`Capture — şu çağrıları ekle:
26669
26789
  ${captureGuide(approvedEvents, identifyHint, isNode)}`);
26790
+ }
26670
26791
  } else {
26671
26792
  const wireFiles = gatherContext({ cwd: opts.cwd }).files.map((f3) => f3.path);
26672
26793
  const snapshots = new Map;
26673
- const s2 = p3.spinner();
26794
+ const s2 = p4.spinner();
26674
26795
  s2.start("AI capture wiring (kod düzenleniyor)…");
26675
- const outcome = await runWireAgent(client, { cwd: opts.cwd, events: approvedEvents, identifyHint, files: wireFiles }, snapshots);
26796
+ const outcome = await runWireAgent(client, { cwd: opts.cwd, events: approvedEvents, identifyHint, files: wireFiles, extraTasks }, snapshots);
26676
26797
  s2.stop(`wire: ${outcome.changedFiles.length} dosya / ${outcome.steps} adım (${outcome.stoppedReason})`);
26677
26798
  if (outcome.changedFiles.length > 0) {
26678
- p3.log.message(formatWireDiff(opts.cwd, snapshots));
26679
- const keep = opts.yes ? true : await p3.confirm({
26799
+ p4.log.message(formatWireDiff(opts.cwd, snapshots));
26800
+ const keep = opts.yes ? true : await p4.confirm({
26680
26801
  message: `${outcome.changedFiles.length} dosyadaki wire değişikliklerini tut?`
26681
26802
  });
26682
- if (p3.isCancel(keep) || !keep) {
26803
+ if (p4.isCancel(keep) || !keep) {
26683
26804
  restoreSnapshots(opts.cwd, snapshots);
26684
- p3.log.info("Wire geri alındı — capture snippet rehberi:");
26685
- p3.log.message(captureGuide(approvedEvents, identifyHint, isNode));
26805
+ if (approvedEvents.length > 0) {
26806
+ p4.log.info("Wire geri alındı — capture snippet rehberi:");
26807
+ p4.log.message(captureGuide(approvedEvents, identifyHint, isNode));
26808
+ } else {
26809
+ p4.log.info("Wire geri alındı — etkinleştirme snippet'leri yukarıda.");
26810
+ }
26686
26811
  } else {
26687
26812
  wiredCount = outcome.changedFiles.length;
26688
26813
  }
26689
- } else {
26690
- p3.log.message(`Capture (AI gömemedi → snippet-göster) — şu çağrıları ekle:
26814
+ } else if (approvedEvents.length > 0) {
26815
+ p4.log.message(`Capture (AI gömemedi → snippet-göster) — şu çağrıları ekle:
26691
26816
  ${captureGuide(approvedEvents, identifyHint, isNode)}`);
26692
26817
  }
26693
26818
  }
@@ -26703,18 +26828,21 @@ ${captureGuide(approvedEvents, identifyHint, isNode)}`);
26703
26828
  }
26704
26829
  if (approvedEvents.length > 0) {
26705
26830
  lines.push(`✓ ${approvedEvents.length} event planlandı, ${registeredCount} yeni registry kuyruğunda`);
26706
- if (wiredCount > 0)
26707
- lines.push(`✓ ${wiredCount} dosya AI ile capture wire edildi`);
26831
+ }
26832
+ if (wiredCount > 0)
26833
+ lines.push(`✓ ${wiredCount} dosya AI ile wire edildi (capture/LLM/provider)`);
26834
+ if (featuresResult.registered && featuresResult.selected.length > 0) {
26835
+ lines.push(`✓ özellikler: ${featuresResult.selected.map((f3) => f3.key).join(", ")} kuruldu`);
26708
26836
  }
26709
26837
  lines.push(`✓ .gurulu/config.json${pulled ? " + registry pull" : ""}`);
26710
- p3.note(lines.join(`
26838
+ p4.note(lines.join(`
26711
26839
  `), c3.neon("✦ Değişiklikler"));
26712
26840
  if (inj.strategy !== "prepend-entry" || inj.reason === "no-entry") {
26713
- p3.log.info(`Wire: ${inj.wireHint ?? plan.placementHint}`);
26841
+ p4.log.info(`Wire: ${inj.wireHint ?? plan.placementHint}`);
26714
26842
  if (inj.strategy === "manual")
26715
- p3.log.message(plan.initSnippet);
26843
+ p4.log.message(plan.initSnippet);
26716
26844
  }
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")}`);
26845
+ 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
26846
  }
26719
26847
  async function resolveWorkspace(client, authWorkspaceId, opts) {
26720
26848
  if (opts.writeKey) {
@@ -26737,7 +26865,7 @@ async function resolveWorkspace(client, authWorkspaceId, opts) {
26737
26865
  selected = CREATE;
26738
26866
  } else {
26739
26867
  const initial = list.find((w2) => w2.workspace_id === authWorkspaceId)?.workspace_id ?? list[0]?.workspace_id ?? CREATE;
26740
- const choice = await p3.select({
26868
+ const choice = await p4.select({
26741
26869
  message: "Workspace seç",
26742
26870
  options: [
26743
26871
  ...list.map((w2) => ({ value: w2.workspace_id, label: w2.name, hint: w2.slug })),
@@ -26745,26 +26873,26 @@ async function resolveWorkspace(client, authWorkspaceId, opts) {
26745
26873
  ],
26746
26874
  initialValue: initial
26747
26875
  });
26748
- if (p3.isCancel(choice))
26876
+ if (p4.isCancel(choice))
26749
26877
  bail();
26750
26878
  selected = choice;
26751
26879
  }
26752
26880
  if (selected === CREATE) {
26753
- const name = await p3.text({
26881
+ const name = await p4.text({
26754
26882
  message: "Workspace adı",
26755
26883
  placeholder: "My App",
26756
26884
  validate: (v2) => v2.trim() ? undefined : "gerekli"
26757
26885
  });
26758
- if (p3.isCancel(name))
26886
+ if (p4.isCancel(name))
26759
26887
  bail();
26760
- const domain = await p3.text({
26888
+ const domain = await p4.text({
26761
26889
  message: "Domain",
26762
26890
  placeholder: "example.com",
26763
26891
  validate: (v2) => v2.trim().length >= 3 ? undefined : "geçerli domain gerekli"
26764
26892
  });
26765
- if (p3.isCancel(domain))
26893
+ if (p4.isCancel(domain))
26766
26894
  bail();
26767
- const s2 = p3.spinner();
26895
+ const s2 = p4.spinner();
26768
26896
  s2.start("Workspace oluşturuluyor…");
26769
26897
  const created = await client.createWorkspace({
26770
26898
  name: String(name).trim(),
@@ -27089,7 +27217,7 @@ import { execFile as execFile2 } from "node:child_process";
27089
27217
  import { existsSync as existsSync11, readFileSync as readFileSync11, rmSync, writeFileSync as writeFileSync10 } from "node:fs";
27090
27218
  import { join as join10 } from "node:path";
27091
27219
  import { promisify as promisify2 } from "node:util";
27092
- import * as p4 from "@clack/prompts";
27220
+ import * as p5 from "@clack/prompts";
27093
27221
  var pexec2 = promisify2(execFile2);
27094
27222
  var ENV_FILES = [".env.local", ".env"];
27095
27223
  var GURULU_PREFIXES = ["GURULU_", "NEXT_PUBLIC_GURULU", "VITE_GURULU"];
@@ -27116,23 +27244,23 @@ var uninstallCmd = defineCommand({
27116
27244
  const config = readProjectConfig(cwd);
27117
27245
  const detected = detectProject(cwd);
27118
27246
  const pkg = config?.sdk_preference === "node" ? "@gurulu/node" : "@gurulu/web";
27119
- p4.intro("Gurulu uninstall");
27120
- p4.note([
27247
+ p5.intro("Gurulu uninstall");
27248
+ p5.note([
27121
27249
  `• SDK kaldır: ${pkg} (${detected.packageManager})`,
27122
27250
  `• env temizle: ${ENV_FILES.join(", ")} (GURULU_* anahtarları)`,
27123
27251
  "• .gurulu/ dizinini sil"
27124
27252
  ].join(`
27125
27253
  `), "Şunlar yapılacak");
27126
27254
  if (!args.yes) {
27127
- const ok = await p4.confirm({ message: "Devam edilsin mi?" });
27128
- if (p4.isCancel(ok) || !ok) {
27129
- p4.cancel("İptal.");
27255
+ const ok = await p5.confirm({ message: "Devam edilsin mi?" });
27256
+ if (p5.isCancel(ok) || !ok) {
27257
+ p5.cancel("İptal.");
27130
27258
  process.exit(0);
27131
27259
  }
27132
27260
  }
27133
27261
  if (!args["no-deps"] && detected.hasPackageJson) {
27134
27262
  const { bin, args: a2 } = removeCmd(detected.packageManager, pkg);
27135
- const s2 = p4.spinner();
27263
+ const s2 = p5.spinner();
27136
27264
  s2.start(`${pkg} kaldırılıyor…`);
27137
27265
  try {
27138
27266
  await pexec2(bin, a2, { cwd, timeout: 120000 });
@@ -27155,7 +27283,7 @@ var uninstallCmd = defineCommand({
27155
27283
  const guruluDir = join10(cwd, ".gurulu");
27156
27284
  if (existsSync11(guruluDir))
27157
27285
  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.)`);
27286
+ p5.outro(`Kaldırıldı. env: ${cleaned.join(", ") || "değişiklik yok"} · .gurulu silindi. (Koddaki init/track çağrılarını elle çıkar.)`);
27159
27287
  }
27160
27288
  });
27161
27289