@rsconcept/rstool 1.7.1 → 2.0.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.
Files changed (126) hide show
  1. package/README.md +7 -7
  2. package/dist/index.js +1 -1
  3. package/dist/mappers/model-adapter.d.ts +6 -2
  4. package/dist/mappers/model-adapter.js +28 -3
  5. package/dist/mappers/model-adapter.js.map +1 -1
  6. package/dist/mappers/schema-adapter.d.ts +1 -2
  7. package/dist/mappers/schema-adapter.js +1 -1
  8. package/dist/mappers/types.d.ts +4 -5
  9. package/dist/models/index.js +1 -1
  10. package/dist/models/rstool-agent.js +1 -2
  11. package/dist/{models-DG2uTaV_.js → models-D06g8LId.js} +6 -5
  12. package/dist/{models-DG2uTaV_.js.map → models-D06g8LId.js.map} +1 -1
  13. package/dist/{rsform-builder-DKwZfJvN.js → rsform-builder-BlXEe5Ow.js} +2 -2
  14. package/dist/{rsform-builder-DKwZfJvN.js.map → rsform-builder-BlXEe5Ow.js.map} +1 -1
  15. package/dist/session/session-store.d.ts +3 -3
  16. package/dist/session/session-store.js +1 -2
  17. package/dist/wrapper/client.d.ts +15 -9
  18. package/dist/wrapper/client.js +79 -12
  19. package/dist/wrapper/client.js.map +1 -1
  20. package/dist/wrapper/stdio-wrapper.d.ts +1 -1
  21. package/dist/wrapper/stdio-wrapper.js +18 -10
  22. package/dist/wrapper/stdio-wrapper.js.map +1 -1
  23. package/docs/BRIEF.md +93 -0
  24. package/docs/CONCEPTUAL-SCHEMA.md +17 -2
  25. package/docs/CONSTRUCTIONS.md +384 -0
  26. package/docs/DIAGNOSTICS.md +9 -8
  27. package/docs/DOMAIN.md +12 -0
  28. package/docs/METHOD.md +208 -0
  29. package/docs/MODEL-TESTING.md +48 -0
  30. package/docs/PORTAL-API.md +38 -285
  31. package/docs/PORTAL-MODELS.md +24 -0
  32. package/docs/PORTAL-OSS.md +56 -0
  33. package/docs/PORTAL-PUBLISH.md +39 -0
  34. package/docs/PORTAL-READ.md +301 -0
  35. package/docs/README.md +8 -4
  36. package/docs/REQUIREMENTS.md +61 -0
  37. package/docs/SYNTAX.md +5 -4
  38. package/docs/TYPIFICATION.md +12 -3
  39. package/docs/brief.schema.json +173 -0
  40. package/examples/README.md +16 -2
  41. package/examples/access-control/NOTES.md +23 -0
  42. package/examples/access-control/anti/collapsed.json +439 -0
  43. package/examples/access-control/anti/weakened.json +439 -0
  44. package/examples/access-control/brief-v1.json +231 -0
  45. package/examples/access-control/brief.json +310 -0
  46. package/examples/access-control/build-rsform.ts +151 -0
  47. package/examples/access-control/requirements-v1.md +9 -0
  48. package/examples/access-control/requirements-v2.md +4 -0
  49. package/examples/access-control/rsform-session-v1.json +439 -0
  50. package/examples/access-control/rsform-session.json +523 -0
  51. package/examples/audit-diagnostics.ts +9 -1
  52. package/examples/briefs.test.ts +126 -0
  53. package/examples/clinic-booking/NOTES.md +24 -0
  54. package/examples/clinic-booking/anti/collapsed.json +615 -0
  55. package/examples/clinic-booking/anti/species-as-genus.json +568 -0
  56. package/examples/clinic-booking/brief-v1.json +332 -0
  57. package/examples/clinic-booking/brief.json +405 -0
  58. package/examples/clinic-booking/build-rsform.ts +174 -0
  59. package/examples/clinic-booking/requirements-v1.md +9 -0
  60. package/examples/clinic-booking/requirements-v2.md +4 -0
  61. package/examples/clinic-booking/rsform-session-v1.json +615 -0
  62. package/examples/clinic-booking/rsform-session.json +700 -0
  63. package/examples/diagnostics-utils.ts +26 -0
  64. package/examples/kinship/brief.json +337 -0
  65. package/examples/kinship/build-rsform.ts +7 -4
  66. package/examples/kinship/rsform-session.json +20 -63
  67. package/examples/kinship/rsmodel-session.json +14 -14
  68. package/examples/kinship-subordination/NOTES.md +49 -0
  69. package/examples/kinship-subordination/brief.json +161 -0
  70. package/examples/kinship-subordination/build-rsform.ts +100 -0
  71. package/examples/kinship-subordination/rsform-session.json +795 -0
  72. package/examples/library-loans/NOTES.md +46 -0
  73. package/examples/library-loans/anti/collapsed.json +481 -0
  74. package/examples/library-loans/anti/species-as-genus.json +334 -0
  75. package/examples/library-loans/anti/uncovered.json +406 -0
  76. package/examples/library-loans/anti/weakened.json +464 -0
  77. package/examples/library-loans/brief-v1.json +340 -0
  78. package/examples/library-loans/brief.json +502 -0
  79. package/examples/library-loans/build-rsform.ts +239 -0
  80. package/examples/library-loans/requirements-v1.md +11 -0
  81. package/examples/library-loans/requirements-v2.md +5 -0
  82. package/examples/library-loans/rsform-session-v1.json +481 -0
  83. package/examples/library-loans/rsform-session.json +652 -0
  84. package/examples/library-loans/source-markup.md +18 -0
  85. package/examples/movd/brief.json +220 -0
  86. package/examples/movd/build-rsform.ts +5 -2
  87. package/examples/movd/rsform-session.json +14 -46
  88. package/examples/subordination/NOTES.md +59 -0
  89. package/examples/subordination/anti/collapsed.json +556 -0
  90. package/examples/subordination/anti/single-relation.json +125 -0
  91. package/examples/subordination/anti/transitive.json +573 -0
  92. package/examples/subordination/anti/weakened.json +539 -0
  93. package/examples/subordination/brief.json +386 -0
  94. package/examples/subordination/build-rsform.ts +63 -0
  95. package/examples/subordination/constants.ts +115 -0
  96. package/examples/subordination/rsform-session.json +556 -0
  97. package/examples/subordination/source-markup.md +19 -0
  98. package/examples/subordination/source.md +40 -0
  99. package/package.json +29 -20
  100. package/skills/INSTALL.md +28 -29
  101. package/skills/README.md +25 -10
  102. package/skills/rs-core/SKILL.md +56 -0
  103. package/skills/rs-explain/SKILL.md +28 -0
  104. package/skills/rs-explicate/SKILL.md +71 -0
  105. package/skills/rs-interpret/SKILL.md +67 -0
  106. package/skills/rs-portal/SKILL.md +51 -0
  107. package/skills/rs-review/SKILL.md +79 -0
  108. package/skills/rs-scope/SKILL.md +67 -0
  109. package/skills/rs-synthesis/SKILL.md +52 -0
  110. package/skills/rstool/SKILL.md +70 -0
  111. package/skills/rstool-helper/GUIDE.md +18 -272
  112. package/skills/rstool-helper/SKILL.md +8 -55
  113. package/skills/{rstool-helper → rstool-runtime}/EXAMPLES.md +40 -12
  114. package/skills/{rstool-helper → rstool-runtime}/REFERENCE.md +28 -7
  115. package/skills/rstool-runtime/SKILL.md +96 -0
  116. package/skills/scripts/brief-check.test.ts +165 -0
  117. package/skills/scripts/brief-check.ts +826 -0
  118. package/skills/scripts/check-brief.ts +94 -0
  119. package/skills/scripts/rstool-skills.mjs +119 -0
  120. package/skills/scripts/skill-stubs.test.ts +48 -0
  121. package/src/mappers/model-adapter.ts +34 -1
  122. package/src/models/rstool-agent.test.ts +95 -0
  123. package/src/wrapper/client.test.ts +43 -4
  124. package/src/wrapper/client.ts +95 -16
  125. package/src/wrapper/stdio-handler.test.ts +43 -0
  126. package/src/wrapper/stdio-handler.ts +19 -5
