@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
package/dist/tools/layouts.js
CHANGED
|
@@ -11,6 +11,8 @@ import { PlatformApiError } from '../platform/errors.js';
|
|
|
11
11
|
import { handle } from '../platform/responses.js';
|
|
12
12
|
import { applicationTypeField, resolveProfile } from '../knowledge/platform/resolve.js';
|
|
13
13
|
import { screenProfileWarnings } from './profileWrite.js';
|
|
14
|
+
import { enforceTextHooks, textHookOverrideParam } from './textHookGuard.js';
|
|
15
|
+
import { attachFindings } from '../knowledge/policy.js';
|
|
14
16
|
import { jsonArray } from '../platform/jsonArray.js';
|
|
15
17
|
import { z } from 'zod';
|
|
16
18
|
const patchOperationsParam = jsonArray(z.array(z.record(z.unknown())).min(1))
|
|
@@ -111,14 +113,16 @@ export function registerLayoutTools(server, platform) {
|
|
|
111
113
|
name: z.string().min(1),
|
|
112
114
|
views: viewsParam.optional(),
|
|
113
115
|
events: eventsParam.optional(),
|
|
114
|
-
parameters: z.record(z.unknown()).optional()
|
|
116
|
+
parameters: z.record(z.unknown()).optional(),
|
|
117
|
+
policyOverride: textHookOverrideParam
|
|
115
118
|
},
|
|
116
119
|
annotations: writes
|
|
117
|
-
}, handle(config, async ({ project, environment, applicationId, name, views, events, parameters }) => {
|
|
120
|
+
}, handle(config, async ({ project, environment, applicationId, name, views, events, parameters, policyOverride }) => {
|
|
118
121
|
const resolved = await resolveProfile(platform, applicationId);
|
|
119
122
|
const named = fillComponentNames(views);
|
|
120
123
|
assertScreenWriteGuards('layout', { schema: views, events }, resolved.profile.platform);
|
|
121
124
|
assertNoRetiredNodes(views);
|
|
125
|
+
const textFindings = await enforceTextHooks(config, { platform, project, environment, applicationId, after: views ?? [], where: `layout '${name}'` }, policyOverride);
|
|
122
126
|
const fixed = normalizeComponentDefaults(views);
|
|
123
127
|
const catalogNotes = await assertScreenCatalog(platform, project, environment, applicationId, views, 'layout_create');
|
|
124
128
|
const gaps = [
|
|
@@ -135,10 +139,10 @@ export function registerLayoutTools(server, platform) {
|
|
|
135
139
|
const normalized = withWriteDiff(withNormalization(response, [...componentNameNote(named), ...componentDefaultsNote(fixed), ...catalogNotes, ...slotWarning(views)]), drops);
|
|
136
140
|
const typeField = applicationTypeField(resolved);
|
|
137
141
|
if (!normalized || typeof normalized !== 'object')
|
|
138
|
-
return normalized;
|
|
142
|
+
return attachFindings(normalized, textFindings);
|
|
139
143
|
if (gaps.length === 0)
|
|
140
|
-
return Object.keys(typeField).length === 0 ? normalized : { ...normalized, ...typeField };
|
|
141
|
-
return { ...normalized, ...typeField, layoutWarnings: gaps };
|
|
144
|
+
return attachFindings(Object.keys(typeField).length === 0 ? normalized : { ...normalized, ...typeField }, textFindings);
|
|
145
|
+
return attachFindings({ ...normalized, ...typeField, layoutWarnings: gaps }, textFindings);
|
|
142
146
|
}));
|
|
143
147
|
server.registerTool('layout_update', {
|
|
144
148
|
title: 'Layout güncelle',
|
|
@@ -151,15 +155,24 @@ export function registerLayoutTools(server, platform) {
|
|
|
151
155
|
name: z.string().min(1).optional(),
|
|
152
156
|
views: viewsParam.optional(),
|
|
153
157
|
events: eventsParam.optional(),
|
|
154
|
-
parameters: z.record(z.unknown()).optional()
|
|
158
|
+
parameters: z.record(z.unknown()).optional(),
|
|
159
|
+
policyOverride: textHookOverrideParam
|
|
155
160
|
},
|
|
156
161
|
annotations: updates
|
|
157
|
-
}, handle(config, async ({ project, environment, applicationId, id, ...changes }) => {
|
|
162
|
+
}, handle(config, async ({ project, environment, applicationId, id, policyOverride, ...changes }) => {
|
|
158
163
|
const overrides = Object.fromEntries(Object.entries(changes).filter(([, value]) => value !== undefined));
|
|
159
164
|
const resolved = overrides.views === undefined ? undefined : await resolveProfile(platform, applicationId);
|
|
160
165
|
const named = fillComponentNames(overrides.views);
|
|
161
166
|
assertScreenWriteGuards('layout', { schema: overrides.views, events: overrides.events }, resolved?.profile.platform);
|
|
162
167
|
const current = await fetchHost(platform, 'layout', project, environment, applicationId, id);
|
|
168
|
+
const textFindings = overrides.views === undefined
|
|
169
|
+
? []
|
|
170
|
+
: await enforceTextHooks(config, {
|
|
171
|
+
platform, project, environment, applicationId,
|
|
172
|
+
after: overrides.views,
|
|
173
|
+
before: async () => current.views,
|
|
174
|
+
where: `layout '${String(current.name ?? id)}'`
|
|
175
|
+
}, policyOverride);
|
|
163
176
|
const fixed = normalizeComponentDefaults(overrides.views);
|
|
164
177
|
const catalogNotes = await assertScreenCatalog(platform, project, environment, applicationId, overrides.views, 'layout_update');
|
|
165
178
|
const body = layoutUpdateBody({ ...current, applicationId }, overrides);
|
|
@@ -175,7 +188,7 @@ export function registerLayoutTools(server, platform) {
|
|
|
175
188
|
const summary = { id, changed: Object.keys(overrides), preserved: { viewNodes: body.views.length } };
|
|
176
189
|
if (gaps.length > 0)
|
|
177
190
|
summary.layoutWarnings = gaps;
|
|
178
|
-
return withNormalization(summary, [...componentNameNote(named), ...componentDefaultsNote(fixed), ...catalogNotes, ...slotWarning(body.views)]);
|
|
191
|
+
return attachFindings(withNormalization(summary, [...componentNameNote(named), ...componentDefaultsNote(fixed), ...catalogNotes, ...slotWarning(body.views)]), textFindings);
|
|
179
192
|
}));
|
|
180
193
|
server.registerTool('layout_patch', {
|
|
181
194
|
title: "Layout'a patch uygula",
|
|
@@ -187,10 +200,11 @@ export function registerLayoutTools(server, platform) {
|
|
|
187
200
|
id: guid,
|
|
188
201
|
operations: patchOperationsParam.optional(),
|
|
189
202
|
ops: patchOperationsParam.optional().describe("'operations' ile aynı alan (eşanlamlı); JSON Patch işlemleriyle set_prop_type micro-op'ları KARIŞIK verilebilir"),
|
|
190
|
-
expectedUpdatedAt: z.string().optional().describe("layout_schema_get çıktısındaki updatedAt; eşleşmezse patch uygulanmaz (araya giren yazmayı ezmeyi engeller)")
|
|
203
|
+
expectedUpdatedAt: z.string().optional().describe("layout_schema_get çıktısındaki updatedAt; eşleşmezse patch uygulanmaz (araya giren yazmayı ezmeyi engeller)"),
|
|
204
|
+
policyOverride: textHookOverrideParam
|
|
191
205
|
},
|
|
192
206
|
annotations: updates
|
|
193
|
-
}, handle(config, async ({ project, environment, applicationId, id, operations: givenOperations, ops, expectedUpdatedAt }) => {
|
|
207
|
+
}, handle(config, async ({ project, environment, applicationId, id, operations: givenOperations, ops, expectedUpdatedAt, policyOverride }) => {
|
|
194
208
|
const operations = microOps('layout_patch', ops, givenOperations);
|
|
195
209
|
const current = await fetchHost(platform, 'layout', project, environment, applicationId, id);
|
|
196
210
|
const audit = current.audit;
|
|
@@ -235,6 +249,12 @@ export function registerLayoutTools(server, platform) {
|
|
|
235
249
|
const fixed = normalizeComponentDefaults(overrides.views);
|
|
236
250
|
const catalogNotes = await assertScreenCatalog(platform, project, environment, applicationId, overrides.views, 'layout_patch');
|
|
237
251
|
const body = layoutUpdateBody({ ...current, applicationId }, overrides);
|
|
252
|
+
const textFindings = await enforceTextHooks(config, {
|
|
253
|
+
platform, project, environment, applicationId,
|
|
254
|
+
after: body.views,
|
|
255
|
+
before: async () => original.views,
|
|
256
|
+
where: `layout '${String(current.name ?? id)}'`
|
|
257
|
+
}, policyOverride);
|
|
238
258
|
// Gövde değil FARK gönderilir: gateway normalizasyonları (komponent varsayılanları, katalog
|
|
239
259
|
// kuralları, value'suz olayların elenmesi) son hâle işlendikten sonra net diff hesaplanır.
|
|
240
260
|
const finalDocument = { ...patched, name: body.name, parameters: body.parameters, views: body.views, events: body.events };
|
|
@@ -261,13 +281,13 @@ export function registerLayoutTools(server, platform) {
|
|
|
261
281
|
summary.propTypes = propTypes.applied;
|
|
262
282
|
if (gaps.length > 0)
|
|
263
283
|
summary.layoutWarnings = gaps;
|
|
264
|
-
return withNormalization(summary, [
|
|
284
|
+
return attachFindings(withNormalization(summary, [
|
|
265
285
|
...componentNameNote(named),
|
|
266
286
|
...componentDefaultsNote(fixed),
|
|
267
287
|
...catalogNotes,
|
|
268
288
|
...slotWarning(body.views),
|
|
269
289
|
...resolved.notes.map(note => `patch yolu seçiciden indekse çözüldü: ${note}`)
|
|
270
|
-
]);
|
|
290
|
+
]), textFindings);
|
|
271
291
|
}));
|
|
272
292
|
server.registerTool('layout_delete', {
|
|
273
293
|
title: 'Layout sil',
|
package/dist/tools/merges.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { destructive, guid, pagingParams, readOnly, updates, writes } from './common.js';
|
|
1
|
+
import { destructive, guid, pagingParams, readOnly, templateSubscriptionLock, updates, writes } from './common.js';
|
|
2
2
|
import { handle } from '../platform/responses.js';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
const mergeView = z.enum(['summary', 'conflicts', 'full']).optional()
|
|
@@ -43,7 +43,7 @@ export function registerMergeTools(server, platform) {
|
|
|
43
43
|
const config = platform.config;
|
|
44
44
|
server.registerTool('merge_plan', {
|
|
45
45
|
title: 'Merge planı oluştur',
|
|
46
|
-
description:
|
|
46
|
+
description: `Bir dalı ebeveynine (development) merge etmek için üç yönlü diff planı ister. Hedef her zaman dalın ebeveynidir — production'a merge eden bir yol YOKTUR. title ZORUNLUDUR: isteğin adıdır ve geçmişte o adla durur. Asenkron: yanıt 202 döner, plan hemen dolu değildir. Projede açık bir plan varsa 400 döner; önce onu uygulayın ya da merge_discard ile bırakın. Süreç tanımları ve iş takvimleri planda modül olarak görünür (fark versions[…].model.nodes[<düğüm id>] yolunda); örnekler, görevler, defter ve uyarlamalar merge edilmez. ${templateSubscriptionLock}`,
|
|
47
47
|
inputSchema: { projectId: guid, sourceEnvironmentId: guid, title: mergeTitle, description: mergeDescription },
|
|
48
48
|
annotations: writes
|
|
49
49
|
}, handle(config, async ({ projectId, sourceEnvironmentId, title, description }) => {
|
|
@@ -61,7 +61,7 @@ export function registerMergeTools(server, platform) {
|
|
|
61
61
|
}, handle(config, ({ projectId, ...query }) => platform.org('GET', `/merges/${projectId}`, { query })));
|
|
62
62
|
server.registerTool('merge_get', {
|
|
63
63
|
title: 'Merge planını oku',
|
|
64
|
-
description: "Bir merge planını döner. items[] yalnız DEĞİŞEN kayıtları taşır; her kayıtta kind (add|update|delete|conflict) ve elements[] vardır. Çakışan elemanlarda base/source/target üç değeri birden gelir. dataRisk: true olan kalemde SEBEP dataRiskReasons[] içindedir: 'field-removed' (alan siliniyor), 'field-narrowed' (tip/nullable/unique daraltılıyor), 'not-null-without-default-on-populated-table' (hedefte satır varken varsayılansız NOT NULL alan ekleniyor — bu apply'ı DDL aşamasında düşürür, alanı nullable yapın ya da varsayılan verin), 'table-removed' (hedefte satırı olan tablo siliniyor). dataRisk bir UYARIDIR, apply'ı bloklamaz. items[].dependents[] ({ id, name, module }) dolu olan kalem, DALIN SİLDİĞİ ama development'ın dal açıldıktan sonra kullanmaya başladığı kayıttır: silme ÇAKIŞMAYA döner; hedef lehine çözüm kaydı ve bağımlısını korur, kaynak lehine çözüm siler (bağımlı FK ile düşebilir). Sorgunun çıktı DTO'su ve alanları aynı çakışma grubuna girer. Süreç kenarlarında (edges) iki taraf AYNI geçidin çıkışlarına dokunduysa yol 'versions[id=…].model.edges{from=<düğüm>}' olan TEK çakışma gelir; farklı geçitler kendiliğinden birleşir. Merge çevirileri (translation, adı 'key') ve microfunction'ları da taşır; microfunction hedefte TASLAK kalır, yayını kullanıcı yapar. derivedFromKey dolu olan kalem OTOMATİK ÜRETİLMİŞ bir kayıttır (varsayılan DTO); kaynağını (entity ya da query) çözdüğünüzde aynı yoldaki çakışması aynı tarafa KENDİLİĞİNDEN çözülür — ayrı ayrı ve zıt çözülemez. Uygulanmış planlarda title, description, createdBy ve appliedBy da gelir. kind=revert ise bu bir geri alma planıdır: revertsPlanId geri aldığı planı verir ve elements'te source merge ÖNCESİ, target ŞİMDİKİ değerdir. isStale: true ise plan alındığından beri DAL ya da development değişmiştir: items o değişikliği taşimaz ve merge_apply 409 döner — merge_refresh ile planı tazeleyin. elements[].isNoise: true olan eleman GÖSTERİM gürültüsüdür — kanvasın kendi durumu (workflow schema), DTO'dan türetilen şema (microservice schema.parameterScheme/returnScheme), sunucu yönetimli anahtar; merge gövdesinde KALIR ve uygulanır, yalnız okurken atlanır. Çakışan eleman asla işaretlenmez. items[].references[] o kalemin gövdesindeki guid'lerin karşılığıdır ({ id, name, module }): bir table step'in rule.entityId'si hangi tabloya, bir branch'in nextStepId'si hangi adıma, bir filtrenin fieldId'si hangi alana işaret ediyor — plan dışına çıkmadan okunur. items[].parentKey dolu olan kayıt başka bir kaydın çocuğudur (DTO çocukları, iç içe klasörler); ebeveyniyle birlikte okunur. items[].recordType kaydın modül içindeki türüdür — bir workflow kaydı 'workflow', 'automation' ya da 'middleware' olabilir ve modül üçüne de workflow der. items[].hiddenFields o kaydın GÖVDESİNDE okunmayacak anahtarlardır (aynı politika; eklenen/silinen kayıt tek eleman olarak geldiği için yolun değil anahtarın sorusudur). Bir taraf prop'un TİPİNİ (valueType: static → code) değiştirip öbür taraf da tipine ya da değerine (ref/data) dokunduysa eleman prop'un KENDİSİDİR: yol '…props[id=…]', base/source/target prop gövdesi, combinable: false — tip ile değer tek karardır. Nesne prop'unda (icon, surfaceStyle) anahtarın değeri '…ref.<anahtar>…', çizilen satırı '…children[name=<anahtar>]…' yolundadır; ikisi de çakışırsa kararı ref'e verin — satır karar istemez, unresolved'a sayılmaz; merge onu değerin birleşik hâlinden kurar. ÇÖZÜM DEĞER TAŞIR: elements[].combinable: true olan çakışma (kimliksiz ya da gruplu liste) both ile birleştirilebilir; elements[].value both/custom çözümünün yazılacak değeridir. kind='duplicate' OLASI KOPYADIR: iki taraf aynı içeriği farklı kimlikle eklemiş, twinPath development'taki ikizdir. combinable: true olan kopya ENGELLEMEZ — çözümsüzse ikisi de yazılır; kopyalar aynı slug'ı taşıyorsa (tablo alanı = kolon, sayfa = rota) combinable: false gelir, ikisi birden kalamaz: unresolved sayılır, both reddedilir, birini seçmek gerekir. Tablo alanında slug, bileşen prop'unda ad TEKİLDİR: içerik farklı olsa da aynı slug'lı alan ya da aynı adlı prop eklemesi combinable: false kopyadır; aynı ad farklı slug'lı iki alan ayrı eklenir (name-clash uyarısı). Development tabanda var olan bir alanı dalın eklediği slug'a yeniden adlandırdıysa dalın alanı yine duplicate gelir; base doludur (alanın taban hâli) ve source 400 döner — veri taşıyan alan silinmez, target ya da custom seçilir. target dalınkini düşürür, source development'ınkini çıkarır, custom tek öğe yazar; düşen kopyadan türemiş DTO alanı da düşer. summary.duplicates çözümsüz kopya sayısıdır. items[].derivedFromPath dolu olan DTO alanı tablo alanına bağlıdır (fields[id=…]); tablo alanı kararı ona kendiliğinden geçer. checks: true merge öncesi doğrulamayı da ekler: unresolved (error) · duplicate-open · name-clash (aynı adla iki kardeş) · dangling-reference (merge'ün düşürdüğü kimliğe kalan başvuru) — uyarılar engellemez, merge_apply'dan önce okunur.",
|
|
64
|
+
description: "Bir merge planını döner. items[] yalnız DEĞİŞEN kayıtları taşır; her kayıtta kind (add|update|delete|conflict) ve elements[] vardır. Çakışan elemanlarda base/source/target üç değeri birden gelir. dataRisk: true olan kalemde SEBEP dataRiskReasons[] içindedir: 'field-removed' (alan siliniyor), 'field-narrowed' (tip/nullable/unique daraltılıyor), 'not-null-without-default-on-populated-table' (hedefte satır varken varsayılansız NOT NULL alan ekleniyor — bu apply'ı DDL aşamasında düşürür, alanı nullable yapın ya da varsayılan verin), 'table-removed' (hedefte satırı olan tablo siliniyor). dataRisk bir UYARIDIR, apply'ı bloklamaz. items[].dependents[] ({ id, name, module }) dolu olan kalem, DALIN SİLDİĞİ ama development'ın dal açıldıktan sonra kullanmaya başladığı kayıttır: silme ÇAKIŞMAYA döner; hedef lehine çözüm kaydı ve bağımlısını korur, kaynak lehine çözüm siler (bağımlı FK ile düşebilir). Sorgunun çıktı DTO'su ve alanları aynı çakışma grubuna girer. Süreç kenarlarında (edges) iki taraf AYNI geçidin çıkışlarına dokunduysa yol 'versions[id=…].model.edges{from=<düğüm>}' olan TEK çakışma gelir; farklı geçitler kendiliğinden birleşir. Merge çevirileri (translation, adı 'key') ve microfunction'ları da taşır; microfunction hedefte TASLAK kalır, yayını kullanıcı yapar. Kayıt taşıma ayarı açık tabloların SATIRLARI da gelir: module='row' kalemi bir tablodur (recordId entity kimliği, name tablo adı), satır farkı 'rows.<anahtar>', hücre farkı 'rows.<anahtar>.<sütun>' yolundadır; yalnız dalın değişiklikleri kalem üretir, development'ın kendi satırları plana girmez. İki taraf tabanda olmayan aynı anahtarla farklı satır açtıysa 'rows.<anahtar>' yolunda base'i boş TEK çakışma gelir (kimlik çakışması) — ayrıntı rehberde (Tablo kayıtları). derivedFromKey dolu olan kalem OTOMATİK ÜRETİLMİŞ bir kayıttır (varsayılan DTO); kaynağını (entity ya da query) çözdüğünüzde aynı yoldaki çakışması aynı tarafa KENDİLİĞİNDEN çözülür — ayrı ayrı ve zıt çözülemez. Uygulanmış planlarda title, description, createdBy ve appliedBy da gelir. kind=revert ise bu bir geri alma planıdır: revertsPlanId geri aldığı planı verir ve elements'te source merge ÖNCESİ, target ŞİMDİKİ değerdir. isStale: true ise plan alındığından beri DAL ya da development değişmiştir: items o değişikliği taşimaz ve merge_apply 409 döner — merge_refresh ile planı tazeleyin. elements[].isNoise: true olan eleman GÖSTERİM gürültüsüdür — kanvasın kendi durumu (workflow schema), DTO'dan türetilen şema (microservice schema.parameterScheme/returnScheme), sunucu yönetimli anahtar; merge gövdesinde KALIR ve uygulanır, yalnız okurken atlanır. Çakışan eleman asla işaretlenmez. items[].references[] o kalemin gövdesindeki guid'lerin karşılığıdır ({ id, name, module }): bir table step'in rule.entityId'si hangi tabloya, bir branch'in nextStepId'si hangi adıma, bir filtrenin fieldId'si hangi alana işaret ediyor — plan dışına çıkmadan okunur. items[].parentKey dolu olan kayıt başka bir kaydın çocuğudur (DTO çocukları, iç içe klasörler); ebeveyniyle birlikte okunur. items[].recordType kaydın modül içindeki türüdür — bir workflow kaydı 'workflow', 'automation' ya da 'middleware' olabilir ve modül üçüne de workflow der. items[].hiddenFields o kaydın GÖVDESİNDE okunmayacak anahtarlardır (aynı politika; eklenen/silinen kayıt tek eleman olarak geldiği için yolun değil anahtarın sorusudur). Bir taraf prop'un TİPİNİ (valueType: static → code) değiştirip öbür taraf da tipine ya da değerine (ref/data) dokunduysa eleman prop'un KENDİSİDİR: yol '…props[id=…]', base/source/target prop gövdesi, combinable: false — tip ile değer tek karardır. Nesne prop'unda (icon, surfaceStyle) anahtarın değeri '…ref.<anahtar>…', çizilen satırı '…children[name=<anahtar>]…' yolundadır; ikisi de çakışırsa kararı ref'e verin — satır karar istemez, unresolved'a sayılmaz; merge onu değerin birleşik hâlinden kurar. ÇÖZÜM DEĞER TAŞIR: elements[].combinable: true olan çakışma (kimliksiz ya da gruplu liste) both ile birleştirilebilir; elements[].value both/custom çözümünün yazılacak değeridir. kind='duplicate' OLASI KOPYADIR: iki taraf aynı içeriği farklı kimlikle eklemiş, twinPath development'taki ikizdir. combinable: true olan kopya ENGELLEMEZ — çözümsüzse ikisi de yazılır; kopyalar aynı slug'ı taşıyorsa (tablo alanı = kolon, sayfa = rota) combinable: false gelir, ikisi birden kalamaz: unresolved sayılır, both reddedilir, birini seçmek gerekir. Tablo alanında slug, bileşen prop'unda ad TEKİLDİR: içerik farklı olsa da aynı slug'lı alan ya da aynı adlı prop eklemesi combinable: false kopyadır; aynı ad farklı slug'lı iki alan ayrı eklenir (name-clash uyarısı). Development tabanda var olan bir alanı dalın eklediği slug'a yeniden adlandırdıysa dalın alanı yine duplicate gelir; base doludur (alanın taban hâli) ve source 400 döner — veri taşıyan alan silinmez, target ya da custom seçilir. target dalınkini düşürür, source development'ınkini çıkarır, custom tek öğe yazar; düşen kopyadan türemiş DTO alanı da düşer. summary.duplicates çözümsüz kopya sayısıdır. items[].derivedFromPath dolu olan DTO alanı tablo alanına bağlıdır (fields[id=…]); tablo alanı kararı ona kendiliğinden geçer. checks: true merge öncesi doğrulamayı da ekler: unresolved (error) · not-applicable (error: kararın yazılacağı yer development'ta yok — apply düşer; merge_refresh edip o yolda yeniden karar ver) · duplicate-open · name-clash (aynı adla iki kardeş) · dangling-reference (merge'ün düşürdüğü kimliğe kalan başvuru) — uyarılar engellemez, merge_apply'dan önce okunur.",
|
|
65
65
|
inputSchema: {
|
|
66
66
|
projectId: guid,
|
|
67
67
|
planId: guid,
|
|
@@ -81,7 +81,7 @@ export function registerMergeTools(server, platform) {
|
|
|
81
81
|
}));
|
|
82
82
|
server.registerTool('merge_resolve', {
|
|
83
83
|
title: 'Merge çakışmalarını çöz',
|
|
84
|
-
description:
|
|
84
|
+
description: `Çakışan elemanlar ve olası kopyalar için kararı plana yazar: source (dal), target (development), both (iki tarafın birleşimi — yalnız combinable: true elemanda; kopyada ikisini de tut; tablo satırının kimlik çakışmasında development'ın satırı kalır, dalın satırı YENİ ANAHTARLA eklenir, metin anahtarda 400) ya da custom (value'daki değer). Yalnız status=planned iken çalışır. path boş bırakılırsa o kaydın tüm çakışmaları aynı karara çözülür. Türetilmiş kaydı (varsayılan DTO) kaynağına zıt çözmek 400 döner. YANIT ÖZETTİR: { planId, status, summary, resolved } — platform planın tamamını döner ama gateway onu kesip yalnız sayaçları verir (orta boy planda tam gövde 68-121 KB'a çıkıyor ve yanıt sınırını aşıyordu; çağrı hata gibi görünürken çözüm UYGULANMIŞ oluyordu). Planın kendisini görmek için merge_get { planId, view:'conflicts' } çağırın; kalan çakışma sayısı summary.unresolved'dadır. ${templateSubscriptionLock}`,
|
|
85
85
|
inputSchema: { projectId: guid, planId: guid, resolutions: z.array(resolution).min(1) },
|
|
86
86
|
annotations: updates
|
|
87
87
|
}, handle(config, async ({ projectId, planId, resolutions }) => {
|
|
@@ -90,7 +90,7 @@ export function registerMergeTools(server, platform) {
|
|
|
90
90
|
}));
|
|
91
91
|
server.registerTool('merge_apply', {
|
|
92
92
|
title: 'Merge planını uygula',
|
|
93
|
-
description:
|
|
93
|
+
description: `Planı tek transaction'da development'a uygular ve dalın şemasını düşürür. İsteğin adı zaten plan açılırken verilir; apply ayrı bir mesaj almaz. Asenkron: yanıt 202 döner. Çözülmemiş çakışma varsa 409 döner. PLAN BAYATSA DA 409 döner: plan alındıktan sonra DAL ya da development değiştiyse apply reddedilir — plan dalın o anki fotoğrafını taşır, uygulansaydı sonradan yapılan iş sessizce düşerdi. Çözümü merge_refresh'tir; yeni plan açmanız gerekmez. ${templateSubscriptionLock}`,
|
|
94
94
|
inputSchema: { projectId: guid, planId: guid },
|
|
95
95
|
annotations: writes
|
|
96
96
|
}, handle(config, async ({ projectId, planId }) => {
|
|
@@ -102,7 +102,7 @@ export function registerMergeTools(server, platform) {
|
|
|
102
102
|
}));
|
|
103
103
|
server.registerTool('merge_refresh', {
|
|
104
104
|
title: 'Merge planını tazele',
|
|
105
|
-
description:
|
|
105
|
+
description: `Açık bir planı dalın ve development'ın ŞU ANKİ hâline göre yeniden hesaplatır. İstek yerinde kalır: id'si, başlığı, açıklaması ve geçmişi korunur — yalnız değişiklik listesi yenilenir. DEĞİŞMEYEN ELEMANIN KARARI KORUNUR: aynı kalem, aynı yol ve üç tarafı (base/source/target) aynı kalan elemanın kararı ve değeri yeni plana taşınır; değişenler yeniden sorulur (etkinlikte merge.resolutions_carried { carried, dropped }). Yalnız status=planned bir planda çalışır ve dal ready olmalıdır. Bayat bir planı (merge_get → isStale: true, ya da merge_apply 409) düzeltmenin yolu budur; merge_discard + merge_plan istemez. Asenkron: yanıt 202, plan planning durumundadır — merge_get ile planned bekleyin. ${templateSubscriptionLock}`,
|
|
106
106
|
inputSchema: { projectId: guid, planId: guid },
|
|
107
107
|
annotations: writes
|
|
108
108
|
}, handle(config, async ({ projectId, planId }) => {
|
|
@@ -114,7 +114,7 @@ export function registerMergeTools(server, platform) {
|
|
|
114
114
|
}));
|
|
115
115
|
server.registerTool('merge_revert', {
|
|
116
116
|
title: "Uygulanmış merge'i geri al",
|
|
117
|
-
description:
|
|
117
|
+
description: `Uygulanmış bir merge'i geri alan YENİ bir plan açar; kaynak plan silinmez, reverted olur ve geçmişte kalır. Yalnız status=applied|applied-with-drift ve kind=merge planlar geri alınabilir, pencere RevertWindowDays (varsayılan 7 gün) — dışında 400 döner. Ters plan kaynak plandaki her işlemi tersine çevirir: eklenen kayıt silinir, silinen geri gelir, değişen eski gövdesine döner; tablo satırları (module='row') da aynı kuralla döner. Merge'den SONRA elle değiştirilen kayıtlar conflict gelir ve orada source = merge öncesi değer, target = şimdiki değer demektir. Asenkron: yanıt 202, ters plan planning durumundadır. ${templateSubscriptionLock}`,
|
|
118
118
|
inputSchema: { projectId: guid, planId: guid },
|
|
119
119
|
annotations: writes
|
|
120
120
|
}, handle(config, async ({ projectId, planId }) => {
|
|
@@ -126,7 +126,7 @@ export function registerMergeTools(server, platform) {
|
|
|
126
126
|
}));
|
|
127
127
|
server.registerTool('merge_discard', {
|
|
128
128
|
title: 'Merge planından vazgeç',
|
|
129
|
-
description:
|
|
129
|
+
description: `Planı uygulamadan kapatır. Uygulanmakta olan (status=applying) bir plan bırakılamaz — 400 döner. Dal ve şeması olduğu gibi kalır. ${templateSubscriptionLock}`,
|
|
130
130
|
inputSchema: { projectId: guid, planId: guid },
|
|
131
131
|
annotations: destructive
|
|
132
132
|
}, handle(config, ({ projectId, planId }) => platform.org('DELETE', `/merges/${projectId}/${planId}`)));
|
|
@@ -2,7 +2,7 @@ import { guid, projectParam, environmentParam, pagingParams, readOnly, writes, u
|
|
|
2
2
|
import { constraintSummary } from '../knowledge/backendConstraints.js';
|
|
3
3
|
import { unmappedMembers, withUnmappedMembers } from '../knowledge/schemaGuard.js';
|
|
4
4
|
import { evaluatePolicy, enforcePolicy, attachFindings } from '../knowledge/policy.js';
|
|
5
|
-
import { policyRules } from '../knowledge/rules.js';
|
|
5
|
+
import { policyRules, microfunctionArchiveEntrypointFindings } from '../knowledge/rules.js';
|
|
6
6
|
import { handle } from '../platform/responses.js';
|
|
7
7
|
import { z } from 'zod';
|
|
8
8
|
const policyOverrideParam = z.boolean().optional()
|
|
@@ -19,7 +19,7 @@ const definitionInput = {
|
|
|
19
19
|
language: z.enum(['node', 'python']).describe("Çalışma dili. Inline kaynakta dosya adı sabittir: node → function.js (exports.handler = async (args, context) => …), python → function.py (def handler(args, context))"),
|
|
20
20
|
provider: z.enum(['built-in', 'aws-lambda']).describe("'built-in' platformun kendi Fission kümesinde koşar ve runtime hesabı İSTEMEZ (runtimeId boş kalır); 'aws-lambda' müşterinin kendi hesabında koşar ve runtimeId ZORUNLUDUR. 'azure-functions' enum'da tanımlı ama v1'de reddedilir (Faz 2)"),
|
|
21
21
|
runtimeId: guid.optional().describe("AWS Lambda hesabı (microfunction_runtime_list). provider 'built-in' ise VERİLMEZ; 'aws-lambda' ise zorunlu ve hesabın provider'ı fonksiyonunkiyle aynı olmalı"),
|
|
22
|
-
sourceKind: z.enum(['inline', 'archive']).describe("'inline' ⇒ code zorunlu (≤ 512 KB
|
|
22
|
+
sourceKind: z.enum(['inline', 'archive']).describe("'inline' ⇒ code zorunlu (≤ 512 KB); dış paketler dependencies ile bildirilir. 'archive' ⇒ entrypoint 'modül.fonksiyon' olarak verilir; dosyalar zip'in içinde yaşar ve microfunction_archive_scaffold (iskelet) + microfunction_files_apply ile yazılır — paketler zip'teki requirements.txt / package.json'dadır, dependencies yok sayılır. Tek parça zip yükleme MCP'de yok (Studio'dan)"),
|
|
23
23
|
code: z.string().optional().describe("Inline kaynak kodu. Sözleşme: tek bir handler dışa aktarılır, args çağrı argümanları, context SALT OKUNUR anlık görüntüdür (input/variables/steps/user/request/language/project/environment). Yazma yalnız dönüş değeriyle olur. Ayrıntı: platform_guide('microfunction')"),
|
|
24
24
|
entrypoint: z.string().optional().describe("Zip kaynağında 'modül.fonksiyon' (ör. 'handlers/sum.handler'). Inline kaynakta gateway'in de platformun da beklediği sabit 'function.handler'dır — vermeyin"),
|
|
25
25
|
parameterDtoId: guid.optional().describe("Çağrı argümanlarının sözleşmesi (DataTransferObject). Workflow step'i ifadeyi bu şemaya göre yazar; boşsa args = {} gider"),
|
|
@@ -29,8 +29,17 @@ const definitionInput = {
|
|
|
29
29
|
timeoutSeconds: z.number().int().min(1).max(900).optional().describe("Fonksiyon bütçesi; varsayılan 30. Built-In üst sınırı 300, Lambda 900. Bütçe dolarsa çağrı MicrofunctionInvocationTimeoutException ile step'in fail dalına düşer"),
|
|
30
30
|
memoryMb: z.number().int().min(128).max(3008).optional().describe("Varsayılan 256. Built-In'de yalnız kaydedilir (küme environment limiti geçerlidir); Lambda'da gerçekten uygulanır"),
|
|
31
31
|
environmentVariables: environmentVariablesParam.optional(),
|
|
32
|
+
dependencies: z.string().optional().describe("Inline kaynağın dış paketleri, SATIR BAŞINA BİR PAKET (≤ 16 KB; boş ve '#' satırları yorum). python: requirements.txt satırı olduğu gibi — 'pillow==11.1.0', 'requests>=2.32'; pip seçeneği ('-r', '--index-url', '-e') YASAK. node: 'ad@aralık' — 'sharp@^0.33.0', '@scope/ad@1.2', aralıksız 'dayjs' → latest. Built-In'de yayın paketleri Fission builder'da kurar: yayın build süresince (5 dk'ya kadar) 'publishing' kalır, kurulum düşerse publish-failed ve publishError'da build günlüğünün son 4 KB'ı. aws-lambda'da KURULMAZ (MF-007) — paketler zip'te gelmeli. archive kaynağında yok sayılır (manifest zip'te). Built-In Python 3.13, Node 22 (Lambda'daki sürümlerle aynı); C uzantılı paketler (Pillow gibi) hazır wheel'den kurulur"),
|
|
33
|
+
testArguments: z.string().optional().describe("Studio Test call'unun kayıtlı argüman metni (≤ 64 KB, MicrofunctionTestArgumentsTooLarge); olduğu gibi saklanır, JSON geçerliliği DENETLENMEZ ve koşuma girmez. update TAM GÖVDEDİR: verilmezse kayıtlı metin silinir — önce microfunction_get'ten alın. Kaydetmek revision'ı artırır (yayındaki kayıt hasUnpublishedChanges: true olur)"),
|
|
32
34
|
publish: z.boolean().optional().describe("true: kayıt açıldıktan/güncellendikten sonra aynı çağrıda yayın istenir ('Kaydet ve yayınla'). Yayın ASENKRONDUR — çağrı status: 'publishing' döner; sonucu microfunction_get ile izleyin (published | publish-failed + publishError)")
|
|
33
35
|
};
|
|
36
|
+
const archiveOperationInput = z.object({
|
|
37
|
+
type: z.enum(['write-file', 'create-directory', 'delete', 'rename']).describe("write-file: dosyayı oluşturur ya da içeriğini değiştirir · create-directory: boş klasör · delete: dosya ya da klasör (altındaki HER girdiyle) · rename: dosya ya da klasörü newPath'e taşır (klasörse altındakilerle)"),
|
|
38
|
+
path: z.string().min(1).describe("Zip içindeki yol, '/' ayraçlı: 'main.js', 'lib/util.js'. Kökle (/) başlamaz, / ile bitmez; boş, '.' ve '..' segmenti ve ters bölü içermez. Klasör yolu da sondaki / OLMADAN yazılır ('lib')"),
|
|
39
|
+
content: z.string().optional().describe("write-file için zorunlu. Metin dosyasında düz metin; ikili dosyada base64 + encoding: 'base64' (MCP'den tek dosya ≤ 8 MB)"),
|
|
40
|
+
encoding: z.enum(['utf8', 'base64']).optional().describe("content'in kodlaması; varsayılan utf8"),
|
|
41
|
+
newPath: z.string().optional().describe('rename için zorunlu hedef yol; path ile aynı kurallar. Hedef dolu olamaz, klasör kendi altına taşınamaz')
|
|
42
|
+
});
|
|
34
43
|
const runtimeInput = {
|
|
35
44
|
name: z.string().min(1).max(255).describe('Hesap adı; benzersiz'),
|
|
36
45
|
provider: z.literal('aws-lambda').optional().describe("v1'de yalnız 'aws-lambda' kabul edilir; gönderilmezse gateway onu koyar"),
|
|
@@ -101,11 +110,52 @@ export function registerMicrofunctionTools(server, platform) {
|
|
|
101
110
|
project: projectParam,
|
|
102
111
|
environment: environmentParam,
|
|
103
112
|
id: guid,
|
|
104
|
-
args: z.
|
|
113
|
+
args: z.unknown().optional().describe("Handler'ın ilk parametresi; herhangi bir JSON değeri. parameterBehavior 'object' ⇒ nesne, 'array' ⇒ dizi, 'primitive' ⇒ tek değer (workflow step'inin gönderdiği şekille aynı). parameterDtoId varsa o şemaya uymalı; boşsa {} gider"),
|
|
105
114
|
preview: z.boolean().optional().describe("true: shim logları (console.log/print) zarfın logs alanında döner. false/boş: logs boş gelir — hata ayıklarken açın")
|
|
106
115
|
},
|
|
107
116
|
annotations: updates
|
|
108
117
|
}, handle(config, ({ project, environment, id, args, preview }) => platform.tenant('POST', project, `/microfunctions/${id}/invoke`, { environment, body: { args, preview } })));
|
|
118
|
+
server.registerTool('microfunction_files_list', {
|
|
119
|
+
title: 'Microfunction arşiv dosyalarını listele',
|
|
120
|
+
description: "Zip kaynaklı microfunction'ın arşivindeki dosya ve klasörleri listeler: { hash, entries: [{ path, size, isDirectory }] }. Yalnız zip'te açık girdisi olan klasörler listelenir; ara klasörler dosya yollarından çıkar. microfunction_files_apply'a vereceğiniz expectedHash BURADAN gelir — yazmadan önce bu tool'u çağırın. Arşiv yoksa hash null ve liste boştur: sıfırdan başlamak için microfunction_archive_scaffold.",
|
|
121
|
+
inputSchema: { project: projectParam, environment: environmentParam, id: guid },
|
|
122
|
+
annotations: readOnly
|
|
123
|
+
}, handle(config, ({ project, environment, id }) => platform.tenant('GET', project, `/microfunctions/${id}/archive/entries`, { environment })));
|
|
124
|
+
server.registerTool('microfunction_file_get', {
|
|
125
|
+
title: 'Microfunction arşiv dosyasını oku',
|
|
126
|
+
description: "Arşivdeki tek dosyanın içeriğini döner: { path, size, isBinary, content }. 1 MB'ı aşan ya da UTF-8 metin olmayan dosyada isBinary: true ve content boştur — içeriği görmek için zip'in tamamı Studio'dan indirilir. Yol yoksa ya da klasörse 404.",
|
|
127
|
+
inputSchema: {
|
|
128
|
+
project: projectParam,
|
|
129
|
+
environment: environmentParam,
|
|
130
|
+
id: guid,
|
|
131
|
+
path: z.string().min(1).describe("Zip içindeki dosya yolu, microfunction_files_list'teki path ile aynı: 'lib/util.js'")
|
|
132
|
+
},
|
|
133
|
+
annotations: readOnly
|
|
134
|
+
}, handle(config, ({ project, environment, id, path }) => platform.tenant('GET', project, `/microfunctions/${id}/archive/file`, { environment, query: { path } })));
|
|
135
|
+
server.registerTool('microfunction_files_apply', {
|
|
136
|
+
title: 'Microfunction arşiv dosyalarını değiştir',
|
|
137
|
+
description: "Arşive bir dizi dosya işlemini TEK seferde uygular; platform yeni zip üretir, kayıt yeni archiveHash alır, revision artar ve eski zip nesnesi silinir. İşlemler SIRAYLA uygulanır. expectedHash microfunction_files_list'ten okunan hash'tir: kayıt o arada değiştiyse 409 (MicrofunctionArchiveConflictException) döner ve hiçbir şey yazılmaz — listeyi yeniden okuyup işlemleri ona göre kurun. Arşivi olmayan kayıtta expectedHash VERİLMEZ. Kayıt yayındaysa runtime eski sürümü koşmaya devam eder: yeni kod için microfunction_publish; yayın, entrypoint modülü zip'te yoksa 400 döner. " + constraintSummary('ApplyMicrofunctionArchiveChangesCommand'),
|
|
138
|
+
inputSchema: {
|
|
139
|
+
project: projectParam,
|
|
140
|
+
environment: environmentParam,
|
|
141
|
+
id: guid,
|
|
142
|
+
expectedHash: z.string().optional().describe("microfunction_files_list'in döndürdüğü hash; arşiv yoksa verilmez"),
|
|
143
|
+
operations: z.array(archiveOperationInput).describe('Sırayla uygulanan işlemler; en az 1'),
|
|
144
|
+
policyOverride: policyOverrideParam
|
|
145
|
+
},
|
|
146
|
+
annotations: updates
|
|
147
|
+
}, handle(config, async ({ project, environment, id, policyOverride, ...body }) => {
|
|
148
|
+
const findings = enforcePolicy(evaluatePolicy(config, policyRules, 'microfunctionArchive', body, { operation: 'update' }, policyOverride));
|
|
149
|
+
const entrypointFindings = await microfunctionArchiveEntrypointFindings(platform, project, environment, id, body.operations);
|
|
150
|
+
const drift = unmappedMembers('ApplyMicrofunctionArchiveChangesCommand', body);
|
|
151
|
+
return attachFindings(withUnmappedMembers(await platform.tenant('POST', project, `/microfunctions/${id}/archive/changes`, { environment, body }), drift), [...findings, ...entrypointFindings]);
|
|
152
|
+
}));
|
|
153
|
+
server.registerTool('microfunction_archive_scaffold', {
|
|
154
|
+
title: 'Microfunction arşiv iskeleti oluştur',
|
|
155
|
+
description: "Arşivi olmayan kayda dilin iskelet dosyalarını yazar ve kaydı zip kaynağına çevirir: node → main.js + package.json (boş dependencies), python → main.py + requirements.txt (yalnız yorum); entrypoint ikisinde de 'main.handler' olur. Paketler bu manifest dosyalarına yazılır (microfunction_files_apply) ve Built-In yayında kurulur. Arşiv zaten varsa 409 — mevcut dosyaları microfunction_files_list ile okuyun. Node'da giriş modülü index.js OLAMAZ: index.js platform shim'inin adıdır ve yayın bunu 400 ile reddeder.",
|
|
156
|
+
inputSchema: { project: projectParam, environment: environmentParam, id: guid },
|
|
157
|
+
annotations: writes
|
|
158
|
+
}, handle(config, ({ project, environment, id }) => platform.tenant('POST', project, `/microfunctions/${id}/archive/scaffold`, { environment })));
|
|
109
159
|
server.registerTool('microfunction_runtime_list', {
|
|
110
160
|
title: 'Microfunction runtime hesaplarını listele',
|
|
111
161
|
description: "Bulut runtime hesaplarını (v1: AWS Lambda) listeler; secretAccessKey maskeli döner. Built-In fonksiyonların runtime kaydı YOKTUR — liste boşsa yalnız provider: 'built-in' fonksiyon tanımlayabilirsiniz.",
|