@appaflytech/zeyrek-ai-mcp 0.0.24 → 0.0.26

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.
Files changed (81) hide show
  1. package/.env.example +0 -15
  2. package/dist/config.js +0 -11
  3. package/dist/index.js +0 -2
  4. package/dist/knowledge/componentCatalog.js +25 -13
  5. package/dist/knowledge/componentEvents.js +6 -13
  6. package/dist/knowledge/normalize.js +17 -68
  7. package/dist/knowledge/rules.js +49 -137
  8. package/dist/knowledge/styleResolve.js +4 -50
  9. package/dist/knowledge/themeResolve.js +3 -3
  10. package/dist/observability/trace.js +1 -1
  11. package/dist/platform/diagnostics.js +4 -10
  12. package/dist/platform/domSummary.js +1 -1
  13. package/dist/platform/http.js +7 -23
  14. package/dist/platform/responses.js +2 -6
  15. package/dist/platform/{capture/capture.js → screenshot.js} +514 -52
  16. package/dist/platform/secrets.js +0 -9
  17. package/dist/platform/strictArguments.js +12 -68
  18. package/dist/platform/tokenVault.js +4 -187
  19. package/dist/resources/examples/workflow-http-step.json +2 -2
  20. package/dist/resources/guides/component.md +1 -6
  21. package/dist/resources/guides/expressions.md +2 -2
  22. package/dist/resources/guides/functions.md +1 -1
  23. package/dist/resources/guides/layout.md +7 -11
  24. package/dist/resources/guides/microfunction.md +28 -0
  25. package/dist/resources/guides/microservice.md +4 -10
  26. package/dist/resources/guides/middleware.md +1 -5
  27. package/dist/resources/guides/page.md +55 -215
  28. package/dist/resources/guides/theme.md +1 -4
  29. package/dist/resources/guides/translation.md +1 -1
  30. package/dist/resources/guides/workflow.md +9 -12
  31. package/dist/resources/schema-fingerprint.json +2 -2
  32. package/dist/resources/schemas/CreateWorkflowCommand.json +3 -0
  33. package/dist/resources/schemas/PreviewWorkflowCommand.json +3 -0
  34. package/dist/resources/schemas/StepDto.json +12 -9
  35. package/dist/resources/schemas/UpdateWorkflowCommand.json +3 -0
  36. package/dist/server.js +1 -3
  37. package/dist/tools/applications.js +3 -60
  38. package/dist/tools/components.js +10 -50
  39. package/dist/tools/datasources.js +1 -1
  40. package/dist/tools/designSchemaPatch.js +6 -16
  41. package/dist/tools/externalComponents.js +4 -25
  42. package/dist/tools/flows.js +6 -79
  43. package/dist/tools/layouts.js +12 -44
  44. package/dist/tools/microservices.js +10 -26
  45. package/dist/tools/pages.js +67 -303
  46. package/dist/tools/platformInfo.js +2 -6
  47. package/dist/tools/rows.js +1 -7
  48. package/dist/tools/schemaOps.js +1 -1
  49. package/dist/tools/screenWrite.js +5 -6
  50. package/dist/tools/screens.js +3 -90
  51. package/dist/tools/workflows.js +1 -1
  52. package/package.json +1 -1
  53. package/dist/knowledge/mobileComponentCatalog.js +0 -801
  54. package/dist/knowledge/mobileComponentEvents.js +0 -225
  55. package/dist/knowledge/platform/lint.js +0 -312
  56. package/dist/knowledge/platform/mobile.js +0 -78
  57. package/dist/knowledge/platform/mobileRules.js +0 -182
  58. package/dist/knowledge/platform/mobileTabs.js +0 -108
  59. package/dist/knowledge/platform/profile.js +0 -20
  60. package/dist/knowledge/platform/resolve.js +0 -122
  61. package/dist/knowledge/platform/web.js +0 -38
  62. package/dist/knowledge/styleResolveNative.js +0 -510
  63. package/dist/platform/argumentAliases.js +0 -128
  64. package/dist/platform/bodyFile.js +0 -103
  65. package/dist/platform/capture/actions.js +0 -333
  66. package/dist/platform/capture/browser.js +0 -1
  67. package/dist/platform/capture/console-log.js +0 -80
  68. package/dist/platform/capture/index.js +0 -11
  69. package/dist/platform/capture/readiness.js +0 -103
  70. package/dist/platform/capture/summary.js +0 -77
  71. package/dist/platform/capture/target.js +0 -5
  72. package/dist/platform/capture/targets/studio-mobile.js +0 -15
  73. package/dist/platform/capture/targets/studio-web.js +0 -5
  74. package/dist/platform/schemaReadMemory.js +0 -60
  75. package/dist/resources/examples/mobile-app-shell-drawer.json +0 -209
  76. package/dist/resources/examples/mobile-app-shell-stack.json +0 -123
  77. package/dist/resources/examples/mobile-app-shell-tab.json +0 -174
  78. package/dist/resources/examples/mobile-list-detail-form.json +0 -656
  79. package/dist/resources/guides/mobile.md +0 -419
  80. package/dist/tools/mobile.js +0 -203
  81. package/dist/tools/profileWrite.js +0 -45
package/dist/server.js CHANGED
@@ -39,7 +39,6 @@ import { registerMergeTools } from "./tools/merges.js";
39
39
  import { registerRevisionTools } from "./tools/revisions.js";
40
40
  import { registerActivityTools } from "./tools/activities.js";
41
41
  import { registerDtoTools } from "./tools/dtos.js";
