@rsconcept/rstool 1.2.2 → 1.4.0
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 +4 -4
- package/dist/{agent-workflow-Gk0Vfnv1.d.ts → agent-workflow-D22FeODL.d.ts} +6 -6
- package/dist/{analysis-LLnPhmGa.d.ts → analysis-DA44pfgA.d.ts} +4 -3
- package/dist/common-D6TFl6l_.d.ts +11 -0
- package/dist/{constituenta-DnGR6bnM.d.ts → constituenta-QY5w1x91.d.ts} +7 -7
- package/dist/diagnostic-C6TRoBgt.d.ts +38 -0
- package/dist/diagnostic-assembly-DRunIcKQ.js +54 -0
- package/dist/diagnostic-assembly-DRunIcKQ.js.map +1 -0
- package/dist/{evaluation-Cns8BFm4.d.ts → evaluation-Cd4S7-3t.d.ts} +4 -3
- package/dist/index.d.ts +12 -12
- package/dist/index.js +4 -3
- package/dist/mappers/model-adapter.d.ts +3 -3
- package/dist/mappers/model-adapter.js +1 -199
- package/dist/mappers/schema-adapter.d.ts +5 -5
- package/dist/mappers/schema-adapter.js +8 -8
- package/dist/mappers/schema-adapter.js.map +1 -1
- package/dist/mappers/types.d.ts +6 -6
- package/dist/mappers/types.js +6 -10
- package/dist/mappers/types.js.map +1 -1
- package/dist/model-adapter-D-YmIvQW.js +225 -0
- package/dist/model-adapter-D-YmIvQW.js.map +1 -0
- package/dist/{model-value-BbonPzMz.d.ts → model-value-BUhr2IjA.d.ts} +2 -2
- package/dist/models/agent-workflow.d.ts +1 -1
- package/dist/models/analysis.d.ts +1 -1
- package/dist/models/common.d.ts +2 -2
- package/dist/models/common.js +1 -1
- package/dist/models/constituenta.d.ts +1 -1
- package/dist/models/diagnostic.d.ts +2 -2
- package/dist/models/diagnostic.js +3 -1
- package/dist/models/evaluation.d.ts +1 -1
- package/dist/models/index.d.ts +11 -11
- package/dist/models/index.js +3 -2
- package/dist/models/model-value.d.ts +1 -1
- package/dist/models/rstool-agent.d.ts +1 -1
- package/dist/models/rstool-agent.js +1 -1
- package/dist/models/session.d.ts +1 -1
- package/dist/models/tool-contract.d.ts +1 -1
- package/dist/models/tool-contract.js +1 -1
- package/dist/models/tool-contract.js.map +1 -1
- package/dist/{models-9G6ur_pg.js → models-DTLctDmB.js} +72 -15
- package/dist/models-DTLctDmB.js.map +1 -0
- package/dist/{rstool-agent-D2cQze_b.d.ts → rstool-agent-BMVAyMAG.d.ts} +11 -10
- package/dist/session/session-store.d.ts +6 -6
- package/dist/session/session-store.js +1 -1
- package/dist/{session-ChexW8i7.d.ts → session-CI4rLYby.d.ts} +3 -3
- package/dist/{tool-contract-0uRGhEfW.d.ts → tool-contract-sQfr-DYD.d.ts} +12 -12
- package/dist/wrapper/stdio-wrapper.js +1 -1
- package/docs/BASE-SELECTION.md +92 -0
- package/docs/CONCEPTUAL-SCHEMA.md +20 -15
- package/docs/CONSTITUENTA.md +3 -3
- package/docs/DIAGNOSTICS.md +63 -20
- package/docs/DOMAIN.md +27 -21
- package/docs/README.md +1 -0
- package/docs/SYNTAX.md +3 -2
- package/docs/TYPIFICATION.md +3 -9
- package/examples/README.md +2 -0
- package/examples/agent-client.ts +15 -3
- package/examples/audit-diagnostics.ts +40 -0
- package/examples/chocolate-nim/build-rsform.ts +15 -0
- package/examples/chocolate-nim/build-rsmodel.ts +15 -22
- package/examples/chocolate-nim/model-demo.ts +11 -0
- package/examples/chocolate-nim/rsform-session.json +329 -310
- package/examples/chocolate-nim/rsmodel-session.json +311 -311
- package/examples/diagnostics-utils.ts +25 -0
- package/examples/expression-bank/bank-constituents.ts +10 -10
- package/examples/expression-bank/build-rsform.ts +8 -0
- package/examples/expression-bank/rsform-session.json +1501 -1501
- package/examples/kinship/build-rsform.ts +16 -1
- package/examples/kinship/build-rsmodel.ts +15 -56
- package/examples/kinship/model-demo.ts +35 -0
- package/examples/kinship/rsform-session.json +300 -215
- package/examples/kinship/rsmodel-session.json +216 -216
- package/examples/movd/build-rsform.ts +15 -0
- package/examples/movd/build-rsmodel.ts +15 -46
- package/examples/movd/model-demo.ts +31 -0
- package/examples/movd/rsform-session.json +359 -270
- package/examples/movd/rsmodel-session.json +263 -263
- package/examples/sample/build-rsform.ts +43 -3
- package/examples/sample/build-rsmodel.ts +26 -2
- package/examples/sample/rsform-session.json +41 -12
- package/examples/sample/rsmodel-session.json +37 -37
- package/examples/template-apply/build-rsform.ts +26 -9
- package/examples/template-apply/rsform-session.json +100 -45
- package/package.json +3 -2
- package/skills/rstool-helper/EXAMPLES.md +22 -1
- package/skills/rstool-helper/GUIDE.md +23 -28
- package/skills/rstool-helper/REFERENCE.md +28 -23
- package/src/index.ts +7 -4
- package/src/mappers/diagnostic-assembly.ts +96 -0
- package/src/mappers/diagnostics-collector.test.ts +63 -0
- package/src/mappers/diagnostics-collector.ts +73 -0
- package/src/mappers/model-adapter.ts +28 -99
- package/src/mappers/rsform-builder.ts +127 -0
- package/src/mappers/schema-adapter.ts +19 -15
- package/src/mappers/types.ts +12 -12
- package/src/models/agent-workflow.ts +2 -2
- package/src/models/analysis.ts +3 -2
- package/src/models/common.ts +0 -12
- package/src/models/constituenta.ts +4 -4
- package/src/models/diagnostic.ts +15 -10
- package/src/models/evaluation.ts +3 -8
- package/src/models/index.ts +8 -2
- package/src/models/rstool-agent.test.ts +66 -5
- package/src/models/rstool-agent.ts +22 -10
- package/src/models/tool-contract.ts +4 -4
- package/src/session/persistence.ts +2 -2
- package/src/session/session-store.ts +14 -7
- package/dist/common-DHJalS-Q.d.ts +0 -22
- package/dist/diagnostic-D9yl_mEL.d.ts +0 -19
- package/dist/mappers/model-adapter.js.map +0 -1
- package/dist/models-9G6ur_pg.js.map +0 -1
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
- API, методы, stdio: [REFERENCE.md](REFERENCE.md).
|
|
28
28
|
- Примеры: [EXAMPLES.md](EXAMPLES.md).
|
|
29
29
|
- Термины предметной области: [../../docs/DOMAIN.md](../../docs/DOMAIN.md).
|
|
30
|
+
- **`X#` / `C#` / `Z`:** [../../docs/BASE-SELECTION.md](../../docs/BASE-SELECTION.md) — когда какое основание вводить.
|
|
30
31
|
- Концептуализация, создание схемы: [../../docs/CONCEPTUAL-SCHEMA.md](../../docs/CONCEPTUAL-SCHEMA.md).
|
|
31
32
|
- Конституенты и валидация: [../../docs/CONSTITUENTA.md](../../docs/CONSTITUENTA.md).
|
|
32
33
|
- Синтаксис родов структур: [../../docs/SYNTAX.md](../../docs/SYNTAX.md).
|
|
@@ -45,7 +46,7 @@
|
|
|
45
46
|
Когда схема уже есть и нужны точечные правки, новые конституенты или проверка формул.
|
|
46
47
|
|
|
47
48
|
1. Продолжи текущую сессию или вызови `ensureSession`; большинство методов создают сессию лениво.
|
|
48
|
-
2. Развивай схему через `applySchemaPatch`: можно опускать `id` и `cstType`
|
|
49
|
+
2. Развивай схему через `applySchemaPatch`: можно опускать `id` и `cstType` — они выводятся из префикса `alias` (`X/C/S/D/F/P/A/T/N`).
|
|
49
50
|
3. Для пачки конституент передавай все элементы вместе — `applySchemaPatch` упорядочит поставщиков раньше потребителей.
|
|
50
51
|
4. Перед patch в `applySchemaPatch` при сомнении вызывай `analyzeExpression`.
|
|
51
52
|
5. Исправляй диагностики по диапазону `from` / `to` в `definitionFormal` ([DIAGNOSTICS.md](../../docs/DIAGNOSTICS.md)).
|
|
@@ -58,29 +59,24 @@
|
|
|
58
59
|
### Оценка или правка КС из Portal
|
|
59
60
|
|
|
60
61
|
Когда пользователь даёт UI-ссылку вида `https://portal.acconcept.ru/rsforms/:id`,
|
|
61
|
-
не открывай SPA и не парси HTML
|
|
62
|
-
[PORTAL-API.md](../../docs/PORTAL-API.md)
|
|
63
|
-
полная КС `GET /api/rsforms/:id/details`, версия `GET /api/library/:id/versions/:version`.
|
|
64
|
-
Если id неизвестен — контекстный поиск `GET /api/library/context-search?q=...`, затем
|
|
65
|
-
метаданные по найденным id: `GET /api/library/by-ids?ids=...` (curl и поля поиска — в том же файле).
|
|
62
|
+
не открывай SPA и не парси HTML: преобразуй ссылку в REST-запрос по правилам
|
|
63
|
+
[PORTAL-API.md](../../docs/PORTAL-API.md) — там пути, контекстный поиск, правила доступа и curl.
|
|
66
64
|
|
|
67
65
|
Portal JSON из `/details` не является форматом `exportSession`. Используй `importData(payload)` —
|
|
68
|
-
auto определит `portal-details` или `portal-schema`. Явный kind: `'portal-details'`, `'portal-schema'`, `'session'`.
|
|
66
|
+
kind `auto` (default) определит `portal-details` или `portal-schema`. Явный kind: `'portal-details'`, `'portal-schema'`, `'session'`.
|
|
69
67
|
|
|
70
68
|
### Концептуализация (КС из содержания источника)
|
|
71
69
|
|
|
72
70
|
Когда нужно построить или существенно развить КС по тексту ПО, требованиям или предметному описанию. Правила редукции, слоёв и паттернов — [CONCEPTUAL-SCHEMA.md](../../docs/CONCEPTUAL-SCHEMA.md).
|
|
73
71
|
|
|
74
72
|
1. Собери словарь: неопределяемые понятия, ключевые отношения, сценарий синтеза.
|
|
75
|
-
2. Добавь неопределяемые понятия `X#`, `C#`, `S#` с конвенциями из источника (не копируй дословно).
|
|
76
|
-
3.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
8. Сомнительную семантику проверь на маленькой КМ ([цикл КМ](#проверка-на-маленькой-км), [MODEL-TESTING.md](../../docs/MODEL-TESTING.md)).
|
|
83
|
-
9. Перед показом результата пройди [чеклист ревью КС](#ревью-концептуальной-схемы).
|
|
73
|
+
2. Добавь независимые неопределяемые понятия `X#`, `C#`, `S#` с конвенциями из источника (не копируй дословно). Для выбора `X#` vs `C#` vs `Z` — [BASE-SELECTION.md](../../docs/BASE-SELECTION.md).
|
|
74
|
+
3. Всё, что выводится из уже введённых понятий, оформляй как `D#` / `F#` / `P#`, а не как новое `X#` / `C#` / `S#`.
|
|
75
|
+
4. Вводи промежуточные `D#`, `F#`, `P#` для проекций, функциональных связей и повторяющихся фрагментов формул.
|
|
76
|
+
5. Добавь `A#` и `T#` после терминов, на которые они опираются.
|
|
77
|
+
6. Перед каждым patch — `analyzeExpression`; при ошибках — [цикл диагностик](#цикл-диагностик).
|
|
78
|
+
7. Сомнительную семантику проверь на маленькой КМ ([цикл КМ](#проверка-на-маленькой-км), [MODEL-TESTING.md](../../docs/MODEL-TESTING.md)).
|
|
79
|
+
8. Перед показом результата пройди [чеклист ревью КС](#ревью-концептуальной-схемы).
|
|
84
80
|
|
|
85
81
|
Дальше — обычное [редактирование и проверка](#редактирование-и-проверка-схемы): commit, export.
|
|
86
82
|
|
|
@@ -88,12 +84,13 @@ auto определит `portal-details` или `portal-schema`. Явный kind
|
|
|
88
84
|
|
|
89
85
|
Когда `analysis.success === false` или `listDiagnostics` не пуст. Коды и типичные ошибки — [DIAGNOSTICS.md](../../docs/DIAGNOSTICS.md).
|
|
90
86
|
|
|
91
|
-
1.
|
|
92
|
-
2.
|
|
93
|
-
3.
|
|
94
|
-
4.
|
|
95
|
-
5.
|
|
96
|
-
6.
|
|
87
|
+
1. Вызови `listDiagnostics()` — смотри `kind`: `expression` (формула), `schema` (омонимы, дубликаты, термин/конвенция), `model` (интерпретация).
|
|
88
|
+
2. Для черновика формулы — `analyzeExpression` (без сохранения).
|
|
89
|
+
3. Прочитай `name`, `severity`, `alias`, `from`, `to`, `params` в `analysis.diagnostics` или через `listDiagnostics({ kind })`.
|
|
90
|
+
4. Сопоставь `name` (или `code`) с исправлением в [DIAGNOSTICS.md](../../docs/DIAGNOSTICS.md).
|
|
91
|
+
5. Исправь именно диапазон в `definitionFormal` (expression) или метаданные/данные модели (schema/model).
|
|
92
|
+
6. Не повторяй вызов без изменения ввода.
|
|
93
|
+
7. После успеха — ещё один `applySchemaPatch` / `setModelValues` с исправлением.
|
|
97
94
|
|
|
98
95
|
### Проверка на маленькой КМ
|
|
99
96
|
|
|
@@ -110,12 +107,9 @@ auto определит `portal-details` или `portal-schema`. Явный kind
|
|
|
110
107
|
|
|
111
108
|
### Порядок объявления конституент
|
|
112
109
|
|
|
113
|
-
|
|
114
|
-
2. Родовые структуры производные и ключевые понятия, аксиомы и утверждения в произвольном порядке.
|
|
115
|
-
3. Конституенты в топологическом порядке.
|
|
116
|
-
4. Предпочитай размещать связанные с родовыми структурами конституенты вместе с этой структурой.
|
|
110
|
+
В начале схемы — `basic` и `constant`, затем независимые `structure`, затем производные (`term`, `function`, `predicate`, `axiom`, `statement`) в топологическом порядке. Производные при родовой структуре держи рядом с ней, если это не ломает зависимости.
|
|
117
111
|
|
|
118
|
-
Правила валидации по типам — [CONSTITUENTA.md](../../docs/CONSTITUENTA.md).
|
|
112
|
+
Правила валидации по типам — [CONSTITUENTA.md](../../docs/CONSTITUENTA.md); разворачивание понятий при проектировании — [CONCEPTUAL-SCHEMA.md](../../docs/CONCEPTUAL-SCHEMA.md).
|
|
119
113
|
|
|
120
114
|
## Формат ответа агента
|
|
121
115
|
|
|
@@ -160,7 +154,7 @@ auto определит `portal-details` или `portal-schema`. Явный kind
|
|
|
160
154
|
### Сессия и rstool
|
|
161
155
|
|
|
162
156
|
- [ ] Используется текущая сессия (`getSessionState`) или явный `sessionId`, если сессий несколько.
|
|
163
|
-
- [ ] Для стандартных
|
|
157
|
+
- [ ] Для стандартных `X/C/S/D/F/P/A/T/N` можно не указывать `cstType` в `applySchemaPatch`.
|
|
164
158
|
- [ ] Для пачки конституент предпочитай один `applySchemaPatch` с массивом `items`.
|
|
165
159
|
|
|
166
160
|
### Перед показом, commit и export
|
|
@@ -177,6 +171,7 @@ auto определит `portal-details` или `portal-schema`. Явный kind
|
|
|
177
171
|
- [ ] Атрибутивная и родоструктурная экспликации не смешаны без явного запроса.
|
|
178
172
|
- [ ] Нет избыточной проверки принадлежности к собственной типизации (`x∈X1`, если `x` уже в `X1`).
|
|
179
173
|
- [ ] Неопределяемые понятия независимы; производные отношения вынесены в `D#` / `F#` / `P#`, а не объявлены новыми структурами.
|
|
174
|
+
- [ ] `X#` — только предметные сущности; `C#` — только если нужны порядок/арифметика над именованным конечным набором в КМ; чистая целочисленная математика — `Z` без лишней конституенты ([BASE-SELECTION.md](../../docs/BASE-SELECTION.md)).
|
|
180
175
|
- [ ] Покрыты главные сущности, роли, отношения, утверждения.
|
|
181
176
|
- [ ] В текстовых определениях используются только понятия из схемы.
|
|
182
177
|
- [ ] Повторяющиеся части формальных определений вынесены в производные понятия `D#` и `F#`.
|
|
@@ -3,30 +3,30 @@
|
|
|
3
3
|
## Контракт rstool
|
|
4
4
|
|
|
5
5
|
- Пакет: `@rsconcept/rstool`
|
|
6
|
-
- Версия контракта: `
|
|
6
|
+
- Версия контракта: `3.0.0` (`CONTRACT_VERSION`)
|
|
7
7
|
- Основной класс: `RSToolAgent`
|
|
8
8
|
- Публичные импорты: `@rsconcept/rstool` и `@rsconcept/rstool/wrapper`
|
|
9
9
|
|
|
10
10
|
### Методы library API
|
|
11
11
|
|
|
12
|
-
| Метод | Назначение
|
|
13
|
-
| ---------------------------------------------- |
|
|
14
|
-
| `ensureSession(initial?)` | Вернуть текущую сессию или создать новую
|
|
15
|
-
| `createSession(initial?)` | Новая in-memory сессия
|
|
16
|
-
| `getCurrentSession()` | Текущая активная сессия или `null`
|
|
17
|
-
| `setCurrentSession(sessionId)` | Сделать сессию текущей
|
|
18
|
-
| `applySchemaPatch(input, sessionId?)` | Единственный путь правки схемы
|
|
19
|
-
| `getSessionState(detail?, sessionId?)` | `summary` (default) или `full`
|
|
20
|
-
| `listDiagnostics(filters?, sessionId?)` | Активные диагностики
|
|
21
|
-
| `analyzeExpression(input, sessionId?)` | Разбор без сохранения (`recordDiagnostics?`)
|
|
22
|
-
| `commitStep(message?, sessionId?)` | Ревизия
|
|
23
|
-
| `exportSession(sessionId?)` | JSON сессии
|
|
24
|
-
| `exportPortal({ kind, format? }, sessionId?)` | Portal Load from JSON
|
|
25
|
-
| `importData(payload, kind?)` | Импорт сессии / Portal
|
|
26
|
-
| `setModelValues({ set?, clear? }, sessionId?)` | Значения модели
|
|
27
|
-
| `getModelState(sessionId?)` | Состояние интерпретации
|
|
28
|
-
| `evaluate(input, sessionId?)` | Scratch или конституента
|
|
29
|
-
| `recalculateModel(sessionId?)` | Пересчёт
|
|
12
|
+
| Метод | Назначение |
|
|
13
|
+
| ---------------------------------------------- | ------------------------------------------------------------------ |
|
|
14
|
+
| `ensureSession(initial?)` | Вернуть текущую сессию или создать новую |
|
|
15
|
+
| `createSession(initial?)` | Новая in-memory сессия |
|
|
16
|
+
| `getCurrentSession()` | Текущая активная сессия или `null` |
|
|
17
|
+
| `setCurrentSession(sessionId)` | Сделать сессию текущей |
|
|
18
|
+
| `applySchemaPatch(input, sessionId?)` | Единственный путь правки схемы |
|
|
19
|
+
| `getSessionState(detail?, sessionId?)` | `summary` (default) или `full` |
|
|
20
|
+
| `listDiagnostics(filters?, sessionId?)` | Активные диагностики (`kind`: `expression` \| `schema` \| `model`) |
|
|
21
|
+
| `analyzeExpression(input, sessionId?)` | Разбор без сохранения (`recordDiagnostics?`) |
|
|
22
|
+
| `commitStep(message?, sessionId?)` | Ревизия |
|
|
23
|
+
| `exportSession(sessionId?)` | JSON сессии |
|
|
24
|
+
| `exportPortal({ kind, format? }, sessionId?)` | Portal Load from JSON |
|
|
25
|
+
| `importData(payload, kind?)` | Импорт сессии / Portal (`kind` см. ниже) |
|
|
26
|
+
| `setModelValues({ set?, clear? }, sessionId?)` | Значения модели (async — нужен `await`) |
|
|
27
|
+
| `getModelState(sessionId?)` | Состояние интерпретации |
|
|
28
|
+
| `evaluate(input, sessionId?)` | Scratch или конституента |
|
|
29
|
+
| `recalculateModel(sessionId?)` | Пересчёт |
|
|
30
30
|
|
|
31
31
|
### `applySchemaPatch`
|
|
32
32
|
|
|
@@ -38,6 +38,15 @@ tool.applySchemaPatch({
|
|
|
38
38
|
});
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
+
- `items` упорядочиваются автоматически: поставщики раньше потребителей.
|
|
42
|
+
- `id` и `cstType` можно опускать — выводятся из префикса `alias` (`X/C/S/D/F/P/A/T/N`).
|
|
43
|
+
- `mode`: `'atomic'` (default; откат всей пачки при первой ошибке) или `'best_effort'` (применяются корректные элементы).
|
|
44
|
+
- `commitMessage` фиксирует ревизию после успешного patch.
|
|
45
|
+
|
|
46
|
+
### `importData(payload, kind?)`
|
|
47
|
+
|
|
48
|
+
`kind`: `'auto'` (default; определяет формат по содержимому), `'session'`, `'portal-details'` (ответ `GET /api/rsforms/:id/details`), `'portal-schema'` (Portal Load from JSON). После импорта новая сессия становится текущей.
|
|
49
|
+
|
|
41
50
|
### Протокол stdio
|
|
42
51
|
|
|
43
52
|
Плоские `params` (без `input`). Опционально: переменная окружения `RSTOOL_PERSISTENCE_DIR` — каталог для сохранения сессий между перезапусками обёртки (в library API — `new RSToolAgent({ persistenceDir })`).
|
|
@@ -55,10 +64,6 @@ tool.applySchemaPatch({
|
|
|
55
64
|
{"id":"10","method":"importData","params":{"payload":"..."}}
|
|
56
65
|
```
|
|
57
66
|
|
|
58
|
-
### MCP tools
|
|
59
|
-
|
|
60
|
-
17 tools — см. `rstool-mcp/README.md`.
|
|
61
|
-
|
|
62
67
|
## Документация
|
|
63
68
|
|
|
64
69
|
Воркфлоу: `GUIDE.md`. Примеры: `EXAMPLES.md`. Язык: `docs/*.md`.
|
package/src/index.ts
CHANGED
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
* Public API for `@rsconcept/rstool`.
|
|
3
3
|
*
|
|
4
4
|
* Primary entry points: {@link RSToolAgent} (in-process) and {@link RSToolWrapperClient}
|
|
5
|
-
* (stdio child process). Types describe the
|
|
5
|
+
* (stdio child process). Types describe the v3 agent contract.
|
|
6
6
|
*/
|
|
7
|
-
export {
|
|
7
|
+
export { toDiagnostic, toPublicAnalysis, type DomainAnalysisLike, type DomainErrorLike } from './mappers/types';
|
|
8
8
|
export {
|
|
9
9
|
CONTRACT_VERSION,
|
|
10
10
|
CstType,
|
|
11
|
+
DiagnosticKind,
|
|
11
12
|
EvalStatus,
|
|
12
13
|
RSErrorCode,
|
|
14
|
+
RSDiagnosticCode,
|
|
13
15
|
RSToolAgent,
|
|
14
16
|
ValueClass,
|
|
15
17
|
type AgentConstituentaPatch,
|
|
@@ -20,7 +22,9 @@ export {
|
|
|
20
22
|
type BasicBinding,
|
|
21
23
|
type ConstituentaDraft,
|
|
22
24
|
type ConstituentaState,
|
|
23
|
-
type
|
|
25
|
+
type CstDiagnostic,
|
|
26
|
+
type Diagnostic,
|
|
27
|
+
type DiagnosticSeverity,
|
|
24
28
|
type EvaluateInput,
|
|
25
29
|
type EvaluationResult,
|
|
26
30
|
type ExportFormat,
|
|
@@ -40,7 +44,6 @@ export {
|
|
|
40
44
|
type RecalculateModelResult,
|
|
41
45
|
type RSToolAgentContract,
|
|
42
46
|
type RSToolAgentOptions,
|
|
43
|
-
type RSToolErrorDescription,
|
|
44
47
|
type RSToolValue,
|
|
45
48
|
type SessionHandle,
|
|
46
49
|
type SessionModelState,
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Constituenta,
|
|
3
|
+
type CstDiagnostic,
|
|
4
|
+
DiagnosticKind,
|
|
5
|
+
modelStatusCstDiagnostic,
|
|
6
|
+
RSDiagnosticCode
|
|
7
|
+
} from '@rsconcept/domain/library';
|
|
8
|
+
import { EvalStatus } from '@rsconcept/domain/library/rsmodel';
|
|
9
|
+
import { isCritical, RSErrorCode, type RSErrorDescription } from '@rsconcept/domain/rslang/error';
|
|
10
|
+
|
|
11
|
+
export { DiagnosticKind, RSDiagnosticCode };
|
|
12
|
+
|
|
13
|
+
/** Severity of a {@link Diagnostic}. */
|
|
14
|
+
export type DiagnosticSeverity = 'error' | 'warning';
|
|
15
|
+
|
|
16
|
+
/** Agent-facing diagnostic with redundant fields for autonomous repair. */
|
|
17
|
+
export interface Diagnostic extends CstDiagnostic {
|
|
18
|
+
name: string;
|
|
19
|
+
severity: DiagnosticSeverity;
|
|
20
|
+
constituentId?: number;
|
|
21
|
+
alias?: string;
|
|
22
|
+
expression: string;
|
|
23
|
+
from: number;
|
|
24
|
+
to: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Context for attributing a {@link Diagnostic} to a constituent. */
|
|
28
|
+
export interface DiagnosticTarget {
|
|
29
|
+
constituentId?: number;
|
|
30
|
+
alias?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const DIAGNOSTIC_NAMES: ReadonlyMap<number, string> = new Map([
|
|
34
|
+
...Object.entries(RSErrorCode).map(([name, code]) => [code, name] as const),
|
|
35
|
+
...Object.entries(RSDiagnosticCode).map(([name, code]) => [code, name] as const)
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
export function getDiagnosticName(code: number): string {
|
|
39
|
+
return DIAGNOSTIC_NAMES.get(code) ?? `0x${code.toString(16).toUpperCase()}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function getDiagnosticSeverity(code: number): DiagnosticSeverity {
|
|
43
|
+
return isCritical(code as RSErrorCode) ? 'error' : 'warning';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function expandCstDiagnostic(cst: Constituenta, diagnostic: CstDiagnostic): Diagnostic {
|
|
47
|
+
const expression = expressionForCstDiagnostic(cst, diagnostic);
|
|
48
|
+
return {
|
|
49
|
+
...diagnostic,
|
|
50
|
+
name: getDiagnosticName(diagnostic.code),
|
|
51
|
+
severity: getDiagnosticSeverity(diagnostic.code),
|
|
52
|
+
constituentId: cst.id,
|
|
53
|
+
alias: cst.alias,
|
|
54
|
+
expression,
|
|
55
|
+
from: 0,
|
|
56
|
+
to: diagnostic.kind === DiagnosticKind.MODEL ? 0 : Math.max(expression.length, 1)
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function expressionDiagnostic(
|
|
61
|
+
error: RSErrorDescription,
|
|
62
|
+
expression: string,
|
|
63
|
+
target?: DiagnosticTarget
|
|
64
|
+
): Diagnostic {
|
|
65
|
+
return {
|
|
66
|
+
kind: DiagnosticKind.EXPRESSION,
|
|
67
|
+
code: error.code,
|
|
68
|
+
name: getDiagnosticName(error.code),
|
|
69
|
+
severity: getDiagnosticSeverity(error.code),
|
|
70
|
+
constituentId: target?.constituentId,
|
|
71
|
+
alias: target?.alias,
|
|
72
|
+
expression,
|
|
73
|
+
from: error.from,
|
|
74
|
+
to: error.to,
|
|
75
|
+
...(error.params ? { params: error.params } : {})
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function modelStatusDiagnostic(status: EvalStatus, cst: Constituenta): Diagnostic | null {
|
|
80
|
+
const base = modelStatusCstDiagnostic(status, cst.cst_type);
|
|
81
|
+
return base ? expandCstDiagnostic(cst, base) : null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function expressionForCstDiagnostic(cst: Constituenta, diagnostic: CstDiagnostic): string {
|
|
85
|
+
switch (diagnostic.code) {
|
|
86
|
+
case RSDiagnosticCode.schemaHomonym:
|
|
87
|
+
case RSDiagnosticCode.schemaMissingTerm:
|
|
88
|
+
return cst.term_resolved;
|
|
89
|
+
case RSDiagnosticCode.schemaMissingConvention:
|
|
90
|
+
return cst.convention;
|
|
91
|
+
case RSDiagnosticCode.schemaTypeMismatch:
|
|
92
|
+
return cst.typification_manual;
|
|
93
|
+
default:
|
|
94
|
+
return cst.definition_formal;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { CstType, RSDiagnosticCode, type SessionState, ValueClass } from '../models';
|
|
4
|
+
import { collectSessionDiagnostics } from './diagnostics-collector';
|
|
5
|
+
|
|
6
|
+
describe('collectSessionDiagnostics', () => {
|
|
7
|
+
it('collects expression, schema, and model diagnostics together', () => {
|
|
8
|
+
const session = {
|
|
9
|
+
sessionId: 'test',
|
|
10
|
+
alias: '',
|
|
11
|
+
title: '',
|
|
12
|
+
comment: '',
|
|
13
|
+
createdAt: '',
|
|
14
|
+
updatedAt: '',
|
|
15
|
+
revisions: [],
|
|
16
|
+
model: { items: [] },
|
|
17
|
+
items: [
|
|
18
|
+
{
|
|
19
|
+
id: 1,
|
|
20
|
+
alias: 'X1',
|
|
21
|
+
cstType: CstType.BASE,
|
|
22
|
+
definitionFormal: 'Z',
|
|
23
|
+
term: '',
|
|
24
|
+
definitionText: '',
|
|
25
|
+
convention: '',
|
|
26
|
+
analysis: {
|
|
27
|
+
success: false,
|
|
28
|
+
type: null,
|
|
29
|
+
valueClass: null,
|
|
30
|
+
diagnostics: [{ code: 0x8862, from: 0, to: 1, params: [CstType.BASE, 'X1'] }]
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: 2,
|
|
35
|
+
alias: 'X2',
|
|
36
|
+
cstType: CstType.BASE,
|
|
37
|
+
definitionFormal: '',
|
|
38
|
+
term: 'person',
|
|
39
|
+
definitionText: '',
|
|
40
|
+
convention: 'people',
|
|
41
|
+
analysis: { success: true, type: {}, valueClass: ValueClass.VALUE, diagnostics: [] }
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: 3,
|
|
45
|
+
alias: 'X3',
|
|
46
|
+
cstType: CstType.BASE,
|
|
47
|
+
definitionFormal: '',
|
|
48
|
+
term: 'Person',
|
|
49
|
+
definitionText: '',
|
|
50
|
+
convention: 'other',
|
|
51
|
+
analysis: { success: true, type: {}, valueClass: ValueClass.VALUE, diagnostics: [] }
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const records = collectSessionDiagnostics(session as SessionState);
|
|
57
|
+
expect(records.some(record => record.kind === 'expression')).toBe(true);
|
|
58
|
+
expect(records.some(record => record.code === RSDiagnosticCode.schemaHomonym)).toBe(true);
|
|
59
|
+
expect(records.some(record => record.code === RSDiagnosticCode.schemaMissingTerm)).toBe(true);
|
|
60
|
+
expect(records.some(record => record.code === RSDiagnosticCode.modelEmpty)).toBe(true);
|
|
61
|
+
expect(records.every(record => record.name.length > 0)).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { isModelIssue } from '@rsconcept/domain/library/rsmodel-api';
|
|
2
|
+
import { type RSErrorDescription } from '@rsconcept/domain/rslang';
|
|
3
|
+
|
|
4
|
+
import { type SessionState } from '../models';
|
|
5
|
+
import {
|
|
6
|
+
DiagnosticKind,
|
|
7
|
+
expandCstDiagnostic,
|
|
8
|
+
expressionDiagnostic,
|
|
9
|
+
modelStatusDiagnostic,
|
|
10
|
+
type Diagnostic
|
|
11
|
+
} from './diagnostic-assembly';
|
|
12
|
+
import { ModelAdapter } from './model-adapter';
|
|
13
|
+
import { enrichSessionConstituents } from './rsform-builder';
|
|
14
|
+
|
|
15
|
+
const modelAdapter = new ModelAdapter();
|
|
16
|
+
|
|
17
|
+
/** Collect expression, schema, and model diagnostics for a session (Portal parity). */
|
|
18
|
+
export function collectSessionDiagnostics(session: SessionState): Diagnostic[] {
|
|
19
|
+
const records: Diagnostic[] = [];
|
|
20
|
+
|
|
21
|
+
for (const item of session.items) {
|
|
22
|
+
for (const diagnostic of item.analysis.diagnostics) {
|
|
23
|
+
const base = diagnostic.name
|
|
24
|
+
? diagnostic
|
|
25
|
+
: expressionDiagnostic(
|
|
26
|
+
{
|
|
27
|
+
code: diagnostic.code,
|
|
28
|
+
from: diagnostic.from,
|
|
29
|
+
to: diagnostic.to,
|
|
30
|
+
params: diagnostic.params
|
|
31
|
+
} as RSErrorDescription,
|
|
32
|
+
item.definitionFormal,
|
|
33
|
+
{
|
|
34
|
+
constituentId: item.id,
|
|
35
|
+
alias: item.alias
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
records.push({
|
|
39
|
+
...base,
|
|
40
|
+
kind: DiagnosticKind.EXPRESSION,
|
|
41
|
+
constituentId: base.constituentId ?? item.id,
|
|
42
|
+
alias: base.alias ?? item.alias
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const enriched = enrichSessionConstituents(session);
|
|
48
|
+
for (const { cst } of enriched) {
|
|
49
|
+
for (const diagnostic of cst.diagnostics) {
|
|
50
|
+
if (diagnostic.kind !== DiagnosticKind.SCHEMA) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
records.push(expandCstDiagnostic(cst, diagnostic));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (session.items.length > 0) {
|
|
58
|
+
const schema = enriched.map(entry => entry.cst);
|
|
59
|
+
const engine = modelAdapter.createEngine(session);
|
|
60
|
+
engine.recalculateAll();
|
|
61
|
+
for (const cst of schema) {
|
|
62
|
+
if (!isModelIssue(engine, cst)) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const diagnostic = modelStatusDiagnostic(engine.getCstStatus(cst.id), cst);
|
|
66
|
+
if (diagnostic) {
|
|
67
|
+
records.push(diagnostic);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return records;
|
|
73
|
+
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { type ExpressionType, RSLangAnalyzer, type Value, type ValueClass } from '@rsconcept/domain/rslang';
|
|
1
|
+
import { DiagnosticKind, expressionDiagnostic } from './diagnostic-assembly';
|
|
2
|
+
import { type RSErrorDescription, type Value } from '@rsconcept/domain/rslang';
|
|
4
3
|
import { isBaseSet } from '@rsconcept/domain/library/rsform-api';
|
|
5
|
-
import {
|
|
4
|
+
import { CstType, type RSForm } from '@rsconcept/domain/library/rsform';
|
|
6
5
|
import { RSEngine, type RSEngineServices } from '@rsconcept/domain/library/rsengine';
|
|
7
6
|
import { type BasicBinding, EvalStatus, type RSModel } from '@rsconcept/domain/library/rsmodel';
|
|
8
7
|
import {
|
|
@@ -14,14 +13,13 @@ import {
|
|
|
14
13
|
} from '@rsconcept/domain/library/rsmodel-api';
|
|
15
14
|
|
|
16
15
|
import {
|
|
17
|
-
type ConstituentaState,
|
|
18
16
|
type EvaluationResult,
|
|
19
17
|
type RecalculateModelResult,
|
|
20
18
|
type SessionModelState,
|
|
21
19
|
type SessionState,
|
|
22
20
|
type SetConstituentaValueInput
|
|
23
21
|
} from '../models';
|
|
24
|
-
import {
|
|
22
|
+
import { buildRSFormFromSession } from './rsform-builder';
|
|
25
23
|
|
|
26
24
|
const SESSION_MODEL_ID = 0;
|
|
27
25
|
|
|
@@ -73,7 +71,14 @@ export class ModelAdapter {
|
|
|
73
71
|
? EvalStatus.EVAL_FAIL
|
|
74
72
|
: EvalStatus.EMPTY
|
|
75
73
|
: EvalStatus.HAS_DATA;
|
|
76
|
-
return toPublicEvaluationResult(
|
|
74
|
+
return toPublicEvaluationResult(
|
|
75
|
+
result.value,
|
|
76
|
+
result.errors,
|
|
77
|
+
result.iterations,
|
|
78
|
+
result.cacheHits,
|
|
79
|
+
status,
|
|
80
|
+
expression
|
|
81
|
+
);
|
|
77
82
|
}
|
|
78
83
|
|
|
79
84
|
public evaluateConstituenta(session: SessionState, constituentId: number): EvaluationResult {
|
|
@@ -84,7 +89,15 @@ export class ModelAdapter {
|
|
|
84
89
|
const engine = this.createEngine(session);
|
|
85
90
|
const result = engine.calculateCst(constituentId);
|
|
86
91
|
const status = engine.getCstStatus(constituentId);
|
|
87
|
-
return toPublicEvaluationResult(
|
|
92
|
+
return toPublicEvaluationResult(
|
|
93
|
+
result.value,
|
|
94
|
+
result.errors,
|
|
95
|
+
result.iterations,
|
|
96
|
+
result.cacheHits,
|
|
97
|
+
status,
|
|
98
|
+
cst.definitionFormal,
|
|
99
|
+
{ constituentId: cst.id, alias: cst.alias }
|
|
100
|
+
);
|
|
88
101
|
}
|
|
89
102
|
|
|
90
103
|
public recalculateModel(session: SessionState): RecalculateModelResult {
|
|
@@ -155,55 +168,6 @@ function createInMemoryServices(session: SessionState): RSEngineServices {
|
|
|
155
168
|
};
|
|
156
169
|
}
|
|
157
170
|
|
|
158
|
-
function buildRSFormFromSession(session: SessionState): RSForm {
|
|
159
|
-
const graph = new Graph<number>();
|
|
160
|
-
const cstByAlias = new Map<string, Constituenta>();
|
|
161
|
-
const cstByID = new Map<number, Constituenta>();
|
|
162
|
-
const analyzer = new RSLangAnalyzer();
|
|
163
|
-
|
|
164
|
-
const items = session.items.map(item => {
|
|
165
|
-
const cst = toFrontendConstituenta(item);
|
|
166
|
-
cstByAlias.set(cst.alias, cst);
|
|
167
|
-
cstByID.set(cst.id, cst);
|
|
168
|
-
graph.addNode(cst.id);
|
|
169
|
-
if (item.cstType === CstType.BASE) {
|
|
170
|
-
analyzer.addBase(cst.alias);
|
|
171
|
-
}
|
|
172
|
-
if (cst.effectiveType) {
|
|
173
|
-
analyzer.setGlobal(cst.alias, cst.effectiveType, cst.analysis.valueClass as ValueClass | null);
|
|
174
|
-
}
|
|
175
|
-
return cst;
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
for (const cst of items) {
|
|
179
|
-
for (const alias of extractGlobals(cst.definition_formal)) {
|
|
180
|
-
const source = cstByAlias.get(alias);
|
|
181
|
-
if (source) {
|
|
182
|
-
graph.addEdge(source.id, cst.id);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
return {
|
|
188
|
-
id: 0,
|
|
189
|
-
items,
|
|
190
|
-
cstByAlias,
|
|
191
|
-
cstByID,
|
|
192
|
-
graph,
|
|
193
|
-
analyzer,
|
|
194
|
-
inheritance: [],
|
|
195
|
-
attribution: [],
|
|
196
|
-
attribution_graph: graph.clone(),
|
|
197
|
-
oss: [],
|
|
198
|
-
models: [],
|
|
199
|
-
editors: [],
|
|
200
|
-
versions: [],
|
|
201
|
-
is_produced: false,
|
|
202
|
-
is_attributive: false,
|
|
203
|
-
version: 'latest'
|
|
204
|
-
} as unknown as RSForm;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
171
|
function buildRSModelFromSession(session: SessionState): RSModel {
|
|
208
172
|
return {
|
|
209
173
|
id: SESSION_MODEL_ID,
|
|
@@ -217,54 +181,19 @@ function buildRSModelFromSession(session: SessionState): RSModel {
|
|
|
217
181
|
} as unknown as RSModel;
|
|
218
182
|
}
|
|
219
183
|
|
|
220
|
-
function toFrontendConstituenta(item: ConstituentaState): Constituenta {
|
|
221
|
-
const effectiveType = (item.analysis.type ?? null) as ExpressionType | null;
|
|
222
|
-
return {
|
|
223
|
-
id: item.id,
|
|
224
|
-
alias: item.alias,
|
|
225
|
-
cst_type: item.cstType,
|
|
226
|
-
definition_formal: item.definitionFormal,
|
|
227
|
-
definition_raw: item.definitionFormal,
|
|
228
|
-
definition_resolved: item.definitionFormal,
|
|
229
|
-
term_raw: item.term,
|
|
230
|
-
term_resolved: item.term,
|
|
231
|
-
term_forms: [],
|
|
232
|
-
convention: item.convention,
|
|
233
|
-
typification_manual: '',
|
|
234
|
-
value_is_property: false,
|
|
235
|
-
crucial: false,
|
|
236
|
-
attributes: [],
|
|
237
|
-
homonyms: [],
|
|
238
|
-
formalDuplicates: [],
|
|
239
|
-
analysis: {
|
|
240
|
-
success: item.analysis.success,
|
|
241
|
-
type: effectiveType,
|
|
242
|
-
valueClass: item.analysis.valueClass
|
|
243
|
-
},
|
|
244
|
-
effectiveType,
|
|
245
|
-
is_type_mismatch: false,
|
|
246
|
-
schema: 0,
|
|
247
|
-
cst_class: 'derived',
|
|
248
|
-
status: item.analysis.success ? 'verified' : 'incorrect',
|
|
249
|
-
is_template: false,
|
|
250
|
-
is_simple_expression: true,
|
|
251
|
-
parent_schema_index: 0,
|
|
252
|
-
parent_schema: null,
|
|
253
|
-
is_inherited: false,
|
|
254
|
-
has_inherited_children: false,
|
|
255
|
-
spawn: [],
|
|
256
|
-
spawn_alias: []
|
|
257
|
-
} as unknown as Constituenta;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
184
|
function toPublicEvaluationResult(
|
|
261
185
|
value: Value | null,
|
|
262
186
|
errors: { code: number; from: number; to: number; params?: readonly string[] }[],
|
|
263
187
|
iterations: number,
|
|
264
188
|
cacheHits: number,
|
|
265
|
-
status: EvalStatus
|
|
189
|
+
status: EvalStatus,
|
|
190
|
+
expression: string,
|
|
191
|
+
target?: { constituentId?: number; alias?: string }
|
|
266
192
|
): EvaluationResult {
|
|
267
|
-
const diagnostics = errors.map(
|
|
193
|
+
const diagnostics = errors.map(error => ({
|
|
194
|
+
...expressionDiagnostic(error as RSErrorDescription, expression, target),
|
|
195
|
+
kind: DiagnosticKind.MODEL
|
|
196
|
+
}));
|
|
268
197
|
return {
|
|
269
198
|
success: diagnostics.length === 0 && value !== null,
|
|
270
199
|
value: value as EvaluationResult['value'],
|