@akredit/acik-mcp 0.6.0 → 0.8.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.
- 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 +493 -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/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
|
@@ -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();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
// Bologna ders sayfası taslağı denetimi (
|
|
1
|
+
// Bologna ders sayfası taslağı denetimi (K2-K10, K12 ve diğer kurallar). K1 (ders adıyla tutarlılık, başka
|
|
2
|
+
// dersten kopya) ve K11 (başka dersin yöntem metniyle aynılık) tek taslaktan denetlenemez; burada yoktur.
|
|
2
3
|
// apps/cli/lib/bologna-taslak.mjs `taslakDenetle` işlevinin saf, tipli taşıması. Mesajlar aynen korunur:
|
|
3
4
|
// CLI'deki "K8: metin" dizesi burada { kural: "K8", aciklama: "metin" } olur.
|
|
4
5
|
//
|
|
@@ -22,6 +23,11 @@ const kelime = (s) => String(s ?? "")
|
|
|
22
23
|
const bos = (s) => /^\s*(-|\.|yok|)\s*$/i.test(String(s ?? ""));
|
|
23
24
|
// ASCII'ye düşürülmüş Türkçe kelimeler (talimat bölüm 6). CLI ile aynı ifade.
|
|
24
25
|
const ASCII_TURKCE = /\b(icin|haftalik|ogrenme|ogrenci|ciktilar[ıi]?|ciktisi|bilisim|kaynag[ıi]|devam[ıi]|uygulamali|notlar[ıi]n[ıi]|incelenmesi|gelistirme|yazilim|programlamanin|tasarim[ıi]?|olusturma|degerlendirme|sinav[ıi]?|calisma|donem|guvenlik|baglant[ıi])\b/i;
|
|
26
|
+
// "guncel" set: aynı kelime listesi, Türkçe harfleri de kelime harfi sayan sınırlarla. CLI ifadesindeki `\b`
|
|
27
|
+
// ASCII dışı harfi kelime sınırı sayar; bu yüzden doğru yazılmış "devamını", "notlarının" kelimelerinin içinde
|
|
28
|
+
// "devamı", "notlarını" eşleşir ve hoca yanlış yere hata alır. Burada "ı" ile yazılan doğru biçimler ve zaten
|
|
29
|
+
// doğru yazılmış olan "incelenmesi" aranmaz.
|
|
30
|
+
const ASCII_TURKCE_GUNCEL = /(?<![\p{L}\p{N}_])(icin|haftalik|ogrenme|ogrenci|ciktilar[ıi]?|ciktisi|bilisim|kaynag[ıi]|devami|uygulamali|notlarini|gelistirme|yazilim|programlamanin|tasarim[ıi]?|olusturma|degerlendirme|sinav[ıi]?|calisma|donem|guvenlik|baglant[ıi])(?![\p{L}\p{N}_])/giu;
|
|
25
31
|
// Ölçülemeyen çıktı kalıpları (K4). "gösterebilir", "açıklayabilir" geçerlidir.
|
|
26
32
|
const OLCULEMEZ = /(bilgi sahibi olur|hakkında bilgi|fikir sahibi olur|(^|\s)(öğrenir|kavrar|anlar|bilir))\.?\s*$/i;
|
|
27
33
|
const ZAYIF = /farkındalık/i;
|
|
@@ -213,7 +219,7 @@ export function taslakDenetle(t, secenek = {}) {
|
|
|
213
219
|
...cik.map((c) => c.tr),
|
|
214
220
|
...haftalar.flatMap((h) => [h.konu?.tr, h.onHazirlik, h.dokuman]),
|
|
215
221
|
].filter(Boolean);
|
|
216
|
-
const tumu = new RegExp(ASCII_TURKCE, "gi");
|
|
222
|
+
const tumu = guncel ? ASCII_TURKCE_GUNCEL : new RegExp(ASCII_TURKCE, "gi");
|
|
217
223
|
const ascii = [...new Set(trMetinler.flatMap((m) => [...String(m).matchAll(tumu)].map((x) => x[0])))];
|
|
218
224
|
if (ascii.length)
|
|
219
225
|
hata("Türkçe", `Türkçe karakteri düşürülmüş kelimeler: ${ascii.slice(0, 10).join(", ")}.`);
|
|
@@ -50,8 +50,8 @@ export declare function sureliOnayUygunMu(s: KatmanSonucu): boolean;
|
|
|
50
50
|
/** Toplu onay yalnız katman 2 dışındaki önerilerde olur. */
|
|
51
51
|
export declare function topluOnayaUygunMu(s: KatmanSonucu): boolean;
|
|
52
52
|
/**
|
|
53
|
-
* Katman 2 bir kararın kabul edilebilirliği: politika ya da süre dayanağı
|
|
54
|
-
* kişi
|
|
53
|
+
* Katman 2 bir kararın kabul edilebilirliği: politika ya da süre dayanağı ve toplu onay reddedilir.
|
|
54
|
+
* Her katmanda kararı veren kişi yazılmalıdır. Kartta geçen süre burada denetlenmez.
|
|
55
55
|
*/
|
|
56
56
|
export declare function zorunluKararDenetle(s: KatmanSonucu, karar: {
|
|
57
57
|
dayanak: "dogrudan" | "politika" | "sure";
|
|
@@ -59,8 +59,8 @@ export function topluOnayaUygunMu(s) {
|
|
|
59
59
|
return !s.devredilemez;
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
62
|
-
* Katman 2 bir kararın kabul edilebilirliği: politika ya da süre dayanağı
|
|
63
|
-
* kişi
|
|
62
|
+
* Katman 2 bir kararın kabul edilebilirliği: politika ya da süre dayanağı ve toplu onay reddedilir.
|
|
63
|
+
* Her katmanda kararı veren kişi yazılmalıdır. Kartta geçen süre burada denetlenmez.
|
|
64
64
|
*/
|
|
65
65
|
export function zorunluKararDenetle(s, karar) {
|
|
66
66
|
const hatalar = [];
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
/** Türkçe kurallarıyla küçük harfe çevirir: "İ" → "i", "I" → "ı". */
|
|
2
2
|
export declare function kucukHarf(metin: string): string;
|
|
3
|
-
/** Türkçe kurallarıyla büyük harfe çevirir: "i" → "İ", "ı" → "I". */
|
|
4
|
-
export declare function buyukHarf(metin: string): string;
|
|
5
3
|
/**
|
|
6
4
|
* Karşılaştırma için normalleştirir: Unicode NFC, Türkçe küçük harf, tipografik tırnak ve tireler,
|
|
7
5
|
* yumuşak tire, satır sonunda bölünmüş kelimeler ve boşluklar. Anlamı değiştirmez, harf düşürmez.
|
|
@@ -9,10 +9,6 @@ const SATIR_SONU_BOLME = /(\p{Ll})-\s*\n\s*(\p{Ll})/gu;
|
|
|
9
9
|
export function kucukHarf(metin) {
|
|
10
10
|
return metin.toLocaleLowerCase("tr-TR");
|
|
11
11
|
}
|
|
12
|
-
/** Türkçe kurallarıyla büyük harfe çevirir: "i" → "İ", "ı" → "I". */
|
|
13
|
-
export function buyukHarf(metin) {
|
|
14
|
-
return metin.toLocaleUpperCase("tr-TR");
|
|
15
|
-
}
|
|
16
12
|
/**
|
|
17
13
|
* Karşılaştırma için normalleştirir: Unicode NFC, Türkçe küçük harf, tipografik tırnak ve tireler,
|
|
18
14
|
* yumuşak tire, satır sonunda bölünmüş kelimeler ve boşluklar. Anlamı değiştirmez, harf düşürmez.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// Ölçme girdisinin tutarlılık denetimi (kurucu kararı 12.11.2026, review.md madde 2). dersiOlc bozuk girdiyi
|
|
2
|
+
// sessizce hesaplıyordu: tam puanı aşan puan %100'ün üstünde başarı, yinelenen satırda sonuncunun kazanması,
|
|
3
|
+
// bilinmeyen araç/soruya yazılan puanın atılıp öğrencinin 0 sayılması, aynı ÇK'nın PÇ'ye iki kez girmesi.
|
|
4
|
+
// Bu işlev hesaptan önce çağrılır; sorun varsa hesap yapılmaz, hocaya ne olduğunu ve ne yapılacağını söyler.
|
|
5
|
+
// Saf: IO yok. dersiOlc'nin kendisi değişmez (HESAP_SURUMU aynı kalır).
|
|
6
|
+
const EN_COK = 10;
|
|
7
|
+
/** Hesabı bozacak girdi sorunları; boş dizi ise girdi tutarlıdır. İletiler Türkçe ve kullanıcıya gösterilebilir. */
|
|
8
|
+
export function olcmeGirdiSorunlari(v) {
|
|
9
|
+
const sorunlar = [];
|
|
10
|
+
const ekle = (s) => sorunlar.push(s);
|
|
11
|
+
const ckSay = new Map();
|
|
12
|
+
for (const c of v.ciktilar)
|
|
13
|
+
ckSay.set(c.kod, (ckSay.get(c.kod) ?? 0) + 1);
|
|
14
|
+
for (const [kod, n] of ckSay)
|
|
15
|
+
if (n > 1)
|
|
16
|
+
ekle(`Ders çıktısı ${kod} ${n} kez yazılmış. Her çıktıyı bir kez yazın.`);
|
|
17
|
+
const araclar = new Map();
|
|
18
|
+
for (const a of v.araclar) {
|
|
19
|
+
if (araclar.has(a.id))
|
|
20
|
+
ekle(`Ölçme aracı ${a.id} birden çok kez yazılmış. Her aracı bir kez yazın.`);
|
|
21
|
+
const sorular = new Map();
|
|
22
|
+
for (const q of a.sorular) {
|
|
23
|
+
if (sorular.has(q.no))
|
|
24
|
+
ekle(`${a.id} içinde ${q.no}. soru birden çok kez yazılmış.`);
|
|
25
|
+
sorular.set(q.no, q.tamPuan);
|
|
26
|
+
for (const e of q.eslemeler)
|
|
27
|
+
if (!ckSay.has(e.ciktiKod))
|
|
28
|
+
ekle(`${a.id} ${q.no}. soru, listede olmayan ${e.ciktiKod} çıktısına eşlenmiş. Çıktıyı ekleyin ya da eşlemeyi düzeltin.`);
|
|
29
|
+
}
|
|
30
|
+
araclar.set(a.id, sorular);
|
|
31
|
+
}
|
|
32
|
+
const gorulen = new Set();
|
|
33
|
+
for (const p of v.puanlar) {
|
|
34
|
+
const sorular = araclar.get(p.aracId);
|
|
35
|
+
if (!sorular) {
|
|
36
|
+
ekle(`${p.ogrenci} için tanımsız ${p.aracId} aracına puan yazılmış. Aracı ekleyin ya da satırı silin.`);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const tam = sorular.get(p.soruNo);
|
|
40
|
+
// Sorusuz araçta (toplam puan) soru numarası denetlenmez.
|
|
41
|
+
if (sorular.size > 0 && tam === undefined) {
|
|
42
|
+
ekle(`${p.ogrenci} için ${p.aracId} aracında olmayan ${p.soruNo}. soruya puan yazılmış.`);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const anahtar = `${p.ogrenci}\u0000${p.aracId}\u0000${p.soruNo}`;
|
|
46
|
+
if (gorulen.has(anahtar))
|
|
47
|
+
ekle(`${p.ogrenci} için ${p.aracId} ${p.soruNo}. soru puanı birden çok kez yazılmış.`);
|
|
48
|
+
gorulen.add(anahtar);
|
|
49
|
+
if (p.puan !== null && tam !== undefined && p.puan > tam)
|
|
50
|
+
ekle(`${p.ogrenci} için ${p.aracId} ${p.soruNo}. soru puanı (${p.puan}) tam puanı (${tam}) aşıyor.`);
|
|
51
|
+
}
|
|
52
|
+
return sorunlar.length > EN_COK
|
|
53
|
+
? [...sorunlar.slice(0, EN_COK), `ve ${sorunlar.length - EN_COK} sorun daha.`]
|
|
54
|
+
: sorunlar;
|
|
55
|
+
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// Kapsam ve kabul ölçütleri: plan/ip/IP-06-olcme-motoru.md · Yöntem: docs/olcme-yontemi.md
|
|
3
3
|
export const PAKET = "./index.js";
|
|
4
4
|
export { dersiOlc, ORNEK_HARF_TABLOSU } from "./ders.js";
|
|
5
|
+
export { olcmeGirdiSorunlari } from "./girdi.js";
|
|
5
6
|
export * from "./istatistik.js";
|
|
6
7
|
export * from "./kok-neden.js";
|
|
7
8
|
export * from "./program.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akredit/acik-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"description": "Herkese açık Akredit MCP sunucusu: hesapsız, salt okuma, deterministik araçlar (ölçüt, Bologna denetimi, ÇK/PÇ hesabı, rapor dil denetimi). Kurum verisine erişmez, model çağırmaz.",
|
|
@@ -13,6 +13,12 @@
|
|
|
13
13
|
"akts"
|
|
14
14
|
],
|
|
15
15
|
"homepage": "https://akredit.org/mcp-kullan",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/tialkan/akredit.git",
|
|
19
|
+
"directory": "apps/acik-mcp"
|
|
20
|
+
},
|
|
21
|
+
"bugs": "https://github.com/tialkan/akredit/issues",
|
|
16
22
|
"engines": {
|
|
17
23
|
"node": ">=22.18"
|
|
18
24
|
},
|
|
@@ -38,8 +44,8 @@
|
|
|
38
44
|
"@akredit/baglayicilar": "0.1.0",
|
|
39
45
|
"@akredit/cekirdek": "0.1.0",
|
|
40
46
|
"@akredit/olcme": "0.1.0",
|
|
41
|
-
"@akredit/
|
|
42
|
-
"@akredit/
|
|
47
|
+
"@akredit/cerceveler": "0.1.0",
|
|
48
|
+
"@akredit/yz": "0.1.0"
|
|
43
49
|
},
|
|
44
50
|
"publishConfig": {
|
|
45
51
|
"access": "public"
|