@akredit/acik-mcp 0.1.0 → 0.4.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 (29) 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 +27 -114
  4. package/dist/apps/acik-mcp/src/bologna.d.ts +209 -0
  5. package/dist/apps/acik-mcp/src/bologna.js +1321 -0
  6. package/dist/apps/acik-mcp/src/genel-ayristir.d.ts +83 -0
  7. package/dist/apps/acik-mcp/src/genel-ayristir.js +411 -0
  8. package/dist/apps/acik-mcp/src/http.js +4 -2
  9. package/dist/apps/acik-mcp/src/index.d.ts +6 -0
  10. package/dist/apps/acik-mcp/src/index.js +6 -0
  11. package/dist/apps/acik-mcp/src/kaynak-dogrula.d.ts +47 -0
  12. package/dist/apps/acik-mcp/src/kaynak-dogrula.js +319 -0
  13. package/dist/apps/acik-mcp/src/kaynak.d.ts +72 -0
  14. package/dist/apps/acik-mcp/src/kaynak.js +155 -0
  15. package/dist/apps/acik-mcp/src/kisisel-veri.d.ts +14 -2
  16. package/dist/apps/acik-mcp/src/kisisel-veri.js +63 -15
  17. package/dist/apps/acik-mcp/src/not-tablosu.d.ts +33 -0
  18. package/dist/apps/acik-mcp/src/not-tablosu.js +243 -0
  19. package/dist/apps/acik-mcp/src/promptlar.d.ts +25 -0
  20. package/dist/apps/acik-mcp/src/promptlar.js +253 -0
  21. package/dist/apps/acik-mcp/src/sunucu.d.ts +12 -4
  22. package/dist/apps/acik-mcp/src/sunucu.js +103 -24
  23. package/dist/apps/acik-mcp/src/temel.d.ts +54 -0
  24. package/dist/apps/acik-mcp/src/temel.js +10 -0
  25. package/dist/apps/acik-mcp/src/yardim.d.ts +56 -0
  26. package/dist/apps/acik-mcp/src/yardim.js +371 -0
  27. package/dist/packages/baglayicilar/src/bologna-proliz/ayristir.d.ts +29 -0
  28. package/dist/packages/baglayicilar/src/bologna-proliz/ayristir.js +200 -0
  29. package/package.json +4 -2
