@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.
- package/.env.example +0 -15
- package/dist/config.js +0 -11
- package/dist/index.js +0 -2
- package/dist/knowledge/componentCatalog.js +25 -13
- package/dist/knowledge/componentEvents.js +6 -13
- package/dist/knowledge/normalize.js +17 -68
- package/dist/knowledge/rules.js +49 -137
- package/dist/knowledge/styleResolve.js +4 -50
- package/dist/knowledge/themeResolve.js +3 -3
- package/dist/observability/trace.js +1 -1
- package/dist/platform/diagnostics.js +4 -10
- package/dist/platform/domSummary.js +1 -1
- package/dist/platform/http.js +7 -23
- package/dist/platform/responses.js +2 -6
- package/dist/platform/{capture/capture.js → screenshot.js} +514 -52
- package/dist/platform/secrets.js +0 -9
- package/dist/platform/strictArguments.js +12 -68
- package/dist/platform/tokenVault.js +4 -187
- package/dist/resources/examples/workflow-http-step.json +2 -2
- package/dist/resources/guides/component.md +1 -6
- package/dist/resources/guides/expressions.md +2 -2
- package/dist/resources/guides/functions.md +1 -1
- package/dist/resources/guides/layout.md +7 -11
- package/dist/resources/guides/microfunction.md +28 -0
- package/dist/resources/guides/microservice.md +4 -10
- package/dist/resources/guides/middleware.md +1 -5
- package/dist/resources/guides/page.md +55 -215
- package/dist/resources/guides/theme.md +1 -4
- package/dist/resources/guides/translation.md +1 -1
- package/dist/resources/guides/workflow.md +9 -12
- package/dist/resources/schema-fingerprint.json +2 -2
- package/dist/resources/schemas/CreateWorkflowCommand.json +3 -0
- package/dist/resources/schemas/PreviewWorkflowCommand.json +3 -0
- package/dist/resources/schemas/StepDto.json +12 -9
- package/dist/resources/schemas/UpdateWorkflowCommand.json +3 -0
- package/dist/server.js +1 -3
- package/dist/tools/applications.js +3 -60
- package/dist/tools/components.js +10 -50
- package/dist/tools/datasources.js +1 -1
- package/dist/tools/designSchemaPatch.js +6 -16
- package/dist/tools/externalComponents.js +4 -25
- package/dist/tools/flows.js +6 -79
- package/dist/tools/layouts.js +12 -44
- package/dist/tools/microservices.js +10 -26
- package/dist/tools/pages.js +67 -303
- package/dist/tools/platformInfo.js +2 -6
- package/dist/tools/rows.js +1 -7
- package/dist/tools/schemaOps.js +1 -1
- package/dist/tools/screenWrite.js +5 -6
- package/dist/tools/screens.js +3 -90
- package/dist/tools/workflows.js +1 -1
- package/package.json +1 -1
- package/dist/knowledge/mobileComponentCatalog.js +0 -801
- package/dist/knowledge/mobileComponentEvents.js +0 -225
- package/dist/knowledge/platform/lint.js +0 -312
- package/dist/knowledge/platform/mobile.js +0 -78
- package/dist/knowledge/platform/mobileRules.js +0 -182
- package/dist/knowledge/platform/mobileTabs.js +0 -108
- package/dist/knowledge/platform/profile.js +0 -20
- package/dist/knowledge/platform/resolve.js +0 -122
- package/dist/knowledge/platform/web.js +0 -38
- package/dist/knowledge/styleResolveNative.js +0 -510
- package/dist/platform/argumentAliases.js +0 -128
- package/dist/platform/bodyFile.js +0 -103
- package/dist/platform/capture/actions.js +0 -333
- package/dist/platform/capture/browser.js +0 -1
- package/dist/platform/capture/console-log.js +0 -80
- package/dist/platform/capture/index.js +0 -11
- package/dist/platform/capture/readiness.js +0 -103
- package/dist/platform/capture/summary.js +0 -77
- package/dist/platform/capture/target.js +0 -5
- package/dist/platform/capture/targets/studio-mobile.js +0 -15
- package/dist/platform/capture/targets/studio-web.js +0 -5
- package/dist/platform/schemaReadMemory.js +0 -60
- package/dist/resources/examples/mobile-app-shell-drawer.json +0 -209
- package/dist/resources/examples/mobile-app-shell-stack.json +0 -123
- package/dist/resources/examples/mobile-app-shell-tab.json +0 -174
- package/dist/resources/examples/mobile-list-detail-form.json +0 -656
- package/dist/resources/guides/mobile.md +0 -419
- package/dist/tools/mobile.js +0 -203
- package/dist/tools/profileWrite.js +0 -45
package/dist/knowledge/rules.js
CHANGED
|
@@ -69,12 +69,21 @@ function carriesValue(value) {
|
|
|
69
69
|
return value.trim() !== '';
|
|
70
70
|
return true;
|
|
71
71
|
}
|
|
72
|
-
|
|
72
|
+
/**
|
|
73
|
+
* `type` tipindeki adımlar ve `loop` adımının `rule.stepType === type` olan çocuk kuralı.
|
|
74
|
+
* `LoopStep.cs` çocuğu `rule.Children.FirstOrDefault()` ile aynı tipin keyed `IStep`'ine verir:
|
|
75
|
+
* çocuk, üst seviyedeki aynı tip adımla AYNI kuralı okur ve aynı denetimden geçmelidir. İki
|
|
76
|
+
* kullanıcısı var: WF-032 (`workflow`) ve WF-MF-001 (`microfunction`; loop içinde koştuğu
|
|
77
|
+
* ölçüldü 2026-09-28, zeyrek-backend/docs/microfunction/03-workflow-adimi.md §Loop içinde).
|
|
78
|
+
* Etiketteki "(loop çocuğu)" bulguyu okuyan
|
|
79
|
+
* ajanı adımın `rule.stepRule`'una yönlendirir.
|
|
80
|
+
*/
|
|
81
|
+
function stepCallSites(body, type) {
|
|
73
82
|
return workflowSteps(body).flatMap((step) => {
|
|
74
83
|
const rule = (step.rule ?? {});
|
|
75
|
-
if (step.type ===
|
|
84
|
+
if (step.type === type)
|
|
76
85
|
return [{ step, rule, label: stepLabel(step) }];
|
|
77
|
-
if (step.type === 'loop' && rule.stepType ===
|
|
86
|
+
if (step.type === 'loop' && rule.stepType === type && rule.stepRule && typeof rule.stepRule === 'object') {
|
|
78
87
|
return [{ step, rule: rule.stepRule, label: `${stepLabel(step)} (loop çocuğu)` }];
|
|
79
88
|
}
|
|
80
89
|
return [];
|
|
@@ -137,14 +146,11 @@ export function readsBeforeGuard(source, root) {
|
|
|
137
146
|
* code.ts:49). Eşleşme yoksa flow-engine.ts:79 sessizce durur. Studio tarafında da zincir
|
|
138
147
|
* `sourceBranch === 'always'` ile çizilir (EventActionsStart.svelte:47, EventActionsItem.svelte:298).
|
|
139
148
|
* condition dalları rule id'sidir (serbest), microservice'te 'success' yalnız eski şema için
|
|
140
|
-
* yaşatılır (microservice.ts:
|
|
141
|
-
* KENDİSİ tanır (ADR 0004, ZM-07/g-02): bağlıysa hata anında `always` hiç koşmaz, sürer
|
|
142
|
-
* (microservice.ts:182 `hasBranch`) — eski motor tanımadığı dalı hiç aramadığı için bu ekleme
|
|
143
|
-
* geriye dönük zararsızdır.
|
|
149
|
+
* yaşatılır (microservice.ts:144).
|
|
144
150
|
*/
|
|
145
151
|
const flowBranchNames = {
|
|
146
152
|
start: ['always'],
|
|
147
|
-
microservice: ['always', 'success'
|
|
153
|
+
microservice: ['always', 'success'],
|
|
148
154
|
confirm: ['yes', 'no', 'always'],
|
|
149
155
|
function: ['always'],
|
|
150
156
|
end: []
|
|
@@ -157,7 +163,7 @@ const flowBranchNames = {
|
|
|
157
163
|
*/
|
|
158
164
|
export const knownFlowStepTypes = new Set([
|
|
159
165
|
'start', 'end', 'query', 'setter', 'download', 'condition', 'redirect', 'setcookie', 'alert', 'confirm',
|
|
160
|
-
'microservice', 'validation', 'flow-trigger', 'storage', 'navigate', 'code', 'function'
|
|
166
|
+
'microservice', 'validation', 'flow-trigger', 'storage', 'navigate', 'code', 'function'
|
|
161
167
|
]);
|
|
162
168
|
const flowFreeBranchTypes = new Set(['condition']);
|
|
163
169
|
/** `condition.types.ts` ConditionArgumentRuleType — motorun tanıdığı üçlü. */
|
|
@@ -170,15 +176,16 @@ const conditionRuleIdPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}
|
|
|
170
176
|
// Runtime.svelte'de HAM verilir (`argument: step.args`), yani bu alanlarda ifade değerlendirilmez.
|
|
171
177
|
const flowLiteralTextFields = new Map([
|
|
172
178
|
['alert', ['message', 'description']],
|
|
173
|
-
['confirm', ['message', 'title', 'confirmText', 'cancelText']]
|
|
174
|
-
['share', ['title']]
|
|
179
|
+
['confirm', ['message', 'title', 'confirmText', 'cancelText']]
|
|
175
180
|
]);
|
|
176
181
|
const flowExpressionLooking = /\$\{|\b(?:Steps|Page|Row|Widget|LocalStorage|state|self|item|event|error|cookie)\s*(?:\?\.|\.|\[)/;
|
|
177
|
-
// Barındırıcıya özel tipler
|
|
178
|
-
//
|
|
179
|
-
//
|
|
180
|
-
//
|
|
181
|
-
//
|
|
182
|
+
// Barındırıcıya özel tipler (`navigate` web'de, `confirm`/`download` mobilde register edilmez)
|
|
183
|
+
// BURADA kural üretmez. `navigate`i gateway normalizasyonu zaten `redirect`e çeviriyor
|
|
184
|
+
// (normalize.ts `normalizeFlowHostGaps`) — `redirect` iki barındırıcıda da koşar, yani vaka
|
|
185
|
+
// uyarılmaz, ORTADAN KALKAR. Geriye kalan `confirm`/`download` tek başına kusur değildir: sayfa
|
|
186
|
+
// tek bir uygulamaya aittir (`Page.ApplicationId`), uygulamanın tipi web ya da mobile'dır
|
|
187
|
+
// (`ApplicationType.cs`) ve gateway hangisi olduğunu bilmez. Mobil ayağı uygulama tarafında
|
|
188
|
+
// kapanır (`ScreenRuntime.tsx`), lint'te değil.
|
|
182
189
|
const flowUnregisteredStepTypes = new Set(['end', 'query']);
|
|
183
190
|
const flowSetterIterateeTypes = new Set(['change', 'fill']);
|
|
184
191
|
function flowStepList(value) {
|
|
@@ -298,71 +305,25 @@ function writesRolesWithoutSlug(entityId, parameters) {
|
|
|
298
305
|
}
|
|
299
306
|
const rolesSlugMessage = "Built-in 'roles' entity'sine slug YAZMADAN rol satırı ÜRETİLİYOR (operation create/upsert). Insert 200 döner, satır role_list'te görünür ve page.roleIds ile bağlanır — ama yetkilendirme SLUG karşılaştırır: platformun get-user sorgusu roles+user_roles join'inden slug dizisi üretir ve Authorized(user.roles) o rol için hiçbir zaman tutmaz. fields'a slug'ı ekleyin ('super-admin' slug'ını vermeyin — platform süper yöneticiyi o slug ile arar). Upsert'te slug'ı İFADEYLE üretmeyin: UPDATE yolunda ifade yeniden değerlendirilir ve var olan rolün slug'ı sessizce değişir (MS-016) — üretilen slug'ı yalnız create ucunda yazın. Rolü kullanıcıya bağlamak ayrı bir user_roles satırıdır.";
|
|
300
307
|
const contractKeys = ['returnDtoId', 'parameterDtoId', 'returnBehavior', 'parameterBehavior'];
|
|
301
|
-
|
|
302
|
-
* Filtre işleci sözlüğü — backend `OperatorType` enum'u (paketlenmiş `Filter` şeması; eşitliği
|
|
303
|
-
* `test/filter-operators.test.ts` kilitler). Studio filtre ARAYÜZÜNÜN sözlüğü (`notContains`, `between`…,
|
|
304
|
-
* `componentCatalog.ts`) ayrı bir kavramdır: arayüz onları bu işleçlere çevirir.
|
|
305
|
-
*/
|
|
306
|
-
export const filterOperators = new Set(['eq', 'neq', 'lt', 'lte', 'gt', 'gte', 'contains', 'icontains', 'in', 'notin', 'startswith', 'endswith', 'istartswith', 'iendswith', 'isnull', 'isnotnull']);
|
|
307
|
-
/** Ajanların sık yazdığı yanlış adlar → doğru işleç. Yalnız ÖNERİLİR, sessizce çevrilmez. */
|
|
308
|
-
const filterOperatorSuggestions = {
|
|
309
|
-
ne: 'neq', '!=': 'neq', '<>': 'neq', noteq: 'neq', notequal: 'neq', notequals: 'neq', not_eq: 'neq',
|
|
310
|
-
'=': 'eq', '==': 'eq', equal: 'eq', equals: 'eq',
|
|
311
|
-
'<': 'lt', '<=': 'lte', '>': 'gt', '>=': 'gte',
|
|
312
|
-
like: 'contains', ilike: 'icontains', nin: 'notin', 'not in': 'notin', not_in: 'notin'
|
|
313
|
-
};
|
|
308
|
+
const filterOperators = new Set(['eq', 'neq', 'lt', 'lte', 'gt', 'gte', 'contains', 'icontains', 'in', 'notin', 'startswith', 'endswith', 'istartswith', 'iendswith', 'isnull', 'isnotnull']);
|
|
314
309
|
function flattenFilterTree(filters) {
|
|
315
310
|
return filters
|
|
316
311
|
.filter((filter) => Boolean(filter) && typeof filter === 'object')
|
|
317
312
|
.flatMap(filter => [filter, ...flattenFilterTree(asArray(filter.children))]);
|
|
318
313
|
}
|
|
319
|
-
/**
|
|
320
|
-
* Bilinmeyen işleçler, öneriyle: `status: 'ne' (neq mı demek istedin?)`. Grup çocukları da okunur. Ad
|
|
321
|
-
* büyük/küçük harfe DUYARLI eşlenir — backend de öyle eşler (`GetValueFromDescription` `==`); `NEQ`
|
|
322
|
-
* bilinmeyendir ve küçük harfli adı önerilir.
|
|
323
|
-
*/
|
|
324
|
-
function unknownFilterOperators(filters) {
|
|
325
|
-
return flattenFilterTree(filters)
|
|
326
|
-
.filter(filter => filter.operator !== undefined && filter.operator !== null && !filterOperators.has(String(filter.operator)))
|
|
327
|
-
.map(filter => {
|
|
328
|
-
const operator = String(filter.operator);
|
|
329
|
-
const lower = operator.toLowerCase();
|
|
330
|
-
const suggestion = filterOperators.has(lower) ? lower : filterOperatorSuggestions[lower];
|
|
331
|
-
return `${String(filter.fieldSlug ?? filter.fieldId ?? '?')}: '${operator}'${suggestion ? ` (${suggestion} mı demek istedin?)` : ''}`;
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
const unknownOperatorConsequence = "Bilinmeyen işleç yola ve backend sürümüne göre ya 400 alır ya sessizce 'eq'e düşer ve sorgu yanlış sonuç döner (2026-09-27'den sonraki backend uç çağrısının `filters` parametresini 400 ile reddeder; workflow tablo adımı hâlâ sessizce 'eq' yapar); ad büyük/küçük harfe duyarlıdır — doğru işleci yazın";
|
|
335
314
|
function unknownOperatorFindings(ruleId, owner, filters) {
|
|
336
|
-
const unknownOperators =
|
|
315
|
+
const unknownOperators = flattenFilterTree(filters)
|
|
316
|
+
.filter(filter => filter.operator !== undefined && filter.operator !== null && !filterOperators.has(String(filter.operator).toLowerCase()))
|
|
317
|
+
.map(filter => `${String(filter.fieldSlug ?? filter.fieldId ?? '?')}: '${String(filter.operator)}'`);
|
|
337
318
|
return unknownOperators.length > 0
|
|
338
319
|
? [{
|
|
339
320
|
ruleId,
|
|
340
321
|
severity: 'block',
|
|
341
|
-
message: `${owner}: bilinmeyen filtre
|
|
322
|
+
message: `${owner}: bilinmeyen filtre operatörü — ${unknownOperators.join(', ')}. Platform bilinmeyen operatörü 400 ile REDDETMEZ, sessizce 'eq'e düşürür (EnumExtensions.GetValueFromDescription null → default) ve uç testten geçip yanlış çalışır. Geçerli sözlük: ${[...filterOperators].join(' · ')} ('like' yok — metin araması için 'contains'/'icontains').`,
|
|
342
323
|
guide: 'ngapps://guides/microservice'
|
|
343
324
|
}]
|
|
344
325
|
: [];
|
|
345
326
|
}
|
|
346
|
-
/**
|
|
347
|
-
* Çalışma anında gelen filtre (`row_list.filters`, `microservice_execute` `filters` parametresi): dizi ya
|
|
348
|
-
* da JSON dizesi. Bilinmeyen işleç varsa hata METNİ döner — araç isteği göndermeden 400 verir
|
|
349
|
-
* (plans/mobil-plantcare-acigi g-03). Ayrıştırılamayan değer backend'e bırakılır.
|
|
350
|
-
*/
|
|
351
|
-
export function filterOperatorError(owner, filters) {
|
|
352
|
-
let parsed = filters;
|
|
353
|
-
if (typeof filters === 'string') {
|
|
354
|
-
try {
|
|
355
|
-
parsed = JSON.parse(filters);
|
|
356
|
-
}
|
|
357
|
-
catch {
|
|
358
|
-
return undefined;
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
const unknownOperators = Array.isArray(parsed) ? unknownFilterOperators(parsed) : [];
|
|
362
|
-
return unknownOperators.length > 0
|
|
363
|
-
? `${owner}: bilinmeyen filtre işleci — ${unknownOperators.join(', ')}. İstek GÖNDERİLMEDİ. ${unknownOperatorConsequence}. Geçerli sözlük: ${[...filterOperators].join(' · ')}.`
|
|
364
|
-
: undefined;
|
|
365
|
-
}
|
|
366
327
|
function isReadOperation(parameters) {
|
|
367
328
|
const operation = String(parameters?.operation ?? '').toLowerCase();
|
|
368
329
|
return !writeOperations.has(operation);
|
|
@@ -761,19 +722,17 @@ export const policyRules = [
|
|
|
761
722
|
id: 'WF-MF-001',
|
|
762
723
|
module: 'workflow',
|
|
763
724
|
appliesTo: ['create', 'update', 'preview'],
|
|
764
|
-
sourceRef: "MicrofunctionStep.cs: rule.MicrofunctionId ile kayıt yüklenir, Status != Published ise FailedOutput(MicrofunctionNotPublishedException) — adım hata dalına düşer, akış 200 dönse bile iş yapılmaz. Ölçüldü 2026-09-10 (B4 doğrulaması: taslak fonksiyona bağlı uç 500 MicrofunctionNotPublishedException)",
|
|
765
|
-
check: definition => {
|
|
766
|
-
const body = workflowBody(definition);
|
|
767
|
-
return
|
|
768
|
-
.
|
|
769
|
-
.flatMap((step) => {
|
|
770
|
-
const rule = (step.rule ?? {});
|
|
725
|
+
sourceRef: "MicrofunctionStep.cs: rule.MicrofunctionId ile kayıt yüklenir, Status != Published ise FailedOutput(MicrofunctionNotPublishedException) — adım hata dalına düşer, akış 200 dönse bile iş yapılmaz. Ölçüldü 2026-09-10 (B4 doğrulaması: taslak fonksiyona bağlı uç 500 MicrofunctionNotPublishedException). Loop çocuğu (rule.stepType: 'microfunction', rule.stepRule) aynı adımla koşar — ölçüldü 2026-09-28, microfunction-faz-2/development; taslak seçen loop İLK iterasyonda fail dalına düşer ve durur (ölçülen çıktı [{ item: 1 }])",
|
|
726
|
+
check: (definition, context) => {
|
|
727
|
+
const body = workflowBody(definition, context.workflowKind);
|
|
728
|
+
return stepCallSites(body, 'microfunction')
|
|
729
|
+
.flatMap(({ rule, label }) => {
|
|
771
730
|
const microfunctionId = rule.microfunctionId;
|
|
772
731
|
if (!hasText(microfunctionId)) {
|
|
773
732
|
return [{
|
|
774
733
|
ruleId: 'WF-MF-001',
|
|
775
734
|
severity: 'block',
|
|
776
|
-
message: `'${
|
|
735
|
+
message: `'${label}' microfunction adımında rule.microfunctionId yok — adım hangi fonksiyonu koşturacağını bilmez. microfunction_list(status: 'published') ile id seçin; argümanlar rule.expression'a yazılır (fonksiyonun parameterDto'su varsa o şemaya göre).`,
|
|
777
736
|
guide: 'ngapps://guides/microfunction'
|
|
778
737
|
}];
|
|
779
738
|
}
|
|
@@ -781,7 +740,7 @@ export const policyRules = [
|
|
|
781
740
|
return [{
|
|
782
741
|
ruleId: 'WF-MF-001',
|
|
783
742
|
severity: 'block',
|
|
784
|
-
message: `'${
|
|
743
|
+
message: `'${label}' adımının rule.microfunctionId'si GUID değil: '${String(microfunctionId)}'. Platform alanı Guid'e çeviremediği için 400 döner.`,
|
|
785
744
|
guide: 'ngapps://guides/microfunction'
|
|
786
745
|
}];
|
|
787
746
|
}
|
|
@@ -794,7 +753,7 @@ export const policyRules = [
|
|
|
794
753
|
module: 'workflow',
|
|
795
754
|
appliesTo: ['create', 'update', 'preview'],
|
|
796
755
|
sourceRef: "WorkflowStep.cs EvaluateAsync: kural yalnız rule.WorkflowId ve rule.Expression okur; girdi workflow.HasParameter iken Expression'ın DataTransferObjectExpression.Eval'iyle bağlanır, başka hiçbir alan okunmaz. Studio WorkflowTrigger.svelte de yalnız bu iki alanı yazar ve expression'ı çağrılan akışın parameterScheme'inden nesne literali olarak doldurur. RFQ koşusu W-7 (2026-09-14): payloadExpression/customParameters kaydedildi, alt akış girdisiz koştu",
|
|
797
|
-
check: (definition, context) =>
|
|
756
|
+
check: (definition, context) => stepCallSites(workflowBody(definition, context.workflowKind), 'workflow').flatMap(({ label, rule }) => {
|
|
798
757
|
const workflowId = rule.workflowId;
|
|
799
758
|
if (!hasText(workflowId)) {
|
|
800
759
|
return [{
|
|
@@ -2254,7 +2213,7 @@ export const policyRules = [
|
|
|
2254
2213
|
findings.push({
|
|
2255
2214
|
ruleId: 'WF-018',
|
|
2256
2215
|
severity: 'block',
|
|
2257
|
-
message: `'${stepLabel(step)}' loop step'inde rule.stepRule yok${hasChildren ? " — ama rule.children dolu: çocuk kural alanının adı 'children' DEĞİL 'stepRule'dur (tekil)" : ''}. Çocuksuz loop çalışma anında NullReferenceException verir ve hata mesajı arrayExpression'ı suçlar. Çocuğun kendi rule gövdesini rule.stepRule'a koyun; loop'un çıktısı [{ item, result }] dizisidir. Geçerli öğeye 'loopItem' ile erişilir AMA yalnız loop'un kendi değerlendirdiği ifadelerde (table çocuğunun fields[].value / filters[].value gibi) — 'code' çocuğunda loopItem TANIMSIZDIR ve adım "loopItem is not defined" ile düşer (ölçüldü 2026-09-16); her öğe için hesabı arrayExpression'da önden yapın.`,
|
|
2216
|
+
message: `'${stepLabel(step)}' loop step'inde rule.stepRule yok${hasChildren ? " — ama rule.children dolu: çocuk kural alanının adı 'children' DEĞİL 'stepRule'dur (tekil)" : ''}. Çocuksuz loop çalışma anında NullReferenceException verir ve hata mesajı arrayExpression'ı suçlar. Çocuğun kendi rule gövdesini rule.stepRule'a koyun; loop'un çıktısı [{ item, result }] dizisidir. Geçerli öğeye 'loopItem' ile erişilir AMA yalnız loop'un kendi değerlendirdiği ifadelerde (table çocuğunun fields[].value / filters[].value, workflow ve microfunction çocuğunun expression'ı gibi) — 'code' çocuğunda loopItem TANIMSIZDIR ve adım "loopItem is not defined" ile düşer (ölçüldü 2026-09-16); her öğe için hesabı arrayExpression'da önden yapın.`,
|
|
2258
2217
|
guide: 'ngapps://guides/workflow'
|
|
2259
2218
|
});
|
|
2260
2219
|
}
|
|
@@ -2415,7 +2374,7 @@ export const policyRules = [
|
|
|
2415
2374
|
id: 'FLOW-022',
|
|
2416
2375
|
module: 'flow',
|
|
2417
2376
|
appliesTo: ['create', 'update'],
|
|
2418
|
-
sourceRef: "alert.ts `const { message, alertType, description } = task.argument` → toast.error(message, { description }) / dialog.alert(message); confirm.ts `dialog.confirm(message, { title, confirmText, cancelText })` (boş çerçeve metni dialog.functions.ts resolveDialogFrame'de sabit metne düşer). Argüman Runtime.svelte'de HAM geçer (`argument: step.args`) — bu alanlarda hiçbir ifade değerlendirilmez, yazılan metin ekranda harfi harfine görünür (2026-09-06·2 koşusu S-13'ün ikinci turu: rehber hata mesajını göstermek için alert adımını öneriyordu)
|
|
2377
|
+
sourceRef: "alert.ts `const { message, alertType, description } = task.argument` → toast.error(message, { description }) / dialog.alert(message); confirm.ts `dialog.confirm(message, { title, confirmText, cancelText })` (boş çerçeve metni dialog.functions.ts resolveDialogFrame'de sabit metne düşer). Argüman Runtime.svelte'de HAM geçer (`argument: step.args`) — bu alanlarda hiçbir ifade değerlendirilmez, yazılan metin ekranda harfi harfine görünür (2026-09-06·2 koşusu S-13'ün ikinci turu: rehber hata mesajını göstermek için alert adımını öneriyordu)",
|
|
2419
2378
|
check: definition => flowAllSteps(definition)
|
|
2420
2379
|
.flatMap((step) => {
|
|
2421
2380
|
const type = String(step.type ?? '');
|
|
@@ -2428,61 +2387,16 @@ export const policyRules = [
|
|
|
2428
2387
|
.map(field => ({
|
|
2429
2388
|
ruleId: 'FLOW-022',
|
|
2430
2389
|
severity: 'warn',
|
|
2431
|
-
message: type
|
|
2432
|
-
? `'${flowStepLabel(step)}' share adımının '${field}' alanı ifade içeriyor ama bu alan DÜZ METİNDİR: başlık paylaşım penceresine olduğu gibi gider (iOS'ta e-posta konusu, Android'de seçici başlığı), ifade değerlendirilmez. Değişen içeriği ifade olan 'message' alanına yazın — ör. message: "'Şuna bak: ' + Page.properties.name"; bağlantı 'path' alanındadır.`
|
|
2433
|
-
: `'${flowStepLabel(step)}' ${type} adımının '${field}' alanı ifade içeriyor ama bu alan DÜZ METİNDİR: ${type}.ts task.argument.${field}'i doğrudan ekrana geçirir ve args hiçbir yerde değerlendirilmez (Runtime.svelte \`argument: step.args\`). Kullanıcı ifadenin sonucunu değil ifadenin KENDİSİNİ görür. Ucun mesajını göstermek için bir setter (ya da code) adımı kullanın — value { type: 'code', ref: 'Steps.error?.message' }; hata metninin nerede durduğu page.md §hata yolu'nda.`,
|
|
2390
|
+
message: `'${flowStepLabel(step)}' ${type} adımının '${field}' alanı ifade içeriyor ama bu alan DÜZ METİNDİR: ${type}.ts task.argument.${field}'i doğrudan ekrana geçirir ve args hiçbir yerde değerlendirilmez (Runtime.svelte \`argument: step.args\`). Kullanıcı ifadenin sonucunu değil ifadenin KENDİSİNİ görür. Ucun mesajını göstermek için bir setter (ya da code) adımı kullanın — value { type: 'code', ref: 'Steps.error?.message' }; hata metninin nerede durduğu page.md §hata yolu'nda.`,
|
|
2434
2391
|
guide: 'ngapps://guides/page'
|
|
2435
2392
|
}));
|
|
2436
2393
|
})
|
|
2437
2394
|
},
|
|
2438
|
-
{
|
|
2439
|
-
id: 'FLOW-027',
|
|
2440
|
-
module: 'flow',
|
|
2441
|
-
appliesTo: ['create', 'update'],
|
|
2442
|
-
sourceRef: "share adımının argümanı StepManagementArgument'ın Title/Message/Path alanlarında saklanır (StepType.cs `share`, kök docs/adr/0001-share-akis-adimi.md); url/link/text gibi anahtarlar sözleşmede YOKTUR ve platform onları 200 ile sessizce düşürür — adım hiçbir şey paylaşmadan akış sürer. `message` ve `path` İFADEDİR (@ng-apps/flow resolveShareContent → runCode): tırnaksız 'https://…' JS'te etiket + yorumdur, undefined döner",
|
|
2443
|
-
check: definition => flowAllSteps(definition)
|
|
2444
|
-
.filter(step => step.type === 'share')
|
|
2445
|
-
.flatMap((step) => {
|
|
2446
|
-
const args = (step.args ?? {});
|
|
2447
|
-
const filled = (key) => typeof args[key] === 'string' && String(args[key]).trim().length > 0;
|
|
2448
|
-
const findings = [];
|
|
2449
|
-
const strayLinks = ['url', 'link', 'href'].filter(filled);
|
|
2450
|
-
const strayTexts = ['text', 'body', 'content'].filter(filled);
|
|
2451
|
-
if (strayLinks.length > 0) {
|
|
2452
|
-
findings.push({
|
|
2453
|
-
ruleId: 'FLOW-027',
|
|
2454
|
-
severity: filled('path') ? 'warn' : 'block',
|
|
2455
|
-
message: `'${flowStepLabel(step)}' share adımının bağlantısı args.${strayLinks.join('/args.')} alanında: bu anahtar StepManagementArgument sözleşmesinde YOK, platform onu 200 ile sessizce düşürür ve adım bağlantısız kalır. Bağlantıyı args.path'e ifade olarak yazın — ör. "'https://ornek.app/urun/' + Page.queryParams.id".`,
|
|
2456
|
-
guide: 'ngapps://guides/page'
|
|
2457
|
-
});
|
|
2458
|
-
}
|
|
2459
|
-
if (strayTexts.length > 0) {
|
|
2460
|
-
findings.push({
|
|
2461
|
-
ruleId: 'FLOW-027',
|
|
2462
|
-
severity: filled('message') ? 'warn' : 'block',
|
|
2463
|
-
message: `'${flowStepLabel(step)}' share adımının metni args.${strayTexts.join('/args.')} alanında: bu anahtar StepManagementArgument sözleşmesinde YOK, platform onu sessizce düşürür. Metni args.message'a ifade olarak yazın — ör. "'Şuna bak: ' + Page.properties.name".`,
|
|
2464
|
-
guide: 'ngapps://guides/page'
|
|
2465
|
-
});
|
|
2466
|
-
}
|
|
2467
|
-
for (const key of ['message', 'path']) {
|
|
2468
|
-
const value = typeof args[key] === 'string' ? String(args[key]).trim() : '';
|
|
2469
|
-
if (/^[a-z][a-z\d+\-.]*:\/\//i.test(value)) {
|
|
2470
|
-
findings.push({
|
|
2471
|
-
ruleId: 'FLOW-027',
|
|
2472
|
-
severity: 'block',
|
|
2473
|
-
message: `'${flowStepLabel(step)}' share adımının '${key}' alanı tırnaksız bir adres: '${value}'. Bu alan İFADEDİR — tırnaksız adres JS'te etiket + yorumdur, undefined döner ve hiçbir şey paylaşılmaz. Dize olarak yazın: "'${value}'".`,
|
|
2474
|
-
guide: 'ngapps://guides/page'
|
|
2475
|
-
});
|
|
2476
|
-
}
|
|
2477
|
-
}
|
|
2478
|
-
return findings;
|
|
2479
|
-
})
|
|
2480
|
-
},
|
|
2481
2395
|
{
|
|
2482
2396
|
id: 'FLOW-023',
|
|
2483
2397
|
module: 'flow',
|
|
2484
2398
|
appliesTo: ['create', 'update'],
|
|
2485
|
-
sourceRef: "Adım tipi sözlüğü backend'indir (StepType.cs) ama koşan tipler barındırıcıdan gelir: flow-engine.ts start·setter·code·condition·microservice·validation·flow-trigger register eder, web Runtime.svelte alert·confirm·redirect·download·storage·setcookie ekler, mobil
|
|
2399
|
+
sourceRef: "Adım tipi sözlüğü backend'indir (StepType.cs) ama koşan tipler barındırıcıdan gelir: flow-engine.ts start·setter·code·condition·microservice·validation·flow-trigger register eder, web Runtime.svelte alert·confirm·redirect·download·storage·setcookie ekler, mobil ScreenRuntime.tsx alert·redirect·navigate·storage·setcookie ekler. navigate web'de, confirm/download mobilde YOKTUR; end ve query hiçbir barındırıcıda yoktur (Studio kataloğu da bunu visibility ile söyler: navigate 'mobile', confirm/download 'web'; End eklenebilir adımlar arasında değil — EventActionsAdd.svelte). Register edilmemiş tipe gelen akış SESSİZCE durur: flow-engine.ts process() callback bulamazsa hiçbir şey yapmaz (next yok, completed/stopped yok, hata yok, log yok), run() Promise'i çözülmez ve flowRunFinished() hiç koşmaz — __ngAppsFlowActivity.running sıfıra inmez, page_screenshot'ın hazır bekleyişi her eylemde bütçesini sonuna kadar yakar",
|
|
2486
2400
|
check: definition => {
|
|
2487
2401
|
const steps = flowAllSteps(definition);
|
|
2488
2402
|
// Studio her akış tuvaline dekoratif bir End düğümü koyar ve onu sildirmez; zararlı olan
|
|
@@ -3067,15 +2981,13 @@ export const policyRules = [
|
|
|
3067
2981
|
export async function microfunctionStepFindings(platform, project, environment, definition, kind, policyOverride = false) {
|
|
3068
2982
|
if (platform.config.policyMode === 'off')
|
|
3069
2983
|
return [];
|
|
3070
|
-
const
|
|
3071
|
-
.filter(
|
|
3072
|
-
|
|
3073
|
-
if (steps.length === 0)
|
|
2984
|
+
const sites = stepCallSites(workflowBody(definition, kind), 'microfunction')
|
|
2985
|
+
.filter(site => hasText(site.rule.microfunctionId));
|
|
2986
|
+
if (sites.length === 0)
|
|
3074
2987
|
return [];
|
|
3075
2988
|
const records = new Map();
|
|
3076
2989
|
const findings = [];
|
|
3077
|
-
for (const
|
|
3078
|
-
const rule = (step.rule ?? {});
|
|
2990
|
+
for (const { rule, label } of sites) {
|
|
3079
2991
|
const microfunctionId = String(rule.microfunctionId);
|
|
3080
2992
|
if (!records.has(microfunctionId)) {
|
|
3081
2993
|
try {
|
|
@@ -3093,7 +3005,7 @@ export async function microfunctionStepFindings(platform, project, environment,
|
|
|
3093
3005
|
findings.push({
|
|
3094
3006
|
ruleId: 'WF-MF-001',
|
|
3095
3007
|
severity: 'block',
|
|
3096
|
-
message: `'${
|
|
3008
|
+
message: `'${label}' adımının microfunctionId'si (${microfunctionId}) bu ortamda YOK. Adım kuralı step_rules.microfunction_id ile kayda FK'lıdır: gövde gitseydi platform 400 dönerdi. microfunction_list ile bu ortamdaki kayıtları görün — fonksiyon başka bir dalda/ortamda kalmış olabilir.`,
|
|
3097
3009
|
guide: 'ngapps://guides/microfunction'
|
|
3098
3010
|
});
|
|
3099
3011
|
continue;
|
|
@@ -3103,7 +3015,7 @@ export async function microfunctionStepFindings(platform, project, environment,
|
|
|
3103
3015
|
findings.push({
|
|
3104
3016
|
ruleId: 'WF-MF-001',
|
|
3105
3017
|
severity: 'block',
|
|
3106
|
-
message: `'${
|
|
3018
|
+
message: `'${label}' adımı '${String(record.name ?? microfunctionId)}' fonksiyonunu seçiyor ama kaydın durumu '${status}'${status === 'publish-failed' && hasText(record.publishError) ? ` (publishError: ${String(record.publishError)})` : ''}. Step YALNIZ yayındaki kaydı koşturur: MicrofunctionStep kaydı yükleyip Status != Published görünce MicrofunctionNotPublishedException ile FAIL dalına düşer — akış kurulur, kaydedilir ve koşumda sessizce hata yoluna girer. Önce microfunction_publish çağırın ve microfunction_get ile 'published' olduğunu görün.`,
|
|
3107
3019
|
guide: 'ngapps://guides/microfunction'
|
|
3108
3020
|
});
|
|
3109
3021
|
continue;
|
|
@@ -3112,7 +3024,7 @@ export async function microfunctionStepFindings(platform, project, environment,
|
|
|
3112
3024
|
findings.push({
|
|
3113
3025
|
ruleId: 'WF-MF-001',
|
|
3114
3026
|
severity: 'warn',
|
|
3115
|
-
message: `'${
|
|
3027
|
+
message: `'${label}' adımının fonksiyonu ('${String(record.name ?? microfunctionId)}') şu anda yayınlanıyor. Yayın ASENKRONDUR: bu akış şimdi koşarsa adım fail dalına düşer. microfunction_get ile 'published' olduğunu doğrulayın (yayın başarısız olursa durum 'publish-failed' olur).`,
|
|
3116
3028
|
guide: 'ngapps://guides/microfunction'
|
|
3117
3029
|
});
|
|
3118
3030
|
}
|
|
@@ -3128,7 +3040,7 @@ export async function microfunctionStepFindings(platform, project, environment,
|
|
|
3128
3040
|
findings.push({
|
|
3129
3041
|
ruleId: 'WF-MF-001',
|
|
3130
3042
|
severity: 'warn',
|
|
3131
|
-
message: `'${
|
|
3043
|
+
message: `'${label}' adımında rule.expression boş ama '${String(record.name ?? microfunctionId)}' fonksiyonunun bir parametre DTO'su var (parameterDtoId: ${String(record.parameterDtoId)}). Fonksiyon args olarak boş nesne alır ve kendi alanlarını undefined görür. Argümanları ifadeyle geçirin — şemayı microfunction_get çıktısındaki parameterScheme verir.`,
|
|
3132
3044
|
guide: 'ngapps://guides/microfunction'
|
|
3133
3045
|
});
|
|
3134
3046
|
}
|
|
@@ -3154,7 +3066,7 @@ export async function workflowStepFindings(platform, project, environment, appli
|
|
|
3154
3066
|
: hasText(definition.applicationId) ? String(definition.applicationId) : undefined;
|
|
3155
3067
|
if (application === undefined)
|
|
3156
3068
|
return [];
|
|
3157
|
-
const sites =
|
|
3069
|
+
const sites = stepCallSites(workflowBody(definition, kind), 'workflow')
|
|
3158
3070
|
.filter(site => GUID_PATTERN.test(String(site.rule.workflowId ?? '')));
|
|
3159
3071
|
if (sites.length === 0)
|
|
3160
3072
|
return [];
|
|
@@ -154,24 +154,6 @@ const resolveShadow = (shadow) => {
|
|
|
154
154
|
return undefined;
|
|
155
155
|
return SHADOW_VALUES[shadow] ?? String(shadow);
|
|
156
156
|
};
|
|
157
|
-
/**
|
|
158
|
-
* Döndür / ölçekle / kaydır alanlarının kabul aralığı — frontend `style-groups/transform-fields.ts`
|
|
159
|
-
* `TRANSFORM_RANGES`'in kopyası (altın vakalar kilitler). Aralık dışı ve birimli değer yazılmaz.
|
|
160
|
-
*/
|
|
161
|
-
export const TRANSFORM_RANGES = {
|
|
162
|
-
rotate: [-360, 360],
|
|
163
|
-
scale: [10, 500],
|
|
164
|
-
translateX: [-1000, 1000],
|
|
165
|
-
translateY: [-1000, 1000]
|
|
166
|
-
};
|
|
167
|
-
/** Sayı ya da sayısal metin, aralığın içinde; aksi `undefined` — frontend `transformValue`. */
|
|
168
|
-
export const transformValue = (value, field) => {
|
|
169
|
-
if (typeof value !== 'number' && (typeof value !== 'string' || value.trim() === ''))
|
|
170
|
-
return undefined;
|
|
171
|
-
const parsed = Number(value);
|
|
172
|
-
const [min, max] = TRANSFORM_RANGES[field];
|
|
173
|
-
return Number.isFinite(parsed) && parsed >= min && parsed <= max ? parsed : undefined;
|
|
174
|
-
};
|
|
175
157
|
/**
|
|
176
158
|
* Grupların alan listeleri — frontend `style-groups/style-group-schemas.ts`
|
|
177
159
|
* `STYLE_GROUP_FIELDS`'in kopyası. Parite testi `components.json`'daki gerçek
|
|
@@ -188,11 +170,7 @@ export const STYLE_GROUP_FIELDS = {
|
|
|
188
170
|
'borderLeft',
|
|
189
171
|
'shadow',
|
|
190
172
|
'contentOverflow',
|
|
191
|
-
'opacity'
|
|
192
|
-
'rotate',
|
|
193
|
-
'scale',
|
|
194
|
-
'translateX',
|
|
195
|
-
'translateY'
|
|
173
|
+
'opacity'
|
|
196
174
|
],
|
|
197
175
|
typographyStyle: [
|
|
198
176
|
'textColor',
|
|
@@ -242,21 +220,6 @@ export function composeTypedStyle(input, ext) {
|
|
|
242
220
|
if (opacity !== undefined && opacity >= 0 && opacity < 100) {
|
|
243
221
|
groups.opacity = String(opacity / 100);
|
|
244
222
|
}
|
|
245
|
-
// Döndür / ölçekle / kaydır (ADR 0005): kaydır → döndür → ölçekle, köken merkez;
|
|
246
|
-
// ölçek yüzdedir, nötr değer ve aralık dışı yazılmaz — frontend `composeSurfaceTransform`.
|
|
247
|
-
const transform = [];
|
|
248
|
-
const x = transformValue(surface.translateX, 'translateX') ?? 0;
|
|
249
|
-
const y = transformValue(surface.translateY, 'translateY') ?? 0;
|
|
250
|
-
if (x !== 0 || y !== 0)
|
|
251
|
-
transform.push(`translate(${x}px, ${y}px)`);
|
|
252
|
-
const rotate = transformValue(surface.rotate, 'rotate');
|
|
253
|
-
if (rotate !== undefined && rotate !== 0)
|
|
254
|
-
transform.push(`rotate(${rotate}deg)`);
|
|
255
|
-
const scale = transformValue(surface.scale, 'scale');
|
|
256
|
-
if (scale !== undefined && scale !== 100)
|
|
257
|
-
transform.push(`scale(${scale / 100})`);
|
|
258
|
-
if (transform.length)
|
|
259
|
-
groups.transform = transform.join(' ');
|
|
260
223
|
// `ROOT_TARGET` (`&`) kökün kendisidir: kendi derleyicisi olmayan kaplarda
|
|
261
224
|
// yüzey düğüm kutusuna yazılır ve kaydırılan da odur.
|
|
262
225
|
if (isSet(surface.contentOverflow) && ext?.overflowTarget) {
|
|
@@ -288,10 +251,8 @@ export function composeTypedStyle(input, ext) {
|
|
|
288
251
|
assign(rules, 'borderColor', hover.borderColor);
|
|
289
252
|
assign(rules, 'boxShadow', resolveShadow(hover.shadow));
|
|
290
253
|
const lift = asDimension(hover.lift);
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
rules.transform = `translateY(calc(-1 * ${lift}))${typeof groups.transform === 'string' ? ` ${groups.transform}` : ''}`;
|
|
294
|
-
}
|
|
254
|
+
if (lift !== undefined)
|
|
255
|
+
rules.transform = `translateY(calc(-1 * ${lift}))`;
|
|
295
256
|
if (Object.keys(rules).length) {
|
|
296
257
|
const duration = asNumber(hover.transitionMs) ?? 160;
|
|
297
258
|
groups.transition = `background-color ${duration}ms ease, border-color ${duration}ms ease, box-shadow ${duration}ms ease, transform ${duration}ms ease`;
|
|
@@ -539,13 +500,6 @@ export const NODE_SURFACE_TYPES = new Set([
|
|
|
539
500
|
'qm-sidebar',
|
|
540
501
|
'auth-layout'
|
|
541
502
|
]);
|
|
542
|
-
/**
|
|
543
|
-
* `style`'ı kendi içeriğinin CSS'i olarak alan tipler: `html`in `style`'ı uzun metindir ve yazarın
|
|
544
|
-
* işaretlemesine kapsamlı girer — web'de emotion sınıfı (`html.functions.ts` `resolveHtmlStyleClass`),
|
|
545
|
-
* mobilde korumalı belgenin stil bloğu (plans/mobil-plantcare-acigi f-20). "Düz CSS string style"
|
|
546
|
-
* (PAGE-014) ve "ham CSS çizilmez" (MOB-002) uyarıları bu tiplerde yanlıştır.
|
|
547
|
-
*/
|
|
548
|
-
export const DOCUMENT_STYLE_TYPES = new Set(['html']);
|
|
549
503
|
const NODE_SURFACE_EXTENSION = { overflowTarget: ROOT_TARGET };
|
|
550
504
|
/** Düğüm kutusuna inen yüzey; kap tipi değilse ya da grup boşsa yok. */
|
|
551
505
|
export function composeNodeSurfaceStyle(type, surfaceStyle) {
|
|
@@ -585,7 +539,7 @@ const unwrapProp = (value) => {
|
|
|
585
539
|
result[key] = unwrapProp(item);
|
|
586
540
|
return result;
|
|
587
541
|
};
|
|
588
|
-
|
|
542
|
+
const rawProp = (props, name) => {
|
|
589
543
|
const prop = props?.[name];
|
|
590
544
|
// İfadeye bağlı prop'un değeri çalışma anında oluşur, burada çözülemez.
|
|
591
545
|
return prop && typeof prop === 'object' && 'data' in prop ? unwrapProp(prop.data) : undefined;
|
|
@@ -332,8 +332,8 @@ export function buildSpacingScaleVars(scale) {
|
|
|
332
332
|
.join('\n\t');
|
|
333
333
|
}
|
|
334
334
|
/**
|
|
335
|
-
* Bir seviyenin
|
|
336
|
-
* Kullanıcı tek çarpan ayarlar,
|
|
335
|
+
* Bir seviyenin mobil karşılığının masaüstüne oranı — bugünkü breakpoint değerlerinden türer.
|
|
336
|
+
* Kullanıcı tek çarpan ayarlar, mobil ona orantılı hareket eder.
|
|
337
337
|
*/
|
|
338
338
|
const TYPE_SCALE_MOBILE_RATIO = {
|
|
339
339
|
h1: 1.7 / 2.25,
|
|
@@ -363,7 +363,7 @@ export function mergeTypeScale(overrides) {
|
|
|
363
363
|
}
|
|
364
364
|
return result;
|
|
365
365
|
}
|
|
366
|
-
/** Ölçekten `--ng-font-size-*` değişkenlerini üretir (masaüstü +
|
|
366
|
+
/** Ölçekten `--ng-font-size-*` değişkenlerini üretir (masaüstü + mobil). */
|
|
367
367
|
export function buildTypeScaleVars(scale) {
|
|
368
368
|
const lines = [];
|
|
369
369
|
for (const [level, factor] of Object.entries(scale)) {
|
|
@@ -351,7 +351,7 @@ export function logGatewayEvent(message) {
|
|
|
351
351
|
*/
|
|
352
352
|
export function logCapabilityGap(gap) {
|
|
353
353
|
const lines = [
|
|
354
|
-
`┌─ ${clockOf(new Date())} · KABİLİYET BOŞLUĞU · ${gap.severity}${gap.module ? ` · ${gap.module}` : ''}
|
|
354
|
+
`┌─ ${clockOf(new Date())} · KABİLİYET BOŞLUĞU · ${gap.severity}${gap.module ? ` · ${gap.module}` : ''}`,
|
|
355
355
|
`│ hedef : ${condense(gap.goal, maxBodyChars)}`,
|
|
356
356
|
`│ engel : ${condense(gap.blocker, maxBodyChars)}`
|
|
357
357
|
];
|
|
@@ -5,9 +5,8 @@ const MAX_NOTES = 8;
|
|
|
5
5
|
const MAX_NOTE_CHARS = 240;
|
|
6
6
|
const MAX_DROPS = 5;
|
|
7
7
|
export const diagnosticsParam = z.enum(['compact', 'full']).optional().describe("Yanıttaki gatewayNormalized / silentlyDropped listelerinin boyu. compact (varsayılan): aynı not tekilleşir, uzun not kısalır (en fazla 8); aynı yolun düşmeleri tek satırda sayıyla toplanır (en fazla 5 grup); droppedCount her zaman tam sayıdır. full: listelerin tamamı.");
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
return activeMode.run({ mode, adjustable }, run);
|
|
8
|
+
export function runWithDiagnostics(mode, run) {
|
|
9
|
+
return activeMode.run(mode, run);
|
|
11
10
|
}
|
|
12
11
|
/**
|
|
13
12
|
* Tanılama listeleri her yazma çağrısında yanıta girer ve aynı gerekçe cümlesi çağrı başına tekrar
|
|
@@ -19,7 +18,7 @@ export function runWithDiagnostics(mode, run, adjustable = true) {
|
|
|
19
18
|
* listeyi görür; kısaltma yalnız `diagnostics` parametresini taşıyan yazma tool'larında devreye girer.
|
|
20
19
|
*/
|
|
21
20
|
export function compactDiagnostics(payload) {
|
|
22
|
-
if (activeMode.getStore()
|
|
21
|
+
if (activeMode.getStore() !== 'compact')
|
|
23
22
|
return payload;
|
|
24
23
|
if (!payload || typeof payload !== 'object' || Array.isArray(payload))
|
|
25
24
|
return payload;
|
|
@@ -59,12 +58,7 @@ export function compactDiagnostics(payload) {
|
|
|
59
58
|
}
|
|
60
59
|
if (hidden.length === 0)
|
|
61
60
|
return result;
|
|
62
|
-
return {
|
|
63
|
-
...result,
|
|
64
|
-
diagnosticsNote: activeMode.getStore()?.adjustable === false
|
|
65
|
-
? 'Kısaltıldı; tam liste gateway günlüğünde (bu tool diagnostics parametresi almaz).'
|
|
66
|
-
: "Kısaltıldı; yazmayı tekrarlamayın. Tam liste: sonraki çağrıda diagnostics:'full'."
|
|
67
|
-
};
|
|
61
|
+
return { ...result, diagnosticsNote: "Kısaltıldı; yazmayı tekrarlamayın. Tam liste: sonraki çağrıda diagnostics:'full'." };
|
|
68
62
|
}
|
|
69
63
|
/**
|
|
70
64
|
* Aynı yolun farklı öğelerindeki düşmeler (`selectFields[fieldId=a].path`, `selectFields[fieldId=b].path`, …)
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* (card) · GİZLİ" 200 karakterdir.
|
|
8
8
|
*
|
|
9
9
|
* Katman saftır: tarayıcıdan gelen anlık görüntüyü doğrular ve biçimler. Toplama işi
|
|
10
|
-
* `
|
|
10
|
+
* `screenshot.ts` `domSummaryScript`'te, sunum `pages.ts`'te.
|
|
11
11
|
*/
|
|
12
12
|
function text(value) {
|
|
13
13
|
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
package/dist/platform/http.js
CHANGED
|
@@ -6,20 +6,6 @@ import { randomUUID } from 'node:crypto';
|
|
|
6
6
|
import { request } from 'undici';
|
|
7
7
|
export const requestAuthStorage = new AsyncLocalStorage();
|
|
8
8
|
const hiddenResponseHeaders = new Set(['set-cookie', 'authorization', 'proxy-authorization']);
|
|
9
|
-
/**
|
|
10
|
-
* g-08: yürütme yanıtının varsayılan başlıkları — işin okuduğu olanlar. `total-count` sayfalı tablo
|
|
11
|
-
* akışlarının sözleşmesidir (İK koşusu M-8), `location` yönlendirmenin, `x-request-id`/`traceparent`
|
|
12
|
-
* platform günlüğünde aynı isteği bulmanın anahtarıdır. Cloudflare ve sunucu başlıkları (`cf-ray`,
|
|
13
|
-
* `server`, `alt-svc`, `date` …) ajan bağlamında yer kaplıyordu ve hiçbir karar onlara bakmıyordu.
|
|
14
|
-
*/
|
|
15
|
-
const essentialResponseHeaders = new Set(['content-type', 'content-length', 'content-disposition', 'location', 'total-count', 'x-request-id', 'traceparent']);
|
|
16
|
-
export function headersForMode(headers, mode) {
|
|
17
|
-
if (mode === 'none')
|
|
18
|
-
return undefined;
|
|
19
|
-
if (mode === 'all')
|
|
20
|
-
return headers;
|
|
21
|
-
return Object.fromEntries(Object.entries(headers).filter(([name]) => essentialResponseHeaders.has(name)));
|
|
22
|
-
}
|
|
23
9
|
/**
|
|
24
10
|
* Sayfalı tablo akışları `Total-Count` header'ına bağlı ama execute ailesi yalnız gövdeyi
|
|
25
11
|
* döndürüyordu; sözleşme hiçbir tool'dan doğrulanamıyordu (İK koşusu M-8). Gizli header'lar
|
|
@@ -167,15 +153,13 @@ export class Platform {
|
|
|
167
153
|
body = JSON.stringify(options.body);
|
|
168
154
|
}
|
|
169
155
|
const startedAt = Date.now();
|
|
170
|
-
logStep('istek →', `${method} ${url.href} · ${api} api${options.environment ? ` · env=${options.environment}` : ''}${options.anonymous ? ' · ANONİM (Authorization header YOK)' : ''}${isRetry ? ' · 401 sonrası tekrar' : ''}`, options.
|
|
171
|
-
? [
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
?
|
|
175
|
-
: options.
|
|
176
|
-
|
|
177
|
-
: options.body)}`]
|
|
178
|
-
: []);
|
|
156
|
+
logStep('istek →', `${method} ${url.href} · ${api} api${options.environment ? ` · env=${options.environment}` : ''}${options.anonymous ? ' · ANONİM (Authorization header YOK)' : ''}${isRetry ? ' · 401 sonrası tekrar' : ''}`, logsDetail() && (options.multipart || options.form || options.body !== undefined)
|
|
157
|
+
? [`gövde: ${renderJson(options.multipart
|
|
158
|
+
? describeMultipart(options.multipart)
|
|
159
|
+
: options.form
|
|
160
|
+
? Object.fromEntries(options.form)
|
|
161
|
+
: options.body)}`]
|
|
162
|
+
: []);
|
|
179
163
|
let statusCode;
|
|
180
164
|
let payload;
|
|
181
165
|
let responseBytes = 0;
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { compactDiagnostics } from './diagnostics.js';
|
|
2
|
-
import { argumentNotes } from './argumentAliases.js';
|
|
3
|
-
import { tokenTtlMinutes } from './tokenVault.js';
|
|
4
2
|
import { logError, logStep } from '../observability/trace.js';
|
|
5
3
|
import { PlatformApiError, describeErrorBody } from './errors.js';
|
|
6
4
|
import { PolicyBlockError } from '../knowledge/policy.js';
|
|
@@ -164,10 +162,8 @@ export function toolResult(payload, config, expectFailure) {
|
|
|
164
162
|
...(runtimeErrors.length > 0 ? { runtimeErrors } : {}),
|
|
165
163
|
...(runtimeErrors.length > 0 && expectFailure === true ? { expectedFailure: true } : {}),
|
|
166
164
|
...(masked.length > 0 ? { gatewayMasked: masked } : {}),
|
|
167
|
-
...(Object.keys(tokenRefs).length > 0 ? { tokenRefs, tokenRefNote:
|
|
168
|
-
...(truncated ? { truncated: true, truncationNote: 'Liste, yanıt boyutu sınırı nedeniyle kırpıldı; sayfalama ya da daha dar filtre kullanın.' } : {})
|
|
169
|
-
...(argumentNotes().aliasesApplied.length > 0 ? { aliasesApplied: argumentNotes().aliasesApplied } : {}),
|
|
170
|
-
...(argumentNotes().bodyFile ? { bodyFile: argumentNotes().bodyFile } : {})
|
|
165
|
+
...(Object.keys(tokenRefs).length > 0 ? { tokenRefs, tokenRefNote: "Maskelenen JWT'ler gateway içinde tutuldu; bu referansları page_screenshot / page_runtime_get 'asUser' alanına verebilirsiniz (15 dk geçerli). Jetonun kendisi yanıta ve günlüğe hiç girmez." } : {}),
|
|
166
|
+
...(truncated ? { truncated: true, truncationNote: 'Liste, yanıt boyutu sınırı nedeniyle kırpıldı; sayfalama ya da daha dar filtre kullanın.' } : {})
|
|
171
167
|
};
|
|
172
168
|
return {
|
|
173
169
|
content: [{ type: 'text', text: JSON.stringify(enriched) }],
|