@gurulu/cli 1.2.1 → 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 +290 -91
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +290 -91
- package/dist/lib/config.d.ts.map +1 -1
- 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/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/guard.d.ts +6 -1
- package/dist/wizard/guard.d.ts.map +1 -1
- package/dist/wizard/run.d.ts.map +1 -1
- package/dist/wizard/wire.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/bin.js
CHANGED
|
@@ -24529,7 +24529,7 @@ class ApiClient {
|
|
|
24529
24529
|
}
|
|
24530
24530
|
|
|
24531
24531
|
// src/lib/config.ts
|
|
24532
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
24532
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
24533
24533
|
import { homedir } from "node:os";
|
|
24534
24534
|
import { dirname, join } from "node:path";
|
|
24535
24535
|
var DEFAULT_ENDPOINT = process.env.GURULU_ENDPOINT ?? "https://api.gurulu.io";
|
|
@@ -24586,10 +24586,9 @@ function writeGlobalCredentials(creds) {
|
|
|
24586
24586
|
const path = globalCredentialsPath();
|
|
24587
24587
|
ensureDir(path);
|
|
24588
24588
|
writeFileSync(path, `${JSON.stringify(creds, null, 2)}
|
|
24589
|
-
`, "utf-8");
|
|
24589
|
+
`, { encoding: "utf-8", mode: 384 });
|
|
24590
24590
|
try {
|
|
24591
|
-
|
|
24592
|
-
fs.chmodSync(path, 384);
|
|
24591
|
+
chmodSync(path, 384);
|
|
24593
24592
|
} catch {}
|
|
24594
24593
|
}
|
|
24595
24594
|
function findCredentialForWorkspace(workspaceId) {
|
|
@@ -25119,7 +25118,7 @@ function sleep(ms) {
|
|
|
25119
25118
|
// src/wizard/run.ts
|
|
25120
25119
|
import { existsSync as existsSync9, mkdirSync as mkdirSync2, writeFileSync as writeFileSync8 } from "node:fs";
|
|
25121
25120
|
import { dirname as dirname3 } from "node:path";
|
|
25122
|
-
import * as
|
|
25121
|
+
import * as p4 from "@clack/prompts";
|
|
25123
25122
|
|
|
25124
25123
|
// src/commands/pull.ts
|
|
25125
25124
|
import { writeFileSync as writeFileSync3 } from "node:fs";
|
|
@@ -25263,6 +25262,17 @@ var pullCmd = defineCommand({
|
|
|
25263
25262
|
// src/lib/detect.ts
|
|
25264
25263
|
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
|
|
25265
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
|
+
};
|
|
25266
25276
|
function readPackageJson(dir) {
|
|
25267
25277
|
const p = join5(dir, "package.json");
|
|
25268
25278
|
if (!existsSync4(p))
|
|
@@ -25348,6 +25358,14 @@ function frameworkRuntime(fw) {
|
|
|
25348
25358
|
return "unknown";
|
|
25349
25359
|
}
|
|
25350
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
|
+
}
|
|
25351
25369
|
function detectProject(dir) {
|
|
25352
25370
|
const pkg = readPackageJson(dir);
|
|
25353
25371
|
const framework = detectFramework(pkg, dir);
|
|
@@ -25357,7 +25375,8 @@ function detectProject(dir) {
|
|
|
25357
25375
|
framework,
|
|
25358
25376
|
runtime: frameworkRuntime(framework),
|
|
25359
25377
|
packageManager: detectPackageManager(dir),
|
|
25360
|
-
packageJson: pkg
|
|
25378
|
+
packageJson: pkg,
|
|
25379
|
+
llmFrameworks: detectLlmFrameworks(pkg)
|
|
25361
25380
|
};
|
|
25362
25381
|
}
|
|
25363
25382
|
|
|
@@ -26134,8 +26153,77 @@ function gatherContext(opts) {
|
|
|
26134
26153
|
return { files, capped, totalBytes };
|
|
26135
26154
|
}
|
|
26136
26155
|
|
|
26137
|
-
// src/wizard/
|
|
26156
|
+
// src/wizard/features.ts
|
|
26138
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";
|
|
26139
26227
|
async function fetchPlan(client, context, input) {
|
|
26140
26228
|
if (context.files.length === 0)
|
|
26141
26229
|
return null;
|
|
@@ -26180,28 +26268,29 @@ function formatPlan(plan) {
|
|
|
26180
26268
|
`).trimEnd();
|
|
26181
26269
|
}
|
|
26182
26270
|
async function renderPlan(plan) {
|
|
26183
|
-
|
|
26271
|
+
p3.note(formatPlan(plan), plan.summary);
|
|
26184
26272
|
const newCount = plan.events.filter((e2) => !e2.existing).length;
|
|
26185
|
-
const ok = await
|
|
26273
|
+
const ok = await p3.confirm({
|
|
26186
26274
|
message: `${plan.events.length} event (${newCount} yeni) — bu planı uygula?`
|
|
26187
26275
|
});
|
|
26188
|
-
if (
|
|
26276
|
+
if (p3.isCancel(ok) || !ok)
|
|
26189
26277
|
return null;
|
|
26190
26278
|
return plan.events;
|
|
26191
26279
|
}
|
|
26192
26280
|
|
|
26193
26281
|
// src/wizard/wire.ts
|
|
26194
26282
|
import { existsSync as existsSync8, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "node:fs";
|
|
26195
|
-
import { join as join10 } from "node:path";
|
|
26196
26283
|
|
|
26197
26284
|
// src/wizard/agent.ts
|
|
26198
26285
|
import { execFile } from "node:child_process";
|
|
26199
26286
|
import { existsSync as existsSync7, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "node:fs";
|
|
26200
|
-
import { join as join9 } from "node:path";
|
|
26201
26287
|
import { promisify } from "node:util";
|
|
26202
26288
|
|
|
26203
26289
|
// src/wizard/guard.ts
|
|
26204
26290
|
import { basename, isAbsolute, relative as relative2, resolve } from "node:path";
|
|
26291
|
+
function resolveInCwd(p4, cwd) {
|
|
26292
|
+
return isAbsolute(p4) ? p4 : resolve(cwd, p4);
|
|
26293
|
+
}
|
|
26205
26294
|
function isAdditiveEdit(find, replace) {
|
|
26206
26295
|
if (find.length === 0)
|
|
26207
26296
|
return { ok: false, reason: "empty find" };
|
|
@@ -26212,22 +26301,45 @@ function isAdditiveEdit(find, replace) {
|
|
|
26212
26301
|
return { ok: false, reason: "no-op edit (replace === find)" };
|
|
26213
26302
|
return { ok: true };
|
|
26214
26303
|
}
|
|
26215
|
-
var
|
|
26216
|
-
"bun",
|
|
26217
|
-
"bunx",
|
|
26218
|
-
"npm",
|
|
26219
|
-
"npx",
|
|
26220
|
-
"pnpm",
|
|
26221
|
-
"yarn",
|
|
26304
|
+
var CHECKER_BINS = new Set([
|
|
26222
26305
|
"tsc",
|
|
26223
26306
|
"tsgo",
|
|
26307
|
+
"vue-tsc",
|
|
26308
|
+
"svelte-check",
|
|
26224
26309
|
"biome",
|
|
26225
26310
|
"eslint",
|
|
26226
26311
|
"prettier",
|
|
26227
|
-
"vue-tsc",
|
|
26228
|
-
"svelte-check",
|
|
26229
26312
|
"astro"
|
|
26230
26313
|
]);
|
|
26314
|
+
var RUNNER_BINS = new Set(["bun", "npm", "pnpm", "yarn"]);
|
|
26315
|
+
var DENY_SUBCMDS = new Set([
|
|
26316
|
+
"install",
|
|
26317
|
+
"i",
|
|
26318
|
+
"add",
|
|
26319
|
+
"remove",
|
|
26320
|
+
"rm",
|
|
26321
|
+
"uninstall",
|
|
26322
|
+
"un",
|
|
26323
|
+
"ci",
|
|
26324
|
+
"dlx",
|
|
26325
|
+
"x",
|
|
26326
|
+
"exec",
|
|
26327
|
+
"create",
|
|
26328
|
+
"init",
|
|
26329
|
+
"up",
|
|
26330
|
+
"update",
|
|
26331
|
+
"upgrade",
|
|
26332
|
+
"link",
|
|
26333
|
+
"unlink",
|
|
26334
|
+
"global",
|
|
26335
|
+
"dedupe",
|
|
26336
|
+
"audit",
|
|
26337
|
+
"publish",
|
|
26338
|
+
"pack",
|
|
26339
|
+
"import",
|
|
26340
|
+
"config"
|
|
26341
|
+
]);
|
|
26342
|
+
var SCRIPT_NAME = /^[a-z0-9][a-z0-9:._-]*$/i;
|
|
26231
26343
|
var BASH_DENY = /[;&|`$<>]|\.\.\/|\b(rm|curl|wget|sudo|chmod|chown|mv|dd|kill|eval|sh|bash|node|python)\b/;
|
|
26232
26344
|
function isAllowedBash(cmd) {
|
|
26233
26345
|
const t2 = cmd.trim();
|
|
@@ -26235,13 +26347,27 @@ function isAllowedBash(cmd) {
|
|
|
26235
26347
|
return { ok: false, reason: "empty cmd" };
|
|
26236
26348
|
if (BASH_DENY.test(t2))
|
|
26237
26349
|
return { ok: false, reason: "yasak operatör/binary" };
|
|
26238
|
-
const
|
|
26239
|
-
|
|
26240
|
-
|
|
26241
|
-
|
|
26350
|
+
const tokens = t2.split(/\s+/);
|
|
26351
|
+
const bin = tokens[0] ?? "";
|
|
26352
|
+
if (CHECKER_BINS.has(bin))
|
|
26353
|
+
return { ok: true };
|
|
26354
|
+
if (RUNNER_BINS.has(bin)) {
|
|
26355
|
+
const sub = tokens[1] ?? "";
|
|
26356
|
+
if (sub === "run") {
|
|
26357
|
+
const script = tokens[2] ?? "";
|
|
26358
|
+
if (!SCRIPT_NAME.test(script))
|
|
26359
|
+
return { ok: false, reason: `geçersiz script adı: ${script}` };
|
|
26360
|
+
return { ok: true };
|
|
26361
|
+
}
|
|
26362
|
+
if (bin === "yarn" && sub && !DENY_SUBCMDS.has(sub) && SCRIPT_NAME.test(sub)) {
|
|
26363
|
+
return { ok: true };
|
|
26364
|
+
}
|
|
26365
|
+
return { ok: false, reason: `yasak alt-komut (sadece 'run' izinli): ${bin} ${sub}` };
|
|
26366
|
+
}
|
|
26367
|
+
return { ok: false, reason: `allowlist dışı binary: ${bin}` };
|
|
26242
26368
|
}
|
|
26243
|
-
function isAllowedPath(
|
|
26244
|
-
const abs = isAbsolute(
|
|
26369
|
+
function isAllowedPath(p4, cwd) {
|
|
26370
|
+
const abs = isAbsolute(p4) ? p4 : resolve(cwd, p4);
|
|
26245
26371
|
const rel = relative2(cwd, abs);
|
|
26246
26372
|
if (rel === "" || rel.startsWith("..") || isAbsolute(rel)) {
|
|
26247
26373
|
return { ok: false, reason: "cwd dışı yol" };
|
|
@@ -26258,6 +26384,31 @@ function hasPromptInjection(content) {
|
|
|
26258
26384
|
// src/wizard/agent.ts
|
|
26259
26385
|
var MAX_OBS = 4000;
|
|
26260
26386
|
var pexec = promisify(execFile);
|
|
26387
|
+
function safeEnv() {
|
|
26388
|
+
const keep = [
|
|
26389
|
+
"PATH",
|
|
26390
|
+
"HOME",
|
|
26391
|
+
"USERPROFILE",
|
|
26392
|
+
"TMPDIR",
|
|
26393
|
+
"TEMP",
|
|
26394
|
+
"TMP",
|
|
26395
|
+
"LANG",
|
|
26396
|
+
"LC_ALL",
|
|
26397
|
+
"TERM",
|
|
26398
|
+
"SHELL",
|
|
26399
|
+
"NODE_ENV",
|
|
26400
|
+
"PATHEXT",
|
|
26401
|
+
"SystemRoot",
|
|
26402
|
+
"ComSpec"
|
|
26403
|
+
];
|
|
26404
|
+
const env2 = {};
|
|
26405
|
+
for (const k2 of keep) {
|
|
26406
|
+
const v2 = process.env[k2];
|
|
26407
|
+
if (v2 !== undefined)
|
|
26408
|
+
env2[k2] = v2;
|
|
26409
|
+
}
|
|
26410
|
+
return env2;
|
|
26411
|
+
}
|
|
26261
26412
|
async function defaultRunBash(cmd, cwd) {
|
|
26262
26413
|
const parts = cmd.trim().split(/\s+/);
|
|
26263
26414
|
const bin = parts[0] ?? "";
|
|
@@ -26265,7 +26416,8 @@ async function defaultRunBash(cmd, cwd) {
|
|
|
26265
26416
|
const { stdout: stdout2, stderr } = await pexec(bin, parts.slice(1), {
|
|
26266
26417
|
cwd,
|
|
26267
26418
|
timeout: 120000,
|
|
26268
|
-
maxBuffer: 4 * 1024 * 1024
|
|
26419
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
26420
|
+
env: safeEnv()
|
|
26269
26421
|
});
|
|
26270
26422
|
return { stdout: stdout2, stderr };
|
|
26271
26423
|
} catch (e2) {
|
|
@@ -26280,7 +26432,7 @@ async function executeTool(action, deps) {
|
|
|
26280
26432
|
const g3 = isAllowedPath(action.path, cwd);
|
|
26281
26433
|
if (!g3.ok)
|
|
26282
26434
|
return { ok: false, observation: `read reddedildi: ${g3.reason}` };
|
|
26283
|
-
const abs =
|
|
26435
|
+
const abs = resolveInCwd(action.path, cwd);
|
|
26284
26436
|
if (!existsSync7(abs))
|
|
26285
26437
|
return { ok: false, observation: `dosya yok: ${action.path}` };
|
|
26286
26438
|
let content = readFileSync8(abs, "utf-8");
|
|
@@ -26298,7 +26450,7 @@ async function executeTool(action, deps) {
|
|
|
26298
26450
|
const ga = isAdditiveEdit(action.find, action.replace);
|
|
26299
26451
|
if (!ga.ok)
|
|
26300
26452
|
return { ok: false, observation: `edit reddedildi: ${ga.reason}` };
|
|
26301
|
-
const abs =
|
|
26453
|
+
const abs = resolveInCwd(action.path, cwd);
|
|
26302
26454
|
if (!existsSync7(abs))
|
|
26303
26455
|
return { ok: false, observation: `dosya yok: ${action.path}` };
|
|
26304
26456
|
const src2 = readFileSync8(abs, "utf-8");
|
|
@@ -26334,7 +26486,9 @@ function buildWireSystemPrompt() {
|
|
|
26334
26486
|
"- `find` must be an EXACT, UNIQUE snippet copied from a file you have read (read before edit).",
|
|
26335
26487
|
"- Use the exact provided event_key (snake_case). Wire gurulu.track(...) at the right place and",
|
|
26336
26488
|
" gurulu.identify(...) at the auth point if given.",
|
|
26337
|
-
"- bash
|
|
26489
|
+
"- bash is ONLY for verification: the project's own scripts (`npm run typecheck`, `bun run build`,",
|
|
26490
|
+
" `pnpm run lint`) or a checker binary (`tsc --noEmit`, `biome check`, `eslint .`). Installing or",
|
|
26491
|
+
" fetching packages (`npm install`, `npx`, `bunx`, `pnpm dlx`, `add`, `exec`) is REJECTED by the guard.",
|
|
26338
26492
|
"- After wiring, run the project typecheck/build to verify; if it breaks, fix additively.",
|
|
26339
26493
|
"- When all events are wired and verify passes, emit done{summary}. Keep edits minimal."
|
|
26340
26494
|
].join(`
|
|
@@ -26368,17 +26522,35 @@ async function runWireAgent(client, input, snapshots) {
|
|
|
26368
26522
|
try {
|
|
26369
26523
|
res = await client.agentStep({ messages, first: i2 === 0 });
|
|
26370
26524
|
} catch {
|
|
26371
|
-
return {
|
|
26525
|
+
return {
|
|
26526
|
+
edits,
|
|
26527
|
+
changedFiles: [...changed],
|
|
26528
|
+
summary: "gateway hata",
|
|
26529
|
+
steps: i2,
|
|
26530
|
+
stoppedReason: "error"
|
|
26531
|
+
};
|
|
26372
26532
|
}
|
|
26373
26533
|
if (res.status === "stub") {
|
|
26374
|
-
return {
|
|
26534
|
+
return {
|
|
26535
|
+
edits,
|
|
26536
|
+
changedFiles: [...changed],
|
|
26537
|
+
summary: "AI kullanılamadı",
|
|
26538
|
+
steps: i2,
|
|
26539
|
+
stoppedReason: "stub"
|
|
26540
|
+
};
|
|
26375
26541
|
}
|
|
26376
26542
|
const { action, reasoning } = res.step;
|
|
26377
26543
|
if (action.tool === "done") {
|
|
26378
|
-
return {
|
|
26544
|
+
return {
|
|
26545
|
+
edits,
|
|
26546
|
+
changedFiles: [...changed],
|
|
26547
|
+
summary: action.summary,
|
|
26548
|
+
steps: i2,
|
|
26549
|
+
stoppedReason: "done"
|
|
26550
|
+
};
|
|
26379
26551
|
}
|
|
26380
26552
|
if (action.tool === "edit") {
|
|
26381
|
-
const abs =
|
|
26553
|
+
const abs = resolveInCwd(action.path, input.cwd);
|
|
26382
26554
|
if (!snapshots.has(action.path) && existsSync8(abs)) {
|
|
26383
26555
|
snapshots.set(action.path, readFileSync9(abs, "utf-8"));
|
|
26384
26556
|
}
|
|
@@ -26391,11 +26563,17 @@ async function runWireAgent(client, input, snapshots) {
|
|
|
26391
26563
|
messages.push({ role: "assistant", content: JSON.stringify(res.step) });
|
|
26392
26564
|
messages.push({ role: "user", content: `[${reasoning}] → ${out.observation}` });
|
|
26393
26565
|
}
|
|
26394
|
-
return {
|
|
26566
|
+
return {
|
|
26567
|
+
edits,
|
|
26568
|
+
changedFiles: [...changed],
|
|
26569
|
+
summary: "adım limiti",
|
|
26570
|
+
steps: MAX_STEPS,
|
|
26571
|
+
stoppedReason: "cap"
|
|
26572
|
+
};
|
|
26395
26573
|
}
|
|
26396
26574
|
function restoreSnapshots(cwd, snapshots) {
|
|
26397
26575
|
for (const [rel, content] of snapshots) {
|
|
26398
|
-
writeFileSync7(
|
|
26576
|
+
writeFileSync7(resolveInCwd(rel, cwd), content, "utf-8");
|
|
26399
26577
|
}
|
|
26400
26578
|
}
|
|
26401
26579
|
function unifiedDiff(oldStr, newStr, file, context = 2) {
|
|
@@ -26427,7 +26605,7 @@ function unifiedDiff(oldStr, newStr, file, context = 2) {
|
|
|
26427
26605
|
function formatWireDiff(cwd, snapshots) {
|
|
26428
26606
|
const blocks = [];
|
|
26429
26607
|
for (const [rel, oldContent] of snapshots) {
|
|
26430
|
-
const abs =
|
|
26608
|
+
const abs = resolveInCwd(rel, cwd);
|
|
26431
26609
|
const cur = existsSync8(abs) ? readFileSync9(abs, "utf-8") : "";
|
|
26432
26610
|
if (cur !== oldContent)
|
|
26433
26611
|
blocks.push(unifiedDiff(oldContent, cur, rel));
|
|
@@ -26453,16 +26631,16 @@ var FRAMEWORKS = [
|
|
|
26453
26631
|
"node-server"
|
|
26454
26632
|
];
|
|
26455
26633
|
function bail() {
|
|
26456
|
-
|
|
26634
|
+
p4.cancel("İptal edildi.");
|
|
26457
26635
|
process.exit(0);
|
|
26458
26636
|
}
|
|
26459
26637
|
async function runWizard(opts) {
|
|
26460
26638
|
if (process.stdout.isTTY)
|
|
26461
26639
|
process.stdout.write(banner());
|
|
26462
|
-
|
|
26640
|
+
p4.intro(c3.dim("otonom kurulum başlıyor — auth → workspace → install → wire"));
|
|
26463
26641
|
const TOTAL = 6;
|
|
26464
26642
|
const phase = (n2, label) => {
|
|
26465
|
-
|
|
26643
|
+
p4.log.step(`${c3.dim(`[${n2}/${TOTAL}]`)} ${c3.bold(label)}`);
|
|
26466
26644
|
};
|
|
26467
26645
|
phase(1, "Kimlik doğrulama");
|
|
26468
26646
|
const auth = await ensureAuth({
|
|
@@ -26479,18 +26657,18 @@ async function runWizard(opts) {
|
|
|
26479
26657
|
if (opts.framework && FRAMEWORKS.includes(opts.framework)) {
|
|
26480
26658
|
framework = opts.framework;
|
|
26481
26659
|
} else if (!opts.yes) {
|
|
26482
|
-
const ok = await
|
|
26660
|
+
const ok = await p4.confirm({
|
|
26483
26661
|
message: `Saptanan: ${detected.framework} (${detected.packageManager}). Doğru mu?`
|
|
26484
26662
|
});
|
|
26485
|
-
if (
|
|
26663
|
+
if (p4.isCancel(ok))
|
|
26486
26664
|
bail();
|
|
26487
26665
|
if (!ok) {
|
|
26488
|
-
const choice = await
|
|
26666
|
+
const choice = await p4.select({
|
|
26489
26667
|
message: "Framework seç",
|
|
26490
26668
|
options: FRAMEWORKS.map((f3) => ({ value: f3, label: f3 })),
|
|
26491
26669
|
initialValue: detected.framework
|
|
26492
26670
|
});
|
|
26493
|
-
if (
|
|
26671
|
+
if (p4.isCancel(choice))
|
|
26494
26672
|
bail();
|
|
26495
26673
|
framework = choice;
|
|
26496
26674
|
}
|
|
@@ -26498,9 +26676,10 @@ async function runWizard(opts) {
|
|
|
26498
26676
|
const project = { ...detected, framework };
|
|
26499
26677
|
const plan = buildInstallPlan(project, { writeKey, workspaceId });
|
|
26500
26678
|
const isNode = plan.sdk === "@gurulu/node";
|
|
26679
|
+
const authed = Boolean(auth.apiKey);
|
|
26501
26680
|
let approvedEvents = [];
|
|
26502
26681
|
let identifyHint = null;
|
|
26503
|
-
if (!opts.noAi && detected.hasPackageJson) {
|
|
26682
|
+
if (!opts.noAi && authed && detected.hasPackageJson) {
|
|
26504
26683
|
const ctx = gatherContext({ cwd: opts.cwd });
|
|
26505
26684
|
const aiPlan = await fetchPlan(client, ctx, { framework });
|
|
26506
26685
|
if (aiPlan) {
|
|
@@ -26509,17 +26688,21 @@ async function runWizard(opts) {
|
|
|
26509
26688
|
if (approved)
|
|
26510
26689
|
approvedEvents = approved;
|
|
26511
26690
|
} else {
|
|
26512
|
-
|
|
26691
|
+
p4.log.info("AI planı yok — autocapture + sektör paketi (deterministik floor).");
|
|
26513
26692
|
}
|
|
26514
26693
|
}
|
|
26694
|
+
let featuresResult = { selected: [], registered: false };
|
|
26695
|
+
if (authed) {
|
|
26696
|
+
featuresResult = await runFeatures(client, project, { yes: opts.yes, authed });
|
|
26697
|
+
}
|
|
26515
26698
|
phase(4, "SDK kurulumu");
|
|
26516
26699
|
let installed = false;
|
|
26517
26700
|
if (opts.noInstall) {
|
|
26518
|
-
|
|
26701
|
+
p4.log.info(`SDK kurulumu atlandı — elle: ${plan.installCommand}`);
|
|
26519
26702
|
} else if (!detected.hasPackageJson) {
|
|
26520
|
-
|
|
26703
|
+
p4.log.warn("package.json yok — script tag ile kur: https://cdn.gurulu.io/t.js");
|
|
26521
26704
|
} else {
|
|
26522
|
-
const s2 =
|
|
26705
|
+
const s2 = p4.spinner();
|
|
26523
26706
|
s2.start(`${plan.sdk} kuruluyor (${plan.installCommand})…`);
|
|
26524
26707
|
const res = await execInstall(plan, { cwd: opts.cwd });
|
|
26525
26708
|
if (res.ok) {
|
|
@@ -26540,10 +26723,15 @@ async function runWizard(opts) {
|
|
|
26540
26723
|
const envFile = isNode ? ".env" : ".env.local";
|
|
26541
26724
|
const vars = [];
|
|
26542
26725
|
for (const k2 of plan.envKeys) {
|
|
26543
|
-
if (k2.key.endsWith("_WORKSPACE"))
|
|
26726
|
+
if (k2.key.endsWith("_WORKSPACE")) {
|
|
26544
26727
|
vars.push({ key: k2.key, value: writeKey });
|
|
26545
|
-
else if (k2.key === "GURULU_SECRET_KEY")
|
|
26546
|
-
|
|
26728
|
+
} else if (k2.key === "GURULU_SECRET_KEY") {
|
|
26729
|
+
if (auth.apiKey.startsWith("sk_")) {
|
|
26730
|
+
vars.push({ key: k2.key, value: auth.apiKey });
|
|
26731
|
+
} else {
|
|
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.");
|
|
26733
|
+
}
|
|
26734
|
+
}
|
|
26547
26735
|
}
|
|
26548
26736
|
const envRes = vars.length > 0 ? writeEnvFile({ cwd: opts.cwd, file: envFile, vars }) : null;
|
|
26549
26737
|
writeProjectScaffold(opts.cwd, {
|
|
@@ -26561,7 +26749,7 @@ async function runWizard(opts) {
|
|
|
26561
26749
|
}
|
|
26562
26750
|
let registeredCount = 0;
|
|
26563
26751
|
if (approvedEvents.length > 0) {
|
|
26564
|
-
const s2 =
|
|
26752
|
+
const s2 = p4.spinner();
|
|
26565
26753
|
s2.start("Yeni eventler registry kuyruguna oneriliyor…");
|
|
26566
26754
|
const res = await registerNewEvents(client, approvedEvents);
|
|
26567
26755
|
registeredCount = res.registered.length;
|
|
@@ -26570,29 +26758,29 @@ async function runWizard(opts) {
|
|
|
26570
26758
|
let wiredCount = 0;
|
|
26571
26759
|
if (approvedEvents.length > 0) {
|
|
26572
26760
|
if (opts.noAi) {
|
|
26573
|
-
|
|
26761
|
+
p4.log.message(`Capture — şu çağrıları ekle:
|
|
26574
26762
|
${captureGuide(approvedEvents, identifyHint, isNode)}`);
|
|
26575
26763
|
} else {
|
|
26576
26764
|
const wireFiles = gatherContext({ cwd: opts.cwd }).files.map((f3) => f3.path);
|
|
26577
26765
|
const snapshots = new Map;
|
|
26578
|
-
const s2 =
|
|
26766
|
+
const s2 = p4.spinner();
|
|
26579
26767
|
s2.start("AI capture wiring (kod düzenleniyor)…");
|
|
26580
26768
|
const outcome = await runWireAgent(client, { cwd: opts.cwd, events: approvedEvents, identifyHint, files: wireFiles }, snapshots);
|
|
26581
26769
|
s2.stop(`wire: ${outcome.changedFiles.length} dosya / ${outcome.steps} adım (${outcome.stoppedReason})`);
|
|
26582
26770
|
if (outcome.changedFiles.length > 0) {
|
|
26583
|
-
|
|
26584
|
-
const keep = opts.yes ? true : await
|
|
26771
|
+
p4.log.message(formatWireDiff(opts.cwd, snapshots));
|
|
26772
|
+
const keep = opts.yes ? true : await p4.confirm({
|
|
26585
26773
|
message: `${outcome.changedFiles.length} dosyadaki wire değişikliklerini tut?`
|
|
26586
26774
|
});
|
|
26587
|
-
if (
|
|
26775
|
+
if (p4.isCancel(keep) || !keep) {
|
|
26588
26776
|
restoreSnapshots(opts.cwd, snapshots);
|
|
26589
|
-
|
|
26590
|
-
|
|
26777
|
+
p4.log.info("Wire geri alındı — capture snippet rehberi:");
|
|
26778
|
+
p4.log.message(captureGuide(approvedEvents, identifyHint, isNode));
|
|
26591
26779
|
} else {
|
|
26592
26780
|
wiredCount = outcome.changedFiles.length;
|
|
26593
26781
|
}
|
|
26594
26782
|
} else {
|
|
26595
|
-
|
|
26783
|
+
p4.log.message(`Capture (AI gömemedi → snippet-göster) — şu çağrıları ekle:
|
|
26596
26784
|
${captureGuide(approvedEvents, identifyHint, isNode)}`);
|
|
26597
26785
|
}
|
|
26598
26786
|
}
|
|
@@ -26611,15 +26799,18 @@ ${captureGuide(approvedEvents, identifyHint, isNode)}`);
|
|
|
26611
26799
|
if (wiredCount > 0)
|
|
26612
26800
|
lines.push(`✓ ${wiredCount} dosya AI ile capture wire edildi`);
|
|
26613
26801
|
}
|
|
26802
|
+
if (featuresResult.registered && featuresResult.selected.length > 0) {
|
|
26803
|
+
lines.push(`✓ özellikler: ${featuresResult.selected.map((f3) => f3.key).join(", ")} kuruldu`);
|
|
26804
|
+
}
|
|
26614
26805
|
lines.push(`✓ .gurulu/config.json${pulled ? " + registry pull" : ""}`);
|
|
26615
|
-
|
|
26806
|
+
p4.note(lines.join(`
|
|
26616
26807
|
`), c3.neon("✦ Değişiklikler"));
|
|
26617
26808
|
if (inj.strategy !== "prepend-entry" || inj.reason === "no-entry") {
|
|
26618
|
-
|
|
26809
|
+
p4.log.info(`Wire: ${inj.wireHint ?? plan.placementHint}`);
|
|
26619
26810
|
if (inj.strategy === "manual")
|
|
26620
|
-
|
|
26811
|
+
p4.log.message(plan.initSnippet);
|
|
26621
26812
|
}
|
|
26622
|
-
|
|
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")}`);
|
|
26623
26814
|
}
|
|
26624
26815
|
async function resolveWorkspace(client, authWorkspaceId, opts) {
|
|
26625
26816
|
if (opts.writeKey) {
|
|
@@ -26642,7 +26833,7 @@ async function resolveWorkspace(client, authWorkspaceId, opts) {
|
|
|
26642
26833
|
selected = CREATE;
|
|
26643
26834
|
} else {
|
|
26644
26835
|
const initial = list.find((w2) => w2.workspace_id === authWorkspaceId)?.workspace_id ?? list[0]?.workspace_id ?? CREATE;
|
|
26645
|
-
const choice = await
|
|
26836
|
+
const choice = await p4.select({
|
|
26646
26837
|
message: "Workspace seç",
|
|
26647
26838
|
options: [
|
|
26648
26839
|
...list.map((w2) => ({ value: w2.workspace_id, label: w2.name, hint: w2.slug })),
|
|
@@ -26650,26 +26841,26 @@ async function resolveWorkspace(client, authWorkspaceId, opts) {
|
|
|
26650
26841
|
],
|
|
26651
26842
|
initialValue: initial
|
|
26652
26843
|
});
|
|
26653
|
-
if (
|
|
26844
|
+
if (p4.isCancel(choice))
|
|
26654
26845
|
bail();
|
|
26655
26846
|
selected = choice;
|
|
26656
26847
|
}
|
|
26657
26848
|
if (selected === CREATE) {
|
|
26658
|
-
const name = await
|
|
26849
|
+
const name = await p4.text({
|
|
26659
26850
|
message: "Workspace adı",
|
|
26660
26851
|
placeholder: "My App",
|
|
26661
26852
|
validate: (v2) => v2.trim() ? undefined : "gerekli"
|
|
26662
26853
|
});
|
|
26663
|
-
if (
|
|
26854
|
+
if (p4.isCancel(name))
|
|
26664
26855
|
bail();
|
|
26665
|
-
const domain = await
|
|
26856
|
+
const domain = await p4.text({
|
|
26666
26857
|
message: "Domain",
|
|
26667
26858
|
placeholder: "example.com",
|
|
26668
26859
|
validate: (v2) => v2.trim().length >= 3 ? undefined : "geçerli domain gerekli"
|
|
26669
26860
|
});
|
|
26670
|
-
if (
|
|
26861
|
+
if (p4.isCancel(domain))
|
|
26671
26862
|
bail();
|
|
26672
|
-
const s2 =
|
|
26863
|
+
const s2 = p4.spinner();
|
|
26673
26864
|
s2.start("Workspace oluşturuluyor…");
|
|
26674
26865
|
const created = await client.createWorkspace({
|
|
26675
26866
|
name: String(name).trim(),
|
|
@@ -26729,11 +26920,19 @@ var wizardArgs = {
|
|
|
26729
26920
|
framework: { type: "string", description: "Framework override (auto-detect yerine)" },
|
|
26730
26921
|
install: { type: "boolean", description: "SDK install (--no-install ile atla)", default: true },
|
|
26731
26922
|
pull: { type: "boolean", description: "İlk registry pull (--no-pull ile atla)", default: true },
|
|
26732
|
-
ai: {
|
|
26923
|
+
ai: {
|
|
26924
|
+
type: "boolean",
|
|
26925
|
+
description: "AI Plan/wire fazı (--no-ai ile atla → floor)",
|
|
26926
|
+
default: true
|
|
26927
|
+
},
|
|
26733
26928
|
yes: { type: "boolean", description: "Onayları otomatik geç" },
|
|
26734
26929
|
ci: { type: "boolean", description: "Non-interaktif (api-key + workspace zorunlu)" }
|
|
26735
26930
|
};
|
|
26736
26931
|
async function runWizardFromArgs(args) {
|
|
26932
|
+
if (args.ci && (!args["api-key"] || !args.workspace)) {
|
|
26933
|
+
console.error("[gurulu] --ci için --api-key <sk_...> ve --workspace <uuid> zorunlu (non-interaktif kurulum).");
|
|
26934
|
+
process.exit(1);
|
|
26935
|
+
}
|
|
26737
26936
|
const opts = {
|
|
26738
26937
|
cwd: process.cwd(),
|
|
26739
26938
|
noInstall: args.install === false,
|
|
@@ -26767,7 +26966,7 @@ var initCmd = defineCommand({
|
|
|
26767
26966
|
// src/lib/editor-mcp.ts
|
|
26768
26967
|
import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync10, writeFileSync as writeFileSync9 } from "node:fs";
|
|
26769
26968
|
import { homedir as homedir2 } from "node:os";
|
|
26770
|
-
import { dirname as dirname4, join as
|
|
26969
|
+
import { dirname as dirname4, join as join9 } from "node:path";
|
|
26771
26970
|
var SERVER_NAME = "gurulu";
|
|
26772
26971
|
function buildMcpServerConfig(creds) {
|
|
26773
26972
|
return {
|
|
@@ -26781,14 +26980,14 @@ function buildMcpServerConfig(creds) {
|
|
|
26781
26980
|
};
|
|
26782
26981
|
}
|
|
26783
26982
|
var EDITORS = {
|
|
26784
|
-
cursor: { path: () =>
|
|
26785
|
-
claude: { path: () =>
|
|
26983
|
+
cursor: { path: () => join9(homedir2(), ".cursor", "mcp.json"), key: "mcpServers", label: "Cursor" },
|
|
26984
|
+
claude: { path: () => join9(homedir2(), ".claude.json"), key: "mcpServers", label: "Claude Code" },
|
|
26786
26985
|
windsurf: {
|
|
26787
|
-
path: () =>
|
|
26986
|
+
path: () => join9(homedir2(), ".codeium", "windsurf", "mcp_config.json"),
|
|
26788
26987
|
key: "mcpServers",
|
|
26789
26988
|
label: "Windsurf"
|
|
26790
26989
|
},
|
|
26791
|
-
vscode: { path: (cwd) =>
|
|
26990
|
+
vscode: { path: (cwd) => join9(cwd, ".vscode", "mcp.json"), key: "servers", label: "VS Code" }
|
|
26792
26991
|
};
|
|
26793
26992
|
function mergeMcpConfig(existing, serverConfig, key) {
|
|
26794
26993
|
const servers = existing[key] ?? {};
|
|
@@ -26984,9 +27183,9 @@ var pushCmd = defineCommand({
|
|
|
26984
27183
|
// src/commands/uninstall.ts
|
|
26985
27184
|
import { execFile as execFile2 } from "node:child_process";
|
|
26986
27185
|
import { existsSync as existsSync11, readFileSync as readFileSync11, rmSync, writeFileSync as writeFileSync10 } from "node:fs";
|
|
26987
|
-
import { join as
|
|
27186
|
+
import { join as join10 } from "node:path";
|
|
26988
27187
|
import { promisify as promisify2 } from "node:util";
|
|
26989
|
-
import * as
|
|
27188
|
+
import * as p5 from "@clack/prompts";
|
|
26990
27189
|
var pexec2 = promisify2(execFile2);
|
|
26991
27190
|
var ENV_FILES = [".env.local", ".env"];
|
|
26992
27191
|
var GURULU_PREFIXES = ["GURULU_", "NEXT_PUBLIC_GURULU", "VITE_GURULU"];
|
|
@@ -27013,23 +27212,23 @@ var uninstallCmd = defineCommand({
|
|
|
27013
27212
|
const config = readProjectConfig(cwd);
|
|
27014
27213
|
const detected = detectProject(cwd);
|
|
27015
27214
|
const pkg = config?.sdk_preference === "node" ? "@gurulu/node" : "@gurulu/web";
|
|
27016
|
-
|
|
27017
|
-
|
|
27215
|
+
p5.intro("Gurulu uninstall");
|
|
27216
|
+
p5.note([
|
|
27018
27217
|
`• SDK kaldır: ${pkg} (${detected.packageManager})`,
|
|
27019
27218
|
`• env temizle: ${ENV_FILES.join(", ")} (GURULU_* anahtarları)`,
|
|
27020
27219
|
"• .gurulu/ dizinini sil"
|
|
27021
27220
|
].join(`
|
|
27022
27221
|
`), "Şunlar yapılacak");
|
|
27023
27222
|
if (!args.yes) {
|
|
27024
|
-
const ok = await
|
|
27025
|
-
if (
|
|
27026
|
-
|
|
27223
|
+
const ok = await p5.confirm({ message: "Devam edilsin mi?" });
|
|
27224
|
+
if (p5.isCancel(ok) || !ok) {
|
|
27225
|
+
p5.cancel("İptal.");
|
|
27027
27226
|
process.exit(0);
|
|
27028
27227
|
}
|
|
27029
27228
|
}
|
|
27030
27229
|
if (!args["no-deps"] && detected.hasPackageJson) {
|
|
27031
27230
|
const { bin, args: a2 } = removeCmd(detected.packageManager, pkg);
|
|
27032
|
-
const s2 =
|
|
27231
|
+
const s2 = p5.spinner();
|
|
27033
27232
|
s2.start(`${pkg} kaldırılıyor…`);
|
|
27034
27233
|
try {
|
|
27035
27234
|
await pexec2(bin, a2, { cwd, timeout: 120000 });
|
|
@@ -27040,7 +27239,7 @@ var uninstallCmd = defineCommand({
|
|
|
27040
27239
|
}
|
|
27041
27240
|
const cleaned = [];
|
|
27042
27241
|
for (const f3 of ENV_FILES) {
|
|
27043
|
-
const abs =
|
|
27242
|
+
const abs = join10(cwd, f3);
|
|
27044
27243
|
if (!existsSync11(abs))
|
|
27045
27244
|
continue;
|
|
27046
27245
|
const { content, removed } = removeEnvKeys(readFileSync11(abs, "utf-8"), GURULU_PREFIXES);
|
|
@@ -27049,15 +27248,15 @@ var uninstallCmd = defineCommand({
|
|
|
27049
27248
|
cleaned.push(`${f3} (-${removed.length})`);
|
|
27050
27249
|
}
|
|
27051
27250
|
}
|
|
27052
|
-
const guruluDir =
|
|
27251
|
+
const guruluDir = join10(cwd, ".gurulu");
|
|
27053
27252
|
if (existsSync11(guruluDir))
|
|
27054
27253
|
rmSync(guruluDir, { recursive: true, force: true });
|
|
27055
|
-
|
|
27254
|
+
p5.outro(`Kaldırıldı. env: ${cleaned.join(", ") || "değişiklik yok"} · .gurulu silindi. (Koddaki init/track çağrılarını elle çıkar.)`);
|
|
27056
27255
|
}
|
|
27057
27256
|
});
|
|
27058
27257
|
|
|
27059
27258
|
// src/index.ts
|
|
27060
|
-
var VERSION = "1.2.
|
|
27259
|
+
var VERSION = "1.2.2";
|
|
27061
27260
|
var mainCmd = defineCommand({
|
|
27062
27261
|
meta: {
|
|
27063
27262
|
name: "gurulu",
|