@gurulu/cli 1.1.0 → 1.2.1

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
@@ -25121,6 +25121,145 @@ import { existsSync as existsSync9, mkdirSync as mkdirSync2, writeFileSync as wr
25121
25121
  import { dirname as dirname3 } from "node:path";
25122
25122
  import * as p3 from "@clack/prompts";
25123
25123
 
25124
+ // src/commands/pull.ts
25125
+ import { writeFileSync as writeFileSync3 } from "node:fs";
25126
+
25127
+ // src/lib/codegen.ts
25128
+ function enumKeyName(key) {
25129
+ return key.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
25130
+ }
25131
+ function escapePropName(name) {
25132
+ if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))
25133
+ return name;
25134
+ return `'${name.replace(/'/g, "\\'")}'`;
25135
+ }
25136
+ function tsType(t2) {
25137
+ switch (t2) {
25138
+ case "string":
25139
+ return "string";
25140
+ case "number":
25141
+ return "number";
25142
+ case "boolean":
25143
+ return "boolean";
25144
+ case "date":
25145
+ return "string | Date";
25146
+ case "array":
25147
+ return "unknown[]";
25148
+ case "json":
25149
+ return "Record<string, unknown>";
25150
+ default:
25151
+ return "unknown";
25152
+ }
25153
+ }
25154
+ function generateTypescript(manifest) {
25155
+ const banner = `// Generated by @gurulu/cli — DO NOT EDIT
25156
+ // Workspace: ${manifest.workspace_id} | Manifest version: ${manifest.manifest_version} | Schema: v${manifest.schema_version}
25157
+ // Generated: ${manifest.exported_at}
25158
+ // Events: ${manifest.events.length}
25159
+
25160
+ `;
25161
+ if (manifest.events.length === 0) {
25162
+ return `${banner}export const GuruluEvents = {} as const;
25163
+ export type GuruluEvents = (typeof GuruluEvents)[keyof typeof GuruluEvents];
25164
+
25165
+ export type EventProperties = Record<never, never>;
25166
+
25167
+ export declare function track<E extends GuruluEvents>(
25168
+ event: E,
25169
+ properties: EventProperties[E],
25170
+ ): Promise<void>;
25171
+ `;
25172
+ }
25173
+ const enumLines = manifest.events.map((e2) => ` ${enumKeyName(e2.key)}: '${e2.key}',`);
25174
+ const mapLines = manifest.events.map((e2) => {
25175
+ const props = (e2.properties ?? []).slice().sort((a2, b2) => (a2.position ?? 0) - (b2.position ?? 0)).map((p) => {
25176
+ const optional = p.required ? "" : "?";
25177
+ const comment = p.format ? ` // format: ${p.format}` : "";
25178
+ return ` ${escapePropName(p.name)}${optional}: ${tsType(p.type)};${comment}`;
25179
+ }).join(`
25180
+ `);
25181
+ return ` '${e2.key}': {
25182
+ ${props || " // no properties"}
25183
+ };`;
25184
+ });
25185
+ return `${banner}export const GuruluEvents = {
25186
+ ${enumLines.join(`
25187
+ `)}
25188
+ } as const;
25189
+ export type GuruluEvents = (typeof GuruluEvents)[keyof typeof GuruluEvents];
25190
+
25191
+ export interface EventProperties {
25192
+ ${mapLines.join(`
25193
+ `)}
25194
+ }
25195
+
25196
+ /**
25197
+ * Typed track — compile-time validation against pulled registry.
25198
+ * Runtime implementation: @gurulu/web or @gurulu/node.
25199
+ */
25200
+ export declare function track<E extends GuruluEvents>(
25201
+ event: E,
25202
+ properties: EventProperties[E],
25203
+ ): Promise<void>;
25204
+ `;
25205
+ }
25206
+ function generateManifestLock(manifest) {
25207
+ return `${manifest.manifest_version}
25208
+ `;
25209
+ }
25210
+
25211
+ // src/commands/pull.ts
25212
+ async function runPull(opts = {}) {
25213
+ const cwd = opts.cwd ?? process.cwd();
25214
+ const project = readProjectConfig(cwd);
25215
+ if (!project) {
25216
+ throw new Error("no .gurulu/config.json — run `gurulu init` first");
25217
+ }
25218
+ const cred = resolveActiveCredential({
25219
+ workspaceId: opts.workspaceId ?? project.workspace_id,
25220
+ cwd
25221
+ });
25222
+ if (!cred) {
25223
+ throw new Error("no credentials — run `gurulu login` or set GURULU_API_KEY env (workspace sk_xxx)");
25224
+ }
25225
+ const client = new ApiClient({
25226
+ endpoint: project.endpoint ?? cred.endpoint,
25227
+ apiKey: cred.apiKey
25228
+ });
25229
+ const manifest = await client.get("/v1/cli/registry/pull", {
25230
+ workspace_id: cred.workspaceId
25231
+ });
25232
+ writeFileSync3(projectRegistryPath(cwd), `${JSON.stringify(manifest, null, 2)}
25233
+ `, "utf-8");
25234
+ const ts = generateTypescript(manifest);
25235
+ writeFileSync3(projectGeneratedPath(cwd), ts, "utf-8");
25236
+ writeFileSync3(projectManifestLockPath(cwd), generateManifestLock(manifest), "utf-8");
25237
+ return manifest;
25238
+ }
25239
+ var pullCmd = defineCommand({
25240
+ meta: {
25241
+ name: "pull",
25242
+ description: "Pull registry snapshot + code-gen typed events"
25243
+ },
25244
+ args: {
25245
+ workspace: { type: "string", description: "Workspace ID (override project config)" }
25246
+ },
25247
+ async run({ args }) {
25248
+ try {
25249
+ const manifest = await runPull({
25250
+ ...args.workspace ? { workspaceId: String(args.workspace) } : {}
25251
+ });
25252
+ console.log(`[gurulu] pulled ${manifest.events.length} events (manifest ${manifest.manifest_version})`);
25253
+ console.log(` → ${projectRegistryPath()}`);
25254
+ console.log(` → ${projectGeneratedPath()}`);
25255
+ console.log(` → ${projectManifestLockPath()}`);
25256
+ } catch (err) {
25257
+ console.error(`[gurulu] pull failed: ${err instanceof Error ? err.message : String(err)}`);
25258
+ process.exit(1);
25259
+ }
25260
+ }
25261
+ });
25262
+
25124
25263
  // src/lib/detect.ts
25125
25264
  import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
25126
25265
  import { dirname as dirname2, join as join5, parse } from "node:path";
@@ -25223,7 +25362,7 @@ function detectProject(dir) {
25223
25362
  }
25224
25363
 
25225
25364
  // src/lib/env-file.ts
