@gurulu/cli 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js CHANGED
@@ -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
- const fs = __require("node:fs");
24592
- fs.chmodSync(path, 384);
24591
+ chmodSync(path, 384);
24593
24592
  } catch {}
24594
24593
  }
24595
24594
  function findCredentialForWorkspace(workspaceId) {
@@ -25121,6 +25120,145 @@ import { existsSync as existsSync9, mkdirSync as mkdirSync2, writeFileSync as wr
25121
25120
  import { dirname as dirname3 } from "node:path";
25122
25121
  import * as p3 from "@clack/prompts";
25123
25122
 
25123
+ // src/commands/pull.ts
25124
+ import { writeFileSync as writeFileSync3 } from "node:fs";
25125
+
25126
+ // src/lib/codegen.ts
25127
+ function enumKeyName(key) {
25128
+ return key.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
25129
+ }
25130
+ function escapePropName(name) {
25131
+ if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))
25132
+ return name;
25133
+ return `'${name.replace(/'/g, "\\'")}'`;
25134
+ }
25135
+ function tsType(t2) {
25136
+ switch (t2) {
25137
+ case "string":
25138
+ return "string";
25139
+ case "number":
25140
+ return "number";
25141
+ case "boolean":
25142
+ return "boolean";
25143
+ case "date":
25144
+ return "string | Date";
25145
+ case "array":
25146
+ return "unknown[]";
25147
+ case "json":
25148
+ return "Record<string, unknown>";
25149
+ default:
25150
+ return "unknown";
25151
+ }
25152
+ }
25153
+ function generateTypescript(manifest) {
25154
+ const banner = `// Generated by @gurulu/cli — DO NOT EDIT
25155
+ // Workspace: ${manifest.workspace_id} | Manifest version: ${manifest.manifest_version} | Schema: v${manifest.schema_version}
25156
+ // Generated: ${manifest.exported_at}
25157
+ // Events: ${manifest.events.length}
25158
+
25159
+ `;
25160
+ if (manifest.events.length === 0) {
25161
+ return `${banner}export const GuruluEvents = {} as const;
25162
+ export type GuruluEvents = (typeof GuruluEvents)[keyof typeof GuruluEvents];
25163
+
25164
+ export type EventProperties = Record<never, never>;
25165
+
25166
+ export declare function track<E extends GuruluEvents>(
25167
+ event: E,
25168
+ properties: EventProperties[E],
25169
+ ): Promise<void>;
25170
+ `;
25171
+ }
25172
+ const enumLines = manifest.events.map((e2) => ` ${enumKeyName(e2.key)}: '${e2.key}',`);
25173
+ const mapLines = manifest.events.map((e2) => {
25174
+ const props = (e2.properties ?? []).slice().sort((a2, b2) => (a2.position ?? 0) - (b2.position ?? 0)).map((p) => {
25175
+ const optional = p.required ? "" : "?";
25176
+ const comment = p.format ? ` // format: ${p.format}` : "";
25177
+ return ` ${escapePropName(p.name)}${optional}: ${tsType(p.type)};${comment}`;
25178
+ }).join(`
25179
+ `);
25180
+ return ` '${e2.key}': {
25181
+ ${props || " // no properties"}
25182
+ };`;
25183
+ });
25184
+ return `${banner}export const GuruluEvents = {
25185
+ ${enumLines.join(`
25186
+ `)}
25187
+ } as const;
25188
+ export type GuruluEvents = (typeof GuruluEvents)[keyof typeof GuruluEvents];
25189
+
25190
+ export interface EventProperties {
25191
+ ${mapLines.join(`
25192
+ `)}
25193
+ }
25194
+
25195
+ /**
25196
+ * Typed track — compile-time validation against pulled registry.
25197
+ * Runtime implementation: @gurulu/web or @gurulu/node.
25198
+ */
25199
+ export declare function track<E extends GuruluEvents>(
25200
+ event: E,
25201
+ properties: EventProperties[E],
25202
+ ): Promise<void>;
25203
+ `;
25204
+ }
25205
+ function generateManifestLock(manifest) {
25206
+ return `${manifest.manifest_version}
25207
+ `;
25208
+ }
25209
+
25210
+ // src/commands/pull.ts
25211
+ async function runPull(opts = {}) {
25212
+ const cwd = opts.cwd ?? process.cwd();
25213
+ const project = readProjectConfig(cwd);
25214
+ if (!project) {
25215
+ throw new Error("no .gurulu/config.json — run `gurulu init` first");
25216
+ }
25217
+ const cred = resolveActiveCredential({
25218
+ workspaceId: opts.workspaceId ?? project.workspace_id,
25219
+ cwd
25220
+ });
25221
+ if (!cred) {
25222
+ throw new Error("no credentials — run `gurulu login` or set GURULU_API_KEY env (workspace sk_xxx)");
25223
+ }
25224
+ const client = new ApiClient({
25225
+ endpoint: project.endpoint ?? cred.endpoint,
25226
+ apiKey: cred.apiKey
25227
+ });
25228
+ const manifest = await client.get("/v1/cli/registry/pull", {
25229
+ workspace_id: cred.workspaceId
25230
+ });
25231
+ writeFileSync3(projectRegistryPath(cwd), `${JSON.stringify(manifest, null, 2)}
25232
+ `, "utf-8");
25233
+ const ts = generateTypescript(manifest);
25234
+ writeFileSync3(projectGeneratedPath(cwd), ts, "utf-8");
25235
+ writeFileSync3(projectManifestLockPath(cwd), generateManifestLock(manifest), "utf-8");
25236
+ return manifest;
25237
+ }
25238
+ var pullCmd = defineCommand({
25239
+ meta: {
25240
+ name: "pull",
25241
+ description: "Pull registry snapshot + code-gen typed events"
25242
+ },
25243
+ args: {
25244
+ workspace: { type: "string", description: "Workspace ID (override project config)" }
25245
+ },
25246
+ async run({ args }) {
25247
+ try {
25248
+ const manifest = await runPull({
25249
+ ...args.workspace ? { workspaceId: String(args.workspace) } : {}
25250
+ });
25251
+ console.log(`[gurulu] pulled ${manifest.events.length} events (manifest ${manifest.manifest_version})`);
25252
+ console.log(` → ${projectRegistryPath()}`);
25253
+ console.log(` → ${projectGeneratedPath()}`);
25254
+ console.log(` → ${projectManifestLockPath()}`);
25255
+ } catch (err) {
25256
+ console.error(`[gurulu] pull failed: ${err instanceof Error ? err.message : String(err)}`);
25257
+ process.exit(1);
25258
+ }
25259
+ }
25260
+ });
25261
+
25124
25262
  // src/lib/detect.ts