42
- import { registerMobileTools } from "./tools/mobile.js";
43
42
  const moduleRegistrations = {
44
43
  platform: registerPlatformTools,
45
44
  project: registerProjectTools,
@@ -81,10 +80,9 @@ const moduleRegistrations = {
81
80
  merge: registerMergeTools,
82
81
  activity: registerActivityTools,
83
82
  revision: registerRevisionTools,
84
- mobile: registerMobileTools,
85
83
  };
86
84
  export function createGatewayServer(platform) {
87
- const server = rejectUnknownArguments(instrumentServer(new McpServer({ name: "ngapps", version: "0.1.0" }), platform.config), platform);
85
+ const server = rejectUnknownArguments(instrumentServer(new McpServer({ name: "ngapps", version: "0.1.0" }), platform.config));
88
86
  for (const moduleName of platform.config.modules) {
89
87
  moduleRegistrations[moduleName](server, platform);
90
88
  }
@@ -1,44 +1,6 @@
1
1
  import { guid, pagingParams, readOnly, writes, updates, destructive } from './common.js';
2
2
  import { handle } from '../platform/responses.js';
3
- import { forgetApplication, readApplicationPlatform, resolveApplication } from '../knowledge/platform/resolve.js';
4
- import { mobileTabsProblems, readMobileTabs } from '../knowledge/platform/mobileTabs.js';
5
- import { findingLine } from '../knowledge/platform/profile.js';
6
3
  import { z } from 'zod';
7
- /**
8
- * MOB-007 (sekme ayarı) — `properties.mobile.tabs` yazan mobil uygulama çağrısının denetimi. Yazım
9
- * platforma YİNE gider (D3; backend `properties`'i doğrulamaz): bulgu `platformWarnings`'e düşer.
10
- * Sayfa ve widget listesi okunamazsa o denetimler atlanır, biçim denetimi yine koşar.
11
- */
12
- export async function mobileTabsWarnings(platform, applicationId, projectSlug, homepageId, properties) {
13
- const tabs = readMobileTabs(properties);
14
- if (tabs === undefined)
15
- return [];
16
- const pages = applicationId && projectSlug
17
- ? await platform.tenant('GET', projectSlug, `/pages/${applicationId}`, { query: { pageIndex: 0, pageLength: 200 } })
18
- .then(response => (response?.data ?? []).map(page => ({ id: String(page.id ?? '') })))
19
- .catch(() => undefined)
20
- : undefined;
21
- const widgetIds = applicationId && projectSlug
22
- ? await platform.tenant('GET', projectSlug, `/components/${applicationId}`, { query: { pageIndex: 0, pageLength: 999 } })
23
- .then(response => new Set((response?.data ?? []).filter(entry => entry.kind === 'widget').map(entry => String(entry.id ?? ''))))
24
- .catch(() => undefined)
25
- : undefined;
26
- return mobileTabsProblems(tabs, {
27
- ...(pages ? { pages } : {}),
28
- ...(homepageId ? { homepageId } : {}),
29
- ...(widgetIds ? { widgetIds } : {})
30
- }).map(message => findingLine({
31
- code: 'MOB-007',
32
- severity: 'warn',
33
- message,
34
- guide: "platform_guide('mobile') §Gezinme"
35
- }));
36
- }
37
- function withPlatformWarnings(response, warnings) {
38
- if (warnings.length === 0 || !response || typeof response !== 'object' || Array.isArray(response))
39
- return response;
40
- return { ...response, platformWarnings: warnings };
41
- }
42
4
  export function registerApplicationTools(server, platform) {
43
5
  const config = platform.config;
44
6
  server.registerTool('application_list', {
@@ -72,14 +34,7 @@ export function registerApplicationTools(server, platform) {
72
34
  notFoundPageId: guid.optional()
73
35
  },
74
36
  annotations: writes
75
- }, handle(config, async ({ projectId, ...body }) => {
76
- const warnings = readApplicationPlatform(body.type) === 'mobile'
77
- ? await mobileTabsWarnings(platform, undefined, undefined, undefined, body.properties)
78
- : [];
79
- const response = await platform.org('POST', `/applications/${projectId}`, { body });
80
- forgetApplication(platform);
81
- return withPlatformWarnings(response, warnings);
82
- }));
37
+ }, handle(config, ({ projectId, ...body }) => platform.org('POST', `/applications/${projectId}`, { body })));
83
38
  server.registerTool('application_update', {
84
39
  title: 'Application güncelle',
85
40
  description: 'Application bilgilerini günceller; homepageId zorunludur (mevcut değeri application_get ile alın).',
@@ -94,23 +49,11 @@ export function registerApplicationTools(server, platform) {
94
49
  notFoundPageId: guid.optional()
95
50
  },
96
51
  annotations: updates
97
- }, handle(config, async ({ id, ...body }) => {
98
- const current = await resolveApplication(platform, id);
99
- const warnings = current?.platform === 'mobile'
100
- ? await mobileTabsWarnings(platform, id, current.projectSlug, body.homepageId, body.properties)
101
- : [];
102
- const response = await platform.org('PUT', `/applications/${id}`, { body });
103
- forgetApplication(platform, id);
104
- return withPlatformWarnings(response, warnings);
105
- }));
52
+ }, handle(config, ({ id, ...body }) => platform.org('PUT', `/applications/${id}`, { body })));
106
53
  server.registerTool('application_delete', {
107
54
  title: 'Application sil',
108
55
  description: 'Application\'ı kalıcı olarak siler.',
109
56
  inputSchema: { id: guid },
110
57
  annotations: destructive
111
- }, handle(config, async (args) => {
112
- const response = await platform.org('DELETE', `/applications/${args.id}`);
113
- forgetApplication(platform, args.id);
114
- return response;
115
- }));
58
+ }, handle(config, args => platform.org('DELETE', `/applications/${args.id}`)));
116
59
  }
@@ -1,40 +1,25 @@
1
1
  import { guid, projectParam, environmentParam, readOnly, writes, updates, destructive } from './common.js';
2
- import { normalizeComponentDefaults, componentDefaultsNote, clampBlockSizes, blockSizeNote, normalizeHeightTypes, heightTypeNote, normalizeSizeStrings, sizeStringNote, normalizeDroppableStates, withNormalization } from '../knowledge/normalize.js';
2
+ import { normalizeComponentDefaults, componentDefaultsNote, clampBlockSizes, blockSizeNote, normalizeHeightTypes, heightTypeNote, normalizeSizeStrings, sizeStringNote, withNormalization } from '../knowledge/normalize.js';
3
3
  import { eventContractsFor, eventPayloadNote } from '../knowledge/componentEvents.js';