@@ -1,19 +1,21 @@
1
1
  # ЯРЭ и rstool — примеры
2
2
 
3
- Короткие фрагменты для агентов. Воркфлоу — [GUIDE.md](GUIDE.md). Контракт — [REFERENCE.md](REFERENCE.md).
3
+ Короткие фрагменты для агентов. Запуск и правила — [SKILL.md](SKILL.md); этапы работы — [../rstool/SKILL.md](../rstool/SKILL.md). Контракт — [REFERENCE.md](REFERENCE.md).
4
4
 
5
5
  ## Индекс runnable `examples/`
6
6
 
7
7
  Полные сценарии пакета:
8
8
 
9
- | Тема | Паттерн | Смотри |
10
- | ----------------------------------------------------- | ------------------------------------ | ------------------------------------------------- |
11
- | [`sample/`](../../examples/sample/) | Минимальная КС + КМ | `X1`, `C1`, `S1`, `D1`, `A1` |
12
- | [`kinship/`](../../examples/kinship/) | Предметная схема, модель, CLI | отношения на `X1`, правки интерпретации |
13
- | [`chocolate-nim/`](../../examples/chocolate-nim/) | Математика на `Z` без `X#` | [BASE-SELECTION.md](../../docs/BASE-SELECTION.md) |
14
- | [`movd/`](../../examples/movd/) | Сложные `S#`, мультипроекции, `Fi` | фильтры и проекции |
15
- | [`expression-bank/`](../../examples/expression-bank/) | Шаблоны на радикалах `R#` | [SYNTAX.md](../../docs/SYNTAX.md) «Радикалы» |
16
- | [`template-apply/`](../../examples/template-apply/) | Подстановка `R#` → предметные домены | применение шаблонов |
9
+ | Тема | Паттерн | Смотри |
10
+ | ----------------------------------------------------------------- | ------------------------------------ | ------------------------------------------------- |
11
+ | [`sample/`](../../examples/sample/) | Минимальная КС + КМ | `X1`, `C1`, `S1`, `D1`, `A1` |
12
+ | [`kinship/`](../../examples/kinship/) | Предметная схема, модель, CLI | отношения на `X1`, правки интерпретации |
13
+ | [`chocolate-nim/`](../../examples/chocolate-nim/) | Математика на `Z` без `X#` | [BASE-SELECTION.md](../../docs/BASE-SELECTION.md) |
14
+ | [`movd/`](../../examples/movd/) | Сложные `S#`, мультипроекции, `Fi` | фильтры и проекции |
15
+ | [`expression-bank/`](../../examples/expression-bank/) | Шаблоны на радикалах `R#` | [SYNTAX.md](../../docs/SYNTAX.md) «Радикалы» |
16
+ | [`template-apply/`](../../examples/template-apply/) | Подстановка `R#` → предметные домены | применение шаблонов |
17
+ | [`subordination/`](../../examples/subordination/) | Метод по этапам, бриф, антипримеры | [METHOD.md](../../docs/METHOD.md) |
18
+ | [`kinship-subordination/`](../../examples/kinship-subordination/) | Синтез микротеорий | [rs-synthesis](../rs-synthesis/SKILL.md) |
17
19
 
