@rsconcept/rstool 0.10.3 → 1.0.1

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 (116) hide show
  1. package/README.md +61 -33
  2. package/dist/agent-workflow-Gk0Vfnv1.d.ts +64 -0
  3. package/dist/analysis-LLnPhmGa.d.ts +23 -0
  4. package/dist/{common-DxLg3eXX.d.ts → common-DHJalS-Q.d.ts} +6 -1
  5. package/dist/constituenta-DnGR6bnM.d.ts +54 -0
  6. package/dist/diagnostic-D9yl_mEL.d.ts +19 -0
  7. package/dist/evaluation-Cns8BFm4.d.ts +31 -0
  8. package/dist/index.d.ts +11 -11
  9. package/dist/index.js +1 -2
  10. package/dist/mappers/model-adapter.d.ts +3 -3
  11. package/dist/mappers/schema-adapter.d.ts +4 -4
  12. package/dist/mappers/types.d.ts +6 -2
  13. package/dist/mappers/types.js +2 -0
  14. package/dist/mappers/types.js.map +1 -1
  15. package/dist/{model-value-SFAVj0dw.d.ts → model-value-BbonPzMz.d.ts} +14 -3
  16. package/dist/models/agent-workflow.d.ts +2 -0
  17. package/dist/models/agent-workflow.js +1 -0
  18. package/dist/models/analysis.d.ts +1 -1
  19. package/dist/models/common.d.ts +1 -1
  20. package/dist/models/constituenta.d.ts +2 -2
  21. package/dist/models/diagnostic.d.ts +1 -1
  22. package/dist/models/evaluation.d.ts +2 -2
  23. package/dist/models/index.d.ts +11 -11
  24. package/dist/models/index.js +2 -2
  25. package/dist/models/model-value.d.ts +2 -2
  26. package/dist/models/rstool-agent.d.ts +1 -1
  27. package/dist/models/rstool-agent.js +1 -1
  28. package/dist/models/session.d.ts +1 -1
  29. package/dist/models/tool-contract.d.ts +2 -2
  30. package/dist/models/tool-contract.js +2 -1
  31. package/dist/models/tool-contract.js.map +1 -1
  32. package/dist/models-Bw6Uum8i.js +685 -0
  33. package/dist/models-Bw6Uum8i.js.map +1 -0
  34. package/dist/rstool-agent-D2cQze_b.d.ts +71 -0
  35. package/dist/session/session-store.d.ts +18 -5
  36. package/dist/session/session-store.js +1 -64
  37. package/dist/{session-BPgsE80c.d.ts → session-ChexW8i7.d.ts} +11 -8
  38. package/dist/tool-contract-0uRGhEfW.d.ts +164 -0
  39. package/dist/wrapper/client.d.ts +23 -0
  40. package/dist/wrapper/client.js +17 -0
  41. package/dist/wrapper/client.js.map +1 -1
  42. package/dist/wrapper/stdio-wrapper.js +75 -63
  43. package/dist/wrapper/stdio-wrapper.js.map +1 -1
  44. package/docs/CONSTITUENTA.md +2 -2
  45. package/docs/DIAGNOSTICS.md +6 -5
  46. package/docs/MODEL-TESTING.md +3 -3
  47. package/docs/PORTAL-API.md +24 -18
  48. package/examples/README.md +1 -1
  49. package/examples/agent-client.ts +11 -41
  50. package/examples/build-chocolate-nim-rsform.ts +21 -70
  51. package/examples/chocolate-nim/build-rsform.ts +23 -18
  52. package/examples/chocolate-nim/build-rsmodel.ts +10 -12
  53. package/examples/chocolate-nim/rsform-session.json +290 -290
  54. package/examples/chocolate-nim/rsmodel-session.json +291 -291
  55. package/examples/expression-bank/bank-constituents.ts +304 -53
  56. package/examples/expression-bank/build-rsform.ts +19 -16
  57. package/examples/expression-bank/rsform-session.json +1551 -1551
  58. package/examples/kinship/build-rsform.ts +23 -18
  59. package/examples/kinship/build-rsmodel.ts +16 -16
  60. package/examples/kinship/rsform-session.json +219 -219
  61. package/examples/kinship/rsmodel-session.json +221 -221
  62. package/examples/kinship/session.ts +19 -21
  63. package/examples/movd/build-rsform.ts +23 -18
  64. package/examples/movd/build-rsmodel.ts +18 -20
  65. package/examples/movd/rsform-session.json +262 -262
  66. package/examples/movd/rsmodel-session.json +264 -264
  67. package/examples/sample/build-rsform.ts +18 -51
  68. package/examples/sample/build-rsmodel.ts +25 -44
  69. package/examples/sample/rsform-session.json +10 -7
  70. package/examples/sample/rsmodel-session.json +36 -33
  71. package/examples/template-apply/build-rsform.ts +27 -24
  72. package/examples/template-apply/rsform-session.json +48 -48
  73. package/package.json +4 -2
  74. package/skills/rstool-helper/EXAMPLES.md +44 -116
  75. package/skills/rstool-helper/GUIDE.md +40 -25
  76. package/skills/rstool-helper/REFERENCE.md +40 -177
  77. package/src/index.ts +24 -17
  78. package/src/mappers/portal-adapter.ts +49 -0
  79. package/src/mappers/types.ts +4 -0
  80. package/src/models/agent-workflow.ts +66 -0
  81. package/src/models/analysis.ts +7 -0
  82. package/src/models/common.ts +7 -0
  83. package/src/models/constituenta.ts +24 -6
  84. package/src/models/diagnostic.ts +4 -0
  85. package/src/models/evaluation.ts +11 -0
  86. package/src/models/import-detect.test.ts +66 -0
  87. package/src/models/import-detect.ts +42 -0
  88. package/src/models/import-export.ts +24 -0
  89. package/src/models/index.ts +22 -14
  90. package/src/models/model-value.ts +12 -0
  91. package/src/models/portal-json.test.ts +38 -0
  92. package/src/models/portal-json.ts +54 -1
  93. package/src/models/rstool-agent.test.ts +698 -146
  94. package/src/models/rstool-agent.ts +392 -92
  95. package/src/models/session.ts +8 -5
  96. package/src/models/tool-contract.ts +81 -42
  97. package/src/session/batch-apply.test.ts +123 -0
  98. package/src/session/batch-apply.ts +82 -0
  99. package/src/session/persistence.test.ts +63 -0
  100. package/src/session/persistence.ts +69 -0
  101. package/src/session/session-store.ts +76 -6
  102. package/src/wrapper/client.test.ts +58 -0
  103. package/src/wrapper/client.ts +23 -0
  104. package/src/wrapper/stdio-handler.test.ts +101 -0
  105. package/src/wrapper/stdio-handler.ts +195 -0
  106. package/src/wrapper/stdio-wrapper.ts +4 -187
  107. package/dist/analysis-JiwOYDKx.d.ts +0 -16
  108. package/dist/constituenta-Dnd6iToB.d.ts +0 -36
  109. package/dist/diagnostic-BMYvciz8.d.ts +0 -15
  110. package/dist/evaluation-CCVYH0wA.d.ts +0 -21
  111. package/dist/index-uhkmwruf.d.ts +0 -46
  112. package/dist/rstool-agent-BZi5jO1y.js +0 -158
  113. package/dist/rstool-agent-BZi5jO1y.js.map +0 -1
  114. package/dist/rstool-agent-pRaPnZay.d.ts +0 -35
  115. package/dist/session/session-store.js.map +0 -1
  116. package/dist/tool-contract-n1ghUOrK.d.ts +0 -32
