@appaflytech/zeyrek-ai-mcp 0.0.5 → 0.0.7
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/.env.example +2 -2
- package/.env.production.example +9 -1
- package/README.md +14 -38
- package/dist/config.js +36 -3
- package/dist/knowledge/backendConstraints.js +982 -0
- package/dist/knowledge/componentCatalog.js +549 -92
- package/dist/knowledge/componentEvents.js +120 -25
- package/dist/knowledge/coverage.js +43 -0
- package/dist/knowledge/flowGuards.js +30 -0
- package/dist/knowledge/functionGuards.js +134 -0
- package/dist/knowledge/guideSections.js +49 -0
- package/dist/knowledge/hydrate.js +97 -0
- package/dist/knowledge/languageCodes.js +36 -0
- package/dist/knowledge/languages.js +105 -0
- package/dist/knowledge/layoutSummary.js +10 -0
- package/dist/knowledge/localization.js +51 -0
- package/dist/knowledge/normalize.js +500 -16
- package/dist/knowledge/outlines.js +167 -12
- package/dist/knowledge/policy.js +14 -5
- package/dist/knowledge/propTypes.js +80 -0
- package/dist/knowledge/rules.js +961 -44
- package/dist/knowledge/schemaGuard.js +199 -0
- package/dist/knowledge/styleResolve.js +63 -4
- package/dist/observability/trace.js +27 -3
- package/dist/platform/csv.js +123 -0
- package/dist/platform/errors.js +107 -6
- package/dist/platform/http.js +34 -4
- package/dist/platform/patch.js +27 -0
- package/dist/platform/refs.js +104 -0
- package/dist/platform/responses.js +25 -6
- package/dist/platform/screenshot.js +544 -16
- package/dist/platform/secrets.js +40 -0
- package/dist/platform/tokenVault.js +89 -0
- package/dist/platform/writeDiff.js +281 -0
- package/dist/resources/examples/flow-call-function.json +66 -0
- package/dist/resources/examples/function-total.json +70 -0
- package/dist/resources/examples/layout-app-shell.json +1 -1
- package/dist/resources/examples/microfunction-node-sum.json +56 -0
- package/dist/resources/examples/microservice-table-list.json +2 -4
- package/dist/resources/examples/page-dynamic-form.json +3 -3
- package/dist/resources/examples/page-flex-sections.json +99 -0
- package/dist/resources/examples/page-sign-in.json +4 -3
- package/dist/resources/guides/component.md +81 -8
- package/dist/resources/guides/entity.md +712 -20
- package/dist/resources/guides/expressions.md +47 -2
- package/dist/resources/guides/external-component.md +9 -0
- package/dist/resources/guides/functions.md +262 -0
- package/dist/resources/guides/getting-started.md +82 -7
- package/dist/resources/guides/layout.md +53 -10
- package/dist/resources/guides/merge.md +231 -0
- package/dist/resources/guides/microfunction.md +166 -0
- package/dist/resources/guides/microservice.md +287 -15
- package/dist/resources/guides/middleware.md +89 -1
- package/dist/resources/guides/modify-existing.md +23 -0
- package/dist/resources/guides/page.md +402 -49
- package/dist/resources/guides/translation.md +150 -8
- package/dist/resources/guides/view.md +16 -1
- package/dist/resources/guides/workflow.md +199 -28
- package/dist/resources/knowledge.js +5 -0
- package/dist/resources/rules.js +27 -0
- package/dist/resources/schema-fingerprint.json +8 -0
- package/dist/resources/schemas/AnalyzeImportQuery.json +51 -0
- package/dist/resources/schemas/ApplyMergePlanCommand.json +19 -0
- package/dist/resources/schemas/CreateBulkRowCommand.json +36 -0
- package/dist/resources/schemas/CreateDatasourceCommand.json +15 -6
- package/dist/resources/schemas/CreateDiscoveredEntitiesCommand.json +19 -8
- package/dist/resources/schemas/CreateEntityCommand.json +52 -12
- package/dist/resources/schemas/CreateEnvironmentCommand.json +31 -0
- package/dist/resources/schemas/CreateGlobalFunctionCommand.json +95 -0
- package/dist/resources/schemas/CreateImportPlanCommand.json +278 -0
- package/dist/resources/schemas/CreateMergePlanCommand.json +34 -0
- package/dist/resources/schemas/CreateMicrofunctionCommand.json +117 -0
- package/dist/resources/schemas/CreateMicrofunctionRuntimeCommand.json +51 -0
- package/dist/resources/schemas/CreateMicroserviceCommand.json +145 -3
- package/dist/resources/schemas/CreateQueryCommand.json +56 -3
- package/dist/resources/schemas/CreateRowCommand.json +38 -0
- package/dist/resources/schemas/CreateViewCommand.json +13 -10
- package/dist/resources/schemas/CreateWorkflowCommand.json +106 -14
- package/dist/resources/schemas/DataJobDto.json +267 -0
- package/dist/resources/schemas/ExportRowsCommand.json +172 -0
- package/dist/resources/schemas/Filter.json +3 -1
- package/dist/resources/schemas/GetRowsQuery.json +6 -1
- package/dist/resources/schemas/GlobalFunctionDto.json +89 -0
- package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +249 -0
- package/dist/resources/schemas/ImportAnalysisDto.json +401 -0
- package/dist/resources/schemas/ImportPlanDto.json +260 -0
- package/dist/resources/schemas/ImportSampleDto.json +90 -0
- package/dist/resources/schemas/InvokeMicrofunctionCommand.json +25 -0
- package/dist/resources/schemas/PreviewMicroserviceCommand.json +135 -1
- package/dist/resources/schemas/PreviewQueryCommand.json +5 -2
- package/dist/resources/schemas/PreviewWorkflowCommand.json +45 -9
- package/dist/resources/schemas/ResolveMergeConflictsCommand.json +58 -0
- package/dist/resources/schemas/RevertMergePlanCommand.json +19 -0
- package/dist/resources/schemas/RunImportCommand.json +62 -0
- package/dist/resources/schemas/StepDto.json +34 -3
- package/dist/resources/schemas/UpdateBulkRowCommand.json +36 -0
- package/dist/resources/schemas/UpdateDatasourceCommand.json +15 -6
- package/dist/resources/schemas/UpdateEntityCommand.json +52 -11
- package/dist/resources/schemas/UpdateGlobalFunctionCommand.json +66 -0
- package/dist/resources/schemas/UpdateMicrofunctionCommand.json +121 -0
- package/dist/resources/schemas/UpdateMicrofunctionRuntimeCommand.json +54 -0
- package/dist/resources/schemas/UpdateMicroserviceCommand.json +147 -4
- package/dist/resources/schemas/UpdateQueryCommand.json +13 -3
- package/dist/resources/schemas/UpdateRowCommand.json +40 -0
- package/dist/resources/schemas/UpdateViewCommand.json +15 -10
- package/dist/resources/schemas/UpdateWorkflowCommand.json +106 -14
- package/dist/server.js +17 -1
- package/dist/tools/access.js +3 -3
- package/dist/tools/activities.js +40 -0
- package/dist/tools/applications.js +1 -1
- package/dist/tools/automations.js +76 -34
- package/dist/tools/common.js +55 -0
- package/dist/tools/components.js +16 -7
- package/dist/tools/datasources.js +83 -21
- package/dist/tools/dependencies.js +1 -1
- package/dist/tools/deployments.js +34 -2
- package/dist/tools/dtos.js +25 -12
- package/dist/tools/entities.js +113 -28
- package/dist/tools/environments.js +52 -0
- package/dist/tools/externalComponents.js +9 -3
- package/dist/tools/files.js +57 -42
- package/dist/tools/flows.js +205 -13
- package/dist/tools/folders.js +7 -2
- package/dist/tools/functions.js +331 -0
- package/dist/tools/globalFunctions.js +63 -0
- package/dist/tools/importSchemas.js +79 -0
- package/dist/tools/imports.js +241 -0
- package/dist/tools/layouts.js +103 -29
- package/dist/tools/merges.js +113 -0
- package/dist/tools/microfunctions.js +155 -0
- package/dist/tools/microservices.js +270 -40
- package/dist/tools/organizations.js +5 -6
- package/dist/tools/pages.js +421 -104
- package/dist/tools/platformInfo.js +155 -11
- package/dist/tools/projects.js +183 -33
- package/dist/tools/queries.js +32 -10
- package/dist/tools/revisions.js +94 -0
- package/dist/tools/rows.js +484 -50
- package/dist/tools/screenWrite.js +68 -0
- package/dist/tools/screens.js +28 -0
- package/dist/tools/templates.js +32 -5
- package/dist/tools/translations.js +24 -8
- package/dist/tools/views.js +20 -10
- package/dist/tools/workflows.js +56 -21
- package/package.json +7 -2
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { invalidScreenEventNames, invalidWidgetTypeNodes, nestedRepeaterNodes, nestedRepeaterMessage, blockSizeNote, heightTypeNote, sizeStringNote } from '../knowledge/normalize.js';
|
|
2
|
+
import { FUNCTIONS_NAMESPACE } from '../knowledge/functionGuards.js';
|
|
3
|
+
import { applyCatalogLayoutRules } from './components.js';
|
|
4
|
+
import { PlatformApiError } from '../platform/errors.js';
|
|
5
|
+
const GUARD_CODES = {
|
|
6
|
+
page: { events: 'PAGE-011', widgets: 'PAGE-012', noun: 'sayfa', tree: 'schema' },
|
|
7
|
+
layout: { events: 'LAY-004', widgets: 'LAY-005', noun: 'layout', tree: 'views' }
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* JS tanımlayıcısı olmayan ya da AYRILMIŞ `name` alanlarını toplar; ad
|
|
11
|
+
* `const <ad> = Components["<ad>"]` üretimine girer.
|
|
12
|
+
*/
|
|
13
|
+
export function invalidComponentNames(nodes) {
|
|
14
|
+
const found = [];
|
|
15
|
+
for (const node of nodes ?? []) {
|
|
16
|
+
const name = node.name;
|
|
17
|
+
if (typeof name === 'string' && name.length > 0 && !/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name.replace(/-/g, ''))) {
|
|
18
|
+
found.push(`'${name}' (${node.elementId ?? '?'})`);
|
|
19
|
+
}
|
|
20
|
+
else if (typeof name === 'string' && name.replace(/-/g, '') === FUNCTIONS_NAMESPACE) {
|
|
21
|
+
// K1: preamble her komponent için `const <ad> = Components["<ad>"]` üretir; `Functions` adlı
|
|
22
|
+
// komponent kullanıcı fonksiyonlarının ad alanını ezer ve sayfadaki her Functions.x() ölür.
|
|
23
|
+
found.push(`'${name}' (${node.elementId ?? '?'}) — ayrılmış ad: ${FUNCTIONS_NAMESPACE} kullanıcı fonksiyonlarının ad alanıdır (K1)`);
|
|
24
|
+
}
|
|
25
|
+
found.push(...invalidComponentNames(node.children));
|
|
26
|
+
}
|
|
27
|
+
return found;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Sayfa ve layout yazma yollarının ORTAK kapısı: olay adı (PAGE-011 · LAY-004), widget düğümü
|
|
31
|
+
* (PAGE-012 · LAY-005), komponent adı (PAGE-009) ve iç içe repeater (PAGE-013) denetimleri —
|
|
32
|
+
* hepsi istek gitmeden 400.
|
|
33
|
+
*
|
|
34
|
+
* PAGE-009 ve PAGE-013'ün layout ayağı 2026-09-09'da eklendi: ikisi de yalnız sayfa yollarında
|
|
35
|
+
* koşuyordu, oysa layout `views`'ü aynı runtime'dan geçer — bozuk ad o layout'a bağlı HER
|
|
36
|
+
* sayfanın ifadelerini öldürür, iç içe repeater'ın geri yazma kırılması ise yapısaldır ve
|
|
37
|
+
* barındıranın sayfa mı layout mu olduğuna bakmaz.
|
|
38
|
+
*/
|
|
39
|
+
export function assertScreenWriteGuards(kind, screen) {
|
|
40
|
+
const codes = GUARD_CODES[kind];
|
|
41
|
+
const badEvents = invalidScreenEventNames(screen.events, codes.events);
|
|
42
|
+
if (badEvents.length > 0)
|
|
43
|
+
throw new PlatformApiError(`Geçersiz ${codes.noun} olayı (istek gönderilmedi): ${badEvents.join(' · ')}`, 400);
|
|
44
|
+
const badWidgets = invalidWidgetTypeNodes(screen.schema, codes.widgets);
|
|
45
|
+
if (badWidgets.length > 0)
|
|
46
|
+
throw new PlatformApiError(`Geçersiz widget düğümü (istek gönderilmedi): ${badWidgets.join(' · ')}`, 400);
|
|
47
|
+
const badNames = invalidComponentNames(screen.schema);
|
|
48
|
+
if (badNames.length > 0) {
|
|
49
|
+
throw new PlatformApiError(`PAGE-009 — komponent adı JS tanımlayıcısı değil ya da ayrılmış (istek gönderilmedi): ${badNames.join(' · ')}. `
|
|
50
|
+
+ 'Runtime her komponent için `const <ad> = Components["<ad>"]` üretir; boşluklu ya da geçersiz bir ad '
|
|
51
|
+
+ 'SAYFADAKİ TÜM ifadeleri "Missing initializer in const declaration" ile öldürür (layout adları her sayfaya sızar). '
|
|
52
|
+
+ `name alanını elementId ile aynı yaz; okunabilir Türkçe başlık için props.title / props.text / props.label kullan (${codes.noun} ${codes.tree}).`, 400);
|
|
53
|
+
}
|
|
54
|
+
const nested = nestedRepeaterNodes(screen.schema);
|
|
55
|
+
if (nested.length > 0)
|
|
56
|
+
throw new PlatformApiError(nestedRepeaterMessage(nested), 400);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Katalog kurallarını (blok sınırı · auto-height · boyut string'i) ağaca uygular ve
|
|
60
|
+
* `withNormalization` kuyruğuna giren üç notu döndürür. Boş/verilmemiş ağaçta katalog
|
|
61
|
+
* okunmaz — uygulanacak düğüm yoktur, notlar da boş çıkardı.
|
|
62
|
+
*/
|
|
63
|
+
export async function screenCatalogNotes(platform, project, environment, applicationId, nodes) {
|
|
64
|
+
if (!Array.isArray(nodes) || nodes.length === 0)
|
|
65
|
+
return [];
|
|
66
|
+
const catalog = await applyCatalogLayoutRules(platform, project, environment, applicationId, nodes);
|
|
67
|
+
return [...blockSizeNote(catalog.clamped), ...heightTypeNote(catalog.heights), ...sizeStringNote(catalog.sizes)];
|
|
68
|
+
}
|
package/dist/tools/screens.js
CHANGED
|
@@ -31,6 +31,33 @@ export function summarize(node, styleSource) {
|
|
|
31
31
|
}
|
|
32
32
|
return summary;
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Yazma yanıtındaki `appliedPatch` gövdesini iskelete indirger (B-55 · S-9).
|
|
36
|
+
*
|
|
37
|
+
* Alanın KANIT değeri path'indedir: "gerçekten yalnız o komponente mi dokunuldu" sorusunu
|
|
38
|
+
* JSON Pointer cevaplar (`page.md` Kural 2). `value` ise ajanın aynı turda KENDİ gönderdiği
|
|
39
|
+
* gövdenin yankısıdır — `add_component`'te eklenen alt ağacın tamamı, `replace_prop`'ta
|
|
40
|
+
* yazılan Prop'un tamamı (`AppliedJsonPatch(Op, Path, Value)`). 2026-09-06·2 koşusunda on
|
|
41
|
+
* dört yazma çağrısının yanıtı bağlamın en büyük tek kalemiydi.
|
|
42
|
+
*
|
|
43
|
+
* Kanıt kaybı yok: yamanın KAYDEDİLDİĞİNİ `appliedPatch` zaten söylemiyordu (G-23). Onu
|
|
44
|
+
* yamadan sonra okunan şemayla karşılaştıran `schemaOpDrops` söylüyor ve sonucu yanıtta
|
|
45
|
+
* `silentlyDropped` olarak duruyor. Tam gövde `view: 'full'` ile alınır.
|
|
46
|
+
*/
|
|
47
|
+
export function outlineAppliedPatch(applied) {
|
|
48
|
+
if (!Array.isArray(applied))
|
|
49
|
+
return applied;
|
|
50
|
+
return applied.map(entry => {
|
|
51
|
+
if (!entry || typeof entry !== 'object' || Array.isArray(entry))
|
|
52
|
+
return entry;
|
|
53
|
+
const record = entry;
|
|
54
|
+
const value = record.value;
|
|
55
|
+
const node = value && typeof value === 'object' && !Array.isArray(value) && typeof value.elementId === 'string'
|
|
56
|
+
? summarize(value)
|
|
57
|
+
: undefined;
|
|
58
|
+
return { op: record.op, path: record.path, ...(node ? { component: node } : {}) };
|
|
59
|
+
});
|
|
60
|
+
}
|
|
34
61
|
/** elementId ya da id ile ağaçta düğüm bulur. */
|
|
35
62
|
export function findNode(nodes, target) {
|
|
36
63
|
for (const node of nodes ?? []) {
|
|
@@ -77,6 +104,7 @@ export function pageUpdateBody(page, overrides = {}) {
|
|
|
77
104
|
name: page.name,
|
|
78
105
|
slug: page.slug,
|
|
79
106
|
browserTitle: page.browserTitle ?? '',
|
|
107
|
+
browserTitleKey: page.browserTitleKey ?? '',
|
|
80
108
|
schema: page.schema ?? [],
|
|
81
109
|
events: asArray(page.events).filter(event => event?.value),
|
|
82
110
|
middlewareIds: page.middlewareIds ?? [],
|
package/dist/tools/templates.js
CHANGED
|
@@ -1,6 +1,30 @@
|
|
|
1
1
|
import { guid, pagingParams, readOnly, writes, updates } from './common.js';
|
|
2
|
+
import { withNormalization } from '../knowledge/normalize.js';
|
|
2
3
|
import { handle } from '../platform/responses.js';
|
|
3
4
|
import { z } from 'zod';
|
|
5
|
+
/**
|
|
6
|
+
* `environmentId` verilmediğinde platform PRODUCTION'ı paketler
|
|
7
|
+
* (`CreateProjectAsTemplateCommand`: `EnvironmentId ??= ActiveEnvironments().First(f => f.IsProduction)`).
|
|
8
|
+
* Promote edilmemiş projede o environment boştur ve build yine 'success' döner; şablon seed
|
|
9
|
+
* kayıtlarından ibaret kalır. Çağıran bunu yanıttan görmediği için hangi environment'ın
|
|
10
|
+
* paketlendiğini adıyla söylüyoruz (2026-09-12 koşusu S-2).
|
|
11
|
+
*/
|
|
12
|
+
async function defaultTemplateEnvironmentNote(platform, projectId) {
|
|
13
|
+
const fallback = "environmentId verilmedi: platform PRODUCTION environment'ını paketler (varsayılan/development değil). Promote edilmemiş projede şablon boş çıkar; development içeriğini istiyorsanız o environment'ın id'sini açıkça verin.";
|
|
14
|
+
try {
|
|
15
|
+
const payload = await platform.org('GET', `/projects/${projectId}`);
|
|
16
|
+
const environments = Array.isArray(payload?.data?.environments)
|
|
17
|
+
? payload.data.environments
|
|
18
|
+
: [];
|
|
19
|
+
const production = environments.find(environment => environment.isProduction === true);
|
|
20
|
+
if (!production)
|
|
21
|
+
return fallback;
|
|
22
|
+
return `environmentId verilmedi: platform '${String(production.name)}' (production, id ${String(production.id)}) environment'ını paketler — varsayılan/development environment'ı DEĞİL. Oraya henüz promote etmediyseniz şablon yalnız seed kayıtlarını taşır; development içeriğini paketlemek için o environment'ın id'sini açıkça verin.`;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return fallback;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
4
28
|
export function registerTemplateTools(server, platform) {
|
|
5
29
|
const config = platform.config;
|
|
6
30
|
server.registerTool('template_list', {
|
|
@@ -24,31 +48,34 @@ export function registerTemplateTools(server, platform) {
|
|
|
24
48
|
description: "Şablonun bir modüldeki kayıtlarını listeler (project_create'in templateOptions.filters'ını doldurmak için).",
|
|
25
49
|
inputSchema: {
|
|
26
50
|
id: guid,
|
|
27
|
-
module: z.string().describe("Module değeri: entity | microservice | workflow | page | layout | component | query | view …")
|
|
51
|
+
module: z.string().describe("Module değeri: entity | microservice | workflow | page | layout | component | query | view | variable | global-function (fonksiyonlar, iki kaynak) | flow … (platform Module enum değeri, kebab-case)")
|
|
28
52
|
},
|
|
29
53
|
annotations: readOnly
|
|
30
54
|
}, handle(config, ({ id, module }) => platform.org('GET', `/templates/${id}/items`, { query: { module } })));
|
|
31
55
|
server.registerTool('template_create', {
|
|
32
56
|
title: 'Projeyi şablon olarak yayımla',
|
|
33
|
-
description:
|
|
57
|
+
description: "Mevcut projeden yeni bir şablon sürümü üretir. **Paketlenen environment `environmentId`'dir ve boş bırakılırsa platform PRODUCTION'ı paketler** (`CreateProjectAsTemplateCommand`: `EnvironmentId ??= ActiveEnvironments().First(f => f.IsProduction)`) — 'varsayılan environment' DEĞİL. Henüz promote edilmemiş projede production boştur: build 'success' döner ama şablon yalnız seed kayıtlarını taşır (microfunction/workflow/microservice sıfır). Geliştirmede yazdığınız içeriği paketlemek için development environment id'sini AÇIKÇA verin. Build asenkrondur: yanıt hemen döner, sürüm birkaç saniye sonra template_list'te görünür; içeriği template_items ile doğrulayın. Görsel yükleme bu tool'da desteklenmez (ikili aktarım kapsam dışı).",
|
|
34
58
|
inputSchema: {
|
|
35
59
|
projectId: guid,
|
|
36
60
|
name: z.string().min(1),
|
|
37
61
|
version: z.string().min(1).describe("Sürüm etiketi, ör. '1.0.0'"),
|
|
38
62
|
description: z.string().optional(),
|
|
39
63
|
changeLog: z.string().optional(),
|
|
40
|
-
environmentId: guid.optional().describe(
|
|
64
|
+
environmentId: guid.optional().describe("Hangi environment'ın içeriği paketlenecek. BOŞSA PRODUCTION paketlenir (projenin varsayılan/development environment'ı değil) — development içeriğini şablona koyacaksanız o environment'ın id'sini açıkça verin.")
|
|
41
65
|
},
|
|
42
66
|
annotations: writes
|
|
43
|
-
}, handle(config, ({ projectId, name, version, description, changeLog, environmentId }) => {
|
|
67
|
+
}, handle(config, async ({ projectId, name, version, description, changeLog, environmentId }) => {
|
|
44
68
|
const form = new URLSearchParams({ Name: name, Version: version });
|
|
69
|
+
const normalized = [];
|
|
45
70
|
if (description)
|
|
46
71
|
form.set('Description', description);
|
|
47
72
|
if (changeLog)
|
|
48
73
|
form.set('ChangeLog', changeLog);
|
|
49
74
|
if (environmentId)
|
|
50
75
|
form.set('EnvironmentId', environmentId);
|
|
51
|
-
|
|
76
|
+
else
|
|
77
|
+
normalized.push(await defaultTemplateEnvironmentNote(platform, projectId));
|
|
78
|
+
return withNormalization(await platform.org('POST', `/projects/${projectId}/templates`, { form }), normalized);
|
|
52
79
|
}));
|
|
53
80
|
server.registerTool('template_check_updates', {
|
|
54
81
|
title: 'Şablon güncellemesi var mı',
|
|
@@ -1,22 +1,38 @@
|
|
|
1
1
|
import { guid, projectParam, environmentParam, readOnly, updates } from './common.js';
|
|
2
2
|
import { handle } from '../platform/responses.js';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
+
import { evaluatePolicy, enforcePolicy, attachFindings } from '../knowledge/policy.js';
|
|
5
|
+
import { readProjectLanguages, translationLanguageFindings } from '../knowledge/languages.js';
|
|
6
|
+
import { policyRules } from '../knowledge/rules.js';
|
|
4
7
|
const translationKeyInput = z.object({
|
|
5
8
|
key: z.string().min(1),
|
|
6
|
-
values: z.record(z.string()).describe("Dil kodu (ISO 639-1) → çeviri metni
|
|
9
|
+
values: z.record(z.string().regex(/^[a-z]{2}$/, 'ISO 639-1 iki harfli küçük dil kodu (tr, en, de …); tr-TR gibi bölge ekli kod reddedilir'), z.string()).describe("Dil kodu (ISO 639-1, iki küçük harf) → çeviri metni. Platform kodu yalnız 184 kodluk ISO sözlüğüne göre doğrular (TR-001); PROJENİN languages listesine göre doğrulamaz — o bağı gateway kurar (TR-002)"),
|
|
7
10
|
componentId: guid.optional().describe("Çeviriyi belirli bir komponente bağlar; o komponent silinince kaydı da silinir")
|
|
8
11
|
});
|
|
12
|
+
/**
|
|
13
|
+
* Yazma öncesi projenin dil durumunu okur. Proje okunamazsa (uç düşer, yetki yoksa) kontrol
|
|
14
|
+
* ATLANIR ve karar platforma kalır — `project_create`'in slug ön aramasındaki (PRJ-001) davranışın
|
|
15
|
+
* aynısı. Uydurma bulgu üretilmez.
|
|
16
|
+
*/
|
|
17
|
+
async function languageFindings(platform, project, keys) {
|
|
18
|
+
const slug = platform.resolveProject(project);
|
|
19
|
+
const codes = keys.flatMap(entry => Object.keys(entry.values ?? {}));
|
|
20
|
+
if (codes.length === 0)
|
|
21
|
+
return [];
|
|
22
|
+
const payload = await platform.org('GET', `/p/${slug}`).catch(() => undefined);
|
|
23
|
+
return translationLanguageFindings(readProjectLanguages(payload), codes, slug);
|
|
24
|
+
}
|
|
9
25
|
export function registerTranslationTools(server, platform) {
|
|
10
26
|
const config = platform.config;
|
|
11
27
|
server.registerTool('translation_list', {
|
|
12
28
|
title: 'Çevirileri listele',
|
|
13
|
-
description: "Application'ın tüm çeviri kayıtlarını (dil × anahtar × değer) düz liste olarak döner. Proje dilleri/varsayılan dil için project_get; sayfada bir prop'u çeviriye bağlamak için platform_guide('translation').",
|
|
29
|
+
description: "Application'ın tüm çeviri kayıtlarını (dil × anahtar × değer) düz liste olarak döner. Proje dilleri/varsayılan dil için project_get (yanıtındaki localization bloğu runtime'ın bu çevirileri çözüp çözemeyeceğini söyler); sayfada bir prop'u çeviriye bağlamak için platform_guide('translation').",
|
|
14
30
|
inputSchema: { project: projectParam, environment: environmentParam, applicationId: guid },
|
|
15
31
|
annotations: readOnly
|
|
16
32
|
}, handle(config, ({ project, environment, applicationId }) => platform.tenant('GET', project, `/translations/${applicationId}`, { environment })));
|
|
17
33
|
server.registerTool('translation_update', {
|
|
18
34
|
title: 'Çevirileri güncelle',
|
|
19
|
-
description: "Bir ya da daha çok çeviri anahtarını toplu ekler/günceller (keys) ve/veya siler (deletedKeys) — tek çağrıda ikisi de verilebilir. 'keys' üzerinden yeni bir anahtar da açılabilir (upsert).
|
|
35
|
+
description: "Bir ya da daha çok çeviri anahtarını toplu ekler/günceller (keys) ve/veya siler (deletedKeys) — tek çağrıda ikisi de verilebilir. 'keys' üzerinden yeni bir anahtar da açılabilir (upsert; verilmeyen diller silinmez, korunur). DİKKAT: çeviri yazmak tek başına YETMEZ — runtime bir etiketi ancak projenin languages listesi ve defaultLanguage kuruluysa çözer, aksi hâlde ekrana ham anahtar basar ve yazma yine 200 döner (ölçüldü 2026-09-09, S-15). Gateway yazmadan önce projeyi okur ve bağ kopuksa TR-002 caution'ı düşer; dilleri project_update(languages, defaultLanguage) ile kurun. Backend ön kontrolü (TR-001, block): anahtarlar boş olamaz ve tekil, dil kodları ISO 639-1 listesinden, deletedKeys boş olamaz.",
|
|
20
36
|
inputSchema: {
|
|
21
37
|
project: projectParam,
|
|
22
38
|
environment: environmentParam,
|
|
@@ -25,13 +41,13 @@ export function registerTranslationTools(server, platform) {
|
|
|
25
41
|
deletedKeys: z.array(z.string().min(1)).optional().describe('Silinecek anahtar adları')
|
|
26
42
|
},
|
|
27
43
|
annotations: updates
|
|
28
|
-
}, handle(config, ({ project, environment, applicationId, keys, deletedKeys }) => {
|
|
44
|
+
}, handle(config, async ({ project, environment, applicationId, keys, deletedKeys }) => {
|
|
29
45
|
if (!keys?.length && !deletedKeys?.length) {
|
|
30
46
|
throw new Error("'keys' ya da 'deletedKeys' parametrelerinden en az biri dolu olmalı.");
|
|
31
47
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
});
|
|
48
|
+
const body = { keys: keys ?? [], deletedKeys: deletedKeys ?? [] };
|
|
49
|
+
const findings = enforcePolicy(evaluatePolicy(config, policyRules, 'translation', body, { operation: 'update' }));
|
|
50
|
+
const languages = await languageFindings(platform, project, keys ?? []);
|
|
51
|
+
return attachFindings(await platform.tenant('PUT', project, `/translations/${applicationId}`, { environment, body }), [...findings, ...languages]);
|
|
36
52
|
}));
|
|
37
53
|
}
|
package/dist/tools/views.js
CHANGED
|
@@ -3,6 +3,12 @@ import { guid, projectParam, environmentParam, definitionParam, pagingParams, re
|
|
|
3
3
|
import { PlatformApiError } from '../platform/errors.js';
|
|
4
4
|
import { handle } from '../platform/responses.js';
|
|
5
5
|
import { z } from 'zod';
|
|
6
|
+
import { unmappedMembers, withUnmappedMembers } from '../knowledge/schemaGuard.js';
|
|
7
|
+
import { evaluatePolicy, enforcePolicy, attachFindings } from '../knowledge/policy.js';
|
|
8
|
+
import { policyRules } from '../knowledge/rules.js';
|
|
9
|
+
import { constraintSummary } from '../knowledge/backendConstraints.js';
|
|
10
|
+
const policyOverrideParam = z.boolean().optional()
|
|
11
|
+
.describe('true: politika block bulgularını warn\'a indirir (bilinçli istisna; yanıtta işaretlenir)');
|
|
6
12
|
export function registerViewTools(server, platform) {
|
|
7
13
|
const config = platform.config;
|
|
8
14
|
const normalizeSource = (definition) => {
|
|
@@ -19,29 +25,33 @@ export function registerViewTools(server, platform) {
|
|
|
19
25
|
}, handle(config, ({ project, environment, ...query }) => platform.tenant('GET', project, '/views', { environment, query })));
|
|
20
26
|
server.registerTool('view_get', {
|
|
21
27
|
title: 'View getir',
|
|
22
|
-
description:
|
|
28
|
+
description: "Tek view tanımını getirir; view_create için en iyi gövde şablonudur. Hatırlatma: view TAM METİN ARAMA indeksidir, agregasyon/raporlama aracı değildir — özet için query_create (09-02 M-3).",
|
|
23
29
|
inputSchema: { project: projectParam, environment: environmentParam, id: guid },
|
|
24
30
|
annotations: readOnly
|
|
25
31
|
}, handle(config, ({ project, environment, id }) => platform.tenant('GET', project, `/views/${id}`, { environment })));
|
|
26
32
|
server.registerTool('view_create', {
|
|
27
33
|
title: 'View oluştur',
|
|
28
|
-
description: "TAM METİN ARAMA indeksi tanımlar (definition = CreateViewCommand; gövde şeması ngapps://schemas/CreateViewCommand, analizör sözlüğü platform_guide('view')) — raporlama/agregasyon aracı DEĞİLDİR. Seçilen tablo/alanlar analizörden (tokenizer/dil) geçirilip slug adlı projeksiyon tablosuna indekslenir; tüketimi source:'view' microservice'idir ve o uç ZORUNLU 'searchText' parametresi ister (+limit/offset). Rapor/özet için raw query (query_create) + query kaynaklı microservice kullanın. Birden çok entity verilebilir (entities: [{entityId, alias}], fields alias'la bağlanır: viewEntityAlias) ama bu JOIN DEĞİLDİR: her tablo ayrı ayrı indekslenir, aralarında ilişki tanımı yoktur ve eşleşme hangi tablodan geldiyse dönen kayıt o tablonun satırıdır. İlişkili içeriği tek kayıtta aratmak için denormalize bir alan kullanın (yorum metnini talebe yazan automation + tek entity'li view).",
|
|
29
|
-
inputSchema: { project: projectParam, environment: environmentParam, definition: definitionParam },
|
|
34
|
+
description: "TAM METİN ARAMA indeksi tanımlar (definition = CreateViewCommand; gövde şeması ngapps://schemas/CreateViewCommand, analizör sözlüğü platform_guide('view')) — raporlama/agregasyon aracı DEĞİLDİR. Seçilen tablo/alanlar analizörden (tokenizer/dil) geçirilip slug adlı projeksiyon tablosuna indekslenir; tüketimi source:'view' microservice'idir ve o uç ZORUNLU 'searchText' parametresi ister (+limit/offset). Rapor/özet için raw query (query_create) + query kaynaklı microservice kullanın. Birden çok entity verilebilir (entities: [{entityId, alias}], fields alias'la bağlanır: viewEntityAlias) ama bu JOIN DEĞİLDİR: her tablo ayrı ayrı indekslenir, aralarında ilişki tanımı yoktur ve eşleşme hangi tablodan geldiyse dönen kayıt o tablonun satırıdır. İlişkili içeriği tek kayıtta aratmak için denormalize bir alan kullanın (yorum metnini talebe yazan automation + tek entity'li view). " + constraintSummary('CreateViewCommand'),
|
|
35
|
+
inputSchema: { project: projectParam, environment: environmentParam, definition: definitionParam, policyOverride: policyOverrideParam },
|
|
30
36
|
annotations: writes
|
|
31
|
-
}, handle(config, async ({ project, environment, definition }) => {
|
|
37
|
+
}, handle(config, async ({ project, environment, definition, policyOverride }) => {
|
|
32
38
|
const fixes = normalizeSource(definition);
|
|
39
|
+
const findings = enforcePolicy(evaluatePolicy(config, policyRules, 'view', definition, { operation: 'create' }, policyOverride));
|
|
40
|
+
const drift = unmappedMembers('CreateViewCommand', definition);
|
|
33
41
|
const response = await platform.tenant('POST', project, '/views', { environment, body: definition });
|
|
34
|
-
return withNormalization(response, viewAliasNote(fixes));
|
|
42
|
+
return attachFindings(withUnmappedMembers(withNormalization(response, viewAliasNote(fixes)), drift), findings);
|
|
35
43
|
}));
|
|
36
44
|
server.registerTool('view_update', {
|
|
37
45
|
title: 'View güncelle',
|
|
38
|
-
description: "View tanımını günceller (definition = UpdateViewCommand, şema ngapps://schemas/UpdateViewCommand); mevcut hâli view_get ile alın. UpdateViewCommand'da datasourceId YOKTUR (create'te bağlanır). DİKKAT: view_get alanları 'viewEntityId' ile döndürür, yazma tarafı 'viewEntityAlias' ister — okuduğunuzu birebir geri yazarsanız gateway id'yi alias'a çevirir, çeviremezse isteği reddeder.",
|
|
39
|
-
inputSchema: { project: projectParam, environment: environmentParam, id: guid, definition: definitionParam },
|
|
46
|
+
description: "View tanımını günceller (definition = UpdateViewCommand, şema ngapps://schemas/UpdateViewCommand); mevcut hâli view_get ile alın. UpdateViewCommand'da datasourceId YOKTUR (create'te bağlanır). DİKKAT: view_get alanları 'viewEntityId' ile döndürür, yazma tarafı 'viewEntityAlias' ister — okuduğunuzu birebir geri yazarsanız gateway id'yi alias'a çevirir, çeviremezse isteği reddeder. " + constraintSummary('UpdateViewCommand'),
|
|
47
|
+
inputSchema: { project: projectParam, environment: environmentParam, id: guid, definition: definitionParam, policyOverride: policyOverrideParam },
|
|
40
48
|
annotations: updates
|
|
41
|
-
}, handle(config, async ({ project, environment, id, definition }) => {
|
|
49
|
+
}, handle(config, async ({ project, environment, id, definition, policyOverride }) => {
|
|
42
50
|
const fixes = normalizeSource(definition);
|
|
51
|
+
const findings = enforcePolicy(evaluatePolicy(config, policyRules, 'view', definition, { operation: 'update' }, policyOverride));
|
|
52
|
+
const drift = unmappedMembers('UpdateViewCommand', definition);
|
|
43
53
|
const response = await platform.tenant('PUT', project, `/views/${id}`, { environment, body: definition });
|
|
44
|
-
return withNormalization(response, viewAliasNote(fixes));
|
|
54
|
+
return attachFindings(withUnmappedMembers(withNormalization(response, viewAliasNote(fixes)), drift), findings);
|
|
45
55
|
}));
|
|
46
56
|
server.registerTool('view_delete', {
|
|
47
57
|
title: 'View sil',
|
|
@@ -51,7 +61,7 @@ export function registerViewTools(server, platform) {
|
|
|
51
61
|
}, handle(config, ({ project, environment, id }) => platform.tenant('DELETE', project, `/views/${id}`, { environment })));
|
|
52
62
|
server.registerTool('view_rebuild', {
|
|
53
63
|
title: 'View yeniden kur',
|
|
54
|
-
description:
|
|
64
|
+
description: "View projeksiyon tablosunu yeniden inşa eder (veri değişikliklerinden sonra senkron için). Rebuild ARAMA indeksini tazeler; sayım/özet üretmez — raporlama için query_create (09-02 M-3).",
|
|
55
65
|
inputSchema: { project: projectParam, environment: environmentParam, id: guid },
|
|
56
66
|
annotations: writes
|
|
57
67
|
}, handle(config, ({ project, environment, id }) => platform.tenant('POST', project, `/views/${id}/rebuild`, { environment })));
|
package/dist/tools/workflows.js
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
import { guid, projectParam, environmentParam, definitionParam, pagingParams, readOnly, writes, updates, destructive } from './common.js';
|
|
1
|
+
import { guid, projectParam, environmentParam, definitionParam, pagingParams, readOnly, writes, updates, destructive, microOps, languageParam } from './common.js';
|
|
2
2
|
import { normalizeWorkflowDefinition, withNormalization } from '../knowledge/normalize.js';
|
|
3
3
|
import { evaluatePolicy, enforcePolicy, attachFindings } from '../knowledge/policy.js';
|
|
4
4
|
import { workflowOutline, resolvePart, resolvePatchOperations } from '../knowledge/outlines.js';
|
|
5
|
-
import {
|
|
5
|
+
import { patchResult, baseVersionOf } from '../platform/patch.js';
|
|
6
|
+
import { writeDiff, withWriteDiff } from '../platform/writeDiff.js';
|
|
7
|
+
import { policyRules, microfunctionStepFindings } from '../knowledge/rules.js';
|
|
8
|
+
import { languageHeader } from '../knowledge/languageCodes.js';
|
|
6
9
|
import { handle } from '../platform/responses.js';
|
|
7
10
|
import fastJsonPatch from 'fast-json-patch';
|
|
8
11
|
import { z } from 'zod';
|
|
12
|
+
import { constraintSummary } from '../knowledge/backendConstraints.js';
|
|
13
|
+
import { unmappedMembers, introducedUnmappedMembers, withUnmappedMembers } from '../knowledge/schemaGuard.js';
|
|
9
14
|
const policyOverrideParam = z.boolean().optional()
|
|
10
15
|
.describe('true: politika block bulgularını warn\'a indirir (bilinçli istisna; yanıtta işaretlenir)');
|
|
11
16
|
const patchOperationsParam = z.array(z.record(z.unknown())).min(1)
|
|
@@ -106,44 +111,65 @@ export function registerWorkflowTools(server, platform) {
|
|
|
106
111
|
}));
|
|
107
112
|
server.registerTool('workflow_create', {
|
|
108
113
|
title: 'Workflow oluştur',
|
|
109
|
-
description: "Yeni workflow tanımlar (definition = CreateWorkflowCommand). type: 'workflow' | 'automation' | 'middleware'. İlk kullanımdan önce platform_guide('workflow') okuyun: DTO-önce akışı, branch bağlama (branches[].nextStepId), tip×step matrisi. Her adım ve akışın kendisi 'description' taşımak ZORUNDADIR (WF-024, block): adımın NE İŞE YARADIĞINI 1-2 cümleyle yazın — Studio kanvasında ⓘ ikonu olarak görünür; mekanizmayı değil niyeti yazın. Middleware (istek öncesi koşan guard/setter, user değişkeni, alfabetik sıra) için platform_guide('middleware') + ngapps://examples/middleware-authenticate. Adımın gerçek bir tuzağı varsa (idempotent değil, kapsam adımda değil, dış bağımlılık, sessiz düşen dal) 'caution' alanına yazın — OPSİYONELDİR, tuzak yoksa boş bırakın; doldurma metin yazmayın. Gövde politika kontrolünden geçer.",
|
|
114
|
+
description: "Yeni workflow tanımlar (definition = CreateWorkflowCommand). type: 'workflow' | 'automation' | 'middleware'. İlk kullanımdan önce platform_guide('workflow') okuyun: DTO-önce akışı, branch bağlama (branches[].nextStepId), tip×step matrisi. Her adım ve akışın kendisi 'description' taşımak ZORUNDADIR (WF-024, block): adımın NE İŞE YARADIĞINI 1-2 cümleyle yazın — Studio kanvasında ⓘ ikonu olarak görünür; mekanizmayı değil niyeti yazın. Middleware (istek öncesi koşan guard/setter, user değişkeni, alfabetik sıra) için platform_guide('middleware') + ngapps://examples/middleware-authenticate. Adımın gerçek bir tuzağı varsa (idempotent değil, kapsam adımda değil, dış bağımlılık, sessiz düşen dal) 'caution' alanına yazın — OPSİYONELDİR, tuzak yoksa boş bırakın; doldurma metin yazmayın. Gövde politika kontrolünden geçer. " + constraintSummary('CreateWorkflowCommand'),
|
|
110
115
|
inputSchema: { project: projectParam, environment: environmentParam, applicationId: guid, definition: definitionParam, policyOverride: policyOverrideParam },
|
|
111
116
|
annotations: writes
|
|
112
117
|
}, handle(config, async ({ project, environment, applicationId, definition, policyOverride }) => {
|
|
113
118
|
const normalized = normalizeWorkflowDefinition(definition);
|
|
114
|
-
const findings = enforcePolicy(
|
|
119
|
+
const findings = enforcePolicy([
|
|
120
|
+
...evaluatePolicy(config, policyRules, 'workflow', definition, { operation: 'create', workflowKind: definition.type }, policyOverride),
|
|
121
|
+
...await microfunctionStepFindings(platform, project, environment, definition, definition.type, policyOverride)
|
|
122
|
+
]);
|
|
123
|
+
const drift = unmappedMembers('CreateWorkflowCommand', definition);
|
|
115
124
|
const payload = await platform.tenant('POST', project, `/workflows/${applicationId}`, { environment, body: definition });
|
|
116
|
-
return attachFindings(withNormalization(payload, normalized), findings);
|
|
125
|
+
return attachFindings(withUnmappedMembers(withWriteDiff(withNormalization(payload, normalized), writeDiff(definition, payload)), drift), findings);
|
|
117
126
|
}));
|
|
118
127
|
server.registerTool('workflow_update', {
|
|
119
128
|
title: 'Workflow güncelle',
|
|
120
|
-
description: 'Workflow tanımını günceller (definition = UpdateWorkflowCommand, tam gövde). Hedefli değişiklik için workflow_patch tercih edin. Her adım ve akışın kendisi \'description\' taşımak ZORUNDADIR (WF-024, block). Adımın gerçek bir tuzağı varsa (idempotent değil, kapsam adımda değil, dış bağımlılık, sessiz düşen dal) \'caution\' alanına yazın — OPSİYONELDİR, tuzak yoksa boş bırakın; doldurma metin yazmayın. Gövde politika kontrolünden geçer.',
|
|
129
|
+
description: 'Workflow tanımını günceller (definition = UpdateWorkflowCommand, tam gövde). Hedefli değişiklik için workflow_patch tercih edin. Her adım ve akışın kendisi \'description\' taşımak ZORUNDADIR (WF-024, block). Adımın gerçek bir tuzağı varsa (idempotent değil, kapsam adımda değil, dış bağımlılık, sessiz düşen dal) \'caution\' alanına yazın — OPSİYONELDİR, tuzak yoksa boş bırakın; doldurma metin yazmayın. Gövde politika kontrolünden geçer. ' + constraintSummary('UpdateWorkflowCommand'),
|
|
121
130
|
inputSchema: { project: projectParam, environment: environmentParam, applicationId: guid, id: guid, definition: definitionParam, policyOverride: policyOverrideParam },
|
|
122
131
|
annotations: updates
|
|
123
132
|
}, handle(config, async ({ project, environment, applicationId, id, definition, policyOverride }) => {
|
|
124
133
|
const normalized = normalizeWorkflowDefinition(definition);
|
|
125
|
-
const findings = enforcePolicy(
|
|
134
|
+
const findings = enforcePolicy([
|
|
135
|
+
...evaluatePolicy(config, policyRules, 'workflow', definition, { operation: 'update', workflowKind: definition.type }, policyOverride),
|
|
136
|
+
...await microfunctionStepFindings(platform, project, environment, definition, definition.type, policyOverride)
|
|
137
|
+
]);
|
|
138
|
+
const drift = unmappedMembers('UpdateWorkflowCommand', definition);
|
|
126
139
|
const payload = await platform.tenant('PUT', project, `/workflows/${applicationId}/${id}`, { environment, body: definition });
|
|
127
|
-
return attachFindings(withNormalization(payload, normalized), findings);
|
|
140
|
+
return attachFindings(withUnmappedMembers(withWriteDiff(withNormalization(payload, normalized), writeDiff(definition, payload)), drift), findings);
|
|
128
141
|
}));
|
|
129
142
|
server.registerTool('workflow_patch', {
|
|
130
143
|
title: 'Workflow\'a patch uygula',
|
|
131
|
-
description: 'Tam gövdeyi bağlama almadan hedefli değişiklik: gateway mevcut workflow\'u çeker, JSON Patch işlemlerini uygular, politika kontrolünden geçirir, tam
|
|
132
|
-
inputSchema: { project: projectParam, environment: environmentParam, applicationId: guid, id: guid, operations: patchOperationsParam, policyOverride: policyOverrideParam },
|
|
144
|
+
description: 'Tam gövdeyi bağlama almadan hedefli değişiklik: gateway mevcut workflow\'u çeker, JSON Patch işlemlerini uygular, politika kontrolünden geçirir ve FARKI platformun PATCH /workflows/{app}/{id} ucuna `{ baseVersion, ops }` olarak yazar — tam gövde PUT\'u ATILMAZ. `baseVersion` okunan kaydın `version` alanıdır; kayıt bu arada değiştiyse platform 409 döner ve hiçbir op uygulanmaz. Değişiklik hedefli ama yazma değil: hata yolu olmayan bir workflow/middleware kaydına patch atmak o kaydın grafiğini de düzeltir — start adımına global-error dalı + 500 dönen response adımı eklenir ve yanıtta gatewayNormalized ile bildirilir. Yanıt outline özetidir.',
|
|
145
|
+
inputSchema: { project: projectParam, environment: environmentParam, applicationId: guid, id: guid, operations: patchOperationsParam.optional(), ops: patchOperationsParam.optional().describe("'operations' ile aynı alan (eşanlamlı) — sayfa micro-op tool'larıyla aynı adı kullanabilmeniz için"), policyOverride: policyOverrideParam },
|
|
133
146
|
annotations: updates
|
|
134
|
-
}, handle(config, async ({ project, environment, applicationId, id, operations, policyOverride }) => {
|
|
147
|
+
}, handle(config, async ({ project, environment, applicationId, id, operations: givenOperations, ops, policyOverride }) => {
|
|
148
|
+
const operations = microOps('workflow_patch', ops, givenOperations);
|
|
135
149
|
const current = await platform.tenant('GET', project, `/workflows/${applicationId}/${id}`, { environment });
|
|
136
150
|
const definition = structuredClone((current?.data ?? current));
|
|
137
151
|
const resolved = resolvePatchOperations(definition, operations);
|
|
138
152
|
const patched = fastJsonPatch.applyPatch(definition, resolved.operations, true, false).newDocument;
|
|
139
153
|
const normalized = normalizeWorkflowDefinition(patched);
|
|
140
|
-
const findings = enforcePolicy(
|
|
141
|
-
|
|
142
|
-
|
|
154
|
+
const findings = enforcePolicy([
|
|
155
|
+
...evaluatePolicy(config, policyRules, 'workflow', patched, { operation: 'update', workflowKind: patched.type }, policyOverride),
|
|
156
|
+
...await microfunctionStepFindings(platform, project, environment, patched, patched.type, policyOverride)
|
|
157
|
+
]);
|
|
158
|
+
const drift = introducedUnmappedMembers('UpdateWorkflowCommand', (current?.data ?? current), patched);
|
|
159
|
+
// Gövde değil FARK gönderilir: gateway normalizasyonları da op'a çevrilsin diye net diff
|
|
160
|
+
// okunan kayıt ile son hâl arasından hesaplanır (tam PUT yok, yalnız değişen alanlar yazılır).
|
|
161
|
+
const netOps = fastJsonPatch.compare(definition, patched);
|
|
162
|
+
const saved = await platform.tenant('PATCH', project, `/workflows/${applicationId}/${id}`, {
|
|
163
|
+
environment,
|
|
164
|
+
body: { baseVersion: baseVersionOf(definition, 'workflow_get'), ops: netOps }
|
|
165
|
+
});
|
|
166
|
+
const written = patchResult(saved, patched);
|
|
167
|
+
return attachFindings(withUnmappedMembers(withNormalization({
|
|
143
168
|
applied: operations.length,
|
|
169
|
+
newVersion: written.newVersion,
|
|
144
170
|
patchTargets: resolved.targets,
|
|
145
|
-
outline: workflowOutline(
|
|
146
|
-
}, [...normalized, ...resolved.notes.map(note => `patch yolu seçiciden indekse çözüldü: ${note}`)]), findings);
|
|
171
|
+
outline: workflowOutline(written.data)
|
|
172
|
+
}, [...normalized, ...resolved.notes.map(note => `patch yolu seçiciden indekse çözüldü: ${note}`)]), drift), findings);
|
|
147
173
|
}));
|
|
148
174
|
server.registerTool('workflow_delete', {
|
|
149
175
|
title: 'Workflow sil',
|
|
@@ -159,13 +185,22 @@ export function registerWorkflowTools(server, platform) {
|
|
|
159
185
|
}, handle(config, ({ project, environment, id }) => platform.tenant('POST', project, `/workflows/clone/${id}`, { environment })));
|
|
160
186
|
server.registerTool('workflow_preview', {
|
|
161
187
|
title: 'Workflow önizle',
|
|
162
|
-
description: "Kaydedilmemiş workflow tanımını çalıştırır; kaydetmeden önce her akışı preview ile doğrulayın. definition = PreviewWorkflowCommand gövdesi. Test girdisi 'previewPayload' anahtarıyla verilir ('parameters'/'input' ÇALIŞMAZ), değişkenler 'previewVariables'. previewPayload STRING olmalıdır (JSON.stringify(...) ya da \"({ id: 1 })\") — nesne gönderilirse platform 'Unexpected end of input' ile 500 döner. Preview
|
|
163
|
-
inputSchema: { project: projectParam, environment: environmentParam, applicationId: guid, definition: definitionParam, policyOverride: policyOverrideParam },
|
|
188
|
+
description: "Kaydedilmemiş workflow tanımını çalıştırır; kaydetmeden önce her akışı preview ile doğrulayın. definition = PreviewWorkflowCommand gövdesi. Test girdisi 'previewPayload' anahtarıyla verilir ('parameters'/'input' ÇALIŞMAZ), değişkenler 'previewVariables'. previewPayload STRING olmalıdır (JSON.stringify(...) ya da \"({ id: 1 })\") — nesne gönderilirse platform 'Unexpected end of input' ile 500 döner. Akışın parameterDtoId'si YOKSA previewPayload verilmez (platform 400 döner; gateway alanı düşürüp gatewayNormalized ile bildirir). Preview tek transaction'da koşar ve sonunda ROLLBACK edilir: table create/update step'leri kalıcı satır YAZMAZ (ölçüldü, İK koşusu W-1). Tek istisna code step içindeki dış HTTP çağrılarıdır — onlar geri alınamaz. Davranış kuralları: platform_guide('workflow'). " + constraintSummary('PreviewWorkflowCommand'),
|
|
189
|
+
inputSchema: { project: projectParam, environment: environmentParam, applicationId: guid, definition: definitionParam, policyOverride: policyOverrideParam, language: languageParam },
|
|
164
190
|
annotations: writes
|
|
165
|
-
}, handle(config, async ({ project, environment, applicationId, definition, policyOverride }) => {
|
|
191
|
+
}, handle(config, async ({ project, environment, applicationId, definition, policyOverride, language }) => {
|
|
166
192
|
const normalized = normalizeWorkflowDefinition(definition);
|
|
167
|
-
|
|
168
|
-
|
|
193
|
+
// 33/S-6: parameterDtoId olmayan akışa previewPayload gönderilince platform 400 verir
|
|
194
|
+
// ("'previewPayload' requires a parameter DTO"). Girdisiz akışta alanın anlamı yok — düşürülür.
|
|
195
|
+
if (!definition.parameterDtoId && definition.previewPayload !== undefined) {
|
|
196
|
+
delete definition.previewPayload;
|
|
197
|
+
normalized.push("previewPayload düşürüldü — akışın parameterDtoId'si yok, platform 400 \"'previewPayload' requires a parameter DTO\" verir; girdi gerekiyorsa önce parameterDtoId + parameterBehavior tanımlayın");
|
|
198
|
+
}
|
|
199
|
+
const findings = enforcePolicy([
|
|
200
|
+
...evaluatePolicy(config, policyRules, 'workflow', definition, { operation: 'preview', workflowKind: definition.type }, policyOverride),
|
|
201
|
+
...await microfunctionStepFindings(platform, project, environment, definition, definition.type, policyOverride)
|
|
202
|
+
]);
|
|
203
|
+
const payload = await platform.tenant('POST', project, `/workflows/${applicationId}/preview`, { environment, body: definition, headers: languageHeader(language, normalized) });
|
|
169
204
|
return attachFindings(withNormalization(payload, normalized), findings);
|
|
170
205
|
}));
|
|
171
206
|
server.registerTool('workflow_step_schema', {
|
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.7",
|
|
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",
|
|
@@ -29,8 +29,13 @@
|
|
|
29
29
|
"test": "vitest run",
|
|
30
30
|
"docs:lint": "tsx scripts/docs-lint.ts",
|
|
31
31
|
"generate-schemas": "tsx scripts/generate-schemas.ts",
|
|
32
|
+
"refresh-schemas": "scripts/refresh-schemas.sh",
|
|
33
|
+
"schema:check": "tsx scripts/schemaFingerprint.ts",
|
|
32
34
|
"generate-reserved-tables": "tsx scripts/generate-reserved-tables.ts",
|
|
33
|
-
"harvest-examples": "tsx scripts/harvest-examples.ts"
|
|
35
|
+
"harvest-examples": "tsx scripts/harvest-examples.ts",
|
|
36
|
+
"kabul:import-adres": "tsx scripts/import-kabul-adres.ts",
|
|
37
|
+
"kabul:import-senaryolar": "tsx scripts/import-kabul-senaryolar.ts",
|
|
38
|
+
"benchmark:report": "tsx scripts/benchmark-report.ts"
|
|
34
39
|
},
|
|
35
40
|
"dependencies": {
|
|
36
41
|
"@modelcontextprotocol/sdk": "^1.12.0",
|