@akredit/acik-mcp 0.1.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/README.md +94 -8
  2. package/dist/apps/acik-mcp/src/araclar.d.ts +2 -28
  3. package/dist/apps/acik-mcp/src/araclar.js +29 -114
  4. package/dist/apps/acik-mcp/src/bologna.d.ts +291 -0
  5. package/dist/apps/acik-mcp/src/bologna.js +1693 -0
  6. package/dist/apps/acik-mcp/src/genel-ayristir.d.ts +92 -0
  7. package/dist/apps/acik-mcp/src/genel-ayristir.js +489 -0
  8. package/dist/apps/acik-mcp/src/http.d.ts +31 -3
  9. package/dist/apps/acik-mcp/src/http.js +90 -17
  10. package/dist/apps/acik-mcp/src/index.d.ts +7 -0
  11. package/dist/apps/acik-mcp/src/index.js +7 -0
  12. package/dist/apps/acik-mcp/src/kaynak-dogrula.d.ts +94 -0
  13. package/dist/apps/acik-mcp/src/kaynak-dogrula.js +460 -0
  14. package/dist/apps/acik-mcp/src/kaynak.d.ts +72 -0
  15. package/dist/apps/acik-mcp/src/kaynak.js +155 -0
  16. package/dist/apps/acik-mcp/src/kisisel-veri.d.ts +16 -2
  17. package/dist/apps/acik-mcp/src/kisisel-veri.js +78 -15
  18. package/dist/apps/acik-mcp/src/not-tablosu.d.ts +39 -0
  19. package/dist/apps/acik-mcp/src/not-tablosu.js +268 -0
  20. package/dist/apps/acik-mcp/src/promptlar.d.ts +48 -0
  21. package/dist/apps/acik-mcp/src/promptlar.js +323 -0
  22. package/dist/apps/acik-mcp/src/sunucu.d.ts +12 -4
  23. package/dist/apps/acik-mcp/src/sunucu.js +108 -24
  24. package/dist/apps/acik-mcp/src/temel.d.ts +59 -0
  25. package/dist/apps/acik-mcp/src/temel.js +10 -0
  26. package/dist/apps/acik-mcp/src/yardim.d.ts +56 -0
  27. package/dist/apps/acik-mcp/src/yardim.js +381 -0
  28. package/dist/packages/baglayicilar/src/bologna-proliz/ayristir.d.ts +29 -0
  29. package/dist/packages/baglayicilar/src/bologna-proliz/ayristir.js +200 -0
  30. package/dist/packages/cekirdek/src/bologna/taslak.d.ts +19 -3
  31. package/dist/packages/cekirdek/src/bologna/taslak.js +70 -9
  32. package/dist/packages/cekirdek/src/turler.d.ts +8 -0
  33. package/package.json +5 -3
