@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/index.js
CHANGED
|
@@ -24106,7 +24106,7 @@ class ApiClient {
|
|
|
24106
24106
|
}
|
|
24107
24107
|
|
|
24108
24108
|
// src/lib/config.ts
|
|
24109
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
24109
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
24110
24110
|
import { homedir } from "node:os";
|
|
24111
24111
|
import { dirname, join } from "node:path";
|
|
24112
24112
|
var DEFAULT_ENDPOINT = process.env.GURULU_ENDPOINT ?? "https://api.gurulu.io";
|
|
@@ -24163,10 +24163,9 @@ function writeGlobalCredentials(creds) {
|
|
|
24163
24163
|
const path = globalCredentialsPath();
|
|
24164
24164
|
ensureDir(path);
|
|
24165
24165
|
writeFileSync(path, `${JSON.stringify(creds, null, 2)}
|
|
24166
|
-
`, "utf-8");
|
|
24166
|
+
`, { encoding: "utf-8", mode: 384 });
|
|
24167
24167
|
try {
|
|
24168
|
-
|
|
24169
|
-
fs.chmodSync(path, 384);
|
|
24168
|
+
chmodSync(path, 384);
|
|
24170
24169
|
} catch {}
|
|
24171
24170
|
}
|
|
24172
24171
|
function findCredentialForWorkspace(workspaceId) {
|
|
@@ -24696,7 +24695,7 @@ function sleep(ms) {
|
|
|
24696
24695
|
// src/wizard/run.ts
|
|
24697
24696
|
import { existsSync as existsSync9, mkdirSync as mkdirSync2, writeFileSync as writeFileSync8 } from "node:fs";
|
|
24698
24697
|
import { dirname as dirname3 } from "node:path";
|
|
24699
|
-
import * as
|
|
24698
|
+
import * as p4 from "@clack/prompts";
|
|
24700
24699
|
|
|
24701
24700
|
// src/commands/pull.ts
|
|
24702
24701
|
import { writeFileSync as writeFileSync3 } from "node:fs";
|
|
@@ -24840,6 +24839,17 @@ var pullCmd = defineCommand({
|
|
|
24840
24839
|
// src/lib/detect.ts
|
|
24841
24840
|
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
|
|
24842
24841
|
import { dirname as dirname2, join as join5, parse } from "node:path";
|
|
24842
|
+
var LLM_DEP_MAP = {
|
|
24843
|
+
openai: "openai",
|
|
24844
|
+
"@anthropic-ai/sdk": "anthropic",
|
|
24845
|
+
"@langchain/core": "langchain",
|
|
24846
|
+
langchain: "langchain",
|
|
24847
|
+
"@google/generative-ai": "google-genai",
|
|
24848
|
+
ai: "vercel-ai",
|
|
24849
|
+
"cohere-ai": "cohere",
|
|
24850
|
+
"@mistralai/mistralai": "mistral",
|
|
24851
|
+
ollama: "ollama"
|
|
24852
|
+
};
|
|
24843
24853
|
function readPackageJson(dir) {
|
|
24844
24854
|
const p = join5(dir, "package.json");
|
|
24845
24855
|
if (!existsSync4(p))
|
|
@@ -24925,6 +24935,14 @@ function frameworkRuntime(fw) {
|
|
|
24925
24935
|
return "unknown";
|
|
24926
24936
|
}
|
|
24927
24937
|
}
|
|
24938
|
+
function detectLlmFrameworks(pkg) {
|
|
24939
|
+
const found = new Set;
|
|
24940
|
+
for (const [dep, fw] of Object.entries(LLM_DEP_MAP)) {
|
|
24941
|
+
if (hasDep(pkg, dep))
|
|
24942
|
+
found.add(fw);
|
|
24943
|
+
}
|
|
24944
|
+
return [...found];
|
|
24945
|
+
}
|
|
24928
24946
|
function detectProject(dir) {
|
|
24929
24947
|
const pkg = readPackageJson(dir);
|
|
24930
24948
|
const framework = detectFramework(pkg, dir);
|
|
@@ -24934,7 +24952,8 @@ function detectProject(dir) {
|
|
|
24934
24952
|
framework,
|
|
24935
24953
|
runtime: frameworkRuntime(framework),
|
|
24936
24954
|
packageManager: detectPackageManager(dir),
|
|
24937
|
-
packageJson: pkg
|
|
24955
|
+
packageJson: pkg,
|
|
24956
|
+
llmFrameworks: detectLlmFrameworks(pkg)
|
|
24938
24957
|
};
|
|
24939
24958
|
}
|
|
24940
24959
|
|
|
@@ -25711,8 +25730,77 @@ function gatherContext(opts) {
|
|
|
25711
25730
|
return { files, capped, totalBytes };
|
|
25712
25731
|
}
|
|
25713
25732
|
|
|
25714
|
-
// src/wizard/
|
|
25733
|
+
// src/wizard/features.ts
|
|
25715
25734
|
import * as p2 from "@clack/prompts";
|
|
25735
|
+
function availableFeatures(detected) {
|
|
25736
|
+
const isBrowser = frameworkRuntime(detected.framework) !== "node";
|
|
25737
|
+
const feats = [];
|
|
25738
|
+
feats.push({
|
|
25739
|
+
key: "error",
|
|
25740
|
+
label: "Hata takibi",
|
|
25741
|
+
detail: "Tarayıcı JS hatalarını otomatik yakala (js_error)",
|
|
25742
|
+
enableHint: isBrowser ? "gurulu.init({ ..., autocapture: { js_error: true } })" : "Sunucu hatalarında: gurulu.track('js_error', { message, error_type })",
|
|
25743
|
+
recommended: isBrowser
|
|
25744
|
+
});
|
|
25745
|
+
if (detected.llmFrameworks.length > 0) {
|
|
25746
|
+
feats.push({
|
|
25747
|
+
key: "llm",
|
|
25748
|
+
label: `LLM analizi (${detected.llmFrameworks.join(", ")} tespit edildi)`,
|
|
25749
|
+
detail: "AI çağrı maliyeti/latency/hata/model performansı",
|
|
25750
|
+
enableHint: "import { wrapOpenAI } from '@gurulu/node'; const client = wrapOpenAI(openai);",
|
|
25751
|
+
recommended: true
|
|
25752
|
+
});
|
|
25753
|
+
}
|
|
25754
|
+
if (isBrowser) {
|
|
25755
|
+
feats.push({
|
|
25756
|
+
key: "activation",
|
|
25757
|
+
label: "Activation (popup · tur · A/B test · kişiselleştirme)",
|
|
25758
|
+
detail: "Dashboard'dan yayınla, SDK render etsin (Action Layer)",
|
|
25759
|
+
enableHint: "import { runActivation } from '@gurulu/web/activate'; runActivation(gurulu);",
|
|
25760
|
+
recommended: false
|
|
25761
|
+
});
|
|
25762
|
+
}
|
|
25763
|
+
return feats;
|
|
25764
|
+
}
|
|
25765
|
+
async function runFeatures(client, detected, opts) {
|
|
25766
|
+
const avail = availableFeatures(detected);
|
|
25767
|
+
if (avail.length === 0 || !opts.authed)
|
|
25768
|
+
return { selected: [], registered: false };
|
|
25769
|
+
let selectedKeys;
|
|
25770
|
+
if (opts.yes) {
|
|
25771
|
+
selectedKeys = avail.filter((f3) => f3.recommended).map((f3) => f3.key);
|
|
25772
|
+
} else {
|
|
25773
|
+
const choice = await p2.multiselect({
|
|
25774
|
+
message: "Hangi özellikleri kuralım? (event'ler registry'ye otomatik eklenir)",
|
|
25775
|
+
options: avail.map((f3) => ({ value: f3.key, label: f3.label, hint: f3.detail })),
|
|
25776
|
+
initialValues: avail.filter((f3) => f3.recommended).map((f3) => f3.key),
|
|
25777
|
+
required: false
|
|
25778
|
+
});
|
|
25779
|
+
if (p2.isCancel(choice))
|
|
25780
|
+
return { selected: [], registered: false };
|
|
25781
|
+
selectedKeys = choice;
|
|
25782
|
+
}
|
|
25783
|
+
if (selectedKeys.length === 0)
|
|
25784
|
+
return { selected: [], registered: false };
|
|
25785
|
+
const selected = avail.filter((f3) => selectedKeys.includes(f3.key));
|
|
25786
|
+
const s2 = p2.spinner();
|
|
25787
|
+
s2.start("Özellikler registry'ye kuruluyor…");
|
|
25788
|
+
try {
|
|
25789
|
+
await client.post("/features/register", { features: selectedKeys });
|
|
25790
|
+
s2.stop(c3.neon(`✓ ${selected.length} özellik kuruldu`));
|
|
25791
|
+
} catch {
|
|
25792
|
+
s2.stop("Özellik kurulumu atlandı (gateway hatası) — sonra: gurulu doctor", 1);
|
|
25793
|
+
return { selected, registered: false };
|
|
25794
|
+
}
|
|
25795
|
+
p2.note(selected.map((f3) => `${c3.bold(f3.label)}
|
|
25796
|
+
${c3.dim(f3.enableHint)}`).join(`
|
|
25797
|
+
|
|
25798
|
+
`), "Etkinleştirme");
|
|
25799
|
+
return { selected, registered: true };
|
|
25800
|
+
}
|
|
25801
|
+
|
|
25802
|
+
// src/wizard/plan.ts
|
|
25803
|
+
import * as p3 from "@clack/prompts";
|
|
25716
25804
|
async function fetchPlan(client, context, input) {
|
|
25717
25805
|
if (context.files.length === 0)
|
|
25718
25806
|
return null;
|
|
@@ -25757,28 +25845,29 @@ function formatPlan(plan) {
|
|
|
25757
25845
|
`).trimEnd();
|
|
25758
25846
|
}
|
|
25759
25847
|
async function renderPlan(plan) {
|
|
25760
|
-
|
|
25848
|
+
p3.note(formatPlan(plan), plan.summary);
|
|
25761
25849
|
const newCount = plan.events.filter((e2) => !e2.existing).length;
|
|
25762
|
-
const ok = await
|
|
25850
|
+
const ok = await p3.confirm({
|
|
25763
25851
|
message: `${plan.events.length} event (${newCount} yeni) — bu planı uygula?`
|
|
25764
25852
|
});
|
|
25765
|
-
if (
|
|
25853
|
+
if (p3.isCancel(ok) || !ok)
|
|
25766
25854
|
return null;
|
|
25767
25855
|
return plan.events;
|
|
25768
25856
|
}
|
|
25769
25857
|
|
|
25770
25858
|
// src/wizard/wire.ts
|
|
25771
25859
|
import { existsSync as existsSync8, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "node:fs";
|
|
25772
|
-
import { join as join10 } from "node:path";
|
|
25773
25860
|
|
|
25774
25861
|
// src/wizard/agent.ts
|
|
25775
25862
|
import { execFile } from "node:child_process";
|
|
25776
25863
|
import { existsSync as existsSync7, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "node:fs";
|
|
25777
|
-
import { join as join9 } from "node:path";
|
|
25778
25864
|
import { promisify } from "node:util";
|
|
25779
25865
|
|
|
25780
25866
|
// src/wizard/guard.ts
|
|
25781
25867
|
import { basename, isAbsolute, relative as relative2, resolve } from "node:path";
|
|
25868
|
+
function resolveInCwd(p4, cwd) {
|
|
25869
|
+
return isAbsolute(p4) ? p4 : resolve(cwd, p4);
|
|
25870
|
+
}
|
|
25782
25871
|
function isAdditiveEdit(find, replace) {
|
|
25783
25872
|
if (find.length === 0)
|
|
25784
25873
|
return { ok: false, reason: "empty find" };
|
|
@@ -25789,22 +25878,45 @@ function isAdditiveEdit(find, replace) {
|
|
|
25789
25878
|
return { ok: false, reason: "no-op edit (replace === find)" };
|
|
25790
25879
|
return { ok: true };
|
|
25791
25880
|
}
|
|
25792
|
-
var
|
|
25793
|
-
"bun",
|
|
25794
|
-
"bunx",
|
|
25795
|
-
"npm",
|
|
25796
|
-
"npx",
|
|
25797
|
-
"pnpm",
|
|
25798
|
-
"yarn",
|
|
25881
|
+
var CHECKER_BINS = new Set([
|
|
25799
25882
|
"tsc",
|
|
25800
25883
|
"tsgo",
|
|
25884
|
+
"vue-tsc",
|
|
25885
|
+
"svelte-check",
|
|
25801
25886
|
"biome",
|
|
25802
25887
|
"eslint",
|
|
25803
25888
|
"prettier",
|
|
25804
|
-
"vue-tsc",
|
|
25805
|
-
"svelte-check",
|
|
25806
25889
|
"astro"
|
|
25807
25890
|
]);
|
|
25891
|
+
var RUNNER_BINS = new Set(["bun", "npm", "pnpm", "yarn"]);
|
|
25892
|
+
var DENY_SUBCMDS = new Set([
|
|
25893
|
+
"install",
|
|
25894
|
+
"i",
|
|
25895
|
+
"add",
|
|
25896
|
+
"remove",
|
|
25897
|
+
"rm",
|
|
25898
|
+
"uninstall",
|
|
25899
|
+
"un",
|
|
25900
|
+
"ci",
|
|
25901
|
+
"dlx",
|
|
25902
|
+
"x",
|
|
25903
|
+
"exec",
|
|
25904
|
+
"create",
|
|
25905
|
+
"init",
|
|
25906
|
+
"up",
|
|
25907
|
+
"update",
|
|
25908
|
+
"upgrade",
|
|
25909
|
+
"link",
|
|
25910
|
+
"unlink",
|
|
25911
|
+
"global",
|
|
25912
|
+
"dedupe",
|
|
25913
|
+
"audit",
|
|
25914
|
+
"publish",
|
|
25915
|
+
"pack",
|
|
25916
|
+
"import",
|
|
25917
|
+
"config"
|
|
25918
|
+
]);
|
|
25919
|
+
var SCRIPT_NAME = /^[a-z0-9][a-z0-9:._-]*$/i;
|
|
25808
25920
|
var BASH_DENY = /[;&|`$<>]|\.\.\/|\b(rm|curl|wget|sudo|chmod|chown|mv|dd|kill|eval|sh|bash|node|python)\b/;
|
|
25809
25921
|
function isAllowedBash(cmd) {
|
|
25810
25922
|
const t2 = cmd.trim();
|
|
@@ -25812,13 +25924,27 @@ function isAllowedBash(cmd) {
|
|
|
25812
25924
|
return { ok: false, reason: "empty cmd" };
|
|
25813
25925
|
if (BASH_DENY.test(t2))
|
|
25814
25926
|
return { ok: false, reason: "yasak operatör/binary" };
|
|
25815
|
-
const
|
|
25816
|
-
|
|
25817
|
-
|
|
25818
|
-
|
|
25927
|
+
const tokens = t2.split(/\s+/);
|
|
25928
|
+
const bin = tokens[0] ?? "";
|
|
25929
|
+
if (CHECKER_BINS.has(bin))
|
|
25930
|
+
return { ok: true };
|
|
25931
|
+
if (RUNNER_BINS.has(bin)) {
|
|
25932
|
+
const sub = tokens[1] ?? "";
|
|
25933
|
+
if (sub === "run") {
|
|
25934
|
+
const script = tokens[2] ?? "";
|
|
25935
|
+
if (!SCRIPT_NAME.test(script))
|
|
25936
|
+
return { ok: false, reason: `geçersiz script adı: ${script}` };
|
|
25937
|
+
return { ok: true };
|
|
25938
|
+
}
|
|
25939
|
+
if (bin === "yarn" && sub && !DENY_SUBCMDS.has(sub) && SCRIPT_NAME.test(sub)) {
|
|
25940
|
+
return { ok: true };
|
|
25941
|
+
}
|
|
25942
|
+
return { ok: false, reason: `yasak alt-komut (sadece 'run' izinli): ${bin} ${sub}` };
|
|
25943
|
+
}
|
|
25944
|
+
return { ok: false, reason: `allowlist dışı binary: ${bin}` };
|
|
25819
25945
|
}
|
|
25820
|
-
function isAllowedPath(
|
|
25821
|
-
const abs = isAbsolute(
|
|
25946
|
+
function isAllowedPath(p4, cwd) {
|
|
25947
|
+
const abs = isAbsolute(p4) ? p4 : resolve(cwd, p4);
|
|
25822
25948
|
const rel = relative2(cwd, abs);
|
|
25823
25949
|
if (rel === "" || rel.startsWith("..") || isAbsolute(rel)) {
|
|
25824
25950
|
return { ok: false, reason: "cwd dışı yol" };
|
|
@@ -25835,6 +25961,31 @@ function hasPromptInjection(content) {
|
|
|
25835
25961
|
// src/wizard/agent.ts
|
|
25836
25962
|
var MAX_OBS = 4000;
|
|
25837
25963
|
var pexec = promisify(execFile);
|
|
25964
|
+
function safeEnv() {
|
|
25965
|
+
const keep = [
|
|
25966
|
+
"PATH",
|
|
25967
|
+
"HOME",
|
|
25968
|
+
"USERPROFILE",
|
|
25969
|
+
"TMPDIR",
|
|
25970
|
+
"TEMP",
|
|
25971
|
+
"TMP",
|
|
25972
|
+
"LANG",
|
|
25973
|
+
"LC_ALL",
|
|
25974
|
+
"TERM",
|
|
25975
|
+
"SHELL",
|
|
25976
|
+
"NODE_ENV",
|
|
25977
|
+
"PATHEXT",
|
|
25978
|
+
"SystemRoot",
|
|
25979
|
+
"ComSpec"
|
|
25980
|
+
];
|
|
25981
|
+
const env2 = {};
|
|
25982
|
+
for (const k2 of keep) {
|
|
25983
|
+
const v2 = process.env[k2];
|
|
25984
|
+
if (v2 !== undefined)
|
|
25985
|
+
env2[k2] = v2;
|
|
25986
|
+
}
|
|
25987
|
+
return env2;
|
|
25988
|
+
}
|
|
25838
25989
|
async function defaultRunBash(cmd, cwd) {
|
|
25839
25990
|
const parts = cmd.trim().split(/\s+/);
|
|
25840
25991
|
const bin = parts[0] ?? "";
|
|
@@ -25842,7 +25993,8 @@ async function defaultRunBash(cmd, cwd) {
|
|
|
25842
25993
|
const { stdout: stdout2, stderr } = await pexec(bin, parts.slice(1), {
|
|
25843
25994
|
cwd,
|
|
25844
25995
|
timeout: 120000,
|
|
25845
|
-
maxBuffer: 4 * 1024 * 1024
|
|
25996
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
25997
|
+
env: safeEnv()
|
|
25846
25998
|
});
|
|
25847
25999
|
return { stdout: stdout2, stderr };
|
|
25848
26000
|
} catch (e2) {
|
|
@@ -25857,7 +26009,7 @@ async function executeTool(action, deps) {
|
|
|
25857
26009
|
const g3 = isAllowedPath(action.path, cwd);
|
|
25858
26010
|
if (!g3.ok)
|
|
25859
26011
|
return { ok: false, observation: `read reddedildi: ${g3.reason}` };
|
|
25860
|
-
const abs =
|
|
26012
|
+
const abs = resolveInCwd(action.path, cwd);
|
|
25861
26013
|
if (!existsSync7(abs))
|
|
25862
26014
|
return { ok: false, observation: `dosya yok: ${action.path}` };
|
|
25863
26015
|
let content = readFileSync8(abs, "utf-8");
|
|
@@ -25875,7 +26027,7 @@ async function executeTool(action, deps) {
|
|
|
25875
26027
|
const ga = isAdditiveEdit(action.find, action.replace);
|
|
25876
26028
|
if (!ga.ok)
|
|
25877
26029
|
return { ok: false, observation: `edit reddedildi: ${ga.reason}` };
|
|
25878
|
-
const abs =
|
|
26030
|
+
const abs = resolveInCwd(action.path, cwd);
|
|
25879
26031
|
if (!existsSync7(abs))
|
|
25880
26032
|
return { ok: false, observation: `dosya yok: ${action.path}` };
|
|
25881
26033
|
const src2 = readFileSync8(abs, "utf-8");
|
|
@@ -25911,7 +26063,9 @@ function buildWireSystemPrompt() {
|
|
|
25911
26063
|
"- `find` must be an EXACT, UNIQUE snippet copied from a file you have read (read before edit).",
|
|
25912
26064
|
"- Use the exact provided event_key (snake_case). Wire gurulu.track(...) at the right place and",
|
|
25913
26065
|
" gurulu.identify(...) at the auth point if given.",
|
|
25914
|
-
"- bash
|
|
26066
|
+
"- bash is ONLY for verification: the project's own scripts (`npm run typecheck`, `bun run build`,",
|
|
26067
|
+
" `pnpm run lint`) or a checker binary (`tsc --noEmit`, `biome check`, `eslint .`). Installing or",
|
|
26068
|
+
" fetching packages (`npm install`, `npx`, `bunx`, `pnpm dlx`, `add`, `exec`) is REJECTED by the guard.",
|
|
25915
26069
|
"- After wiring, run the project typecheck/build to verify; if it breaks, fix additively.",
|
|
25916
26070
|
"- When all events are wired and verify passes, emit done{summary}. Keep edits minimal."
|
|
25917
26071
|
].join(`
|
|
@@ -25945,17 +26099,35 @@ async function runWireAgent(client, input, snapshots) {
|
|
|
25945
26099
|
try {
|
|
25946
26100
|
res = await client.agentStep({ messages, first: i2 === 0 });
|
|
25947
26101
|
} catch {
|
|
25948
|
-
return {
|
|
26102
|
+
return {
|
|
26103
|
+
edits,
|
|
26104
|
+
changedFiles: [...changed],
|
|
26105
|
+
summary: "gateway hata",
|
|
26106
|
+
steps: i2,
|
|
26107
|
+
stoppedReason: "error"
|
|
26108
|
+
};
|
|
25949
26109
|
}
|
|
25950
26110
|
if (res.status === "stub") {
|
|
25951
|
-
return {
|
|
26111
|
+
return {
|
|
26112
|
+
edits,
|
|
26113
|
+
changedFiles: [...changed],
|
|
26114
|
+
summary: "AI kullanılamadı",
|
|
26115
|
+
steps: i2,
|
|
26116
|
+
stoppedReason: "stub"
|
|
26117
|
+
};
|
|
25952
26118
|
}
|
|
25953
26119
|
const { action, reasoning } = res.step;
|
|
25954
26120
|
if (action.tool === "done") {
|
|
25955
|
-
return {
|
|
26121
|
+
return {
|
|
26122
|
+
edits,
|
|
26123
|
+
changedFiles: [...changed],
|
|
26124
|
+
summary: action.summary,
|
|
26125
|
+
steps: i2,
|
|
26126
|
+
stoppedReason: "done"
|
|
26127
|
+
};
|
|
25956
26128
|
}
|
|
25957
26129
|
if (action.tool === "edit") {
|
|
25958
|
-
const abs =
|
|
26130
|
+
const abs = resolveInCwd(action.path, input.cwd);
|
|
25959
26131
|
if (!snapshots.has(action.path) && existsSync8(abs)) {
|
|
25960
26132
|
snapshots.set(action.path, readFileSync9(abs, "utf-8"));
|
|
25961
26133
|
}
|
|
@@ -25968,11 +26140,17 @@ async function runWireAgent(client, input, snapshots) {
|
|
|
25968
26140
|
messages.push({ role: "assistant", content: JSON.stringify(res.step) });
|
|
25969
26141
|
messages.push({ role: "user", content: `[${reasoning}] → ${out.observation}` });
|
|
25970
26142
|
}
|
|
25971
|
-
return {
|
|
26143
|
+
return {
|
|
26144
|
+
edits,
|
|
26145
|
+
changedFiles: [...changed],
|
|
26146
|
+
summary: "adım limiti",
|
|
26147
|
+
steps: MAX_STEPS,
|
|
26148
|
+
stoppedReason: "cap"
|
|
26149
|
+
};
|
|
25972
26150
|
}
|
|
25973
26151
|
function restoreSnapshots(cwd, snapshots) {
|
|
25974
26152
|
for (const [rel, content] of snapshots) {
|
|
25975
|
-
writeFileSync7(
|
|
26153
|
+
writeFileSync7(resolveInCwd(rel, cwd), content, "utf-8");
|
|
25976
26154
|
}
|
|
25977
26155
|
}
|
|
25978
26156
|
function unifiedDiff(oldStr, newStr, file, context = 2) {
|
|
@@ -26004,7 +26182,7 @@ function unifiedDiff(oldStr, newStr, file, context = 2) {
|
|
|
26004
26182
|
function formatWireDiff(cwd, snapshots) {
|
|
26005
26183
|
const blocks = [];
|
|
26006
26184
|
for (const [rel, oldContent] of snapshots) {
|
|
26007
|
-
const abs =
|
|
26185
|
+
const abs = resolveInCwd(rel, cwd);
|
|
26008
26186
|
const cur = existsSync8(abs) ? readFileSync9(abs, "utf-8") : "";
|
|
26009
26187
|
if (cur !== oldContent)
|
|
26010
26188
|
blocks.push(unifiedDiff(oldContent, cur, rel));
|
|
@@ -26030,16 +26208,16 @@ var FRAMEWORKS = [
|
|
|
26030
26208
|
"node-server"
|
|
26031
26209
|
];
|
|
26032
26210
|
function bail() {
|
|
26033
|
-
|
|
26211
|
+
p4.cancel("İptal edildi.");
|
|
26034
26212
|
process.exit(0);
|
|
26035
26213
|
}
|
|
26036
26214
|
async function runWizard(opts) {
|
|
26037
26215
|
if (process.stdout.isTTY)
|
|
26038
26216
|
process.stdout.write(banner());
|
|
26039
|
-
|
|
26217
|
+
p4.intro(c3.dim("otonom kurulum başlıyor — auth → workspace → install → wire"));
|
|
26040
26218
|
const TOTAL = 6;
|
|
26041
26219
|
const phase = (n2, label) => {
|
|
26042
|
-
|
|
26220
|
+
p4.log.step(`${c3.dim(`[${n2}/${TOTAL}]`)} ${c3.bold(label)}`);
|
|
26043
26221
|
};
|
|
26044
26222
|
phase(1, "Kimlik doğrulama");
|
|
26045
26223
|
const auth = await ensureAuth({
|
|
@@ -26056,18 +26234,18 @@ async function runWizard(opts) {
|
|
|
26056
26234
|
if (opts.framework && FRAMEWORKS.includes(opts.framework)) {
|
|
26057
26235
|
framework = opts.framework;
|
|
26058
26236
|
} else if (!opts.yes) {
|
|
26059
|
-
const ok = await
|
|
26237
|
+
const ok = await p4.confirm({
|
|
26060
26238
|
message: `Saptanan: ${detected.framework} (${detected.packageManager}). Doğru mu?`
|
|
26061
26239
|
});
|
|
26062
|
-
if (
|
|
26240
|
+
if (p4.isCancel(ok))
|
|
26063
26241
|
bail();
|
|
26064
26242
|
if (!ok) {
|
|
26065
|
-
const choice = await
|
|
26243
|
+
const choice = await p4.select({
|
|
26066
26244
|
message: "Framework seç",
|
|
26067
26245
|
options: FRAMEWORKS.map((f3) => ({ value: f3, label: f3 })),
|
|
26068
26246
|
initialValue: detected.framework
|
|
26069
26247
|
});
|
|
26070
|
-
if (
|
|
26248
|
+
if (p4.isCancel(choice))
|
|
26071
26249
|
bail();
|
|
26072
26250
|
framework = choice;
|
|
26073
26251
|
}
|
|
@@ -26075,9 +26253,10 @@ async function runWizard(opts) {
|
|
|
26075
26253
|
const project = { ...detected, framework };
|
|
26076
26254
|
const plan = buildInstallPlan(project, { writeKey, workspaceId });
|
|
26077
26255
|
const isNode = plan.sdk === "@gurulu/node";
|
|
26256
|
+
const authed = Boolean(auth.apiKey);
|
|
26078
26257
|
let approvedEvents = [];
|
|
26079
26258
|
let identifyHint = null;
|
|
26080
|
-
if (!opts.noAi && detected.hasPackageJson) {
|
|
26259
|
+
if (!opts.noAi && authed && detected.hasPackageJson) {
|
|
26081
26260
|
const ctx = gatherContext({ cwd: opts.cwd });
|
|
26082
26261
|
const aiPlan = await fetchPlan(client, ctx, { framework });
|
|
26083
26262
|
if (aiPlan) {
|
|
@@ -26086,17 +26265,21 @@ async function runWizard(opts) {
|
|
|
26086
26265
|
if (approved)
|
|
26087
26266
|
approvedEvents = approved;
|
|
26088
26267
|
} else {
|
|
26089
|
-
|
|
26268
|
+
p4.log.info("AI planı yok — autocapture + sektör paketi (deterministik floor).");
|
|
26090
26269
|
}
|
|
26091
26270
|
}
|
|
26271
|
+
let featuresResult = { selected: [], registered: false };
|
|
26272
|
+
if (authed) {
|
|
26273
|
+
featuresResult = await runFeatures(client, project, { yes: opts.yes, authed });
|
|
26274
|
+
}
|
|
26092
26275
|
phase(4, "SDK kurulumu");
|
|
26093
26276
|
let installed = false;
|
|
26094
26277
|
if (opts.noInstall) {
|
|
26095
|
-
|
|
26278
|
+
p4.log.info(`SDK kurulumu atlandı — elle: ${plan.installCommand}`);
|
|
26096
26279
|
} else if (!detected.hasPackageJson) {
|
|
26097
|
-
|
|
26280
|
+
p4.log.warn("package.json yok — script tag ile kur: https://cdn.gurulu.io/t.js");
|
|
26098
26281
|
} else {
|
|
26099
|
-
const s2 =
|
|
26282
|
+
const s2 = p4.spinner();
|
|
26100
26283
|
s2.start(`${plan.sdk} kuruluyor (${plan.installCommand})…`);
|
|
26101
26284
|
const res = await execInstall(plan, { cwd: opts.cwd });
|
|
26102
26285
|
if (res.ok) {
|
|
@@ -26117,10 +26300,15 @@ async function runWizard(opts) {
|
|
|
26117
26300
|
const envFile = isNode ? ".env" : ".env.local";
|
|
26118
26301
|
const vars = [];
|
|
26119
26302
|
for (const k2 of plan.envKeys) {
|
|
26120
|
-
if (k2.key.endsWith("_WORKSPACE"))
|
|
26303
|
+
if (k2.key.endsWith("_WORKSPACE")) {
|
|
26121
26304
|
vars.push({ key: k2.key, value: writeKey });
|
|
26122
|
-
else if (k2.key === "GURULU_SECRET_KEY")
|
|
26123
|
-
|
|
26305
|
+
} else if (k2.key === "GURULU_SECRET_KEY") {
|
|
26306
|
+
if (auth.apiKey.startsWith("sk_")) {
|
|
26307
|
+
vars.push({ key: k2.key, value: auth.apiKey });
|
|
26308
|
+
} else {
|
|
26309
|
+
p4.log.warn("GURULU_SECRET_KEY atlandı (login token workspace sk_ anahtarı değil). Dashboard → Settings → API Keys'ten server key oluşturup .env'e elle ekle.");
|
|
26310
|
+
}
|
|
26311
|
+
}
|
|
26124
26312
|
}
|
|
26125
26313
|
const envRes = vars.length > 0 ? writeEnvFile({ cwd: opts.cwd, file: envFile, vars }) : null;
|
|
26126
26314
|
writeProjectScaffold(opts.cwd, {
|
|
@@ -26138,7 +26326,7 @@ async function runWizard(opts) {
|
|
|
26138
26326
|
}
|
|
26139
26327
|
let registeredCount = 0;
|
|
26140
26328
|
if (approvedEvents.length > 0) {
|
|
26141
|
-
const s2 =
|
|
26329
|
+
const s2 = p4.spinner();
|
|
26142
26330
|
s2.start("Yeni eventler registry kuyruguna oneriliyor…");
|
|
26143
26331
|
const res = await registerNewEvents(client, approvedEvents);
|
|
26144
26332
|
registeredCount = res.registered.length;
|
|
@@ -26147,29 +26335,29 @@ async function runWizard(opts) {
|
|
|
26147
26335
|
let wiredCount = 0;
|
|
26148
26336
|
if (approvedEvents.length > 0) {
|
|
26149
26337
|
if (opts.noAi) {
|
|
26150
|
-
|
|
26338
|
+
p4.log.message(`Capture — şu çağrıları ekle:
|
|
26151
26339
|
${captureGuide(approvedEvents, identifyHint, isNode)}`);
|
|
26152
26340
|
} else {
|
|
26153
26341
|
const wireFiles = gatherContext({ cwd: opts.cwd }).files.map((f3) => f3.path);
|
|
26154
26342
|
const snapshots = new Map;
|
|
26155
|
-
const s2 =
|
|
26343
|
+
const s2 = p4.spinner();
|
|
26156
26344
|
s2.start("AI capture wiring (kod düzenleniyor)…");
|
|
26157
26345
|
const outcome = await runWireAgent(client, { cwd: opts.cwd, events: approvedEvents, identifyHint, files: wireFiles }, snapshots);
|
|
26158
26346
|
s2.stop(`wire: ${outcome.changedFiles.length} dosya / ${outcome.steps} adım (${outcome.stoppedReason})`);
|
|
26159
26347
|
if (outcome.changedFiles.length > 0) {
|
|
26160
|
-
|
|
26161
|
-
const keep = opts.yes ? true : await
|
|
26348
|
+
p4.log.message(formatWireDiff(opts.cwd, snapshots));
|
|
26349
|
+
const keep = opts.yes ? true : await p4.confirm({
|
|
26162
26350
|
message: `${outcome.changedFiles.length} dosyadaki wire değişikliklerini tut?`
|
|
26163
26351
|
});
|
|
26164
|
-
if (
|
|
26352
|
+
if (p4.isCancel(keep) || !keep) {
|
|
26165
26353
|
restoreSnapshots(opts.cwd, snapshots);
|
|
26166
|
-
|
|
26167
|
-
|
|
26354
|
+
p4.log.info("Wire geri alındı — capture snippet rehberi:");
|
|
26355
|
+
p4.log.message(captureGuide(approvedEvents, identifyHint, isNode));
|
|
26168
26356
|
} else {
|
|
26169
26357
|
wiredCount = outcome.changedFiles.length;
|
|
26170
26358
|
}
|
|
26171
26359
|
} else {
|
|
26172
|
-
|
|
26360
|
+
p4.log.message(`Capture (AI gömemedi → snippet-göster) — şu çağrıları ekle:
|
|
26173
26361
|
${captureGuide(approvedEvents, identifyHint, isNode)}`);
|
|
26174
26362
|
}
|
|
26175
26363
|
}
|
|
@@ -26188,15 +26376,18 @@ ${captureGuide(approvedEvents, identifyHint, isNode)}`);
|
|
|
26188
26376
|
if (wiredCount > 0)
|
|
26189
26377
|
lines.push(`✓ ${wiredCount} dosya AI ile capture wire edildi`);
|
|
26190
26378
|
}
|
|
26379
|
+
if (featuresResult.registered && featuresResult.selected.length > 0) {
|
|
26380
|
+
lines.push(`✓ özellikler: ${featuresResult.selected.map((f3) => f3.key).join(", ")} kuruldu`);
|
|
26381
|
+
}
|
|
26191
26382
|
lines.push(`✓ .gurulu/config.json${pulled ? " + registry pull" : ""}`);
|
|
26192
|
-
|
|
26383
|
+
p4.note(lines.join(`
|
|
26193
26384
|
`), c3.neon("✦ Değişiklikler"));
|
|
26194
26385
|
if (inj.strategy !== "prepend-entry" || inj.reason === "no-entry") {
|
|
26195
|
-
|
|
26386
|
+
p4.log.info(`Wire: ${inj.wireHint ?? plan.placementHint}`);
|
|
26196
26387
|
if (inj.strategy === "manual")
|
|
26197
|
-
|
|
26388
|
+
p4.log.message(plan.initSnippet);
|
|
26198
26389
|
}
|
|
26199
|
-
|
|
26390
|
+
p4.outro(`${c3.neon("\uD83E\uDD89 Hazır!")} ${c3.dim("Doğrula:")} ${c3.bold("gurulu doctor")} ${c3.dim("·")} ${c3.dim("Dashboard:")} ${c3.cyan("https://dashboard.gurulu.io/app?onboard=done")}`);
|
|
26200
26391
|
}
|
|
26201
26392
|
async function resolveWorkspace(client, authWorkspaceId, opts) {
|
|
26202
26393
|
if (opts.writeKey) {
|
|
@@ -26219,7 +26410,7 @@ async function resolveWorkspace(client, authWorkspaceId, opts) {
|
|
|
26219
26410
|
selected = CREATE;
|
|
26220
26411
|
} else {
|
|
26221
26412
|
const initial = list.find((w2) => w2.workspace_id === authWorkspaceId)?.workspace_id ?? list[0]?.workspace_id ?? CREATE;
|
|
26222
|
-
const choice = await
|
|
26413
|
+
const choice = await p4.select({
|
|
26223
26414
|
message: "Workspace seç",
|
|
26224
26415
|
options: [
|
|
26225
26416
|
...list.map((w2) => ({ value: w2.workspace_id, label: w2.name, hint: w2.slug })),
|
|
@@ -26227,26 +26418,26 @@ async function resolveWorkspace(client, authWorkspaceId, opts) {
|
|
|
26227
26418
|
],
|
|
26228
26419
|
initialValue: initial
|
|
26229
26420
|
});
|
|
26230
|
-
if (
|
|
26421
|
+
if (p4.isCancel(choice))
|
|
26231
26422
|
bail();
|
|
26232
26423
|
selected = choice;
|
|
26233
26424
|
}
|
|
26234
26425
|
if (selected === CREATE) {
|
|
26235
|
-
const name = await
|
|
26426
|
+
const name = await p4.text({
|
|
26236
26427
|
message: "Workspace adı",
|
|
26237
26428
|
placeholder: "My App",
|
|
26238
26429
|
validate: (v2) => v2.trim() ? undefined : "gerekli"
|
|
26239
26430
|
});
|
|
26240
|
-
if (
|
|
26431
|
+
if (p4.isCancel(name))
|
|
26241
26432
|
bail();
|
|
26242
|
-
const domain = await
|
|
26433
|
+
const domain = await p4.text({
|
|
26243
26434
|
message: "Domain",
|
|
26244
26435
|
placeholder: "example.com",
|
|
26245
26436
|
validate: (v2) => v2.trim().length >= 3 ? undefined : "geçerli domain gerekli"
|
|
26246
26437
|
});
|
|
26247
|
-
if (
|
|
26438
|
+
if (p4.isCancel(domain))
|
|
26248
26439
|
bail();
|
|
26249
|
-
const s2 =
|
|
26440
|
+
const s2 = p4.spinner();
|
|
26250
26441
|
s2.start("Workspace oluşturuluyor…");
|
|
26251
26442
|
const created = await client.createWorkspace({
|
|
26252
26443
|
name: String(name).trim(),
|
|
@@ -26306,11 +26497,19 @@ var wizardArgs = {
|
|
|
26306
26497
|
framework: { type: "string", description: "Framework override (auto-detect yerine)" },
|
|
26307
26498
|
install: { type: "boolean", description: "SDK install (--no-install ile atla)", default: true },
|
|
26308
26499
|
pull: { type: "boolean", description: "İlk registry pull (--no-pull ile atla)", default: true },
|
|
26309
|
-
ai: {
|
|
26500
|
+
ai: {
|
|
26501
|
+
type: "boolean",
|
|
26502
|
+
description: "AI Plan/wire fazı (--no-ai ile atla → floor)",
|
|
26503
|
+
default: true
|
|
26504
|
+
},
|
|
26310
26505
|
yes: { type: "boolean", description: "Onayları otomatik geç" },
|
|
26311
26506
|
ci: { type: "boolean", description: "Non-interaktif (api-key + workspace zorunlu)" }
|
|
26312
26507
|
};
|
|
26313
26508
|
async function runWizardFromArgs(args) {
|
|
26509
|
+
if (args.ci && (!args["api-key"] || !args.workspace)) {
|
|
26510
|
+
console.error("[gurulu] --ci için --api-key <sk_...> ve --workspace <uuid> zorunlu (non-interaktif kurulum).");
|
|
26511
|
+
process.exit(1);
|
|
26512
|
+
}
|
|
26314
26513
|
const opts = {
|
|
26315
26514
|
cwd: process.cwd(),
|
|
26316
26515
|
noInstall: args.install === false,
|
|
@@ -26344,7 +26543,7 @@ var initCmd = defineCommand({
|
|
|
26344
26543
|
// src/lib/editor-mcp.ts
|
|
26345
26544
|
import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync10, writeFileSync as writeFileSync9 } from "node:fs";
|
|
26346
26545
|
import { homedir as homedir2 } from "node:os";
|
|
26347
|
-
import { dirname as dirname4, join as
|
|
26546
|
+
import { dirname as dirname4, join as join9 } from "node:path";
|
|
26348
26547
|
var SERVER_NAME = "gurulu";
|
|
26349
26548
|
function buildMcpServerConfig(creds) {
|
|
26350
26549
|
return {
|
|
@@ -26358,14 +26557,14 @@ function buildMcpServerConfig(creds) {
|
|
|
26358
26557
|
};
|
|
26359
26558
|
}
|
|
26360
26559
|
var EDITORS = {
|
|
26361
|
-
cursor: { path: () =>
|
|
26362
|
-
claude: { path: () =>
|
|
26560
|
+
cursor: { path: () => join9(homedir2(), ".cursor", "mcp.json"), key: "mcpServers", label: "Cursor" },
|
|
26561
|
+
claude: { path: () => join9(homedir2(), ".claude.json"), key: "mcpServers", label: "Claude Code" },
|
|
26363
26562
|
windsurf: {
|
|
26364
|
-
path: () =>
|
|
26563
|
+
path: () => join9(homedir2(), ".codeium", "windsurf", "mcp_config.json"),
|
|
26365
26564
|
key: "mcpServers",
|
|
26366
26565
|
label: "Windsurf"
|
|
26367
26566
|
},
|
|
26368
|
-
vscode: { path: (cwd) =>
|
|
26567
|
+
vscode: { path: (cwd) => join9(cwd, ".vscode", "mcp.json"), key: "servers", label: "VS Code" }
|
|
26369
26568
|
};
|
|
26370
26569
|
function mergeMcpConfig(existing, serverConfig, key) {
|
|
26371
26570
|
const servers = existing[key] ?? {};
|
|
@@ -26561,9 +26760,9 @@ var pushCmd = defineCommand({
|
|
|
26561
26760
|
// src/commands/uninstall.ts
|
|
26562
26761
|
import { execFile as execFile2 } from "node:child_process";
|
|
26563
26762
|
import { existsSync as existsSync11, readFileSync as readFileSync11, rmSync, writeFileSync as writeFileSync10 } from "node:fs";
|
|
26564
|
-
import { join as
|
|
26763
|
+
import { join as join10 } from "node:path";
|
|
26565
26764
|
import { promisify as promisify2 } from "node:util";
|
|
26566
|
-
import * as
|
|
26765
|
+
import * as p5 from "@clack/prompts";
|
|
26567
26766
|
var pexec2 = promisify2(execFile2);
|
|
26568
26767
|
var ENV_FILES = [".env.local", ".env"];
|
|
26569
26768
|
var GURULU_PREFIXES = ["GURULU_", "NEXT_PUBLIC_GURULU", "VITE_GURULU"];
|
|
@@ -26590,23 +26789,23 @@ var uninstallCmd = defineCommand({
|
|
|
26590
26789
|
const config = readProjectConfig(cwd);
|
|
26591
26790
|
const detected = detectProject(cwd);
|
|
26592
26791
|
const pkg = config?.sdk_preference === "node" ? "@gurulu/node" : "@gurulu/web";
|
|
26593
|
-
|
|
26594
|
-
|
|
26792
|
+
p5.intro("Gurulu uninstall");
|
|
26793
|
+
p5.note([
|
|
26595
26794
|
`• SDK kaldır: ${pkg} (${detected.packageManager})`,
|
|
26596
26795
|
`• env temizle: ${ENV_FILES.join(", ")} (GURULU_* anahtarları)`,
|
|
26597
26796
|
"• .gurulu/ dizinini sil"
|
|
26598
26797
|
].join(`
|
|
26599
26798
|
`), "Şunlar yapılacak");
|
|
26600
26799
|
if (!args.yes) {
|
|
26601
|
-
const ok = await
|
|
26602
|
-
if (
|
|
26603
|
-
|
|
26800
|
+
const ok = await p5.confirm({ message: "Devam edilsin mi?" });
|
|
26801
|
+
if (p5.isCancel(ok) || !ok) {
|
|
26802
|
+
p5.cancel("İptal.");
|
|
26604
26803
|
process.exit(0);
|
|
26605
26804
|
}
|
|
26606
26805
|
}
|
|
26607
26806
|
if (!args["no-deps"] && detected.hasPackageJson) {
|
|
26608
26807
|
const { bin, args: a2 } = removeCmd(detected.packageManager, pkg);
|
|
26609
|
-
const s2 =
|
|
26808
|
+
const s2 = p5.spinner();
|
|
26610
26809
|
s2.start(`${pkg} kaldırılıyor…`);
|
|
26611
26810
|
try {
|
|
26612
26811
|
await pexec2(bin, a2, { cwd, timeout: 120000 });
|
|
@@ -26617,7 +26816,7 @@ var uninstallCmd = defineCommand({
|
|
|
26617
26816
|
}
|
|
26618
26817
|
const cleaned = [];
|
|
26619
26818
|
for (const f3 of ENV_FILES) {
|
|
26620
|
-
const abs =
|
|
26819
|
+
const abs = join10(cwd, f3);
|
|
26621
26820
|
if (!existsSync11(abs))
|
|
26622
26821
|
continue;
|
|
26623
26822
|
const { content, removed } = removeEnvKeys(readFileSync11(abs, "utf-8"), GURULU_PREFIXES);
|
|
@@ -26626,15 +26825,15 @@ var uninstallCmd = defineCommand({
|
|
|
26626
26825
|
cleaned.push(`${f3} (-${removed.length})`);
|
|
26627
26826
|
}
|
|
26628
26827
|
}
|
|
26629
|
-
const guruluDir =
|
|
26828
|
+
const guruluDir = join10(cwd, ".gurulu");
|
|
26630
26829
|
if (existsSync11(guruluDir))
|
|
26631
26830
|
rmSync(guruluDir, { recursive: true, force: true });
|
|
26632
|
-
|
|
26831
|
+
p5.outro(`Kaldırıldı. env: ${cleaned.join(", ") || "değişiklik yok"} · .gurulu silindi. (Koddaki init/track çağrılarını elle çıkar.)`);
|
|
26633
26832
|
}
|
|
26634
26833
|
});
|
|
26635
26834
|
|
|
26636
26835
|
// src/index.ts
|
|
26637
|
-
var VERSION = "1.2.
|
|
26836
|
+
var VERSION = "1.2.2";
|
|
26638
26837
|
var mainCmd = defineCommand({
|
|
26639
26838
|
meta: {
|
|
26640
26839
|
name: "gurulu",
|