4
4
  import { componentPresetDefaults, readProjectTheme } from '../knowledge/themeSchema.js';
5
5
  import { knowledgeFor, knowledgeNote, APPEARANCE_TOKEN_SETS, STATE_FLAG_NOTES, INTERNAL_ROLES_BY_TYPE } from '../knowledge/componentCatalog.js';
6
- import { MOBILE_STATE_FLAG_NOTES, mobileComponentKnowledge } from '../knowledge/mobileComponentCatalog.js';
7
- import { mobileComponentEventContracts } from '../knowledge/mobileComponentEvents.js';
8
6
  import { componentUpdateBody, fetchHost, schemaParam, unwrap } from './screens.js';
9
7
  import { PlatformApiError } from '../platform/errors.js';
10
8
  import { handle } from '../platform/responses.js';
11
- import { applicationTypeField, resolveProfile } from '../knowledge/platform/resolve.js';
12
- import { mobileComponentNotes } from '../knowledge/platform/mobileRules.js';
13
9
  import { z } from 'zod';
14
- const typeParam = z.enum(['web', 'mobile']).optional().describe('Hedef platform (ComponentType); verilmezse uygulamanın tipi — mobil uygulamada mobile');
10
+ const typeParam = z.enum(['web', 'mobile']).optional().describe('Hedef platform; varsayılan web');
15
11
  const kindParam = z.enum(['component', 'widget']).optional()
16
12
  .describe("component: sayfaya konan tekil eleman. widget: kendi şeması olan kapsayıcı (container/modal/drawer)");
17
13
  const widgetTypeParam = z.enum(['container', 'modal', 'drawer']).optional()
18
14
  .describe("kind:'widget' iken zorunlu");
19
- /**
20
- * Uç `type` verilmezse WEB kataloğunu döner (`GetComponentsQuery` `Type ?? Web`); mobil uygulamanın
21
- * paleti, doğrulayıcısı ve widget'ları `type=mobile` satırlarıdır. Profil mobil derse sorgu tipi
22
- * taşır; web'de sorgu profil öncesiyle aynıdır (G1 kilidi).
23
- */
24
15
  async function listComponents(platform, project, environment, applicationId, scope) {
25
16
  const path = scope === 'all' ? `/components/${applicationId}/all` : `/components/${applicationId}`;
26
- const catalogType = scope === 'all' ? 'web' : (await resolveProfile(platform, applicationId)).profile.catalogType;
27
17
  const response = await platform.tenant('GET', project, path, {
28
18
  environment,
29
- query: scope === 'all' ? undefined : { pageIndex: 0, pageLength: 999, ...(catalogType === 'mobile' ? { type: 'mobile' } : {}) }
19
+ query: scope === 'all' ? undefined : { pageIndex: 0, pageLength: 999 }
30
20
  });
31
21
  return response?.data ?? [];
32
22
  }
33
- /** Uygulamanın kayıtlı bileşen slug'ları (mobil profilin MOB-003 denetimi). */
34
- export async function fetchCatalogSlugs(platform, project, environment, applicationId) {
35
- const components = await listComponents(platform, project, environment, applicationId);
36
- return new Set(components.map(component => String(component.slug ?? '')).filter(slug => slug.length > 0));
37
- }
38
23
  /**
39
24
  * Yerleşim normalizasyonlarının ikisi de aynı katalog listesinden beslenir; tek okumada
40
25
  * çıkarılır ki yazma yolları fazladan istek atmasın. Uygulamanın kendi sözlüğü okunur
@@ -53,17 +38,12 @@ export async function fetchComponentLayoutRules(platform, project, environment,
53
38
  export function componentLayoutRules(components) {
54
39
  const maxSizes = new Map();
55
40
  const autoHeights = new Map();
56
- const droppable = new Map();
57
41
  for (const component of components) {
58
42
  const slug = typeof component.slug === 'string' ? component.slug : undefined;
59
43
  if (!slug)
60
44
  continue;
61
45
  if (typeof component.isDefaultAutoHeight === 'boolean')
62
46
  autoHeights.set(slug, component.isDefaultAutoHeight);
63
- // Kap bilgisi sözlükten gelir; düğümün `states.isDroppable`ı onu izler (Studio paleti de
64
- // aynı alanı katalogdan yazar). `true` gören tip kap sayılır.
65
- if (typeof component.isDroppable === 'boolean')
66
- droppable.set(slug, component.isDroppable);
67
47
  const blocks = (component.definition ?? {}).blocks;
68
48
  if (!Array.isArray(blocks))
69
49
  continue;
@@ -78,7 +58,7 @@ export function componentLayoutRules(components) {
78
58
  });
79
59
  }
80
60
  }
81
- return { maxSizes, autoHeights, droppable };
61
+ return { maxSizes, autoHeights };
82
62
  }
83
63
  /**
84
64
  * Katalog okuması başarısız olsa da yazma isteği gitmeli, ama iki normalizasyonun düşüş davranışı
@@ -89,21 +69,14 @@ export function componentLayoutRules(components) {
89
69
  * varsayılanını (`fixed`, `DesignComponentManagementSchema.cs:24`) kabul etmek demektir; en fazla
90
70
  * sekiz tipte (auth-layout/html/image/layout/qrcode/table/text-editor/video) fazladan yükseklik
91
71
  * üretir, atlamak ise her tipte içerik kırpar.
92
- * - `states.isDroppable` atlanır — katalog okunamadığında hangi tipin kap olduğu bilinmez ve
93
- * uydurulmaz; düğüm bugünkü hâliyle yazılır.
94
72
  */
95
73
  export async function applyCatalogLayoutRules(platform, project, environment, applicationId, nodes) {
96
74
  try {
97
75
  const rules = await fetchComponentLayoutRules(platform, project, environment, applicationId);
98
- return {
99
- clamped: clampBlockSizes(nodes, rules.maxSizes),
100
- heights: normalizeHeightTypes(nodes, rules.autoHeights),
101
- sizes: normalizeSizeStrings(nodes),
102
- states: normalizeDroppableStates(nodes, rules.droppable)
103
- };
76
+ return { clamped: clampBlockSizes(nodes, rules.maxSizes), heights: normalizeHeightTypes(nodes, rules.autoHeights), sizes: normalizeSizeStrings(nodes) };
104
77
  }
105
78
  catch {
106
- return { clamped: [], heights: normalizeHeightTypes(nodes, new Map()), sizes: normalizeSizeStrings(nodes), states: [] };
79
+ return { clamped: [], heights: normalizeHeightTypes(nodes, new Map()), sizes: normalizeSizeStrings(nodes) };
107
80
  }
108
81
  }
