@appaflytech/zeyrek-ai-mcp 0.0.10 → 0.0.11
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 +11 -6
- package/dist/knowledge/designSnapshot.js +77 -0
- package/dist/knowledge/normalize.js +47 -0
- package/dist/knowledge/pageDiscover.js +151 -0
- package/dist/knowledge/themeDiscover.js +884 -0
- package/dist/knowledge/themeResolve.js +4 -2
- package/dist/resources/examples/design-snapshot.json +157 -0
- package/dist/resources/guides/theme.md +84 -1
- package/dist/tools/flows.js +119 -17
- package/dist/tools/pages.js +16 -0
- package/dist/tools/themes.js +52 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Zeyrek (NgApps) platformunu **MCP tool'ları** olarak sunan bağımsız gateway.
|
|
|
4
4
|
oturumu Studio arayüzüne hiç girmeden proje kurabilir, veri modeli çıkarabilir, mikroservis ve
|
|
5
5
|
workflow yazıp çalıştırabilir, sayfa tasarlayabilir.
|
|
6
6
|
|
|
7
|
-
- **
|
|
7
|
+
- **212 tool · 34 modül** — veri/mantık tarafı (project, application, datasource, entity, row,
|
|
8
8
|
import, microservice, query, workflow, automation, function, dto, view, dependency), Studio
|
|
9
9
|
tasarım tarafı (page, **theme**, component, external component, flow, layout, variable, function,
|
|
10
10
|
folder, file, access, translation), yönetim (template, organization, deployment) ve proje dallanması
|
|
@@ -140,9 +140,9 @@ ya da ikisi karışık (`core,page`). `platform` modülü (3 tool) her kümede v
|
|
|
140
140
|
| Küme | Tool | Modüller |
|
|
141
141
|
|---|---|---|
|
|
142
142
|
| `core` | 136 | platform, project, application, datasource, entity, row, import, microservice, microfunction, query, workflow, automation, function, dto, view, dependency, environment, merge, activity, revision |
|
|
143
|
-
| `studio` |
|
|
143
|
+
| `studio` | 82 | platform, page, theme, component, externalComponent, flow, layout, variable, function, folder, file, import, access, translation, revision |
|
|
144
144
|
| `admin` | 27 | platform, template, organization, deployment, environment, merge, activity |
|
|
145
|
-
| (boş) | **
|
|
145
|
+
| (boş) | **212** | 34 modülün tamamı (ölçüm 2026-09-16, `listTools()`) |
|
|
146
146
|
|
|
147
147
|
Bilinmeyen bir modül/küme adı verilirse sunucu açılmaz, geçerli adları listeleyen bir hata yazar.
|
|
148
148
|
|
|
@@ -281,9 +281,14 @@ kural envanteri [`docs/08-kural-envanteri.md`](docs/08-kural-envanteri.md).
|
|
|
281
281
|
Yayın otomatiktir: `main`'e `zeyrek-mcp/` değişikliği girince CI işi `publish:mcp:npm`
|
|
282
282
|
([`scripts/ci-publish-npm.sh`](scripts/ci-publish-npm.sh)) paketi üretip npm'deki son sürümle
|
|
283
283
|
içerik olarak karşılaştırır; pakete giren dosyalar değiştiyse yeni patch sürümünü yayınlar.
|
|
284
|
-
|
|
285
|
-
`
|
|
286
|
-
|
|
284
|
+
Yayından sonra CI yeni sürümü `package.json` + `package-lock.json`'a yazıp
|
|
285
|
+
`chore: zeyrek-mcp X.Y.Z [skip ci]` bot commit'iyle `main`'e push eder (yeni pipeline
|
|
286
|
+
başlatmaz); yayın olmazsa commit de olmaz. Push CI_JOB_TOKEN ile yapılır; gereken GitLab
|
|
287
|
+
ayarları `.gitlab-ci.yml`'daki `publish:mcp:npm` notunda. Commit yazılamayıp iş kırmızı düşerse
|
|
288
|
+
push yetkisi olan biri işi Retry eder: yayın tekrarlanmaz, yalnız sürüm `main`'e yazılır.
|
|
289
|
+
Minor/major için `package.json`'daki
|
|
290
|
+
sürümü elle yükseltip merge edin. Yayını o commit için atlamak: commit mesajına `DoNotDeploy`
|
|
291
|
+
(iş elle tetiklenir hâle gelir).
|
|
287
292
|
|
|
288
293
|
Yerelde deneme (yayın yapmaz; `npm ci` çalıştırdığı için bir kopyada ya da Linux container'da):
|
|
289
294
|
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* TASARIM ANLIK GÖRÜNTÜSÜ — bir tasarım dosyasının (Figma) TEK GEÇİŞTE okunup dosyaya alınmış
|
|
4
|
+
* hâli. `theme_discover`'ın girdisi budur; gateway Figma'ya kendisi gitmez (plan K1), süreç içi
|
|
5
|
+
* önbellek de tutmaz (HTTP taşımasında her POST yeni sunucu kurar — anlık görüntü DOSYADIR, K2).
|
|
6
|
+
*
|
|
7
|
+
* `.strict()` her seviyede: tanınmayan anahtar sessizce yaşamaz. Gerekçe tema şemasıyla aynı —
|
|
8
|
+
* ajan `variables` yerine `tokens` yazarsa bu bir yazım hatası değil, eşlemeye hiç girmeyen ve
|
|
9
|
+
* kimsenin görmediği bir veri kaybıdır. Şema onu istek anında adıyla reddeder.
|
|
10
|
+
*
|
|
11
|
+
* Ölçek: `textStyles.fontSize`, `components.*` uzunlukları ve `layout` px'tir; `effects.opacity`
|
|
12
|
+
* Figma'nın 0–1'idir (tema 0–100 ister, çeviri eşlemede — g-02). `variables` `get_variable_defs`
|
|
13
|
+
* çıktısının KENDİSİDİR: ad yeniden yazılmaz, değer olduğu gibi taşınır; eşleme adı okur.
|
|
14
|
+
*/
|
|
15
|
+
const scalar = z.union([z.string(), z.number()]);
|
|
16
|
+
export const TEXT_STYLE_ROLES = ['h1', 'h2', 'h3', 'h4', 'label', 'p', 'small'];
|
|
17
|
+
export const SCREEN_ROLES = ['shell', 'list', 'form', 'detail', 'auth', 'other'];
|
|
18
|
+
/** `hints` değeri: bu Figma adı eşlemeye HİÇ girmesin (bilinçli karar; `unmapped` sebebi olarak döner). */
|
|
19
|
+
export const SNAPSHOT_HINT_IGNORE = 'ignore';
|
|
20
|
+
export const designSnapshotInput = z.object({
|
|
21
|
+
source: z.object({
|
|
22
|
+
kind: z.enum(['figma', 'manual']),
|
|
23
|
+
fileKey: z.string().optional(),
|
|
24
|
+
fileName: z.string().optional(),
|
|
25
|
+
nodeIds: z.array(z.string()).optional(),
|
|
26
|
+
fetchedAt: z.string().optional(),
|
|
27
|
+
calls: z.number().int().optional(),
|
|
28
|
+
characters: z.number().int().optional()
|
|
29
|
+
}).strict(),
|
|
30
|
+
variables: z.record(scalar),
|
|
31
|
+
variablesDark: z.record(scalar).optional(),
|
|
32
|
+
textStyles: z.array(z.object({
|
|
33
|
+
name: z.string(),
|
|
34
|
+
role: z.enum(TEXT_STYLE_ROLES).optional(),
|
|
35
|
+
fontFamily: z.string(),
|
|
36
|
+
fontSize: z.number(),
|
|
37
|
+
fontWeight: scalar.optional(),
|
|
38
|
+
lineHeight: z.number().optional()
|
|
39
|
+
}).strict()).optional(),
|
|
40
|
+
effects: z.array(z.object({
|
|
41
|
+
name: z.string(),
|
|
42
|
+
offsetX: z.number(),
|
|
43
|
+
offsetY: z.number(),
|
|
44
|
+
blur: z.number(),
|
|
45
|
+
spread: z.number(),
|
|
46
|
+
color: z.string(),
|
|
47
|
+
opacity: z.number()
|
|
48
|
+
}).strict()).optional(),
|
|
49
|
+
layout: z.object({
|
|
50
|
+
desktopWidth: z.number().optional(),
|
|
51
|
+
mobileWidth: z.number().optional(),
|
|
52
|
+
gutter: z.number().optional(),
|
|
53
|
+
sidebarWidth: z.number().optional(),
|
|
54
|
+
notes: z.array(z.string()).optional()
|
|
55
|
+
}).strict().optional(),
|
|
56
|
+
components: z.record(z.object({
|
|
57
|
+
background: z.string().optional(),
|
|
58
|
+
color: z.string().optional(),
|
|
59
|
+
border: z.string().optional(),
|
|
60
|
+
borderRadius: scalar.optional(),
|
|
61
|
+
paddingX: z.number().optional(),
|
|
62
|
+
paddingY: z.number().optional(),
|
|
63
|
+
height: z.number().optional(),
|
|
64
|
+
fontSize: z.number().optional(),
|
|
65
|
+
fontWeight: scalar.optional(),
|
|
66
|
+
shadow: z.string().optional()
|
|
67
|
+
}).strict()).optional(),
|
|
68
|
+
screens: z.array(z.object({
|
|
69
|
+
nodeId: z.string(),
|
|
70
|
+
name: z.string(),
|
|
71
|
+
role: z.enum(SCREEN_ROLES),
|
|
72
|
+
screenshot: z.string().optional(),
|
|
73
|
+
notes: z.array(z.string()).optional()
|
|
74
|
+
}).strict()).optional(),
|
|
75
|
+
/** Figma adı → tema yolu (`accent.muted`, `colors.blue.500`) ya da `ignore`; ajanın KALICI kararı. */
|
|
76
|
+
hints: z.record(z.string()).optional()
|
|
77
|
+
}).strict();
|
|
@@ -1905,6 +1905,53 @@ export function inertFlexPropWarning(entries) {
|
|
|
1905
1905
|
+ "sessizce yok sayılır (istek reddedilmez, prop katalogda vardır). Akış düzeni istiyorsan aynı düğüme "
|
|
1906
1906
|
+ "layout:'flex' de yaz, istemiyorsan bu prop'ları kaldır — platform_guide('page') Kural 1f-2."];
|
|
1907
1907
|
}
|
|
1908
|
+
/**
|
|
1909
|
+
* Akış id'si → ona bağlı olaylar. Bağ üç yerde durur: düğümün `events[].value`'su, düğüm
|
|
1910
|
+
* prop'larındaki `type:'flow'` referansları (`event` alanı `prop:<ad>` olur) ve barındırıcının
|
|
1911
|
+
* düzey olayları (`target: 'page'` — `remove_event`'in aynı hedef adı). Akış tarafından bu
|
|
1912
|
+
* listeyi veren bir uç yok; 2026-09-16 raporunda uygulama kabuğunda hangi olayın hangi akışa
|
|
1913
|
+
* bağlı olduğu kaybolmuş, ikinci "zil rozeti" akışı sahipsiz kalmıştı.
|
|
1914
|
+
*/
|
|
1915
|
+
export function flowBindings(schema, hostEvents) {
|
|
1916
|
+
const bindings = new Map();
|
|
1917
|
+
const add = (flowId, binding) => {
|
|
1918
|
+
if (flowId === '')
|
|
1919
|
+
return;
|
|
1920
|
+
bindings.set(flowId.toLowerCase(), [...(bindings.get(flowId.toLowerCase()) ?? []), binding]);
|
|
1921
|
+
};
|
|
1922
|
+
for (const event of asObjects(hostEvents)) {
|
|
1923
|
+
if (typeof event.value === 'string')
|
|
1924
|
+
add(event.value, { target: 'page', event: String(event.name ?? '') });
|
|
1925
|
+
}
|
|
1926
|
+
const visitProp = (target, propName, value) => {
|
|
1927
|
+
if (Array.isArray(value)) {
|
|
1928
|
+
for (const entry of value)
|
|
1929
|
+
visitProp(target, propName, entry);
|
|
1930
|
+
return;
|
|
1931
|
+
}
|
|
1932
|
+
if (!value || typeof value !== 'object')
|
|
1933
|
+
return;
|
|
1934
|
+
const record = value;
|
|
1935
|
+
if (record.type === 'flow' && typeof record.ref === 'string')
|
|
1936
|
+
add(record.ref, { target, event: `prop:${propName}` });
|
|
1937
|
+
for (const entry of Object.values(record))
|
|
1938
|
+
visitProp(target, propName, entry);
|
|
1939
|
+
};
|
|
1940
|
+
const visitNode = (node) => {
|
|
1941
|
+
const target = String(node.elementId ?? node.name ?? '');
|
|
1942
|
+
for (const event of asObjects(node.events)) {
|
|
1943
|
+
if (typeof event.value === 'string')
|
|
1944
|
+
add(event.value, { target, event: String(event.name ?? '') });
|
|
1945
|
+
}
|
|
1946
|
+
for (const [propName, value] of Object.entries((node.props ?? {})))
|
|
1947
|
+
visitProp(target, propName, value);
|
|
1948
|
+
for (const child of asObjects(node.children))
|
|
1949
|
+
visitNode(child);
|
|
1950
|
+
};
|
|
1951
|
+
for (const node of asObjects(schema))
|
|
1952
|
+
visitNode(node);
|
|
1953
|
+
return bindings;
|
|
1954
|
+
}
|
|
1908
1955
|
/**
|
|
1909
1956
|
* Bir yamanın SİLECEĞİ akışlar. Platform referanssız kalan akışı KALICI siler; uyarı yamadan sonra
|
|
1910
1957
|
* geldiğinde "önce yedekle" tavsiyesi uygulanamaz hâle geliyordu (09-05 koşusu: sekiz adımlı giriş
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { readKnowledgeFile } from '../resources/knowledge.js';
|
|
2
|
+
import { PlatformApiError } from '../platform/errors.js';
|
|
3
|
+
import { discoverTheme } from './themeDiscover.js';
|
|
4
|
+
const ARCHETYPES = {
|
|
5
|
+
form: { example: 'page-form-upsert', flows: { mount: 'mountFlowCreateArgs', submit: 'submitFlowCreateArgs' } },
|
|
6
|
+
detail: { example: 'page-detail-profile', flows: { mount: 'mountFlowCreateArgs' } },
|
|
7
|
+
auth: { example: 'page-sign-in', flows: { submit: 'submitFlowCreateArgs' } }
|
|
8
|
+
};
|
|
9
|
+
const LIST_ARCHETYPE = 'list (kod içi iskelet) + flow-list-to-form';
|
|
10
|
+
const SHELL_EXAMPLE = 'layout-app-shell';
|
|
11
|
+
const LIST_EVENTS_EXAMPLE = 'flow-list-to-form';
|
|
12
|
+
const turkishMap = { ç: 'c', ğ: 'g', ı: 'i', ö: 'o', ş: 's', ü: 'u', â: 'a', î: 'i', û: 'u' };
|
|
13
|
+
export function slugifyScreenName(name) {
|
|
14
|
+
return name.toLocaleLowerCase('tr')
|
|
15
|
+
.replace(/[çğıöşüâîû]/g, letter => turkishMap[letter] ?? letter)
|
|
16
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
17
|
+
.replace(/^-+|-+$/g, '');
|
|
18
|
+
}
|
|
19
|
+
const readExample = (name) => JSON.parse(readKnowledgeFile('examples', `${name}.json`));
|
|
20
|
+
const isPlaceholder = (value) => typeof value === 'string' && value.startsWith('<');
|
|
21
|
+
const staticProp = (data) => ({ type: 'static', data });
|
|
22
|
+
const node = (elementId, type, props, wrapper, block) => ({
|
|
23
|
+
elementId,
|
|
24
|
+
kind: 'component',
|
|
25
|
+
type,
|
|
26
|
+
name: elementId,
|
|
27
|
+
props,
|
|
28
|
+
states: { isSticky: false, isDroppable: wrapper, isScrollable: false, isWrapper: wrapper },
|
|
29
|
+
blocks: [{ breakpoint: 1024, size: { h: block.h, w: block.w }, position: { x: block.x, y: block.y } }],
|
|
30
|
+
children: [],
|
|
31
|
+
events: [],
|
|
32
|
+
validations: [],
|
|
33
|
+
stateBindings: []
|
|
34
|
+
});
|
|
35
|
+
/** Liste sayfası asgari iskeleti: araç çubuğu (Yeni) + kayıt tablosu; adlar `flow-list-to-form` ile aynı. */
|
|
36
|
+
function listSkeleton() {
|
|
37
|
+
return [
|
|
38
|
+
{ op: 'add_component', parent: 'page_container', component: node('list_toolbar', 'container', { layout: staticProp('flex'), direction: staticProp('row') }, true, { h: 4, w: 12, x: 0, y: 0 }) },
|
|
39
|
+
{ op: 'add_component', parent: 'list_toolbar', component: node('btn_new', 'button', { text: staticProp('Yeni') }, false, { h: 4, w: 3, x: 0, y: 0 }) },
|
|
40
|
+
{ op: 'add_component', parent: 'page_container', component: node('records_table', 'table', {}, false, { h: 40, w: 12, x: 0, y: 4 }) }
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
function pageArgs(screenName, base, options, caveats) {
|
|
44
|
+
const args = { ...base, name: screenName, slug: slugifyScreenName(screenName), browserTitle: screenName };
|
|
45
|
+
if (options.layoutId !== undefined) {
|
|
46
|
+
args.layoutId = options.layoutId;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
if (isPlaceholder(args.layoutId) || args.layoutId === undefined)
|
|
50
|
+
delete args.layoutId;
|
|
51
|
+
caveats.push("layoutId verilmedi — sayfa kabuksuz açılır; kabuk için 'shell' ekranını page_discover ile layout_create'e çevirip (ya da layout_list ile mevcut kabuğu bulup) pageCreateArgs.layoutId verin");
|
|
52
|
+
}
|
|
53
|
+
if (options.middlewareIds !== undefined) {
|
|
54
|
+
args.middlewareIds = options.middlewareIds;
|
|
55
|
+
}
|
|
56
|
+
else if (Array.isArray(args.middlewareIds) && args.middlewareIds.some(isPlaceholder)) {
|
|
57
|
+
delete args.middlewareIds;
|
|
58
|
+
caveats.push('middlewareIds verilmedi — örnek korumalı sayfa istiyor; auth middleware id için middleware_list, sonra pageCreateArgs.middlewareIds (bir-iki ucu bağlayıp gerisini açık bırakmak yasak)');
|
|
59
|
+
}
|
|
60
|
+
return args;
|
|
61
|
+
}
|
|
62
|
+
/** Tek aday preset bağlanır (`props.style = { $preset }`); birden çok aday karar ister (K4). */
|
|
63
|
+
function bindPresets(ops, presets, caveats) {
|
|
64
|
+
const bindings = [];
|
|
65
|
+
for (const op of ops) {
|
|
66
|
+
if (op.op !== 'add_component')
|
|
67
|
+
continue;
|
|
68
|
+
const component = op.component;
|
|
69
|
+
const type = typeof component?.type === 'string' ? component.type : undefined;
|
|
70
|
+
const elementId = typeof component?.elementId === 'string' ? component.elementId : undefined;
|
|
71
|
+
if (component === undefined || type === undefined || elementId === undefined)
|
|
72
|
+
continue;
|
|
73
|
+
const candidates = presets.filter(preset => preset === type || preset.startsWith(`${type}-`));
|
|
74
|
+
if (candidates.length === 1) {
|
|
75
|
+
component.props = { ...(component.props ?? {}), style: { $preset: candidates[0] } };
|
|
76
|
+
bindings.push({ elementId, type, preset: candidates[0] });
|
|
77
|
+
}
|
|
78
|
+
else if (candidates.length > 1) {
|
|
79
|
+
caveats.push(`${elementId} (${type}) için birden çok preset adayı var: ${candidates.join(', ')} — hangisi olacağına siz karar verin (page_schema_patch replace_prop style { $preset })`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return bindings;
|
|
83
|
+
}
|
|
84
|
+
export function discoverPage(snapshot, screenRef, options = {}) {
|
|
85
|
+
const screens = snapshot.screens ?? [];
|
|
86
|
+
const screen = screens.find(entry => entry.nodeId === screenRef) ?? screens.find(entry => entry.name === screenRef);
|
|
87
|
+
if (screen === undefined) {
|
|
88
|
+
throw new PlatformApiError(`page_discover: '${screenRef}' anlık görüntünün screens listesinde yok (nodeId ya da name). Mevcut ekranlar: ${screens.map(entry => `${entry.name} (${entry.nodeId}, ${entry.role})`).join(' · ') || 'yok'}.`, 400);
|
|
89
|
+
}
|
|
90
|
+
const caveats = [];
|
|
91
|
+
const notes = [...(snapshot.layout?.notes ?? []), ...(screen.notes ?? [])];
|
|
92
|
+
const head = { screen: { nodeId: screen.nodeId, name: screen.name, role: screen.role }, notes };
|
|
93
|
+
const presets = Object.keys(discoverTheme(snapshot).theme.presets ?? {});
|
|
94
|
+
if (screen.role === 'shell') {
|
|
95
|
+
const example = readExample(SHELL_EXAMPLE);
|
|
96
|
+
return {
|
|
97
|
+
...head,
|
|
98
|
+
archetype: SHELL_EXAMPLE,
|
|
99
|
+
layoutCreateArgs: { ...example.layoutCreate, name: screen.name },
|
|
100
|
+
schemaPatchOps: [],
|
|
101
|
+
flows: {},
|
|
102
|
+
presetBindings: [],
|
|
103
|
+
caveats: ['kabuk bir SAYFA değil LAYOUT kaydıdır; yan menü/üst şerit içeriğini ekran notlarına göre layout_schema_patch ile doldurun'],
|
|
104
|
+
next: 'layout_create(layoutCreateArgs) → layout_list ile id → diğer ekranların pageCreateArgs.layoutId'
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
if (screen.role === 'other') {
|
|
108
|
+
return {
|
|
109
|
+
...head,
|
|
110
|
+
archetype: 'yok',
|
|
111
|
+
pageCreateArgs: pageArgs(screen.name, {}, options, caveats),
|
|
112
|
+
schemaPatchOps: [],
|
|
113
|
+
flows: {},
|
|
114
|
+
presetBindings: [],
|
|
115
|
+
caveats: [...caveats, "rol 'other' — arketip yok; ekran notlarına göre page_schema_patch ile elle kurun (platform_guide('page') §arketipler) ya da anlık görüntüde role list/form/detail/auth verin"],
|
|
116
|
+
next: "page_create(pageCreateArgs) → page_schema_patch(ops — elle) → page_screenshot"
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
if (screen.role === 'list') {
|
|
120
|
+
const events = readExample(LIST_EVENTS_EXAMPLE);
|
|
121
|
+
const ops = [...listSkeleton(), ...(events.schemaPatchOps ?? [])];
|
|
122
|
+
const presetBindings = bindPresets(ops, presets, caveats);
|
|
123
|
+
caveats.push("records_table props boş — kolonları ve veri kaynağını component_get('table') + flow-load-table örneğine göre verin; set_event op'larındaki '<… flow id>' yer tutucuları flow_create sonrası gerçek id ile değiştirilir");
|
|
124
|
+
return {
|
|
125
|
+
...head,
|
|
126
|
+
archetype: LIST_ARCHETYPE,
|
|
127
|
+
pageCreateArgs: pageArgs(screen.name, {}, options, caveats),
|
|
128
|
+
schemaPatchOps: ops,
|
|
129
|
+
flows: { openRecord: events.openRecordFlowCreateArgs, newRecord: events.newRecordFlowCreateArgs },
|
|
130
|
+
presetBindings,
|
|
131
|
+
caveats,
|
|
132
|
+
next: 'page_create(pageCreateArgs) → flow_create(flows.openRecord, flows.newRecord) → set_event yer tutucularını flow id ile değiştir → page_schema_patch(schemaPatchOps) → page_screenshot'
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
const archetype = ARCHETYPES[screen.role];
|
|
136
|
+
const example = readExample(archetype.example);
|
|
137
|
+
const ops = structuredClone(example.schemaPatchOps ?? []);
|
|
138
|
+
const presetBindings = bindPresets(ops, presets, caveats);
|
|
139
|
+
const flows = Object.fromEntries(Object.entries(archetype.flows).map(([key, field]) => [key, example[field]]).filter(([, value]) => value !== undefined));
|
|
140
|
+
caveats.push(`iskelet '${archetype.example}' altın örneğinden — elementId'ler ve metinler örneğin domainindedir (${String(example.pageCreateArgs?.name ?? '')}); ekran notlarına göre alan adlarını, etiketleri ve akış adımlarını değiştirin`);
|
|
141
|
+
return {
|
|
142
|
+
...head,
|
|
143
|
+
archetype: archetype.example,
|
|
144
|
+
pageCreateArgs: pageArgs(screen.name, example.pageCreateArgs ?? {}, options, caveats),
|
|
145
|
+
schemaPatchOps: ops,
|
|
146
|
+
flows,
|
|
147
|
+
presetBindings,
|
|
148
|
+
caveats,
|
|
149
|
+
next: 'page_create(pageCreateArgs) → page_schema_patch(pageId, schemaPatchOps) → flow_create(flows.*) ve set_event yer tutucularını flow id ile değiştir → page_screenshot'
|
|
150
|
+
};
|
|
151
|
+
}
|