25226
- import { appendFileSync, existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "node:fs";
25365
+ import { appendFileSync, existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "node:fs";
25227
25366
  import { join as join6 } from "node:path";
25228
25367
  var ENV_KEY_LINE = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/;
25229
25368
  function parseEnvKeys(content) {
@@ -25261,7 +25400,7 @@ function writeEnvFile(opts) {
25261
25400
  const block = opts.vars.filter((v2) => added.includes(v2.key)).map((v2) => `${v2.key}=${formatValue(v2.value)}`).join(`
25262
25401
  `);
25263
25402
  if (existing === "") {
25264
- writeFileSync3(envPath, `# Gurulu
25403
+ writeFileSync4(envPath, `# Gurulu
25265
25404
  ${block}
25266
25405
  `, "utf-8");
25267
25406
  } else {
@@ -25286,7 +25425,7 @@ function ensureGitignored(cwd, file) {
25286
25425
  if (covered)
25287
25426
  return false;
25288
25427
  if (content === "") {
25289
- writeFileSync3(giPath, `# Gurulu
25428
+ writeFileSync4(giPath, `# Gurulu
25290
25429
  ${file}
25291
25430
  `, "utf-8");
25292
25431
  } else {
@@ -25376,7 +25515,7 @@ async function execInstall(plan, opts) {
25376
25515
  }
25377
25516
 
25378
25517
  // src/lib/inject.ts
25379
- import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
25518
+ import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
25380
25519
  import { join as join7 } from "node:path";
25381
25520
  var DIRECTIVE = /^\s*(['"])use [a-z ]+\1;?\s*$/;
25382
25521
  function lastImportEnd(lines, start) {
@@ -25498,7 +25637,7 @@ function applyInjection(opts) {
25498
25637
  const src2 = readFileSync6(abs, "utf-8");
25499
25638
  const res = injectInit(src2, webPieces(workspaceKey, detected.framework));
25500
25639
  if (res.changed)
25501
- writeFileSync4(abs, res.output, "utf-8");
25640
+ writeFileSync5(abs, res.output, "utf-8");
25502
25641
  return { strategy, changed: res.changed, file: entry, reason: res.reason };
25503
25642
  }
25504
25643
  if (strategy === "create-module") {
@@ -25507,7 +25646,7 @@ function applyInjection(opts) {
25507
25646
  if (existsSync6(abs)) {
25508
25647
  return { strategy, changed: false, file: rel, reason: "already-present", wireHint: opts.placementHint };
25509
25648
  }
25510
- writeFileSync4(abs, `${opts.snippet}
25649
+ writeFileSync5(abs, `${opts.snippet}
25511
25650
  `, "utf-8");
25512
25651
  return { strategy, changed: true, file: rel, reason: "created", wireHint: opts.placementHint };
25513
25652
  }
@@ -25692,145 +25831,57 @@ function buildInstallPlan(detected, ctx = {}) {
25692
25831
  };
25693
25832
  }
25694
25833
 
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, "_");
25834
+ // src/lib/ui.ts
25835
+ var noColor = Boolean(process.env.NO_COLOR) || process.env.TERM === "dumb" || !process.stdout.isTTY;
25836
+ function wrap(open, close) {
25837
+ return (s2) => noColor ? s2 : `\x1B[${open}m${s2}\x1B[${close}m`;
25701
25838
  }
25702
- function escapePropName(name) {
25703
- if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))
25704
- return name;
25705
- return `'${name.replace(/'/g, "\\'")}'`;
25839
+ function fg(code) {
25840
+ return (s2) => noColor ? s2 : `\x1B[38;5;${code}m${s2}\x1B[39m`;
25706
25841
  }
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
- }
25842
+ var c3 = {
25843
+ bold: wrap("1", "22"),
25844
+ dim: wrap("2", "22"),
25845
+ italic: wrap("3", "23"),
25846
+ underline: wrap("4", "24"),
25847
+ reset: (s2) => s2,
25848
+ neon: fg(120),
25849
+ green: fg(78),
25850
+ cyan: fg(45),
25851
+ mint: fg(85),
25852
+ violet: fg(141),
25853
+ pink: fg(212),
25854
+ gray: fg(245),
25855
+ slate: fg(240)
25856
+ };
25857
+ var GRAD = [120, 84, 85, 86, 80, 44, 45, 51];
25858
+ function gradient(text) {
25859
+ if (noColor)
25860
+ return text;
25861
+ const chars = [...text];
25862
+ return chars.map((ch, i2) => {
25863
+ if (ch === " ")
25864
+ return ch;
25865
+ const idx = Math.floor(i2 / Math.max(chars.length - 1, 1) * (GRAD.length - 1));
25866
+ const code = GRAD[idx] ?? GRAD[0];
25867
+ return `\x1B[38;5;${code}m${ch}`;
25868
+ }).join("") + "\x1B[39m";
25724
25869
  }
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(`
25870
+ var OWL = [" ╲▏▔▔▔▔▏╱ ", " ▕ ◉ ◉ ▏ ", " ▕ ╲╱ ▏ ", " ╲▁▁▁▁╱ "];
25871
+ var WORD = ["█▀▀ █▀▄ █ █ █", "█▄█ █▄█ █▀▄ █▄█ █▄▄ █▄█"];
25872
+ function banner(subtitle = "truth layer · otonom kurulum") {
25873
+ if (noColor)
25874
+ return `\uD83E\uDD89 Gurulu — ${subtitle}`;
25875
+ const owlC = OWL.map((l2) => c3.neon(l2));
25876
+ const wordC = WORD.map((l2) => gradient(l2));
25877
+ const right = ["", wordC[0] ?? "", wordC[1] ?? "", c3.gray(subtitle)];
25878
+ const lines = owlC.map((owl, i2) => right[i2] ? `${owl} ${right[i2]}` : owl);
25879
+ return `
25880
+ ${lines.join(`
25764
25881
  `)}
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
25882
  `;
25780
25883
  }
25781
25884
 
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
25885
  // src/wizard/apply.ts
25835
25886
  async function registerNewEvents(client, events) {
25836
25887
  const registered = [];
@@ -26406,14 +26457,23 @@ function bail() {
26406
26457
  process.exit(0);
26407
26458
  }
26408
26459
  async function runWizard(opts) {
26409
- p3.intro("\uD83E\uDD89 Gurulu kurulum sihirbazı");
26460
+ if (process.stdout.isTTY)
26461
+ process.stdout.write(banner());
26462
+ p3.intro(c3.dim("otonom kurulum başlıyor — auth → workspace → install → wire"));
26463
+ const TOTAL = 6;
26464
+ const phase = (n2, label) => {
26465
+ p3.log.step(`${c3.dim(`[${n2}/${TOTAL}]`)} ${c3.bold(label)}`);
26466
+ };
26467
+ phase(1, "Kimlik doğrulama");
26410
26468
  const auth = await ensureAuth({
26411
26469
  ...opts.endpoint ? { endpoint: opts.endpoint } : {},
26412
26470
  ...opts.apiKey ? { apiKey: opts.apiKey } : {},
26413
26471
  ...opts.workspaceId ? { workspaceId: opts.workspaceId } : {}
26414
26472
  });
26415
26473
  const client = new ApiClient({ endpoint: auth.endpoint, apiKey: auth.apiKey });
26474
+ phase(2, "Workspace");
26416
26475
  const { workspaceId, writeKey } = await resolveWorkspace(client, auth.workspaceId, opts);
26476
+ phase(3, "Proje tespiti & plan");
26417
26477
  const detected = detectProject(opts.cwd);
26418
26478
  let framework = detected.framework;
26419
26479
  if (opts.framework && FRAMEWORKS.includes(opts.framework)) {
@@ -26452,6 +26512,7 @@ async function runWizard(opts) {
26452
26512
  p3.log.info("AI planı yok — autocapture + sektör paketi (deterministik floor).");
26453
26513
  }
26454
26514
  }
26515
+ phase(4, "SDK kurulumu");
26455
26516
  let installed = false;
26456
26517
  if (opts.noInstall) {
26457
26518
  p3.log.info(`SDK kurulumu atlandı — elle: ${plan.installCommand}`);
@@ -26468,6 +26529,7 @@ async function runWizard(opts) {
26468
26529
  s2.stop(`Kurulum başarısız — elle çalıştır: ${plan.installCommand}`, 1);
26469
26530
  }
26470
26531
  }
26532
+ phase(5, "Kod & env wiring");
26471
26533
  const inj = applyInjection({
26472
26534
  cwd: opts.cwd,
26473
26535
  detected: project,
@@ -26489,6 +26551,7 @@ async function runWizard(opts) {
26489
26551
  endpoint: auth.endpoint,
26490
26552
  sdkPref: isNode ? "node" : "web"
26491
26553
  });
26554
+ phase(6, "Registry & rapor");
26492
26555
  let pulled = false;
26493
26556
  if (!opts.noPull) {
26494
26557
  try {
@@ -26518,7 +26581,9 @@ ${captureGuide(approvedEvents, identifyHint, isNode)}`);
26518
26581
  s2.stop(`wire: ${outcome.changedFiles.length} dosya / ${outcome.steps} adım (${outcome.stoppedReason})`);
26519
26582
  if (outcome.changedFiles.length > 0) {
26520
26583
  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?` });
26584
+ const keep = opts.yes ? true : await p3.confirm({
26585
+ message: `${outcome.changedFiles.length} dosyadaki wire değişikliklerini tut?`
26586
+ });
26522
26587
  if (p3.isCancel(keep) || !keep) {
26523
26588
  restoreSnapshots(opts.cwd, snapshots);
26524
26589
  p3.log.info("Wire geri alındı — capture snippet rehberi:");
@@ -26548,13 +26613,13 @@ ${captureGuide(approvedEvents, identifyHint, isNode)}`);
26548
26613
  }
26549
26614
  lines.push(`✓ .gurulu/config.json${pulled ? " + registry pull" : ""}`);
26550
26615
  p3.note(lines.join(`
26551
- `), "Değişiklikler");
26616
+ `), c3.neon("Değişiklikler"));
26552
26617
  if (inj.strategy !== "prepend-entry" || inj.reason === "no-entry") {
26553
26618
  p3.log.info(`Wire: ${inj.wireHint ?? plan.placementHint}`);
26554
26619
  if (inj.strategy === "manual")
26555
26620
  p3.log.message(plan.initSnippet);
26556
26621
  }
26557
- p3.outro(`Hazır \uD83C\uDF89 Doğrula: gurulu doctor · Dashboard: https://dashboard.gurulu.io/app?onboard=done`);
26622
+ 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
26623
  }
26559
26624
  async function resolveWorkspace(client, authWorkspaceId, opts) {
26560
26625
  if (opts.writeKey) {
@@ -26656,42 +26721,46 @@ function writeProjectScaffold(cwd, opts) {
26656
26721
  }
26657
26722
 
26658
26723
  // src/commands/init.ts
26724
+ var wizardArgs = {
26725
+ workspace: { type: "string", description: "Workspace ID (uuid) — non-interaktif" },
26726
+ "write-key": { type: "string", description: "Workspace write key (pk_xxx) — non-interaktif" },
26727
+ "api-key": { type: "string", description: "sk_xxx workspace key (CI auth)" },
26728
+ endpoint: { type: "string", description: "API endpoint", default: DEFAULT_ENDPOINT },
26729
+ framework: { type: "string", description: "Framework override (auto-detect yerine)" },
26730
+ install: { type: "boolean", description: "SDK install (--no-install ile atla)", default: true },
26731
+ pull: { type: "boolean", description: "İlk registry pull (--no-pull ile atla)", default: true },
26732
+ ai: { type: "boolean", description: "AI Plan/wire fazı (--no-ai ile atla → floor)", default: true },
26733
+ yes: { type: "boolean", description: "Onayları otomatik geç" },
26734
+ ci: { type: "boolean", description: "Non-interaktif (api-key + workspace zorunlu)" }
26735
+ };
26736
+ async function runWizardFromArgs(args) {
26737
+ const opts = {
26738
+ cwd: process.cwd(),
26739
+ noInstall: args.install === false,
26740
+ noPull: args.pull === false,
26741
+ noAi: args.ai === false,
26742
+ yes: Boolean(args.yes) || Boolean(args.ci),
26743
+ ...args.endpoint ? { endpoint: String(args.endpoint) } : {},
26744
+ ...args.workspace ? { workspaceId: String(args.workspace) } : {},
26745
+ ...args["write-key"] ? { writeKey: String(args["write-key"]) } : {},
26746
+ ...args["api-key"] ? { apiKey: String(args["api-key"]) } : {},
26747
+ ...args.framework ? { framework: String(args.framework) } : {}
26748
+ };
26749
+ try {
26750
+ await runWizard(opts);
26751
+ } catch (err) {
26752
+ console.error(`[gurulu] kurulum başarısız: ${err instanceof Error ? err.message : String(err)}`);
26753
+ process.exit(1);
26754
+ }
26755
+ }
26659
26756
  var initCmd = defineCommand({
26660
26757
  meta: {
26661
26758
  name: "init",
26662
26759
  description: "Otonom kurulum sihirbazı (auth → workspace → install → wire)"
26663
26760
  },
26664
- args: {
26665
- workspace: { type: "string", description: "Workspace ID (uuid) — non-interaktif" },
26666
- "write-key": { type: "string", description: "Workspace write key (pk_xxx) — non-interaktif" },
26667
- "api-key": { type: "string", description: "sk_xxx workspace key (CI auth)" },
26668
- endpoint: { type: "string", description: "API endpoint", default: DEFAULT_ENDPOINT },
26669
- framework: { type: "string", description: "Framework override (auto-detect yerine)" },
26670
- install: { type: "boolean", description: "SDK install (--no-install ile atla)", default: true },
26671
- pull: { type: "boolean", description: "İlk registry pull (--no-pull ile atla)", default: true },
26672
- ai: { type: "boolean", description: "AI Plan/wire fazı (--no-ai ile atla → floor)", default: true },
26673
- yes: { type: "boolean", description: "Onayları otomatik geç" },
26674
- ci: { type: "boolean", description: "Non-interaktif (api-key + workspace zorunlu)" }
26675
- },
26761
+ args: wizardArgs,
26676
26762
  async run({ args }) {
26677
- const opts = {
26678
- cwd: process.cwd(),
26679
- noInstall: args.install === false,
26680
- noPull: args.pull === false,
26681
- noAi: args.ai === false,
26682
- yes: Boolean(args.yes) || Boolean(args.ci),
26683
- ...args.endpoint ? { endpoint: String(args.endpoint) } : {},
26684
- ...args.workspace ? { workspaceId: String(args.workspace) } : {},
26685
- ...args["write-key"] ? { writeKey: String(args["write-key"]) } : {},
26686
- ...args["api-key"] ? { apiKey: String(args["api-key"]) } : {},
26687
- ...args.framework ? { framework: String(args.framework) } : {}
26688
- };
26689
- try {
26690
- await runWizard(opts);
26691
- } catch (err) {
26692
- console.error(`[gurulu] kurulum başarısız: ${err instanceof Error ? err.message : String(err)}`);
26693
- process.exit(1);
26694
- }
26763
+ await runWizardFromArgs(args);
26695
26764
  }
26696
26765
  });
26697
26766
 
@@ -26988,13 +27057,14 @@ var uninstallCmd = defineCommand({
26988
27057
  });
26989
27058
 
26990
27059
  // src/index.ts
26991
- var VERSION = "1.1.0";
27060
+ var VERSION = "1.2.1";
26992
27061
  var mainCmd = defineCommand({
26993
27062
  meta: {
26994
27063
  name: "gurulu",
26995
27064
  description: "Gurulu CLI — Truth Layer for product analytics. Registry-as-code, typed events.",
26996
27065
  version: VERSION
26997
27066
  },
27067
+ args: wizardArgs,
26998
27068
  subCommands: {
26999
27069
  init: initCmd,
27000
27070
  pull: pullCmd,
@@ -27007,6 +27077,11 @@ var mainCmd = defineCommand({
27007
27077
  whoami: whoamiCmd,
27008
27078
  mcp: mcpCmd,
27009
27079
  uninstall: uninstallCmd
27080
+ },
27081
+ async run({ args }) {
27082
+ if (args._.length > 0)
27083
+ return;
27084
+ await runWizardFromArgs(args);
27010
27085
  }
27011
27086
  });
27012
27087
  var src_default = mainCmd;
@@ -1,3 +1,50 @@
1
+ export declare const wizardArgs: {
2
+ workspace: {
3
+ type: "string";
4
+ description: string;
5
+ };
6
+ 'write-key': {
7
+ type: "string";
8
+ description: string;
9
+ };
10
+ 'api-key': {
11
+ type: "string";
12
+ description: string;
13
+ };
14
+ endpoint: {
15
+ type: "string";
16
+ description: string;
17
+ default: string;
18
+ };
19
+ framework: {
20
+ type: "string";
21
+ description: string;
22
+ };
23
+ install: {
24
+ type: "boolean";
25
+ description: string;
26
+ default: true;
27
+ };
28
+ pull: {
29
+ type: "boolean";
30
+ description: string;
31
+ default: true;
32
+ };
33
+ ai: {
34
+ type: "boolean";
35
+ description: string;
36
+ default: true;
37
+ };
38
+ yes: {
39
+ type: "boolean";
40
+ description: string;
41
+ };
42
+ ci: {
43
+ type: "boolean";
44
+ description: string;
45
+ };
46
+ };
47
+ export declare function runWizardFromArgs(args: Record<string, unknown>): Promise<void>;
1
48
  export declare const initCmd: import("citty").CommandDef<{
2
49
  workspace: {
3
50
  type: "string";
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqClB,CAAC"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWJ,CAAC;AAIpB,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBpF;AAED,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EASlB,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,49 @@
1
- export declare const VERSION = "1.1.0";
2
- declare const mainCmd: import("citty").CommandDef<import("citty").ArgsDef>;
1
+ export declare const VERSION = "1.2.1";
2
+ declare const mainCmd: import("citty").CommandDef<{
3
+ workspace: {
4
+ type: "string";
5
+ description: string;
6
+ };
7
+ 'write-key': {
8
+ type: "string";
9
+ description: string;
10
+ };
11
+ 'api-key': {
12
+ type: "string";
13
+ description: string;
14
+ };
15
+ endpoint: {
16
+ type: "string";
17
+ description: string;
18
+ default: string;
19
+ };
20
+ framework: {
21
+ type: "string";
22
+ description: string;
23
+ };
24
+ install: {
25
+ type: "boolean";
26
+ description: string;
27
+ default: true;
28
+ };
29
+ pull: {
30
+ type: "boolean";
31
+ description: string;
32
+ default: true;
33
+ };
34
+ ai: {
35
+ type: "boolean";
36
+ description: string;
37
+ default: true;
38
+ };
39
+ yes: {
40
+ type: "boolean";
41
+ description: string;
42
+ };
43
+ ci: {
44
+ type: "boolean";
45
+ description: string;
46
+ };
47
+ }>;
3
48
  export default mainCmd;
4
49
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA0BA,eAAO,MAAM,OAAO,UAAU,CAAC;AAE/B,QAAA,MAAM,OAAO,qDAmBX,CAAC;AAEH,eAAe,OAAO,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA0BA,eAAO,MAAM,OAAO,UAAU,CAAC;AAE/B,QAAA,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4BX,CAAC;AAEH,eAAe,OAAO,CAAC"}
package/dist/index.js CHANGED
@@ -24698,6 +24698,145 @@ import { existsSync as existsSync9, mkdirSync as mkdirSync2, writeFileSync as wr
24698
24698
  import { dirname as dirname3 } from "node:path";
24699
24699
  import * as p3 from "@clack/prompts";
24700
24700
 
24701
+ // src/commands/pull.ts
24702
+ import { writeFileSync as writeFileSync3 } from "node:fs";
24703
+
24704
+ // src/lib/codegen.ts
24705
+ function enumKeyName(key) {
24706
+ return key.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
24707
+ }
24708
+ function escapePropName(name) {
24709
+ if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))
24710
+ return name;
24711
+ return `'${name.replace(/'/g, "\\'")}'`;
24712
+ }
24713
+ function tsType(t2) {
24714
+ switch (t2) {
24715
+ case "string":
24716
+ return "string";
24717
+ case "number":
24718
+ return "number";
24719
+ case "boolean":
24720
+ return "boolean";
24721
+ case "date":
24722
+ return "string | Date";
24723
+ case "array":
24724
+ return "unknown[]";
24725
+ case "json":
24726
+ return "Record<string, unknown>";
24727
+ default:
24728
+ return "unknown";
24729
+ }
24730
+ }
24731
+ function generateTypescript(manifest) {
24732
+ const banner = `// Generated by @gurulu/cli — DO NOT EDIT
24733
+ // Workspace: ${manifest.workspace_id} | Manifest version: ${manifest.manifest_version} | Schema: v${manifest.schema_version}
24734
+ // Generated: ${manifest.exported_at}
24735
+ // Events: ${manifest.events.length}
24736
+
24737
+ `;
24738
+ if (manifest.events.length === 0) {
24739
+ return `${banner}export const GuruluEvents = {} as const;
24740
+ export type GuruluEvents = (typeof GuruluEvents)[keyof typeof GuruluEvents];
24741
+
24742
+ export type EventProperties = Record<never, never>;
24743
+
24744
+ export declare function track<E extends GuruluEvents>(
24745
+ event: E,
24746
+ properties: EventProperties[E],
24747
+ ): Promise<void>;
24748
+ `;
24749
+ }
24750
+ const enumLines = manifest.events.map((e2) => ` ${enumKeyName(e2.key)}: '${e2.key}',`);
24751
+ const mapLines = manifest.events.map((e2) => {
24752
+ const props = (e2.properties ?? []).slice().sort((a2, b2) => (a2.position ?? 0) - (b2.position ?? 0)).map((p) => {
24753
+ const optional = p.required ? "" : "?";
24754
+ const comment = p.format ? ` // format: ${p.format}` : "";
24755
+ return ` ${escapePropName(p.name)}${optional}: ${tsType(p.type)};${comment}`;
24756
+ }).join(`
24757
+ `);
24758
+ return ` '${e2.key}': {
24759
+ ${props || " // no properties"}
24760
+ };`;
24761
+ });
24762
+ return `${banner}export const GuruluEvents = {
24763
+ ${enumLines.join(`
24764
+ `)}
24765
+ } as const;
24766
+ export type GuruluEvents = (typeof GuruluEvents)[keyof typeof GuruluEvents];
24767
+
24768
+ export interface EventProperties {
24769
+ ${mapLines.join(`
24770
+ `)}
24771
+ }
24772
+
24773
+ /**
24774
+ * Typed track — compile-time validation against pulled registry.
24775
+ * Runtime implementation: @gurulu/web or @gurulu/node.
24776
+ */
24777
+ export declare function track<E extends GuruluEvents>(
24778
+ event: E,
24779
+ properties: EventProperties[E],
24780
+ ): Promise<void>;
24781
+ `;
24782
+ }
24783
+ function generateManifestLock(manifest) {
24784
+ return `${manifest.manifest_version}
24785
+ `;
24786
+ }
24787
+
24788
+ // src/commands/pull.ts
24789
+ async function runPull(opts = {}) {
24790
+ const cwd = opts.cwd ?? process.cwd();
24791
+ const project = readProjectConfig(cwd);
24792
+ if (!project) {
24793
+ throw new Error("no .gurulu/config.json — run `gurulu init` first");
24794
+ }
24795
+ const cred = resolveActiveCredential({
24796
+ workspaceId: opts.workspaceId ?? project.workspace_id,
24797
+ cwd
24798
+ });
24799
+ if (!cred) {
24800
+ throw new Error("no credentials — run `gurulu login` or set GURULU_API_KEY env (workspace sk_xxx)");
24801
+ }
24802
+ const client = new ApiClient({
24803
+ endpoint: project.endpoint ?? cred.endpoint,
24804
+ apiKey: cred.apiKey
24805
+ });
24806
+ const manifest = await client.get("/v1/cli/registry/pull", {
24807
+ workspace_id: cred.workspaceId
24808
+ });
24809
+ writeFileSync3(projectRegistryPath(cwd), `${JSON.stringify(manifest, null, 2)}
24810
+ `, "utf-8");
24811
+ const ts = generateTypescript(manifest);
24812
+ writeFileSync3(projectGeneratedPath(cwd), ts, "utf-8");
24813
+ writeFileSync3(projectManifestLockPath(cwd), generateManifestLock(manifest), "utf-8");
24814
+ return manifest;
24815
+ }
24816
+ var pullCmd = defineCommand({
24817
+ meta: {
24818
+ name: "pull",
24819
+ description: "Pull registry snapshot + code-gen typed events"
24820
+ },
24821
+ args: {
24822
+ workspace: { type: "string", description: "Workspace ID (override project config)" }
24823
+ },
24824
+ async run({ args }) {
24825
+ try {
24826
+ const manifest = await runPull({
24827
+ ...args.workspace ? { workspaceId: String(args.workspace) } : {}
24828
+ });
24829
+ console.log(`[gurulu] pulled ${manifest.events.length} events (manifest ${manifest.manifest_version})`);
24830
+ console.log(` → ${projectRegistryPath()}`);
24831
+ console.log(` → ${projectGeneratedPath()}`);
24832
+ console.log(` → ${projectManifestLockPath()}`);
24833
+ } catch (err) {
24834
+ console.error(`[gurulu] pull failed: ${err instanceof Error ? err.message : String(err)}`);
24835
+ process.exit(1);
24836
+ }
24837
+ }
24838
+ });
24839
+
24701
24840
  // src/lib/detect.ts
24702
24841
  import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
24703
24842
  import { dirname as dirname2, join as join5, parse } from "node:path";
@@ -24800,7 +24939,7 @@ function detectProject(dir) {
24800
24939
  }
24801
24940
 
24802
24941
  // src/lib/env-file.ts
24803
- import { appendFileSync, existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "node:fs";
24942
+ import { appendFileSync, existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "node:fs";
24804
24943
  import { join as join6 } from "node:path";
24805
24944
  var ENV_KEY_LINE = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/;
24806
24945
  function parseEnvKeys(content) {
@@ -24838,7 +24977,7 @@ function writeEnvFile(opts) {
24838
24977
  const block = opts.vars.filter((v2) => added.includes(v2.key)).map((v2) => `${v2.key}=${formatValue(v2.value)}`).join(`
24839
24978
  `);
24840
24979
  if (existing === "") {
24841
- writeFileSync3(envPath, `# Gurulu
24980
+ writeFileSync4(envPath, `# Gurulu
24842
24981
  ${block}
24843
24982
  `, "utf-8");
24844
24983
  } else {
@@ -24863,7 +25002,7 @@ function ensureGitignored(cwd, file) {
24863
25002
  if (covered)
24864
25003
  return false;
24865
25004
  if (content === "") {
24866
- writeFileSync3(giPath, `# Gurulu
25005
+ writeFileSync4(giPath, `# Gurulu
24867
25006
  ${file}
24868
25007
  `, "utf-8");
24869
25008
  } else {
@@ -24953,7 +25092,7 @@ async function execInstall(plan, opts) {
24953
25092
  }
24954
25093
 
24955
25094
  // src/lib/inject.ts
24956
- import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
25095
+ import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
24957
25096
  import { join as join7 } from "node:path";
24958
25097
  var DIRECTIVE = /^\s*(['"])use [a-z ]+\1;?\s*$/;
24959
25098
  function lastImportEnd(lines, start) {
@@ -25075,7 +25214,7 @@ function applyInjection(opts) {
25075
25214
  const src2 = readFileSync6(abs, "utf-8");
25076
25215
  const res = injectInit(src2, webPieces(workspaceKey, detected.framework));
25077
25216
  if (res.changed)
25078
- writeFileSync4(abs, res.output, "utf-8");
25217
+ writeFileSync5(abs, res.output, "utf-8");
25079
25218
  return { strategy, changed: res.changed, file: entry, reason: res.reason };
25080
25219
  }
25081
25220
  if (strategy === "create-module") {
@@ -25084,7 +25223,7 @@ function applyInjection(opts) {
25084
25223
  if (existsSync6(abs)) {
25085
25224
  return { strategy, changed: false, file: rel, reason: "already-present", wireHint: opts.placementHint };
25086
25225
  }
25087
- writeFileSync4(abs, `${opts.snippet}
25226
+ writeFileSync5(abs, `${opts.snippet}
25088
25227
  `, "utf-8");
25089
25228
  return { strategy, changed: true, file: rel, reason: "created", wireHint: opts.placementHint };
25090
25229
  }
@@ -25269,145 +25408,57 @@ function buildInstallPlan(detected, ctx = {}) {
25269
25408
  };
25270
25409
  }
25271
25410
 
25272
- // src/commands/pull.ts
25273
- import { writeFileSync as writeFileSync5 } from "node:fs";
25274
-
25275
- // src/lib/codegen.ts
25276
- function enumKeyName(key) {
25277
- return key.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
25411
+ // src/lib/ui.ts
25412
+ var noColor = Boolean(process.env.NO_COLOR) || process.env.TERM === "dumb" || !process.stdout.isTTY;
25413
+ function wrap(open, close) {
25414
+ return (s2) => noColor ? s2 : `\x1B[${open}m${s2}\x1B[${close}m`;
25278
25415
  }
25279
- function escapePropName(name) {
25280
- if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))
25281
- return name;
25282
- return `'${name.replace(/'/g, "\\'")}'`;
25416
+ function fg(code) {
25417
+ return (s2) => noColor ? s2 : `\x1B[38;5;${code}m${s2}\x1B[39m`;
25283
25418
  }
25284
- function tsType(t2) {
25285
- switch (t2) {
25286
- case "string":
25287
- return "string";
25288
- case "number":
25289
- return "number";
25290
- case "boolean":
25291
- return "boolean";
25292
- case "date":
25293
- return "string | Date";
25294
- case "array":
25295
- return "unknown[]";
25296
- case "json":
25297
- return "Record<string, unknown>";
25298
- default:
25299
- return "unknown";
25300
- }
25419
+ var c3 = {
25420
+ bold: wrap("1", "22"),
25421
+ dim: wrap("2", "22"),
25422
+ italic: wrap("3", "23"),
25423
+ underline: wrap("4", "24"),
25424
+ reset: (s2) => s2,
25425
+ neon: fg(120),
25426
+ green: fg(78),
25427
+ cyan: fg(45),
25428
+ mint: fg(85),
25429
+ violet: fg(141),
25430
+ pink: fg(212),
25431
+ gray: fg(245),
25432
+ slate: fg(240)
25433
+ };
25434
+ var GRAD = [120, 84, 85, 86, 80, 44, 45, 51];
25435
+ function gradient(text) {
25436
+ if (noColor)
25437
+ return text;
25438
+ const chars = [...text];
25439
+ return chars.map((ch, i2) => {
25440
+ if (ch === " ")
25441
+ return ch;
25442
+ const idx = Math.floor(i2 / Math.max(chars.length - 1, 1) * (GRAD.length - 1));
25443
+ const code = GRAD[idx] ?? GRAD[0];
25444
+ return `\x1B[38;5;${code}m${ch}`;
25445
+ }).join("") + "\x1B[39m";
25301
25446
  }
25302
- function generateTypescript(manifest) {
25303
- const banner = `// Generated by @gurulu/cli DO NOT EDIT
25304
- // Workspace: ${manifest.workspace_id} | Manifest version: ${manifest.manifest_version} | Schema: v${manifest.schema_version}
25305
- // Generated: ${manifest.exported_at}
25306
- // Events: ${manifest.events.length}
25307
-
25308
- `;
25309
- if (manifest.events.length === 0) {
25310
- return `${banner}export const GuruluEvents = {} as const;
25311
- export type GuruluEvents = (typeof GuruluEvents)[keyof typeof GuruluEvents];
25312
-
25313
- export type EventProperties = Record<never, never>;
25314
-
25315
- export declare function track<E extends GuruluEvents>(
25316
- event: E,
25317
- properties: EventProperties[E],
25318
- ): Promise<void>;
25319
- `;
25320
- }
25321
- const enumLines = manifest.events.map((e2) => ` ${enumKeyName(e2.key)}: '${e2.key}',`);
25322
- const mapLines = manifest.events.map((e2) => {
25323
- const props = (e2.properties ?? []).slice().sort((a2, b2) => (a2.position ?? 0) - (b2.position ?? 0)).map((p) => {
25324
- const optional = p.required ? "" : "?";
25325
- const comment = p.format ? ` // format: ${p.format}` : "";
25326
- return ` ${escapePropName(p.name)}${optional}: ${tsType(p.type)};${comment}`;
25327
- }).join(`
25328
- `);
25329
- return ` '${e2.key}': {
25330
- ${props || " // no properties"}
25331
- };`;
25332
- });
25333
- return `${banner}export const GuruluEvents = {
25334
- ${enumLines.join(`
25335
- `)}
25336
- } as const;
25337
- export type GuruluEvents = (typeof GuruluEvents)[keyof typeof GuruluEvents];
25338
-
25339
- export interface EventProperties {
25340
- ${mapLines.join(`
25447
+ var OWL = [" ╲▏▔▔▔▔▏╱ ", " ▕ ◉ ◉ ▏ ", " ▕ ╲╱ ▏ ", " ╲▁▁▁▁╱ "];
25448
+ var WORD = ["█▀▀ █▀▄ █ █ █", "█▄█ █▄█ █▀▄ █▄█ █▄▄ █▄█"];
25449
+ function banner(subtitle = "truth layer · otonom kurulum") {
25450
+ if (noColor)
25451
+ return `\uD83E\uDD89 Gurulu — ${subtitle}`;
25452
+ const owlC = OWL.map((l2) => c3.neon(l2));
25453
+ const wordC = WORD.map((l2) => gradient(l2));
25454
+ const right = ["", wordC[0] ?? "", wordC[1] ?? "", c3.gray(subtitle)];
25455
+ const lines = owlC.map((owl, i2) => right[i2] ? `${owl} ${right[i2]}` : owl);
25456
+ return `
25457
+ ${lines.join(`
25341
25458
  `)}
25342
- }
25343
-
25344
- /**
25345
- * Typed track — compile-time validation against pulled registry.
25346
- * Runtime implementation: @gurulu/web or @gurulu/node.
25347
- */
25348
- export declare function track<E extends GuruluEvents>(
25349
- event: E,
25350
- properties: EventProperties[E],
25351
- ): Promise<void>;
25352
- `;
25353
- }
25354
- function generateManifestLock(manifest) {
25355
- return `${manifest.manifest_version}
25356
25459
  `;
25357
25460
  }
25358
25461
 
25359
- // src/commands/pull.ts
25360
- async function runPull(opts = {}) {
25361
- const cwd = opts.cwd ?? process.cwd();
25362
- const project = readProjectConfig(cwd);
25363
- if (!project) {
25364
- throw new Error("no .gurulu/config.json — run `gurulu init` first");
25365
- }
25366
- const cred = resolveActiveCredential({
25367
- workspaceId: opts.workspaceId ?? project.workspace_id,
25368
- cwd
25369
- });
25370
- if (!cred) {
25371
- throw new Error("no credentials — run `gurulu login` or set GURULU_API_KEY env (workspace sk_xxx)");
25372
- }
25373
- const client = new ApiClient({
25374
- endpoint: project.endpoint ?? cred.endpoint,
25375
- apiKey: cred.apiKey
25376
- });
25377
- const manifest = await client.get("/v1/cli/registry/pull", {
25378
- workspace_id: cred.workspaceId
25379
- });
25380
- writeFileSync5(projectRegistryPath(cwd), `${JSON.stringify(manifest, null, 2)}
25381
- `, "utf-8");
25382
- const ts = generateTypescript(manifest);
25383
- writeFileSync5(projectGeneratedPath(cwd), ts, "utf-8");
25384
- writeFileSync5(projectManifestLockPath(cwd), generateManifestLock(manifest), "utf-8");
25385
- return manifest;
25386
- }
25387
- var pullCmd = defineCommand({
25388
- meta: {
25389
- name: "pull",
25390
- description: "Pull registry snapshot + code-gen typed events"
25391
- },
25392
- args: {
25393
- workspace: { type: "string", description: "Workspace ID (override project config)" }
25394
- },
25395
- async run({ args }) {
25396
- try {
25397
- const manifest = await runPull({
25398
- ...args.workspace ? { workspaceId: String(args.workspace) } : {}
25399
- });
25400
- console.log(`[gurulu] pulled ${manifest.events.length} events (manifest ${manifest.manifest_version})`);
25401
- console.log(` → ${projectRegistryPath()}`);
25402
- console.log(` → ${projectGeneratedPath()}`);
25403
- console.log(` → ${projectManifestLockPath()}`);
25404
- } catch (err) {
25405
- console.error(`[gurulu] pull failed: ${err instanceof Error ? err.message : String(err)}`);
25406
- process.exit(1);
25407
- }
25408
- }
25409
- });
25410
-
25411
25462
  // src/wizard/apply.ts
25412
25463
  async function registerNewEvents(client, events) {
25413
25464
  const registered = [];
@@ -25983,14 +26034,23 @@ function bail() {
25983
26034
  process.exit(0);
25984
26035
  }
25985
26036
  async function runWizard(opts) {
25986
- p3.intro("\uD83E\uDD89 Gurulu kurulum sihirbazı");
26037
+ if (process.stdout.isTTY)
26038
+ process.stdout.write(banner());
26039
+ p3.intro(c3.dim("otonom kurulum başlıyor — auth → workspace → install → wire"));
26040
+ const TOTAL = 6;
26041
+ const phase = (n2, label) => {
26042
+ p3.log.step(`${c3.dim(`[${n2}/${TOTAL}]`)} ${c3.bold(label)}`);
26043
+ };
26044
+ phase(1, "Kimlik doğrulama");
25987
26045
  const auth = await ensureAuth({
25988
26046
  ...opts.endpoint ? { endpoint: opts.endpoint } : {},
25989
26047
  ...opts.apiKey ? { apiKey: opts.apiKey } : {},
25990
26048
  ...opts.workspaceId ? { workspaceId: opts.workspaceId } : {}
25991
26049
  });
25992
26050
  const client = new ApiClient({ endpoint: auth.endpoint, apiKey: auth.apiKey });
26051
+ phase(2, "Workspace");
25993
26052
  const { workspaceId, writeKey } = await resolveWorkspace(client, auth.workspaceId, opts);
26053
+ phase(3, "Proje tespiti & plan");
25994
26054
  const detected = detectProject(opts.cwd);
25995
26055
  let framework = detected.framework;
25996
26056
  if (opts.framework && FRAMEWORKS.includes(opts.framework)) {
@@ -26029,6 +26089,7 @@ async function runWizard(opts) {
26029
26089
  p3.log.info("AI planı yok — autocapture + sektör paketi (deterministik floor).");
26030
26090
  }
26031
26091
  }
26092
+ phase(4, "SDK kurulumu");
26032
26093
  let installed = false;
26033
26094
  if (opts.noInstall) {
26034
26095
  p3.log.info(`SDK kurulumu atlandı — elle: ${plan.installCommand}`);
@@ -26045,6 +26106,7 @@ async function runWizard(opts) {
26045
26106
  s2.stop(`Kurulum başarısız — elle çalıştır: ${plan.installCommand}`, 1);
26046
26107
  }
26047
26108
  }
26109
+ phase(5, "Kod & env wiring");
26048
26110
  const inj = applyInjection({
26049
26111
  cwd: opts.cwd,
26050
26112
  detected: project,
@@ -26066,6 +26128,7 @@ async function runWizard(opts) {
26066
26128
  endpoint: auth.endpoint,
26067
26129
  sdkPref: isNode ? "node" : "web"
26068
26130
  });
26131
+ phase(6, "Registry & rapor");
26069
26132
  let pulled = false;
26070
26133
  if (!opts.noPull) {
26071
26134
  try {
@@ -26095,7 +26158,9 @@ ${captureGuide(approvedEvents, identifyHint, isNode)}`);
26095
26158
  s2.stop(`wire: ${outcome.changedFiles.length} dosya / ${outcome.steps} adım (${outcome.stoppedReason})`);
26096
26159
  if (outcome.changedFiles.length > 0) {
26097
26160
  p3.log.message(formatWireDiff(opts.cwd, snapshots));
26098
- const keep = opts.yes ? true : await p3.confirm({ message: `${outcome.changedFiles.length} dosyadaki wire değişikliklerini tut?` });
26161
+ const keep = opts.yes ? true : await p3.confirm({
26162
+ message: `${outcome.changedFiles.length} dosyadaki wire değişikliklerini tut?`
26163
+ });
26099
26164
  if (p3.isCancel(keep) || !keep) {
26100
26165
  restoreSnapshots(opts.cwd, snapshots);
26101
26166
  p3.log.info("Wire geri alındı — capture snippet rehberi:");
@@ -26125,13 +26190,13 @@ ${captureGuide(approvedEvents, identifyHint, isNode)}`);
26125
26190
  }
26126
26191
  lines.push(`✓ .gurulu/config.json${pulled ? " + registry pull" : ""}`);
26127
26192
  p3.note(lines.join(`
26128
- `), "Değişiklikler");
26193
+ `), c3.neon("Değişiklikler"));
26129
26194
  if (inj.strategy !== "prepend-entry" || inj.reason === "no-entry") {
26130
26195
  p3.log.info(`Wire: ${inj.wireHint ?? plan.placementHint}`);
26131
26196
  if (inj.strategy === "manual")
26132
26197
  p3.log.message(plan.initSnippet);
26133
26198
  }
26134
- p3.outro(`Hazır \uD83C\uDF89 Doğrula: gurulu doctor · Dashboard: https://dashboard.gurulu.io/app?onboard=done`);
26199
+ 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")}`);
26135
26200
  }
26136
26201
  async function resolveWorkspace(client, authWorkspaceId, opts) {
26137
26202
  if (opts.writeKey) {
@@ -26233,42 +26298,46 @@ function writeProjectScaffold(cwd, opts) {
26233
26298
  }
26234
26299
 
26235
26300
  // src/commands/init.ts
26301
+ var wizardArgs = {
26302
+ workspace: { type: "string", description: "Workspace ID (uuid) — non-interaktif" },
26303
+ "write-key": { type: "string", description: "Workspace write key (pk_xxx) — non-interaktif" },
26304
+ "api-key": { type: "string", description: "sk_xxx workspace key (CI auth)" },
26305
+ endpoint: { type: "string", description: "API endpoint", default: DEFAULT_ENDPOINT },
26306
+ framework: { type: "string", description: "Framework override (auto-detect yerine)" },
26307
+ install: { type: "boolean", description: "SDK install (--no-install ile atla)", default: true },
26308
+ pull: { type: "boolean", description: "İlk registry pull (--no-pull ile atla)", default: true },
26309
+ ai: { type: "boolean", description: "AI Plan/wire fazı (--no-ai ile atla → floor)", default: true },
26310
+ yes: { type: "boolean", description: "Onayları otomatik geç" },
26311
+ ci: { type: "boolean", description: "Non-interaktif (api-key + workspace zorunlu)" }
26312
+ };
26313
+ async function runWizardFromArgs(args) {
26314
+ const opts = {
26315
+ cwd: process.cwd(),
26316
+ noInstall: args.install === false,
26317
+ noPull: args.pull === false,
26318
+ noAi: args.ai === false,
26319
+ yes: Boolean(args.yes) || Boolean(args.ci),
26320
+ ...args.endpoint ? { endpoint: String(args.endpoint) } : {},
26321
+ ...args.workspace ? { workspaceId: String(args.workspace) } : {},
26322
+ ...args["write-key"] ? { writeKey: String(args["write-key"]) } : {},
26323
+ ...args["api-key"] ? { apiKey: String(args["api-key"]) } : {},
26324
+ ...args.framework ? { framework: String(args.framework) } : {}
26325
+ };
26326
+ try {
26327
+ await runWizard(opts);
26328
+ } catch (err) {
26329
+ console.error(`[gurulu] kurulum başarısız: ${err instanceof Error ? err.message : String(err)}`);
26330
+ process.exit(1);
26331
+ }
26332
+ }
26236
26333
  var initCmd = defineCommand({
26237
26334
  meta: {
26238
26335
  name: "init",
26239
26336
  description: "Otonom kurulum sihirbazı (auth → workspace → install → wire)"
26240
26337
  },
26241
- args: {
26242
- workspace: { type: "string", description: "Workspace ID (uuid) — non-interaktif" },
26243
- "write-key": { type: "string", description: "Workspace write key (pk_xxx) — non-interaktif" },
26244
- "api-key": { type: "string", description: "sk_xxx workspace key (CI auth)" },
26245
- endpoint: { type: "string", description: "API endpoint", default: DEFAULT_ENDPOINT },
26246
- framework: { type: "string", description: "Framework override (auto-detect yerine)" },
26247
- install: { type: "boolean", description: "SDK install (--no-install ile atla)", default: true },
26248
- pull: { type: "boolean", description: "İlk registry pull (--no-pull ile atla)", default: true },
26249
- ai: { type: "boolean", description: "AI Plan/wire fazı (--no-ai ile atla → floor)", default: true },
26250
- yes: { type: "boolean", description: "Onayları otomatik geç" },
26251
- ci: { type: "boolean", description: "Non-interaktif (api-key + workspace zorunlu)" }
26252
- },
26338
+ args: wizardArgs,
26253
26339
  async run({ args }) {
26254
- const opts = {
26255
- cwd: process.cwd(),
26256
- noInstall: args.install === false,
26257
- noPull: args.pull === false,
26258
- noAi: args.ai === false,
26259
- yes: Boolean(args.yes) || Boolean(args.ci),
26260
- ...args.endpoint ? { endpoint: String(args.endpoint) } : {},
26261
- ...args.workspace ? { workspaceId: String(args.workspace) } : {},
26262
- ...args["write-key"] ? { writeKey: String(args["write-key"]) } : {},
26263
- ...args["api-key"] ? { apiKey: String(args["api-key"]) } : {},
26264
- ...args.framework ? { framework: String(args.framework) } : {}
26265
- };
26266
- try {
26267
- await runWizard(opts);
26268
- } catch (err) {
26269
- console.error(`[gurulu] kurulum başarısız: ${err instanceof Error ? err.message : String(err)}`);
26270
- process.exit(1);
26271
- }
26340
+ await runWizardFromArgs(args);
26272
26341
  }
26273
26342
  });
26274
26343
 
@@ -26565,13 +26634,14 @@ var uninstallCmd = defineCommand({
26565
26634
  });
26566
26635
 
26567
26636
  // src/index.ts
26568
- var VERSION = "1.1.0";
26637
+ var VERSION = "1.2.1";
26569
26638
  var mainCmd = defineCommand({
26570
26639
  meta: {
26571
26640
  name: "gurulu",
26572
26641
  description: "Gurulu CLI — Truth Layer for product analytics. Registry-as-code, typed events.",
26573
26642
  version: VERSION
26574
26643
  },
26644
+ args: wizardArgs,
26575
26645
  subCommands: {
26576
26646
  init: initCmd,
26577
26647
  pull: pullCmd,
@@ -26584,6 +26654,11 @@ var mainCmd = defineCommand({
26584
26654
  whoami: whoamiCmd,
26585
26655
  mcp: mcpCmd,
26586
26656
  uninstall: uninstallCmd
26657
+ },
26658
+ async run({ args }) {
26659
+ if (args._.length > 0)
26660
+ return;
26661
+ await runWizardFromArgs(args);
26587
26662
  }
26588
26663
  });
26589
26664
  var src_default = mainCmd;
@@ -0,0 +1,28 @@
1
+ export declare const c: {
2
+ bold: (s: string) => string;
3
+ dim: (s: string) => string;
4
+ italic: (s: string) => string;
5
+ underline: (s: string) => string;
6
+ reset: (s: string) => string;
7
+ neon: (s: string) => string;
8
+ green: (s: string) => string;
9
+ cyan: (s: string) => string;
10
+ mint: (s: string) => string;
11
+ violet: (s: string) => string;
12
+ pink: (s: string) => string;
13
+ gray: (s: string) => string;
14
+ slate: (s: string) => string;
15
+ };
16
+ export declare const supportsColor: boolean;
17
+ /**
18
+ * Açılış banner'ı — renkli Bubo + GURULU + alt başlık.
19
+ * Renk kapalıysa (CI/pipe/NO_COLOR) tek satır sade fallback döner.
20
+ */
21
+ export declare function banner(subtitle?: string): string;
22
+ /** Adım başlığı — "[2/7] Workspace" net ilerleme göstergesi. */
23
+ export declare function step(n: number, total: number, label: string, icon?: string): string;
24
+ /** Başarılı satır — yeşil ✓. */
25
+ export declare function ok(text: string): string;
26
+ /** Bilgi/atlandı satırı — gri •. */
27
+ export declare function skip(text: string): string;
28
+ //# sourceMappingURL=ui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/lib/ui.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,CAAC;cARD,MAAM,KAAG,MAAM;aAAf,MAAM,KAAG,MAAM;gBAAf,MAAM,KAAG,MAAM;mBAAf,MAAM,KAAG,MAAM;eAaf,MAAM;cARN,MAAM,KAAG,MAAM;eAAf,MAAM,KAAG,MAAM;cAAf,MAAM,KAAG,MAAM;cAAf,MAAM,KAAG,MAAM;gBAAf,MAAM,KAAG,MAAM;cAAf,MAAM,KAAG,MAAM;cAAf,MAAM,KAAG,MAAM;eAAf,MAAM,KAAG,MAAM;CAkB3B,CAAC;AAEF,eAAO,MAAM,aAAa,SAAW,CAAC;AAwBtC;;;GAGG;AACH,wBAAgB,MAAM,CAAC,QAAQ,SAAiC,GAAG,MAAM,CAUxE;AAED,gEAAgE;AAChE,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,SAAM,GAAG,MAAM,CAGhF;AAED,gCAAgC;AAChC,wBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvC;AAED,oCAAoC;AACpC,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzC"}
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/wizard/run.ts"],"names":[],"mappings":"AA+BA,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,4CAA4C;IAC5C,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAsBD,wBAAsB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAuLlE"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/wizard/run.ts"],"names":[],"mappings":"AAgCA,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,4CAA4C;IAC5C,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAsBD,wBAAsB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA2MlE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gurulu/cli",
3
- "version": "1.1.0",
3
+ "version": "1.2.1",
4
4
  "private": false,
5
5
  "license": "BUSL-1.1",
6
6
  "publishConfig": {