@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 +207 -79
- package/dist/index.js +207 -79
- package/dist/lib/detect.d.ts +5 -0
- package/dist/lib/detect.d.ts.map +1 -1
- package/dist/lib/detect.js +22 -1
- package/dist/lib/install-plan.d.ts +6 -0
- package/dist/lib/install-plan.d.ts.map +1 -1
- package/dist/lib/install-plan.js +12 -8
- package/dist/wizard/agent.d.ts +2 -2
- package/dist/wizard/agent.d.ts.map +1 -1
- package/dist/wizard/features.d.ts +28 -0
- package/dist/wizard/features.d.ts.map +1 -0
- package/dist/wizard/run.d.ts.map +1 -1
- package/dist/wizard/wire.d.ts +2 -0
- package/dist/wizard/wire.d.ts.map +1 -1
- package/package.json +2 -2
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
|
|
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
|
|
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/
|
|
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
|
-
|
|
26275
|
+
p3.note(formatPlan(plan), plan.summary);
|
|
26183
26276
|
const newCount = plan.events.filter((e2) => !e2.existing).length;
|
|
26184
|
-
const ok = await
|
|
26277
|
+
const ok = await p3.confirm({
|
|
26185
26278
|
message: `${plan.events.length} event (${newCount} yeni) — bu planı uygula?`
|
|
26186
26279
|
});
|
|
26187
|
-
if (
|
|
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(
|
|
26203
|
-
return isAbsolute(
|
|
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(
|
|
26281
|
-
const abs = isAbsolute(
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
26412
|
-
|
|
26413
|
-
|
|
26414
|
-
|
|
26415
|
-
|
|
26416
|
-
|
|
26417
|
-
|
|
26418
|
-
|
|
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
|
-
{
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
26672
|
+
const ok = await p4.confirm({
|
|
26572
26673
|
message: `Saptanan: ${detected.framework} (${detected.packageManager}). Doğru mu?`
|
|
26573
26674
|
});
|
|
26574
|
-
if (
|
|
26675
|
+
if (p4.isCancel(ok))
|
|
26575
26676
|
bail();
|
|
26576
26677
|
if (!ok) {
|
|
26577
|
-
const choice = await
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
26718
|
+
p4.log.info(`SDK kurulumu atlandı — elle: ${plan.installCommand}`);
|
|
26609
26719
|
} else if (!detected.hasPackageJson) {
|
|
26610
|
-
|
|
26720
|
+
p4.log.warn("package.json yok — script tag ile kur: https://cdn.gurulu.io/t.js");
|
|
26611
26721
|
} else {
|
|
26612
|
-
const s2 =
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
26784
|
+
const hasWireWork = approvedEvents.length > 0 || extraTasks.length > 0;
|
|
26785
|
+
if (hasWireWork) {
|
|
26667
26786
|
if (opts.noAi) {
|
|
26668
|
-
|
|
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 =
|
|
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
|
-
|
|
26679
|
-
const keep = opts.yes ? true : await
|
|
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 (
|
|
26803
|
+
if (p4.isCancel(keep) || !keep) {
|
|
26683
26804
|
restoreSnapshots(opts.cwd, snapshots);
|
|
26684
|
-
|
|
26685
|
-
|
|
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
|
-
|
|
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
|
-
|
|
26707
|
-
|
|
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
|
-
|
|
26838
|
+
p4.note(lines.join(`
|
|
26711
26839
|
`), c3.neon("✦ Değişiklikler"));
|
|
26712
26840
|
if (inj.strategy !== "prepend-entry" || inj.reason === "no-entry") {
|
|
26713
|
-
|
|
26841
|
+
p4.log.info(`Wire: ${inj.wireHint ?? plan.placementHint}`);
|
|
26714
26842
|
if (inj.strategy === "manual")
|
|
26715
|
-
|
|
26843
|
+
p4.log.message(plan.initSnippet);
|
|
26716
26844
|
}
|
|
26717
|
-
|
|
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
|
|
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 (
|
|
26876
|
+
if (p4.isCancel(choice))
|
|
26749
26877
|
bail();
|
|
26750
26878
|
selected = choice;
|
|
26751
26879
|
}
|
|
26752
26880
|
if (selected === CREATE) {
|
|
26753
|
-
const name = await
|
|
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 (
|
|
26886
|
+
if (p4.isCancel(name))
|
|
26759
26887
|
bail();
|
|
26760
|
-
const domain = await
|
|
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 (
|
|
26893
|
+
if (p4.isCancel(domain))
|
|
26766
26894
|
bail();
|
|
26767
|
-
const s2 =
|
|
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
|
|
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
|
-
|
|
27120
|
-
|
|
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
|
|
27128
|
-
if (
|
|
27129
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
|