109
82
  /**
@@ -143,7 +116,6 @@ export function registerComponentTools(server, platform) {
143
116
  }, handle(config, async ({ project, environment, applicationId, scope, includeHidden }) => {
144
117
  const components = await listComponents(platform, project, environment, applicationId, scope);
145
118
  return {
146
- ...applicationTypeField(await resolveProfile(platform, applicationId)),
147
119
  components: components
148
120
  .filter(component => includeHidden === true || component.isHide !== true)
149
121
  .map(component => ({
@@ -189,15 +161,6 @@ export function registerComponentTools(server, platform) {
189
161
  : [];
190
162
  const componentSlug = typeof component.slug === 'string' ? component.slug : undefined;
191
163
  const knowledge = knowledgeFor(componentSlug);
192
- // Mobil uygulamada kayıt mobil kataloğun satırıdır (`listComponents` type=mobile); davranış
193
- // notları web runtime'ından gelir (`knowledge` — mobil şema web sınıfını genişletir), bileşenin
194
- // mobil farkları `mobileKnowledge`'ta, bütün mobil bileşenlere geçen notlar `mobileNotes`'ta (G4).
195
- // Web ikizi olmayan bileşende (`app-bar`, `tooltip`…) bilgi yalnız `mobileKnowledge`'tadır; olay
196
- // yükleri de önce mobil sözlükten okunur (`mobileComponentEvents.ts`).
197
- const mobile = (await resolveProfile(platform, applicationId)).profile.platform === 'mobile';
198
- const mobileKnowledge = mobile && componentSlug !== undefined && Object.hasOwn(mobileComponentKnowledge, componentSlug)
199
- ? mobileComponentKnowledge[componentSlug]
200
- : undefined;
201
164
  // S-3 — `defaults` HAM katalogdur; Studio'da bırakılan düğüm ise temanın bileşen preseti
202
165
  // kaplanmış katalogdan kurulur (`withThemeComponentDefaults`). Tema okunamazsa (uç düşer,
203
166
  // yetki yoksa) alan yanıta HİÇ girmez: uydurulmuş bir varsayılan yanlış bilgidir.
@@ -214,7 +177,7 @@ export function registerComponentTools(server, platform) {
214
177
  isDroppable: component.isDroppable,
215
178
  props: definition.props,
216
179
  defaults: definition.defaults,
217
- events: eventContractsFor(componentSlug, eventNames, mobile ? mobileComponentEventContracts : undefined),
180
+ events: eventContractsFor(componentSlug, eventNames),
218
181
  eventPayloadNote,
219
182
  ...(knowledge
220
183
  ? {
@@ -225,7 +188,7 @@ export function registerComponentTools(server, platform) {
225
188
  },
226
189
  ...(knowledge.guide ? { guide: knowledge.guide } : {})
227
190
  }
228
- : mobileKnowledge ? {} : { knowledgeNote }),
191
+ : { knowledgeNote }),
229
192
  ...(componentSlug && INTERNAL_ROLES_BY_TYPE[componentSlug]
230
193
  ? {
231
194
  internalRoles: INTERNAL_ROLES_BY_TYPE[componentSlug],
@@ -233,9 +196,8 @@ export function registerComponentTools(server, platform) {
233
196
  }
234
197
  : {}),
235
198
  ...(themeDefaults ? { themeDefaults } : {}),
236
- ...(mobile ? { platform: 'mobile', ...(mobileKnowledge ? { mobileKnowledge } : {}), mobileNotes: mobileComponentNotes(componentSlug) } : {}),
237
199
  appearanceValues: APPEARANCE_TOKEN_SETS,
238
- stateFlags: mobile ? { ...STATE_FLAG_NOTES, ...MOBILE_STATE_FLAG_NOTES } : STATE_FLAG_NOTES,
200
+ stateFlags: STATE_FLAG_NOTES,
239
201
  validations: definition.validations,
240
202
  sizes: definition.blocks
241
203
  };
@@ -272,13 +234,11 @@ export function registerComponentTools(server, platform) {
272
234
  const catalog = (body.schema ?? []).length > 0
273
235
  ? await applyCatalogLayoutRules(platform, project, environment, applicationId, body.schema)
274
236
  : { clamped: [], heights: [], sizes: [] };
275
- // Mobil uygulamanın widget'ı mobil katalog satırıdır; tip verilmezse uygulamanın tipi.
276
- const defaultType = body.type ?? (await resolveProfile(platform, applicationId)).profile.catalogType;
277
237
  return platform.tenant('POST', project, `/components/${applicationId}`, {
278
238
  environment,
279
239
  body: {
280
240
  kind: 'component',
281
- type: defaultType,
241
+ type: 'web',
282
242
  categories: [],
283
243
  definition: {},
284
244
  schema: [],
@@ -118,7 +118,7 @@ export function registerDatasourceTools(server, platform) {
118
118
  }, handle(config, ({ project, environment }) => platform.tenant('GET', project, '/datasources/resources', { environment })));
119
119
  server.registerTool('datasource_configuration_options', {
120
120
  title: 'Yapılandırma seçenekleri',
121
- description: "Datasource'un alan tipi kataloğunu döner: commonType başına dbType listesi, varsayılan tip, tipin kabul ettiği seçenek anahtarları (length/precision/collation/...) ve dönüştürülebilir tipler; ayrıca ilişki kuralları (onUpdate/onDelete) ve identity generation tipleri. İlişki alanına yazarken kuralı SAYI olarak verin (`None` 0 · `Cascade` 1 · `SetNull` 2 · `SetDefault` 3 — `Rule` sırası): her backend sürümünde çalışır. Katalog adı listeler; `onDelete` adı (`Cascade`) 2026-09-27'den sonraki backend'de de kabul edilir, `onUpdate` adı hâlâ reddedilir (500). VARSAYILAN YANIT ÖZETTİR (~5 KB): collation DEĞER listesi (816 kayıt, tam yanıtın %79'u) dışarıdadır — tipin collation kabul edip etmediği zaten options'ta yazar. Collation değerleri gerçekten gerekiyorsa includeCollations: true ile tam yanıtı isteyin (~45 KB).",
121
+ description: "Datasource'un alan tipi kataloğunu döner: commonType başına dbType listesi, varsayılan tip, tipin kabul ettiği seçenek anahtarları (length/precision/collation/...) ve dönüştürülebilir tipler; ayrıca ilişki kuralları (onUpdate/onDelete) ve identity generation tipleri. VARSAYILAN YANIT ÖZETTİR (~5 KB): collation DEĞER listesi (816 kayıt, tam yanıtın %79'u) dışarıdadır — tipin collation kabul edip etmediği zaten options'ta yazar. Collation değerleri gerçekten gerekiyorsa includeCollations: true ile tam yanıtı isteyin (~45 KB).",
122
122
  inputSchema: {
123
123
  project: projectParam,
124
124
  environment: environmentParam,
@@ -8,8 +8,6 @@ import { fetchComponentEventNames } from './components.js';
8
8
  import { PlatformApiError } from '../platform/errors.js';
9
9
  import { handle } from '../platform/responses.js';
10
10
  import { slotWarning } from './layouts.js';
11
- import { applicationTypeField, resolveProfile } from '../knowledge/platform/resolve.js';
12
- import { boundFlowSteps, screenProfileWarnings } from './profileWrite.js';
13
11
  import { z } from 'zod';
14
12
  const HOSTS = {
15
13
  layout: {
@@ -87,8 +85,7 @@ export function registerDesignSchemaPatchTool(server, platform, host) {
87
85
  if (deletedFlows.length > 0 && allowFlowDeletion !== true)
88
86
  throw new PlatformApiError(orphanedFlowMessage(deletedFlows), 400);
89
87
  const added = opRecords.filter(entry => entry.op === 'add_component').map(entry => entry.component);
90
- const resolved = await resolveProfile(platform, applicationId);
91
- assertScreenWriteGuards(spec.kind, { schema: added }, resolved.profile.platform);
88
+ assertScreenWriteGuards(spec.kind, { schema: added });
92
89
  const catalogNotes = await screenCatalogNotes(platform, project, environment, applicationId, added);
93
90
  const flowWarnings = opRecords.some(entry => entry.op === 'remove_component')
94
91
  ? [...orphanedFlowWarnings(nodes, events, opRecords), ...staleSetterWarnings(Array.isArray(record.flows) ? record.flows : [], opRecords, nodes)]
@@ -103,19 +100,13 @@ export function registerDesignSchemaPatchTool(server, platform, host) {
103
100
  || (entry.op === 'replace_prop' && FLEX_LAYOUT_PROP_NAMES.has(String(entry.prop ?? ''))));
104
101
  const nested = simulatable ? nestedRepeaterNodes(simulated) : [];
105
102
  if (nested.length > 0)
106
- throw new PlatformApiError(nestedRepeaterMessage(nested, resolved.profile.platform), 400);
103
+ throw new PlatformApiError(nestedRepeaterMessage(nested), 400);
107
104
  const reshaped = simulatable || opRecords.some(entry => entry.op === 'remove_component');
108
- const profileWarnings = await screenProfileWarnings(platform, resolved, project, environment, applicationId, {
109
- kind: spec.kind,
110
- ops: [...opRecords, ...propTypeOps],
111
- savedNodes: nodes,
112
- steps: await boundFlowSteps(platform, resolved, project, environment, host, applicationId, id, opRecords)
113
- });
114
105
  const layoutWarnings = reshaped
115
106
  ? [
116
- ...(resolved.profile.layout.blocksMeaningful ? verticalGapWarnings(simulated, spec.codes.gap, touched) : []),
107
+ ...verticalGapWarnings(simulated, spec.codes.gap, touched),
117
108
  ...stringStyleWarning(stringStyleNodes(simulated)),
118
- ...(resolved.profile.layout.modes.has('grid') ? inertFlexPropWarning(inertFlexPropNodes(simulated)) : []),
109
+ ...inertFlexPropWarning(inertFlexPropNodes(simulated)),
119
110
  ...flexSizeWarnings(simulated, spec.codes.flexMismatch, spec.codes.flexInvalid),
120
111
  ...(host === 'layout' ? slotWarning(simulated) : [])
121
112
  ]
@@ -142,9 +133,8 @@ export function registerDesignSchemaPatchTool(server, platform, host) {
142
133
  response.deletedFlows = deletedFlows;
143
134
  if (flowWarnings.length > 0)
144
135
  response.flowWarnings = flowWarnings;
145
- if (layoutWarnings.length > 0 || profileWarnings.length > 0)
146
- response.layoutWarnings = [...layoutWarnings, ...profileWarnings];
147
- Object.assign(response, applicationTypeField(resolved));
136
+ if (layoutWarnings.length > 0)
137
+ response.layoutWarnings = layoutWarnings;
148
138
  const contentOps = opRecords.filter(entry => entry.op === 'add_component' || entry.op === 'replace_prop');
149
139
  let opDrops = emptyWriteDiff();
150
140
  if (contentOps.length > 0) {
@@ -7,23 +7,6 @@ import { z } from 'zod';
7
7
  import { evaluatePolicy, enforcePolicy } from '../knowledge/policy.js';
8
8
  import { policyRules } from '../knowledge/rules.js';
9
9
  import { EXTERNAL_COMPONENT_PROTOCOL_VERSION } from '../knowledge/backendConstraints.js';
10
- import { resolveProfile } from '../knowledge/platform/resolve.js';
11
- import { findingLine } from '../knowledge/platform/profile.js';
12
- /**
13
- * MOB-006 — harici bileşen protokolü v1 tarayıcıda koşan `.mjs` custom element'tir; mobil
14
- * uygulamanın native çizeri onu yükleyemez (mobil protokol v2 Faz 3). Profil kapalı derse çağrı
15
- * platforma GİTMEZ: yüklenen paket hiçbir ekranda çizilmeyecekti.
16
- */
17
- async function assertExternalComponentsAllowed(platform, applicationId, tool) {
18
- const resolved = await resolveProfile(platform, applicationId);
19
- if (resolved.profile.externalComponents)
20
- return;
21
- throw new PlatformApiError(`${tool}: ${findingLine({
22
- code: 'MOB-006',
23
- severity: 'warn',
24
- message: "harici bileşen mobil uygulamada desteklenmiyor — protokol v1 tarayıcıda koşan .mjs custom element'tir, native çizer onu yükleyemez (mobil protokol v2 Faz 3). Çağrı platforma gönderilmedi; mobil ekranı katalog bileşenleriyle kurun (component_list). Katalogda karşılığı olmayan küçük görünüm için geçici yol 'html' bileşenidir: içerik korumalı belgede tema değişkenleriyle çizilir, fireEvent/ngApps.emit ile akışa bağlanır (component_get('html'))."
25
- })}`, 400);
26
- }
27
10
  /** Platformun köprü protokolü; scaffold ve publish bu sürüme göre üretir/doğrular (backend ExternalComponentRules.CurrentProtocolVersion) */
