@rsconcept/rstool 1.7.1 → 1.9.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 +5 -5
- package/dist/index.js +1 -1
- package/dist/mappers/model-adapter.d.ts +5 -0
- package/dist/mappers/model-adapter.js +28 -3
- package/dist/mappers/model-adapter.js.map +1 -1
- package/dist/mappers/schema-adapter.js +1 -1
- package/dist/models/index.js +1 -1
- package/dist/models/rstool-agent.js +1 -1
- package/dist/{models-DG2uTaV_.js → models-D06g8LId.js} +6 -5
- package/dist/{models-DG2uTaV_.js.map → models-D06g8LId.js.map} +1 -1
- package/dist/{rsform-builder-DKwZfJvN.js → rsform-builder-BlXEe5Ow.js} +2 -2
- package/dist/{rsform-builder-DKwZfJvN.js.map → rsform-builder-BlXEe5Ow.js.map} +1 -1
- package/dist/session/session-store.js +1 -1
- package/dist/wrapper/client.d.ts +12 -5
- package/dist/wrapper/client.js +79 -12
- package/dist/wrapper/client.js.map +1 -1
- package/dist/wrapper/stdio-wrapper.d.ts +1 -1
- package/dist/wrapper/stdio-wrapper.js +18 -10
- package/dist/wrapper/stdio-wrapper.js.map +1 -1
- package/docs/CONCEPTUAL-SCHEMA.md +1 -1
- package/docs/CONSTRUCTIONS.md +372 -0
- package/docs/DIAGNOSTICS.md +6 -6
- package/docs/MODEL-TESTING.md +48 -0
- package/docs/README.md +1 -0
- package/docs/SYNTAX.md +1 -1
- package/docs/TYPIFICATION.md +11 -2
- package/package.json +20 -19
- package/skills/README.md +1 -1
- package/skills/rstool-helper/EXAMPLES.md +24 -0
- package/skills/rstool-helper/GUIDE.md +46 -19
- package/skills/rstool-helper/REFERENCE.md +22 -3
- package/skills/rstool-helper/SKILL.md +6 -3
- package/src/mappers/model-adapter.ts +34 -1
- package/src/models/rstool-agent.test.ts +95 -0
- package/src/wrapper/client.test.ts +43 -4
- package/src/wrapper/client.ts +95 -16
- package/src/wrapper/stdio-handler.test.ts +43 -0
- package/src/wrapper/stdio-handler.ts +19 -5
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
- Stdio/MCP: **плоские** `params` — поля метода и optional `sessionId` на одном уровне (без `params.input`).
|
|
19
19
|
- Состояние: `getSessionState()` (summary) или `getSessionState('full')`.
|
|
20
20
|
- Импорт/экспорт Portal: `importData`, `exportPortal({ kind })`.
|
|
21
|
-
- Модель: `setModelValues`, `evaluate`, `recalculateModel`.
|
|
21
|
+
- Модель: `setModelValues`, `evaluate`, `recalculateModel`. Статусы вычисления приходят числами (`EvalStatus`, см. REFERENCE).
|
|
22
22
|
- Перед сохранением сомнительной формулы — `analyzeExpression`.
|
|
23
23
|
|
|
24
24
|
## Задача → чтение
|
|
@@ -31,9 +31,10 @@
|
|
|
31
31
|
| Оценить / отревьюить готовую КС (без запроса «перепиши») | этот GUIDE → [ревью / оценка](#ревью--оценка-готовой-кс); [чеклист ревью](#ревью-концептуальной-схемы); [CONCEPTUAL-SCHEMA.md](../../docs/CONCEPTUAL-SCHEMA.md); при импорте — [PORTAL-API.md](../../docs/PORTAL-API.md) | EXAMPLES с batch patch; полный SYNTAX |
|
|
32
32
|
| Точечные правки существующей схемы | этот GUIDE → [редактирование](#редактирование-и-проверка-схемы); [REFERENCE.md](REFERENCE.md) при вызовах | CONCEPTUAL-SCHEMA целиком |
|
|
33
33
|
| Починить формулу / диагностики | этот GUIDE → [цикл диагностик](#цикл-диагностик); [DIAGNOSTICS.md](../../docs/DIAGNOSTICS.md); [EXAMPLES.md](EXAMPLES.md) «типичные диагностики» | CONCEPTUAL-SCHEMA; PORTAL-API |
|
|
34
|
+
| Написать формулу; синтаксис `D{}`/`I{}`/`R{}`, `F#`/`P#` | [SYNTAX.md](../../docs/SYNTAX.md); при необходимости [EXAMPLES.md](EXAMPLES.md) | CONSTRUCTIONS; воркфлоу сессий |
|
|
35
|
+
| Объяснить формулу или конструкцию человеку | [CONSTRUCTIONS.md](../../docs/CONSTRUCTIONS.md) | SYNTAX целиком; воркфлоу сессий |
|
|
34
36
|
| Импорт / правка по ссылке Portal | этот GUIDE → [Portal](#оценка-или-правка-кс-из-portal); [PORTAL-API.md](../../docs/PORTAL-API.md) | SYNTAX; BASE-SELECTION |
|
|
35
37
|
| Проверить смысл на данных / КМ | этот GUIDE → [КМ](#проверка-на-маленькой-км); [MODEL-TESTING.md](../../docs/MODEL-TESTING.md) | DOMAIN/ОСС; CONCEPTUAL-SCHEMA |
|
|
36
|
-
| Объяснить синтаксис / генераторы / `F#`/`P#` | [SYNTAX.md](../../docs/SYNTAX.md); при необходимости [EXAMPLES.md](EXAMPLES.md) | воркфлоу сессий |
|
|
37
38
|
| Разобрать типизацию / ступени | [TYPIFICATION.md](../../docs/TYPIFICATION.md) | PORTAL-API |
|
|
38
39
|
| Вызовы API / stdio / MCP | [REFERENCE.md](REFERENCE.md) | docs языка |
|
|
39
40
|
| Термины КС, ядро/тело, не путать ярлыки | [DOMAIN.md](../../docs/DOMAIN.md) | — |
|
|
@@ -56,10 +57,28 @@
|
|
|
56
57
|
Из корня workspace Portal (после `pnpm install` и сборки `@rsconcept/domain`):
|
|
57
58
|
|
|
58
59
|
```bash
|
|
59
|
-
pnpm --filter @rsconcept/rstool exec tsx path/to/
|
|
60
|
+
pnpm --filter @rsconcept/rstool exec tsx C:/path/to/review.mts
|
|
60
61
|
```
|
|
61
62
|
|
|
62
|
-
|
|
63
|
+
Правила для скрипта **вне** `rsconcept/rstool/`:
|
|
64
|
+
|
|
65
|
+
- `import … from '@rsconcept/rstool'` из такого файла **не резолвится** — пакет не поднят в корневой `node_modules`. Импортируй по абсолютному `file://` URL: `file:///<workspace>/rsconcept/rstool/src/index.ts` (или `…/dist/index.js`). На Windows абсолютный путь без `file://` тоже падает (`ERR_UNSUPPORTED_ESM_URL_SCHEME`).
|
|
66
|
+
- Расширение **`.mts`**: `.ts` вне пакета трактуется как CommonJS, а `@rsconcept/*` экспортируют только ESM (`ERR_PACKAGE_PATH_NOT_EXPORTED`).
|
|
67
|
+
- Helpers domain — тем же способом: `file:///…/rsconcept/domain/src/index.ts` (`TUPLE_ID`), `…/domain/src/rslang/labels.ts` (`labelType`).
|
|
68
|
+
- Вывод в файл с `-Encoding utf8` (PowerShell) — в консоли cp1251 символы ЯРЭ ломаются.
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import { readFileSync } from 'node:fs';
|
|
72
|
+
// <workspace> — абсолютный путь к корню Portal, например D:/work/Portal или /home/me/Portal
|
|
73
|
+
import { RSToolAgent } from 'file:///<workspace>/rsconcept/rstool/src/index.ts';
|
|
74
|
+
import { TUPLE_ID } from 'file:///<workspace>/rsconcept/domain/src/index.ts';
|
|
75
|
+
|
|
76
|
+
const tool = new RSToolAgent();
|
|
77
|
+
tool.importData(readFileSync('C:/tmp/details.json', 'utf-8'));
|
|
78
|
+
console.log(tool.listDiagnostics());
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Альтернатива без резолвинга — stdio-обёртка из собранного `dist`: `RSToolWrapperClient({ command: 'node', args: ['<abs>/rsconcept/rstool/dist/wrapper/stdio-wrapper.js'], cwd: '<abs>/rsconcept/rstool' })`. Внутри пакета (тесты, штатные `examples/`) обычный `@rsconcept/rstool` работает.
|
|
63
82
|
|
|
64
83
|
## Что читать
|
|
65
84
|
|
|
@@ -72,6 +91,7 @@ pnpm --filter @rsconcept/rstool exec tsx path/to/your/build-schema.ts
|
|
|
72
91
|
- Концептуализация, создание схемы: [../../docs/CONCEPTUAL-SCHEMA.md](../../docs/CONCEPTUAL-SCHEMA.md).
|
|
73
92
|
- Конституенты и валидация: [../../docs/CONSTITUENTA.md](../../docs/CONSTITUENTA.md).
|
|
74
93
|
- Синтаксис ЯРЭ: [../../docs/SYNTAX.md](../../docs/SYNTAX.md).
|
|
94
|
+
- Объяснение формул и конструкций: [../../docs/CONSTRUCTIONS.md](../../docs/CONSTRUCTIONS.md).
|
|
75
95
|
- Типизация: [../../docs/TYPIFICATION.md](../../docs/TYPIFICATION.md).
|
|
76
96
|
- Проверка определений на КМ: [../../docs/MODEL-TESTING.md](../../docs/MODEL-TESTING.md).
|
|
77
97
|
- Диагностики: [../../docs/DIAGNOSTICS.md](../../docs/DIAGNOSTICS.md).
|
|
@@ -130,19 +150,20 @@ kind `auto` (default) определит `portal-details` или `portal-schema`
|
|
|
130
150
|
**Правило:** без явного запроса на правку не делай массовый рефакторинг и не заменяй схему «улучшенной версией». Сначала отчёт; правки — только по согласованию или если пользователь сразу сказал «исправь».
|
|
131
151
|
|
|
132
152
|
1. Загрузи схему: текущая сессия, `importData`, или Portal → [PORTAL-API.md](../../docs/PORTAL-API.md).
|
|
133
|
-
2. `listDiagnostics()` — раздели `expression` / `schema` / `model`; зафиксируй ошибки и предупреждения.
|
|
134
|
-
3. `getSessionState('summary')` — обзор состава; при необходимости `full` для формул.
|
|
153
|
+
2. `listDiagnostics()` — раздели `expression` / `schema` / `model`; зафиксируй ошибки и предупреждения. `analysisSuccess: true` в summary **не** означает отсутствие диагностик (например, `invalidPropertyUsage` даёт `error` при успешном разборе) — опирайся на `listDiagnostics`.
|
|
154
|
+
3. `getSessionState('summary')` — обзор состава; при необходимости `full` для формул. Типизацию из `analysis.type` печатай через `labelType` ([TYPIFICATION.md](../../docs/TYPIFICATION.md)), а не разбирай AST вручную.
|
|
135
155
|
4. Структурный проход по [чеклисту ревью](#ревью-концептуальной-схемы) и [CONCEPTUAL-SCHEMA.md](../../docs/CONCEPTUAL-SCHEMA.md):
|
|
136
156
|
- неопределяемые vs производные (`S#` там, где должно быть `D#`/`F#`/`P#`);
|
|
137
157
|
- `X#` / `C#` / `Z` ([BASE-SELECTION.md](../../docs/BASE-SELECTION.md));
|
|
138
158
|
- терм-функции vs множества пар;
|
|
139
159
|
- радикалы `R#` не объявлены конституентами;
|
|
140
160
|
- покрытие задачи vs избыточность.
|
|
141
|
-
5. Severity в
|
|
142
|
-
- **блокер** —
|
|
143
|
-
- **важно** — нарушение правил проектирования (лишнее `S#`, график вместо `F#`, смешение
|
|
144
|
-
- **замечание** — стиль, именование,
|
|
145
|
-
6.
|
|
161
|
+
5. Severity в отчёте — по **смыслу** диагностики, а не только по полю `severity` (инструмент помечает `error` и метаданные):
|
|
162
|
+
- **блокер** — `expression` с `severity: error` (формула не разбирается, невычислима: `invalidPropertyUsage`, …), `schemaDependencyCycle`, `schemaFormalDuplicate`, `schemaHomonym`; схема не анализируется / ломает вычисление;
|
|
163
|
+
- **важно** — нарушение правил проектирования (лишнее `S#`, график вместо `F#`, смешение экспликаций, перекрёстные ссылки `C#`, термин сильнее формулы);
|
|
164
|
+
- **замечание** — `schemaMissingConvention`, `schemaMissingTerm`, `modelEmpty` у структур, не задействованных в проверке; стиль, именование, упрощения, пробелы покрытия.
|
|
165
|
+
6. Проверь на маленькой КМ ключевые производные и аксиомы ([цикл КМ](#проверка-на-маленькой-км)): позитивный набор данных → ожидаемые значения, негативный → `AXIOM_FALSE`. Это чаще всего даёт главные находки (расхождение термина и формулы, лишние/пропущенные элементы).
|
|
166
|
+
7. Ответ — по [шаблону ревью](#шаблон-ответа-ревью). Предлагай конкретные правки списком; применяй их только по запросу.
|
|
146
167
|
|
|
147
168
|
### Цикл диагностик
|
|
148
169
|
|
|
@@ -160,12 +181,14 @@ kind `auto` (default) определит `portal-details` или `portal-schema`
|
|
|
160
181
|
|
|
161
182
|
Когда синтаксис верен, но смысл формулы неочевиден. Подробности и форма данных — [MODEL-TESTING.md](../../docs/MODEL-TESTING.md).
|
|
162
183
|
|
|
163
|
-
1. Отдельная `createSession` или изолированная копия текущей
|
|
184
|
+
1. Отдельная `createSession` или изолированная копия текущей сессии (для ревью схемы из Portal достаточно самой импортированной сессии).
|
|
164
185
|
2. Только нужные поставщики: `X#`, `C#`, `S#` и проверяемые `D#` / `F#` / `P#` / `A#`.
|
|
165
186
|
3. `analyzeExpression` и `applySchemaPatch`.
|
|
166
|
-
4. Значения: `setModelValues`.
|
|
167
|
-
5. `evaluate
|
|
168
|
-
6.
|
|
187
|
+
4. Значения: `setModelValues`. `X#` — `{ 0: 'a', 1: 'b' }` (индекс → подпись), `S#` — массив кортежей `[TUPLE_ID, i, j]` по индексам `X#`; порядок элементов не важен, значения приводятся к канонической форме автоматически.
|
|
188
|
+
5. `evaluate({ constituentId })` для конституенты; `evaluate({ expression, cstType })` для scratch-выражения — `cstType` задаёт ожидаемую ступень: множества и числа — `'term'`, логические выражения (`P1[S1]`, `D2⊆S1`) — `'axiom'`. В scratch можно ссылаться на любые конституенты схемы, включая `D#` — зависимости вычисляются автоматически.
|
|
189
|
+
6. `status` в ответе — **число** (`EvalStatus`): `7` `HAS_DATA`, `6` `EMPTY`, `5` `AXIOM_FALSE`, `4` `EVAL_FAIL`, `3` `INVALID_DATA`, `1` `NO_EVAL`; полный список — [REFERENCE.md](REFERENCE.md). Сравни `value` с ожидаемым.
|
|
190
|
+
7. При нескольких зависимых определениях — `recalculateModel`.
|
|
191
|
+
8. Для аксиом — два набора данных: корректный (истина) и нарушающий (`AXIOM_FALSE`).
|
|
169
192
|
|
|
170
193
|
Для регрессий вынеси проверку в скрипт или colocated `*.test.ts` (см. [MODEL-TESTING.md](../../docs/MODEL-TESTING.md)).
|
|
171
194
|
|
|
@@ -194,8 +217,8 @@ kind `auto` (default) определит `portal-details` или `portal-schema`
|
|
|
194
217
|
2. **Диагностики:** число ошибок / предупреждений по `expression` / `schema` / `model` (без полного JSON).
|
|
195
218
|
3. **Находки** списком: блокер → важно → замечание; у каждой — имя конституенты и суть.
|
|
196
219
|
4. **Покрытие:** что из задачи отражено; чего не хватает.
|
|
197
|
-
5. **Рекомендации:** конкретные правки; не применяй их без запроса.
|
|
198
|
-
6. **Проверки:** что уже сделано (
|
|
220
|
+
5. **Рекомендации:** конкретные правки; не применяй их без запроса. Предложенную замену формулы прогони через анализ выражения (и по возможности через КМ) до того, как её советовать.
|
|
221
|
+
6. **Проверки:** что уже сделано (импорт, диагностики, выборочный анализ) и **КМ**: данные → ожидание → результат для проверенных конституент.
|
|
199
222
|
|
|
200
223
|
### Шаблон ответа: диагностики
|
|
201
224
|
|
|
@@ -206,10 +229,14 @@ kind `auto` (default) определит `portal-details` или `portal-schema`
|
|
|
206
229
|
|
|
207
230
|
### Шаблон ответа: объяснение формулы
|
|
208
231
|
|
|
232
|
+
Полный сценарий и карточки конструкций — [CONSTRUCTIONS.md](../../docs/CONSTRUCTIONS.md). Кратко:
|
|
233
|
+
|
|
209
234
|
- роль конституенты и термин;
|
|
210
235
|
- формула как есть;
|
|
211
|
-
-
|
|
212
|
-
-
|
|
236
|
+
- ТМВ или ЛВ;
|
|
237
|
+
- снаружи внутрь, только конструкции из формулы;
|
|
238
|
+
- ступень и опоры;
|
|
239
|
+
- вычисление на данных — только по запросу.
|
|
213
240
|
|
|
214
241
|
### Язык ответа
|
|
215
242
|
|
|
@@ -114,7 +114,9 @@ tool.listDiagnostics({ kind: 'expression' });
|
|
|
114
114
|
tool.listDiagnostics({ kind: 'schema', constituentId: 3, severity: 'error' });
|
|
115
115
|
```
|
|
116
116
|
|
|
117
|
-
Фильтры: `kind?: 'expression' | 'schema' | 'model'`, `constituentId?`, `severity?: 'error' | 'warning'`.
|
|
117
|
+
Фильтры: `kind?: 'expression' | 'schema' | 'model'`, `constituentId?`, `severity?: 'error' | 'warning'`. В stdio / MCP те же поля передаются **плоско** в `params` (`{ "kind": "schema", "severity": "warning" }`); stdio дополнительно принимает устаревший вложенный `filters`.
|
|
118
|
+
|
|
119
|
+
`severity` отражает правило инструмента, а не вес для ревью: `schemaMissingConvention` / `schemaMissingTerm` приходят как `error`. Как ранжировать в отчёте — [GUIDE.md](GUIDE.md), «Ревью / оценка готовой КС».
|
|
118
120
|
|
|
119
121
|
Элемент диагностики (агентский вид): `kind`, `code`, `name`, `severity`, `alias?`, `expression`, `from`, `to`, `params?`, `stack?` (цепочка вызовов при ошибке внутри `F#`/`P#`). Ключ для поиска исправления — `name` ([DIAGNOSTICS.md](../../docs/DIAGNOSTICS.md)).
|
|
120
122
|
|
|
@@ -132,6 +134,8 @@ tool.analyzeExpression({
|
|
|
132
134
|
|
|
133
135
|
**Результат:** `{ success, type, valueClass, diagnostics }`. Не сохраняет конституенту. Для черновика формулы — до `applySchemaPatch`.
|
|
134
136
|
|
|
137
|
+
`type` — AST типизации; для чтения используй `labelType` из `@rsconcept/domain/rslang/labels` (`ℬ(X1×X1)`, `[X1] → ℬ(X1)`, `Logic`). `success: true` совместим с диагностикой `error` (например, `invalidPropertyUsage` при `valueClass: null`) — проверяй `diagnostics`.
|
|
138
|
+
|
|
135
139
|
## `evaluate`
|
|
136
140
|
|
|
137
141
|
Ровно один вариант входа:
|
|
@@ -141,7 +145,19 @@ tool.analyzeExpression({
|
|
|
141
145
|
|
|
142
146
|
**Результат:** `{ success, value, status, iterations, cacheHits, diagnostics }`.
|
|
143
147
|
|
|
144
|
-
`status` — статус вычисления
|
|
148
|
+
`status` — статус вычисления КМ, **числовой** код `EvalStatus` (`@rsconcept/domain`); смысл — [DOMAIN.md](../../docs/DOMAIN.md):
|
|
149
|
+
|
|
150
|
+
| Код | Имя | Смысл |
|
|
151
|
+
| --: | --------------- | --------------------------------------- |
|
|
152
|
+
| `1` | `NO_EVAL` | не вычисляется (`X#`, `C#`, `F#`, `P#`) |
|
|
153
|
+
| `2` | `NOT_PROCESSED` | вычисление не запускалось |
|
|
154
|
+
| `3` | `INVALID_DATA` | неверная интерпретация |
|
|
155
|
+
| `4` | `EVAL_FAIL` | ошибка вычисления |
|
|
156
|
+
| `5` | `AXIOM_FALSE` | аксиома ложна |
|
|
157
|
+
| `6` | `EMPTY` | результат пуст |
|
|
158
|
+
| `7` | `HAS_DATA` | вычислено, непусто |
|
|
159
|
+
|
|
160
|
+
Scratch-выражение: `cstType` задаёт ожидаемую ступень (`term` — множество / число, `axiom` — логическое). Ссылки на `D#` / `A#` / `T#` внутри scratch допустимы — их значения (и зависимости через `F#` / `P#`) вычисляются перед оценкой.
|
|
145
161
|
|
|
146
162
|
## `setModelValues` / `getModelState` / `recalculateModel`
|
|
147
163
|
|
|
@@ -155,8 +171,9 @@ await tool.setModelValues({
|
|
|
155
171
|
- `set[]`: `{ target, value, type? }` — `target` = id конституенты; `type` обычно не нужен.
|
|
156
172
|
- `clear[]`: id для сброса значений.
|
|
157
173
|
- Метод **async**. После изменения данных пересчитываются диагностики модели.
|
|
174
|
+
- Значения `S#` приводятся к канонической форме (сортировка, без дубликатов) — порядок элементов во входе не важен; в `getModelState` хранится уже нормализованное значение.
|
|
158
175
|
- `getModelState()` → `{ items: [{ id, type, value }] }`.
|
|
159
|
-
- `recalculateModel()` → `{ items: [{ id, alias, value, status }] }
|
|
176
|
+
- `recalculateModel()` → `{ items: [{ id, alias, value, status }] }` (`status` — числовой `EvalStatus`, таблица выше).
|
|
160
177
|
|
|
161
178
|
Формы `value` для `X#` / `S#` — [MODEL-TESTING.md](../../docs/MODEL-TESTING.md).
|
|
162
179
|
|
|
@@ -237,6 +254,7 @@ JSON-строка сессии для последующего `importData(...,
|
|
|
237
254
|
{"id":"9","method":"exportPortal","params":{"kind":"schema"}}
|
|
238
255
|
{"id":"10","method":"importData","params":{"payload":"..."}}
|
|
239
256
|
{"id":"11","method":"getSessionState","params":{"detail":"summary"}}
|
|
257
|
+
{"id":"12","method":"listDiagnostics","params":{"kind":"expression","severity":"error"}}
|
|
240
258
|
```
|
|
241
259
|
|
|
242
260
|
## Help map: ошибка → документ
|
|
@@ -245,6 +263,7 @@ JSON-строка сессии для последующего `importData(...,
|
|
|
245
263
|
| -------------------------------------------------- | ------------------------------------------------------- |
|
|
246
264
|
| Код / `name` диагностики | [DIAGNOSTICS.md](../../docs/DIAGNOSTICS.md) |
|
|
247
265
|
| Синтаксис операторов, `D{}`/`I{}`/`R{}`, `F#`/`P#` | [SYNTAX.md](../../docs/SYNTAX.md) |
|
|
266
|
+
| Объяснить формулу / конструкцию человеку | [CONSTRUCTIONS.md](../../docs/CONSTRUCTIONS.md) |
|
|
248
267
|
| Ступени, `AnalysisResult.type` | [TYPIFICATION.md](../../docs/TYPIFICATION.md) |
|
|
249
268
|
| `X#` vs `C#` vs `Z`, переносимость | [BASE-SELECTION.md](../../docs/BASE-SELECTION.md) |
|
|
250
269
|
| Проектирование, `F#` vs пары, ревью | [CONCEPTUAL-SCHEMA.md](../../docs/CONCEPTUAL-SCHEMA.md) |
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
name: rstool-helper
|
|
3
3
|
description: >-
|
|
4
4
|
ЯРЭ и концептуальные схемы через rstool: концептуализация, ревью/оценка КС,
|
|
5
|
-
правки и диагностики формул, проверка на КМ (evaluate),
|
|
6
|
-
импорт/экспорт Portal (/rsforms, /details).
|
|
5
|
+
правки и диагностики формул, объяснение конструкций ЯРЭ, проверка на КМ (evaluate),
|
|
6
|
+
выбор X#/C#/Z, импорт/экспорт Portal (/rsforms, /details).
|
|
7
|
+
Читай GUIDE и docs из node_modules.
|
|
7
8
|
---
|
|
8
9
|
|
|
9
10
|
# rstool-helper
|
|
@@ -39,9 +40,11 @@ description: >-
|
|
|
39
40
|
| Собрать / развить КС из текста | GUIDE: концептуализация; `docs/CONCEPTUAL-SCHEMA.md`; `docs/BASE-SELECTION.md` |
|
|
40
41
|
| Оценить / отревьюить готовую КС | GUIDE: ревью; чеклист ревью; `docs/CONCEPTUAL-SCHEMA.md` |
|
|
41
42
|
| Починить формулу / диагностики | GUIDE: цикл диагностик; `docs/DIAGNOSTICS.md` |
|
|
43
|
+
| Написать формулу / синтаксис | `docs/SYNTAX.md` |
|
|
44
|
+
| Объяснить формулу / конструкцию | `docs/CONSTRUCTIONS.md` |
|
|
42
45
|
| Импорт / правка по ссылке Portal | GUIDE: Portal; `docs/PORTAL-API.md` |
|
|
43
46
|
| Проверить смысл на данных | GUIDE: КМ; `docs/MODEL-TESTING.md` |
|
|
44
|
-
|
|
|
47
|
+
| Типизация / вызов API | `docs/TYPIFICATION.md` / `REFERENCE.md` |
|
|
45
48
|
|
|
46
49
|
Перед работой всегда открой **GUIDE.md**; остальное — по строке таблицы.
|
|
47
50
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { DiagnosticKind, expressionDiagnostic } from './diagnostic-assembly';
|
|
2
2
|
import { type RSErrorDescription, type Value } from '@rsconcept/domain/rslang';
|
|
3
|
+
import { extractGlobals } from '@rsconcept/domain/rslang/api';
|
|
4
|
+
import { normalizeValue } from '@rsconcept/domain/rslang/eval/value-api';
|
|
3
5
|
import { isBaseSet } from '@rsconcept/domain/library/rsform-api';
|
|
4
6
|
import { CstType, type RSForm } from '@rsconcept/domain/library/rsform';
|
|
5
7
|
import { RSEngine, type RSEngineServices } from '@rsconcept/domain/library/rsengine';
|
|
@@ -37,7 +39,11 @@ export class ModelAdapter {
|
|
|
37
39
|
const binding = toBasicBinding(input.value as Record<string | number, string>);
|
|
38
40
|
await engine.setBasicValue(input.target, binding);
|
|
39
41
|
} else {
|
|
40
|
-
|
|
42
|
+
// Set operations in the evaluator assume canonical form (sorted, deduplicated);
|
|
43
|
+
// agents may pass elements in arbitrary order.
|
|
44
|
+
const value = structuredClone(input.value) as Value;
|
|
45
|
+
normalizeValue(value);
|
|
46
|
+
await engine.setStructureValue(input.target, value);
|
|
41
47
|
}
|
|
42
48
|
session.updatedAt = new Date().toISOString();
|
|
43
49
|
return structuredClone(session.model);
|
|
@@ -64,6 +70,7 @@ export class ModelAdapter {
|
|
|
64
70
|
|
|
65
71
|
public evaluateExpression(session: SessionState, expression: string, cstType: CstType): EvaluationResult {
|
|
66
72
|
const engine = this.createEngine(session);
|
|
73
|
+
this.prepareReferencedValues(engine, session, expression);
|
|
67
74
|
const result = engine.evaluateExpression(expression, cstType);
|
|
68
75
|
const status =
|
|
69
76
|
result.value === null
|
|
@@ -120,6 +127,32 @@ export class ModelAdapter {
|
|
|
120
127
|
return engine;
|
|
121
128
|
}
|
|
122
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Computes values of inferrable constituents referenced by a scratch expression (directly or
|
|
132
|
+
* through `F#` / `P#` bodies). A fresh engine only holds interpreted `X#` / `C#` / `S#` values.
|
|
133
|
+
*/
|
|
134
|
+
private prepareReferencedValues(engine: RSEngine, session: SessionState, expression: string): void {
|
|
135
|
+
const schema = engine.schema;
|
|
136
|
+
if (!schema) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const globals = extractGlobals(expression);
|
|
140
|
+
const referenced = session.items.filter(item => globals.has(item.alias)).map(item => item.id);
|
|
141
|
+
if (referenced.length === 0) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const required = new Set([...referenced, ...schema.graph.expandAllInputs(referenced)]);
|
|
145
|
+
for (const cstID of schema.graph.topologicalOrder()) {
|
|
146
|
+
if (!required.has(cstID)) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const cst = schema.cstByID.get(cstID);
|
|
150
|
+
if (cst && isInferrable(cst.cst_type)) {
|
|
151
|
+
engine.calculateCst(cstID);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
123
156
|
private validateSetInput(session: SessionState, input: SetConstituentaValueInput): void {
|
|
124
157
|
const cst = session.items.find(item => item.id === input.target);
|
|
125
158
|
if (!cst) {
|
|
@@ -1029,6 +1029,101 @@ describe('RSToolAgent modeling semantics', () => {
|
|
|
1029
1029
|
expect(modelIssues.some(record => record.code === RSDiagnosticCode.modelAxiomFalse)).toBe(true);
|
|
1030
1030
|
});
|
|
1031
1031
|
|
|
1032
|
+
function buildGraphScratch(tool: RSToolAgent, sessionId: string) {
|
|
1033
|
+
tool.applySchemaPatch(
|
|
1034
|
+
{
|
|
1035
|
+
items: [
|
|
1036
|
+
{ alias: 'X1' },
|
|
1037
|
+
{ alias: 'S1', definitionFormal: 'ℬ(X1×X1)' },
|
|
1038
|
+
{ alias: 'D1', definitionFormal: 'Pr2,1(S1)' },
|
|
1039
|
+
{ alias: 'D2', definitionFormal: 'S1\\D1' },
|
|
1040
|
+
{ alias: 'F1', definitionFormal: '[α∈X1] Pr2(Fi1[{α}](D2))' }
|
|
1041
|
+
]
|
|
1042
|
+
},
|
|
1043
|
+
sessionId
|
|
1044
|
+
);
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
it('normalizes unsorted structure values before evaluation', async () => {
|
|
1048
|
+
const tool = new RSToolAgent();
|
|
1049
|
+
const session = tool.createSession();
|
|
1050
|
+
buildGraphScratch(tool, session.sessionId);
|
|
1051
|
+
|
|
1052
|
+
await tool.setModelValues(
|
|
1053
|
+
{
|
|
1054
|
+
set: [
|
|
1055
|
+
{ target: 1, value: { 0: 'a', 1: 'b', 2: 'c' } },
|
|
1056
|
+
{
|
|
1057
|
+
target: 2,
|
|
1058
|
+
value: [
|
|
1059
|
+
[TUPLE_ID, 1, 2],
|
|
1060
|
+
[TUPLE_ID, 0, 2],
|
|
1061
|
+
[TUPLE_ID, 0, 1],
|
|
1062
|
+
[TUPLE_ID, 1, 0],
|
|
1063
|
+
[TUPLE_ID, 0, 1]
|
|
1064
|
+
]
|
|
1065
|
+
}
|
|
1066
|
+
]
|
|
1067
|
+
},
|
|
1068
|
+
session.sessionId
|
|
1069
|
+
);
|
|
1070
|
+
|
|
1071
|
+
const stored = tool.getModelState(session.sessionId).items.find(item => item.id === 2);
|
|
1072
|
+
expect(stored?.value).toEqual([
|
|
1073
|
+
[TUPLE_ID, 0, 1],
|
|
1074
|
+
[TUPLE_ID, 0, 2],
|
|
1075
|
+
[TUPLE_ID, 1, 0],
|
|
1076
|
+
[TUPLE_ID, 1, 2]
|
|
1077
|
+
]);
|
|
1078
|
+
|
|
1079
|
+
// S1 \ inverse(S1): (0,1) and (1,0) cancel out
|
|
1080
|
+
const result = tool.evaluate({ constituentId: 4 }, session.sessionId);
|
|
1081
|
+
expect(result.status).toBe(EvalStatus.HAS_DATA);
|
|
1082
|
+
expect(result.value).toEqual([
|
|
1083
|
+
[TUPLE_ID, 0, 2],
|
|
1084
|
+
[TUPLE_ID, 1, 2]
|
|
1085
|
+
]);
|
|
1086
|
+
});
|
|
1087
|
+
|
|
1088
|
+
it('evaluates scratch expressions that reference derived constituents', async () => {
|
|
1089
|
+
const tool = new RSToolAgent();
|
|
1090
|
+
const session = tool.createSession();
|
|
1091
|
+
buildGraphScratch(tool, session.sessionId);
|
|
1092
|
+
await tool.setModelValues(
|
|
1093
|
+
{
|
|
1094
|
+
set: [
|
|
1095
|
+
{ target: 1, value: { 0: 'a', 1: 'b', 2: 'c' } },
|
|
1096
|
+
{
|
|
1097
|
+
target: 2,
|
|
1098
|
+
value: [
|
|
1099
|
+
[TUPLE_ID, 0, 1],
|
|
1100
|
+
[TUPLE_ID, 0, 2],
|
|
1101
|
+
[TUPLE_ID, 1, 0],
|
|
1102
|
+
[TUPLE_ID, 1, 2]
|
|
1103
|
+
]
|
|
1104
|
+
}
|
|
1105
|
+
]
|
|
1106
|
+
},
|
|
1107
|
+
session.sessionId
|
|
1108
|
+
);
|
|
1109
|
+
|
|
1110
|
+
const direct = tool.evaluate({ expression: 'card(D2)', cstType: CstType.TERM }, session.sessionId);
|
|
1111
|
+
expect(direct.success).toBe(true);
|
|
1112
|
+
expect(direct.value).toBe(2);
|
|
1113
|
+
|
|
1114
|
+
// F1 body references D2, which must be computed before the call
|
|
1115
|
+
const viaFunction = tool.evaluate(
|
|
1116
|
+
{ expression: 'card(red(I{F1[ξ] | ξ:∈Pr1(D2)}))', cstType: CstType.TERM },
|
|
1117
|
+
session.sessionId
|
|
1118
|
+
);
|
|
1119
|
+
expect(viaFunction.success).toBe(true);
|
|
1120
|
+
expect(viaFunction.value).toBe(1);
|
|
1121
|
+
|
|
1122
|
+
const logic = tool.evaluate({ expression: 'D2⊆S1', cstType: CstType.AXIOM }, session.sessionId);
|
|
1123
|
+
expect(logic.success).toBe(true);
|
|
1124
|
+
expect(logic.value).toBe(1);
|
|
1125
|
+
});
|
|
1126
|
+
|
|
1032
1127
|
it('throws when evaluate input is incomplete', () => {
|
|
1033
1128
|
const tool = new RSToolAgent();
|
|
1034
1129
|
const session = tool.createSession();
|
|
@@ -5,14 +5,53 @@ import { describe, expect, it } from 'vitest';
|
|
|
5
5
|
import { CstType, EvalStatus, RSToolWrapperClient } from '../index';
|
|
6
6
|
|
|
7
7
|
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../..');
|
|
8
|
+
const tsxCli = fileURLToPath(import.meta.resolve('tsx/cli'));
|
|
9
|
+
const wrapperEntry = resolve(packageRoot, 'src/wrapper/stdio-wrapper.ts');
|
|
8
10
|
|
|
9
11
|
describe('RSToolWrapperClient integration', () => {
|
|
12
|
+
it('rejects readiness and calls when the wrapper command cannot start', async () => {
|
|
13
|
+
const client = new RSToolWrapperClient({
|
|
14
|
+
command: resolve(packageRoot, 'definitely-missing-rstool-wrapper-binary'),
|
|
15
|
+
args: [],
|
|
16
|
+
cwd: packageRoot
|
|
17
|
+
});
|
|
18
|
+
try {
|
|
19
|
+
await expect(client.waitUntilReady()).rejects.toThrow(/ENOENT/);
|
|
20
|
+
await expect(client.call('methods')).rejects.toThrow(/ENOENT/);
|
|
21
|
+
} finally {
|
|
22
|
+
await client.close();
|
|
23
|
+
}
|
|
24
|
+
}, 30_000);
|
|
25
|
+
|
|
26
|
+
it('rejects outstanding calls when the wrapper exits before responding', async () => {
|
|
27
|
+
const client = new RSToolWrapperClient({
|
|
28
|
+
command: process.execPath,
|
|
29
|
+
args: ['-e', 'process.stdin.resume(); setTimeout(() => process.exit(3), 200)'],
|
|
30
|
+
cwd: packageRoot
|
|
31
|
+
});
|
|
32
|
+
try {
|
|
33
|
+
await expect(client.call('methods')).rejects.toThrow(/exited before responding \(code 3/);
|
|
34
|
+
} finally {
|
|
35
|
+
await client.close();
|
|
36
|
+
}
|
|
37
|
+
}, 30_000);
|
|
38
|
+
|
|
39
|
+
it('starts the default npm wrapper without a shell', async () => {
|
|
40
|
+
const client = new RSToolWrapperClient({ cwd: packageRoot });
|
|
41
|
+
try {
|
|
42
|
+
await client.waitUntilReady();
|
|
43
|
+
const methods = await client.call<string[]>('methods');
|
|
44
|
+
expect(methods).toContain('applySchemaPatch');
|
|
45
|
+
} finally {
|
|
46
|
+
await client.close();
|
|
47
|
+
}
|
|
48
|
+
}, 30_000);
|
|
49
|
+
|
|
10
50
|
it('runs createSession, patch, model, and evaluate over stdio', async () => {
|
|
11
51
|
const client = new RSToolWrapperClient({
|
|
12
|
-
command:
|
|
13
|
-
args: [
|
|
14
|
-
cwd: packageRoot
|
|
15
|
-
shell: true
|
|
52
|
+
command: process.execPath,
|
|
53
|
+
args: [tsxCli, wrapperEntry],
|
|
54
|
+
cwd: packageRoot
|
|
16
55
|
});
|
|
17
56
|
|
|
18
57
|
try {
|