@@ -0,0 +1,685 @@
1
+ import { CstType } from "./models/common.js";
2
+ import { ModelAdapter } from "./mappers/model-adapter.js";
3
+ import { SchemaAdapter } from "./mappers/schema-adapter.js";
4
+ import { CONTRACT_VERSION } from "./models/tool-contract.js";
5
+ import { Graph } from "@rsconcept/domain/graph/graph";
6
+ import { extractGlobals } from "@rsconcept/domain/rslang/api";
7
+ import { randomUUID } from "node:crypto";
8
+ import fs from "node:fs";
9
+ import path from "node:path";
10
+ //#region src/models/portal-json.ts
11
+ const CST_TYPE_VALUES = new Set(Object.values(CstType));
12
+ function parsePortalCstType(value, alias) {
13
+ if (!CST_TYPE_VALUES.has(value)) throw new Error(`Invalid cst_type "${value}" for constituent "${alias}"`);
14
+ return value;
15
+ }
16
+ /** Portal JSON import/export format version (schema and model files). */
17
+ const PORTAL_JSON_CONTRACT_VERSION = "1.0.0";
18
+ /** Map a Portal API or JSON schema item to an agent {@link ConstituentaDraft}. */
19
+ function portalItemToDraft(item) {
20
+ return {
21
+ id: item.id,
22
+ alias: item.alias,
23
+ cstType: parsePortalCstType(item.cst_type, item.alias),
24
+ definitionFormal: item.definition_formal ?? "",
25
+ term: item.term_raw ?? "",
26
+ definitionText: item.definition_raw ?? "",
27
+ convention: item.convention ?? ""
28
+ };
29
+ }
30
+ //#endregion
31
+ //#region src/mappers/portal-adapter.ts
32
+ function portalMetadataToSessionSeed(data) {
33
+ return {
34
+ alias: data.alias ?? "",
35
+ title: data.title ?? "",
36
+ comment: data.description ?? "",
37
+ items: []
38
+ };
39
+ }
40
+ function portalSchemaToSessionSeed(data) {
41
+ return portalMetadataToSessionSeed(data);
42
+ }
43
+ function portalDetailsToSessionSeed(data) {
44
+ return portalMetadataToSessionSeed(data);
45
+ }
46
+ function portalItemsToDrafts(items) {
47
+ return items.map((item) => portalItemToDraft(item));
48
+ }
49
+ function portalSchemaToDrafts(data) {
50
+ return portalItemsToDrafts(data.items);
51
+ }
52
+ function portalDetailsToDrafts(data) {
53
+ return portalItemsToDrafts(data.items);
54
+ }
55
+ //#endregion
56
+ //#region src/session/batch-apply.ts
57
+ /** Order drafts so suppliers are applied before dependents. */
58
+ function orderDrafts(sessionItems, drafts) {
59
+ const merged = /* @__PURE__ */ new Map();
60
+ for (const item of sessionItems) merged.set(item.id, {
61
+ id: item.id,
62
+ alias: item.alias,
63
+ cstType: item.cstType,
64
+ definitionFormal: item.definitionFormal
65
+ });
66
+ for (const draft of drafts) merged.set(draft.id, draft);
67
+ const graph = new Graph();
68
+ const aliasToId = /* @__PURE__ */ new Map();
69
+ for (const [id, draft] of merged) {
70
+ graph.addNode(id);
71
+ aliasToId.set(draft.alias, id);
72
+ }
73
+ for (const [id, draft] of merged) {
74
+ if (!draft.definitionFormal) continue;
75
+ for (const alias of extractGlobals(draft.definitionFormal)) {
76
+ const depId = aliasToId.get(alias);
77
+ if (depId !== void 0 && depId !== id) graph.addEdge(depId, id);
78
+ }
79
+ }
80
+ const draftIds = new Set(drafts.map((draft) => draft.id));
81
+ const topoIds = graph.topologicalOrder().filter((id) => draftIds.has(id));
82
+ const seen = new Set(topoIds);
83
+ const missing = drafts.filter((draft) => !seen.has(draft.id)).map((draft) => draft.id);
84
+ return [...topoIds, ...missing].map((id) => drafts.find((draft) => draft.id === id)).filter(Boolean);
85
+ }
86
+ /**
87
+ * Restore declaration order in session items after a batch apply.
88
+ * Topological apply order is only needed for analysis; Portal JSON uses array order.
89
+ */
90
+ function reorderSessionItemsByDrafts(items, drafts) {
91
+ if (drafts.length === 0 || items.length === 0) return;
92
+ const draftIds = drafts.map((draft) => draft.id);
93
+ const draftIdSet = new Set(draftIds);
94
+ if (items.filter((item) => draftIdSet.has(item.id)).length === 0) return;
95
+ const unmentioned = items.filter((item) => !draftIdSet.has(item.id));
96
+ if (unmentioned.length === 0) {
97
+ const byId = new Map(items.map((item) => [item.id, item]));
98
+ items.splice(0, items.length, ...draftIds.map((id) => byId.get(id)));
99
+ return;
100
+ }
101
+ const existingIds = new Set(unmentioned.map((item) => item.id));
102
+ const newDrafts = drafts.filter((draft) => !existingIds.has(draft.id));
103
+ if (newDrafts.length === 0) return;
104
+ const newIds = new Set(newDrafts.map((draft) => draft.id));
105
+ const kept = items.filter((item) => !newIds.has(item.id));
106
+ const byId = new Map(items.map((item) => [item.id, item]));
107
+ items.splice(0, items.length, ...kept, ...newDrafts.map((draft) => byId.get(draft.id)));
108
+ }
109
+ //#endregion
110
+ //#region src/session/persistence.ts
111
+ const CURRENT_SESSION_FILE = "_current.json";
112
+ const UNSAFE_SESSION_ID = /[/\\]|\.\./;
113
+ function assertSafeSessionId(sessionId) {
114
+ if (!sessionId || UNSAFE_SESSION_ID.test(sessionId)) throw new Error(`Invalid session ID: ${sessionId}`);
115
+ }
116
+ var SessionPersistence = class {
117
+ dir;
118
+ constructor(dir) {
119
+ this.dir = dir;
120
+ fs.mkdirSync(dir, { recursive: true });
121
+ }
122
+ save(sessionId, envelope) {
123
+ fs.writeFileSync(this.filePath(sessionId), JSON.stringify(envelope, null, 2), "utf-8");
124
+ }
125
+ load(sessionId) {
126
+ const file = this.filePath(sessionId);
127
+ if (!fs.existsSync(file)) return null;
128
+ return JSON.parse(fs.readFileSync(file, "utf-8"));
129
+ }
130
+ delete(sessionId) {
131
+ const file = this.filePath(sessionId);
132
+ if (fs.existsSync(file)) fs.unlinkSync(file);
133
+ }
134
+ saveCurrentSessionId(sessionId) {
135
+ fs.writeFileSync(path.join(this.dir, CURRENT_SESSION_FILE), JSON.stringify({ sessionId }, null, 2), "utf-8");
136
+ }
137
+ loadCurrentSessionId() {
138
+ const file = path.join(this.dir, CURRENT_SESSION_FILE);
139
+ if (!fs.existsSync(file)) return null;
140
+ return JSON.parse(fs.readFileSync(file, "utf-8")).sessionId ?? null;
141
+ }
142
+ filePath(sessionId) {
143
+ assertSafeSessionId(sessionId);
144
+ const file = path.resolve(this.dir, `${sessionId}.json`);
145
+ const relative = path.relative(path.resolve(this.dir), file);
146
+ if (relative.startsWith("..") || path.isAbsolute(relative)) throw new Error(`Invalid session ID: ${sessionId}`);
147
+ return file;
148
+ }
149
+ };
150
+ //#endregion
151
+ //#region src/session/session-store.ts
152
+ var SessionStore = class {
153
+ sessions = /* @__PURE__ */ new Map();
154
+ persistence;
155
+ constructor(options = {}) {
156
+ this.persistence = options.persistenceDir ? new SessionPersistence(options.persistenceDir) : null;
157
+ }
158
+ create(initial, contractVersion) {
159
+ const now = (/* @__PURE__ */ new Date()).toISOString();
160
+ const sessionId = initial?.sessionId ?? randomUUID();
161
+ const envelope = {
162
+ state: {
163
+ sessionId,
164
+ alias: initial?.alias ?? "",
165
+ title: initial?.title ?? "",
166
+ comment: initial?.comment ?? "",
167
+ createdAt: initial?.createdAt ?? now,
168
+ updatedAt: now,
169
+ revisions: initial?.revisions ?? [],
170
+ items: initial?.items ?? [],
171
+ model: initial?.model ?? { items: [] }
172
+ },
173
+ diagnostics: []
174
+ };
175
+ this.sessions.set(sessionId, envelope);
176
+ this.persist(sessionId, envelope);
177
+ return {
178
+ sessionId,
179
+ contractVersion: contractVersion ?? "2.0.0"
180
+ };
181
+ }
182
+ get(sessionId) {
183
+ const found = this.sessions.get(sessionId) ?? this.loadFromDisk(sessionId);
184
+ if (!found) throw new Error(`Unknown session: ${sessionId}`);
185
+ return found;
186
+ }
187
+ has(sessionId) {
188
+ if (this.sessions.has(sessionId)) return true;
189
+ if (!this.persistence) return false;
190
+ return this.persistence.load(sessionId) !== null;
191
+ }
192
+ replaceState(sessionId, nextState) {
193
+ const found = this.get(sessionId);
194
+ found.state = {
195
+ ...nextState,
196
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
197
+ };
198
+ this.persist(sessionId, found);
199
+ }
200
+ addRevision(sessionId, message) {
201
+ const found = this.get(sessionId);
202
+ const revision = {
203
+ revisionId: randomUUID(),
204
+ at: (/* @__PURE__ */ new Date()).toISOString(),
205
+ message
206
+ };
207
+ found.state.revisions.push(revision);
208
+ found.state.updatedAt = revision.at;
209
+ this.persist(sessionId, found);
210
+ return revision;
211
+ }
212
+ /** Replace active diagnostics for one constituent (or scratch when constituentId is undefined). */
213
+ replaceDiagnosticsForConstituent(sessionId, constituentId, records) {
214
+ const found = this.get(sessionId);
215
+ found.diagnostics = found.diagnostics.filter((record) => record.constituentId !== constituentId);
216
+ found.diagnostics.push(...records);
217
+ found.state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
218
+ this.persist(sessionId, found);
219
+ }
220
+ setDiagnostics(sessionId, records) {
221
+ const found = this.get(sessionId);
222
+ found.diagnostics = [...records];
223
+ found.state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
224
+ this.persist(sessionId, found);
225
+ }
226
+ listDiagnostics(sessionId, filters) {
227
+ const found = this.get(sessionId);
228
+ if (filters?.constituentId === void 0) return [...found.diagnostics];
229
+ return found.diagnostics.filter((record) => record.constituentId === filters.constituentId);
230
+ }
231
+ snapshot(sessionId) {
232
+ const found = this.get(sessionId);
233
+ return structuredClone(found);
234
+ }
235
+ restore(sessionId, snapshot) {
236
+ this.sessions.set(sessionId, structuredClone(snapshot));
237
+ this.persist(sessionId, this.sessions.get(sessionId));
238
+ }
239
+ saveCurrentSessionId(sessionId) {
240
+ this.persistence?.saveCurrentSessionId(sessionId);
241
+ }
242
+ loadCurrentSessionId() {
243
+ return this.persistence?.loadCurrentSessionId() ?? null;
244
+ }
245
+ loadFromDisk(sessionId) {
246
+ const loaded = this.persistence?.load(sessionId);
247
+ if (!loaded) return null;
248
+ this.sessions.set(sessionId, loaded);
249
+ return loaded;
250
+ }
251
+ persist(sessionId, envelope) {
252
+ this.persistence?.save(sessionId, envelope);
253
+ }
254
+ };
255
+ //#endregion
256
+ //#region src/models/import-detect.ts
257
+ function isRecord(value) {
258
+ return value !== null && typeof value === "object" && !Array.isArray(value);
259
+ }
260
+ function parseImportPayload(payload) {
261
+ if (typeof payload === "string") return JSON.parse(payload);
262
+ return payload;
263
+ }
264
+ function detectImportKind(data) {
265
+ if (!isRecord(data)) throw new Error("Invalid import payload");
266
+ if ("contractVersion" in data && "state" in data) return "session";
267
+ if ("contract_version" in data && Array.isArray(data.items)) {
268
+ const items = data.items;
269
+ if (items.length > 0) {
270
+ const first = items[0];
271
+ if (isRecord(first) && "cst_type" in first) return "portal-schema";
272
+ throw new Error("Portal model JSON cannot be imported as a schema session");
273
+ }
274
+ }
275
+ if (Array.isArray(data.items) && data.items.length > 0) {
276
+ const first = data.items[0];
277
+ if (isRecord(first) && "cst_type" in first) return "portal-details";
278
+ }
279
+ throw new Error("Cannot detect import kind; pass kind explicitly");
280
+ }
281
+ //#endregion
282
+ //#region src/models/rstool-agent.ts
283
+ function normalizeImportedState(state) {
284
+ return {
285
+ ...state,
286
+ alias: state.alias ?? "",
287
+ title: state.title ?? "",
288
+ comment: state.comment ?? "",
289
+ model: state.model ?? { items: [] }
290
+ };
291
+ }
292
+ function portalImportMetadata(session, kind) {
293
+ const defaults = kind === "schema" ? {
294
+ title: "Conceptual schema",
295
+ alias: "SCHEMA"
296
+ } : {
297
+ title: "Conceptual model",
298
+ alias: "MODEL"
299
+ };
300
+ const title = session.title.trim();
301
+ const alias = session.alias.trim();
302
+ return {
303
+ title: title.length > 0 ? title : defaults.title,
304
+ alias: alias.length > 0 ? alias : defaults.alias,
305
+ description: session.comment.trim()
306
+ };
307
+ }
308
+ function inferCstType(alias) {
309
+ switch (alias.trim().charAt(0).toUpperCase()) {
310
+ case "X": return CstType.BASE;
311
+ case "C": return CstType.CONSTANT;
312
+ case "S": return CstType.STRUCTURED;
313
+ case "D": return CstType.TERM;
314
+ case "A": return CstType.AXIOM;
315
+ case "F": return CstType.FUNCTION;
316
+ case "P": return CstType.PREDICATE;
317
+ case "N": return CstType.NOMINAL;
318
+ case "T": return CstType.STATEMENT;
319
+ default: throw new Error(`Cannot infer cstType from alias "${alias}"; pass cstType explicitly`);
320
+ }
321
+ }
322
+ /**
323
+ * Agent-facing entry point for incremental RSForm editing, analysis, diagnostics,
324
+ * modeling, and evaluation.
325
+ *
326
+ * Holds in-memory (optionally persisted) sessions and delegates language work
327
+ * to internal schema and model adapters.
328
+ */
329
+ var RSToolAgent = class {
330
+ contractVersion = CONTRACT_VERSION;
331
+ sessions;
332
+ adapter = new SchemaAdapter();
333
+ evaluation = new ModelAdapter();
334
+ currentSessionId;
335
+ /** @param options - Optional persistence directory for session storage. */
336
+ constructor(options = {}) {
337
+ this.sessions = new SessionStore({ persistenceDir: options.persistenceDir });
338
+ this.currentSessionId = this.sessions.loadCurrentSessionId();
339
+ }
340
+ /** @inheritdoc */
341
+ ensureSession(initial) {
342
+ return this.getCurrentSession() ?? this.createSession(initial);
343
+ }
344
+ /** @inheritdoc */
345
+ createSession(initial) {
346
+ return this.trackSession(this.sessions.create(initial, this.contractVersion));
347
+ }
348
+ /** @inheritdoc */
349
+ getCurrentSession() {
350
+ if (!this.currentSessionId) return null;
351
+ if (!this.sessions.has(this.currentSessionId)) {
352
+ this.currentSessionId = null;
353
+ this.sessions.saveCurrentSessionId(null);
354
+ return null;
355
+ }
356
+ return {
357
+ sessionId: this.currentSessionId,
358
+ contractVersion: this.contractVersion
359
+ };
360
+ }
361
+ /** @inheritdoc */
362
+ setCurrentSession(sessionId) {
363
+ if (!this.sessions.has(sessionId)) throw new Error(`Unknown session: ${sessionId}`);
364
+ return this.trackSession({
365
+ sessionId,
366
+ contractVersion: this.contractVersion
367
+ });
368
+ }
369
+ /** @inheritdoc */
370
+ applySchemaPatch(input, sessionId) {
371
+ const session = sessionId ? {
372
+ sessionId: this.resolveSessionId(sessionId),
373
+ contractVersion: this.contractVersion
374
+ } : this.ensureSession(input.initial);
375
+ const drafts = this.resolveAgentPatches(session.sessionId, input.items);
376
+ const result = this.applyConstituents({
377
+ drafts,
378
+ mode: input.mode
379
+ }, session.sessionId);
380
+ const revision = result.success && input.commitMessage ? this.commitStep(input.commitMessage, session.sessionId) : void 0;
381
+ return {
382
+ ...result,
383
+ session,
384
+ summary: this.buildSessionSummary(session.sessionId),
385
+ revision
386
+ };
387
+ }
388
+ /** @inheritdoc */
389
+ getSessionState(detail = "summary", sessionId) {
390
+ if (detail === "full") {
391
+ const envelope = this.sessions.get(this.resolveSessionId(sessionId));
392
+ return structuredClone(envelope.state);
393
+ }
394
+ return this.buildSessionSummary(sessionId);
395
+ }
396
+ /** @inheritdoc */
397
+ listDiagnostics(filters, sessionId) {
398
+ return this.sessions.listDiagnostics(this.resolveSessionId(sessionId), filters);
399
+ }
400
+ /** @inheritdoc */
401
+ analyzeExpression(input, sessionId) {
402
+ const id = this.resolveSessionId(sessionId);
403
+ const envelope = this.sessions.get(id);
404
+ const { result, diagnostics } = this.adapter.analyzeAgainstSession(envelope.state, {
405
+ id: -1,
406
+ alias: "_analysis",
407
+ cstType: input.cstType,
408
+ definitionFormal: input.expression
409
+ });
410
+ if (input.recordDiagnostics) this.sessions.replaceDiagnosticsForConstituent(id, void 0, diagnostics.map((item) => ({
411
+ ...item,
412
+ constituentId: void 0
413
+ })));
414
+ return result;
415
+ }
416
+ /** @inheritdoc */
417
+ commitStep(message, sessionId) {
418
+ return this.sessions.addRevision(this.resolveSessionId(sessionId), message);
419
+ }
420
+ /** @inheritdoc */
421
+ exportSession(sessionId) {
422
+ const envelope = this.sessions.get(this.resolveSessionId(sessionId));
423
+ return JSON.stringify({
424
+ contractVersion: this.contractVersion,
425
+ state: envelope.state,
426
+ diagnostics: envelope.diagnostics
427
+ }, null, 2);
428
+ }
429
+ /** @inheritdoc */
430
+ exportPortal(input, sessionId) {
431
+ const format = input.format ?? "json";
432
+ const object = input.kind === "schema" ? this.buildPortalSchemaObject(sessionId) : this.buildPortalModelObject(sessionId);
433
+ return format === "object" ? object : JSON.stringify(object, null, 2);
434
+ }
435
+ /** @inheritdoc */
436
+ importData(payload, kind = "auto") {
437
+ const parsed = parseImportPayload(payload);
438
+ const resolvedKind = kind === "auto" ? detectImportKind(parsed) : kind;
439
+ switch (resolvedKind) {
440
+ case "session": return this.importSessionExport(parsed);
441
+ case "portal-schema": return this.importPortalSchemaData(parsed);
442
+ case "portal-details": return this.importPortalDetailsData(parsed);
443
+ default: throw new Error(`Unsupported import kind: ${resolvedKind}`);
444
+ }
445
+ }
446
+ /** @inheritdoc */
447
+ async setModelValues(input, sessionId) {
448
+ const id = this.resolveSessionId(sessionId);
449
+ const snapshot = this.sessions.snapshot(id);
450
+ try {
451
+ let state = this.sessions.get(id).state;
452
+ if (input.clear?.length) {
453
+ const model = await this.evaluation.clearConstituentaValues(state, input.clear);
454
+ state = {
455
+ ...state,
456
+ model
457
+ };
458
+ this.sessions.replaceState(id, state);
459
+ }
460
+ if (input.set?.length) {
461
+ state = this.sessions.get(id).state;
462
+ const model = await this.evaluation.setConstituentaValues(state, { items: input.set });
463
+ state = {
464
+ ...state,
465
+ model
466
+ };
467
+ this.sessions.replaceState(id, state);
468
+ return model;
469
+ }
470
+ return structuredClone(this.sessions.get(id).state.model);
471
+ } catch (error) {
472
+ this.sessions.restore(id, snapshot);
473
+ throw error;
474
+ }
475
+ }
476
+ /** @inheritdoc */
477
+ getModelState(sessionId) {
478
+ const envelope = this.sessions.get(this.resolveSessionId(sessionId));
479
+ return structuredClone(envelope.state.model);
480
+ }
481
+ /** @inheritdoc */
482
+ evaluate(input, sessionId) {
483
+ const envelope = this.sessions.get(this.resolveSessionId(sessionId));
484
+ if (input.constituentId !== void 0) return this.evaluation.evaluateConstituenta(envelope.state, input.constituentId);
485
+ if (input.expression !== void 0 && input.cstType !== void 0) return this.evaluation.evaluateExpression(envelope.state, input.expression, input.cstType);
486
+ throw new Error("evaluate requires constituentId or expression with cstType");
487
+ }
488
+ /** @inheritdoc */
489
+ recalculateModel(sessionId) {
490
+ const envelope = this.sessions.get(this.resolveSessionId(sessionId));
491
+ return this.evaluation.recalculateModel(envelope.state);
492
+ }
493
+ addOrUpdateConstituenta(input, sessionId) {
494
+ const id = this.resolveSessionId(sessionId);
495
+ const envelope = this.sessions.get(id);
496
+ const { result, diagnostics } = this.adapter.analyzeAgainstSession(envelope.state, input.draft);
497
+ const state = this.adapter.mergeStateWithDraft(envelope.state, input.draft, result);
498
+ this.sessions.replaceDiagnosticsForConstituent(id, input.draft.id, diagnostics);
499
+ return {
500
+ state,
501
+ diagnostics
502
+ };
503
+ }
504
+ applyConstituents(input, sessionId) {
505
+ const id = this.resolveSessionId(sessionId);
506
+ const mode = input.mode ?? "atomic";
507
+ const ordered = orderDrafts(this.sessions.get(id).state.items, input.drafts);
508
+ const snapshot = this.sessions.snapshot(id);
509
+ const applied = [];
510
+ const failed = [];
511
+ for (const draft of ordered) {
512
+ const result = this.addOrUpdateConstituenta({ draft }, id);
513
+ if (result.state.analysis.success) {
514
+ applied.push(result.state);
515
+ continue;
516
+ }
517
+ failed.push({
518
+ draft,
519
+ diagnostics: result.diagnostics
520
+ });
521
+ if (mode === "atomic") {
522
+ this.sessions.restore(id, snapshot);
523
+ return {
524
+ success: false,
525
+ applied: [],
526
+ failed,
527
+ diagnostics: this.sessions.listDiagnostics(id)
528
+ };
529
+ }
530
+ }
531
+ const envelope = this.sessions.get(id);
532
+ reorderSessionItemsByDrafts(envelope.state.items, input.drafts);
533
+ this.sessions.replaceState(id, envelope.state);
534
+ return {
535
+ success: failed.length === 0,
536
+ applied,
537
+ failed,
538
+ diagnostics: this.sessions.listDiagnostics(id)
539
+ };
540
+ }
541
+ buildSessionSummary(sessionId) {
542
+ const id = this.resolveSessionId(sessionId);
543
+ const envelope = this.sessions.get(id);
544
+ const diagnostics = this.sessions.listDiagnostics(id);
545
+ return {
546
+ sessionId: id,
547
+ contractVersion: this.contractVersion,
548
+ alias: envelope.state.alias,
549
+ title: envelope.state.title,
550
+ comment: envelope.state.comment,
551
+ itemCount: envelope.state.items.length,
552
+ modelItemCount: envelope.state.model.items.length,
553
+ diagnosticsCount: diagnostics.length,
554
+ items: envelope.state.items.map((item) => ({
555
+ id: item.id,
556
+ alias: item.alias,
557
+ cstType: item.cstType,
558
+ analysisSuccess: item.analysis.success
559
+ })),
560
+ diagnostics,
561
+ lastRevision: envelope.state.revisions.at(-1)
562
+ };
563
+ }
564
+ buildPortalSchemaObject(sessionId) {
565
+ const envelope = this.sessions.get(this.resolveSessionId(sessionId));
566
+ return {
567
+ contract_version: PORTAL_JSON_CONTRACT_VERSION,
568
+ ...portalImportMetadata(envelope.state, "schema"),
569
+ items: envelope.state.items.map((item) => ({
570
+ id: item.id,
571
+ alias: item.alias,
572
+ convention: item.convention,
573
+ crucial: false,
574
+ cst_type: item.cstType,
575
+ definition_formal: item.definitionFormal,
576
+ typification_manual: "",
577
+ value_is_property: false,
578
+ definition_raw: item.definitionText,
579
+ definition_resolved: item.definitionText,
580
+ term_raw: item.term,
581
+ term_resolved: item.term,
582
+ term_forms: []
583
+ })),
584
+ attribution: []
585
+ };
586
+ }
587
+ buildPortalModelObject(sessionId) {
588
+ const envelope = this.sessions.get(this.resolveSessionId(sessionId));
589
+ return {
590
+ contract_version: PORTAL_JSON_CONTRACT_VERSION,
591
+ ...portalImportMetadata(envelope.state, "model"),
592
+ items: envelope.state.model.items.map((item) => ({
593
+ id: item.id,
594
+ type: item.type,
595
+ value: item.value
596
+ }))
597
+ };
598
+ }
599
+ importSessionExport(parsed) {
600
+ if (!parsed || typeof parsed !== "object" || !("state" in parsed)) throw new Error("Invalid session export payload");
601
+ const data = parsed;
602
+ const handle = this.sessions.create(normalizeImportedState(data.state), this.contractVersion);
603
+ if (data.diagnostics?.length) this.sessions.setDiagnostics(handle.sessionId, data.diagnostics);
604
+ return this.trackSession(handle);
605
+ }
606
+ importPortalSchemaData(data) {
607
+ const handle = this.createSession(portalSchemaToSessionSeed(data));
608
+ this.applyConstituents({
609
+ drafts: portalSchemaToDrafts(data),
610
+ mode: "best_effort"
611
+ }, handle.sessionId);
612
+ return handle;
613
+ }
614
+ importPortalDetailsData(data) {
615
+ const handle = this.createSession(portalDetailsToSessionSeed(data));
616
+ this.applyConstituents({
617
+ drafts: portalDetailsToDrafts(data),
618
+ mode: "best_effort"
619
+ }, handle.sessionId);
620
+ return handle;
621
+ }
622
+ resolveAgentPatches(sessionId, patches) {
623
+ const items = this.sessions.get(sessionId).state.items;
624
+ const existingByAlias = new Map(items.map((item) => [item.alias, item]));
625
+ const usedIds = new Set(items.map((item) => item.id));
626
+ let nextId = items.reduce((max, item) => Math.max(max, item.id), 0) + 1;
627
+ const reserveId = (id) => {
628
+ usedIds.add(id);
629
+ if (id >= nextId) nextId = id + 1;
630
+ };
631
+ const allocateId = () => {
632
+ while (usedIds.has(nextId)) nextId += 1;
633
+ const id = nextId;
634
+ nextId += 1;
635
+ usedIds.add(id);
636
+ return id;
637
+ };
638
+ return patches.map((patch) => {
639
+ const existing = existingByAlias.get(patch.alias);
640
+ let id;
641
+ if (patch.id !== void 0) {
642
+ id = patch.id;
643
+ reserveId(id);
644
+ } else if (existing !== void 0) id = existing.id;
645
+ else id = allocateId();
646
+ const draft = {
647
+ id,
648
+ alias: patch.alias,
649
+ cstType: patch.cstType ?? existing?.cstType ?? inferCstType(patch.alias),
650
+ definitionFormal: patch.definitionFormal ?? existing?.definitionFormal ?? "",
651
+ term: patch.term ?? existing?.term ?? "",
652
+ definitionText: patch.definitionText ?? existing?.definitionText ?? "",
653
+ convention: patch.convention ?? existing?.convention ?? ""
654
+ };
655
+ existingByAlias.set(patch.alias, {
656
+ ...draft,
657
+ analysis: existing?.analysis ?? {
658
+ success: true,
659
+ type: null,
660
+ valueClass: "value",
661
+ diagnostics: []
662
+ }
663
+ });
664
+ return draft;
665
+ });
666
+ }
667
+ resolveSessionId(sessionId) {
668
+ const id = sessionId ?? this.currentSessionId;
669
+ if (!id) return this.createSession().sessionId;
670
+ if (!this.sessions.has(id)) {
671
+ if (sessionId) throw new Error(`Unknown session: ${sessionId}`);
672
+ return this.createSession().sessionId;
673
+ }
674
+ return id;
675
+ }
676
+ trackSession(handle) {
677
+ this.currentSessionId = handle.sessionId;
678
+ this.sessions.saveCurrentSessionId(handle.sessionId);
679
+ return handle;
680
+ }
681
+ };
682
+ //#endregion
683
+ export { portalItemToDraft as i, SessionStore as n, PORTAL_JSON_CONTRACT_VERSION as r, RSToolAgent as t };
684
+
685
+ //# sourceMappingURL=models-Bw6Uum8i.js.map