28
11
  const PROTOCOL_VERSION = EXTERNAL_COMPONENT_PROTOCOL_VERSION;
29
12
  /** Backend `ExternalComponentRules.MaxBundleSizeBytes` ile aynı sınır */
@@ -216,7 +199,6 @@ export function registerExternalComponentTools(server, platform) {
216
199
  },
217
200
  annotations: writes
218
201
  }, handle(config, async ({ project, environment, applicationId, bundlePath, manifestPath, version }) => {
219
- await assertExternalComponentsAllowed(platform, applicationId, 'external_component_publish');
220
202
  const manifestFile = resolve(manifestPath);
221
203
  const bundleFile = resolve(bundlePath);
222
204
  let manifest;
@@ -280,13 +262,10 @@ export function registerExternalComponentTools(server, platform) {
280
262
  acknowledgeWarnings: z.boolean().optional().describe('Doğrulama uyarılarını okuyup kabul ettiğinizi bildirir; uyarısı olan sürümlerde zorunlu')
281
263
  },
282
264
  annotations: updates
283
- }, handle(config, async ({ project, environment, applicationId, slug, version, acknowledgeWarnings }) => {
284
- await assertExternalComponentsAllowed(platform, applicationId, 'external_component_activate');
285
- return platform.tenant('POST', project, `/components/${applicationId}/external/${slug}/activate`, {
286
- environment,
287
- body: { version, acknowledgeWarnings: acknowledgeWarnings === true }
288
- });
289
- }));
265
+ }, handle(config, ({ project, environment, applicationId, slug, version, acknowledgeWarnings }) => platform.tenant('POST', project, `/components/${applicationId}/external/${slug}/activate`, {
266
+ environment,
267
+ body: { version, acknowledgeWarnings: acknowledgeWarnings === true }
268
+ })));
290
269
  server.registerTool('external_component_versions', {
291
270
  title: 'Paket sürümlerini listele',
292
271
  description: 'Bir harici komponentin yayınlanmış paket sürümlerini, hangisinin aktif olduğunu ve her sürümün doğrulama raporunu listeler. Geri alınacak sürümü buradan seçin.',
@@ -13,7 +13,6 @@ import { policyRules, flowExpressionSites } from '../knowledge/rules.js';
13
13
  import { functionCallRefs } from '../knowledge/functionGuards.js';
14
14
  import { existingMatch, ifExistsParam, platformRename, withRename } from '../platform/ifExists.js';
15
15
  import { randomUUID } from 'node:crypto';
16
- import { flowProfileWarnings } from './profileWrite.js';
17
16
  import { z } from 'zod';
18
17
  /**
19
18
  * Akış yazması yanıtında gövdeyi geri döndürmüyor, bu yüzden diff için akışı bir kez okuruz.
@@ -275,7 +274,7 @@ async function functionWarnings(platform, host, project, environment, applicatio
275
274
  }
276
275
  const missing = fn.parameters.filter(parameter => parameter.required && !given.includes(parameter.name)).map(parameter => parameter.name);
277
276
  if (missing.length > 0) {
278
- warnings.add(`FLOW-024: '${label(step)}' adımında '${fn.name}' fonksiyonunun zorunlu parametresi eksik: ${missing.join(', ')} — çağrı 'Functions.${fn.name}: "${missing[0]}" is required' ile düşer, Steps.${String(step.name ?? label(step))}.error.message dolar ve .data null'dur; errorSteps yoksa akış 'always' dalından devam eder.`);
277
+ warnings.add(`FLOW-024: '${label(step)}' adımında '${fn.name}' fonksiyonunun zorunlu parametresi eksik: ${missing.join(', ')} — çağrı 'Functions.${fn.name}: "${missing[0]}" is required' ile düşer, Steps.${String(step.name ?? label(step))}.error dolar ve akış hata gövdesiyle 'always' dalından devam eder.`);
279
278
  }
280
279
  }
281
280
  for (const { step, origin, ref } of callSites) {
@@ -296,60 +295,6 @@ async function functionWarnings(platform, host, project, environment, applicatio
296
295
  }
297
296
  return [...warnings];
298
297
  }
299
- /**
300
- * FLOW-028 (g-02, ADR 0004 — ZM-07). `microservice.ts` `.finally` üç yoldan birini dener: adımın
301
- * kendi `error` dalı bağlıysa oradan sürer, yoksa flow `errorSteps`'i (`engine.onError`) devralır,
302
- * ikisi de yoksa `always` koşar ve storage artık `{ data: null, headers: null, error }`'dır — hata
303
- * gövdesi ARTIK `data`'da DEĞİL. İkisi de bağlı değilken bu adımın `.data`'sını okuyan bir
304
- * setter/condition varsa hata anında NULL üzerinden koşar ve yazar hiç fark etmez. Aynı yürüyüş
305
- * FLOW-024/025'in kullandığı `flowExpressionSites` taramasıdır; setter'ın STORAGE (kod olmayan)
306
- * referansı ayrıca kendi düz alanından okunur (FLOW-008/009 deseni, `rowsTargetsByStepName`).
307
- */
308
- function microserviceAlwaysDataWarnings(steps, errorSteps) {
309
- const mainSteps = (Array.isArray(steps) ? steps : []).filter(isRecord);
310
- const hasErrorFlow = (Array.isArray(errorSteps) ? errorSteps : []).filter(isRecord).some(step => String(step.type ?? '') !== 'start');
311
- const label = (step) => String(step.stepId ?? step.name ?? '?');
312
- const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
313
- const warnings = new Set();
314
- for (const step of mainSteps) {
315
- if (String(step.type ?? '') !== 'microservice')
316
- continue;
317
- const name = String(step.name ?? step.stepId ?? '');
318
- if (name === '')
319
- continue;
320
- const hasErrorBranch = (Array.isArray(step.branches) ? step.branches : [])
321
- .filter(isRecord)
322
- .some(branch => String(branch.name ?? '') === 'error' && Boolean(branch.nextStepId));
323
- if (hasErrorBranch || hasErrorFlow)
324
- continue;
325
- const pattern = new RegExp(`Steps\\s*(?:\\.\\s*${escapeRegExp(name)}\\b|\\[\\s*['"]${escapeRegExp(name)}['"]\\s*\\])\\s*\\??\\.\\s*data\\b`);
326
- const message = (other) => `FLOW-028: '${label(other)}' adımı 'always' dalında '${name}.data' okuyor ama '${name}' adımının ne bağlı bir 'error' dalı ne akışın 'errorSteps'i var — uç hata dönerse bu adımın 'data'sı NULL olur (eskiden hata gövdesiydi, ADR 0004) ve '${label(other)}' boş/null veriyle koşar. '${name}' adımına 'error' dalı bağlayın ya da flow'a errorSteps verin.`;
327
- for (const other of mainSteps) {
328
- if (other === step)
329
- continue;
330
- if (String(other.type ?? '') === 'setter') {
331
- const iteratees = Array.isArray(other.args?.iteratees)
332
- ? other.args.iteratees.filter(isRecord)
333
- : [];
334
- for (const iteratee of iteratees) {
335
- const mapping = (iteratee.mapping ?? {});
336
- const value = (iteratee.value ?? {});
337
- const reference = typeof mapping.source === 'string' && mapping.source.length > 0
338
- ? mapping.source
339
- : typeof value.ref === 'string' ? value.ref : '';
340
- if (value.type === 'storage' && (reference === `${name}.data` || reference.startsWith(`${name}.data.`) || reference.startsWith(`${name}.data[`))) {
341
- warnings.add(message(other));
342
- }
343
- }
344
- }
345
- for (const site of flowExpressionSites(other)) {
346
- if (pattern.test(site.expression))
347
- warnings.add(message(other));
348
- }
349
- }
350
- }
351
- return [...warnings];
352
- }
353
298
  export function registerFlowTools(server, platform) {
354
299
  const config = platform.config;
355
300
  server.registerTool('flow_list', {
@@ -423,8 +368,7 @@ export function registerFlowTools(server, platform) {
423
368
  ...await requiredParameterWarnings(platform, project, environment, applicationId, steps),
424
369
  ...await functionWarnings(platform, host, project, environment, applicationId, hostId, steps),
425
370
  ...flowBodyWarnings(steps),
426
- ...unknownSetterTargetWarnings(steps, errorSteps ?? [], hostNodes(hostRecord)),
427
- ...microserviceAlwaysDataWarnings(steps, errorSteps ?? [])
371
+ ...unknownSetterTargetWarnings(steps, errorSteps ?? [], hostNodes(hostRecord))
428
372
  ];
429
373
  // Gövde yalnız akıştır (designer-partial-update K1): barındırıcı zarfı platformda hâlâ isteğe bağlı
430
374
  // ama gönderilirse okunan tam kaydı yeniden yazar, açık Studio designer'ının kayıtlı tabanını
@@ -438,7 +382,6 @@ export function registerFlowTools(server, platform) {
438
382
  // Diff YALNIZ çağıranın yazdığı alanları kapsar; `id` ve barındırıcı bağı (`pageId` vb.)
439
383
  // gövdeye gateway koyar, kullanıcının düzeltebileceği bir şey değildir.
440
384
  const drops = await flowWriteDrops(platform, host, project, environment, applicationId, hostId, writtenFlowId, { name: flow.name, slug: flow.slug, steps: flow.steps, errorSteps: flow.errorSteps }, ifExists === 'duplicate');
441
- const platformWarnings = await flowProfileWarnings(platform, applicationId, [...(flow.steps ?? []), ...(flow.errorSteps ?? [])]);
442
385
  return attachFindings(withWriteDiff(withRename(withNormalization({
443
386
  host,
444
387
  hostId,
@@ -450,7 +393,6 @@ export function registerFlowTools(server, platform) {
450
393
  steps: steps.length
451
394
  },
452
395
  ...(parameterWarnings.length > 0 ? { parameterWarnings } : {}),
453
- ...(platformWarnings.length > 0 ? { platformWarnings } : {}),
454
396
  hint: "Akışı bir olaya bağlamak için: page_schema_patch (layout'ta layout_schema_patch, widget'ta component_schema_patch) ops:[{op:'set_event', target:<elementId>, event:'<component_get events listesindeki ad>', eventValue:<flow id>}]; olayda zaten akış bağlıysa ikinciyi add_event ile ekleyin (set_event bağlı akışı değiştirir, PAGE-034). Olay adları komponente özeldir ve 'on' ÖNEKİ ALMAZ (button → 'click', form → 'submit', table → 'mount'/'select'/'sort'…); uydurma ad 200 döner ama bağ sessizce ölü kalır — gateway PAGE-008 ile yakalar."
455
397
  }, normalized), drops.renamed), drops), findings);
456
398
  }));
@@ -493,8 +435,7 @@ export function registerFlowTools(server, platform) {
493
435
  ...await requiredParameterWarnings(platform, project, environment, applicationId, flow.steps),
494
436
  ...await functionWarnings(platform, host, project, environment, applicationId, hostId, flow.steps),
495
437
  ...flowBodyWarnings(flow.steps),
496
- ...unknownSetterTargetWarnings(flow.steps, flow.errorSteps, hostNodes(hostRecord)),
497
- ...microserviceAlwaysDataWarnings(flow.steps, flow.errorSteps)
438
+ ...unknownSetterTargetWarnings(flow.steps, flow.errorSteps, hostNodes(hostRecord))
498
439
  ];
499
440
  await platform.tenant('PUT', project, flowPath(host, applicationId, hostId, flowId), { environment, body: { flow } });
500
441
  // Kısmi güncellemede yalnız GÖNDERİLEN alanlar karşılaştırılır; verilmeyen alan için
@@ -505,9 +446,7 @@ export function registerFlowTools(server, platform) {
505
446
  ...(steps === undefined ? {} : { steps }),
506
447
  ...(errorSteps === undefined ? {} : { errorSteps })
507
448
  });
508
- const platformWarnings = await flowProfileWarnings(platform, applicationId, [...(flow.steps ?? []), ...(flow.errorSteps ?? [])]);
509
- return attachFindings(withWriteDiff(withNormalization({ host, hostId, flow: flowSummary(flow), ...(parameterWarnings.length > 0 ? { parameterWarnings } : {}),
510
- ...(platformWarnings.length > 0 ? { platformWarnings } : {}) }, normalized), drops), findings);
449
+ return attachFindings(withWriteDiff(withNormalization({ host, hostId, flow: flowSummary(flow), ...(parameterWarnings.length > 0 ? { parameterWarnings } : {}) }, normalized), drops), findings);
511
450
  }));
