@qontinui/shared-types 0.2.3 → 0.2.4
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/dist/tauri-events.d.cts +114 -1
- package/dist/tauri-events.d.ts +114 -1
- package/dist/ui-bridge-ir.cjs +37 -0
- package/dist/ui-bridge-ir.cjs.map +1 -1
- package/dist/ui-bridge-ir.d.cts +90 -1
- package/dist/ui-bridge-ir.d.ts +90 -1
- package/dist/ui-bridge-ir.js +37 -0
- package/dist/ui-bridge-ir.js.map +1 -1
- package/package.json +1 -1
- package/src/generated/UiBridgeRequestEnvelope.d.ts +45 -0
- package/src/generated/UiBridgeResponseEnvelope.d.ts +66 -0
- package/src/generated/index.ts +432 -430
- package/src/tauri-events/_api.ts +14 -0
- package/src/ui-bridge-ir/document.ts +9 -0
- package/src/ui-bridge-ir/group.ts +84 -0
- package/src/ui-bridge-ir/index.ts +1 -0
- package/src/ui-bridge-ir/ir.schema.json +58 -0
- package/src/ui-bridge-ir/projection.ts +58 -0
package/src/tauri-events/_api.ts
CHANGED
|
@@ -74,3 +74,17 @@ export type { RecommendationReviewDecisionPayload } from "../generated/Recommend
|
|
|
74
74
|
// pre-dates this generated re-export; both shapes are intentionally
|
|
75
75
|
// identical. New consumers should prefer this generated import. ──
|
|
76
76
|
export type { CanvasPanel as CanvasUpdatePanel } from "../generated/CanvasPanel";
|
|
77
|
+
|
|
78
|
+
// ── UI Bridge IPC envelope payloads carried on the `ui-bridge-request` and
|
|
79
|
+
// `ui-bridge-response` Tauri channels. Stage 1 of the ui-bridge-request
|
|
80
|
+
// envelope concretization (deferral note in commit ea5d9a61f). The Rust
|
|
81
|
+
// sources live in `qontinui-schemas/rust/src/app_events.rs`; the runner's
|
|
82
|
+
// React handler in `src/hooks/ui-bridge-events/types.ts` should pick the
|
|
83
|
+
// `requestId | type` fields off these to keep the envelope head in sync
|
|
84
|
+
// while leaving its rich set of optional payload fields hand-written.
|
|
85
|
+
// Stage 2 (per-payload tagged union of all 171 request_types) is deferred
|
|
86
|
+
// indefinitely — the existing AssertEqual<AllHandledTypes,
|
|
87
|
+
// UIBridgeRequestType> + per-hook never checks already enforce dispatch
|
|
88
|
+
// exhaustiveness from the right end of the pipeline. ──
|
|
89
|
+
export type { UiBridgeRequestEnvelope } from "../generated/UiBridgeRequestEnvelope";
|
|
90
|
+
export type { UiBridgeResponseEnvelope } from "../generated/UiBridgeResponseEnvelope";
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* adapter folds it into ui-bridge-auto's `WorkflowConfig`.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import type { IRGroup } from "./group";
|
|
9
10
|
import type { IRMetadata, IRProvenance } from "./primitives";
|
|
10
11
|
import type { IRState } from "./state";
|
|
11
12
|
import type { IRTransition } from "./transition";
|
|
@@ -100,6 +101,14 @@ export interface IRDocument {
|
|
|
100
101
|
/** Transition declarations within this document. */
|
|
101
102
|
transitions: IRTransition[];
|
|
102
103
|
|
|
104
|
+
/**
|
|
105
|
+
* Groups produced by workflow-criteria synthesis (not by IR state authoring).
|
|
106
|
+
* Synthesis appends to this list; the projection emits them after state-derived
|
|
107
|
+
* groups in legacy `groups[]` output. Authoring tools should treat this field
|
|
108
|
+
* as read-only.
|
|
109
|
+
*/
|
|
110
|
+
synthesizedGroups?: IRGroup[];
|
|
111
|
+
|
|
103
112
|
/** ID of the initial/starting state, if applicable. */
|
|
104
113
|
initialState?: string;
|
|
105
114
|
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IR-side group + assertion types.
|
|
3
|
+
*
|
|
4
|
+
* The IR's primary authoring surface is `states + transitions`, which the
|
|
5
|
+
* projection maps into legacy `groups[]` (one group per state). However, the
|
|
6
|
+
* runner's `workflow_generation::spec_synthesis` pipeline produces "free-form"
|
|
7
|
+
* groups from acceptance criteria — these are NOT tied to any state and
|
|
8
|
+
* therefore have no home in the state-derived projection path.
|
|
9
|
+
*
|
|
10
|
+
* `IRGroup` is the dedicated channel for those synthesized groups. The IR
|
|
11
|
+
* carries them in the optional `IRDocument.synthesizedGroups` field; the
|
|
12
|
+
* projection appends them after the state-derived groups, in declared order,
|
|
13
|
+
* to preserve byte-stable output.
|
|
14
|
+
*
|
|
15
|
+
* The shape mirrors the legacy `SpecGroup` / `SpecAssertion` (canonical
|
|
16
|
+
* definitions live in `@qontinui/ui-bridge/specs`), but is re-defined here to
|
|
17
|
+
* keep `qontinui-schemas/ts` free of any runtime dep on `@qontinui/ui-bridge/*`
|
|
18
|
+
* (per the schemas package's "zero ui-bridge deps" policy).
|
|
19
|
+
*
|
|
20
|
+
* Note on field shape: the IR-side `IRAssertion` keeps the legacy assertion's
|
|
21
|
+
* field types as loose as the synthesis path emits them. Strict consumers
|
|
22
|
+
* (e.g. the canonical `SpecAssertion` in `@qontinui/ui-bridge/specs`) can
|
|
23
|
+
* narrow as needed at the consumer boundary; the projection preserves the
|
|
24
|
+
* objects verbatim into the legacy output.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* IR-side assertion target. Always `type: "search"` for synthesis-emitted
|
|
29
|
+
* assertions; the wider legacy schema also supports point/region targets but
|
|
30
|
+
* the IR doesn't express those today.
|
|
31
|
+
*/
|
|
32
|
+
export interface IRAssertionTarget {
|
|
33
|
+
/** Always `"search"` for synthesis-emitted assertions. */
|
|
34
|
+
type: string;
|
|
35
|
+
/**
|
|
36
|
+
* Free-form criteria object. Kept as a loose record so synthesis can emit
|
|
37
|
+
* partially-populated criteria without tripping the schema.
|
|
38
|
+
*/
|
|
39
|
+
criteria: Record<string, unknown>;
|
|
40
|
+
label: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* IR-side assertion. Mirrors the legacy `SpecAssertion` shape.
|
|
45
|
+
*/
|
|
46
|
+
export interface IRAssertion {
|
|
47
|
+
id: string;
|
|
48
|
+
description: string;
|
|
49
|
+
category: string;
|
|
50
|
+
severity: string;
|
|
51
|
+
assertionType: string;
|
|
52
|
+
target: IRAssertionTarget;
|
|
53
|
+
source: string;
|
|
54
|
+
reviewed: boolean;
|
|
55
|
+
enabled: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Optional human-readable precondition. Synthesis populates this from the
|
|
58
|
+
* acceptance criterion's verification hint.
|
|
59
|
+
*/
|
|
60
|
+
precondition?: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* IR-side group produced by workflow-criteria synthesis (i.e. NOT derived
|
|
65
|
+
* from `IRState` annotations). Mirrors the legacy `SpecGroup` shape one-to-one
|
|
66
|
+
* so the projection can pass it through to legacy `groups[]` without loss.
|
|
67
|
+
*/
|
|
68
|
+
export interface IRGroup {
|
|
69
|
+
id: string;
|
|
70
|
+
name: string;
|
|
71
|
+
description: string;
|
|
72
|
+
category: string;
|
|
73
|
+
assertions: IRAssertion[];
|
|
74
|
+
/**
|
|
75
|
+
* Provenance of the group itself (typically `"ai-generated"` for synthesis
|
|
76
|
+
* output, but kept open for future authoring channels).
|
|
77
|
+
*/
|
|
78
|
+
source?: string;
|
|
79
|
+
/**
|
|
80
|
+
* Free-form tags. Synthesis emits e.g. `["workflow-generated",
|
|
81
|
+
* "acceptance-criteria"]` so downstream tooling can filter.
|
|
82
|
+
*/
|
|
83
|
+
tags?: string[];
|
|
84
|
+
}
|
|
@@ -24,6 +24,10 @@
|
|
|
24
24
|
"transitions": {
|
|
25
25
|
"type": "array",
|
|
26
26
|
"items": { "$ref": "#/$defs/IRTransition" }
|
|
27
|
+
},
|
|
28
|
+
"synthesizedGroups": {
|
|
29
|
+
"type": "array",
|
|
30
|
+
"items": { "$ref": "#/$defs/IRGroup" }
|
|
27
31
|
}
|
|
28
32
|
},
|
|
29
33
|
"$defs": {
|
|
@@ -230,6 +234,60 @@
|
|
|
230
234
|
"provenance": { "$ref": "#/$defs/IRProvenance" },
|
|
231
235
|
"crossRefs": { "type": "array", "items": { "$ref": "#/$defs/IRCrossRef" } }
|
|
232
236
|
}
|
|
237
|
+
},
|
|
238
|
+
"IRAssertionTarget": {
|
|
239
|
+
"type": "object",
|
|
240
|
+
"required": ["type", "criteria", "label"],
|
|
241
|
+
"additionalProperties": false,
|
|
242
|
+
"properties": {
|
|
243
|
+
"type": { "type": "string" },
|
|
244
|
+
"criteria": { "type": "object", "additionalProperties": true },
|
|
245
|
+
"label": { "type": "string" }
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
"IRAssertion": {
|
|
249
|
+
"type": "object",
|
|
250
|
+
"required": [
|
|
251
|
+
"id",
|
|
252
|
+
"description",
|
|
253
|
+
"category",
|
|
254
|
+
"severity",
|
|
255
|
+
"assertionType",
|
|
256
|
+
"target",
|
|
257
|
+
"source",
|
|
258
|
+
"reviewed",
|
|
259
|
+
"enabled"
|
|
260
|
+
],
|
|
261
|
+
"additionalProperties": false,
|
|
262
|
+
"properties": {
|
|
263
|
+
"id": { "type": "string" },
|
|
264
|
+
"description": { "type": "string" },
|
|
265
|
+
"category": { "type": "string" },
|
|
266
|
+
"severity": { "type": "string" },
|
|
267
|
+
"assertionType": { "type": "string" },
|
|
268
|
+
"target": { "$ref": "#/$defs/IRAssertionTarget" },
|
|
269
|
+
"source": { "type": "string" },
|
|
270
|
+
"reviewed": { "type": "boolean" },
|
|
271
|
+
"enabled": { "type": "boolean" },
|
|
272
|
+
"precondition": { "type": "string" }
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
"IRGroup": {
|
|
276
|
+
"type": "object",
|
|
277
|
+
"required": ["id", "name", "description", "category", "assertions"],
|
|
278
|
+
"additionalProperties": false,
|
|
279
|
+
"properties": {
|
|
280
|
+
"id": { "type": "string" },
|
|
281
|
+
"name": { "type": "string" },
|
|
282
|
+
"description": { "type": "string" },
|
|
283
|
+
"category": { "type": "string" },
|
|
284
|
+
"assertions": {
|
|
285
|
+
"type": "array",
|
|
286
|
+
"items": { "$ref": "#/$defs/IRAssertion" }
|
|
287
|
+
},
|
|
288
|
+
"source": { "type": "string" },
|
|
289
|
+
"tags": { "type": "array", "items": { "type": "string" } }
|
|
290
|
+
}
|
|
233
291
|
}
|
|
234
292
|
}
|
|
235
293
|
}
|
|
@@ -179,6 +179,7 @@
|
|
|
179
179
|
|
|
180
180
|
import type { IRElementCriteria } from "./element-criteria";
|
|
181
181
|
import type { IRDocument } from "./document";
|
|
182
|
+
import type { IRAssertion, IRGroup } from "./group";
|
|
182
183
|
import type { IRState } from "./state";
|
|
183
184
|
import type { IRTransition, IRTransitionAction, IRWaitSpec } from "./transition";
|
|
184
185
|
|
|
@@ -432,6 +433,55 @@ function buildGroup(state: IRState): LegacyGroup {
|
|
|
432
433
|
};
|
|
433
434
|
}
|
|
434
435
|
|
|
436
|
+
/**
|
|
437
|
+
* Convert an `IRAssertion` (IR-side, free-form criteria) into a `LegacyAssertion`.
|
|
438
|
+
* The shapes are near-identical; the only meaningful difference is that the
|
|
439
|
+
* IR-side `target.criteria` is `Record<string, unknown>` while the legacy
|
|
440
|
+
* shape is `LegacyCriteria` (a typed but extensible record). We pass the
|
|
441
|
+
* criteria object through verbatim — the open `[key: string]: unknown` index
|
|
442
|
+
* signature on `LegacyCriteria` accepts any record shape.
|
|
443
|
+
*/
|
|
444
|
+
function synthesizedAssertionToLegacy(assertion: IRAssertion): LegacyAssertion {
|
|
445
|
+
const target: LegacyAssertionTarget = {
|
|
446
|
+
type: "search",
|
|
447
|
+
criteria: assertion.target.criteria as LegacyCriteria,
|
|
448
|
+
label: assertion.target.label,
|
|
449
|
+
};
|
|
450
|
+
const out: LegacyAssertion = {
|
|
451
|
+
id: assertion.id,
|
|
452
|
+
description: assertion.description,
|
|
453
|
+
category: assertion.category,
|
|
454
|
+
severity: assertion.severity as LegacyAssertion["severity"],
|
|
455
|
+
assertionType: assertion.assertionType,
|
|
456
|
+
target,
|
|
457
|
+
source: assertion.source,
|
|
458
|
+
reviewed: assertion.reviewed,
|
|
459
|
+
enabled: assertion.enabled,
|
|
460
|
+
};
|
|
461
|
+
if (assertion.precondition !== undefined) {
|
|
462
|
+
out.precondition = assertion.precondition;
|
|
463
|
+
}
|
|
464
|
+
return out;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Convert a synthesized `IRGroup` into a `LegacyGroup`. Mirrors the legacy
|
|
469
|
+
* shape one-to-one (modulo the free-form criteria pass-through described in
|
|
470
|
+
* `synthesizedAssertionToLegacy`). The synthesized group always carries a
|
|
471
|
+
* `source` (synthesis emits `"ai-generated"`); fall back to `"ai-generated"`
|
|
472
|
+
* for hand-written IR documents that omit it.
|
|
473
|
+
*/
|
|
474
|
+
function synthesizedGroupToLegacy(group: IRGroup): LegacyGroup {
|
|
475
|
+
return {
|
|
476
|
+
id: group.id,
|
|
477
|
+
name: group.name,
|
|
478
|
+
description: group.description,
|
|
479
|
+
category: group.category,
|
|
480
|
+
assertions: group.assertions.map(synthesizedAssertionToLegacy),
|
|
481
|
+
source: group.source ?? "ai-generated",
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
|
|
435
485
|
/**
|
|
436
486
|
* Convert an IR transition action into the legacy `process[]` step shape.
|
|
437
487
|
* Renames IR's `type` to legacy `action` (matches the runtime engine
|
|
@@ -520,6 +570,14 @@ export function projectIRToBundledPage(doc: IRDocument, notes?: string): LegacyS
|
|
|
520
570
|
if (doc.metadata?.tags !== undefined) metadata.tags = doc.metadata.tags;
|
|
521
571
|
|
|
522
572
|
const groups: LegacyGroup[] = doc.states.map(buildGroup);
|
|
573
|
+
if (doc.synthesizedGroups !== undefined) {
|
|
574
|
+
// Append synthesis-produced groups AFTER state-derived ones, in declared
|
|
575
|
+
// order. Byte-stable output (see file header) requires this exact ordering
|
|
576
|
+
// — anything else breaks `check-spec-pairing` style hashes.
|
|
577
|
+
for (const g of doc.synthesizedGroups) {
|
|
578
|
+
groups.push(synthesizedGroupToLegacy(g));
|
|
579
|
+
}
|
|
580
|
+
}
|
|
523
581
|
const smStates: LegacyStateMachineState[] = doc.states.map((s) =>
|
|
524
582
|
buildStateMachineState(s, doc.transitions, doc),
|
|
525
583
|
);
|