18
20
  Запуск и структура папок — [examples/README.md](../../examples/README.md).
19
21
 
@@ -152,12 +154,15 @@ tool.applySchemaPatch({
152
154
  | `arithmeticNotSupported` / `orderingNotSupported` | `ξ+1` или `α<β` при `ξ∈X1` | `Z` или `C#` ([BASE-SELECTION.md](../../docs/BASE-SELECTION.md)) |
153
155
  | `globalFuncParenCall` | `F1(ξ)` | `F1[ξ]` |
154
156
  | `globalFuncWithoutArgs` | голое `F1` в формуле | `F1[…]` |
157
+ | `globalDeleted` | `X1∪DEL` — ссылка на удаленную конституенту | подставь действующее обозначение |
155
158
  | `radicalUsage` | `R1` в теле формулы или как конституента | `R#` только в `[…]` у `F#`/`P#` |
159
+ | `invalidPropertyUsage` | `∀σ∈ℬ(S1)\{∅} ¬P1[σ]` — квантор по булеану | вычислимая форма через достижимость: `∀α∈X1 α∉F4[α]` |
156
160
  | `schemaMissingConvention` | `X1` без конвенции | добавь предметную конвенцию |
157
161
  | `schemaHomonym` | одинаковый термин у разных конституент | различай термины |
158
162
  | `schemaDependencyCycle` | круг в определениях (`F3 → P1 → F3`) | разорви цикл: убери взаимные ссылки |
159
163
  | `localOutOfScopeParentheses` | `∀a∈S P(a) & Q(a)` | `∀a∈S (P(a) & Q(a))` |
160
164
  | `invalidFilterSyntax` | кривой `Fi` | `Fi1[{ξ}](S1)` / `Fi1,2[D1,D2](S1)` |
165
+ | стиль: `card(S) > 0` / `card(S) = 0` | проверка (не)пустоты через мощность | `S ≠ ∅` / `S = ∅` / `A ∩ B ≠ ∅` |
161
166
 
162
167
  ```ts
163
168
  const analysis = tool.analyzeExpression({
@@ -237,6 +242,29 @@ const scratch = tool.evaluate({ expression: '1+2', cstType: CstType.TERM });
237
242
  const recalc = tool.recalculateModel();
238
243
  ```
239
244
 
245
+ Множества `S#` — кортежи `[TUPLE_ID, i, j]` по индексам `X#`; порядок во входе не важен (нормализуется). Scratch может ссылаться на производные конституенты; логические выражения — с `cstType: CstType.AXIOM`:
246
+
247
+ ```ts
248
+ import { EvalStatus, TUPLE_ID } from '@rsconcept/domain';
249
+
250
+ await tool.setModelValues({
251
+ set: [
252
+ { target: 1, value: { 0: 'a', 1: 'b', 2: 'c' } },
253
+ {
254
+ target: 2,
255
+ value: [
256
+ [TUPLE_ID, 1, 2],
257
+ [TUPLE_ID, 0, 1]
258
+ ]
259
+ } // S1: ℬ(X1×X1)
260
+ ]
261
+ });
262
+ const closure = tool.evaluate({ constituentId: 9 }); // D9 — транзитивное замыкание
263
+ closure.status === EvalStatus.HAS_DATA; // status — число: 7
264
+ const check = tool.evaluate({ expression: 'S1⊆D9', cstType: CstType.AXIOM });
265
+ check.value === 1;
266
+ ```
267
+
240
268
  ## Экспорт / импорт и Portal round-trip
241
269
 
242
270
  ```ts
@@ -246,14 +274,14 @@ const restored = tool.importData(payload, 'session');
246
274
  const schemaJson = tool.exportPortal({ kind: 'schema' });
247
275
  const modelObj = tool.exportPortal({ kind: 'model', format: 'object' });
248
276
 
249
- // Portal GET /api/rsforms/:id/details → строка или объект
277
+ // Portal JSON: GET /api/agents/rsforms/:id/details (Bearer key), same shape as public /details
250
278
  const session = tool.importData(portalDetailsJsonString); // kind auto
251
279
  tool.listDiagnostics();
252
280
  // правки…
253
281
  const forPortal = tool.exportPortal({ kind: 'schema' });
254
282
  ```
255
283
 
256
- Не передавай `/details` с `kind: 'session'`. REST и curl — [PORTAL-API.md](../../docs/PORTAL-API.md).
284
+ Не передавай `/details` с `kind: 'session'`. REST и curl — [PORTAL-READ.md](../../docs/PORTAL-READ.md).
257
285
 
258
286
  ## Встраивание схемы (синтез)
259
287
 
@@ -282,7 +310,7 @@ tool.synthesize({
282
310
 
283
311
  ## Образец текста ревью (не код)
284
312
 
285
- После [воркфлоу ревью](GUIDE.md#ревью--оценка-готовой-кс) ответ может выглядеть так:
313
+ После [ревью](../rs-review/SKILL.md) ответ может выглядеть так:
286
314
 
287
315
  > **Вердикт:** схема покрывает роли и отношение подчинения; главный риск — вычисляемая «степень» задана графиком пар вместо терм-функции.
288
316
  >
@@ -1,6 +1,6 @@
1
1
  # ЯРЭ и rstool — справочник
2
2
 
3
- Контракт library / stdio / MCP для агентов. Воркфлоу — [GUIDE.md](GUIDE.md). Примеры — [EXAMPLES.md](EXAMPLES.md). Язык — `docs/*.md`.
3
+ Контракт library / stdio / MCP для агентов. Запуск и правила — [SKILL.md](SKILL.md); этапы работы — [../rstool/SKILL.md](../rstool/SKILL.md). Примеры — [EXAMPLES.md](EXAMPLES.md). Язык — `docs/*.md`.
4
4
 
5
5
  ## Контракт rstool
6
6
 
@@ -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`. Как ранжировать в отчёте — [rs-review](../rs-review/SKILL.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` — статус вычисления КМ (`HAS_DATA`, `EMPTY`, `AXIOM_FALSE`, `EVAL_FAIL`, … — [DOMAIN.md](../../docs/DOMAIN.md)).
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
 
@@ -206,7 +223,7 @@ tool.synthesize({
206
223
 
207
224
  ### `importData(payload, kind?)`
208
225
 
209
- `kind`: `'auto'` (default), `'session'`, `'portal-details'` (`GET /api/rsforms/:id/details`), `'portal-schema'` (Portal Load from JSON). После импорта новая сессия становится текущей. Возвращает `SessionHandle`.
226
+ `kind`: `'auto'` (default), `'session'`, `'portal-details'` (JSON of `GET /api/agents/rsforms/:id/details` or public `GET /api/rsforms/:id/details`), `'portal-schema'` (Portal Load from JSON). После импорта новая сессия становится текущей. Возвращает `SessionHandle`.
210
227
 
211
228
  Portal JSON из `/details` **не** является `exportSession` — не передавай его с `kind: 'session'`.
212
229
 
@@ -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,14 +263,17 @@ 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) |
251
270
  | Поля и валидация конституенты | [CONSTITUENTA.md](../../docs/CONSTITUENTA.md) |
252
271
  | Формы значений КМ, тесты | [MODEL-TESTING.md](../../docs/MODEL-TESTING.md) |
253
- | Ссылка Portal, REST, curl | [PORTAL-API.md](../../docs/PORTAL-API.md) |
272
+ | Ссылка Portal, REST, curl | [PORTAL-READ.md](../../docs/PORTAL-READ.md) |
254
273
  | Термины, статусы, «не путать» | [DOMAIN.md](../../docs/DOMAIN.md) |
255
- | Воркфлоу агента | [GUIDE.md](GUIDE.md) |
274
+ | Бриф, сценарии, `check-brief` | [BRIEF.md](../../docs/BRIEF.md) |
275
+ | Метод: этапы и гейты | [METHOD.md](../../docs/METHOD.md) |
276
+ | Этапы работы, маршрут | [../rstool/SKILL.md](../rstool/SKILL.md) |
256
277
  | Сниппеты и антипаттерны | [EXAMPLES.md](EXAMPLES.md) |
257
278
 
258
279
  Исходники кодов ошибок ЯРЭ: `@rsconcept/domain` (`RSErrorCode`, `error.ts`). Не дублируй грамматику в skill — правь domain и при необходимости этот help map.
@@ -0,0 +1,96 @@
1
+ ---
2
+ name: rstool-runtime
3
+ description: >-
4
+ Как вызывать rstool: библиотека RSToolAgent, stdio-обёртка, MCP. Быстрый
5
+ контракт, запуск скриптов вне пакета, сохранение сессий, кодировки Windows,
6
+ словарь «API → текст для пользователя».
7
+ ---
8
+
9
+ # rstool · запуск и контракт
10
+
11
+ Пути — от `<rstool>`. Полный контракт — [REFERENCE.md](REFERENCE.md); сниппеты и антипаттерны — [EXAMPLES.md](EXAMPLES.md).
12
+
13
+ ## Быстрый контракт
14
+
15
+ - Библиотека: `@rsconcept/rstool`, класс `RSToolAgent`. Анализатор — `@rsconcept/domain`.
16
+ - Правка схемы — только `applySchemaPatch({ items, mode?, commitMessage? })`. `id` и `cstType` выводятся из префикса имени (`X/C/S/D/F/P/A/T/N`); пачка упорядочивается сама. `mode: 'atomic'` (по умолчанию) откатывает всё при первой ошибке; `'best_effort'` применяет корректное — после него `failed` должен стать пустым.
17
+ - Черновик формулы — `analyzeExpression({ expression, cstType })` без сохранения.
18
+ - Диагностики — `listDiagnostics({ kind?, severity? })`; `analysisSuccess: true` в summary не означает их отсутствия.
19
+ - Состояние — `getSessionState()` (summary) или `getSessionState('full')`.
20
+ - Модель — `await setModelValues(...)`, `evaluate`, `recalculateModel`; `status` — число (`EvalStatus`). Для проверки смысла по брифу удобнее сценарии и `check-brief` (`docs/BRIEF.md`).
21
+ - Синтез (встраивание) — `synthesize({ sourceSessionId, substitutions })`; имена источника перенумеровываются (`aliasMapping` в ответе).
22
+ - Импорт / экспорт — `importData(payload, kind?)` (`auto` различает сессию и JSON Portal), `exportSession()`, `exportPortal({ kind: 'schema' })`.
23
+ - Stdio (`npx rstool-wrapper`) и MCP (`@rsconcept/rstool-mcp`, имена в `snake_case`): **плоские** `params` — поля метода и `sessionId` на одном уровне.
24
+
25
+ ## Запуск скрипта вне пакета
26
+
27
+ Разовые скрипты, сессии, бриф и экспорт — в папке задачи, **не** в `<rstool>`.
28
+
29
+ **В workspace Portal** (после `pnpm install` и сборки `@rsconcept/domain`):
30
+
31
+ ```bash
32
+ pnpm --filter @rsconcept/rstool exec tsx <abs>/task/build.mts
33
+ ```
34
+
35
+ - Импорт по абсолютному `file://` URL: `import { RSToolAgent } from 'file:///<workspace>/rsconcept/rstool/src/index.ts'`. Обычный `'@rsconcept/rstool'` из файла вне пакета не резолвится; на Windows путь без `file://` падает (`ERR_UNSUPPORTED_ESM_URL_SCHEME`).
36
+ - Расширение **`.mts`**: `.ts` вне пакета считается CommonJS, а `@rsconcept/*` — только ESM.
37
+ - Helpers domain — тем же способом: `file:///…/rsconcept/domain/src/index.ts` (`TUPLE_ID`, `EvalStatus`), `…/domain/src/rslang/labels.ts` (`labelType`).
38
+
39
+ **В npm-проекте:** `npx tsx task/build.mts` с обычным `import { RSToolAgent } from '@rsconcept/rstool'`.
40
+
41
+ Альтернатива без резолвинга — stdio из собранного `dist`: `new RSToolWrapperClient({ command: 'node', args: ['<abs>/rsconcept/rstool/dist/wrapper/stdio-wrapper.js'] })`.
42
+
43
+ ```ts
44
+ import { readFileSync, writeFileSync } from 'node:fs';
45
+ import { RSToolAgent } from 'file:///<workspace>/rsconcept/rstool/src/index.ts';
46
+
47
+ const tool = new RSToolAgent();
48
+ tool.importData(readFileSync('<abs>/task/session.json', 'utf-8'));
49
+ console.log(tool.listDiagnostics());
50
+ writeFileSync('<abs>/task/session.json', tool.exportSession(), 'utf-8');
51
+ ```
52
+
53
+ **Проверка брифа** — `skills/scripts/check-brief.ts` запускается из пакета, не копируется: `pnpm --filter @rsconcept/rstool exec tsx skills/scripts/check-brief.ts --session <abs> --brief <abs>` (npm: `npx tsx node_modules/@rsconcept/rstool/skills/scripts/check-brief.ts …`).
54
+
55
+ ## Сохранение сессий
56
+
57
+ Сессии живут в памяти процесса. Между запусками скрипта сохраняй `exportSession()` в файл и загружай `importData`. `new RSToolAgent({ persistenceDir })` (stdio / MCP: `RSTOOL_PERSISTENCE_DIR`) сохраняет сессии автоматически.
58
+
59
+ ## Windows и кодировки
60
+
61
+ - Консоль часто в cp1251: символы ЯРЭ в выводе ломаются. Пиши результаты в файл UTF-8; в PowerShell — `-Encoding utf8`.
62
+ - JSON — UTF-8 без экранирования Unicode (`ensure_ascii=False` в Python). Логи в `print` — ASCII.
63
+ - В PowerShell вызывай `curl.exe`, а не alias `curl`.
64
+
65
+ ## Язык ответа
66
+
67
+ С пользователем — термины предметной области, не имена API. Идентификаторы уместны только в коде, патчах и JSON.
68
+
69
+ | В API | В тексте ответа |
70
+ | :-------------------------------- | :---------------------------------- |
71
+ | `alias` | имя конституенты |
72
+ | `cstType` | тип конституенты |
73
+ | `definitionFormal` | формальное определение (формула) |
74
+ | `term` | термин |
75
+ | `definitionText` | текстовое определение |
76
+ | `convention` | конвенция |
77
+ | `applySchemaPatch` | правка схемы |
78
+ | `synthesize` | встраивание / синтез схем |
79
+ | `analyzeExpression` | проверка / анализ выражения |
80
+ | `listDiagnostics`, `diagnostics` | диагностики |
81
+ | `setModelValues`, `getModelState` | интерпретация, значения модели |
82
+ | `evaluate`, `recalculateModel` | вычисление, пересчёт модели |
83
+ | `commitStep`, `commitMessage` | фиксация шага (ревизия) |
84
+ | `exportSession` / `exportPortal` | экспорт сессии / экспорт для Portal |
85
+ | `importData` | импорт данных |
86
+ | session, `sessionId` | сессия |
87
+ | brief, `check-brief` | бриф, проверка по брифу |
88
+
89
+ Имена конституент (`X1`, `D3`) и формулы — часть схемы, приводи как есть, лучше с термином. Термины КС — `docs/DOMAIN.md` «Термины: не путать».
90
+
91
+ ## Не делай
92
+
93
+ - Не клади разовые скрипты и снимки в `<rstool>` и `examples/`.
94
+ - Не передавай JSON `/details` Portal с `kind: 'session'`.
95
+ - Не повторяй вызов без изменения ввода.
96
+ - Не задавай значения производным понятиям — только `X#`, `C#`, `S#`.
@@ -0,0 +1,165 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { RSToolAgent } from '../../src';
4
+
5
+ import { type Brief, checkBrief } from './brief-check';
6
+
7
+ function buildSession(overrides: Record<string, { definitionFormal?: string; cstType?: string }> = {}): string {
8
+ const tool = new RSToolAgent();
9
+ tool.createSession({ title: 'Выдачи' });
10
+ const items = [
11
+ { alias: 'X1', term: 'читатели', convention: 'Читатели библиотеки.' },
12
+ { alias: 'X2', term: 'экземпляры', convention: 'Экземпляры книг в фонде.' },
13
+ {
14
+ alias: 'S1',
15
+ term: 'выдачи',
16
+ definitionFormal: 'ℬ(X1×X2×Z)',
17
+ convention: 'Тройка (читатель, экземпляр, срок в днях).'
18
+ },
19
+ { alias: 'D1', term: 'выданные экземпляры', definitionFormal: 'Pr2(S1)' },
20
+ { alias: 'D2', term: 'доступные экземпляры', definitionFormal: 'X2\\D1' },
21
+ { alias: 'F1', term: 'экземпляры читателя', definitionFormal: '[ξ∈X1] Pr2(Fi1[{ξ}](S1))' },
22
+ { alias: 'P1', term: 'должник', definitionFormal: '[ξ∈X1] F1[ξ]≠∅' },
23
+ { alias: 'A1', term: 'экземпляр выдан одному', definitionFormal: 'card(Pr2(S1))=card(S1)' }
24
+ ].map(item => ({ ...item, ...overrides[item.alias] }));
25
+ tool.applySchemaPatch({ items: items as Parameters<RSToolAgent['applySchemaPatch']>[0]['items'] });
26
+ return tool.exportSession();
27
+ }
28
+
29
+ const BRIEF: Brief = {
30
+ version: 1,
31
+ status: 'confirmed',
32
+ approach: 'project',
33
+ object: 'Выдача книг',
34
+ task: 'Проверка выдач',
35
+ expressiveness: [
36
+ { id: 'E1', concept: 'выданный экземпляр', via: 'Pr2 выдач', constituent: 'D1' },
37
+ { id: 'E2', concept: 'доступный экземпляр', via: 'дополнение E1', constituent: 'D2' },
38
+ { id: 'E3', concept: 'экземпляры читателя', via: 'фильтр выдач', constituent: 'F1' }
39
+ ],
40
+ distinctions: [{ id: 'V1', between: ['E1', 'E2'], witness: 'SC1' }],
41
+ invariants: [{ id: 'I1', text: 'Экземпляр не выдан дважды', constituent: 'A1', positive: 'SC1', negative: 'SC2' }],
42
+ decisions: [{ id: 'DC1', topic: 'выдача', choice: 'читатель × экземпляр × срок', rationale: 'срок нужен' }],
43
+ scenarios: [
44
+ {
45
+ id: 'SC1',
46
+ title: 'Обычные выдачи',
47
+ values: {
48
+ X1: ['ann', 'bob'],
49
+ X2: ['e1', 'e2', 'e3'],
50
+ S1: [
51
+ ['ann', 'e1', 3],
52
+ ['bob', 'e2', 5]
53
+ ]
54
+ },
55
+ expect: [
56
+ { of: 'D1', value: ['e1', 'e2'] },
57
+ { of: 'D2', contains: ['e3'], excludes: ['e1'] },
58
+ { of: 'F1', args: ['ann'], value: ['e1'] },
59
+ { of: 'P1', args: ['bob'], holds: true },
60
+ { of: 'A1', holds: true },
61
+ { expr: 'card(D1)', value: 2 }
62
+ ]
63
+ },
64
+ {
65
+ id: 'SC2',
66
+ title: 'Двойная выдача',
67
+ base: 'SC1',
68
+ values: {
69
+ S1: [
70
+ ['ann', 'e1', 3],
71
+ ['bob', 'e1', 4]
72
+ ]
73
+ },
74
+ expect: [{ of: 'A1', holds: false }]
75
+ }
76
+ ]
77
+ };
78
+
79
+ describe('checkBrief', () => {
80
+ it('passes a schema that answers the brief', async () => {
81
+ const { readiness, scenarios } = await checkBrief({ session: buildSession(), brief: BRIEF });
82
+ expect(scenarios.flatMap(item => item.checks.filter(check => !check.passed))).toEqual([]);
83
+ expect(readiness.blockers).toEqual([]);
84
+ expect(readiness.ready).toBe(true);
85
+ expect(readiness.stage).toBe('review');
86
+ expect(readiness.coverage).toEqual({ expressiveness: '3/3', invariants: '1/1', distinctions: '1/1' });
87
+ });
88
+
89
+ it('reports a failed expectation with labels', async () => {
90
+ const session = buildSession({ D2: { definitionFormal: 'X2' } });
91
+ const { readiness, scenarios } = await checkBrief({ session, brief: BRIEF });
92
+ const failed = scenarios[0].checks.find(check => !check.passed);
93
+ expect(failed?.target).toBe('D2');
94
+ expect(failed?.actual).toBe('["e1","e2","e3"]');
95
+ expect(readiness.stage).toBe('interpret');
96
+ });
97
+
98
+ it('reports uncovered requirements and missing reasoning', async () => {
99
+ const brief: Brief = {
100
+ ...BRIEF,
101
+ status: 'draft',
102
+ expressiveness: [...BRIEF.expressiveness, { id: 'E4', concept: 'просроченная выдача', constituent: null }]
103
+ };
104
+ const { readiness } = await checkBrief({ session: buildSession(), brief });
105
+ expect(readiness.stage).toBe('scope');
106
+ expect(readiness.coverage.expressiveness).toBe('3/4');
107
+ expect(readiness.blockers.some(item => item.startsWith('E4'))).toBe(true);
108
+ });
109
+
110
+ it('detects a collapsed distinction', async () => {
111
+ const session = buildSession({ D2: { definitionFormal: 'Pr2(S1)' } });
112
+ const { readiness } = await checkBrief({
113
+ session,
114
+ brief: { ...BRIEF, approach: 'research', scenarios: [BRIEF.scenarios![1]] }
115
+ });
116
+ expect(readiness.blockers.some(item => item.startsWith('V1'))).toBe(true);
117
+ });
118
+
119
+ it('detects weakening against the base version', async () => {
120
+ const base = buildSession();
121
+ const session = buildSession({
122
+ A1: { definitionFormal: 'S1=S1' },
123
+ D1: { cstType: 'structure', definitionFormal: 'ℬ(X2)' }
124
+ });
125
+ const { readiness } = await checkBrief({ session, base, brief: { ...BRIEF, scenarios: [] } });
126
+ expect(readiness.blockers.some(item => item.startsWith('A1: формула стала тривиальной'))).toBe(true);
127
+ expect(readiness.blockers.some(item => item.startsWith('D1: производное понятие стало неопределяемым'))).toBe(true);
128
+ });
129
+
130
+ it('reports orphans for project schemas', async () => {
131
+ const tool = new RSToolAgent();
132
+ tool.importData(buildSession(), 'session');
133
+ tool.applySchemaPatch({ items: [{ alias: 'D3', term: 'лишнее', definitionFormal: 'X1×X2' }] });
134
+ const { readiness } = await checkBrief({ session: tool.exportSession(), brief: BRIEF });
135
+ expect(readiness.blockers.some(item => item.includes('D3'))).toBe(true);
136
+ });
137
+
138
+ it('flags an axiom that is false on an admissible scenario', async () => {
139
+ const tool = new RSToolAgent();
140
+ tool.importData(buildSession(), 'session');
141
+ tool.applySchemaPatch({ items: [{ alias: 'A2', term: 'один читатель', definitionFormal: 'card(Pr1(S1))≤1' }] });
142
+ const { readiness, scenarios } = await checkBrief({ session: tool.exportSession(), brief: BRIEF });
143
+ expect(scenarios[0].checks.some(check => check.target === 'A2 (допустимый сценарий)')).toBe(true);
144
+ expect(scenarios[1].checks.some(check => check.target.startsWith('A2'))).toBe(false);
145
+ expect(readiness.ready).toBe(false);
146
+ });
147
+
148
+ it('compares functions by their graphs in distinctions', async () => {
149
+ const tool = new RSToolAgent();
150
+ tool.importData(buildSession(), 'session');
151
+ tool.applySchemaPatch({ items: [{ alias: 'F2', term: 'то же', definitionFormal: '[ξ∈X1] Pr2(Fi1[{ξ}](S1))' }] });
152
+ const brief: Brief = { ...BRIEF, approach: 'research', distinctions: [{ id: 'V2', between: ['F1', 'F2'] }] };
153
+ const { readiness } = await checkBrief({ session: tool.exportSession(), brief });
154
+ expect(readiness.blockers.some(item => item.startsWith('V2: F1 и F2 совпадают'))).toBe(true);
155
+ });
156
+
157
+ it('warns when conventions cite brief decisions', async () => {
158
+ const tool = new RSToolAgent();
159
+ tool.importData(buildSession(), 'session');
160
+ tool.applySchemaPatch({ items: [{ alias: 'X2', convention: 'Экземпляры книг (решение DC1).' }] });
161
+ const { readiness } = await checkBrief({ session: tool.exportSession(), brief: BRIEF });
162
+ expect(readiness.warnings.some(item => item.includes('(DC#): X2'))).toBe(true);
163
+ expect(readiness.warnings.some(item => item.startsWith('Описание схемы пусто'))).toBe(true);
164
+ });
165
+ });