@appaflytech/zeyrek-ai-mcp 0.0.43 → 0.0.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/knowledge/backendConstraints.js +86 -2
- package/dist/knowledge/componentCatalog.js +63 -26
- package/dist/knowledge/componentEvents.js +6 -0
- package/dist/knowledge/connectDataBind.js +43 -6
- package/dist/knowledge/connectDataDefinition.js +74 -3
- package/dist/knowledge/connectDataRules.js +14 -0
- package/dist/knowledge/mobileComponentCatalog.js +66 -7
- package/dist/knowledge/mobileStore.js +61 -2
- package/dist/knowledge/platform/mobile.js +1 -1
- package/dist/knowledge/platform/mobileRules.js +2 -1
- package/dist/knowledge/platform/mobileTabs.js +31 -2
- package/dist/knowledge/platform/web.js +1 -1
- package/dist/knowledge/rules.js +195 -4
- package/dist/knowledge/textHooks.js +434 -0
- package/dist/platform/capture/capture.js +1 -1
- package/dist/platform/capture/readiness.js +4 -0
- package/dist/platform/errors.js +22 -2
- package/dist/prompts/mobilePublish.js +21 -0
- package/dist/resources/examples/flow-biometric-confirm.json +199 -0
- package/dist/resources/examples/microfunction-node-dependencies.json +19 -0
- package/dist/resources/guides/access.md +3 -3
- package/dist/resources/guides/component.md +20 -4
- package/dist/resources/guides/deployment.md +98 -0
- package/dist/resources/guides/entity.md +1 -1
- package/dist/resources/guides/expressions.md +5 -1
- package/dist/resources/guides/external-component.md +6 -4
- package/dist/resources/guides/merge.md +81 -4
- package/dist/resources/guides/microfunction.md +104 -9
- package/dist/resources/guides/microservice.md +34 -5
- package/dist/resources/guides/mobile-connect-data.md +70 -0
- package/dist/resources/guides/mobile-flow.md +64 -0
- package/dist/resources/guides/mobile-publish.md +161 -16
- package/dist/resources/guides/mobile-steps.md +17 -0
- package/dist/resources/guides/mobile.md +41 -23
- package/dist/resources/guides/page.md +11 -5
- package/dist/resources/guides/translation.md +95 -0
- package/dist/resources/knowledge.js +3 -1
- package/dist/resources/prompts/mobile-publish-prepare.md +89 -0
- package/dist/resources/schema-fingerprint.json +4 -4
- package/dist/resources/schemas/ApplyMicrofunctionArchiveChangesCommand.json +76 -0
- package/dist/resources/schemas/ConnectDataDescribeDto.json +44 -0
- package/dist/resources/schemas/ConnectDataResultDto.json +10 -0
- package/dist/resources/schemas/CreateMicrofunctionCommand.json +8 -0
- package/dist/resources/schemas/InvokeMicrofunctionCommand.json +0 -4
- package/dist/resources/schemas/MobileStorePreflightScope.json +13 -0
- package/dist/resources/schemas/StartMobileBuildCommand.json +35 -1
- package/dist/resources/schemas/UpdateMicrofunctionCommand.json +8 -0
- package/dist/resources/schemas/UpsertMobileStoreSettingsCommand.json +75 -0
- package/dist/server.js +2 -0
- package/dist/tools/common.js +6 -0
- package/dist/tools/components.js +19 -6
- package/dist/tools/connectData.js +9 -4
- package/dist/tools/deployments.js +1 -1
- package/dist/tools/designSchemaPatch.js +16 -4
- package/dist/tools/environments.js +3 -3
- package/dist/tools/files.js +1 -1
- package/dist/tools/flows.js +29 -3
- package/dist/tools/layouts.js +32 -12
- package/dist/tools/merges.js +8 -8
- package/dist/tools/microfunctions.js +53 -3
- package/dist/tools/mobileStore.js +83 -21
- package/dist/tools/pages.js +59 -24
- package/dist/tools/platformInfo.js +4 -2
- package/dist/tools/textHookGuard.js +116 -0
- package/package.json +2 -2
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { applyPolicyMode, enforcePolicy } from '../knowledge/policy.js';
|
|
3
|
+
import { readProjectLanguages } from '../knowledge/languages.js';
|
|
4
|
+
import { logStep } from '../observability/trace.js';
|
|
5
|
+
import { addedHooks, addedWords, comparedWordsIn, displayTextsIn, textHooksIn } from '../knowledge/textHooks.js';
|
|
6
|
+
/**
|
|
7
|
+
* Sayfa / layout / widget yazan araçların kaçış girdisi. Ad bilerek akış araçlarınınkiyle aynı: PolicyBlockError
|
|
8
|
+
* "aynı çağrıyı policyOverride: true ile tekrarlayın" der ve o alan bu araçlarda da var olmalı (S-12 dersi).
|
|
9
|
+
*/
|
|
10
|
+
export const textHookOverrideParam = z.boolean().optional().describe("true: görünen metne bağlı mantık (metin kancası, TR-005) bilinçli istisna olarak yazılır — yalnız sunucu metin döndürüyor ve karşılaştırılacak kod yoksa. Bulgu yanıtta uyarı olarak kalır. Varsayılan false: bu yazımla gelen kanca isteği durdurur");
|
|
11
|
+
const GUIDE = 'ngapps://guides/translation';
|
|
12
|
+
const DICTIONARY_TTL_MS = 5 * 60 * 1000;
|
|
13
|
+
const FAILED_DICTIONARY_TTL_MS = 30 * 1000;
|
|
14
|
+
const LISTED = 5;
|
|
15
|
+
// Her akış / şema yazımında sözlüğü okumamak için: qm sözlüğü ≈ 7.700 satır (2026-10-15). Okuma düşerse boş
|
|
16
|
+
// sonuç da önbelleğe girer — kapı yalnız sayfa yazılarıyla karar verir, platformu dövmez.
|
|
17
|
+
const dictionaryCache = new Map();
|
|
18
|
+
/** Testler birbirinin önbelleğini görmesin diye. */
|
|
19
|
+
export function clearTextHookDictionaryCache() {
|
|
20
|
+
dictionaryCache.clear();
|
|
21
|
+
}
|
|
22
|
+
async function defaultLanguageTexts(platform, project, environment, applicationId) {
|
|
23
|
+
const key = `${platform.resolveProject(project)}|${environment ?? ''}|${applicationId.toLowerCase()}`;
|
|
24
|
+
const cached = dictionaryCache.get(key);
|
|
25
|
+
if (cached && Date.now() - cached.at < cached.ttl)
|
|
26
|
+
return cached.values;
|
|
27
|
+
const values = new Map();
|
|
28
|
+
let ttl = DICTIONARY_TTL_MS;
|
|
29
|
+
try {
|
|
30
|
+
const language = readProjectLanguages(await platform.org('GET', `/p/${platform.resolveProject(project)}`))?.defaultLanguage;
|
|
31
|
+
if (language) {
|
|
32
|
+
const listed = await platform.tenant('GET', project, `/translations/${applicationId}`, { environment });
|
|
33
|
+
for (const row of listed?.data ?? []) {
|
|
34
|
+
const text = (row.value ?? '').trim();
|
|
35
|
+
if (row.language === language && text !== '' && row.key && !values.has(text))
|
|
36
|
+
values.set(text, row.key);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
// Sözlük okunamadı: TR-006 ve belirsiz kanca yalnız barındırıcının yazılarına bakar; kısa süre sonra yeniden denenir.
|
|
42
|
+
ttl = FAILED_DICTIONARY_TTL_MS;
|
|
43
|
+
logStep('metin kancası', `sözlük okunamadı (${key}) — yalnız sayfa yazıları kullanıldı`, [error instanceof Error ? error.message : String(error)]);
|
|
44
|
+
}
|
|
45
|
+
dictionaryCache.set(key, { at: Date.now(), ttl, values });
|
|
46
|
+
return values;
|
|
47
|
+
}
|
|
48
|
+
function listed(hooks) {
|
|
49
|
+
const shown = hooks.slice(0, LISTED).map(hook => `'${hook.text}' ← ${hook.excerpt}`).join(' · ');
|
|
50
|
+
return hooks.length > LISTED ? `${shown} · ve ${hooks.length - LISTED} tane daha` : shown;
|
|
51
|
+
}
|
|
52
|
+
const RIGHT_WAY = "Kararı yazıya değil değişmeyen bir değere bağlayın: kayıttaki kod (status === 'Approved'), state ya da değişken, Page.queryParams, element kimliği ya da sekme key'i, sınıf ya da data-* özniteliği. Renk eşlemesinde (colorMap) value koda, görünen yazı label'a (çeviri sarmalı) gider; yazıyı t('anahtar') ile ayrıca basın.";
|
|
53
|
+
/**
|
|
54
|
+
* TR-005: görünen metne bağlı mantık — bu yazımla gelen `block`, kayıtta duran `warn` (karar D1, kullanıcı 2026-10-16).
|
|
55
|
+
* TR-006: biçimden ayırt edilemeyen tek kelime / ASCII boşluklu metin sözlükte (varsayılan dil) ya da sayfa yazısında
|
|
56
|
+
* geçiyorsa — tek kelime `warn` (karar D2), boşluklu metin kesin sayılıp TR-005 olur.
|
|
57
|
+
*/
|
|
58
|
+
export async function textHookFindings(scope) {
|
|
59
|
+
const afterHooks = textHooksIn(scope.after);
|
|
60
|
+
const afterWords = comparedWordsIn(scope.after);
|
|
61
|
+
if (afterHooks.length === 0 && afterWords.length === 0)
|
|
62
|
+
return [];
|
|
63
|
+
let beforeUnreadable = false;
|
|
64
|
+
const before = scope.before
|
|
65
|
+
? await scope.before().catch(() => {
|
|
66
|
+
beforeUnreadable = true;
|
|
67
|
+
return undefined;
|
|
68
|
+
})
|
|
69
|
+
: undefined;
|
|
70
|
+
const added = addedHooks(textHooksIn(before ?? []), afterHooks);
|
|
71
|
+
const kept = addedHooks(added, afterHooks);
|
|
72
|
+
const words = [...new Set(addedWords(comparedWordsIn(before ?? []), afterWords))];
|
|
73
|
+
const needsTexts = words.length > 0 || [...added, ...kept].some(hook => !hook.certain);
|
|
74
|
+
const pageTexts = needsTexts ? displayTextsIn([scope.hostTree ? await scope.hostTree().catch(() => undefined) : undefined, scope.after]) : new Set();
|
|
75
|
+
const dictionary = needsTexts ? await defaultLanguageTexts(scope.platform, scope.project, scope.environment, scope.applicationId) : new Map();
|
|
76
|
+
const knownAs = (text) => dictionary.has(text) ? `sözlükte ${dictionary.get(text)}` : pageTexts.has(text) ? 'sayfadaki yazı' : undefined;
|
|
77
|
+
const isHook = (hook) => hook.certain || knownAs(hook.text) !== undefined;
|
|
78
|
+
const newHooks = added.filter(isHook);
|
|
79
|
+
const oldHooks = kept.filter(isHook);
|
|
80
|
+
const wordHits = words.flatMap(word => {
|
|
81
|
+
const known = knownAs(word);
|
|
82
|
+
return known ? [`'${word}' (${known})`] : [];
|
|
83
|
+
});
|
|
84
|
+
const findings = [];
|
|
85
|
+
if (newHooks.length > 0) {
|
|
86
|
+
findings.push({
|
|
87
|
+
ruleId: 'TR-005',
|
|
88
|
+
severity: 'block',
|
|
89
|
+
message: `${scope.where}: görünen metne bağlı mantık yazılamaz (metin kancası) — ${listed(newHooks)}.${beforeUnreadable ? ' (Kayıtlı hâl okunamadı: kancaların hepsi yeni sayıldı.)' : ''} Ekrandaki yazı dile, çeviriye ve tasarımcının düzeltmesine göre değişir; değişince karşılaştırma sessizce tutmaz (qm'de İngilizceye geçince ev ikonu kayboldu, onay düğmeleri görünür oldu). ${RIGHT_WAY} Sunucu yalnız metin döndürüyor ve kod yoksa bilinçli istisnadır.`,
|
|
90
|
+
guide: GUIDE
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
if (oldHooks.length > 0) {
|
|
94
|
+
findings.push({
|
|
95
|
+
ruleId: 'TR-005',
|
|
96
|
+
severity: 'warn',
|
|
97
|
+
message: `${scope.where}: kayıtta önceden duran metin kancası (bu yazım eklemedi) — ${listed(oldHooks)}. Dokunduğunuz yerdeyse aynı değişiklikte koda çevirin; bu metni çevirmeyin, karşılaştırma kırılır. ${RIGHT_WAY}`,
|
|
98
|
+
guide: GUIDE
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
if (wordHits.length > 0) {
|
|
102
|
+
findings.push({
|
|
103
|
+
ruleId: 'TR-006',
|
|
104
|
+
severity: 'warn',
|
|
105
|
+
message: `${scope.where}: karşılaştırılan tek kelime görünen bir yazıyla aynı — ${wordHits.slice(0, LISTED).join(' · ')}${wordHits.length > LISTED ? ` · ve ${wordHits.length - LISTED} tane daha` : ''}. Görünen yazıysa kararı koda bağlayın (TR-005 ile aynı yol); bir kod değeriyse (sunucu enum'u) bu uyarıyı yok sayın.`,
|
|
106
|
+
guide: GUIDE
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return findings;
|
|
110
|
+
}
|
|
111
|
+
/** Kapı: POLICY=off'ta susar, `policyOverride` block'u warn'a indirir, kalan block isteği platforma gitmeden durdurur. */
|
|
112
|
+
export async function enforceTextHooks(config, scope, policyOverride) {
|
|
113
|
+
if (config.policyMode === 'off')
|
|
114
|
+
return [];
|
|
115
|
+
return enforcePolicy(applyPolicyMode(config, await textHookFindings(scope), policyOverride === true));
|
|
116
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@appaflytech/zeyrek-ai-mcp",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.45",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Zeyrek (NgApps) platform APIs as MCP tools — data, logic and Studio design surface in one gateway",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -60,4 +60,4 @@
|
|
|
60
60
|
"typescript": "^5.7.2",
|
|
61
61
|
"vitest": "^3.0.0"
|
|
62
62
|
}
|
|
63
|
-
}
|
|
63
|
+
}
|