25125
25263
  import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
25126
25264
  import { dirname as dirname2, join as join5, parse } from "node:path";
@@ -25223,7 +25361,7 @@ function detectProject(dir) {
25223
25361
  }
25224
25362
 
25225
25363
  // src/lib/env-file.ts
25226
- import { appendFileSync, existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "node:fs";
25364
+ import { appendFileSync, existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "node:fs";
25227
25365
  import { join as join6 } from "node:path";
25228
25366
  var ENV_KEY_LINE = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/;
25229
25367
  function parseEnvKeys(content) {
@@ -25261,7 +25399,7 @@ function writeEnvFile(opts) {
25261
25399
  const block = opts.vars.filter((v2) => added.includes(v2.key)).map((v2) => `${v2.key}=${formatValue(v2.value)}`).join(`
25262
25400
  `);
25263
25401
  if (existing === "") {
25264
- writeFileSync3(envPath, `# Gurulu
25402
+ writeFileSync4(envPath, `# Gurulu
25265
25403
  ${block}
25266
25404
  `, "utf-8");
25267
25405
  } else {
@@ -25286,7 +25424,7 @@ function ensureGitignored(cwd, file) {
25286
25424
  if (covered)
25287
25425
  return false;
25288
25426
  if (content === "") {
25289
- writeFileSync3(giPath, `# Gurulu
25427
+ writeFileSync4(giPath, `# Gurulu
25290
25428
  ${file}
25291
25429
  `, "utf-8");
25292
25430
  } else {
@@ -25376,7 +25514,7 @@ async function execInstall(plan, opts) {
25376
25514
  }
25377
25515
 
25378
25516
  // src/lib/inject.ts
25379
- import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
25517
+ import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
25380
25518
  import { join as join7 } from "node:path";
25381
25519
  var DIRECTIVE = /^\s*(['"])use [a-z ]+\1;?\s*$/;
25382
25520
  function lastImportEnd(lines, start) {
@@ -25498,7 +25636,7 @@ function applyInjection(opts) {
25498
25636
  const src2 = readFileSync6(abs, "utf-8");
25499
25637
  const res = injectInit(src2, webPieces(workspaceKey, detected.framework));
25500
25638
  if (res.changed)
25501
- writeFileSync4(abs, res.output, "utf-8");
25639
+ writeFileSync5(abs, res.output, "utf-8");
25502
25640
  return { strategy, changed: res.changed, file: entry, reason: res.reason };
25503
25641
  }
25504
25642
  if (strategy === "create-module") {
@@ -25507,7 +25645,7 @@ function applyInjection(opts) {
25507
25645
  if (existsSync6(abs)) {
25508
25646
  return { strategy, changed: false, file: rel, reason: "already-present", wireHint: opts.placementHint };
25509
25647
  }
25510
- writeFileSync4(abs, `${opts.snippet}
25648
+ writeFileSync5(abs, `${opts.snippet}
25511
25649
  `, "utf-8");
25512
25650
  return { strategy, changed: true, file: rel, reason: "created", wireHint: opts.placementHint };
25513
25651
  }
@@ -25692,145 +25830,57 @@ function buildInstallPlan(detected, ctx = {}) {
25692
25830
  };
25693
25831
  }
25694
25832
 
25695
- // src/commands/pull.ts
25696
- import { writeFileSync as writeFileSync5 } from "node:fs";
25697
-
25698
- // src/lib/codegen.ts
25699
- function enumKeyName(key) {
25700
- return key.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
25833
+ // src/lib/ui.ts
25834
+ var noColor = Boolean(process.env.NO_COLOR) || process.env.TERM === "dumb" || !process.stdout.isTTY;
25835
+ function wrap(open, close) {
25836
+ return (s2) => noColor ? s2 : `\x1B[${open}m${s2}\x1B[${close}m`;
25701
25837
  }
25702
- function escapePropName(name) {
25703
- if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))
25704
- return name;
25705
- return `'${name.replace(/'/g, "\\'")}'`;
25838
+ function fg(code) {
25839
+ return (s2) => noColor ? s2 : `\x1B[38;5;${code}m${s2}\x1B[39m`;
25706
25840
  }
25707
- function tsType(t2) {
25708
- switch (t2) {
25709
- case "string":
25710
- return "string";
25711
- case "number":
25712
- return "number";
25713
- case "boolean":
25714
- return "boolean";
25715
- case "date":
25716
- return "string | Date";
25717
- case "array":
25718
- return "unknown[]";
25719
- case "json":
25720
- return "Record<string, unknown>";
25721
- default:
25722
- return "unknown";
25723
- }
25841
+ var c3 = {
25842
+ bold: wrap("1", "22"),
25843
+ dim: wrap("2", "22"),
25844
+ italic: wrap("3", "23"),
25845
+ underline: wrap("4", "24"),
25846
+ reset: (s2) => s2,
25847
+ neon: fg(120),
25848
+ green: fg(78),
25849
+ cyan: fg(45),
25850
+ mint: fg(85),
25851
+ violet: fg(141),
25852
+ pink: fg(212),
25853
+ gray: fg(245),
25854
+ slate: fg(240)
25855
+ };
25856
+ var GRAD = [120, 84, 85, 86, 80, 44, 45, 51];
25857
+ function gradient(text) {
25858
+ if (noColor)
25859
+ return text;
25860
+ const chars = [...text];
25861
+ return chars.map((ch, i2) => {
25862
+ if (ch === " ")
25863
+ return ch;
25864
+ const idx = Math.floor(i2 / Math.max(chars.length - 1, 1) * (GRAD.length - 1));
25865
+ const code = GRAD[idx] ?? GRAD[0];
25866
+ return `\x1B[38;5;${code}m${ch}`;
25867
+ }).join("") + "\x1B[39m";
25724
25868
  }
25725
- function generateTypescript(manifest) {
25726
- const banner = `// Generated by @gurulu/cli DO NOT EDIT
25727
- // Workspace: ${manifest.workspace_id} | Manifest version: ${manifest.manifest_version} | Schema: v${manifest.schema_version}
25728
- // Generated: ${manifest.exported_at}
25729
- // Events: ${manifest.events.length}
25730
-
25731
- `;
25732
- if (manifest.events.length === 0) {
25733
- return `${banner}export const GuruluEvents = {} as const;
25734
- export type GuruluEvents = (typeof GuruluEvents)[keyof typeof GuruluEvents];
25735
-
25736
- export type EventProperties = Record<never, never>;
25737
-
25738
- export declare function track<E extends GuruluEvents>(
25739
- event: E,
25740
- properties: EventProperties[E],
25741
- ): Promise<void>;
25742
- `;
25743
- }
25744
- const enumLines = manifest.events.map((e2) => ` ${enumKeyName(e2.key)}: '${e2.key}',`);
25745
- const mapLines = manifest.events.map((e2) => {
25746
- const props = (e2.properties ?? []).slice().sort((a2, b2) => (a2.position ?? 0) - (b2.position ?? 0)).map((p) => {
25747
- const optional = p.required ? "" : "?";
25748
- const comment = p.format ? ` // format: ${p.format}` : "";
25749
- return ` ${escapePropName(p.name)}${optional}: ${tsType(p.type)};${comment}`;
25750
- }).join(`
25751
- `);
25752
- return ` '${e2.key}': {
25753
- ${props || " // no properties"}
25754
- };`;
25755
- });
25756
- return `${banner}export const GuruluEvents = {
25757
- ${enumLines.join(`
25758
- `)}
25759
- } as const;
25760
- export type GuruluEvents = (typeof GuruluEvents)[keyof typeof GuruluEvents];
25761
-
25762
- export interface EventProperties {
25763
- ${mapLines.join(`
25869
+ var OWL = [" ╲▏▔▔▔▔▏╱ ", " ▕ ◉ ◉ ▏ ", " ▕ ╲╱ ▏ ", " ╲▁▁▁▁╱ "];
25870
+ var WORD = ["█▀▀ █▀▄ █ █ █", "█▄█ █▄█ █▀▄ █▄█ █▄▄ █▄█"];
25871
+ function banner(subtitle = "truth layer · otonom kurulum") {
25872
+ if (noColor)
25873
+ return `\uD83E\uDD89 Gurulu — ${subtitle}`;
25874
+ const owlC = OWL.map((l2) => c3.neon(l2));
25875
+ const wordC = WORD.map((l2) => gradient(l2));
25876
+ const right = ["", wordC[0] ?? "", wordC[1] ?? "", c3.gray(subtitle)];
25877
+ const lines = owlC.map((owl, i2) => right[i2] ? `${owl} ${right[i2]}` : owl);
25878
+ return `
25879
+ ${lines.join(`
25764
25880
  `)}
25765
- }
25766
-
25767
- /**
25768
- * Typed track — compile-time validation against pulled registry.
25769
- * Runtime implementation: @gurulu/web or @gurulu/node.
25770
- */
25771
- export declare function track<E extends GuruluEvents>(
25772
- event: E,
25773
- properties: EventProperties[E],
25774
- ): Promise<void>;
25775
- `;
25776
- }
25777
- function generateManifestLock(manifest) {
25778
- return `${manifest.manifest_version}
25779
25881
  `;
25780
25882
  }
25781
25883
 
25782
- // src/commands/pull.ts
25783
- async function runPull(opts = {}) {
25784
- const cwd = opts.cwd ?? process.cwd();
25785
- const project = readProjectConfig(cwd);
25786
- if (!project) {
25787
- throw new Error("no .gurulu/config.json — run `gurulu init` first");
25788
- }
25789
- const cred = resolveActiveCredential({
25790
- workspaceId: opts.workspaceId ?? project.workspace_id,
25791
- cwd
25792
- });
25793
- if (!cred) {
25794
- throw new Error("no credentials — run `gurulu login` or set GURULU_API_KEY env (workspace sk_xxx)");
25795
- }
25796
- const client = new ApiClient({
25797
- endpoint: project.endpoint ?? cred.endpoint,
25798
- apiKey: cred.apiKey
25799
- });
25800
- const manifest = await client.get("/v1/cli/registry/pull", {
25801
- workspace_id: cred.workspaceId
25802
- });
25803
- writeFileSync5(projectRegistryPath(cwd), `${JSON.stringify(manifest, null, 2)}
25804
- `, "utf-8");
25805
- const ts = generateTypescript(manifest);
25806
- writeFileSync5(projectGeneratedPath(cwd), ts, "utf-8");
25807
- writeFileSync5(projectManifestLockPath(cwd), generateManifestLock(manifest), "utf-8");
25808
- return manifest;
25809
- }
25810
- var pullCmd = defineCommand({
25811
- meta: {
25812
- name: "pull",
25813
- description: "Pull registry snapshot + code-gen typed events"
25814
- },
25815
- args: {
25816
- workspace: { type: "string", description: "Workspace ID (override project config)" }
25817
- },
25818
- async run({ args }) {
25819
- try {
25820
- const manifest = await runPull({
25821
- ...args.workspace ? { workspaceId: String(args.workspace) } : {}
25822
- });
25823
- console.log(`[gurulu] pulled ${manifest.events.length} events (manifest ${manifest.manifest_version})`);
25824
- console.log(` → ${projectRegistryPath()}`);
25825
- console.log(` → ${projectGeneratedPath()}`);
25826
- console.log(` → ${projectManifestLockPath()}`);
25827
- } catch (err) {
25828
- console.error(`[gurulu] pull failed: ${err instanceof Error ? err.message : String(err)}`);
25829
- process.exit(1);
25830
- }
25831
- }
25832
- });
25833
-
25834
25884
  // src/wizard/apply.ts
25835
25885
  async function registerNewEvents(client, events) {
25836
25886
  const registered = [];
@@ -26141,16 +26191,17 @@ async function renderPlan(plan) {
26141
26191
 
26142
26192
  // src/wizard/wire.ts
26143
26193
  import { existsSync as existsSync8, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "node:fs";
26144
- import { join as join10 } from "node:path";
26145
26194
 
26146
26195
  // src/wizard/agent.ts
26147
26196
  import { execFile } from "node:child_process";
26148
26197
  import { existsSync as existsSync7, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "node:fs";
26149
- import { join as join9 } from "node:path";
26150
26198
  import { promisify } from "node:util";
26151
26199
 
26152
26200
  // src/wizard/guard.ts
26153
26201
  import { basename, isAbsolute, relative as relative2, resolve } from "node:path";
26202
+ function resolveInCwd(p3, cwd) {
26203
+ return isAbsolute(p3) ? p3 : resolve(cwd, p3);
26204
+ }
26154
26205
  function isAdditiveEdit(find, replace) {
26155
26206
  if (find.length === 0)
26156
26207
  return { ok: false, reason: "empty find" };
@@ -26161,22 +26212,45 @@ function isAdditiveEdit(find, replace) {
26161
26212
  return { ok: false, reason: "no-op edit (replace === find)" };
26162
26213
  return { ok: true };
26163
26214
  }
26164
- var BASH_ALLOW_BINS = new Set([
26165
- "bun",
26166
- "bunx",
26167
- "npm",
26168
- "npx",
26169
- "pnpm",
26170
- "yarn",
26215
+ var CHECKER_BINS = new Set([
26171
26216
  "tsc",
26172
26217
  "tsgo",
26218
+ "vue-tsc",
26219
+ "svelte-check",
26173
26220
  "biome",
26174
26221
  "eslint",
26175
26222
  "prettier",
26176
- "vue-tsc",
26177
- "svelte-check",
26178
26223
  "astro"
26179
26224
  ]);
26225
+ var RUNNER_BINS = new Set(["bun", "npm", "pnpm", "yarn"]);
26226
+ var DENY_SUBCMDS = new Set([
26227
+ "install",
26228
+ "i",
26229
+ "add",
26230
+ "remove",
26231
+ "rm",
26232
+ "uninstall",
26233
+ "un",
26234
+ "ci",
26235
+ "dlx",
26236
+ "x",
26237
+ "exec",
26238
+ "create",
26239
+ "init",
26240
+ "up",
26241
+ "update",
26242
+ "upgrade",
26243
+ "link",
26244
+ "unlink",
26245
+ "global",
26246
+ "dedupe",
26247
+ "audit",
26248
+ "publish",
26249
+ "pack",
26250
+ "import",
26251
+ "config"
26252
+ ]);
26253
+ var SCRIPT_NAME = /^[a-z0-9][a-z0-9:._-]*$/i;
26180
26254
  var BASH_DENY = /[;&|`$<>]|\.\.\/|\b(rm|curl|wget|sudo|chmod|chown|mv|dd|kill|eval|sh|bash|node|python)\b/;
26181
26255
  function isAllowedBash(cmd) {
26182
26256
  const t2 = cmd.trim();
@@ -26184,10 +26258,24 @@ function isAllowedBash(cmd) {
26184
26258
  return { ok: false, reason: "empty cmd" };
26185
26259
  if (BASH_DENY.test(t2))
26186
26260
  return { ok: false, reason: "yasak operatör/binary" };
26187
- const bin = t2.split(/\s+/)[0] ?? "";
26188
- if (!BASH_ALLOW_BINS.has(bin))
26189
- return { ok: false, reason: `allowlist dışı binary: ${bin}` };
26190
- return { ok: true };
26261
+ const tokens = t2.split(/\s+/);
26262
+ const bin = tokens[0] ?? "";
26263
+ if (CHECKER_BINS.has(bin))
26264
+ return { ok: true };
26265
+ if (RUNNER_BINS.has(bin)) {
26266
+ const sub = tokens[1] ?? "";
26267
+ if (sub === "run") {
26268
+ const script = tokens[2] ?? "";
26269
+ if (!SCRIPT_NAME.test(script))
26270
+ return { ok: false, reason: `geçersiz script adı: ${script}` };
26271
+ return { ok: true };
26272
+ }
26273
+ if (bin === "yarn" && sub && !DENY_SUBCMDS.has(sub) && SCRIPT_NAME.test(sub)) {
26274
+ return { ok: true };
26275
+ }
26276
+ return { ok: false, reason: `yasak alt-komut (sadece 'run' izinli): ${bin} ${sub}` };
26277
+ }
26278
+ return { ok: false, reason: `allowlist dışı binary: ${bin}` };
26191
26279
  }
26192
26280
  function isAllowedPath(p3, cwd) {
26193
26281
  const abs = isAbsolute(p3) ? p3 : resolve(cwd, p3);
@@ -26207,6 +26295,31 @@ function hasPromptInjection(content) {
26207
26295
  // src/wizard/agent.ts
26208
26296
  var MAX_OBS = 4000;
26209
26297
  var pexec = promisify(execFile);
26298
+ function safeEnv() {
26299
+ const keep = [
26300
+ "PATH",
26301
+ "HOME",
26302
+ "USERPROFILE",
26303
+ "TMPDIR",
26304
+ "TEMP",
26305
+ "TMP",
26306
+ "LANG",
26307
+ "LC_ALL",
26308
+ "TERM",
26309
+ "SHELL",
26310
+ "NODE_ENV",
26311
+ "PATHEXT",
26312
+ "SystemRoot",
26313
+ "ComSpec"
26314
+ ];
26315
+ const env2 = {};
26316
+ for (const k2 of keep) {
26317
+ const v2 = process.env[k2];
26318
+ if (v2 !== undefined)
26319
+ env2[k2] = v2;
26320
+ }
26321
+ return env2;
26322
+ }
26210
26323
  async function defaultRunBash(cmd, cwd) {
26211
26324
  const parts = cmd.trim().split(/\s+/);
26212
26325
  const bin = parts[0] ?? "";
@@ -26214,7 +26327,8 @@ async function defaultRunBash(cmd, cwd) {
26214
26327
  const { stdout: stdout2, stderr } = await pexec(bin, parts.slice(1), {
26215
26328
  cwd,
26216
26329
  timeout: 120000,
26217
- maxBuffer: 4 * 1024 * 1024
26330
+ maxBuffer: 4 * 1024 * 1024,
26331
+ env: safeEnv()
26218
26332
  });
26219
26333
  return { stdout: stdout2, stderr };
26220
26334
  } catch (e2) {
@@ -26229,7 +26343,7 @@ async function executeTool(action, deps) {
26229
26343
  const g3 = isAllowedPath(action.path, cwd);
26230
26344
  if (!g3.ok)
26231
26345
  return { ok: false, observation: `read reddedildi: ${g3.reason}` };
26232
- const abs = join9(cwd, action.path);
26346
+ const abs = resolveInCwd(action.path, cwd);
26233
26347
  if (!existsSync7(abs))
26234
26348
  return { ok: false, observation: `dosya yok: ${action.path}` };
26235
26349
  let content = readFileSync8(abs, "utf-8");
@@ -26247,7 +26361,7 @@ async function executeTool(action, deps) {
26247
26361
  const ga = isAdditiveEdit(action.find, action.replace);
26248
26362
  if (!ga.ok)
26249
26363
  return { ok: false, observation: `edit reddedildi: ${ga.reason}` };
26250
- const abs = join9(cwd, action.path);
26364
+ const abs = resolveInCwd(action.path, cwd);
26251
26365
  if (!existsSync7(abs))
26252
26366
  return { ok: false, observation: `dosya yok: ${action.path}` };
26253
26367
  const src2 = readFileSync8(abs, "utf-8");
@@ -26283,7 +26397,9 @@ function buildWireSystemPrompt() {
26283
26397
  "- `find` must be an EXACT, UNIQUE snippet copied from a file you have read (read before edit).",
26284
26398
  "- Use the exact provided event_key (snake_case). Wire gurulu.track(...) at the right place and",
26285
26399
  " gurulu.identify(...) at the auth point if given.",
26286
- "- bash only for verification (typecheck/build/lint) no install, no other commands.",
26400
+ "- bash is ONLY for verification: the project's own scripts (`npm run typecheck`, `bun run build`,",
26401
+ " `pnpm run lint`) or a checker binary (`tsc --noEmit`, `biome check`, `eslint .`). Installing or",
26402
+ " fetching packages (`npm install`, `npx`, `bunx`, `pnpm dlx`, `add`, `exec`) is REJECTED by the guard.",
26287
26403
  "- After wiring, run the project typecheck/build to verify; if it breaks, fix additively.",
26288
26404
  "- When all events are wired and verify passes, emit done{summary}. Keep edits minimal."
26289
26405
  ].join(`
@@ -26317,17 +26433,35 @@ async function runWireAgent(client, input, snapshots) {
26317
26433
  try {
26318
26434
  res = await client.agentStep({ messages, first: i2 === 0 });
26319
26435
  } catch {
26320
- return { edits, changedFiles: [...changed], summary: "gateway hata", steps: i2, stoppedReason: "error" };
26436
+ return {
26437
+ edits,
26438
+ changedFiles: [...changed],
26439
+ summary: "gateway hata",
26440
+ steps: i2,
26441
+ stoppedReason: "error"
26442
+ };
26321
26443
  }
26322
26444
  if (res.status === "stub") {
26323
- return { edits, changedFiles: [...changed], summary: "AI kullanılamadı", steps: i2, stoppedReason: "stub" };
26445
+ return {
26446
+ edits,
26447
+ changedFiles: [...changed],
26448
+ summary: "AI kullanılamadı",
26449
+ steps: i2,
26450
+ stoppedReason: "stub"
26451
+ };
26324
26452
  }
26325
26453
  const { action, reasoning } = res.step;
26326
26454
  if (action.tool === "done") {
26327
- return { edits, changedFiles: [...changed], summary: action.summary, steps: i2, stoppedReason: "done" };
26455
+ return {
26456
+ edits,
26457
+ changedFiles: [...changed],
26458
+ summary: action.summary,
26459
+ steps: i2,
26460
+ stoppedReason: "done"
26461
+ };
26328
26462
  }
26329
26463
  if (action.tool === "edit") {
26330
- const abs = join10(input.cwd, action.path);
26464
+ const abs = resolveInCwd(action.path, input.cwd);
26331
26465
  if (!snapshots.has(action.path) && existsSync8(abs)) {
26332
26466
  snapshots.set(action.path, readFileSync9(abs, "utf-8"));
26333
26467
  }
@@ -26340,11 +26474,17 @@ async function runWireAgent(client, input, snapshots) {
26340
26474
  messages.push({ role: "assistant", content: JSON.stringify(res.step) });
26341
26475
  messages.push({ role: "user", content: `[${reasoning}] → ${out.observation}` });
26342
26476
  }
26343
- return { edits, changedFiles: [...changed], summary: "adım limiti", steps: MAX_STEPS, stoppedReason: "cap" };
26477
+ return {
26478
+ edits,
26479
+ changedFiles: [...changed],
26480
+ summary: "adım limiti",
26481
+ steps: MAX_STEPS,
26482
+ stoppedReason: "cap"
26483
+ };
26344
26484
  }
26345
26485
  function restoreSnapshots(cwd, snapshots) {
26346
26486
  for (const [rel, content] of snapshots) {
26347
- writeFileSync7(join10(cwd, rel), content, "utf-8");
26487
+ writeFileSync7(resolveInCwd(rel, cwd), content, "utf-8");
26348
26488
  }
26349
26489
  }
26350
26490
  function unifiedDiff(oldStr, newStr, file, context = 2) {
@@ -26376,7 +26516,7 @@ function unifiedDiff(oldStr, newStr, file, context = 2) {
26376
26516
  function formatWireDiff(cwd, snapshots) {
26377
26517
  const blocks = [];
26378
26518
  for (const [rel, oldContent] of snapshots) {
26379
- const abs = join10(cwd, rel);
26519
+ const abs = resolveInCwd(rel, cwd);
26380
26520
  const cur = existsSync8(abs) ? readFileSync9(abs, "utf-8") : "";
26381
26521
  if (cur !== oldContent)
26382
26522
  blocks.push(unifiedDiff(oldContent, cur, rel));
@@ -26406,14 +26546,23 @@ function bail() {
26406
26546
  process.exit(0);
26407
26547
  }
26408
26548
  async function runWizard(opts) {
26409
- p3.intro("\uD83E\uDD89 Gurulu kurulum sihirbazı");
26549
+ if (process.stdout.isTTY)
26550
+ process.stdout.write(banner());
26551
+ p3.intro(c3.dim("otonom kurulum başlıyor — auth → workspace → install → wire"));
26552
+ const TOTAL = 6;
26553
+ const phase = (n2, label) => {
26554
+ p3.log.step(`${c3.dim(`[${n2}/${TOTAL}]`)} ${c3.bold(label)}`);
26555
+ };
26556
+ phase(1, "Kimlik doğrulama");
26410
26557
  const auth = await ensureAuth({
26411
26558
  ...opts.endpoint ? { endpoint: opts.endpoint } : {},
26412
26559
  ...opts.apiKey ? { apiKey: opts.apiKey } : {},
26413
26560
  ...opts.workspaceId ? { workspaceId: opts.workspaceId } : {}
26414
26561
  });
26415
26562
  const client = new ApiClient({ endpoint: auth.endpoint, apiKey: auth.apiKey });
26563
+ phase(2, "Workspace");
26416
26564
  const { workspaceId, writeKey } = await resolveWorkspace(client, auth.workspaceId, opts);
26565
+ phase(3, "Proje tespiti & plan");
26417
26566
  const detected = detectProject(opts.cwd);
26418
26567
  let framework = detected.framework;
26419
26568
  if (opts.framework && FRAMEWORKS.includes(opts.framework)) {
@@ -26438,9 +26587,10 @@ async function runWizard(opts) {
26438
26587
  const project = { ...detected, framework };
26439
26588
  const plan = buildInstallPlan(project, { writeKey, workspaceId });
26440
26589
  const isNode = plan.sdk === "@gurulu/node";
26590
+ const authed = Boolean(auth.apiKey);
26441
26591
  let approvedEvents = [];
26442
26592
  let identifyHint = null;
26443
- if (!opts.noAi && detected.hasPackageJson) {
26593
+ if (!opts.noAi && authed && detected.hasPackageJson) {
26444
26594
  const ctx = gatherContext({ cwd: opts.cwd });
26445
26595
  const aiPlan = await fetchPlan(client, ctx, { framework });
26446
26596
  if (aiPlan) {
@@ -26452,6 +26602,7 @@ async function runWizard(opts) {
26452
26602
  p3.log.info("AI planı yok — autocapture + sektör paketi (deterministik floor).");
26453
26603
  }
26454
26604
  }
26605
+ phase(4, "SDK kurulumu");
26455
26606
  let installed = false;
26456
26607
  if (opts.noInstall) {
26457
26608
  p3.log.info(`SDK kurulumu atlandı — elle: ${plan.installCommand}`);
@@ -26468,6 +26619,7 @@ async function runWizard(opts) {
26468
26619
  s2.stop(`Kurulum başarısız — elle çalıştır: ${plan.installCommand}`, 1);
26469
26620
  }
26470
26621
  }
26622
+ phase(5, "Kod & env wiring");
26471
26623
  const inj = applyInjection({
26472
26624
  cwd: opts.cwd,
26473
26625
  detected: project,
@@ -26478,10 +26630,15 @@ async function runWizard(opts) {
26478
26630
  const envFile = isNode ? ".env" : ".env.local";
26479
26631
  const vars = [];
26480
26632
  for (const k2 of plan.envKeys) {
26481
- if (k2.key.endsWith("_WORKSPACE"))
26633
+ if (k2.key.endsWith("_WORKSPACE")) {
26482
26634
  vars.push({ key: k2.key, value: writeKey });
26483
- else if (k2.key === "GURULU_SECRET_KEY")
26484
- vars.push({ key: k2.key, value: auth.apiKey });
26635
+ } else if (k2.key === "GURULU_SECRET_KEY") {
26636
+ if (auth.apiKey.startsWith("sk_")) {
26637
+ vars.push({ key: k2.key, value: auth.apiKey });
26638
+ } else {
26639
+ p3.log.warn("GURULU_SECRET_KEY atlandı (login token workspace sk_ anahtarı değil). Dashboard → Settings → API Keys'ten server key oluşturup .env'e elle ekle.");
26640
+ }
26641
+ }
26485
26642
  }
26486
26643
  const envRes = vars.length > 0 ? writeEnvFile({ cwd: opts.cwd, file: envFile, vars }) : null;
26487
26644
  writeProjectScaffold(opts.cwd, {
@@ -26489,6 +26646,7 @@ async function runWizard(opts) {
26489
26646
  endpoint: auth.endpoint,
26490
26647
  sdkPref: isNode ? "node" : "web"
26491
26648
  });
26649
+ phase(6, "Registry & rapor");
26492
26650
  let pulled = false;
26493
26651
  if (!opts.noPull) {
26494
26652
  try {
@@ -26518,7 +26676,9 @@ ${captureGuide(approvedEvents, identifyHint, isNode)}`);
26518
26676
  s2.stop(`wire: ${outcome.changedFiles.length} dosya / ${outcome.steps} adım (${outcome.stoppedReason})`);
26519
26677
  if (outcome.changedFiles.length > 0) {
26520
26678
  p3.log.message(formatWireDiff(opts.cwd, snapshots));
26521
- const keep = opts.yes ? true : await p3.confirm({ message: `${outcome.changedFiles.length} dosyadaki wire değişikliklerini tut?` });
26679
+ const keep = opts.yes ? true : await p3.confirm({
26680
+ message: `${outcome.changedFiles.length} dosyadaki wire değişikliklerini tut?`
26681
+ });
26522
26682
  if (p3.isCancel(keep) || !keep) {
26523
26683
  restoreSnapshots(opts.cwd, snapshots);
26524
26684
  p3.log.info("Wire geri alındı — capture snippet rehberi:");
@@ -26548,13 +26708,13 @@ ${captureGuide(approvedEvents, identifyHint, isNode)}`);
26548
26708
  }
26549
26709
  lines.push(`✓ .gurulu/config.json${pulled ? " + registry pull" : ""}`);
26550
26710
  p3.note(lines.join(`
26551
- `), "Değişiklikler");
26711
+ `), c3.neon("Değişiklikler"));
26552
26712
  if (inj.strategy !== "prepend-entry" || inj.reason === "no-entry") {
26553
26713
  p3.log.info(`Wire: ${inj.wireHint ?? plan.placementHint}`);
26554
26714
  if (inj.strategy === "manual")
26555
26715
  p3.log.message(plan.initSnippet);
26556
26716
  }
26557
- p3.outro(`Hazır \uD83C\uDF89 Doğrula: gurulu doctor · Dashboard: https://dashboard.gurulu.io/app?onboard=done`);
26717
+ p3.outro(`${c3.neon("\uD83E\uDD89 Hazır!")} ${c3.dim("Doğrula:")} ${c3.bold("gurulu doctor")} ${c3.dim("·")} ${c3.dim("Dashboard:")} ${c3.cyan("https://dashboard.gurulu.io/app?onboard=done")}`);
26558
26718
  }
26559
26719
  async function resolveWorkspace(client, authWorkspaceId, opts) {
26560
26720
  if (opts.writeKey) {
@@ -26664,11 +26824,19 @@ var wizardArgs = {
26664
26824
  framework: { type: "string", description: "Framework override (auto-detect yerine)" },
26665
26825
  install: { type: "boolean", description: "SDK install (--no-install ile atla)", default: true },
26666
26826
  pull: { type: "boolean", description: "İlk registry pull (--no-pull ile atla)", default: true },
26667
- ai: { type: "boolean", description: "AI Plan/wire fazı (--no-ai ile atla → floor)", default: true },
26827
+ ai: {
26828
+ type: "boolean",
26829
+ description: "AI Plan/wire fazı (--no-ai ile atla → floor)",
26830
+ default: true
26831
+ },
26668
26832
  yes: { type: "boolean", description: "Onayları otomatik geç" },
26669
26833
  ci: { type: "boolean", description: "Non-interaktif (api-key + workspace zorunlu)" }
26670
26834
  };
26671
26835
  async function runWizardFromArgs(args) {
26836
+ if (args.ci && (!args["api-key"] || !args.workspace)) {
26837
+ console.error("[gurulu] --ci için --api-key <sk_...> ve --workspace <uuid> zorunlu (non-interaktif kurulum).");
26838
+ process.exit(1);
26839
+ }
26672
26840
  const opts = {
26673
26841
  cwd: process.cwd(),
26674
26842
  noInstall: args.install === false,
@@ -26702,7 +26870,7 @@ var initCmd = defineCommand({
26702
26870
  // src/lib/editor-mcp.ts
26703
26871
  import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync10, writeFileSync as writeFileSync9 } from "node:fs";
26704
26872
  import { homedir as homedir2 } from "node:os";
26705
- import { dirname as dirname4, join as join11 } from "node:path";
26873
+ import { dirname as dirname4, join as join9 } from "node:path";
26706
26874
  var SERVER_NAME = "gurulu";
26707
26875
  function buildMcpServerConfig(creds) {
26708
26876
  return {
@@ -26716,14 +26884,14 @@ function buildMcpServerConfig(creds) {
26716
26884
  };
26717
26885
  }
26718
26886
  var EDITORS = {
26719
- cursor: { path: () => join11(homedir2(), ".cursor", "mcp.json"), key: "mcpServers", label: "Cursor" },
26720
- claude: { path: () => join11(homedir2(), ".claude.json"), key: "mcpServers", label: "Claude Code" },
26887
+ cursor: { path: () => join9(homedir2(), ".cursor", "mcp.json"), key: "mcpServers", label: "Cursor" },
26888
+ claude: { path: () => join9(homedir2(), ".claude.json"), key: "mcpServers", label: "Claude Code" },
26721
26889
  windsurf: {
26722
- path: () => join11(homedir2(), ".codeium", "windsurf", "mcp_config.json"),
26890
+ path: () => join9(homedir2(), ".codeium", "windsurf", "mcp_config.json"),
26723
26891
  key: "mcpServers",
26724
26892
  label: "Windsurf"
26725
26893
  },
26726
- vscode: { path: (cwd) => join11(cwd, ".vscode", "mcp.json"), key: "servers", label: "VS Code" }
26894
+ vscode: { path: (cwd) => join9(cwd, ".vscode", "mcp.json"), key: "servers", label: "VS Code" }
26727
26895
  };
26728
26896
  function mergeMcpConfig(existing, serverConfig, key) {
26729
26897
  const servers = existing[key] ?? {};
@@ -26919,7 +27087,7 @@ var pushCmd = defineCommand({
26919
27087
  // src/commands/uninstall.ts
26920
27088
  import { execFile as execFile2 } from "node:child_process";
26921
27089
  import { existsSync as existsSync11, readFileSync as readFileSync11, rmSync, writeFileSync as writeFileSync10 } from "node:fs";
26922
- import { join as join12 } from "node:path";
27090
+ import { join as join10 } from "node:path";
26923
27091
  import { promisify as promisify2 } from "node:util";
26924
27092
  import * as p4 from "@clack/prompts";
26925
27093
  var pexec2 = promisify2(execFile2);
@@ -26975,7 +27143,7 @@ var uninstallCmd = defineCommand({
26975
27143
  }
26976
27144
  const cleaned = [];
26977
27145
  for (const f3 of ENV_FILES) {
26978
- const abs = join12(cwd, f3);
27146
+ const abs = join10(cwd, f3);
26979
27147
  if (!existsSync11(abs))
26980
27148
  continue;
26981
27149
  const { content, removed } = removeEnvKeys(readFileSync11(abs, "utf-8"), GURULU_PREFIXES);
@@ -26984,7 +27152,7 @@ var uninstallCmd = defineCommand({
26984
27152
  cleaned.push(`${f3} (-${removed.length})`);
26985
27153
  }
26986
27154
  }
26987
- const guruluDir = join12(cwd, ".gurulu");
27155
+ const guruluDir = join10(cwd, ".gurulu");
26988
27156
  if (existsSync11(guruluDir))
26989
27157
  rmSync(guruluDir, { recursive: true, force: true });
26990
27158
  p4.outro(`Kaldırıldı. env: ${cleaned.join(", ") || "değişiklik yok"} · .gurulu silindi. (Koddaki init/track çağrılarını elle çıkar.)`);
@@ -26992,7 +27160,7 @@ var uninstallCmd = defineCommand({
26992
27160
  });
26993
27161
 
26994
27162
  // src/index.ts
26995
- var VERSION = "1.2.0";
27163
+ var VERSION = "1.2.2";
26996
27164
  var mainCmd = defineCommand({
26997
27165
  meta: {
26998
27166
  name: "gurulu",