@appaflytech/zeyrek-ai-mcp 0.0.15 → 0.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -13
- package/dist/knowledge/componentCatalog.js +9 -9
- package/dist/knowledge/componentEvents.js +1 -1
- package/dist/knowledge/rules.js +21 -0
- package/dist/platform/diagnostics.js +85 -0
- package/dist/platform/ifExists.js +129 -0
- package/dist/platform/responses.js +2 -1
- package/dist/platform/strictArguments.js +22 -2
- package/dist/platform/writeDiff.js +58 -31
- package/dist/platform/writeView.js +17 -0
- package/dist/resources/guides/functions.md +31 -2
- package/dist/resources/guides/getting-started.md +35 -0
- package/dist/resources/guides/page.md +1 -1
- package/dist/resources/guides/translation.md +4 -5
- package/dist/resources/schema-fingerprint.json +3 -3
- package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +18 -0
- package/dist/tools/designSchemaPatch.js +3 -3
- package/dist/tools/flows.js +35 -41
- package/dist/tools/functions.js +20 -10
- package/dist/tools/microservices.js +39 -11
- package/dist/tools/pages.js +55 -12
- package/dist/tools/workflows.js +39 -12
- package/package.json +1 -1
package/dist/tools/pages.js
CHANGED
|
@@ -6,8 +6,9 @@ import { fetchComponentEventNames } from './components.js';
|
|
|
6
6
|
import { assertScreenWriteGuards, screenCatalogNotes } from './screenWrite.js';
|
|
7
7
|
import { opsParam, writeViewParam, outlineWriteResponse, unknownEventOps, collectTypes, simulateLayoutOps, planEventRemovals, resizeServerOps, planResizes, planPropTypes, rejectedOpsMessage } from './schemaOps.js';
|
|
8
8
|
import { formBindingWarnings, formSubmitButtonWarnings } from '../knowledge/coverage.js';
|
|
9
|
-
import {
|
|
9
|
+
import { emptyWriteDiff, schemaOpDrops, unwrapProps, withWriteDiff, writeDiff } from '../platform/writeDiff.js';
|
|
10
10
|
import { PlatformApiError } from '../platform/errors.js';
|
|
11
|
+
import { existingMatch, ifExistsParam, listAll, withOutcome } from '../platform/ifExists.js';
|
|
11
12
|
import { handle, toolResult, toolError } from '../platform/responses.js';
|
|
12
13
|
import { StudioScreenshotter } from '../platform/screenshot.js';
|
|
13
14
|
import { diffSummaries, summaryLines, summaryStats } from '../platform/domSummary.js';
|
|
@@ -55,6 +56,10 @@ async function orderByIndex(ops, readPage) {
|
|
|
55
56
|
return { ops, moved: [], warnings: [] };
|
|
56
57
|
}
|
|
57
58
|
}
|
|
59
|
+
/** Şema ağacındaki TÜM düğümler (kök + iç içe çocuklar); page_get ve page_create özeti aynı sayımı kullanır. */
|
|
60
|
+
function countSchemaNodes(nodes) {
|
|
61
|
+
return (nodes ?? []).reduce((total, node) => total + 1 + countSchemaNodes(node.children), 0);
|
|
62
|
+
}
|
|
58
63
|
async function fetchPage(platform, project, environment, applicationId, pageId) {
|
|
59
64
|
const response = await platform.tenant('GET', project, `/pages/${applicationId}/${pageId}`, { environment });
|
|
60
65
|
return response?.data ?? {};
|
|
@@ -101,7 +106,6 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
|
|
|
101
106
|
}, handle(config, async ({ project, environment, applicationId, pageId }) => {
|
|
102
107
|
const page = await fetchPage(platform, project, environment, applicationId, pageId);
|
|
103
108
|
const layout = (page.layout ?? {});
|
|
104
|
-
const countNodes = (nodes) => (nodes ?? []).reduce((total, node) => total + 1 + countNodes(node.children), 0);
|
|
105
109
|
return {
|
|
106
110
|
id: page.id,
|
|
107
111
|
name: page.name,
|
|
@@ -118,7 +122,7 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
|
|
|
118
122
|
events: page.events ?? [],
|
|
119
123
|
flows: (Array.isArray(page.flows) ? page.flows : [])
|
|
120
124
|
.map(flow => ({ id: flow.id, name: flow.name, slug: flow.slug })),
|
|
121
|
-
schemaNodes:
|
|
125
|
+
schemaNodes: countSchemaNodes(page.schema),
|
|
122
126
|
updatedAt: page.audit?.updatedAt ?? page.audit?.createdAt
|
|
123
127
|
};
|
|
124
128
|
}));
|
|
@@ -200,7 +204,7 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
|
|
|
200
204
|
const maxInlinePngBytes = 5 * 1024 * 1024;
|
|
201
205
|
server.registerTool('page_screenshot', {
|
|
202
206
|
title: 'Sayfanın ekran görüntüsünü al',
|
|
203
|
-
description: "Studio arayüzünün runtime render rotasını (/dev ya da /view) headless Chromium'da açar ve sayfanın PNG ekran görüntüsünü inline görüntü olarak döner — kurduğun sayfayı GÖZLE doğrulamanın yolu budur (page_runtime_get paketi verir, bu tool ekranda ne ÇİZİLDİĞİNİ gösterir). Sayfaya bağlı middleware'ler gerçekten koşar; reddedilirse yanıtta middlewareBlocked işaretlenir ve Studio'nun çizdiği hata durumu karesi döner — bu da bir doğrulamadır. YÜKLENMEMİŞ SAYFA ASLA ÇEKİLMEZ: kare, runtime çizilip mount akışları bitince alınır (yanıtta pageState + readyAfterMs); bütçe dolduğunda sayfa hâlâ iskelette ya da akış koşuyorsa çağrı ne görüldüğünü söyleyen bir hatayla döner, boş/yarım kare dönmez. Sayfa akışı bir adımda düşerse (patlayan ifade, hata dönen uç) yanıt runtimeErrors taşır ve hangi komponentin hangi prop'unun YAZILMADIĞINI söyler — kare 'çalışıyor' görünürken sessizce boş kalan komponenti ancak bu yakalar. Kare DİLİ ve TEMASI seçilebilir: 'language' adrese ?lang ekler (çeviriye bağlı prop'lar da çok dilli alanların satır değerleri de o dilde çözülür), 'colorScheme' ziyaretçinin tema tercihini sayfa açılmadan eker — ikisi de sayfaya dil değiştirici ya da theme-toggle koymayı GEREKTİRMEZ, yani referansa sadık bir tasarımın ikinci dili ve koyu teması bozulmadan kanıtlanır. STUDIO_BASE_URL tanımlı olmalı; ilk kullanım için `npx playwright-core install chromium` gerekir. DAL ORTAMI DA GÖRÜNTÜLENİR (2026-09-09'dan beri): 'development' /dev, 'production' /view, dal ise /branch/{dal} şeridinden açılır ve sayfanın BÜTÜN istekleri (şema da akışlar da) o dala gider — dalda kurulan sayfa artık merge'i beklemeden gözle doğrulanır (platform_guide('merge') §Dalda görsel doğrulama).",
|
|
207
|
+
description: "ÖNCE KARESİZ DENE: 'kart göründü mü, tablo doldu mu, hata var mı' gibi olgu sorularında image:'none' verin — kare çekilmez, yanıttaki summaryText her kök düğümün görünürlüğünü, metnini, satır sayısını, açık sekmesini ve hata mesajlarını söyler (bir tam sayfa karesinin yüzlerce katı küçük). Kareyi yalnız görsel soru (renk, hizalama, referansa sadakat) için alın ve küçültün: clip ile bölge, scale:0.5 ile yarı çözünürlük; aynı sayfayı yeniden çekerken image:'ifChanged'. Studio arayüzünün runtime render rotasını (/dev ya da /view) headless Chromium'da açar ve sayfanın PNG ekran görüntüsünü inline görüntü olarak döner — kurduğun sayfayı GÖZLE doğrulamanın yolu budur (page_runtime_get paketi verir, bu tool ekranda ne ÇİZİLDİĞİNİ gösterir). Sayfaya bağlı middleware'ler gerçekten koşar; reddedilirse yanıtta middlewareBlocked işaretlenir ve Studio'nun çizdiği hata durumu karesi döner — bu da bir doğrulamadır. YÜKLENMEMİŞ SAYFA ASLA ÇEKİLMEZ: kare, runtime çizilip mount akışları bitince alınır (yanıtta pageState + readyAfterMs); bütçe dolduğunda sayfa hâlâ iskelette ya da akış koşuyorsa çağrı ne görüldüğünü söyleyen bir hatayla döner, boş/yarım kare dönmez. Sayfa akışı bir adımda düşerse (patlayan ifade, hata dönen uç) yanıt runtimeErrors taşır ve hangi komponentin hangi prop'unun YAZILMADIĞINI söyler — kare 'çalışıyor' görünürken sessizce boş kalan komponenti ancak bu yakalar. Kare DİLİ ve TEMASI seçilebilir: 'language' adrese ?lang ekler (çeviriye bağlı prop'lar da çok dilli alanların satır değerleri de o dilde çözülür), 'colorScheme' ziyaretçinin tema tercihini sayfa açılmadan eker — ikisi de sayfaya dil değiştirici ya da theme-toggle koymayı GEREKTİRMEZ, yani referansa sadık bir tasarımın ikinci dili ve koyu teması bozulmadan kanıtlanır. STUDIO_BASE_URL tanımlı olmalı; ilk kullanım için `npx playwright-core install chromium` gerekir. DAL ORTAMI DA GÖRÜNTÜLENİR (2026-09-09'dan beri): 'development' /dev, 'production' /view, dal ise /branch/{dal} şeridinden açılır ve sayfanın BÜTÜN istekleri (şema da akışlar da) o dala gider — dalda kurulan sayfa artık merge'i beklemeden gözle doğrulanır (platform_guide('merge') §Dalda görsel doğrulama).",
|
|
204
208
|
inputSchema: {
|
|
205
209
|
project: projectParam,
|
|
206
210
|
environment: environmentParam,
|
|
@@ -787,14 +791,14 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
|
|
|
787
791
|
// alanın gerçekten KAYDEDİLDİĞİNİ söylemez. Yamadan sonra şemayı bir kez okuyup op'un yazmak
|
|
788
792
|
// istediğiyle kayıtlı olanı karşılaştırıyoruz. Okuma başarısız olursa yama yine geçerlidir.
|
|
789
793
|
const contentOps = sentOps.filter(entry => entry.op === 'add_component' || entry.op === 'replace_prop');
|
|
790
|
-
let opDrops =
|
|
794
|
+
let opDrops = emptyWriteDiff();
|
|
791
795
|
if (contentOps.length > 0) {
|
|
792
796
|
try {
|
|
793
797
|
const saved = await fetchPage(platform, project, environment, applicationId, pageId);
|
|
794
798
|
opDrops = schemaOpDrops(saved.schema, contentOps);
|
|
795
799
|
}
|
|
796
800
|
catch {
|
|
797
|
-
opDrops =
|
|
801
|
+
opDrops = emptyWriteDiff();
|
|
798
802
|
}
|
|
799
803
|
}
|
|
800
804
|
return withWriteDiff(withNormalization(response, [
|
|
@@ -822,7 +826,7 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
|
|
|
822
826
|
})));
|
|
823
827
|
server.registerTool('page_create', {
|
|
824
828
|
title: 'Sayfa oluştur',
|
|
825
|
-
description: "Yeni sayfa açar. Şemayı burada göndermek yerine boş bırakıp page_schema_patch micro-op'larıyla kurmak daha doğrudur (canlı canvas ve hedefli düzeltme orada). Şemayı burada gönderirseniz 2026-09-08'den beri AYNI doğrulama duvarından geçer: tanınmayan prop adı ve geçersiz enum değeri 422 ile reddedilir ve sayfa HİÇ açılmaz. roleIds için role_list, layoutId için layout_list kullanın. Yanıttaki schema VARSAYILAN OLARAK iskelettir (çözülmüş layout düğümleri dâhil id/type/children'a iner) — tam gövde için view:'full'; gönderdiğiniz bir alan kaydedilmediyse silentlyDropped söyler.",
|
|
829
|
+
description: "Yeni sayfa açar. Uygulamada aynı ad ya da slug'da sayfa varsa varsayılan olarak YAZMAZ ve mevcut sayfanın id'sini döner (PAGE-035 — gönderilseydi platform '<ad> (1)' adıyla ikinci bir sayfa açardı); tekrar çalıştırılabilir yazma için ifExists:'update' verin, yanıttaki outcome 'created' | 'updated' olur. Mevcut sayfalar okunamazsa da yazmaz. Şemayı burada göndermek yerine boş bırakıp page_schema_patch micro-op'larıyla kurmak daha doğrudur (canlı canvas ve hedefli düzeltme orada). Şemayı burada gönderirseniz 2026-09-08'den beri AYNI doğrulama duvarından geçer: tanınmayan prop adı ve geçersiz enum değeri 422 ile reddedilir ve sayfa HİÇ açılmaz. roleIds için role_list, layoutId için layout_list kullanın. Yanıttaki schema VARSAYILAN OLARAK iskelettir (çözülmüş layout düğümleri dâhil id/type/children'a iner) — tam gövde için view:'full'; gönderdiğiniz bir alan kaydedilmediyse silentlyDropped söyler.",
|
|
826
830
|
inputSchema: {
|
|
827
831
|
project: projectParam,
|
|
828
832
|
environment: environmentParam,
|
|
@@ -836,10 +840,11 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
|
|
|
836
840
|
middlewareIds: z.array(guid).optional(),
|
|
837
841
|
events: eventsParam.optional(),
|
|
838
842
|
schema: schemaParam.optional(),
|
|
839
|
-
view: writeViewParam
|
|
843
|
+
view: writeViewParam,
|
|
844
|
+
ifExists: ifExistsParam('sayfa', "mevcut sayfayı page_update gibi günceller — yalnız bu çağrıda VERİLEN alanlar yazılır, verilmeyen şema/olaylar/roller korunur (page_schema_patch ile kurulmuş şema betik tekrar koşunca silinmez); id'si ve flow'ları korunur")
|
|
840
845
|
},
|
|
841
846
|
annotations: writes
|
|
842
|
-
}, handle(config, async ({ project, environment, applicationId, name, slug, browserTitle, browserTitleKey, layoutId, roleIds, middlewareIds, events, schema, view }) => {
|
|
847
|
+
}, handle(config, async ({ project, environment, applicationId, name, slug, browserTitle, browserTitleKey, layoutId, roleIds, middlewareIds, events, schema, view, ifExists }) => {
|
|
843
848
|
const container = ensurePageContainer(schema ?? []);
|
|
844
849
|
assertScreenWriteGuards('page', { schema: container.schema, events });
|
|
845
850
|
const stringStyles = stringStyleNodes(container.schema);
|
|
@@ -850,6 +855,44 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
|
|
|
850
855
|
: [];
|
|
851
856
|
const moved = reorderSchemaBlocks(container.schema);
|
|
852
857
|
const gaps = (schema ?? []).length > 0 ? verticalGapWarnings(container.schema, 'PAGE-010 (uyarı)') : [];
|
|
858
|
+
const existing = await existingMatch({
|
|
859
|
+
code: 'PAGE-035',
|
|
860
|
+
noun: 'sayfa',
|
|
861
|
+
where: 'bu uygulamada',
|
|
862
|
+
name,
|
|
863
|
+
slug,
|
|
864
|
+
idParam: 'pageId',
|
|
865
|
+
ifExists,
|
|
866
|
+
list: () => listAll(platform, project, environment, `/pages/${applicationId}`),
|
|
867
|
+
listTool: 'page_list',
|
|
868
|
+
copyCheck: "kullanılıp kullanılmadığını dependency_graph module:'page' ile kontrol edip gerekirse silin",
|
|
869
|
+
updateTool: 'pageId ile page_update'
|
|
870
|
+
});
|
|
871
|
+
if (existing !== undefined) {
|
|
872
|
+
const pageId = String(existing.id);
|
|
873
|
+
const current = await fetchHost(platform, 'page', project, environment, applicationId, pageId);
|
|
874
|
+
const overrides = Object.fromEntries(Object.entries({
|
|
875
|
+
name, slug, browserTitle, browserTitleKey, layoutId, roleIds, middlewareIds, events,
|
|
876
|
+
schema: schema === undefined ? undefined : container.schema
|
|
877
|
+
}).filter(([, value]) => value !== undefined));
|
|
878
|
+
const body = pageUpdateBody(current, overrides);
|
|
879
|
+
const before = pageUpdateBody(current);
|
|
880
|
+
// Aynı ad/slug ile tekrar koşan betik o alanları "değişti" diye görmemeli (Gözlem 2).
|
|
881
|
+
const changed = Object.keys(overrides).filter(key => JSON.stringify(before[key]) !== JSON.stringify(overrides[key]));
|
|
882
|
+
await platform.tenant('PUT', project, `/pages/${applicationId}/${pageId}`, { environment, body });
|
|
883
|
+
const updateWarnings = schema === undefined
|
|
884
|
+
? []
|
|
885
|
+
: [...gaps, ...stringStyleWarning(stringStyles), ...inertFlexPropWarning(inertFlexPropNodes(container.schema)), ...flexSizeWarnings(container.schema, 'PAGE-017 (uyarı)', 'PAGE-018 (uyarı)'), ...spacingLayerWarnings(container.schema, 'PAGE-029 (uyarı)', 'PAGE-030 (uyarı)')];
|
|
886
|
+
const summary = {
|
|
887
|
+
id: pageId,
|
|
888
|
+
outcome: 'updated',
|
|
889
|
+
changed,
|
|
890
|
+
preserved: { schemaNodes: countSchemaNodes(body.schema), events: body.events.length }
|
|
891
|
+
};
|
|
892
|
+
if (updateWarnings.length > 0)
|
|
893
|
+
summary.layoutWarnings = updateWarnings;
|
|
894
|
+
return withNormalization(summary, schema === undefined ? [] : [...container.fixes, ...reset, ...componentDefaultsNote(fixed), ...catalogNotes, ...reorderNote(moved)]);
|
|
895
|
+
}
|
|
853
896
|
const response = await platform.tenant('POST', project, `/pages/${applicationId}`, {
|
|
854
897
|
environment,
|
|
855
898
|
body: {
|
|
@@ -871,12 +914,12 @@ export function registerPageTools(server, platform, injectedScreenshotter, injec
|
|
|
871
914
|
// kaydedildi mi" sorusunu gövde değil bu diff cevaplar. `layout_create`'in yaptığının sayfa
|
|
872
915
|
// ikizi; Prop sarmalı açılmazsa doğru kaydedilmiş her prop düşmüş görünür (G-28).
|
|
873
916
|
const drops = (schema ?? []).length > 0
|
|
874
|
-
?
|
|
875
|
-
:
|
|
917
|
+
? writeDiff({ schema: unwrapProps(container.schema) }, { schema: unwrapProps(saved.schema) })
|
|
918
|
+
: emptyWriteDiff();
|
|
876
919
|
if (view !== 'full' && Array.isArray(saved.schema)) {
|
|
877
920
|
saved.schema = saved.schema.map(node => summarize(node));
|
|
878
921
|
}
|
|
879
|
-
const normalized = withWriteDiff(withNormalization(response, [...container.fixes, ...reset, ...componentDefaultsNote(fixed), ...catalogNotes, ...reorderNote(moved)]), drops);
|
|
922
|
+
const normalized = withWriteDiff(withNormalization(withOutcome(response, undefined), [...container.fixes, ...reset, ...componentDefaultsNote(fixed), ...catalogNotes, ...reorderNote(moved)]), drops);
|
|
880
923
|
const createWarnings = [...gaps, ...stringStyleWarning(stringStyles), ...inertFlexPropWarning(inertFlexPropNodes(container.schema)), ...flexSizeWarnings(container.schema, 'PAGE-017 (uyarı)', 'PAGE-018 (uyarı)'), ...spacingLayerWarnings(container.schema, 'PAGE-029 (uyarı)', 'PAGE-030 (uyarı)')];
|
|
881
924
|
if (createWarnings.length === 0 || !normalized || typeof normalized !== 'object')
|
|
882
925
|
return normalized;
|
package/dist/tools/workflows.js
CHANGED
|
@@ -7,10 +7,13 @@ import { writeDiff, withWriteDiff } from '../platform/writeDiff.js';
|
|
|
7
7
|
import { policyRules, microfunctionStepFindings, workflowStepFindings, undefinedInputFieldFindings } from '../knowledge/rules.js';
|
|
8
8
|
import { languageHeader } from '../knowledge/languageCodes.js';
|
|
9
9
|
import { handle } from '../platform/responses.js';
|
|
10
|
+
import { existingMatch, ifExistsParam, listAll, platformRename, withOutcome, withRename } from '../platform/ifExists.js';
|
|
11
|
+
import { outlineWrite, recordWriteViewParam } from '../platform/writeView.js';
|
|
10
12
|
import fastJsonPatch from 'fast-json-patch';
|
|
11
13
|
import { z } from 'zod';
|
|
12
14
|
import { constraintSummary } from '../knowledge/backendConstraints.js';
|
|
13
15
|
import { unmappedMembers, introducedUnmappedMembers, withUnmappedMembers } from '../knowledge/schemaGuard.js';
|
|
16
|
+
const workflowIfExistsParam = ifExistsParam('workflow', 'mevcut workflow\'u bu tanımla tam gövde günceller (id\'si korunur; workflow_update ile aynı yazma)');
|
|
14
17
|
const policyOverrideParam = z.boolean().optional()
|
|
15
18
|
.describe('true: politika block bulgularını warn\'a indirir (bilinçli istisna; yanıtta işaretlenir)');
|
|
16
19
|
const patchOperationsParam = z.array(z.record(z.unknown())).min(1)
|
|
@@ -111,27 +114,51 @@ export function registerWorkflowTools(server, platform) {
|
|
|
111
114
|
}));
|
|
112
115
|
server.registerTool('workflow_create', {
|
|
113
116
|
title: 'Workflow oluştur',
|
|
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'),
|
|
115
|
-
inputSchema: { project: projectParam, environment: environmentParam, applicationId: guid, definition: definitionParam, policyOverride: policyOverrideParam },
|
|
117
|
+
description: "Yeni workflow tanımlar (definition = CreateWorkflowCommand). type: 'workflow' | 'automation' | 'middleware'. Uygulamada aynı ad ya da slug'da workflow varsa (tipten bağımsız) varsayılan olarak YAZMAZ ve mevcut kaydın id'sini döner (WF-034 — gönderilseydi platform '<ad> (1)' adıyla ikinci bir kayıt açardı); tekrar çalıştırılabilir yazma için ifExists:'update' verin, yanıttaki outcome 'created' | 'updated' olur. Mevcut workflow'lar okunamazsa da yazmaz. İ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'),
|
|
118
|
+
inputSchema: { project: projectParam, environment: environmentParam, applicationId: guid, definition: definitionParam, ifExists: workflowIfExistsParam, view: recordWriteViewParam, policyOverride: policyOverrideParam },
|
|
116
119
|
annotations: writes
|
|
117
|
-
}, handle(config, async ({ project, environment, applicationId, definition, policyOverride }) => {
|
|
120
|
+
}, handle(config, async ({ project, environment, applicationId, definition, ifExists, view, policyOverride }) => {
|
|
118
121
|
const normalized = normalizeWorkflowDefinition(definition);
|
|
119
|
-
|
|
120
|
-
|
|
122
|
+
// Politika ÖNCE koşar: block alan istek platforma hiç gitmez, var-mı listesi de okunmaz.
|
|
123
|
+
const stepFindings = [
|
|
121
124
|
...await microfunctionStepFindings(platform, project, environment, definition, definition.type, policyOverride),
|
|
122
125
|
...await workflowStepFindings(platform, project, environment, applicationId, definition, definition.type, policyOverride),
|
|
123
126
|
...await undefinedInputFieldFindings(platform, project, environment, definition, definition.type, policyOverride)
|
|
124
|
-
]
|
|
125
|
-
const
|
|
126
|
-
const
|
|
127
|
-
|
|
127
|
+
];
|
|
128
|
+
const bodyFindings = (operation) => evaluatePolicy(config, policyRules, 'workflow', definition, { operation, workflowKind: definition.type }, policyOverride);
|
|
129
|
+
const createFindings = enforcePolicy([...bodyFindings('create'), ...stepFindings]);
|
|
130
|
+
const existing = await existingMatch({
|
|
131
|
+
code: 'WF-034',
|
|
132
|
+
noun: 'workflow',
|
|
133
|
+
where: 'bu uygulamada',
|
|
134
|
+
name: typeof definition.name === 'string' ? definition.name : undefined,
|
|
135
|
+
slug: typeof definition.slug === 'string' ? definition.slug : undefined,
|
|
136
|
+
id: typeof definition.id === 'string' ? definition.id : undefined,
|
|
137
|
+
idParam: 'definition.id',
|
|
138
|
+
ifExists,
|
|
139
|
+
list: () => listAll(platform, project, environment, `/workflows/${applicationId}`),
|
|
140
|
+
listTool: 'workflow_list',
|
|
141
|
+
copyCheck: 'kullanılıp kullanılmadığını workflow_dependencies ile kontrol edip gerekirse silin',
|
|
142
|
+
updateTool: 'id ile workflow_update',
|
|
143
|
+
kind: { key: 'type', value: definition.type }
|
|
144
|
+
});
|
|
145
|
+
// Kayıt bulunduysa yazma bir UPDATE'tir: gövde kuralları workflow_update ile aynı kipte yeniden
|
|
146
|
+
// değerlendirilir (R-1). Adım denetimleri operasyondan bağımsızdır, tekrar koşmaz.
|
|
147
|
+
const findings = existing === undefined ? createFindings : enforcePolicy([...bodyFindings('update'), ...stepFindings]);
|
|
148
|
+
const drift = unmappedMembers(existing === undefined ? 'CreateWorkflowCommand' : 'UpdateWorkflowCommand', definition);
|
|
149
|
+
const payload = existing === undefined
|
|
150
|
+
? await platform.tenant('POST', project, `/workflows/${applicationId}`, { environment, body: definition })
|
|
151
|
+
: await platform.tenant('PUT', project, `/workflows/${applicationId}/${String(existing.id)}`, { environment, body: definition });
|
|
152
|
+
const saved = payload?.data;
|
|
153
|
+
const rename = ifExists === 'duplicate' ? platformRename(definition, saved, 'dash') : { sent: definition };
|
|
154
|
+
return attachFindings(withUnmappedMembers(withWriteDiff(withRename(withNormalization(withOutcome(outlineWrite(payload, view, ['type']), existing), normalized), rename.renamed), writeDiff(rename.sent, payload)), drift), findings);
|
|
128
155
|
}));
|
|
129
156
|
server.registerTool('workflow_update', {
|
|
130
157
|
title: 'Workflow güncelle',
|
|
131
158
|
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'),
|
|
132
|
-
inputSchema: { project: projectParam, environment: environmentParam, applicationId: guid, id: guid, definition: definitionParam, policyOverride: policyOverrideParam },
|
|
159
|
+
inputSchema: { project: projectParam, environment: environmentParam, applicationId: guid, id: guid, definition: definitionParam, view: recordWriteViewParam, policyOverride: policyOverrideParam },
|
|
133
160
|
annotations: updates
|
|
134
|
-
}, handle(config, async ({ project, environment, applicationId, id, definition, policyOverride }) => {
|
|
161
|
+
}, handle(config, async ({ project, environment, applicationId, id, definition, view, policyOverride }) => {
|
|
135
162
|
const normalized = normalizeWorkflowDefinition(definition);
|
|
136
163
|
const findings = enforcePolicy([
|
|
137
164
|
...evaluatePolicy(config, policyRules, 'workflow', definition, { operation: 'update', workflowKind: definition.type }, policyOverride),
|
|
@@ -141,7 +168,7 @@ export function registerWorkflowTools(server, platform) {
|
|
|
141
168
|
]);
|
|
142
169
|
const drift = unmappedMembers('UpdateWorkflowCommand', definition);
|
|
143
170
|
const payload = await platform.tenant('PUT', project, `/workflows/${applicationId}/${id}`, { environment, body: definition });
|
|
144
|
-
return attachFindings(withUnmappedMembers(withWriteDiff(withNormalization(payload, normalized), writeDiff(definition, payload)), drift), findings);
|
|
171
|
+
return attachFindings(withUnmappedMembers(withWriteDiff(withNormalization(outlineWrite(payload, view, ['type']), normalized), writeDiff(definition, payload)), drift), findings);
|
|
145
172
|
}));
|
|
146
173
|
server.registerTool('workflow_patch', {
|
|
147
174
|
title: 'Workflow\'a patch uygula',
|
package/package.json
CHANGED