@@ -0,0 +1,155 @@
1
+ // Kaynak künyesi biçimlendirme: APA 7'ye benzer, Türkçe kısaltmalı, deterministik. Yalnız verilen bilgiyi dizer;
2
+ // eksik bilgi tahmin edilmez, künyede [EKSİK: ...] olarak görünür. Yazar adları yayımlanmış künyedir; bu araçta
3
+ // kişi adı deseni aranmaz (künye kuralı), e-posta ve telefon yine reddedilir.
4
+ import { z } from "zod";
5
+ import { arac, KOD_KAYNAGI } from "./temel.js";
6
+ const Kaynak = z.object({
7
+ tur: z.enum(["kitap", "makale", "kitap_bolumu", "web", "tez"]).default("kitap"),
8
+ yazarlar: z
9
+ .array(z.string().trim().min(2).max(120))
10
+ .max(25)
11
+ .default([])
12
+ .describe("'Soyad, Ad' ya da 'Ad Soyad'; kurum adı da olabilir"),
13
+ kurumYazar: z.boolean().default(false).describe("Yazar bir kurumsa (ör. Kurgu Bakanlığı) true"),
14
+ yil: z.union([z.number().int().min(1400).max(2100), z.string().trim().max(20)]).optional(),
15
+ baslik: z.string().trim().min(2).max(400),
16
+ baski: z.number().int().min(2).max(50).optional(),
17
+ yayinevi: z.string().trim().max(200).optional(),
18
+ dergi: z.string().trim().max(200).optional(),
19
+ cilt: z.string().trim().max(20).optional(),
20
+ sayi: z.string().trim().max(20).optional(),
21
+ sayfalar: z.string().trim().max(30).optional().describe("ör. '12-30'"),
22
+ editorler: z.array(z.string().trim().min(2).max(120)).max(10).optional(),
23
+ kitapBasligi: z.string().trim().max(400).optional(),
24
+ kurum: z.string().trim().max(200).optional().describe("Tezde üniversite"),
25
+ tezTuru: z.enum(["yuksek_lisans", "doktora"]).optional(),
26
+ site: z.string().trim().max(200).optional(),
27
+ doi: z.string().trim().max(200).optional(),
28
+ url: z.string().trim().max(500).optional(),
29
+ });
30
+ const bas = (s) => {
31
+ const h = [...s.trim()][0] ?? "";
32
+ return h ? `${h.toLocaleUpperCase("tr")}.` : "";
33
+ };
34
+ /** "Soyad, Ad İkinci" ya da "Ad İkinci Soyad" → "Soyad, A. İ." */
35
+ export function yazarBicimle(ad, kurum = false) {
36
+ const a = ad.trim().replace(/\s+/gu, " ");
37
+ if (kurum)
38
+ return a;
39
+ if (a.includes(",")) {
40
+ const [soyad, ...ilk] = a.split(",");
41
+ const adlar = ilk
42
+ .join(" ")
43
+ .trim()
44
+ .split(/[\s-]+/u)
45
+ .filter(Boolean);
46
+ return [soyad?.trim(), adlar.map(bas).join(" ")].filter(Boolean).join(", ");
47
+ }
48
+ const p = a.split(" ");
49
+ if (p.length === 1)
50
+ return a;
51
+ const soyad = p.at(-1) ?? "";
52
+ return `${soyad}, ${p.slice(0, -1).map(bas).join(" ")}`;
53
+ }
54
+ /** APA 7: 1 yazar "A"; 2 yazar "A, & B"; 3-20 yazar virgülle, sonuncudan önce "&"; 21+ ilk 19, "...", son. */
55
+ export function yazarListesi(yazarlar, kurum = false) {
56
+ const b = yazarlar.map((y) => yazarBicimle(y, kurum));
57
+ if (b.length === 0)
58
+ return "";
59
+ if (b.length === 1)
60
+ return b[0] ?? "";
61
+ if (b.length <= 20)
62
+ return `${b.slice(0, -1).join(", ")}, & ${b.at(-1)}`;
63
+ return `${b.slice(0, 19).join(", ")}, ... ${b.at(-1)}`;
64
+ }
65
+ const nokta = (s) => (/[.?!]$/u.test(s) ? s : `${s}.`);
66
+ const doiBagi = (d) => (/^https?:\/\//u.test(d) ? d : `https://doi.org/${d.replace(/^doi:\s*/iu, "")}`);
67
+ const editorKisa = (e) => {
68
+ const b = yazarBicimle(e);
69
+ const [soyad, bas] = b.split(", ");
70
+ return bas ? `${bas} ${soyad}` : b;
71
+ };
72
+ /** Tek künye. Eksik zorunlu bilgi [EKSİK: ...] olarak yazılır ve ayrıca listelenir. */
73
+ export function kunyeBicimle(k) {
74
+ const eksikler = [];
75
+ const eksik = (ad) => {
76
+ eksikler.push(ad);
77
+ return `[EKSİK: ${ad}]`;
78
+ };
79
+ const yazar = k.yazarlar.length ? yazarListesi(k.yazarlar, k.kurumYazar) : eksik("yazar");
80
+ const yil = k.yil === undefined || k.yil === "" ? "t.y." : String(k.yil);
81
+ if (yil === "t.y.")
82
+ eksikler.push("yıl (t.y. yazıldı)");
83
+ const parcalar = [`${nokta(yazar)} (${yil}).`];
84
+ const baski = k.baski ? ` (${k.baski}. bs.)` : "";
85
+ switch (k.tur) {
86
+ case "kitap":
87
+ parcalar.push(nokta(`${k.baslik}${baski}`), nokta(k.yayinevi || eksik("yayınevi")));
88
+ break;
89
+ case "makale": {
90
+ parcalar.push(nokta(k.baslik));
91
+ const dergi = k.dergi || eksik("dergi adı");
92
+ const cilt = k.cilt ? `, ${k.cilt}${k.sayi ? `(${k.sayi})` : ""}` : "";
93
+ const sayfa = k.sayfalar ? `, ${k.sayfalar}` : "";
94
+ parcalar.push(nokta(`${dergi}${cilt}${sayfa}`));
95
+ if (!k.cilt)
96
+ eksikler.push("cilt");
97
+ if (!k.sayfalar)
98
+ eksikler.push("sayfalar");
99
+ break;
100
+ }
101
+ case "kitap_bolumu": {
102
+ parcalar.push(nokta(k.baslik));
103
+ const ed = k.editorler?.length
104
+ ? `${k.editorler.map(editorKisa).join(", ")} (${k.editorler.length > 1 ? "Ed'ler" : "Ed."}), `
105
+ : "";
106
+ const kitap = k.kitapBasligi || eksik("kitap adı");
107
+ const ss = k.sayfalar ? ` (ss. ${k.sayfalar})` : "";
108
+ parcalar.push(nokta(`İçinde ${ed}${kitap}${baski}${ss}`), nokta(k.yayinevi || eksik("yayınevi")));
109
+ break;
110
+ }
111
+ case "tez": {
112
+ const tur = k.tezTuru === "doktora"
113
+ ? "Doktora tezi"
114
+ : k.tezTuru === "yuksek_lisans"
115
+ ? "Yüksek lisans tezi"
116
+ : eksik("tez türü");
117
+ parcalar.push(`${k.baslik} [${tur}, ${k.kurum || eksik("üniversite")}].`);
118
+ break;
119
+ }
120
+ case "web":
121
+ parcalar.push(nokta(k.baslik));
122
+ if (k.site)
123
+ parcalar.push(nokta(k.site));
124
+ if (!k.url)
125
+ parcalar.push(eksik("adres"));
126
+ break;
127
+ }
128
+ if (k.doi)
129
+ parcalar.push(doiBagi(k.doi));
130
+ else if (k.url)
131
+ parcalar.push(k.url);
132
+ return { kunye: parcalar.join(" ").replace(/\s+/gu, " ").trim(), eksikler };
133
+ }
134
+ export const kaynakBicimleAraci = arac({
135
+ ad: "kaynak_bicimle",
136
+ baslik: "Kaynak künyesi biçimle",
137
+ aciklama: "Hocanın verdiği kitap, makale, kitap bölümü, tez ya da web kaynağını APA 7'ye benzer Türkçe künyeye çevirir. Yalnız verilen bilgiyi dizer; eksik bilgi [EKSİK] olarak görünür, uydurulmaz.",
138
+ sonrakiAdim: "Künyeleri hocaya gösterin. Eserin varlığını kaynak_dogrula ile doğrulayın; doğrulanamayanı yazmayın. EKSİK bilgiyi tahmin etmeyin. Sonra künyeleri kaynaklar alanına koyun.",
139
+ kunyeAlanlari: ["kaynaklar"],
140
+ girdi: z.object({
141
+ kaynaklar: z.array(Kaynak).min(1).max(30),
142
+ }),
143
+ calistir: ({ kaynaklar }) => {
144
+ const sonuclar = kaynaklar.map((k, i) => ({ no: i + 1, ...kunyeBicimle(k) }));
145
+ return {
146
+ sonuc: {
147
+ kunyeler: sonuclar,
148
+ tamamlanan: sonuclar.filter((s) => !s.eksikler.length).length,
149
+ not: "Biçim APA 7'ye benzer bir Akredit biçimidir; kurumunuzun yazım kılavuzu farklıysa o önceliklidir. Eser bilgisinin doğruluğunu hoca denetler.",
150
+ uydurmaYok: "Bu araç yalnız verilen bilgiyi biçimlendirir. Asistan, kaynak_dogrula ile doğrulanmamış bir eseri önermez.",
151
+ },
152
+ kaynak: [KOD_KAYNAGI("apps/acik-mcp/src/kaynak.ts", "Akredit künye biçimleyici")],
153
+ };
154
+ },
155
+ });
@@ -1,3 +1,17 @@
1
- /** Girdide kişisel veri olabilecek türlerin adları (değerler değil). Boşsa temiz. */
2
- export declare function kisiselVeriTurleri(girdi: unknown): string[];
1
+ /**
2
+ * Girdide kişisel veri olabilecek türlerin adları (değerler değil). Boşsa temiz.
3
+ * `kunyeAnahtarlari`: altındaki metinler künye kuralıyla (yazar adı serbest) değerlendirilen alan adları.
4
+ */
5
+ export type KisiselVeriKapsami = "yok" | "ogrenci" | "tam";
6
+ /** HTML ise yalnız görünen metni bırakır (betik, stil, yorum, etiket ve öznitelikler atılır). Değilse aynen döner. */
7
+ export declare function gorunenMetin(x: string): string;
8
+ export declare function kisiselVeriTurleri(girdi: unknown, kunyeAnahtarlari?: readonly string[], kapsam?: KisiselVeriKapsami): string[];
3
9
  export declare function kisiselVeriIletisi(turler: readonly string[]): string;
10
+ /** Girdide giriş bilgisi var mı? Yalnız evet ya da hayır döner, değer döndürmez. */
11
+ export declare function girisBilgisiVar(girdi: unknown): boolean;
12
+ /** Yapıştırılan sayfadan oturum kimliklerini, parola kutularını ve çerez satırlarını bellekte atar. */
13
+ export declare function girisBilgisiAyikla(metin: string): {
14
+ metin: string;
15
+ atildi: boolean;
16
+ };
17
+ export declare const GIRIS_BILGISI_ILETISI = "G\u00F6nderdi\u011Finiz veride parola, do\u011Frulama kodu ya da oturum \u00E7erezi olabilecek bir ifade var. Akredit bu bilgileri istemez; g\u00F6r\u00FClen istek reddedildi ve kaydedilmedi. Bunlar\u0131 yaln\u0131z OBS'nin kendi giri\u015F ekran\u0131na siz yazars\u0131n\u0131z. O k\u0131sm\u0131 silip yeniden g\u00F6nderin. Parolan\u0131z\u0131 bir sohbete yazd\u0131ysan\u0131z OBS'de de\u011Fi\u015Ftirmeniz iyi olur.";
@@ -1,7 +1,22 @@
1
- // Gelen veride kişisel veri denetimi. Açık sunucu kişisel veri işlemez (CLAUDE.md ilke 7): desen görülürse
2
- // istek reddedilir, kullanıcıdan maskeleyip yeniden göndermesi istenir. Bulunan değer hiçbir yere yazılmaz,
3
- // yalnız türü söylenir. Desenler @akredit/yz KVKK maskeleyicisinden gelir (TCKN, telefon, e-posta, IBAN,
4
- // öğrenci numarası, unvanlı ya da yaygın adla başlayan kişi adı, adres, imza).
1
+ // Gelen veride kişisel veri ve giriş bilgisi denetimi. Bulunan değer hiçbir yere yazılmaz, yalnız türü söylenir.
2
+ // Desenler @akredit/yz KVKK maskeleyicisinden gelir.
3
+ //
4
+ // Kapsam (İP-49): hocanın kendi sayfasında yayımlanmış görev bilgisi (Dersi Verenler, Koordinatör, iletişim)
5
+ // kişisel veri sayılıp atılmaz; olduğu gibi okunur ve korunur. Araçlar kapsamı kendisi seçer:
6
+ // - "yok": yalnız giriş bilgisi denetlenir (kaynak doğrulama: künye ve katalog numaraları).
7
+ // - "ogrenci" (varsayılan; Bologna araçları da bunu kullanır): öğrenci ve kimlik verisi (T.C. kimlik no, öğrenci
8
+ // numarası, IBAN) reddedilir. Yayımlanmış öğretim elemanı adları serbesttir.
9
+ // - "tam": bütün desenler (not tablosu ve ÇK/PÇ: öğrenci adı ve numarası takma adla gelmelidir).
10
+ //
11
+ // Künye kuralı: kaynakçadaki yazar adları yayımlanmış künyedir, kişisel veri sayılmaz. Bu yüzden künye alanlarında
12
+ // (araç bunları adıyla bildirir) kişi adı ve etiketsiz uzun sayı (ISBN, katalog no) deseni aranmaz; e-posta,
13
+ // T.C. kimlik no, IBAN gibi öbür desenler yine aranır.
14
+ //
15
+ // Giriş bilgisi (ilke 8): parola, doğrulama kodu ve oturum çerezi istenmez. Yine de gönderilirse (sunucu isteği
16
+ // almadan bunu engelleyemez) desen görülür görülmez çağrı reddedilir, değer kaydedilmez ve yanıtta tekrarlanmaz.
17
+ //
18
+ // Başarım (dış inceleme 2026-11-05): HTML girdide desenler bütün kaynağa değil, yalnız görünen metne uygulanır
19
+ // (betik, stil, etiket ve öznitelikler önce atılır). Bağlantı adreslerindeki sayılar da böylece numara sayılmaz.
5
20
  import { maskele } from "../../../packages/yz/src/index.js";
6
21
  const TUR_ADI = {
7
22
  KİŞİ: "kişi adı",
@@ -13,28 +28,76 @@ const TUR_ADI = {
13
28
  ADRES: "adres",
14
29
  İMZA: "imza",
15
30
  };
16
- /** Bir girdideki bütün metinleri (anahtarlar dahil) gezer. */
17
- function metinler(deger, cikti = []) {
31
+ /** Bir girdideki bütün metinleri (anahtarlar dahil) gezer; künye alanlarındaki metinleri ayrı toplar. */
32
+ function metinler(deger, kunyeAnahtarlari, cikti = { genel: [], kunye: [] }, kunyede = false) {
18
33
  if (typeof deger === "string")
19
- cikti.push(deger);
34
+ (kunyede ? cikti.kunye : cikti.genel).push(deger);
20
35
  else if (Array.isArray(deger))
21
36
  for (const x of deger)
22
- metinler(x, cikti);
37
+ metinler(x, kunyeAnahtarlari, cikti, kunyede);
23
38
  else if (deger !== null && typeof deger === "object")
24
39
  for (const [k, v] of Object.entries(deger)) {
25
- cikti.push(k);
26
- metinler(v, cikti);
40
+ cikti.genel.push(k);
41
+ metinler(v, kunyeAnahtarlari, cikti, kunyede || kunyeAnahtarlari.has(k));
27
42
  }
28
43
  return cikti;
29
44
  }
30
- /** Girdide kişisel veri olabilecek türlerin adları (değerler değil). Boşsa temiz. */
31
- export function kisiselVeriTurleri(girdi) {
45
+ /** "ogrenci" kapsamında aranan türler; öbürleri (ad, e-posta, telefon, adres, imza) kapalıdır. */
46
+ const OGRENCI_TURLERI = ["TCKN", "ÖĞRENCİ-NO", "IBAN"];
47
+ const TUM_TURLER = Object.keys(TUR_ADI);
48
+ /** HTML ise yalnız görünen metni bırakır (betik, stil, yorum, etiket ve öznitelikler atılır). Değilse aynen döner. */
49
+ export function gorunenMetin(x) {
50
+ if (!/<\/?[a-z][\w-]*[\s>/]/iu.test(x))
51
+ return x;
52
+ return x
53
+ .replace(/<!--[\s\S]*?-->/gu, " ")
54
+ .replace(/<(script|style|noscript|template)\b[\s\S]*?<\/\1\s*>/giu, " ")
55
+ .replace(/<[^>]{0,2000}>/gu, " ")
56
+ .replace(/&nbsp;/gu, " ");
57
+ }
58
+ export function kisiselVeriTurleri(girdi, kunyeAnahtarlari = [], kapsam = "tam") {
59
+ if (kapsam === "yok")
60
+ return [];
61
+ const kapali = kapsam === "ogrenci" ? TUM_TURLER.filter((t) => !OGRENCI_TURLERI.includes(t)) : [];
62
+ const kunyeKapali = [...new Set([...kapali, "KİŞİ", "ÖĞRENCİ-NO"])];
32
63
  const turler = new Set();
33
- for (const m of metinler(girdi))
34
- for (const e of maskele(m).eslemeler)
64
+ const m = metinler(girdi, new Set(kunyeAnahtarlari));
65
+ for (const x of m.genel)
66
+ for (const e of maskele(gorunenMetin(x), { kapali }).eslemeler)
67
+ turler.add(e.tur);
68
+ for (const x of m.kunye)
69
+ for (const e of maskele(gorunenMetin(x), { kapali: kunyeKapali }).eslemeler)
35
70
  turler.add(e.tur);
36
71
  return [...turler].map((t) => TUR_ADI[t]);
37
72
  }
38
73
  export function kisiselVeriIletisi(turler) {
39
- return `Gönderdiğiniz veride kişisel veri olabilecek ifadeler var (${turler.join(", ")}). Bu sunucu kişisel veri işlemez. Adları, numaraları ve iletişim bilgilerini maskeleyip (ör. "Öğrenci 1", "[KİŞİ-1]") yeniden gönderin.`;
74
+ return `Gönderdiğiniz veride kişisel veri olabilecek ifadeler var (${turler.join(", ")}). Öğrenci ve kimlik bilgileri bu araca takma adla gelmelidir. Bu kısımları takma adla (ör. "o1", "Öğrenci 1") değiştirip yeniden gönderin.`;
75
+ }
76
+ const OTURUM_KIMLIGI = /\b(jsessionid|phpsessid|asp\.net_sessionid|aspsessionid\w*|sessionid|connect\.sid|laravel_session|\.aspxauth)\s*=\s*[\w%.-]{6,}/iu;
77
+ /** Giriş bilgisi desenleri: etiketli parola ya da doğrulama kodu, çerez başlığı, oturum kimliği, erişim belirteci. */
78
+ const GIRIS_DESENLERI = [
79
+ /(^|[^\p{L}])(parola|şifre|sifre|password|passwd|pwd)\s*[:=]\s*\S+/iu,
80
+ /(doğrulama kodu|dogrulama kodu|onay kodu|tek kullanımlık kod|sms kodu|verification code|otp|2fa kodu)\s*[:=]?\s*\d{4,8}(?!\d)/iu,
81
+ /\b(set-cookie|cookie)\s*:\s*\S+=/iu,
82
+ OTURUM_KIMLIGI,
83
+ /\bBearer\s+[\w.~+/-]{16,}=*/u,
84
+ ];
85
+ /** Girdide giriş bilgisi var mı? Yalnız evet ya da hayır döner, değer döndürmez. */
86
+ export function girisBilgisiVar(girdi) {
87
+ const m = metinler(girdi, new Set());
88
+ return [...m.genel, ...m.kunye].some((x) => GIRIS_DESENLERI.some((d) => d.test(x)));
89
+ }
90
+ /** Yapıştırılan sayfadan oturum kimliklerini, parola kutularını ve çerez satırlarını bellekte atar. */
91
+ export function girisBilgisiAyikla(metin) {
92
+ let atildi = false;
93
+ const at = () => {
94
+ atildi = true;
95
+ return "";
96
+ };
97
+ const yeni = metin
98
+ .replace(new RegExp(OTURUM_KIMLIGI.source, "giu"), at)
99
+ .replace(/<input\b[^>]*type\s*=\s*["']?password[^>]*>/giu, at)
100
+ .replace(/\b(set-cookie|cookie)\s*:[^\n]*/giu, at);
101
+ return { metin: yeni, atildi };
40
102
  }
103
+ export const GIRIS_BILGISI_ILETISI = "Gönderdiğiniz veride parola, doğrulama kodu ya da oturum çerezi olabilecek bir ifade var. Akredit bu bilgileri istemez; görülen istek reddedildi ve kaydedilmedi. Bunları yalnız OBS'nin kendi giriş ekranına siz yazarsınız. O kısmı silip yeniden gönderin. Parolanızı bir sohbete yazdıysanız OBS'de değiştirmeniz iyi olur.";
@@ -0,0 +1,39 @@
1
+ import { z } from "zod";
2
+ export type Ayirac = "\t" | ";" | ",";
3
+ export declare function ayiracBul(metin: string): Ayirac;
4
+ /** Basit CSV/TSV ayrıştırma; çift tırnaklı hücreleri destekler. */
5
+ export declare function tabloOku(metin: string): {
6
+ ayirac: Ayirac;
7
+ satirlar: string[][];
8
+ };
9
+ /** Kimlik sütunları: başlıktan ya da içerikten (çoğunluğu harfli metin ya da 7+ haneli sayı). */
10
+ export declare function kimlikSutunlari(satirlar: string[][]): number[];
11
+ /** Kimlik sütunu olmayan tablonun başına o1, o2 takma ad sütunu ekler. Başlıkta zaten takma ad varsa dokunmaz. */
12
+ export declare function takmaAdEkle(metin: string): string;
13
+ /** Tablodan kimlik sütunlarını atar, başa o1, o2 takma adı koyar. Yalnız bellekte çalışır. */
14
+ export declare function notTablosuAyikla(metin: string): {
15
+ tablo: string;
16
+ atilan: string[];
17
+ };
18
+ export interface Sutun {
19
+ baslik: string;
20
+ aracId: string;
21
+ tur: string;
22
+ aracAdi: string;
23
+ soruNo: string;
24
+ ciktilar: string[];
25
+ tamPuan: number | null;
26
+ }
27
+ /** Sütun başlığından araç, soru, tam puan ve ÇK eşlemesi sezgisi. "Vize S1 (ÇK2) /20" gibi. */
28
+ export declare function sutunCoz(baslik: string): Sutun | null;
29
+ /** Kişisel veri görülünce verilen ileti (aynen). */
30
+ export declare const NOT_TABLOSU_KISISEL_ILETI = "Ki\u015Fisel veriyi yapay zek\u00E2 sohbetine yap\u0131\u015Ft\u0131rmay\u0131n: Excel'de Ad, Soyad, Numara s\u00FCtunlar\u0131n\u0131 silip yaln\u0131z not s\u00FCtunlar\u0131n\u0131 yap\u0131\u015Ft\u0131r\u0131n ya da verinin taray\u0131c\u0131n\u0131zdan \u00E7\u0131kmad\u0131\u011F\u0131 hesaplay\u0131c\u0131y\u0131 kullan\u0131n: https://akredit.org/deneyin";
31
+ /** Tabloda kimlik sütunu (ad, soyad, numara...) ya da 9-11 haneli numara var mı? Varsa red iletisi döner. */
32
+ export declare function notTablosuKisiselVeri(metin: string): string | null;
33
+ export declare const SUTUN_ESLEME_REHBERI: string[];
34
+ export declare const notTablosuAyristirAraci: import("./temel.ts").AcikArac<z.ZodObject<{
35
+ tablo: z.ZodString;
36
+ tamPuanlar: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNumber>>;
37
+ eslemeler: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
38
+ agirliklar: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNumber>>;
39
+ }, z.core.$strip>>;
@@ -0,0 +1,268 @@
1
+ // Excel ya da CSV'den yapıştırılan not tablosunu ck_pc_hesapla girdisine hazırlar. Öğrenciler satır sırasına göre
2
+ // o1, o2, ... takma adı alır.
3
+ //
4
+ // Kişisel veri (dış inceleme 2026-11-05): tablo sohbete yapıştırıldığı anda yapay zekâ sağlayıcısına gitmiştir;
5
+ // sunucunun sonradan sütun atması bunu geri almaz. Bu yüzden ad, soyad ya da öğrenci numarası sütunu ya da 9-11
6
+ // haneli bir numara görülürse tablo işlenmez; hoca bu sütunları Excel'de silip yalnız not sütunlarını yapıştırır ya
7
+ // da verinin tarayıcıdan çıkmadığı hesaplayıcıyı kullanır. Değerler hiçbir yere yazılmaz. Sütun başlıklarından ölçme aracı, soru numarası, tam puan ve ders çıktısı (ÇK)
8
+ // eşlemesi sezilir; sezilemeyen bilgi tahmin edilmez, eksikler listesine girer. Sayılar yalnız tablodan okunur.
9
+ import { z } from "zod";
10
+ import { arac, KOD_KAYNAGI } from "./temel.js";
11
+ export function ayiracBul(metin) {
12
+ const satirlar = metin
13
+ .split(/\r?\n/u)
14
+ .filter((s) => s.trim())
15
+ .slice(0, 5);
16
+ if (satirlar.some((s) => s.includes("\t")))
17
+ return "\t";
18
+ const say = (c) => satirlar.reduce((t, s) => t + s.split(c).length - 1, 0);
19
+ return say(";") >= say(",") && say(";") > 0 ? ";" : ",";
20
+ }
21
+ /** Basit CSV/TSV ayrıştırma; çift tırnaklı hücreleri destekler. */
22
+ export function tabloOku(metin) {
23
+ const ayirac = ayiracBul(metin);
24
+ const satirlar = metin
25
+ .split(/\r?\n/u)
26
+ .filter((s) => s.trim())
27
+ .map((s) => {
28
+ const hucreler = [];
29
+ let h = "";
30
+ let tirnak = false;
31
+ for (const ch of s) {
32
+ if (ch === '"')
33
+ tirnak = !tirnak;
34
+ else if (ch === ayirac && !tirnak) {
35
+ hucreler.push(h.trim());
36
+ h = "";
37
+ }
38
+ else
39
+ h += ch;
40
+ }
41
+ hucreler.push(h.trim());
42
+ return hucreler;
43
+ });
44
+ return { ayirac, satirlar };
45
+ }
46
+ const KIMLIK_BASLIGI = /^(ad|adı|isim|soyad|soyadı|ad soyad|adı soyadı|ad-soyad|öğrenci|öğrenci adı|öğrenci no|öğrenci numarası|numara|numarası|no|okul no|sıra|sıra no|tc|tc no|t\.c\.|tc kimlik|kimlik|e-?posta|email|e-mail|name|first name|last name|surname|full name|student|student id|student no|student number|student name|id)$/iu;
47
+ const HESAP_BASLIGI = /^(toplam|ortalama|ort|not|harf|harf notu|başarı notu|sonuç|durum|total|average|grade|letter|result)$/iu;
48
+ const kucuk = (s) => s.toLocaleLowerCase("tr").trim();
49
+ /** Başlık eşlemesi: hem olduğu gibi (ID) hem Türkçe küçük harfle (ADI SOYADI) denenir. */
50
+ const esler = (re, b) => re.test(b.trim()) || re.test(kucuk(b));
51
+ /** Kimlik sütunları: başlıktan ya da içerikten (çoğunluğu harfli metin ya da 7+ haneli sayı). */
52
+ export function kimlikSutunlari(satirlar) {
53
+ const [baslik = [], ...veri] = satirlar;
54
+ const sonuc = [];
55
+ baslik.forEach((b, j) => {
56
+ const degerler = veri.map((r) => r[j] ?? "").filter((x) => x.trim());
57
+ const harfli = degerler.filter((x) => /\p{L}{2,}/u.test(x) && !/^[-–]?$/u.test(x)).length;
58
+ const uzunSayi = degerler.filter((x) => /^\d{7,}$/u.test(x.replace(/\s/gu, ""))).length;
59
+ const yari = degerler.length / 2;
60
+ if (esler(KIMLIK_BASLIGI, b) || (degerler.length && (harfli > yari || uzunSayi > yari)))
61
+ if (!esler(HESAP_BASLIGI, b) || uzunSayi > yari)
62
+ sonuc.push(j);
63
+ });
64
+ return sonuc;
65
+ }
66
+ /** Kimlik sütunu olmayan tablonun başına o1, o2 takma ad sütunu ekler. Başlıkta zaten takma ad varsa dokunmaz. */
67
+ export function takmaAdEkle(metin) {
68
+ const { satirlar } = tabloOku(metin);
69
+ if (satirlar.length < 2 || /^takma ad$/iu.test((satirlar[0]?.[0] ?? "").trim()))
70
+ return metin;
71
+ return satirlar.map((r, i) => [i === 0 ? "Takma ad" : `o${i}`, ...r].join("\t")).join("\n");
72
+ }
73
+ /** Tablodan kimlik sütunlarını atar, başa o1, o2 takma adı koyar. Yalnız bellekte çalışır. */
74
+ export function notTablosuAyikla(metin) {
75
+ const { satirlar } = tabloOku(metin);
76
+ if (satirlar.length < 2)
77
+ return { tablo: metin, atilan: [] };
78
+ const kimlik = new Set(kimlikSutunlari(satirlar));
79
+ const baslik = satirlar[0] ?? [];
80
+ const atilan = [...kimlik].map((j) => `"${(baslik[j] ?? `${j + 1}. sütun`).slice(0, 30)}" sütunu`);
81
+ const yeni = satirlar.map((r, i) => [i === 0 ? "Takma ad" : `o${i}`, ...r.filter((_, j) => !kimlik.has(j))]);
82
+ return { tablo: yeni.map((r) => r.join("\t")).join("\n"), atilan };
83
+ }
84
+ const ARAC_TURLERI = [
85
+ [/^(vize|ara ?sınav|ara|midterm|mt|as)\b/iu, "ara_sinav", "Ara Sınav"],
86
+ [/^(final|yarıyıl sonu|yys|fin|dönem sonu)\b/iu, "yariyil_sonu", "Yarıyıl Sonu Sınavı"],
87
+ [/^(bütünleme|but|bütünleme sınavı|makeup|resit)\b/iu, "butunleme", "Bütünleme"],
88
+ [/^(quiz|kısa ?sınav|ks)\b/iu, "kisa_sinav", "Kısa Sınav"],
89
+ [/^(ödev|odev|hw|homework|assignment)\b/iu, "odev", "Ödev"],
90
+ [/^(proje|project)\b/iu, "proje", "Proje"],
91
+ [/^(lab|laboratuvar|laboratory)\b/iu, "laboratuvar", "Laboratuvar"],
92
+ [/^(sunum|presentation)\b/iu, "sunum", "Sunum"],
93
+ [/^(uygulama|practice)\b/iu, "uygulama", "Uygulama"],
94
+ ];
95
+ /** Sütun başlığından araç, soru, tam puan ve ÇK eşlemesi sezgisi. "Vize S1 (ÇK2) /20" gibi. */
96
+ export function sutunCoz(baslik) {
97
+ const b = baslik.trim();
98
+ if (!b || esler(HESAP_BASLIGI, b))
99
+ return null;
100
+ const tur = ARAC_TURLERI.find(([re]) => re.test(b));
101
+ const ciktilar = [...b.matchAll(/(?:ÇK|ÖÇ|DÖÇ|LO|CLO|Ö)\s*-?\s*(\d{1,2})/giu)].map((m) => `Ö${Number(m[1])}`);
102
+ const tamPuanEslesme = b.match(/\/\s*(\d+(?:[.,]\d+)?)\s*$/u) ?? b.match(/\(\s*(\d+(?:[.,]\d+)?)\s*(?:p|puan|pts|points)\s*\)/iu);
103
+ const tamPuan = tamPuanEslesme ? Number((tamPuanEslesme[1] ?? "").replace(",", ".")) : null;
104
+ const sade = b
105
+ .replace(/(?:ÇK|ÖÇ|DÖÇ|LO|CLO|Ö)\s*-?\s*\d{1,2}/giu, "")
106
+ .replace(/\/\s*\d+(?:[.,]\d+)?\s*$/u, "")
107
+ .replace(/\(\s*\d+(?:[.,]\d+)?\s*(?:p|puan|pts|points)\s*\)/iu, "");
108
+ const soru = sade.match(/(?:^|[\s_.-])(?:s|soru|q|question)\s*\.?\s*(\d{1,3})\b/iu)?.[1];
109
+ const aracParca = tur ? (sade.match(tur[0])?.[0] ?? "") : "";
110
+ const aracNo = tur ? sade.slice(aracParca.length).match(/^\s*(\d)(?!\d)/u)?.[1] : undefined;
111
+ if (!tur && !soru)
112
+ return null;
113
+ const aracId = tur ? `${tur[1]}${aracNo ? `_${aracNo}` : ""}` : "sinav";
114
+ const aracAdi = tur ? `${tur[2]}${aracNo ? ` ${aracNo}` : ""}` : "Sınav";
115
+ return { baslik: b, aracId, tur: tur?.[1] ?? "diger", aracAdi, soruNo: soru ?? "1", ciktilar, tamPuan };
116
+ }
117
+ const puanOku = (s, ayirac) => {
118
+ const t = s.trim().replace(/\s/gu, "");
119
+ if (!t || /^(-|–|g|gm|girmedi|yok|na|n\/a)$/iu.test(t))
120
+ return null;
121
+ const n = Number(ayirac === "," ? t : t.replace(",", "."));
122
+ return Number.isFinite(n) ? n : null;
123
+ };
124
+ /** Kişisel veri görülünce verilen ileti (aynen). */
125
+ export const NOT_TABLOSU_KISISEL_ILETI = "Kişisel veriyi yapay zekâ sohbetine yapıştırmayın: Excel'de Ad, Soyad, Numara sütunlarını silip yalnız not sütunlarını yapıştırın ya da verinin tarayıcınızdan çıkmadığı hesaplayıcıyı kullanın: https://akredit.org/deneyin";
126
+ const UZUN_NUMARA = /(?<![\d.,])\d{9,11}(?![\d.,]\d)/u;
127
+ /** Tabloda kimlik sütunu (ad, soyad, numara...) ya da 9-11 haneli numara var mı? Varsa red iletisi döner. */
128
+ export function notTablosuKisiselVeri(metin) {
129
+ const { satirlar } = tabloOku(metin);
130
+ if (satirlar.length >= 2 && kimlikSutunlari(satirlar).length)
131
+ return NOT_TABLOSU_KISISEL_ILETI;
132
+ if (satirlar.some((r) => r.some((h) => UZUN_NUMARA.test(h.replace(/\s/gu, "")))))
133
+ return NOT_TABLOSU_KISISEL_ILETI;
134
+ return null;
135
+ }
136
+ export const SUTUN_ESLEME_REHBERI = [
137
+ "Excel'de ilk satır başlık olsun: her soru ya da ölçme için bir sütun.",
138
+ "Başlık örnekleri: 'Vize S1 (ÇK1) /20', 'Vize S2 (ÇK2) /30', 'Final S1 ÇK3 /50', 'Ödev ÇK4 /100'.",
139
+ "Başlıkta sınavın adı (Vize, Final, Ödev, Proje, Quiz), soru numarası (S1, Soru 2), ölçtüğü ders çıktısı (ÇK1 ya da Ö1) ve tam puanı (/20 ya da (20p)) olsun.",
140
+ "Ad, Soyad ve Numara sütunlarını yapıştırmadan önce Excel'de silin: yalnız not sütunları gelsin. Kimlik sütunu ya da numara görülürse tablo işlenmez. Öğrenciler o1, o2 diye takma ad alır.",
141
+ "Toplam, Ortalama, Harf sütunları yok sayılır.",
142
+ "Boş, '-' ya da 'G' (girmedi) hücreleri boş puan sayılır.",
143
+ "Tabloyu Excel'de seçip Ctrl+C ile kopyalayın, sohbete Ctrl+V ile yapıştırın.",
144
+ ];
145
+ export const notTablosuAyristirAraci = arac({
146
+ ad: "not_tablosu_ayristir",
147
+ baslik: "Not tablosunu ayrıştır",
148
+ aciklama: "Excel ya da CSV'den yapıştırılan not tablosunu ÇK/PÇ hesabına hazırlar. Tabloda yalnız not sütunları olmalı: ad, soyad ya da numara sütunu ya da 9-11 haneli numara görülürse tablo işlenmez. Öğrencilere o1, o2 takma adı verir. Başlıklardan sınav, soru, tam puan ve ders çıktısı eşlemesini sezer; eksikleri listeler.",
149
+ sonrakiAdim: "Sezilen eşlemeyi hocaya tablo olarak gösterin ve eksikleri tek tek seçenekle sorun (ör. S3 hangi çıktıyı ölçüyor? 1) Ö2 2) Ö3). Eksik kalmayınca ckPcHesaplaTaslagi'ni ck_pc_hesapla'ya verin.",
150
+ kisiselVeriIpucu: NOT_TABLOSU_KISISEL_ILETI,
151
+ kisiselVeriKapsami: "tam",
152
+ onDenetim: (g) => {
153
+ const t = g?.tablo;
154
+ return typeof t === "string" ? notTablosuKisiselVeri(t) : null;
155
+ },
156
+ onAyikla: (g) => {
157
+ // Kimlik sütunu yoksa tablo yalnız not sütunlarıdır; başa o1, o2 takma adı eklenir (sütun atılmaz).
158
+ const t = g?.tablo;
159
+ if (typeof t !== "string")
160
+ return { girdi: g, atilan: [] };
161
+ return { girdi: { ...g, tablo: takmaAdEkle(t) }, atilan: [] };
162
+ },
163
+ girdi: z.object({
164
+ tablo: z
165
+ .string()
166
+ .min(5)
167
+ .max(400_000)
168
+ .describe("Excel ya da CSV'den yapıştırılan, yalnız not sütunlarından oluşan tablo; ilk satır başlık"),
169
+ tamPuanlar: z
170
+ .record(z.string().max(80), z.number().positive().max(1000))
171
+ .optional()
172
+ .describe("Sütun başlığı → tam puan; başlıkta yoksa"),
173
+ eslemeler: z
174
+ .record(z.string().max(80), z.array(z.string().max(10)).max(10))
175
+ .optional()
176
+ .describe("Sütun başlığı → ders çıktısı kodları (Ö1, Ö2); başlıkta yoksa"),
177
+ agirliklar: z
178
+ .record(z.string().max(40), z.number().min(0).max(100))
179
+ .optional()
180
+ .describe("Ölçme aracı kimliği (ara_sinav, yariyil_sonu, odev...) → ders notundaki yüzde"),
181
+ }),
182
+ calistir: ({ tablo, tamPuanlar = {}, eslemeler = {}, agirliklar = {} }) => {
183
+ const { ayirac, satirlar } = tabloOku(tablo);
184
+ const [baslik = [], ...veri] = satirlar;
185
+ const sutunlar = baslik.map((b, j) => (j === 0 ? null : sutunCoz(b)));
186
+ const yoksayilan = baslik.filter((_, j) => j > 0 && !sutunlar[j]);
187
+ const kullanilan = sutunlar
188
+ .map((s, j) => (s ? { ...s, j } : null))
189
+ .filter((s) => s !== null)
190
+ .map((s) => ({
191
+ ...s,
192
+ tamPuan: tamPuanlar[s.baslik] ?? s.tamPuan,
193
+ ciktilar: eslemeler[s.baslik] ?? s.ciktilar,
194
+ }));
195
+ const eksikler = [];
196
+ if (!kullanilan.length)
197
+ eksikler.push("Hiçbir sütunda sınav ya da soru bulunamadı. Başlıkları sütun eşleme rehberine göre düzenleyin.");
198
+ for (const s of kullanilan) {
199
+ if (s.tamPuan === null)
200
+ eksikler.push(`"${s.baslik}" sütununun tam puanı yok.`);
201
+ if (!s.ciktilar.length)
202
+ eksikler.push(`"${s.baslik}" sütununun hangi ders çıktısını ölçtüğü yok.`);
203
+ }
204
+ const aracIdleri = [...new Set(kullanilan.map((s) => s.aracId))];
205
+ for (const id of aracIdleri)
206
+ if (agirliklar[id] === undefined)
207
+ eksikler.push(`"${id}" ölçme aracının ders notundaki yüzdesi yok.`);
208
+ // Aynı araçta aynı soru numarası iki kez geçerse ikinciye sütun sırası eklenir.
209
+ const gorulen = new Set();
210
+ for (const s of kullanilan) {
211
+ const k = `${s.aracId}/${s.soruNo}`;
212
+ if (gorulen.has(k))
213
+ s.soruNo = `${s.soruNo}_${s.j + 1}`;
214
+ gorulen.add(`${s.aracId}/${s.soruNo}`);
215
+ }
216
+ const asim = [];
217
+ const puanlar = veri.flatMap((r) => kullanilan.map((s) => {
218
+ const p = puanOku(r[s.j] ?? "", ayirac);
219
+ if (p !== null && s.tamPuan !== null && p > s.tamPuan)
220
+ asim.push(`${r[0]}: "${s.baslik}" ${p} > ${s.tamPuan}`);
221
+ return { ogrenci: r[0] ?? "", aracId: s.aracId, soruNo: s.soruNo, puan: p };
222
+ }));
223
+ if (asim.length)
224
+ eksikler.push(`${asim.length} hücrede puan tam puanı aşıyor (ilk: ${asim[0]}). Tabloyu denetleyin.`);
225
+ const agirlikToplami = aracIdleri.reduce((t, id) => t + (agirliklar[id] ?? 0), 0);
226
+ if (aracIdleri.every((id) => agirliklar[id] !== undefined) && Math.abs(agirlikToplami - 100) > 0.001)
227
+ eksikler.push(`Ölçme aracı yüzdeleri toplamı ${agirlikToplami}; 100 olmalı (bütünleme hariç tutulabilir).`);
228
+ const araclar = aracIdleri.map((id) => {
229
+ const ss = kullanilan.filter((s) => s.aracId === id);
230
+ return {
231
+ id,
232
+ tur: ss[0]?.tur ?? "diger",
233
+ ad: ss[0]?.aracAdi ?? id,
234
+ agirlik: agirliklar[id] ?? null,
235
+ sorular: ss.map((s) => ({
236
+ no: s.soruNo,
237
+ tamPuan: s.tamPuan,
238
+ eslemeler: s.ciktilar.map((c) => ({ ciktiKod: c, agirlik: 1 })),
239
+ })),
240
+ };
241
+ });
242
+ const ciktilar = [...new Set(kullanilan.flatMap((s) => s.ciktilar))].sort((a, b) => Number(a.slice(1)) - Number(b.slice(1)));
243
+ return {
244
+ sonuc: {
245
+ ogrenciSayisi: veri.length,
246
+ ayirac: ayirac === "\t" ? "sekme" : ayirac,
247
+ sutunlar: kullanilan.map(({ j: _j, ...s }) => s),
248
+ yoksayilanSutunlar: yoksayilan,
249
+ ciktilar,
250
+ eksikler,
251
+ hazir: eksikler.length === 0,
252
+ ckPcHesaplaTaslagi: {
253
+ ciktilar: ciktilar.map((kod) => ({ kod })),
254
+ araclar,
255
+ puanlar,
256
+ not: "dersKodu ve donem alanlarını hocadan alıp ekleyin. Eksik kalmayınca ck_pc_hesapla'ya verin.",
257
+ },
258
+ sutunEslemeRehberi: SUTUN_ESLEME_REHBERI,
259
+ },
260
+ kaynak: [KOD_KAYNAGI("apps/acik-mcp/src/not-tablosu.ts", "Akredit not tablosu ayrıştırıcısı")],
261
+ ...(eksikler.length
262
+ ? {
263
+ sonrakiAdim: "Eksikleri hocaya numaralı ve tek tek, seçenekle sorun; yanıtları tamPuanlar, eslemeler ve agirliklar olarak verip aracı yeniden çağırın. Tabloyu yeniden yapıştırtmayın, aynı tabloyu kullanın.",
264
+ }
265
+ : {}),
266
+ };
267
+ },
268
+ });
@@ -0,0 +1,48 @@
1
+ import { z } from "zod";
2
+ export interface AcikIstem {
3
+ ad: string;
4
+ baslik: string;
5
+ aciklama: string;
6
+ /** Bağımsız değişkenler: hepsi isteğe bağlı kısa metin. */
7
+ argumanlar: Record<string, string>;
8
+ metin: (a: Record<string, string | undefined>) => string;
9
+ }
10
+ /** Giriş bilgisi kuralı: bütün istemlerde aynen yer alır. */
11
+ export declare const GIRIS_BILGISI_KURALI: string;
12
+ /** Akıllı doldurma kısayolu: bütün menülerde aynı numara ve aynı anlam. */
13
+ export declare const AKILLI_DOLDURMA_SECENEGI = "4) Hepsini ak\u0131ll\u0131ca doldur (\u00F6nerilen)";
14
+ /** "4) Hepsini akıllıca doldur" seçildiğinde (ya da hoca "sen seç", "hepsi" derse) izlenecek yol. */
15
+ /** Bilinmesi mümkün olmayan ve resmî taahhüt olan bilgiler: sayfadan okunur, yoksa tek mesajda sorulur. */
16
+ export declare const TEYIT_SORULARI: string;
17
+ export declare const AKILLI_DOLDURMA: string;
18
+ /** Bütün istemlerde ortak çalışma biçimi. */
19
+ export declare const ORTAK_KURALLAR: string;
20
+ /** akredit başlangıcının sorduğu odak menüsü; site örnek konuşmayı buradan okur. */
21
+ export declare const AKREDIT_ODAKLARI: readonly {
22
+ no: string;
23
+ ad: string;
24
+ }[];
25
+ export declare const ACIK_ISTEMLER: readonly AcikIstem[];
26
+ /** Kısa kurallar: akredit_basla yanıtında (istem desteklemeyen istemciler için) yer alır. */
27
+ export declare const KISA_KURALLAR: string[];
28
+ /** akredit_basla aracının yanıtı: menü, kısa kurallar ve her seçimin akışı (istem desteklemeyen istemciler için). */
29
+ export declare function baslangic(): {
30
+ hocayaGoster: string;
31
+ menu: ({
32
+ no: "1" | "2" | "3" | "4" | "5";
33
+ ad: "Bologna ders paketini denetle ve boş alanları doldur" | "Ders öğrenme çıktısı yaz ya da iyileştir" | "ÇK ve PÇ sağlanma düzeyini hesapla" | "YÖKAK, MÜDEK, FEDEK, EPDAD ya da SABAK ölçüt ve kanıt rehberi" | "Öz değerlendirme metninin dil denetimi";
34
+ istem: "bologna_doldur" | "cikti_yaz" | "ck_pc_hesabi" | "olcut_rehberi" | "dil_denetimi";
35
+ } | {
36
+ no: string;
37
+ ad: string;
38
+ istem: null;
39
+ })[];
40
+ kisaKurallar: string[];
41
+ akislar: {
42
+ [k: string]: string;
43
+ };
44
+ ortakKurallar: string;
45
+ };
46
+ export declare const akreditBaslaAraci: import("./temel.ts").AcikArac<z.ZodObject<{}, z.core.$strip>>;
47
+ /** SDK için bağımsız değişken şeması: hepsi isteğe bağlı, kısa metin. */
48
+ export declare const istemSemasi: (i: AcikIstem) => Record<string, z.ZodOptional<z.ZodString>>;