512
451
  server.registerTool('flow_patch', {
513
452
  title: "Akışa patch uygula",
@@ -546,8 +485,7 @@ export function registerFlowTools(server, platform) {
546
485
  ...await requiredParameterWarnings(platform, project, environment, applicationId, flow.steps),
547
486
  ...await functionWarnings(platform, host, project, environment, applicationId, hostId, flow.steps),
548
487
  ...flowBodyWarnings(flow.steps),
549
- ...unknownSetterTargetWarnings(flow.steps, flow.errorSteps, hostNodes(hostRecord)),
550
- ...microserviceAlwaysDataWarnings(flow.steps, flow.errorSteps)
488
+ ...unknownSetterTargetWarnings(flow.steps, flow.errorSteps, hostNodes(hostRecord))
551
489
  ];
552
490
  // Gövde değil FARK gönderilir; platform PATCH ucu akışı tek başına yazar. Net diff okunan kayıt ile son hâl arasından hesaplanır.
553
491
  const netOps = fastJsonPatch.compare(current, flow);
@@ -557,7 +495,6 @@ export function registerFlowTools(server, platform) {
557
495
  });
558
496
  const written = patchResult(saved, flow);
559
497
  const drops = await flowWriteDrops(platform, host, project, environment, applicationId, hostId, flowId, { steps: flow.steps, errorSteps: flow.errorSteps });
560
- const platformWarnings = await flowProfileWarnings(platform, applicationId, [...(flow.steps ?? []), ...(flow.errorSteps ?? [])]);
561
498
  return attachFindings(withWriteDiff(withNormalization({
562
499
  host,
563
500
  hostId,
@@ -565,8 +502,7 @@ export function registerFlowTools(server, platform) {
565
502
  newVersion: written.newVersion,
566
503
  patchTargets: resolved.targets,
567
504
  flow: flowSummary(written.data),
568
- ...(parameterWarnings.length > 0 ? { parameterWarnings } : {}),
569
- ...(platformWarnings.length > 0 ? { platformWarnings } : {})
505
+ ...(parameterWarnings.length > 0 ? { parameterWarnings } : {})
570
506
  }, [...normalized, ...resolved.notes.map(note => `patch yolu seçiciden indekse çözüldü: ${note}`)]), drops), findings);
571
507
  }));
