@akredit/acik-mcp 0.6.0 → 0.8.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/README.md +41 -37
- package/dist/apps/acik-mcp/src/araclar.js +7 -2
- package/dist/apps/acik-mcp/src/bologna.d.ts +12 -0
- package/dist/apps/acik-mcp/src/bologna.js +580 -249
- package/dist/apps/acik-mcp/src/genel-ayristir.js +2 -2
- package/dist/apps/acik-mcp/src/http.js +2 -1
- package/dist/apps/acik-mcp/src/kaynak-dogrula.js +1 -1
- package/dist/apps/acik-mcp/src/kisisel-veri.d.ts +4 -3
- package/dist/apps/acik-mcp/src/kisisel-veri.js +5 -0
- package/dist/apps/acik-mcp/src/not-tablosu.d.ts +4 -1
- package/dist/apps/acik-mcp/src/not-tablosu.js +10 -4
- package/dist/apps/acik-mcp/src/proliz-metin.d.ts +60 -0
- package/dist/apps/acik-mcp/src/proliz-metin.js +271 -0
- package/dist/apps/acik-mcp/src/promptlar.d.ts +6 -3
- package/dist/apps/acik-mcp/src/promptlar.js +97 -48
- package/dist/apps/acik-mcp/src/sunucu.d.ts +3 -2
- package/dist/apps/acik-mcp/src/sunucu.js +16 -11
- package/dist/apps/acik-mcp/src/temel.d.ts +8 -0
- package/dist/apps/acik-mcp/src/temel.js +32 -0
- package/dist/apps/acik-mcp/src/yardim.js +46 -12
- package/dist/packages/baglayicilar/src/bologna-proliz/ayristir.js +4 -2
- package/dist/packages/cekirdek/src/bologna/taslak.js +8 -2
- package/dist/packages/cekirdek/src/karar/katman.d.ts +2 -2
- package/dist/packages/cekirdek/src/karar/katman.js +2 -2
- package/dist/packages/cekirdek/src/turkce.d.ts +0 -2
- package/dist/packages/cekirdek/src/turkce.js +0 -4
- package/dist/packages/olcme/src/girdi.d.ts +3 -0
- package/dist/packages/olcme/src/girdi.js +55 -0
- package/dist/packages/olcme/src/index.d.ts +1 -0
- package/dist/packages/olcme/src/index.js +1 -0
- package/package.json +9 -3
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
// MCP istemleri (prompts). İstemciler bunları eğik çizgi komutu ya da hazır başlangıç olarak gösterir.
|
|
2
|
-
// İlke (İP-49):
|
|
3
|
-
//
|
|
4
|
-
// geçmeyeni düzeltip yeniden denetler, sonunda tek bir özet gösterir. Hoca isterse numarayla düzeltir.
|
|
2
|
+
// İlke (İP-49): en az kullanıcı müdahalesiyle süreci hızlıca ama denetimli, teyitli tamamlamak. Varsayılan yol
|
|
3
|
+
// akıllı doldurmadır (hocaya alan alan menü sorulmaz): asistan her alan için en iyi seçeneği kendisi seçer, sunucu
|
|
4
|
+
// denetiminden geçmeyeni düzeltip yeniden denetler, sonunda tek bir özet gösterir. Hoca isterse numarayla düzeltir.
|
|
5
5
|
// Halüsinasyona yer yok: kitap, kişi, tarih, sayı uydurulmaz; kaynaklar kaynak_dogrula'dan geçmeden önerilmez.
|
|
6
6
|
//
|
|
7
7
|
// Dış inceleme 2026-11-05: akıllı doldurma kalır, ama bilinmesi mümkün olmayan ve resmî taahhüt olan bilgiler
|
|
8
|
-
// (değerlendirme yöntemi ve yüzdeleri,
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// hoca bir kez "kaydet" der; kayıttan
|
|
8
|
+
// (değerlendirme yöntemi ve yüzdeleri, kullanılan kaynaklar) sayfadan okunur; yoksa asistan bunları TEK mesajda,
|
|
9
|
+
// numaralı sorar, uydurmaz ve yüzdeye varsayılan koymaz (06.11.2026). Uygulama/lab T+U+L'den okunur; amaç ve içerik
|
|
10
|
+
// sayfada yoksa "öneri" olarak yazılıp son özette teyide sunulur. Ders adından üretilen her şey "öneri" etiketiyle
|
|
11
|
+
// gösterilir. OBS'ye yazmadan önce alan alan önceki/yeni değer özeti gösterilir, hoca bir kez "kaydet" der; kayıttan
|
|
12
|
+
// sonra sayfa geri okunur ve obs_karsilastir ile doğrulanır.
|
|
13
|
+
//
|
|
14
|
+
// Peşin onay (0.8.0): hoca başta "hepsini yap ve kaydet" derse ara durak olmaz; teyit sorulmaz (EKSİK kalır), özet
|
|
15
|
+
// sondaki tek raporda verilir. Onaya Gönder yine hocadadır.
|
|
12
16
|
//
|
|
13
17
|
// İstem metni veri değil asistana yönergedir; içinde hocanın girdisi yalnız isteğe bağlı kısa bağımsız
|
|
14
18
|
// değişkenler olarak yer alır (ders kodu, çerçeve) ve sınırlanır. Giriş bilgisi (parola, doğrulama kodu,
|
|
15
19
|
// çerez) istenmez; görülürse reddedilir ve kaydedilmez (ilke 8).
|
|
16
20
|
import { z } from "zod";
|
|
17
|
-
import { arac, KOD_KAYNAGI } from "./temel.js";
|
|
21
|
+
import { arac, KOD_KAYNAGI, pesinOnayVar, TARAMA_SECENEKLERI } from "./temel.js";
|
|
18
22
|
import { GIRIS_KURALI_HOCAYA } from "./yardim.js";
|
|
19
23
|
/** Giriş bilgisi kuralı: bütün istemlerde aynen yer alır. */
|
|
20
24
|
export const GIRIS_BILGISI_KURALI = [
|
|
@@ -23,11 +27,10 @@ export const GIRIS_BILGISI_KURALI = [
|
|
|
23
27
|
"- Hoca bunları kendisi yalnız OBS'nin kendi giriş ekranına yazar. Bunu hocaya ilk adımda açıkça söyle.",
|
|
24
28
|
"- Hoca yine de sohbete parola yazarsa kullanma, hiçbir araca gönderme; silmesini ve OBS'de parolasını değiştirmesini öner.",
|
|
25
29
|
"- CAPTCHA'yı sen çözmezsin, hoca çözer.",
|
|
26
|
-
'- OBS\'de Kaydet düğmesine yalnız hocanın açık izniyle basarsın: önce alan alan önceki ve yeni değer özetini gösterirsin, hoca bir kez "kaydet" der. İzin yoksa basmazsın. Onaya ya da dış kuruma Gönder düğmesine hiç basmazsın; onu hoca basar.',
|
|
30
|
+
'- OBS\'de Kaydet düğmesine yalnız hocanın açık izniyle basarsın: önce alan alan önceki ve yeni değer özetini gösterirsin, hoca bir kez "kaydet" der. Hoca başta peşin onay verdiyse ("hepsini yap ve kaydet") izin odur; özet sondaki raporda verilir. İzin yoksa basmazsın. Onaya ya da dış kuruma Gönder düğmesine hiç basmazsın; onu hoca basar.',
|
|
27
31
|
].join("\n");
|
|
28
|
-
/** Akıllı doldurma
|
|
29
|
-
export const
|
|
30
|
-
/** "4) Hepsini akıllıca doldur" seçildiğinde (ya da hoca "sen seç", "hepsi" derse) izlenecek yol. */
|
|
32
|
+
/** Akıllı doldurma kuralı: varsayılan yol; bütün istemlerde ve sunucu talimatında aynen geçer. */
|
|
33
|
+
export const AKILLI_DOLDURMA_KURALI = "Varsayılan akıllı doldurmadır; hocaya alan alan menü sorulmaz: her alan için en iyisini sen seçersin, araçla denetlersin, geçmeyeni düzeltip yeniden denetlersin, sonda tek özet gösterirsin.";
|
|
31
34
|
/** Bilinmesi mümkün olmayan ve resmî taahhüt olan bilgiler: sayfadan okunur, yoksa tek mesajda sorulur. */
|
|
32
35
|
export const TEYIT_SORULARI = [
|
|
33
36
|
"Teyit gerektiren bilgiler (asla tahmin etme):",
|
|
@@ -38,17 +41,18 @@ export const TEYIT_SORULARI = [
|
|
|
38
41
|
' "İki bilgiyi yalnız siz bilebilirsiniz:',
|
|
39
42
|
" 1) Değerlendirme yöntemleri ve yüzdeleri: yazın (ör. Vize 40, Final 60)",
|
|
40
43
|
' 2) Kaynaklar: a) katalogdan doğrulayıp önereyim (önerilen) b) şunları kullanıyorum: yazın"',
|
|
41
|
-
"Yanıt gelmeden değerlendirme yüzdesi yazma paketine girmez (degerlendirmeDayanagi: 'hoca').",
|
|
44
|
+
"Yanıt gelmeden değerlendirme yüzdesi yazma paketine girmez. Hocanın yanıtını degerlendirmeKaniti'ne olduğu gibi yazın (degerlendirmeDayanagi: 'hoca'); sayfadan okunduysa sayfadaki tablo metnini (degerlendirmeDayanagi: 'sayfa'). Yüzdeler bu metinde geçmezse sunucu teyitsiz sayar.",
|
|
42
45
|
].join("\n");
|
|
46
|
+
/** Akıllı doldurmanın (varsayılan yol) ayrıntısı. */
|
|
43
47
|
export const AKILLI_DOLDURMA = [
|
|
44
|
-
"
|
|
48
|
+
"Akıllı doldurma (varsayılan):",
|
|
45
49
|
"- Önce teyit gerektiren bilgileri sayfadan oku; sayfada olmayanları hocaya TEK mesajda birlikte sor (aşağıdaki kural). Bundan sonra ara soru sorma.",
|
|
46
50
|
"- Kalan her alan için seçeneklerini kendin yaz ve en iyisini kendin seç. Ders adından ve program çıktılarından ürettiğin her şeyi 'öneri' etiketiyle göster.",
|
|
47
51
|
"- 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.",
|
|
48
52
|
"- Sayıları (toplam, yüzde, iş yükü, sağlanma düzeyi) yalnız araç yanıtından al.",
|
|
49
|
-
"- 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 '
|
|
53
|
+
"- 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 'katalogda_bulundu' dönenler ya da hocanın kullandığını söyledikleridir ('hoca_beyani').",
|
|
50
54
|
"- Araç sonucunu 'geçer' diye sunma: 'biçim denetiminden geçti; içerik teyidi: hoca' de.",
|
|
51
|
-
"- Bitince tek bir özet göster: numara, alan, ne yazdığın (ilk cümle ya da kısa özet), kaynağı (sayfa, hoca ya da öneri), biçim denetimi sonucu.
|
|
55
|
+
"- Bitince tek bir özet göster: numara, alan, ne yazdığın (ilk cümle ya da kısa özet), kaynağı (sayfa, hoca ya da öneri), biçim denetimi sonucu.",
|
|
52
56
|
"- Ara özet gösterip 'devam' bekleme: OBS'ye yazılacaksa özet, yazma onayıyla aynı mesajdadır (OBS'ye yazma adımı). Özetin altına yaz:",
|
|
53
57
|
" \"Öneri yazanlar benim önerimdir, içeriği siz teyit edersiniz. 1) OBS'ye yaz ve kaydet 2) formu doldur, Kaydet'e ben basayım 3) kopya metni ver. Değiştirmek istediğiniz alan varsa numarasını yazın.\"",
|
|
54
58
|
"",
|
|
@@ -60,7 +64,7 @@ export const ORTAK_KURALLAR = [
|
|
|
60
64
|
"- Amaç: hocanın en az müdahalesiyle işi hızlı ama denetimli ve teyitli bitirmek.",
|
|
61
65
|
"- 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.",
|
|
62
66
|
"- Her mesajda tek iş iste. Ne yapacağını ve ekranda ne göreceğini söyle.",
|
|
63
|
-
`-
|
|
67
|
+
`- ${AKILLI_DOLDURMA_KURALI}`,
|
|
64
68
|
'- 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.',
|
|
65
69
|
"- Sunucu metin üretmez. Seçenek metinlerini sen yazarsın; sunucu kural verir, denetler ve sayıları hesaplar.",
|
|
66
70
|
"- Sayıları (toplam, yüzde, iş yükü, sağlanma düzeyi) yalnız araç yanıtından al, kendin toplama.",
|
|
@@ -82,6 +86,9 @@ const kisa = (v, n = 40) => v
|
|
|
82
86
|
.trim()
|
|
83
87
|
.slice(0, n)
|
|
84
88
|
: "";
|
|
89
|
+
/** Odak menüsünün başlığı: istemde ve akredit_basla yanıtında aynı. */
|
|
90
|
+
const MENU_BASLIGI = "Merhaba. Neye odaklanalım? Yalnız numarasını yazın.";
|
|
91
|
+
const BASKA = "Başka bir şey: tüm araçları kısaca listele";
|
|
85
92
|
const ODAKLAR = [
|
|
86
93
|
["1", "Bologna ders paketini denetle ve boş alanları doldur", "bologna_doldur"],
|
|
87
94
|
["2", "Ders öğrenme çıktısı yaz ya da iyileştir", "cikti_yaz"],
|
|
@@ -89,6 +96,7 @@ const ODAKLAR = [
|
|
|
89
96
|
["4", "YÖKAK, MÜDEK, FEDEK, EPDAD ya da SABAK ölçüt ve kanıt rehberi", "olcut_rehberi"],
|
|
90
97
|
["5", "Öz değerlendirme metninin dil denetimi", "dil_denetimi"],
|
|
91
98
|
];
|
|
99
|
+
const MENU_SATIRLARI = [MENU_BASLIGI, ...ODAKLAR.map(([no, ad]) => `${no}) ${ad}`), `${ODAKLAR.length + 1}) ${BASKA}`];
|
|
92
100
|
/** akredit başlangıcının sorduğu odak menüsü; site örnek konuşmayı buradan okur. */
|
|
93
101
|
export const AKREDIT_ODAKLARI = ODAKLAR.map(([no, ad]) => ({ no, ad }));
|
|
94
102
|
/** OBS'ye tarayıcıyla giriş: Bologna akışının ilk adımı. */
|
|
@@ -99,14 +107,13 @@ const obsGirisi = () => [
|
|
|
99
107
|
" a) İLK İŞ: tarayıcıda açık sekmelere bak. Açık bir OBS ya da Bologna sayfası varsa adres ve giriş sorma, doğrudan d) adımına geç. Yoksa hocaya yalnız şunu sor: \"OBS'nizin adresini yazın (bilmiyorsanız üniversitenizin adını yazın).\" Ders adını ya da paketi sorma; onları OBS'den okuyacaksın. Adres gelince hemen tarayıcıda aç. Üniversite adı gelirse kurumun OBS ya da Bologna sayfasını web aramasıyla bul ve aç.",
|
|
100
108
|
' 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."',
|
|
101
109
|
" c) CAPTCHA ya da doğrulama kodu gelirse hocanın kendisinin girmesini bekle; sen girme.",
|
|
102
|
-
" d) Hoca girdim deyince hangi dersi incelemek istediğini SORMA.
|
|
103
|
-
"
|
|
104
|
-
"
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
" Hiç eksik yoksa bunu söyle ve dil ile kaynak denetimini öner. Hoca yalnız numara yazar.",
|
|
110
|
+
" d) Hoca girdim deyince hangi dersi incelemek istediğini SORMA. Listedeki ders kodlarını ve adlarını obs_ders_listesi'ne ver, sonra kendin tara: tarama planındaki her dersin Bologna sayfasını sırayla açıp bologna_ayristir'e ver; yanıttaki denetim eksik ve kurala uymayan alanları sayar (bologna_denetle'yi ayrıca çağırma). Liste 15'erli dilimlerle taranır; sonraki dilime obs_ders_listesi'nin verdiği baslangic değeriyle geçilir.",
|
|
111
|
+
" Peşin onay varsa obs_ders_listesi'ne pesinOnay ver ve yanıtındaki adımları izle: rapor ve seçenek durağı yoktur.",
|
|
112
|
+
" Sonra tek mesajda 'Şu eksiklikleri tespit ettim, önerilerim şunlar' başlıklı kısa bir özet ver: her ders için bir satır, eksik alan sayısı (en eksikten en tamama). Aynı mesajda, eksik derslerin sayfasında olmayan değerlendirme yüzdelerini ve kaynakları da sor (Adım 3; ayrı tur açma). Altına obs_ders_listesi yanıtındaki raporBicimi seçeneklerini aynen koy:",
|
|
113
|
+
...TARAMA_SECENEKLERI.map((t) => ` ${t}`),
|
|
114
|
+
' Eksik yoksa "Eksik görünmüyor" de ve kaliteyi artıracak 2-4 somut öneri ver (zayıf ya da kısa alanlar, öğrenme çıktılarında Bloom düzeyi ve ölçülebilirlik, iş yükü ile AKTS uyumu, kaynakların güncelliği, İngilizce alanların eksiksizliği); önerilen seçenekle numaralı sun. Hoca yalnız numara yazar.',
|
|
108
115
|
" e) Dersin Bologna (ders bilgi paketi) sayfasını oku. Okuduğun metni ya da HTML'i bologna_ayristir'e ver.",
|
|
109
|
-
' Tarayıcı aracın yoksa
|
|
116
|
+
' Tarayıcı aracın yoksa ÖNCE eklentiyi kurdur: engel_coz (engel: tarayici_araci_yok, istemciyi biliyorsan istemci) çağır ve şunu yaz: "Akredit OBS\'nizi Chrome eklentisiyle kendisi açar, doldurur ve kaydeder; eklenti olmadan her alanı siz kopyalarsınız. Kurulum 2 dakika: 1) kuralım (önerilen) 2) kurmadan devam, metni ben yapıştırayım." 1 gelirse adımları tek tek göster, bitince yeni sohbette akredit yazmasını söyle. Yalnız 2 gelirse ya da istemcide eklenti yoksa (ChatGPT/Codex) şunu yaz: "OBS\'de dersinizin Bologna sayfasını açın, Ctrl+A ile seçip Ctrl+C ile kopyalayın ve buraya yapıştırın."',
|
|
110
117
|
" 1 gelirse kurulum_yardimi'nı hocanın asistanıyla (istemci) çağır, adımları tek tek göster.",
|
|
111
118
|
" Herhangi bir engelde engel_coz'u ilgili engel türüyle çağır.",
|
|
112
119
|
].join("\n");
|
|
@@ -121,12 +128,13 @@ const KAYNAK_ADIMI = [
|
|
|
121
128
|
const OBS_YAZMA = [
|
|
122
129
|
"6. OBS'ye yazma.",
|
|
123
130
|
" Önce bologna_kopya_metni'ni çağır (OBS'deki şimdiki değerleri oncekiDegerler olarak ver). Yazma paketine alınmayanları (doğrulanmamış kaynak, teyitsiz değerlendirme yüzdesi) hocaya söyle; onları yazma.",
|
|
124
|
-
" Ara özet gösterip 'devam' bekleme. TEK mesajda degisiklikOzeti'ni göster (numara, sekme, alan, önceki değer, yeni değer, kaynağı: sayfa, hoca ya da öneri; toplu modda bütün dersler tek tabloda) ve altına sor:",
|
|
131
|
+
" Ara özet gösterip 'devam' bekleme. TEK mesajda degisiklikOzeti'ni göster (numara, sekme, alan, önceki değer, yeni değer, kaynağı: sayfa, hoca ya da öneri; toplu modda bologna_toplu_ozet ile bütün dersler tek tabloda) ve altına sor:",
|
|
125
132
|
" 1) OBS'ye yaz ve kaydet (bu seçim, yukarıdaki özete 'kaydet' onayıdır)",
|
|
126
133
|
" 2) Formu doldur, Kaydet'e ben basayım",
|
|
127
134
|
" 3) Alan alan kopya metni ver",
|
|
128
135
|
" Değiştirmek istediğiniz alan varsa numarasını yazın.",
|
|
129
136
|
" Tarayıcı aracın yoksa yalnız 3'ü sun.",
|
|
137
|
+
" Peşin onay: hoca başta 'hepsini yap ve kaydet' gibi bir sözle onay verdiyse o metni bologna_kopya_metni'ne (toplu modda bologna_toplu_ozet'e) pesinOnay olarak ver; araç 'peşin onay var' derse özet gösterip beklemeden yaz, kaydet, geri oku, doğrula ve sonda tek rapor ver. Bilmediğin resmî bilgiyi EKSİK bırak, uydurma.",
|
|
130
138
|
" 1: Yalnız hoca 1 ya da 'kaydet' yazdıysa, yalnız özetteki alanları yaz ve kaydet. Her sekmeden önce ders kodunu ve dönemi sayfada denetle; beklenenden farklıysa yazmayı durdur ve hocaya söyle.",
|
|
131
139
|
" 2: OBS düzenleme ekranında sekme sekme ilgili kutulara yaz. Her sekmeden sonra dur ve hocadan gözle denetleyip Kaydet'e basmasını iste.",
|
|
132
140
|
" 3: bologna_kopya_metni metnini her alan ayrı kod bloğunda ver, hangi sekmedeki hangi kutuya yapıştırılacağını yaz.",
|
|
@@ -141,19 +149,19 @@ const bolognaAkisi = (dersKodu) => [
|
|
|
141
149
|
"1. Ayrıştır. bologna_ayristir önce Proliz biçimini, olmazsa genel ayrıştırıcıyı dener (sekmeli düz metin de olur). Bulunamayan alanları ve ingilizce değerini not al; sonraki araçlara ingilizce değerini aynen ver.",
|
|
142
150
|
" 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.",
|
|
143
151
|
" Program çıktıları sayfası da varsa onu da ayrıştır ve P kodlarını sakla; P kodlarını asla ezberden yazma.",
|
|
144
|
-
"2. Denetle. bologna_denetle'yi çağır. Nasıl doldurulacağını SORMA: varsayılan her zaman akıllı doldurmadır.",
|
|
145
|
-
"3. Teyit. Yalnız sayfada olmayan değerlendirme yüzdeleri ve kaynaklar için hocaya TEK mesaj (toplu modda bütün dersler için tek mesaj). Uygulama/lab T+U+L'den okunur. Uydurma.",
|
|
152
|
+
"2. Denetle. bologna_ayristir yanıtındaki denetim alanı eksikleri ve teyit sorulacakları verir; bologna_denetle'yi yalnız bu alan yoksa çağır. Nasıl doldurulacağını SORMA: varsayılan her zaman akıllı doldurmadır.",
|
|
153
|
+
"3. Teyit. Yalnız sayfada olmayan değerlendirme yüzdeleri ve kaynaklar için hocaya TEK mesaj (toplu modda bütün dersler için tek mesaj; peşin onay varsa sorma, EKSİK bırak). Uygulama/lab T+U+L'den okunur. Uydurma.",
|
|
146
154
|
" Amaç ve içerik için hocanın verdiği kısa odak yoksa ders adından ve program çıktılarından 'öneri' yaz ve öneri olduğunu söyle.",
|
|
147
155
|
"4. bologna_alan_rehberi'ni alan='hepsi' ile bir kez çağır, bütün alanları tek seferde yaz.",
|
|
148
156
|
" Seçenekleri bologna_taslak_denetle ile denetle; biçim denetiminden geçmeyeni düzelt ve yeniden denetle. Uzun metinlerde ilk cümleyi ve kelime sayısını göster. Sonucu 'biçim denetiminden geçti; içerik teyidi: hoca' diye sun.",
|
|
149
157
|
" Akıllı doldurmada (4) en iyi seçeneği kendin seç ve hocaya alan alan sorma; sonunda tek özet göster.",
|
|
150
|
-
" Haftalık konular: 14 hafta, ara sınav ve yarıyıl sonu haftası görünür. Değerlendirme: yalnız sayfadan ya da hocadan; degerlendirmeDayanagi'ni ('sayfa' ya da 'hoca') ver.",
|
|
158
|
+
" Haftalık konular: 14 hafta, ara sınav ve yarıyıl sonu haftası görünür. Değerlendirme: yalnız sayfadan ya da hocadan; degerlendirmeDayanagi'ni ('sayfa' ya da 'hoca') ve kanıt metnini (degerlendirmeKaniti) ver.",
|
|
151
159
|
" AKTS iş yükü: is_yuku_oner'i sayfadaki değerlendirme kalemleriyle çağır; derste olmayan etkinliğe satır açılmaz. Sayfadan okunan iş yüküyle öneriyi ayrı göster. AKTS'yi değiştirme.",
|
|
152
160
|
" Öğrenme çıktısı ile program çıktısı katkı tablosu: yalnız ayrıştırılan P kodlarıyla öner.",
|
|
153
161
|
KAYNAK_ADIMI,
|
|
154
162
|
"5. Hepsini yazınca bologna_durum'u çağır; geçmeyeni düzelt. Ara adımda hocaya rapor verme.",
|
|
155
163
|
OBS_YAZMA,
|
|
156
|
-
'7. Doğrulama. Kayıttan sonra sayfayı yeniden oku (tarayıcı varsa) ya da yeniden yapıştırmasını iste; obs_karsilastir
|
|
164
|
+
'7. Doğrulama. Kayıttan sonra sayfayı yeniden oku (tarayıcı varsa) ya da yeniden yapıştırmasını iste; obs_karsilastir ile denetle (sayfayı yeniden ayrıştırırsan yanıttaki denetim kalan eksiği de sayar). Fark yoksa "Kaydedildi ve geri okunarak doğrulandı; içerik teyidi sizde" de.',
|
|
157
165
|
" Toplu modda sormadan sıradaki derse geç. Tek derste kısa bir sonuç cümlesiyle bitir.",
|
|
158
166
|
].join("\n");
|
|
159
167
|
const ciktiAkisi = (dersKodu) => [
|
|
@@ -219,9 +227,7 @@ const akreditMenusu = (odak) => {
|
|
|
219
227
|
"",
|
|
220
228
|
"Hocaya tam olarak şunu göster ve yanıtını bekle:",
|
|
221
229
|
"",
|
|
222
|
-
|
|
223
|
-
...ODAKLAR.map(([no, ad]) => `${no}) ${ad}`),
|
|
224
|
-
`${ODAKLAR.length + 1}) Başka bir şey: tüm araçları kısaca listele`,
|
|
230
|
+
...MENU_SATIRLARI,
|
|
225
231
|
"",
|
|
226
232
|
`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.`,
|
|
227
233
|
"Bu ilk menüde 4 bir odaktır (ölçüt rehberi); akıllı doldurma kısayolu odak seçildikten sonraki menülerde geçerlidir.",
|
|
@@ -284,25 +290,21 @@ export const KISA_KURALLAR = [
|
|
|
284
290
|
"Hocaya 'hangisi?' diye sormadan önce kendin tara ve öner: bütün dersleri denetle, eksikleri say, 'önerilen' seçenekle gel.",
|
|
285
291
|
"Kısa, sade Türkçe yaz; araç adı, JSON ve teknik terim gösterme. Her mesajda tek iş iste.",
|
|
286
292
|
"Uydurma yok: kişi, kitap, ISBN, DOI, tarih, sayı uydurma. Bilinmeyen EKSİK kalır.",
|
|
287
|
-
"Değerlendirme yöntem ve yüzdeleri
|
|
293
|
+
"Değerlendirme yöntem ve yüzdeleri ile kullanılan kaynaklar sayfadan okunur; yoksa hocaya TEK mesajda, numaralı sorulur; yüzdeye varsayılan konmaz. Uygulama/lab T+U+L'den okunur. Amaç ve içerik sayfada yoksa 'öneri' olarak yazılıp son özette teyide sunulur.",
|
|
288
294
|
"Ders adından ürettiğin her şeyi 'öneri' etiketiyle göster. Araç sonucu 'biçim denetiminden geçti; içerik teyidi: hoca' diye sunulur.",
|
|
289
295
|
"Sayıları yalnız araç yanıtından al.",
|
|
290
296
|
"Kaynak yalnız 'katalogda_bulundu' ise öneri olarak, ya da hoca kullandığını söylerse 'hoca_beyani' olarak yazılır.",
|
|
291
297
|
"Giriş bilgisi (parola, doğrulama kodu, çerez) istenmez; hoca yazarsa kullanma, araçlara gönderme.",
|
|
292
|
-
"OBS'ye yazmadan önce alan alan önceki/yeni değer özeti göster; hoca bir kez 'kaydet' der. Kayıttan sonra geri oku ve obs_karsilastir ile doğrula. Gönder düğmesine hoca basar.",
|
|
298
|
+
"OBS'ye yazmadan önce alan alan önceki/yeni değer özeti göster; hoca bir kez 'kaydet' der (peşin onay verdiyse durak yok, sonda tek rapor). Kayıttan sonra geri oku ve obs_karsilastir ile doğrula. Gönder düğmesine hoca basar.",
|
|
293
299
|
"Öğrenci adı ya da numarası sohbete yapıştırılmaz; not tablosunda yalnız not sütunları olur.",
|
|
294
300
|
];
|
|
295
301
|
/** akredit_basla aracının yanıtı: menü, kısa kurallar ve her seçimin akışı (istem desteklemeyen istemciler için). */
|
|
296
302
|
export function baslangic() {
|
|
297
303
|
return {
|
|
298
|
-
hocayaGoster:
|
|
299
|
-
"Merhaba. Neye odaklanalım? Yalnız numarasını yazın.",
|
|
300
|
-
...ODAKLAR.map(([no, ad]) => `${no}) ${ad}`),
|
|
301
|
-
`${ODAKLAR.length + 1}) Başka bir şey: tüm araçları kısaca listele`,
|
|
302
|
-
].join("\n"),
|
|
304
|
+
hocayaGoster: MENU_SATIRLARI.join("\n"),
|
|
303
305
|
menu: [
|
|
304
306
|
...ODAKLAR.map(([no, ad, istem]) => ({ no, ad, istem })),
|
|
305
|
-
{ no: String(ODAKLAR.length + 1), ad:
|
|
307
|
+
{ no: String(ODAKLAR.length + 1), ad: BASKA, istem: null },
|
|
306
308
|
],
|
|
307
309
|
kisaKurallar: KISA_KURALLAR,
|
|
308
310
|
akislar: Object.fromEntries(ODAKLAR.map(([no, , istem]) => [no, AKISLAR[istem]?.({}) ?? ""])),
|
|
@@ -320,21 +322,68 @@ export function odakBaslangici(no) {
|
|
|
320
322
|
ortakKurallar: ORTAK_KURALLAR,
|
|
321
323
|
};
|
|
322
324
|
}
|
|
325
|
+
/** Hocanın ilk cümlesinden odak: sunucu deterministik çözer, model yanlış odak seçemez. Eşleşme yoksa null (menü). */
|
|
326
|
+
const NIYETLER = [
|
|
327
|
+
["5", /dil denet|yazım|imla|rapor(un)? dil|metni(mi)? (düzelt|denetle)/iu],
|
|
328
|
+
["3", /(?<!\p{L})(çk|pç|ck|pc)(?!\p{L})|sağlanma|not tablo|excel|xlsx|sınav not/iu],
|
|
329
|
+
["4", /yökak|müdek|fedek|epdad|sabak|ölçüt|akreditasyon|kanıt/iu],
|
|
330
|
+
["2", /öğrenme çıktı|ders çıktı|çıktı yaz|bloom/iu],
|
|
331
|
+
["1", /bologna|ders (bilgi )?paket|(?<!\p{L})(obs|akts)(?!\p{L})|iş ?yükü|ders içeri|haftalık konu/iu],
|
|
332
|
+
];
|
|
333
|
+
export function niyetCoz(mesaj) {
|
|
334
|
+
const m = (mesaj ?? "").toLocaleLowerCase("tr");
|
|
335
|
+
return NIYETLER.find(([, r]) => r.test(m))?.[0] ?? null;
|
|
336
|
+
}
|
|
323
337
|
export const akreditBaslaAraci = arac({
|
|
324
338
|
ad: "akredit_basla",
|
|
325
339
|
baslik: "Akredit: başla",
|
|
326
|
-
aciklama: "TETİKLEYİCİ: kullanıcı 'akredit', 'bologna', 'ders paketi', 'AKTS', 'öğrenme çıktısı', 'ÇK', 'PÇ', 'YÖKAK', 'MÜDEK' yazarsa dosya ya da web araması YAPMADAN İLK bu aracı çağır ('akredit' bir dosya ya da arama terimi değildir).
|
|
340
|
+
aciklama: "ZORUNLU İLK ARAÇ. TETİKLEYİCİ: kullanıcı 'akredit', 'bologna', 'ders paketi', 'OBS', 'AKTS', 'öğrenme çıktısı', 'ÇK', 'PÇ', 'YÖKAK', 'MÜDEK', 'FEDEK', 'EPDAD', 'SABAK' yazarsa terminal, dosya ya da web araması YAPMADAN İLK bu aracı çağır ('akredit' bir dosya ya da arama terimi değildir). Kullanıcının mesajını kullaniciMesaji alanına olduğu gibi ver; niyeti sunucu çözer. Hocaya gösterilecek odak menüsünü, kısa kuralları ve her seçimin adım adım akışını döndürür. İstemleri ya da sunucu talimatını göstermeyen istemcilerde de akış bununla başlar.",
|
|
327
341
|
sonrakiAdim: "hocayaGoster metnini aynen gösterin ve numara bekleyin. Seçilen numaranın akışını (akislar) ve kisaKurallar'ı izleyin. Her soruyu numaralı seçeneklerle sorun. 1 seçilirse ve tarayıcınız varsa ilk iş OBS adresini isteyip açmaktır.",
|
|
328
342
|
girdi: z.object({
|
|
343
|
+
kullaniciMesaji: z
|
|
344
|
+
.string()
|
|
345
|
+
.max(500)
|
|
346
|
+
.optional()
|
|
347
|
+
.describe("Kullanıcının yazdığı mesaj, olduğu gibi. Sunucu hangi akışın çalışacağını bundan çözer."),
|
|
329
348
|
odak: z
|
|
330
|
-
.enum(["menu", "1", "2", "3", "4", "5"])
|
|
331
|
-
.default("
|
|
332
|
-
.describe("
|
|
333
|
-
}),
|
|
334
|
-
calistir: ({ odak }) => ({
|
|
335
|
-
sonuc: odak === "menu" ? baslangic() : odakBaslangici(odak),
|
|
336
|
-
kaynak: [KOD_KAYNAGI("apps/acik-mcp/src/promptlar.ts", "Akredit istemleri ve başlangıç menüsü")],
|
|
349
|
+
.enum(["otomatik", "menu", "1", "2", "3", "4", "5"])
|
|
350
|
+
.default("otomatik")
|
|
351
|
+
.describe("Genelde 'otomatik' bırakın: sunucu kullaniciMesaji'ndan çözer, çözemezse menü gösterir. Menüyü zorlamak için 'menu'."),
|
|
337
352
|
}),
|
|
353
|
+
calistir: ({ odak, kullaniciMesaji }) => {
|
|
354
|
+
const no = odak === "otomatik" ? niyetCoz(kullaniciMesaji) : odak === "menu" ? null : odak;
|
|
355
|
+
const temel = no ? odakBaslangici(no) : baslangic();
|
|
356
|
+
// Peşin onay yalnız OBS'ye yazan odaklarda (Bologna paketi, öğrenme çıktısı) anlamlıdır.
|
|
357
|
+
const obsYazar = no === "1" || no === "2";
|
|
358
|
+
const pesin = obsYazar && pesinOnayVar(kullaniciMesaji);
|
|
359
|
+
const sonuc = pesin
|
|
360
|
+
? {
|
|
361
|
+
...temel,
|
|
362
|
+
hocayaGoster: `${temel.hocayaGoster} Peşin onayınızla ara soru sormadan ilerleyeceğim: tarar, doldurur, OBS'ye kaydeder, geri okuyup doğrularım. Yalnız OBS giriş ekranında dururum. Bilmediğim resmî bilgiyi (değerlendirme yüzdesi, kullandığınız kaynak) uydurmam, boş bırakıp sonda listelerim. Onaya Gönder'e siz basarsınız. Vazgeçmek için 'dur' yazın.`,
|
|
363
|
+
pesinOnay: {
|
|
364
|
+
metin: kullaniciMesaji ?? "",
|
|
365
|
+
not: "Bologna araçlarına (obs_ders_listesi, bologna_kopya_metni, bologna_toplu_ozet) pesinOnay olarak bu metni olduğu gibi verin.",
|
|
366
|
+
},
|
|
367
|
+
}
|
|
368
|
+
: obsYazar
|
|
369
|
+
? {
|
|
370
|
+
...temel,
|
|
371
|
+
ipucu: "Hoca 'hepsini yap ve kaydet' yazarsa peşin onay kipi açılır: ara durak olmaz, sonda tek rapor.",
|
|
372
|
+
}
|
|
373
|
+
: temel;
|
|
374
|
+
return {
|
|
375
|
+
sonuc,
|
|
376
|
+
kaynak: [KOD_KAYNAGI("apps/acik-mcp/src/promptlar.ts", "Akredit istemleri ve başlangıç menüsü")],
|
|
377
|
+
hocayaSimdiSor: !no,
|
|
378
|
+
...(no
|
|
379
|
+
? {
|
|
380
|
+
sonrakiAdim: pesin
|
|
381
|
+
? "hocayaGoster cümlesini yazın ve sormadan başlayın. Bologna ise ilk iş tarayıcıda OBS'yi açmaktır; ders listesi gelince obs_ders_listesi'ni pesinOnay ile çağırın."
|
|
382
|
+
: "hocayaGoster cümlesini yazın ve sormadan 'akis' adımlarını izleyin. Bologna ise ilk iş tarayıcıda OBS'yi açmaktır.",
|
|
383
|
+
}
|
|
384
|
+
: {}),
|
|
385
|
+
};
|
|
386
|
+
},
|
|
338
387
|
});
|
|
339
388
|
/** SDK için bağımsız değişken şeması: hepsi isteğe bağlı, kısa metin. */
|
|
340
389
|
export const istemSemasi = (i) => Object.fromEntries(Object.entries(i.argumanlar).map(([k, d]) => [k, z.string().max(60).optional().describe(d)]));
|
|
@@ -2,10 +2,11 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
2
2
|
import { type AcikArac, type AracBaglami } from "./araclar.ts";
|
|
3
3
|
import { type AcikIstem } from "./promptlar.ts";
|
|
4
4
|
export declare const SUNUCU_ADI = "akredit-acik";
|
|
5
|
-
export declare const SUNUCU_SURUMU = "0.
|
|
5
|
+
export declare const SUNUCU_SURUMU = "0.8.1";
|
|
6
6
|
export declare const SUNUCU_TALIMATI: string;
|
|
7
7
|
/** Her araç yanıtında yinelenen kısa kural: uzun sohbette son okunan metin de aynı şeyi söyler. */
|
|
8
|
-
export declare const
|
|
8
|
+
export declare const SORMADAN_DEVAM = "Bu ad\u0131mda hocaya soru sormay\u0131n ve onay beklemeyin; do\u011Frudan sonrakiAdim'\u0131 uygulay\u0131n.";
|
|
9
|
+
export declare const ASISTAN_KURALI = "1) Ara ad\u0131mda hocaya A/B/C sorma; en iyi se\u00E7ene\u011Fi kendin se\u00E7, s\u0131radaki arac\u0131 \u00E7a\u011F\u0131r. 2) Zorunlu soruyu (sayfada olmayan de\u011Ferlendirme y\u00FCzdesi ve kaynak, OBS kay\u0131t onay\u0131) TEK mesajda ve numaral\u0131 sor; pe\u015Fin onay varsa sorma, EKS\u0130K b\u0131rak, sonda listele. 3) Say\u0131, kaynak ve de\u011Ferlendirme y\u00FCzdesi uydurma. 4) Parola ve do\u011Frulama kodu isteme; Onaya G\u00F6nder'e hoca basar.";
|
|
9
10
|
export interface AcikSunucuSecenekleri {
|
|
10
11
|
simdi?: () => Date;
|
|
11
12
|
araclar?: readonly AcikArac[];
|
|
@@ -1,31 +1,34 @@
|
|
|
1
|
-
// Açık MCP sunucusu: resmî TypeScript SDK'nın McpServer'ı üzerine kurulur. Her araç salt
|
|
2
|
-
// deterministiktir
|
|
1
|
+
// Açık MCP sunucusu: resmî TypeScript SDK'nın McpServer'ı üzerine kurulur. Her araç salt okumadır; kaynak_dogrula
|
|
2
|
+
// dışındakiler deterministiktir (o, sabit açık kataloglara sorar). Araç açıklamaları ve yanıtlar Türkçedir. Gelen veride kişisel veri deseni görülürse
|
|
3
3
|
// çağrı hesap yapılmadan reddedilir. Her yanıt kaynak listesi ve "YÖKAK ile bağı yoktur" notu taşır.
|
|
4
4
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
5
|
import { ACIK_ARACLAR, AKREDIT_NOTU, AracHatasi, DEPO, } from "./araclar.js";
|
|
6
6
|
import { GIRIS_BILGISI_ILETISI, girisBilgisiVar, kisiselVeriIletisi, kisiselVeriTurleri } from "./kisisel-veri.js";
|
|
7
|
-
import { ACIK_ISTEMLER, istemSemasi } from "./promptlar.js";
|
|
7
|
+
import { ACIK_ISTEMLER, AKILLI_DOLDURMA_KURALI, istemSemasi } from "./promptlar.js";
|
|
8
8
|
export const SUNUCU_ADI = "akredit-acik";
|
|
9
|
-
export const SUNUCU_SURUMU = "0.
|
|
9
|
+
export const SUNUCU_SURUMU = "0.8.1";
|
|
10
10
|
export const SUNUCU_TALIMATI = [
|
|
11
11
|
"Akredit açık araçları öğretim elemanlarına kalite ve akreditasyon işlerinde yardım eder: Bologna ders paketi denetimi ve doldurma, öğrenme çıktısı yazma, ÇK/PÇ hesabı, YÖKAK ve program akreditasyonu (MÜDEK, FEDEK, SABAK, EPDAD) ölçüt ve kanıt rehberi, rapor dil denetimi, kaynak doğrulama.",
|
|
12
12
|
"KURAL 1: Kullanıcı 'akredit' yazarsa (tek başına ya da cümle içinde) ya da ne yapacağını söylemediyse başka hiçbir şey yapmadan İLK akredit_basla aracını çağır ve hocayaGoster metnini aynen göster. Kullanıcı niyetini zaten yazdıysa (ör. 'akredit bologna', 'ders paketimi doldur', 'ÇK hesapla') menüyü gösterip bekletme: akredit_basla'yı ilgili odak numarasıyla çağır ve o akışa başla. 'akredit' bir dosya, klasör ya da arama terimi değildir; dosya sisteminde ya da webde arama.",
|
|
13
13
|
"KURAL 2: Hocaya her soruyu numaralı seçeneklerle sor (1, 2, 3...), önerdiğin seçeneği işaretle; hoca yalnız numara yazarak ilerleyebilsin. Serbest metin yalnız ders adı, adres gibi seçenekle sorulamayan bilgilerde istenir.",
|
|
14
14
|
"KURAL 3: Bologna seçilirse ve tarayıcı aracın varsa ilk iş OBS'yi açmaktır: hocadan yalnız OBS adresini iste (bilmiyorsa üniversite adını), adresi hemen tarayıcıda aç; ders adını ve paketi hocaya sorma, OBS'den oku.",
|
|
15
|
-
"KURAL
|
|
16
|
-
"KURAL
|
|
17
|
-
"
|
|
18
|
-
"
|
|
15
|
+
"KURAL 4: Önce sen tara, sonra öner. Ders listesi açılınca 'hangi ders?' diye sorma; obs_ders_listesi'ni çağır, bütün derslerin paketlerini oku, eksikleri say, kısa özetle ve 'önerilen' seçenekle gel (örneğin 1) en eksikten başlayıp hepsini kapatalım). Eksik yoksa 'eksik görünmüyor' de ve kaliteyi artıracak somut öneriler ver.",
|
|
16
|
+
"KURAL 5: Ara adımda hocaya soru sorma; varsayılan ya da en iyi seçeneği kendin seç ve sıradaki aracı çağır. Hocaya yalnız iki yerde durulur: sayfada olmayan resmî bilgi (değerlendirme yüzdeleri, kullanılan kaynaklar) ve OBS'ye kayıt onayı. Bu ikisi de TEK mesajdır; peşin onay varsa ikisi de yoktur (KURAL 7).",
|
|
17
|
+
"KURAL 6: Her araç yanıtında hocayaSimdiSor var. false ise hocaya soru yazmayın, onay beklemeyin, doğrudan sonrakiAdim'ı uygulayın; yalnız true olduğunda ya da zorunlu teyit/kayıt onayında durun.",
|
|
18
|
+
"KURAL 7: Peşin onay (tam otonom kip). Hoca 'hepsini yap ve kaydet', 'sen hallet', 'sormadan kaydet' gibi bir sözle baştan onay verdiyse o sözü Bologna araçlarına pesinOnay olarak olduğu gibi ver ve ara durak yapma: tara, doldur, OBS'ye yaz, Kaydet'e bas, geri oku, obs_karsilastir ile doğrula, sonda TEK rapor ver (yazılanlar, EKSİK kalanlar, geri okuma sonucu). Sayfada olmayan değerlendirme yüzdesi ve kaynağı sorma da uydurma da: EKSİK bırak. Yalnız OBS giriş ekranı, CAPTCHA, dur ve ikinci fark için dur. Onaya Gönder yine hocadadır; itirazı olan alanı hoca OBS'de düzeltir ya da sana numarasını yazar.",
|
|
19
|
+
"Amaç: hocanın en az müdahalesiyle işi hızlı ama denetimli ve teyitli bitirmek. " + AKILLI_DOLDURMA_KURALI,
|
|
20
|
+
"Yalnız hocanın bilebileceği ve resmî taahhüt olan bilgiler (değerlendirme yöntem ve yüzdeleri, kullanılan kaynaklar) sayfadan okunur; yoksa hocaya TEK mesajda, numaralı sorulur, uydurulmaz; yüzdeye varsayılan konmaz. Uygulama/lab sorulmaz, T+U+L'den okunur. Amaç ve içerik sayfada yoksa önden sorulmaz; 'öneri' olarak yazılıp son özette teyide sunulur. Ders adından üretilen her şey 'öneri' etiketiyle gösterilir. Araç sonucu 'biçim denetiminden geçti; içerik teyidi: hoca' diye sunulur.",
|
|
19
21
|
"Giriş bilgisi: hocadan kullanıcı adı, parola, doğrulama kodu ya da çerez asla isteme. Sunucu bunları istemez; görülürse çağrıyı reddeder ve kaydetmez. Hoca yazarsa kullanma, araçlara gönderme, silmesini ve parolasını değiştirmesini öner. Hoca giriş bilgisini yalnız OBS'nin kendi ekranına kendisi yazar. CAPTCHA'yı hoca çözer.",
|
|
20
|
-
"OBS'ye yazma: önce alan alan önceki ve yeni değer özetini göster, hoca bir kez 'kaydet' ya da özetin altındaki 1'i (OBS'ye yaz ve kaydet) yazar; ancak ondan sonra Kaydet'e basarsın. Kayıttan sonra sayfayı geri okuyup obs_karsilastir ile doğrula; ders kodu ya da dönem değişmişse yazmayı durdur. Doğrulanmamış kaynak ve teyitsiz değerlendirme yüzdesi yazılmaz. Onaya Gönder düğmesine hoca basar.",
|
|
21
|
-
"Tarayıcı aracın varsa OBS sayfasını okuyup formu doldurabilirsin
|
|
22
|
+
"OBS'ye yazma: önce alan alan önceki ve yeni değer özetini göster, hoca bir kez 'kaydet' ya da özetin altındaki 1'i (OBS'ye yaz ve kaydet) yazar; ancak ondan sonra Kaydet'e basarsın (peşin onay varsa KURAL 7 geçerlidir: bu durak yoktur, özet sondaki raporda verilir). Kayıttan sonra sayfayı geri okuyup obs_karsilastir ile doğrula; ders kodu ya da dönem değişmişse yazmayı durdur. Doğrulanmamış kaynak ve teyitsiz değerlendirme yüzdesi yazılmaz. Onaya Gönder düğmesine hoca basar.",
|
|
23
|
+
"Tarayıcı aracın varsa OBS sayfasını okuyup formu doldurabilirsin. Yoksa kopyalamaya geçmeden önce Chrome eklentisini (Claude in Chrome) kurdurmayı öner: engel_coz(tarayici_araci_yok) adımlarını tek tek göster; otonom akış ancak eklentiyle çalışır. Hoca kurmak istemezse ya da istemcide eklenti yoksa OBS'ye yazma alan alan kopyalamaya düşer. Engel çıkarsa engel_coz ve kurulum_yardimi adımlarını sırayla göster.",
|
|
22
24
|
"Sunucu model çağırmaz ve metin üretmez: seçenekleri sen yazarsın, sunucu kural ve kalıp verir, denetler ve sayıları hesaplar. Sayıları yalnız araç sonucundan al.",
|
|
23
25
|
"Bologna sayfasındaki Dersi Verenler, Yardımcılar ve Koordinatör satırları yayımlanmış görev bilgisidir: olduğu gibi okunur, korunur, değiştirilmez. Öğrenci adı ve numarası sohbete yapıştırılmaz: not tablosunda yalnız not sütunları olur; kimlik sütunu görülürse tablo işlenmez. Sunucu istek içeriğini günlüğe yazmaz.",
|
|
24
26
|
"Kaynak: önce sayfadaki ve hocanın kullandığı kaynaklar. Öneri gerekirse kendi web arama aracınla aday bul, kaynak_dogrula ile sorgula, yalnız 'katalogda_bulundu' dönenleri künyesi ve bağlantısıyla 'öneri' olarak göster; uygunluğuna hoca karar verir. Katalogda bulunmayanı kendin önerme; hoca kullandığını söylerse 'hoca_beyani' olarak yaz. Ölçüt metnini yalnız olcut_getir sonucundan alıntılayın; DOĞRULANMADI ya da 'Belgeden okunamadı' işaretli metni tahminle doldurmayın. Programın disiplinini kurum seçer. Kanıtı olmayan cümle EKSİK kalır. Kitap, kişi, tarih uydurmayın.",
|
|
25
27
|
"Sunucu kullanıcıdan adres çekmez: Bologna sayfasını hoca yapıştırır ya da siz kendi web aracınızla okursunuz. Tek dış istek kaynak_dogrula'nın sabit katalog adresleridir (Crossref, Open Library, Google Books). Onay ve dış kuruma gönderim hocadadır. Akredit'in YÖKAK ile bağı yoktur.",
|
|
26
28
|
].join(" ");
|
|
27
29
|
/** Her araç yanıtında yinelenen kısa kural: uzun sohbette son okunan metin de aynı şeyi söyler. */
|
|
28
|
-
export const
|
|
30
|
+
export const SORMADAN_DEVAM = "Bu adımda hocaya soru sormayın ve onay beklemeyin; doğrudan sonrakiAdim'ı uygulayın.";
|
|
31
|
+
export const ASISTAN_KURALI = "1) Ara adımda hocaya A/B/C sorma; en iyi seçeneği kendin seç, sıradaki aracı çağır. 2) Zorunlu soruyu (sayfada olmayan değerlendirme yüzdesi ve kaynak, OBS kayıt onayı) TEK mesajda ve numaralı sor; peşin onay varsa sorma, EKSİK bırak, sonda listele. 3) Sayı, kaynak ve değerlendirme yüzdesi uydurma. 4) Parola ve doğrulama kodu isteme; Onaya Gönder'e hoca basar.";
|
|
29
32
|
const metinSonuc = (veri, isError = false) => ({
|
|
30
33
|
content: [{ type: "text", text: JSON.stringify(veri, null, 2) }],
|
|
31
34
|
structuredContent: veri,
|
|
@@ -74,6 +77,8 @@ function basari(a, s, atilan, ileti) {
|
|
|
74
77
|
veri: {
|
|
75
78
|
sonuc: s.sonuc,
|
|
76
79
|
sonrakiAdim: s.sonrakiAdim ?? a.sonrakiAdim,
|
|
80
|
+
hocayaSimdiSor: s.hocayaSimdiSor ?? a.hocayaSimdiSor ?? false,
|
|
81
|
+
...((s.hocayaSimdiSor ?? a.hocayaSimdiSor) ? {} : { simdiYap: SORMADAN_DEVAM }),
|
|
77
82
|
asistanKurali: ASISTAN_KURALI,
|
|
78
83
|
...(atilan.length
|
|
79
84
|
? { atilan: ileti ?? `Şu kısımlar okunmadan atıldı, hiçbir yere yazılmadı: ${atilan.join(", ")}.` }
|
|
@@ -15,6 +15,8 @@ export interface AracSonucu {
|
|
|
15
15
|
kaynak: Kaynak[];
|
|
16
16
|
/** Asistana bir sonraki adım önerisi; verilmezse aracın varsayılanı kullanılır. */
|
|
17
17
|
sonrakiAdim?: string;
|
|
18
|
+
/** Bu adımda hocaya bir şey sorulmalı mı; verilmezse aracın varsayılanı (o da yoksa false). */
|
|
19
|
+
hocayaSimdiSor?: boolean;
|
|
18
20
|
}
|
|
19
21
|
export interface AracBaglami {
|
|
20
22
|
simdi: () => Date;
|
|
@@ -28,6 +30,8 @@ export interface AcikArac<S extends z.ZodObject = z.ZodObject> {
|
|
|
28
30
|
girdi: S;
|
|
29
31
|
/** Yanıtta dönen varsayılan "sonraki adım" önerisi. */
|
|
30
32
|
sonrakiAdim: string;
|
|
33
|
+
/** Yanıttaki hocayaSimdiSor bayrağının varsayılanı: true yalnız hocanın karar verdiği duraklarda. */
|
|
34
|
+
hocayaSimdiSor?: boolean;
|
|
31
35
|
/** Kişisel veri reddinde iletiye eklenecek, bu araca özgü ipucu. */
|
|
32
36
|
kisiselVeriIpucu?: string;
|
|
33
37
|
/**
|
|
@@ -56,4 +60,8 @@ export declare const arac: <S extends z.ZodObject>(a: AcikArac<S>) => AcikArac<S
|
|
|
56
60
|
/** Araç girdisi hatası: kullanıcıya gösterilecek Türkçe ileti. */
|
|
57
61
|
export declare class AracHatasi extends Error {
|
|
58
62
|
}
|
|
63
|
+
export declare function pesinOnayVar(metin: string | undefined): boolean;
|
|
64
|
+
export declare const PESIN_ONAY_ACIKLAMASI = "Hocan\u0131n pe\u015Fin onay\u0131, kendi s\u00F6zleriyle oldu\u011Fu gibi (\u00F6r. 'hepsini yap ve kaydet'). Varsa ve kay\u0131t s\u00F6z\u00FC i\u00E7eriyorsa ara durak olmadan yaz\u0131l\u0131p kaydedilir; sonda tek rapor verilir. Olumsuz s\u00F6z ('kaydetme', 'kaydetmeden \u00F6nce sor') onay say\u0131lmaz. Onaya G\u00F6nder hocada kal\u0131r.";
|
|
59
65
|
export declare const KOD_KAYNAGI: (yol: string, ad: string) => Kaynak;
|
|
66
|
+
/** Tarama raporunun numaralı seçenekleri: tek kaynak. obs_ders_listesi'nin raporBicimi ve istem metni bunu kullanır. */
|
|
67
|
+
export declare const TARAMA_SECENEKLERI: readonly ["1) Eksikleri en çok olandan başlayarak hepsini kapatalım (önerilen)", "2) Yalnız en eksik dersi tamamlayalım", "3) Kalite önerilerini de uygulayalım", "4) Dersi ben seçeyim"];
|
|
@@ -7,4 +7,36 @@ export const arac = (a) => a;
|
|
|
7
7
|
/** Araç girdisi hatası: kullanıcıya gösterilecek Türkçe ileti. */
|
|
8
8
|
export class AracHatasi extends Error {
|
|
9
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* Peşin onay (tam otonom kip): hoca başta bir kez "hepsini yap ve kaydet" der; asistan ara durak olmadan tarar, doldurur,
|
|
12
|
+
* OBS'ye kaydeder, geri okuyup doğrular ve sonda tek rapor verir. Onay hocanın kendi sözleriyle verilir ve kayda
|
|
13
|
+
* geçer (ilke 3); metinde kayıt/yetki sözü yoksa onay sayılmaz. Onaya Gönder yine hocadadır; bilinmeyen resmî bilgi
|
|
14
|
+
* uydurulmaz, EKSİK bırakılıp raporda listelenir (ilke 2).
|
|
15
|
+
*/
|
|
16
|
+
// Kurucu kararı (12.11.2026): onay için kayıt ya da yetki sözü zorunludur. "hepsini tara", "otonom", "sormadan"
|
|
17
|
+
// tek başına iş tarifidir, OBS'ye kayıt izni değildir.
|
|
18
|
+
const PESIN_ONAY = /kaydet|sen hallet|tam yetki|onayl[ıi]yorum/iu;
|
|
19
|
+
/**
|
|
20
|
+
* Olumsuz söz onay değildir: "kaydetme", "kaydetmeden önce sor", "sen halletme", "OBS'ye yazma", "onaylamıyorum",
|
|
21
|
+
* "istemiyorum", "hayır", "değil". Ad-fiil ("kaydetmek") olumsuz sayılmaz; "kaydetmeni" gibi belirsiz biçimler
|
|
22
|
+
* bilerek olumsuz sayılır: kuşkuda onay yoktur, hocaya bir kez sorulur (ilke 3).
|
|
23
|
+
*/
|
|
24
|
+
const PESIN_ONAY_OLUMSUZ = /kaydetme(?!k)|halletme(?!k)|(?<!\p{L})(yazma|yapma)(?!k)|onaylam[ıi]yorum|istem[ie]yorum|(?<!\p{L})istemem|verm[ie]yorum|(?<!\p{L})(hay[ıi]r|de[ğg]il)(?!\p{L})/iu;
|
|
25
|
+
export function pesinOnayVar(metin) {
|
|
26
|
+
if (!metin || metin.trim().length < 3)
|
|
27
|
+
return false;
|
|
28
|
+
// Büyük harfle yazılan Türkçe metin (DEĞİL, HAYIR) için ayrıca Türkçe küçük harfle de bakılır.
|
|
29
|
+
const kucuk = metin.toLocaleLowerCase("tr");
|
|
30
|
+
if (PESIN_ONAY_OLUMSUZ.test(metin) || PESIN_ONAY_OLUMSUZ.test(kucuk))
|
|
31
|
+
return false;
|
|
32
|
+
return PESIN_ONAY.test(metin) || PESIN_ONAY.test(kucuk);
|
|
33
|
+
}
|
|
34
|
+
export const PESIN_ONAY_ACIKLAMASI = "Hocanın peşin onayı, kendi sözleriyle olduğu gibi (ör. 'hepsini yap ve kaydet'). Varsa ve kayıt sözü içeriyorsa ara durak olmadan yazılıp kaydedilir; sonda tek rapor verilir. Olumsuz söz ('kaydetme', 'kaydetmeden önce sor') onay sayılmaz. Onaya Gönder hocada kalır.";
|
|
10
35
|
export const KOD_KAYNAGI = (yol, ad) => ({ ad, adres: `${DEPO}/tree/main/${yol}` });
|
|
36
|
+
/** Tarama raporunun numaralı seçenekleri: tek kaynak. obs_ders_listesi'nin raporBicimi ve istem metni bunu kullanır. */
|
|
37
|
+
export const TARAMA_SECENEKLERI = [
|
|
38
|
+
"1) Eksikleri en çok olandan başlayarak hepsini kapatalım (önerilen)",
|
|
39
|
+
"2) Yalnız en eksik dersi tamamlayalım",
|
|
40
|
+
"3) Kalite önerilerini de uygulayalım",
|
|
41
|
+
"4) Dersi ben seçeyim",
|
|
42
|
+
];
|
|
@@ -34,15 +34,26 @@ const ISTEMCI_ADI = {
|
|
|
34
34
|
claude_code: "Claude Code",
|
|
35
35
|
};
|
|
36
36
|
const BAGLAYICI = {
|
|
37
|
-
// Anthropic yardım belgesi "Get started with custom connectors using remote MCP" (erişim 2026-11-05).
|
|
37
|
+
// Anthropic yardım belgesi "Get started with custom connectors using remote MCP" (erişim 2026-11-05). Türkçe
|
|
38
|
+
// arayüz adları Claude masaüstünün Türkçe ekranından (apps/web/public/gorsel/kurulum, 12.11.2026); İngilizce
|
|
39
|
+
// arayüz için karşılığı parantezde.
|
|
38
40
|
claude_web: [
|
|
39
41
|
["claude.ai adresine girin ve oturum açın.", "Sol tarafta sohbet listesi, ortada yazı kutusu."],
|
|
40
|
-
["
|
|
41
|
-
["+ Add düğmesine, ardından Add custom connector seçeneğine basın.", "Ad ve adres soran pencere."],
|
|
42
|
-
[`Ad olarak Akredit, adres olarak ${MCP_ADRESI} yazın ve Continue deyin.`, "Kimlik doğrulama seçenekleri."],
|
|
43
|
-
["Authentication altında No sign in seçin ve Add deyin.", "Listede Akredit görünür."],
|
|
42
|
+
["Ayarlar'da Bağdaştırıcılar (Connectors) bölümünü açın.", "Bağdaştırıcılar listesi."],
|
|
44
43
|
[
|
|
45
|
-
"
|
|
44
|
+
"Sağ üstte + Ekle (Add), ardından Özel bağdaştırıcı ekle (Add custom connector) seçin.",
|
|
45
|
+
"Ad ve adres soran pencere.",
|
|
46
|
+
],
|
|
47
|
+
[
|
|
48
|
+
`Ad olarak Akredit, adres olarak ${MCP_ADRESI} yazın ve Devam et (Continue) deyin.`,
|
|
49
|
+
"Kimlik doğrulama seçenekleri.",
|
|
50
|
+
],
|
|
51
|
+
[
|
|
52
|
+
"Oturum açma olmadan (No sign in) seçeneğini bırakın ve Ekle (Add) deyin. 'Sunucu URL'sine sahip herkes kullanabilir' uyarısı normaldir.",
|
|
53
|
+
"Listede Akredit görünür.",
|
|
54
|
+
],
|
|
55
|
+
[
|
|
56
|
+
"Ücretsiz planda tek özel bağdaştırıcı eklenebilir. Team ve Enterprise planlarında bağdaştırıcıyı kuruluş sahibi ekler; siz Bağdaştırıcılar listesinde Akredit'i bulup Bağlan (Connect) dersiniz.",
|
|
46
57
|
undefined,
|
|
47
58
|
],
|
|
48
59
|
[
|
|
@@ -57,15 +68,18 @@ const BAGLAYICI = {
|
|
|
57
68
|
],
|
|
58
69
|
claude_masaustu: [
|
|
59
70
|
["Claude masaüstü uygulamasını açın ve oturum açın.", "claude.ai ile aynı görünüm."],
|
|
60
|
-
["Customize (Özelleştir), ardından Connectors (Bağlayıcılar) bölümünü açın.", "Bağlayıcı listesi."],
|
|
61
71
|
[
|
|
62
|
-
|
|
72
|
+
"Sol alttaki çark simgesinden Ayarlar'ı açın, soldan Bağdaştırıcılar'ı (Connectors) seçin.",
|
|
73
|
+
"Bağdaştırıcılar listesi.",
|
|
74
|
+
],
|
|
75
|
+
[
|
|
76
|
+
`+ Ekle, Özel bağdaştırıcı ekle (Add custom connector) ile ad Akredit, adres ${MCP_ADRESI} yazın; Devam et, sonra Oturum açma olmadan (No sign in) ile Ekle deyin.`,
|
|
63
77
|
"Listede Akredit görünür.",
|
|
64
78
|
],
|
|
65
79
|
["Yeni sohbette akredit yazın. Menü gelmezse Akredit araçlarıyla Bologna paketimi denetle yazın.", "Odak menüsü."],
|
|
66
80
|
],
|
|
67
81
|
claude_chrome: [
|
|
68
|
-
["Önce Claude'a Akredit
|
|
82
|
+
["Önce Claude'a Akredit bağdaştırıcısını ekleyin (Claude web adımları).", "Sohbette Akredit açık."],
|
|
69
83
|
[
|
|
70
84
|
"Chrome tarayıcısını açın. Chrome Web Mağazası'nda Claude eklentisini arayın (Claude in Chrome).",
|
|
71
85
|
"Eklentinin sayfası.",
|
|
@@ -156,8 +170,8 @@ const TARAYICI = {
|
|
|
156
170
|
"OBS ana sayfası.",
|
|
157
171
|
],
|
|
158
172
|
[
|
|
159
|
-
"Asistana 'girdim' yazın. Asistan ders listesini ve Bologna sayfasını
|
|
160
|
-
"
|
|
173
|
+
"Asistana 'girdim' yazın. Asistan ders listesini okur ve bütün derslerinizin Bologna sayfasını tarar.",
|
|
174
|
+
"Eksikler ve öneriler sohbette tek listede görünür.",
|
|
161
175
|
],
|
|
162
176
|
],
|
|
163
177
|
claude_chrome: [
|
|
@@ -171,7 +185,10 @@ const TARAYICI = {
|
|
|
171
185
|
"Asistan sayfayı okumak için izin isteyebilir; onaylayın.",
|
|
172
186
|
true,
|
|
173
187
|
],
|
|
174
|
-
[
|
|
188
|
+
[
|
|
189
|
+
"Asistan ders listesini okur ve bütün derslerinizi tarar; hangi dersle başlanacağını numarayla seçersiniz.",
|
|
190
|
+
"Eksiklerin ve önerilerin tek listesi.",
|
|
191
|
+
],
|
|
175
192
|
[
|
|
176
193
|
"Asistan formu doldurursa her alanı gözle denetleyin. Kaydet'e siz basarsınız; isterseniz açık izninizle asistan basar. Onaya Gönder düğmesine siz basarsınız.",
|
|
177
194
|
"OBS'nin kayıt iletisi.",
|
|
@@ -336,6 +353,8 @@ export const kurulumYardimiAraci = arac({
|
|
|
336
353
|
ad: "kurulum_yardimi",
|
|
337
354
|
baslik: "Kurulum yardımı",
|
|
338
355
|
aciklama: "Akredit bağlayıcısını eklemek ve OBS'ye tarayıcıyla girmek için istemciye göre adım adım rehber verir: Claude web ve masaüstü, Claude in Chrome, ChatGPT, Cursor, VS Code, Claude Code. Her adımda ekranda ne görüleceğini söyler.",
|
|
356
|
+
// Adımlar hocayla tek tek yürür; her adımda hocanın "oldu" demesi beklenir.
|
|
357
|
+
hocayaSimdiSor: true,
|
|
339
358
|
sonrakiAdim: "Adımları hocaya tek tek gösterin: bir adım verin, 'oldu' demesini bekleyin, sonra sıradakine geçin. 'değişebilir' işaretli menü adını 'sizde biraz farklı olabilir' diye söyleyin. Giriş kuralını hocaya bir kez açıkça söyleyin.",
|
|
340
359
|
girdi: z.object({
|
|
341
360
|
istemci: z.enum(ISTEMCILER).describe("Hocanın kullandığı asistan"),
|
|
@@ -355,6 +374,14 @@ export const kurulumYardimiAraci = arac({
|
|
|
355
374
|
kaynak: [KOD_KAYNAGI("apps/acik-mcp/src/yardim.ts", "Akredit kurulum rehberi")],
|
|
356
375
|
}),
|
|
357
376
|
});
|
|
377
|
+
/** Asistanın hocaya sormadan önce kendisinin deneyeceği toparlama; yalnız giriş, CAPTCHA ve kurulum hocadadır. */
|
|
378
|
+
const KENDI_TOPARLAMA = {
|
|
379
|
+
cerceve: "Hocaya 'yeni sekmede açın' demeden önce: sayfadaki iframe'in src adresini okuyup o adrese kendiniz gidin ve sayfayı yeniden okuyun. Giriş ekranına düşerseniz adımlara geçin.",
|
|
380
|
+
sayfa_okunamiyor: "Hocaya söylemeden önce: sayfadaki sekmeleri (Ders Bilgileri, Öğrenme Çıktıları, Ders Akışı, Katkı) sırayla açıp metinlerini birleştirin ve bologna_ayristir'ı yeniden çağırın. Hâlâ temel alanlar okunamıyorsa adımlara geçin.",
|
|
381
|
+
kaydet_basilamiyor: "Önce kendiniz: sayfayı aşağı kaydırıp sekmenin kendi Kaydet düğmesini arayın, açık uyarı penceresi varsa okuyun. Hata iletisi bir alanı gösteriyorsa onu düzeltin (onaylanan içerik değişmeden). Olmazsa adımlara geçin.",
|
|
382
|
+
oturum_dustu: "Taslağı kaybetmeyin: hemen bologna_kopya_metni ile yedek metni alın. Hocaya tek mesajda 'Oturum düştü; OBS sekmesinde yeniden girip girdim yazın, kaldığım yerden sürdürürüm' deyin ve aynı mesajda kopya metnini verin.",
|
|
383
|
+
site_acilmiyor: "Önce kendiniz: adresi http/https ve www'lü/www'süz deneyin, kurumun OBS sayfasını web aramasıyla bulun. Olmazsa adımlara geçin.",
|
|
384
|
+
};
|
|
358
385
|
export const engelCozAraci = arac({
|
|
359
386
|
ad: "engel_coz",
|
|
360
387
|
baslik: "Engel çöz",
|
|
@@ -370,12 +397,19 @@ export const engelCozAraci = arac({
|
|
|
370
397
|
return {
|
|
371
398
|
sonuc: {
|
|
372
399
|
engel: e.ad,
|
|
400
|
+
...(KENDI_TOPARLAMA[engel] ? { asistanOnceKendisiDener: KENDI_TOPARLAMA[engel] } : {}),
|
|
373
401
|
girisKurali: GIRIS_KURALI_HOCAYA,
|
|
374
402
|
adimlar: numarala([...ozel, ...e.adimlar]),
|
|
375
403
|
...(e.yedek ? { yedekYol: numarala(KOPYALA_YAPISTIR) } : {}),
|
|
376
404
|
obsyeYazmaYedegi: "Tarayıcı aracı yoksa asistan bologna_kopya_metni ile alan alan kopyalanacak metni verir; siz OBS'de ilgili kutuya yapıştırıp Kaydet'e basarsınız.",
|
|
377
405
|
},
|
|
378
406
|
kaynak: [KOD_KAYNAGI("apps/acik-mcp/src/yardim.ts", "Akredit engel çözme rehberi")],
|
|
407
|
+
...(KENDI_TOPARLAMA[engel] && engel !== "oturum_dustu"
|
|
408
|
+
? {
|
|
409
|
+
hocayaSimdiSor: false,
|
|
410
|
+
sonrakiAdim: "Önce asistanOnceKendisiDener'i hocaya sormadan uygulayın. Çözülmezse adımları hocaya tek tek gösterin. Parola, doğrulama kodu ya da çerez istemeyin.",
|
|
411
|
+
}
|
|
412
|
+
: { hocayaSimdiSor: true }),
|
|
379
413
|
};
|
|
380
414
|
},
|
|
381
415
|
});
|
|
@@ -3,14 +3,16 @@
|
|
|
3
3
|
const VARLIKLAR = { nbsp: " ", amp: "&", lt: "<", gt: ">", quot: '"', apos: "'" };
|
|
4
4
|
const ETIKET = /<(?:[^>"']|"[^"]*"|'[^']*')*>/g;
|
|
5
5
|
const BETIK = /<(script|style)\b(?:[^>"']|"[^"]*"|'[^']*')*>[\s\S]*?<\/\1>/gi;
|
|
6
|
+
/** Sayısal karakter başvurusu; geçersiz kod noktası (ör. `�`) hata atmaz, olduğu gibi kalır. */
|
|
7
|
+
const kodNoktasi = (n, ham) => Number.isInteger(n) && n >= 0 && n <= 0x10ffff ? String.fromCodePoint(n) : ham;
|
|
6
8
|
/** HTML parçasını düz metne çevirir. */
|
|
7
9
|
export function metin(html) {
|
|
8
10
|
return html
|
|
9
11
|
.replace(BETIK, "")
|
|
10
12
|
.replace(/<br\s*\/?>/gi, " ")
|
|
11
13
|
.replace(ETIKET, " ")
|
|
12
|
-
.replace(/&#(\d+);/g, (
|
|
13
|
-
.replace(/&#x([0-9a-f]+);/gi, (
|
|
14
|
+
.replace(/&#(\d+);/g, (m, n) => kodNoktasi(Number(n), m))
|
|
15
|
+
.replace(/&#x([0-9a-f]+);/gi, (m, n) => kodNoktasi(Number.parseInt(n, 16), m))
|
|
14
16
|
.replace(/&([a-z]+);/gi, (m, a) => VARLIKLAR[a.toLowerCase()] ?? m)
|
|
15
17
|
.replace(/\s+/g, " ")
|
|
16
18
|
.trim();
|