@@ -0,0 +1,33 @@
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
+ /** Tablodan kimlik sütunlarını atar, başa o1, o2 takma adı koyar. Yalnız bellekte çalışır. */
12
+ export declare function notTablosuAyikla(metin: string): {
13
+ tablo: string;
14
+ atilan: string[];
15
+ };
16
+ export interface Sutun {
17
+ baslik: string;
18
+ aracId: string;
19
+ tur: string;
20
+ aracAdi: string;
21
+ soruNo: string;
22
+ ciktilar: string[];
23
+ tamPuan: number | null;
24
+ }
25
+ /** Sütun başlığından araç, soru, tam puan ve ÇK eşlemesi sezgisi. "Vize S1 (ÇK2) /20" gibi. */
26
+ export declare function sutunCoz(baslik: string): Sutun | null;
27
+ export declare const SUTUN_ESLEME_REHBERI: string[];
28
+ export declare const notTablosuAyristirAraci: import("./temel.ts").AcikArac<z.ZodObject<{
29
+ tablo: z.ZodString;
30
+ tamPuanlar: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNumber>>;
31
+ eslemeler: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
32
+ agirliklar: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNumber>>;
33
+ }, z.core.$strip>>;
@@ -0,0 +1,243 @@
1
+ // Excel ya da CSV'den yapıştırılan not tablosunu ck_pc_hesapla girdisine hazırlar. Öğrenci kimliği (ad, soyad,
2
+ // numara, e-posta) ayrıştırmadan önce bellekte atılır ve satır sırasına göre o1, o2, ... takma adı verilir; atılan
3
+ // 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)
4
+ // eşlemesi sezilir; sezilemeyen bilgi tahmin edilmez, eksikler listesine girer. Sayılar yalnız tablodan okunur.
5
+ import { z } from "zod";
6
+ import { arac, KOD_KAYNAGI } from "./temel.js";
7
+ export function ayiracBul(metin) {
8
+ const satirlar = metin
9
+ .split(/\r?\n/u)
10
+ .filter((s) => s.trim())
11
+ .slice(0, 5);
12
+ if (satirlar.some((s) => s.includes("\t")))
13
+ return "\t";
14
+ const say = (c) => satirlar.reduce((t, s) => t + s.split(c).length - 1, 0);
15
+ return say(";") >= say(",") && say(";") > 0 ? ";" : ",";
16
+ }
17
+ /** Basit CSV/TSV ayrıştırma; çift tırnaklı hücreleri destekler. */
18
+ export function tabloOku(metin) {
19
+ const ayirac = ayiracBul(metin);
20
+ const satirlar = metin
21
+ .split(/\r?\n/u)
22
+ .filter((s) => s.trim())
23
+ .map((s) => {
24
+ const hucreler = [];
25
+ let h = "";
26
+ let tirnak = false;
27
+ for (const ch of s) {
28
+ if (ch === '"')
29
+ tirnak = !tirnak;
30
+ else if (ch === ayirac && !tirnak) {
31
+ hucreler.push(h.trim());
32
+ h = "";
33
+ }
34
+ else
35
+ h += ch;
36
+ }
37
+ hucreler.push(h.trim());
38
+ return hucreler;
39
+ });
40
+ return { ayirac, satirlar };
41
+ }
42
+ 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;
43
+ const HESAP_BASLIGI = /^(toplam|ortalama|ort|not|harf|harf notu|başarı notu|sonuç|durum|total|average|grade|letter|result)$/iu;
44
+ const kucuk = (s) => s.toLocaleLowerCase("tr").trim();
45
+ /** Başlık eşlemesi: hem olduğu gibi (ID) hem Türkçe küçük harfle (ADI SOYADI) denenir. */
46
+ const esler = (re, b) => re.test(b.trim()) || re.test(kucuk(b));
47
+ /** Kimlik sütunları: başlıktan ya da içerikten (çoğunluğu harfli metin ya da 7+ haneli sayı). */
48
+ export function kimlikSutunlari(satirlar) {
49
+ const [baslik = [], ...veri] = satirlar;
50
+ const sonuc = [];
51
+ baslik.forEach((b, j) => {
52
+ const degerler = veri.map((r) => r[j] ?? "").filter((x) => x.trim());
53
+ const harfli = degerler.filter((x) => /\p{L}{2,}/u.test(x) && !/^[-–]?$/u.test(x)).length;
54
+ const uzunSayi = degerler.filter((x) => /^\d{7,}$/u.test(x.replace(/\s/gu, ""))).length;
55
+ const yari = degerler.length / 2;
56
+ if (esler(KIMLIK_BASLIGI, b) || (degerler.length && (harfli > yari || uzunSayi > yari)))
57
+ if (!esler(HESAP_BASLIGI, b) || uzunSayi > yari)
58
+ sonuc.push(j);
59
+ });
60
+ return sonuc;
61
+ }
62
+ /** Tablodan kimlik sütunlarını atar, başa o1, o2 takma adı koyar. Yalnız bellekte çalışır. */
63
+ export function notTablosuAyikla(metin) {
64
+ const { satirlar } = tabloOku(metin);
65
+ if (satirlar.length < 2)
66
+ return { tablo: metin, atilan: [] };
67
+ const kimlik = new Set(kimlikSutunlari(satirlar));
68
+ const baslik = satirlar[0] ?? [];
69
+ const atilan = [...kimlik].map((j) => `"${(baslik[j] ?? `${j + 1}. sütun`).slice(0, 30)}" sütunu`);
70
+ const yeni = satirlar.map((r, i) => [i === 0 ? "Takma ad" : `o${i}`, ...r.filter((_, j) => !kimlik.has(j))]);
71
+ return { tablo: yeni.map((r) => r.join("\t")).join("\n"), atilan };
72
+ }
73
+ const ARAC_TURLERI = [
74
+ [/^(vize|ara ?sınav|ara|midterm|mt|as)\b/iu, "ara_sinav", "Ara Sınav"],
75
+ [/^(final|yarıyıl sonu|yys|fin|dönem sonu)\b/iu, "yariyil_sonu", "Yarıyıl Sonu Sınavı"],
76
+ [/^(bütünleme|but|bütünleme sınavı|makeup|resit)\b/iu, "butunleme", "Bütünleme"],
77
+ [/^(quiz|kısa ?sınav|ks)\b/iu, "kisa_sinav", "Kısa Sınav"],
78
+ [/^(ödev|odev|hw|homework|assignment)\b/iu, "odev", "Ödev"],
79
+ [/^(proje|project)\b/iu, "proje", "Proje"],
80
+ [/^(lab|laboratuvar|laboratory)\b/iu, "laboratuvar", "Laboratuvar"],
81
+ [/^(sunum|presentation)\b/iu, "sunum", "Sunum"],
82
+ [/^(uygulama|practice)\b/iu, "uygulama", "Uygulama"],
83
+ ];
84
+ /** Sütun başlığından araç, soru, tam puan ve ÇK eşlemesi sezgisi. "Vize S1 (ÇK2) /20" gibi. */
85
+ export function sutunCoz(baslik) {
86
+ const b = baslik.trim();
87
+ if (!b || esler(HESAP_BASLIGI, b))
88
+ return null;
89
+ const tur = ARAC_TURLERI.find(([re]) => re.test(b));
90
+ const ciktilar = [...b.matchAll(/(?:ÇK|ÖÇ|DÖÇ|LO|CLO|Ö)\s*-?\s*(\d{1,2})/giu)].map((m) => `Ö${Number(m[1])}`);
91
+ const tamPuanEslesme = b.match(/\/\s*(\d+(?:[.,]\d+)?)\s*$/u) ?? b.match(/\(\s*(\d+(?:[.,]\d+)?)\s*(?:p|puan|pts|points)\s*\)/iu);
92
+ const tamPuan = tamPuanEslesme ? Number((tamPuanEslesme[1] ?? "").replace(",", ".")) : null;
93
+ const sade = b
94
+ .replace(/(?:ÇK|ÖÇ|DÖÇ|LO|CLO|Ö)\s*-?\s*\d{1,2}/giu, "")
95
+ .replace(/\/\s*\d+(?:[.,]\d+)?\s*$/u, "")
96
+ .replace(/\(\s*\d+(?:[.,]\d+)?\s*(?:p|puan|pts|points)\s*\)/iu, "");
97
+ const soru = sade.match(/(?:^|[\s_.-])(?:s|soru|q|question)\s*\.?\s*(\d{1,3})\b/iu)?.[1];
98
+ const aracParca = tur ? (sade.match(tur[0])?.[0] ?? "") : "";
99
+ const aracNo = tur ? sade.slice(aracParca.length).match(/^\s*(\d)(?!\d)/u)?.[1] : undefined;
100
+ if (!tur && !soru)
101
+ return null;
102
+ const aracId = tur ? `${tur[1]}${aracNo ? `_${aracNo}` : ""}` : "sinav";
103
+ const aracAdi = tur ? `${tur[2]}${aracNo ? ` ${aracNo}` : ""}` : "Sınav";
104
+ return { baslik: b, aracId, tur: tur?.[1] ?? "diger", aracAdi, soruNo: soru ?? "1", ciktilar, tamPuan };
105
+ }
106
+ const puanOku = (s, ayirac) => {
107
+ const t = s.trim().replace(/\s/gu, "");
108
+ if (!t || /^(-|–|g|gm|girmedi|yok|na|n\/a)$/iu.test(t))
109
+ return null;
110
+ const n = Number(ayirac === "," ? t : t.replace(",", "."));
111
+ return Number.isFinite(n) ? n : null;
112
+ };
113
+ export const SUTUN_ESLEME_REHBERI = [
114
+ "Excel'de ilk satır başlık olsun: her soru ya da ölçme için bir sütun.",
115
+ "Başlık örnekleri: 'Vize S1 (ÇK1) /20', 'Vize S2 (ÇK2) /30', 'Final S1 ÇK3 /50', 'Ödev ÇK4 /100'.",
116
+ "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.",
117
+ "Ad, soyad ve numara sütunlarını silmenize gerek yok: araç onları ayrıştırmadan önce atar ve o1, o2 diye takma ad verir. Yine de silerseniz daha iyi olur.",
118
+ "Toplam, Ortalama, Harf sütunları yok sayılır.",
119
+ "Boş, '-' ya da 'G' (girmedi) hücreleri boş puan sayılır.",
120
+ "Tabloyu Excel'de seçip Ctrl+C ile kopyalayın, sohbete Ctrl+V ile yapıştırın.",
121
+ ];
122
+ export const notTablosuAyristirAraci = arac({
123
+ ad: "not_tablosu_ayristir",
124
+ baslik: "Not tablosunu ayrıştır",
125
+ aciklama: "Excel ya da CSV'den yapıştırılan not tablosunu ÇK/PÇ hesabına hazırlar. Ad, soyad ve numara sütunlarını ayrıştırmadan önce atar, öğrencilere o1, o2 takma adı verir. Başlıklardan sınav, soru, tam puan ve ders çıktısı eşlemesini sezer; eksikleri listeler.",
126
+ 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.",
127
+ kisiselVeriIpucu: "Kimlik sütunları atıldıktan sonra da kişisel veri kaldı. Ad ya da numara içeren başka sütun varsa silip yeniden yapıştırın.",
128
+ kisiselVeriKapsami: "tam",
129
+ onAyikla: (g) => {
130
+ const t = g?.tablo;
131
+ if (typeof t !== "string")
132
+ return { girdi: g, atilan: [] };
133
+ const r = notTablosuAyikla(t);
134
+ return {
135
+ girdi: { ...g, tablo: r.tablo },
136
+ atilan: r.atilan,
137
+ ileti: r.atilan.length
138
+ ? `Öğrenci kimliği taşıyan sütunlar hesaplamadan önce atıldı, öğrencilere o1, o2 takma adı verildi; hiçbir yere yazılmadı: ${r.atilan.join(", ")}.`
139
+ : undefined,
140
+ };
141
+ },
142
+ girdi: z.object({
143
+ tablo: z.string().min(5).max(2_000_000).describe("Excel ya da CSV'den yapıştırılan tablo; ilk satır başlık"),
144
+ tamPuanlar: z
145
+ .record(z.string().max(80), z.number().positive().max(1000))
146
+ .optional()
147
+ .describe("Sütun başlığı → tam puan; başlıkta yoksa"),
148
+ eslemeler: z
149
+ .record(z.string().max(80), z.array(z.string().max(10)).max(10))
150
+ .optional()
151
+ .describe("Sütun başlığı → ders çıktısı kodları (Ö1, Ö2); başlıkta yoksa"),
152
+ agirliklar: z
153
+ .record(z.string().max(40), z.number().min(0).max(100))
154
+ .optional()
155
+ .describe("Ölçme aracı kimliği (ara_sinav, yariyil_sonu, odev...) → ders notundaki yüzde"),
156
+ }),
157
+ calistir: ({ tablo, tamPuanlar = {}, eslemeler = {}, agirliklar = {} }) => {
158
+ const { ayirac, satirlar } = tabloOku(tablo);
159
+ const [baslik = [], ...veri] = satirlar;
160
+ const sutunlar = baslik.map((b, j) => (j === 0 ? null : sutunCoz(b)));
161
+ const yoksayilan = baslik.filter((_, j) => j > 0 && !sutunlar[j]);
162
+ const kullanilan = sutunlar
163
+ .map((s, j) => (s ? { ...s, j } : null))
164
+ .filter((s) => s !== null)
165
+ .map((s) => ({
166
+ ...s,
167
+ tamPuan: tamPuanlar[s.baslik] ?? s.tamPuan,
168
+ ciktilar: eslemeler[s.baslik] ?? s.ciktilar,
169
+ }));
170
+ const eksikler = [];
171
+ if (!kullanilan.length)
172
+ eksikler.push("Hiçbir sütunda sınav ya da soru bulunamadı. Başlıkları sütun eşleme rehberine göre düzenleyin.");
173
+ for (const s of kullanilan) {
174
+ if (s.tamPuan === null)
175
+ eksikler.push(`"${s.baslik}" sütununun tam puanı yok.`);
176
+ if (!s.ciktilar.length)
177
+ eksikler.push(`"${s.baslik}" sütununun hangi ders çıktısını ölçtüğü yok.`);
178
+ }
179
+ const aracIdleri = [...new Set(kullanilan.map((s) => s.aracId))];
180
+ for (const id of aracIdleri)
181
+ if (agirliklar[id] === undefined)
182
+ eksikler.push(`"${id}" ölçme aracının ders notundaki yüzdesi yok.`);
183
+ // Aynı araçta aynı soru numarası iki kez geçerse ikinciye sütun sırası eklenir.
184
+ const gorulen = new Set();
185
+ for (const s of kullanilan) {
186
+ const k = `${s.aracId}/${s.soruNo}`;
187
+ if (gorulen.has(k))
188
+ s.soruNo = `${s.soruNo}_${s.j + 1}`;
189
+ gorulen.add(`${s.aracId}/${s.soruNo}`);
190
+ }
191
+ const asim = [];
192
+ const puanlar = veri.flatMap((r) => kullanilan.map((s) => {
193
+ const p = puanOku(r[s.j] ?? "", ayirac);
194
+ if (p !== null && s.tamPuan !== null && p > s.tamPuan)
195
+ asim.push(`${r[0]}: "${s.baslik}" ${p} > ${s.tamPuan}`);
196
+ return { ogrenci: r[0] ?? "", aracId: s.aracId, soruNo: s.soruNo, puan: p };
197
+ }));
198
+ if (asim.length)
199
+ eksikler.push(`${asim.length} hücrede puan tam puanı aşıyor (ilk: ${asim[0]}). Tabloyu denetleyin.`);
200
+ const agirlikToplami = aracIdleri.reduce((t, id) => t + (agirliklar[id] ?? 0), 0);
201
+ if (aracIdleri.every((id) => agirliklar[id] !== undefined) && Math.abs(agirlikToplami - 100) > 0.001)
202
+ eksikler.push(`Ölçme aracı yüzdeleri toplamı ${agirlikToplami}; 100 olmalı (bütünleme hariç tutulabilir).`);
203
+ const araclar = aracIdleri.map((id) => {
204
+ const ss = kullanilan.filter((s) => s.aracId === id);
205
+ return {
206
+ id,
207
+ tur: ss[0]?.tur ?? "diger",
208
+ ad: ss[0]?.aracAdi ?? id,
209
+ agirlik: agirliklar[id] ?? null,
210
+ sorular: ss.map((s) => ({
211
+ no: s.soruNo,
212
+ tamPuan: s.tamPuan,
213
+ eslemeler: s.ciktilar.map((c) => ({ ciktiKod: c, agirlik: 1 })),
214
+ })),
215
+ };
216
+ });
217
+ const ciktilar = [...new Set(kullanilan.flatMap((s) => s.ciktilar))].sort((a, b) => Number(a.slice(1)) - Number(b.slice(1)));
218
+ return {
219
+ sonuc: {
220
+ ogrenciSayisi: veri.length,
221
+ ayirac: ayirac === "\t" ? "sekme" : ayirac,
222
+ sutunlar: kullanilan.map(({ j: _j, ...s }) => s),
223
+ yoksayilanSutunlar: yoksayilan,
224
+ ciktilar,
225
+ eksikler,
226
+ hazir: eksikler.length === 0,
227
+ ckPcHesaplaTaslagi: {
228
+ ciktilar: ciktilar.map((kod) => ({ kod })),
229
+ araclar,
230
+ puanlar,
231
+ not: "dersKodu ve donem alanlarını hocadan alıp ekleyin. Eksik kalmayınca ck_pc_hesapla'ya verin.",
232
+ },
233
+ sutunEslemeRehberi: SUTUN_ESLEME_REHBERI,
234
+ },
235
+ kaynak: [KOD_KAYNAGI("apps/acik-mcp/src/not-tablosu.ts", "Akredit not tablosu ayrıştırıcısı")],
236
+ ...(eksikler.length
237
+ ? {
238
+ 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.",
239
+ }
240
+ : {}),
241
+ };
242
+ },
243
+ });
@@ -0,0 +1,25 @@
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
+ export declare const AKILLI_DOLDURMA: string;
16
+ /** Bütün istemlerde ortak çalışma biçimi. */
17
+ export declare const ORTAK_KURALLAR: string;
18
+ /** akredit başlangıcının sorduğu odak menüsü; site örnek konuşmayı buradan okur. */
19
+ export declare const AKREDIT_ODAKLARI: readonly {
20
+ no: string;
21
+ ad: string;
22
+ }[];
23
+ export declare const ACIK_ISTEMLER: readonly AcikIstem[];
24
+ /** SDK için bağımsız değişken şeması: hepsi isteğe bağlı, kısa metin. */
25
+ export declare const istemSemasi: (i: AcikIstem) => Record<string, z.ZodOptional<z.ZodString>>;
@@ -0,0 +1,253 @@
1
+ // MCP istemleri (prompts). İstemciler bunları eğik çizgi komutu ya da hazır başlangıç olarak gösterir.
2
+ // İlke (İP-49): sıfır kullanıcı müdahalesiyle süreci hızlıca ama denetimli, teyitli tamamlamak. Varsayılan yol
3
+ // "4) Hepsini akıllıca doldur"dur: asistan her alan için en iyi seçeneği kendisi seçer, sunucu denetiminden
4
+ // geçmeyeni düzeltip yeniden denetler, sonunda tek bir özet gösterir. Hoca isterse numarayla düzeltir.
5
+ // Halüsinasyona yer yok: kitap, kişi, tarih, sayı uydurulmaz; kaynaklar kaynak_dogrula'dan geçmeden önerilmez.
6
+ //
7
+ // İstem metni veri değil asistana yönergedir; içinde hocanın girdisi yalnız isteğe bağlı kısa bağımsız
8
+ // değişkenler olarak yer alır (ders kodu, çerçeve) ve sınırlanır. Giriş bilgisi (parola, doğrulama kodu,
9
+ // çerez) asistana asla verilmez (ilke 8).
10
+ import { z } from "zod";
11
+ import { GIRIS_KURALI_HOCAYA } from "./yardim.js";
12
+ /** Giriş bilgisi kuralı: bütün istemlerde aynen yer alır. */
13
+ export const GIRIS_BILGISI_KURALI = [
14
+ "Giriş bilgisi kuralı (değişmez):",
15
+ "- Hocadan kullanıcı adı, parola, doğrulama kodu, SMS kodu ya da çerez asla isteme. Bunları sohbete yazmasını önerme.",
16
+ "- Hoca bunları kendisi yalnız OBS'nin kendi giriş ekranına yazar. Bunu hocaya ilk adımda açıkça söyle.",
17
+ "- Hoca yine de sohbete parola yazarsa kullanma, hiçbir araca gönderme; silmesini ve OBS'de parolasını değiştirmesini öner.",
18
+ "- CAPTCHA'yı sen çözmezsin, hoca çözer.",
19
+ '- OBS\'de Kaydet düğmesine yalnız hocanın açık izniyle basarsın (ya o sekme için "evet", ya bir kez verilen "hepsini kaydet" izni). İzin yoksa basmazsın. Onaya ya da dış kuruma Gönder düğmesine hiç basmazsın; onu hoca basar.',
20
+ ].join("\n");
21
+ /** Akıllı doldurma kısayolu: bütün menülerde aynı numara ve aynı anlam. */
22
+ export const AKILLI_DOLDURMA_SECENEGI = "4) Hepsini akıllıca doldur (önerilen)";
23
+ /** "4) Hepsini akıllıca doldur" seçildiğinde (ya da hoca "sen seç", "hepsi" derse) izlenecek yol. */
24
+ export const AKILLI_DOLDURMA = [
25
+ "Hepsini akıllıca doldur (seçenek 4):",
26
+ "- Kalan her alan için seçeneklerini kendin yaz ve en iyisini kendin seç. Hocaya ara soru sorma.",
27
+ "- Her seçimi ilgili araçla denetle (bologna_taslak_denetle, bologna_durum, rapor_dil_denetle). Geçmeyeni düzelt ve yeniden denetle; geçene kadar hocaya gösterme. Üç denemede geçmezse o alanı EKSİK bırak.",
28
+ "- Sayıları (toplam, yüzde, iş yükü, sağlanma düzeyi) yalnız araç yanıtından al.",
29
+ "- Uydurma yok: hocanın vermediği ve doğrulayamadığın bilgi (kişi, kitap, tarih, sayı, toplantı) EKSİK kalır. Kaynaklar yalnız kaynak_dogrula'dan 'dogrulandi' dönenlerdir.",
30
+ "- Bitince tek bir özet göster: numara, alan, ne yazdığın (ilk cümle ya da kısa özet), denetim sonucu. Altına şunu yaz:",
31
+ ' "Şu alanları şöyle doldurdum. Değiştirmek istediğiniz alanın numarasını yazın; yoksa devam diyebilirsiniz. Bunları daha sonra da kolayca güncelleyebilirsiniz."',
32
+ ].join("\n");
33
+ /** Bütün istemlerde ortak çalışma biçimi. */
34
+ export const ORTAK_KURALLAR = [
35
+ "Çalışma biçimi:",
36
+ "- Amaç: hocanın en az müdahalesiyle işi hızlı ama denetimli ve teyitli bitirmek.",
37
+ "- Karşındaki hoca yapay zekâyı belki ilk kez kullanıyor. Kısa, sade Türkçe yaz. Araç adı, JSON ve teknik terim gösterme.",
38
+ "- Her mesajda tek iş iste. Ne yapacağını ve ekranda ne göreceğini söyle.",
39
+ `- Her seçim menüsünde 1-3 arası kısa seçenek ve her zaman son satırda aynı kısayol olsun: "${AKILLI_DOLDURMA_SECENEGI}". 4 her menüde aynı anlama gelir.`,
40
+ '- Hoca tek rakamla seçer. "sen seç", "hepsi", "hepsi 1" gibi yanıtlar toplu onaydır; kalan bütün adımlara uygula, her adımı yeniden sorma.',
41
+ "- Sunucu metin üretmez. Seçenek metinlerini sen yazarsın; sunucu kural verir, denetler ve sayıları hesaplar.",
42
+ "- Sayıları (toplam, yüzde, iş yükü, sağlanma düzeyi) yalnız araç yanıtından al, kendin toplama.",
43
+ "- Uydurma yok: kişi, kitap, ISBN, DOI, tarih, toplantı, sayı uydurma. Bilinmeyen bilgi EKSİK kalır.",
44
+ "- Kaynak önerirken: hocaya kitabın adını sorma. Ders içeriğine uygun kaynakları kendi web arama aracınla bul, her birini kaynak_dogrula ile doğrula ve yalnız 'dogrulandi' dönenleri künyesi ve bağlantısıyla göster. Doğrulanamayan kaynağı asla önerme.",
45
+ "- Bologna sayfasındaki Dersi Verenler, Yardımcılar ve Koordinatör satırları hocanın yayımlanmış görev bilgisidir: olduğu gibi oku, koru, değiştirme.",
46
+ "- Öğrenci adı ve numarası içeren not tablolarında öğrencilere o1, o2 gibi takma ad verilir (not tablosu aracı bunu kendisi yapar).",
47
+ "- Engel çıkarsa (tarayıcı aracı yok, site açılmıyor, giriş ekranı, CAPTCHA, çerçeve, oturum düştü) engel_coz ile adımları al ve hocaya tek tek göster.",
48
+ "- Her araç yanıtındaki sonrakiAdim önerisine uy.",
49
+ "- Sonunda kopyalanabilir bir çıktı ver. Onaya ya da dış kuruma gönderimi hoca yapar.",
50
+ "",
51
+ AKILLI_DOLDURMA,
52
+ "",
53
+ GIRIS_BILGISI_KURALI,
54
+ ].join("\n");
55
+ const kisa = (v, n = 40) => v
56
+ ? v
57
+ .replace(/[\r\n`]/gu, " ")
58
+ .trim()
59
+ .slice(0, n)
60
+ : "";
61
+ const ODAKLAR = [
62
+ ["1", "Bologna ders paketini denetle ve boş alanları doldur", "bologna_doldur"],
63
+ ["2", "Ders öğrenme çıktısı yaz ya da iyileştir", "cikti_yaz"],
64
+ ["3", "ÇK ve PÇ sağlanma düzeyini hesapla", "ck_pc_hesabi"],
65
+ ["4", "YÖKAK, MÜDEK, FEDEK, EPDAD ya da SABAK ölçüt ve kanıt rehberi", "olcut_rehberi"],
66
+ ["5", "Öz değerlendirme metninin dil denetimi", "dil_denetimi"],
67
+ ];
68
+ /** akredit başlangıcının sorduğu odak menüsü; site örnek konuşmayı buradan okur. */
69
+ export const AKREDIT_ODAKLARI = ODAKLAR.map(([no, ad]) => ({ no, ad }));
70
+ /** OBS'ye tarayıcıyla giriş: Bologna akışının ilk adımı. */
71
+ const obsGirisi = () => [
72
+ "Adım 0. OBS'ye giriş (tarayıcı).",
73
+ ` Hocaya önce şunu aynen söyle: "${GIRIS_KURALI_HOCAYA}"`,
74
+ " Tarayıcı aracın varsa (Claude in Chrome, Claude masaüstü tarayıcı paneli, ChatGPT ajan modu gibi):",
75
+ " a) Hocaya OBS ya da Bologna sisteminin adresini sor (kurumun sitesindeki bağlantı). Adresi kenardaki tarayıcıda aç.",
76
+ ' b) Giriş ekranı gelince dur ve şunu yaz: "Kullanıcı adınızı ve parolanızı şimdi açılan OBS ekranına kendiniz yazın. Bitince bana yalnız girdim yazın."',
77
+ " c) CAPTCHA ya da doğrulama kodu gelirse hocanın kendisinin girmesini bekle; sen girme.",
78
+ " d) Hoca girdim deyince ders listesini oku ve numaralı göster. Sor: hangi ders? Hoca numara yazar.",
79
+ " e) Dersin Bologna (ders bilgi paketi) sayfasını oku. Okuduğun metni ya da HTML'i bologna_ayristir'e ver.",
80
+ " Tarayıcı aracın yoksa: hocaya sor: 1) kurulumu birlikte yapalım (önerilen) 2) sayfayı kopyalayıp yapıştırayım 3) sıfırdan başlayalım.",
81
+ " 1 seçilirse kurulum_yardimi'nı hocanın asistanıyla (istemci) çağır, adımları tek tek göster.",
82
+ ' 2 seçilirse şunu yaz: "OBS\'de dersinizin Bologna sayfasını açın. Sayfada Ctrl+A ile hepsini seçin, Ctrl+C ile kopyalayın, buraya Ctrl+V ile yapıştırın."',
83
+ " Herhangi bir engelde engel_coz'u ilgili engel türüyle çağır.",
84
+ ].join("\n");
85
+ /** Kaynak bulma: hocaya sormadan, web aramasıyla, kaynak_dogrula'dan geçirerek. */
86
+ const KAYNAK_ADIMI = [
87
+ " Kaynaklar: hocaya kitabın adını sorma. Ders adı, içerik ve haftalık konulara göre kendi web arama aracınla 4-6 aday eser bul (ders kitabı, temel makale).",
88
+ " Her adayı DOI, ISBN ya da başlık ile yazar olarak kaynak_dogrula'ya ver. Yalnız 'dogrulandi' dönenleri kullan; künyeyi aracın verdiği gibi yaz, bağlantısıyla birlikte göster.",
89
+ " Doğrulanamayan adayı asla önerme, künyesini yazma. Web arama aracın yoksa bunu hocaya söyle; hoca bir eser adı verirse onu da kaynak_dogrula'dan geçir, geçmezse kaynaklar alanı EKSİK kalır.",
90
+ ].join("\n");
91
+ /** OBS'ye yazma menüsü: tarayıcı aracı yoksa 3'e düşer. */
92
+ const OBS_YAZMA = [
93
+ "6. OBS'ye yazma. Tarayıcı aracın yoksa doğrudan 3'ü uygula. Varsa sor:",
94
+ " 1) Formu ben doldurayım, Kaydet'e siz basın",
95
+ " 2) Formu ben doldurup kaydedeyim (her sekmeden önce kısa özet gösterip evet isterim)",
96
+ " 3) Alan alan kopyalayın",
97
+ ` ${AKILLI_DOLDURMA_SECENEGI.replace("doldur", "doldur ve kaydet")}: bütün sekmeleri doldurup kaydederim; başlamadan bir kez "hepsini kaydet" izninizi alırım, sonunda tek özet gösteririm.`,
98
+ " 1: OBS düzenleme ekranında sekme sekme ilgili kutulara yaz. Her sekmeden sonra dur ve hocadan gözle denetleyip Kaydet'e basmasını iste.",
99
+ ' 2: Her sekmeyi doldur, kaydetmeden önce o sekmede ne yazdığını kısa özetle ve "Kaydedeyim mi? evet / hayır" diye sor. Yalnız "evet" gelirse Kaydet\'e bas.',
100
+ ' 4: Önce şunu sor: "Bütün sekmeleri doldurup kaydetmem için izin veriyor musunuz? hepsini kaydet / hayır". Yalnız "hepsini kaydet" gelirse sekme sekme doldur ve kaydet; sonunda neyi nereye yazdığını tek özetle göster.',
101
+ " 3: bologna_kopya_metni ile metni al; her alanı ayrı kod bloğunda ver, hangi sekmedeki hangi kutuya yapıştırılacağını yaz.",
102
+ " Her durumda: Dersin Yetkilileri satırlarına dokunma, OBS'deki hâliyle kalsın. Parolayı asla isteme; o yalnız hocadadır. Onaya gönderme (Gönder) düğmesine sen basma.",
103
+ ].join("\n");
104
+ const bolognaAkisi = (dersKodu) => [
105
+ `Odak: Bologna ders bilgi paketini denetle, eksik ve zayıf alanları tamamla.${dersKodu ? ` Ders: ${dersKodu}.` : ""}`,
106
+ "",
107
+ "Akış:",
108
+ obsGirisi(),
109
+ "1. Ayrıştır. bologna_ayristir önce Proliz biçimini, olmazsa genel ayrıştırıcıyı dener. Bulunamayan alanları not al.",
110
+ " Dersi Verenler, Yardımcılar ve Koordinatör satırları yetkililer alanında olduğu gibi gelir; onları değiştirme, sonraki çağrılarda aynen geri ver.",
111
+ " Program çıktıları sayfası da varsa onu da ayrıştır ve P kodlarını sakla; P kodlarını asla ezberden yazma.",
112
+ "2. Denetle. bologna_denetle'yi çağır. Sonucu tek tabloda göster: numara, alan, durum (boş, zayıf, tamam), kısa neden. Kalan alan sayısını söyle.",
113
+ ` Sor: 1) alan alan seçenek göstererek dolduralım 2) yalnız boş olanlar 3) numaraları kendim seçeyim ${AKILLI_DOLDURMA_SECENEGI}.`,
114
+ "3. Bağlam. Amaç ya da içerik yoksa dersin odağını ders adından ve program çıktılarından çıkar. Akıllı doldurmada sorma; 1-3 seçildiyse tek soru sor: 1) [1. öneri] 2) [2. öneri] 3) kendim yazayım.",
115
+ "4. Her alan için: bologna_alan_rehberi'ni çağır. Kurala uyan 2-3 kısa seçenek yaz.",
116
+ " Seçenekleri bologna_taslak_denetle ile denetle; geçmeyeni düzelt ve yeniden denetle, yalnız geçenleri kullan. Uzun metinlerde ilk cümleyi ve kelime sayısını göster.",
117
+ " Akıllı doldurmada (4) en iyi seçeneği kendin seç ve hocaya alan alan sorma; sonunda tek özet göster.",
118
+ " Haftalık konular: 14 hafta, ara sınav ve yarıyıl sonu haftası görünür. Değerlendirme: yüzdeler toplamı 100.",
119
+ " AKTS iş yükü: is_yuku_oner'i çağır; üç dağılımın toplamı hedefe tam eşittir. AKTS'yi değiştirme.",
120
+ " Öğrenme çıktısı ile program çıktısı katkı tablosu: yalnız ayrıştırılan P kodlarıyla öner.",
121
+ KAYNAK_ADIMI,
122
+ '5. Her alandan sonra bologna_durum\'u çağır. Alan alan ilerliyorsan kalan alan sayısını tek cümleyle söyle: "Kalan 3 alan."',
123
+ OBS_YAZMA,
124
+ '7. Tamamlandı denetimi. Kayıttan sonra sayfayı yeniden oku (tarayıcı varsa) ya da yeniden yapıştırmasını iste; bologna_ayristir ve bologna_denetle ile denetle. Eksik yoksa "Tamamlandı" de.',
125
+ " Sor: 1) başka ders 2) bir alanı değiştir 3) bitir.",
126
+ ].join("\n");
127
+ const ciktiAkisi = (dersKodu) => [
128
+ `Odak: ders öğrenme çıktısı yaz ya da iyileştir.${dersKodu ? ` Ders: ${dersKodu}.` : ""}`,
129
+ "",
130
+ "Akış:",
131
+ "1. Sor: 1) OBS'deki mevcut çıktılarımı okuyalım (tarayıcı aracın varsa OBS girişi için Bologna akışındaki Adım 0'ı izle) 2) çıktılarımı yapıştırayım 3) sıfırdan yaz: ders adı, AKTS, T+U+L ve kısa içerik vereyim.",
132
+ "2. bologna_alan_rehberi'ni alan=ciktilar ile çağır: kurallar, Bloom fiilleri, 8-12 sınırı.",
133
+ `3. Sor: 1) her çıktı için seçenek göstereyim 2) yalnız zayıf olanları iyileştireyim 3) numaraları kendim seçeyim ${AKILLI_DOLDURMA_SECENEGI}.`,
134
+ " 1-3: her çıktı için 2-3 seçenek yaz (farklı Bloom düzeyi ya da ölçme biçimi), türünü (Bilgi, Beceri, Yetkinlik) yaz.",
135
+ " 4: her çıktı için en iyi ifadeyi kendin seç; hocaya ara soru sorma.",
136
+ "4. Bütün listeyi bologna_taslak_denetle ile denetle (ciktilar alanı; İngilizce isteniyorsa en alanıyla). Geçmeyeni düzelt ve yeniden denetle.",
137
+ "5. Tek özet göster: numara, çıktı, tür, denetim sonucu. Değiştirmek istediği numarayı sor.",
138
+ " Program çıktısı katkısı: P kodları ayrıştırıldıysa onlarla doldur; yoksa P kodu uydurma, hocadan program çıktıları sayfasını iste.",
139
+ "6. bologna_kopya_metni ile Öğrenme Çıktıları sekmesine kopyalanacak metni ver ya da Bologna akışındaki OBS'ye yazma adımını izle.",
140
+ ].join("\n");
141
+ const ckPcAkisi = (dersKodu) => [
142
+ `Odak: ÇK ve PÇ sağlanma düzeyi hesabı.${dersKodu ? ` Ders: ${dersKodu}.` : ""}`,
143
+ "",
144
+ "Akış:",
145
+ "1. Hocadan Excel not tablosunu kopyalayıp yapıştırmasını iste. İlk satır başlık, her soru bir sütun; başlıkta sınav, soru, ÇK ve tam puan olursa iş biter (ör. Vize S1 (ÇK1) /20).",
146
+ " Ad ve numara sütunlarını araç ayrıştırmadan önce atar ve o1, o2 takma adı verir; bunu hocaya tek cümleyle söyle.",
147
+ "2. Tabloyu not_tablosu_ayristir'e ver.",
148
+ `3. Sor: 1) eşlemeyi tek tek gözden geçirelim 2) yalnız eksikleri soralım 3) eşlemeyi kendim yazayım ${AKILLI_DOLDURMA_SECENEGI}.`,
149
+ " 4: başlıktan okunan eşlemeyi ve varsayılanları kullan: eşik 60, sınav ağırlıkları tablodan. Başlıkta olmayan soru-çıktı eşlemesini ve tam puanı tahmin etme; bunları tek mesajda topluca sor.",
150
+ "4. Hazır olunca ck_pc_hesapla'yı çağır. Sonucu tablo olarak göster; sayıları yalnız yanıttan al.",
151
+ "5. Tek özet: hangi eşlemeyi ve eşiği kullandığını, eşiğin altında kalan çıktıları yaz. Değiştirmek istediği numarayı sor.",
152
+ "6. Sor: 1) eşiğin altındaki çıktılar için iyileştirme notu taslağı 2) farklı eşikle yeniden hesapla 3) bitir. Not taslağında sayı uydurma; sonucu kopyalanabilir tablo olarak ver.",
153
+ ].join("\n");
154
+ const olcutAkisi = (cerceve) => [
155
+ `Odak: ölçüt ve kanıt rehberi.${cerceve ? ` Çerçeve: ${cerceve}.` : ""}`,
156
+ "",
157
+ "Akış:",
158
+ `1. ${cerceve ? "Çerçeve verildi, sorma." : "Sor: hangi çerçeve? 1) YÖKAK kurumsal 2) program akreditasyonu: MÜDEK, FEDEK, EPDAD ya da SABAK. Hoca söylemezse YÖKAK kurumsal ile başla."}`,
159
+ `2. Sor: 1) bir ölçütün resmî metni 2) bir konuda hangi ölçütler var 3) öz değerlendirme iskeleti ${AKILLI_DOLDURMA_SECENEGI.replace("doldur", "hazırla")}: konuya uyan ölçütleri bulup resmî metinleri ve kanıt kontrol listesini tek seferde çıkarırım.`,
160
+ "3. olcut_ara ile ara, en uygun sonuçları al. olcut_getir ile resmî metni kaynağıyla göster. Akıllı hazırlamada en uygun 2-3 ölçütü kendin seç.",
161
+ "4. YÖKAK alt ölçütüyse olgunluk_duzeyleri ile düzeyleri ve örnek kanıtları al. Kanıtın kurumda olup olmadığını tahmin etme: kontrol listesinde 'hocaya sorulacak' yaz; hoca isterse tek mesajda 'var olanların numaraları' diye sor.",
162
+ "5. Programın disiplinini ya da programa özgü bölümünü sen tahmin etme; bilmiyorsan tek soruyla sor.",
163
+ "6. Ölçüt metnini yalnız araç yanıtından alıntıla. DOĞRULANMADI işaretli metni tahminle doldurma.",
164
+ "7. Sonunda tek özet ve kopyalanabilir kanıt kontrol listesi ver: ölçüt, kanıt, durum (var, yok, hocaya sorulacak, EKSİK), not.",
165
+ ].join("\n");
166
+ const dilAkisi = () => [
167
+ "Odak: öz değerlendirme ya da faaliyet raporu metninin dil denetimi.",
168
+ "",
169
+ "Akış:",
170
+ "1. Hocadan metni yapıştırmasını iste. Öğrenci adı ya da numarası varsa göndermeden önce o1, o2 gibi takma adla değiştir.",
171
+ "2. Rapor dönemini metinden çıkar; çıkaramazsan tek soruyla sor.",
172
+ "3. rapor_dil_denetle'yi çağır.",
173
+ `4. Sor: 1) bulguları tek tek göstereyim 2) yalnız önemli olanları düzelteyim 3) numaraları kendim seçeyim ${AKILLI_DOLDURMA_SECENEGI.replace("doldur", "düzelt")}.`,
174
+ " 4: her bulgu için en iyi düzeltmeyi kendin seç. Kanıt ya da sayı gerektiren düzeltmede bilgi uydurma; o yere EKSİK yaz.",
175
+ "5. Düzeltilmiş metni yeniden rapor_dil_denetle ile denetle; kalan bulguları düzelt.",
176
+ "6. Tek özet göster: numara, eski ifade, yeni ifade. Değiştirmek istediği numarayı sor. Sonunda düzeltilmiş metnin tamamını kopyalanabilir biçimde ver.",
177
+ ].join("\n");
178
+ const AKISLAR = {
179
+ bologna_doldur: (a) => bolognaAkisi(kisa(a.ders_kodu)),
180
+ cikti_yaz: (a) => ciktiAkisi(kisa(a.ders_kodu)),
181
+ ck_pc_hesabi: (a) => ckPcAkisi(kisa(a.ders_kodu)),
182
+ olcut_rehberi: (a) => olcutAkisi(kisa(a.cerceve)),
183
+ dil_denetimi: () => dilAkisi(),
184
+ };
185
+ const akreditMenusu = (odak) => {
186
+ const secilen = ODAKLAR.find(([no, , ad]) => odak === no || odak === ad);
187
+ if (secilen)
188
+ return AKISLAR[secilen[2]]?.({}) ?? "";
189
+ return [
190
+ "Akredit açık araçlarıyla hocaya yardım edeceksin. Önce hangi aracı kullanmak istediğini sor.",
191
+ "Hoca seçmeden hiçbir akışa başlama: OBS girişi isteme, sayfa açma, araç çağırma.",
192
+ "",
193
+ "Hocaya tam olarak şunu göster ve yanıtını bekle:",
194
+ "",
195
+ "Merhaba. Bugün neye odaklanalım? Numarasını yazmanız yeter.",
196
+ ...ODAKLAR.map(([no, ad]) => `${no}) ${ad}`),
197
+ `${ODAKLAR.length + 1}) Başka bir şey: tüm araçları kısaca listele`,
198
+ "",
199
+ `Seçim ${ODAKLAR.length + 1} ise sunucudaki araçları adlarıyla değil, ne işe yaradıklarıyla birer cümlede numaralı listele ve yeniden seçtir.`,
200
+ "Bu ilk menüde 4 bir odaktır (ölçüt rehberi); akıllı doldurma kısayolu odak seçildikten sonraki menülerde geçerlidir.",
201
+ "",
202
+ "Seçime göre aşağıdaki akışlardan ilgili olanı izle:",
203
+ "",
204
+ ...ODAKLAR.map(([no, , ad]) => `Seçim ${no}:\n${AKISLAR[ad]?.({}) ?? ""}\n`),
205
+ ].join("\n");
206
+ };
207
+ const ile = (govde) => `${govde}\n\n${ORTAK_KURALLAR}`;
208
+ export const ACIK_ISTEMLER = [
209
+ {
210
+ ad: "akredit",
211
+ baslik: "Akredit: hangi aracı kullanalım?",
212
+ aciklama: "Akredit ile ilk adım. Önce hangi aracı kullanacağınızı seçersiniz: Bologna paketi, öğrenme çıktısı, ÇK/PÇ hesabı, ölçüt rehberi, dil denetimi ya da başka bir araç.",
213
+ argumanlar: { odak: "İsteğe bağlı: 1-5 arası odak numarası" },
214
+ metin: (a) => ile(akreditMenusu(kisa(a.odak, 20))),
215
+ },
216
+ {
217
+ ad: "bologna_doldur",
218
+ baslik: "Bologna paketini denetle ve doldur",
219
+ aciklama: "OBS'nize kendiniz girersiniz; asistan Bologna sayfanızı okur, boş ve zayıf alanları bulur, hepsini akıllıca doldurup denetler ve tek özet gösterir. Formu doldurur; Kaydet'e siz basarsınız ya da açık izninizle o basar.",
220
+ argumanlar: { ders_kodu: "İsteğe bağlı: ders kodu, ör. KRG101" },
221
+ metin: (a) => ile(bolognaAkisi(kisa(a.ders_kodu))),
222
+ },
223
+ {
224
+ ad: "cikti_yaz",
225
+ baslik: "Öğrenme çıktısı yaz ya da iyileştir",
226
+ aciklama: "Ders öğrenme çıktılarını ölçülebilir fiillerle yazar ya da iyileştirir; hepsini tek adımda yazıp denetler, isterseniz numarayla düzeltirsiniz.",
227
+ argumanlar: { ders_kodu: "İsteğe bağlı: ders kodu" },
228
+ metin: (a) => ile(ciktiAkisi(kisa(a.ders_kodu))),
229
+ },
230
+ {
231
+ ad: "ck_pc_hesabi",
232
+ baslik: "ÇK ve PÇ sağlanma hesabı",
233
+ aciklama: "Excel not tablonuzu yapıştırırsınız; öğrencilere takma ad verilir, ders ve program çıktısı sağlanma düzeyi hesaplanır.",
234
+ argumanlar: { ders_kodu: "İsteğe bağlı: ders kodu" },
235
+ metin: (a) => ile(ckPcAkisi(kisa(a.ders_kodu))),
236
+ },
237
+ {
238
+ ad: "olcut_rehberi",
239
+ baslik: "Ölçüt ve kanıt rehberi",
240
+ aciklama: "YÖKAK, MÜDEK, FEDEK, EPDAD ya da SABAK ölçütünü resmî metniyle bulur, kanıt kontrol listesi çıkarır.",
241
+ argumanlar: { cerceve: "İsteğe bağlı: YÖKAK, MÜDEK, FEDEK, EPDAD ya da SABAK" },
242
+ metin: (a) => ile(olcutAkisi(kisa(a.cerceve, 20))),
243
+ },
244
+ {
245
+ ad: "dil_denetimi",
246
+ baslik: "Öz değerlendirme dil denetimi",
247
+ aciklama: "Rapor metnindeki kanıtsız üstünlük, belirsiz özne gibi sorunları bulur, hepsini düzeltip yeniden denetler ve tek özet gösterir.",
248
+ argumanlar: {},
249
+ metin: () => ile(dilAkisi()),
250
+ },
251
+ ];
252
+ /** SDK için bağımsız değişken şeması: hepsi isteğe bağlı, kısa metin. */
253
+ export const istemSemasi = (i) => Object.fromEntries(Object.entries(i.argumanlar).map(([k, d]) => [k, z.string().max(60).optional().describe(d)]));
@@ -1,16 +1,24 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import { type AcikArac, type AracBaglami } from "./araclar.ts";
3
+ import { type AcikIstem } from "./promptlar.ts";
3
4
  export declare const SUNUCU_ADI = "akredit-acik";
4
- export declare const SUNUCU_SURUMU = "0.1.0";
5
- export declare const SUNUCU_TALIMATI = "Akredit a\u00E7\u0131k ara\u00E7lar\u0131: Y\u00D6KAK ve program akreditasyonu (M\u00DCDEK, FEDEK, SABAK, EPDAD) \u00F6l\u00E7\u00FCt metni, EPDAD g\u00F6stergeleri, Y\u00D6KAK olgunluk d\u00FCzeyleri, Bologna ders bilgisi denetimi, \u00C7K/P\u00C7 sa\u011Flanma hesab\u0131, \u00F6z de\u011Ferlendirme iskeleti, rapor dil denetimi. Ara\u00E7lar salt okumad\u0131r, kurum verisine eri\u015Fmez, model \u00E7a\u011F\u0131rmaz. Ki\u015Fisel veri (ad, numara, e-posta, telefon) g\u00F6ndermeyin; g\u00F6r\u00FCl\u00FCrse \u00E7a\u011Fr\u0131 reddedilir. \u00D6l\u00E7\u00FCt metnini yaln\u0131z olcut_getir sonucundan al\u0131nt\u0131lay\u0131n; DO\u011ERULANMADI ya da 'Belgeden okunamad\u0131' i\u015Faretli metni tahminle doldurmay\u0131n. Program\u0131n disiplinini ya da programa \u00F6zg\u00FC b\u00F6l\u00FCm\u00FCn\u00FC siz tahmin etmeyin, kurum se\u00E7er. Say\u0131lar\u0131 yaln\u0131z ara\u00E7 sonucundan al\u0131n. \u00D6z de\u011Ferlendirme iskeleti metin i\u00E7ermez: kan\u0131t\u0131 olmayan c\u00FCmleyi EKS\u0130K b\u0131rak\u0131n. Akredit'in Y\u00D6KAK ile ba\u011F\u0131 yoktur.";
5
+ export declare const SUNUCU_SURUMU = "0.4.0";
6
+ export declare const SUNUCU_TALIMATI: string;
6
7
  export interface AcikSunucuSecenekleri {
7
8
  simdi?: () => Date;
8
9
  araclar?: readonly AcikArac[];
10
+ istemler?: readonly AcikIstem[];
11
+ /** kaynak_dogrula için fetch (test). */
12
+ fetch?: typeof fetch;
9
13
  }
10
- /** Bir aracı doğrudan çalıştırır (MCP katmanı dışında da kullanılabilir: test, belge). */
11
- export declare function aracCalistir(a: AcikArac, girdi: unknown, b: AracBaglami): {
14
+ type Sonuc = {
12
15
  veri: Record<string, unknown>;
13
16
  hata: boolean;
14
17
  };
18
+ /** Bir aracı doğrudan çalıştırır (MCP katmanı dışında da kullanılabilir: test, belge). Yalnız eşzamanlı araçlar. */
19
+ export declare function aracCalistir(a: AcikArac, girdi: unknown, b: AracBaglami): Sonuc;
20
+ /** Her araç için (eşzamanlı ya da eşzamansız) çalıştırma; MCP katmanı bunu kullanır. */
21
+ export declare function aracCalistirAsenkron(a: AcikArac, girdi: unknown, b: AracBaglami): Promise<Sonuc>;
15
22
  /** Yeni bir McpServer kurar. Durumsuz HTTP'de her istek için, stdio'da süreç başına bir kez çağrılır. */
16
23
  export declare function acikSunucu(s?: AcikSunucuSecenekleri): McpServer;
24
+ export {};