572
508
  server.registerTool('flow_delete', {
@@ -578,13 +514,4 @@ export function registerFlowTools(server, platform) {
578
514
  await platform.tenant('DELETE', project, flowPath(host, applicationId, hostId, flowId), { environment, body: { id: flowId } });
579
515
  return { deleted: flowId, host, hostId };
580
516
  }));
581
- server.registerTool('flow_restore', {
582
- title: 'Silinen akışı geri yükle',
583
- description: "Silinmiş bir akışı revizyon defterindeki son içeriğiyle (ad, slug, adımlar, barındırıcı) AYNI id ile yeniden kurar. Sayfa kaydı bağı kalmayan akışı kalıcı siler (FLOW-002, allowFlowDeletion) — Studio'nun eski sekmesi boş şema kaydettiğinde de (ZM-27). Akışı olaya YENİDEN BAĞLAMAZ: geri geldikten sonra set_event ile bağlayın. SINIR: adımları sayfanın bir komponentini hedefliyorsa (tetikleyen element, iterate/parametre komponenti) o komponent de şemada olmalıdır, yoksa geri yükleme reddedilir — sayfa boşaldıysa (ZM-27) page_restore kullanın: sayfayı ve akışlarını birlikte geri kurar. Akış hâlâ varsa 409, saklama süresi dolup revizyonu budanmışsa 404 döner. Silinen akışı revision_list(module: 'flow') satırlarında operation: delete olarak bulun; recordId akış id'sidir.",
584
- inputSchema: { project: projectParam, environment: environmentParam, flowId: flowIdParam },
585
- annotations: writes
586
- }, handle(config, async ({ project, environment, flowId }) => {
587
- const restored = unwrap(await platform.tenant('POST', project, `/flows/${flowId}/restore`, { environment }));
588
- return { restored: flowId, flow: restored };
589
- }));
590
517
  }