@contractspec/example.policy-safe-knowledge-assistant 3.7.17 → 3.7.19

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 (45) hide show
  1. package/.turbo/turbo-build.log +45 -45
  2. package/CHANGELOG.md +35 -0
  3. package/dist/browser/docs/index.js +3 -27
  4. package/dist/browser/docs/policy-safe-knowledge-assistant.docblock.js +3 -27
  5. package/dist/browser/example.js +1 -37
  6. package/dist/browser/handlers/index.js +5 -334
  7. package/dist/browser/handlers/policy-safe-knowledge-assistant.handlers.js +5 -334
  8. package/dist/browser/index.js +7 -913
  9. package/dist/browser/orchestrator/buildAnswer.js +1 -73
  10. package/dist/browser/policy-safe-knowledge-assistant.feature.js +1 -64
  11. package/dist/browser/seed/fixtures.js +1 -35
  12. package/dist/browser/seed/index.js +1 -35
  13. package/dist/browser/seeders/index.js +2 -12
  14. package/dist/browser/ui/PolicySafeKnowledgeAssistantDashboard.js +1 -420
  15. package/dist/browser/ui/hooks/usePolicySafeKnowledgeAssistant.js +1 -154
  16. package/dist/browser/ui/index.js +1 -420
  17. package/dist/docs/index.js +3 -27
  18. package/dist/docs/policy-safe-knowledge-assistant.docblock.js +3 -27
  19. package/dist/example.js +1 -37
  20. package/dist/handlers/index.js +5 -334
  21. package/dist/handlers/policy-safe-knowledge-assistant.handlers.js +5 -334
  22. package/dist/index.js +7 -913
  23. package/dist/node/docs/index.js +3 -27
  24. package/dist/node/docs/policy-safe-knowledge-assistant.docblock.js +3 -27
  25. package/dist/node/example.js +1 -37
  26. package/dist/node/handlers/index.js +5 -334
  27. package/dist/node/handlers/policy-safe-knowledge-assistant.handlers.js +5 -334
  28. package/dist/node/index.js +7 -913
  29. package/dist/node/orchestrator/buildAnswer.js +1 -73
  30. package/dist/node/policy-safe-knowledge-assistant.feature.js +1 -64
  31. package/dist/node/seed/fixtures.js +1 -35
  32. package/dist/node/seed/index.js +1 -35
  33. package/dist/node/seeders/index.js +2 -12
  34. package/dist/node/ui/PolicySafeKnowledgeAssistantDashboard.js +1 -420
  35. package/dist/node/ui/hooks/usePolicySafeKnowledgeAssistant.js +1 -154
  36. package/dist/node/ui/index.js +1 -420
  37. package/dist/orchestrator/buildAnswer.js +1 -73
  38. package/dist/policy-safe-knowledge-assistant.feature.js +1 -64
  39. package/dist/seed/fixtures.js +1 -35
  40. package/dist/seed/index.js +1 -35
  41. package/dist/seeders/index.js +2 -12
  42. package/dist/ui/PolicySafeKnowledgeAssistantDashboard.js +1 -420
  43. package/dist/ui/hooks/usePolicySafeKnowledgeAssistant.js +1 -154
  44. package/dist/ui/index.js +1 -420
  45. package/package.json +13 -13
@@ -1,155 +1,2 @@
1
1
  // @bun
2
- // src/ui/hooks/usePolicySafeKnowledgeAssistant.ts
3
- import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
4
- import { useCallback, useEffect, useMemo, useState } from "react";
5
- "use client";
6
- function isCitationLike(value) {
7
- if (!value || typeof value !== "object")
8
- return false;
9
- const v = value;
10
- return typeof v.kbSnapshotId === "string" && typeof v.sourceId === "string";
11
- }
12
- function toCitations(value) {
13
- if (!Array.isArray(value))
14
- return [];
15
- return value.filter(isCitationLike).map((c) => ({
16
- kbSnapshotId: c.kbSnapshotId,
17
- sourceId: c.sourceId,
18
- excerpt: c.excerpt
19
- }));
20
- }
21
- function usePolicySafeKnowledgeAssistant() {
22
- const { handlers, projectId } = useTemplateRuntime();
23
- const api = handlers.policySafeKnowledgeAssistant;
24
- const [state, setState] = useState({
25
- context: null,
26
- loading: true,
27
- error: null,
28
- lastAnswer: null,
29
- lastRuleId: null,
30
- lastRuleVersionId: null,
31
- lastSnapshotId: null,
32
- lastReviewTaskId: null
33
- });
34
- const refreshContext = useCallback(async () => {
35
- try {
36
- setState((s) => ({ ...s, loading: true, error: null }));
37
- const ctx = await api.getUserContext({ projectId });
38
- setState((s) => ({
39
- ...s,
40
- context: {
41
- locale: ctx.locale,
42
- jurisdiction: ctx.jurisdiction,
43
- allowedScope: ctx.allowedScope,
44
- kbSnapshotId: ctx.kbSnapshotId
45
- },
46
- loading: false
47
- }));
48
- } catch (e) {
49
- setState((s) => ({
50
- ...s,
51
- loading: false,
52
- error: e instanceof Error ? e : new Error("Unknown error")
53
- }));
54
- }
55
- }, [api, projectId]);
56
- useEffect(() => {
57
- refreshContext();
58
- }, [refreshContext]);
59
- const setContext = useCallback(async (input) => {
60
- const ctx = await api.setUserContext({ projectId, ...input });
61
- setState((s) => ({
62
- ...s,
63
- context: {
64
- locale: ctx.locale,
65
- jurisdiction: ctx.jurisdiction,
66
- allowedScope: ctx.allowedScope,
67
- kbSnapshotId: ctx.kbSnapshotId
68
- }
69
- }));
70
- }, [api, projectId]);
71
- const askAssistant = useCallback(async (question) => {
72
- const answerUnknown = await api.answer({ projectId, question });
73
- const answer = answerUnknown;
74
- setState((s) => ({
75
- ...s,
76
- lastAnswer: {
77
- refused: answer.refused,
78
- refusalReason: answer.refusalReason,
79
- sections: answer.sections,
80
- citations: toCitations(answerUnknown.citations)
81
- }
82
- }));
83
- }, [api, projectId]);
84
- const createDemoRule = useCallback(async () => {
85
- const rule = await api.createRule({
86
- projectId,
87
- jurisdiction: state.context?.jurisdiction ?? "EU",
88
- topicKey: "tax_reporting"
89
- });
90
- setState((s) => ({ ...s, lastRuleId: rule.id }));
91
- return rule.id;
92
- }, [api, projectId, state.context?.jurisdiction]);
93
- const upsertRuleVersion = useCallback(async (input) => {
94
- const rv = await api.upsertRuleVersion({
95
- projectId,
96
- ruleId: input.ruleId,
97
- content: input.content,
98
- sourceRefs: [{ sourceDocumentId: "src_demo", excerpt: "demo excerpt" }]
99
- });
100
- setState((s) => ({ ...s, lastRuleVersionId: rv.id }));
101
- return rv.id;
102
- }, [api, projectId]);
103
- const approveRuleVersion = useCallback(async (ruleVersionId) => {
104
- await api.approveRuleVersion({ ruleVersionId, approver: "demo_expert" });
105
- }, [api]);
106
- const publishSnapshot = useCallback(async () => {
107
- const snap = await api.publishSnapshot({
108
- projectId,
109
- jurisdiction: state.context?.jurisdiction ?? "EU",
110
- asOfDate: new Date("2026-02-01T00:00:00.000Z")
111
- });
112
- setState((s) => ({ ...s, lastSnapshotId: snap.id }));
113
- await refreshContext();
114
- return snap.id;
115
- }, [api, projectId, refreshContext, state.context?.jurisdiction]);
116
- const simulateHighRiskChangeAndApprove = useCallback(async (ruleVersionId) => {
117
- const cand = await api.createChangeCandidate({
118
- projectId,
119
- jurisdiction: state.context?.jurisdiction ?? "EU",
120
- diffSummary: "Simulated change (demo)",
121
- riskLevel: "high",
122
- proposedRuleVersionIds: [ruleVersionId]
123
- });
124
- const review = await api.createReviewTask({ changeCandidateId: cand.id });
125
- setState((s) => ({ ...s, lastReviewTaskId: review.id }));
126
- await api.submitDecision({
127
- reviewTaskId: review.id,
128
- decision: "approve",
129
- decidedByRole: "expert",
130
- decidedBy: "demo_expert"
131
- });
132
- await api.publishIfReady({
133
- jurisdiction: state.context?.jurisdiction ?? "EU"
134
- });
135
- return review.id;
136
- }, [api, projectId, state.context?.jurisdiction]);
137
- const derived = useMemo(() => ({ projectId }), [projectId]);
138
- return {
139
- state,
140
- derived,
141
- actions: {
142
- refreshContext,
143
- setContext,
144
- askAssistant,
145
- createDemoRule,
146
- upsertRuleVersion,
147
- approveRuleVersion,
148
- publishSnapshot,
149
- simulateHighRiskChangeAndApprove
150
- }
151
- };
152
- }
153
- export {
154
- usePolicySafeKnowledgeAssistant
155
- };
2
+ import{useTemplateRuntime as X}from"@contractspec/lib.example-shared-ui";import{useCallback as J,useEffect as Y,useMemo as Z,useState as _}from"react";function $(F){if(!F||typeof F!=="object")return!1;let j=F;return typeof j.kbSnapshotId==="string"&&typeof j.sourceId==="string"}function D(F){if(!Array.isArray(F))return[];return F.filter($).map((j)=>({kbSnapshotId:j.kbSnapshotId,sourceId:j.sourceId,excerpt:j.excerpt}))}function m(){let{handlers:F,projectId:j}=X(),z=F.policySafeKnowledgeAssistant,[G,E]=_({context:null,loading:!0,error:null,lastAnswer:null,lastRuleId:null,lastRuleVersionId:null,lastSnapshotId:null,lastReviewTaskId:null}),K=J(async()=>{try{E((y)=>({...y,loading:!0,error:null}));let b=await z.getUserContext({projectId:j});E((y)=>({...y,context:{locale:b.locale,jurisdiction:b.jurisdiction,allowedScope:b.allowedScope,kbSnapshotId:b.kbSnapshotId},loading:!1}))}catch(b){E((y)=>({...y,loading:!1,error:b instanceof Error?b:Error("Unknown error")}))}},[z,j]);Y(()=>{K()},[K]);let M=J(async(b)=>{let y=await z.setUserContext({projectId:j,...b});E((B)=>({...B,context:{locale:y.locale,jurisdiction:y.jurisdiction,allowedScope:y.allowedScope,kbSnapshotId:y.kbSnapshotId}}))},[z,j]),N=J(async(b)=>{let y=await z.answer({projectId:j,question:b}),B=y;E((L)=>({...L,lastAnswer:{refused:B.refused,refusalReason:B.refusalReason,sections:B.sections,citations:D(y.citations)}}))},[z,j]),O=J(async()=>{let b=await z.createRule({projectId:j,jurisdiction:G.context?.jurisdiction??"EU",topicKey:"tax_reporting"});return E((y)=>({...y,lastRuleId:b.id})),b.id},[z,j,G.context?.jurisdiction]),P=J(async(b)=>{let y=await z.upsertRuleVersion({projectId:j,ruleId:b.ruleId,content:b.content,sourceRefs:[{sourceDocumentId:"src_demo",excerpt:"demo excerpt"}]});return E((B)=>({...B,lastRuleVersionId:y.id})),y.id},[z,j]),Q=J(async(b)=>{await z.approveRuleVersion({ruleVersionId:b,approver:"demo_expert"})},[z]),S=J(async()=>{let b=await z.publishSnapshot({projectId:j,jurisdiction:G.context?.jurisdiction??"EU",asOfDate:new Date("2026-02-01T00:00:00.000Z")});return E((y)=>({...y,lastSnapshotId:b.id})),await K(),b.id},[z,j,K,G.context?.jurisdiction]),T=J(async(b)=>{let y=await z.createChangeCandidate({projectId:j,jurisdiction:G.context?.jurisdiction??"EU",diffSummary:"Simulated change (demo)",riskLevel:"high",proposedRuleVersionIds:[b]}),B=await z.createReviewTask({changeCandidateId:y.id});return E((L)=>({...L,lastReviewTaskId:B.id})),await z.submitDecision({reviewTaskId:B.id,decision:"approve",decidedByRole:"expert",decidedBy:"demo_expert"}),await z.publishIfReady({jurisdiction:G.context?.jurisdiction??"EU"}),B.id},[z,j,G.context?.jurisdiction]),W=Z(()=>({projectId:j}),[j]);return{state:G,derived:W,actions:{refreshContext:K,setContext:M,askAssistant:N,createDemoRule:O,upsertRuleVersion:P,approveRuleVersion:Q,publishSnapshot:S,simulateHighRiskChangeAndApprove:T}}}export{m as usePolicySafeKnowledgeAssistant};
package/dist/ui/index.js CHANGED
@@ -1,421 +1,2 @@
1
1
  // @bun
2
- // src/ui/hooks/usePolicySafeKnowledgeAssistant.ts
3
- import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
4
- import { useCallback, useEffect, useMemo, useState } from "react";
5
- "use client";
6
- function isCitationLike(value) {
7
- if (!value || typeof value !== "object")
8
- return false;
9
- const v = value;
10
- return typeof v.kbSnapshotId === "string" && typeof v.sourceId === "string";
11
- }
12
- function toCitations(value) {
13
- if (!Array.isArray(value))
14
- return [];
15
- return value.filter(isCitationLike).map((c) => ({
16
- kbSnapshotId: c.kbSnapshotId,
17
- sourceId: c.sourceId,
18
- excerpt: c.excerpt
19
- }));
20
- }
21
- function usePolicySafeKnowledgeAssistant() {
22
- const { handlers, projectId } = useTemplateRuntime();
23
- const api = handlers.policySafeKnowledgeAssistant;
24
- const [state, setState] = useState({
25
- context: null,
26
- loading: true,
27
- error: null,
28
- lastAnswer: null,
29
- lastRuleId: null,
30
- lastRuleVersionId: null,
31
- lastSnapshotId: null,
32
- lastReviewTaskId: null
33
- });
34
- const refreshContext = useCallback(async () => {
35
- try {
36
- setState((s) => ({ ...s, loading: true, error: null }));
37
- const ctx = await api.getUserContext({ projectId });
38
- setState((s) => ({
39
- ...s,
40
- context: {
41
- locale: ctx.locale,
42
- jurisdiction: ctx.jurisdiction,
43
- allowedScope: ctx.allowedScope,
44
- kbSnapshotId: ctx.kbSnapshotId
45
- },
46
- loading: false
47
- }));
48
- } catch (e) {
49
- setState((s) => ({
50
- ...s,
51
- loading: false,
52
- error: e instanceof Error ? e : new Error("Unknown error")
53
- }));
54
- }
55
- }, [api, projectId]);
56
- useEffect(() => {
57
- refreshContext();
58
- }, [refreshContext]);
59
- const setContext = useCallback(async (input) => {
60
- const ctx = await api.setUserContext({ projectId, ...input });
61
- setState((s) => ({
62
- ...s,
63
- context: {
64
- locale: ctx.locale,
65
- jurisdiction: ctx.jurisdiction,
66
- allowedScope: ctx.allowedScope,
67
- kbSnapshotId: ctx.kbSnapshotId
68
- }
69
- }));
70
- }, [api, projectId]);
71
- const askAssistant = useCallback(async (question) => {
72
- const answerUnknown = await api.answer({ projectId, question });
73
- const answer = answerUnknown;
74
- setState((s) => ({
75
- ...s,
76
- lastAnswer: {
77
- refused: answer.refused,
78
- refusalReason: answer.refusalReason,
79
- sections: answer.sections,
80
- citations: toCitations(answerUnknown.citations)
81
- }
82
- }));
83
- }, [api, projectId]);
84
- const createDemoRule = useCallback(async () => {
85
- const rule = await api.createRule({
86
- projectId,
87
- jurisdiction: state.context?.jurisdiction ?? "EU",
88
- topicKey: "tax_reporting"
89
- });
90
- setState((s) => ({ ...s, lastRuleId: rule.id }));
91
- return rule.id;
92
- }, [api, projectId, state.context?.jurisdiction]);
93
- const upsertRuleVersion = useCallback(async (input) => {
94
- const rv = await api.upsertRuleVersion({
95
- projectId,
96
- ruleId: input.ruleId,
97
- content: input.content,
98
- sourceRefs: [{ sourceDocumentId: "src_demo", excerpt: "demo excerpt" }]
99
- });
100
- setState((s) => ({ ...s, lastRuleVersionId: rv.id }));
101
- return rv.id;
102
- }, [api, projectId]);
103
- const approveRuleVersion = useCallback(async (ruleVersionId) => {
104
- await api.approveRuleVersion({ ruleVersionId, approver: "demo_expert" });
105
- }, [api]);
106
- const publishSnapshot = useCallback(async () => {
107
- const snap = await api.publishSnapshot({
108
- projectId,
109
- jurisdiction: state.context?.jurisdiction ?? "EU",
110
- asOfDate: new Date("2026-02-01T00:00:00.000Z")
111
- });
112
- setState((s) => ({ ...s, lastSnapshotId: snap.id }));
113
- await refreshContext();
114
- return snap.id;
115
- }, [api, projectId, refreshContext, state.context?.jurisdiction]);
116
- const simulateHighRiskChangeAndApprove = useCallback(async (ruleVersionId) => {
117
- const cand = await api.createChangeCandidate({
118
- projectId,
119
- jurisdiction: state.context?.jurisdiction ?? "EU",
120
- diffSummary: "Simulated change (demo)",
121
- riskLevel: "high",
122
- proposedRuleVersionIds: [ruleVersionId]
123
- });
124
- const review = await api.createReviewTask({ changeCandidateId: cand.id });
125
- setState((s) => ({ ...s, lastReviewTaskId: review.id }));
126
- await api.submitDecision({
127
- reviewTaskId: review.id,
128
- decision: "approve",
129
- decidedByRole: "expert",
130
- decidedBy: "demo_expert"
131
- });
132
- await api.publishIfReady({
133
- jurisdiction: state.context?.jurisdiction ?? "EU"
134
- });
135
- return review.id;
136
- }, [api, projectId, state.context?.jurisdiction]);
137
- const derived = useMemo(() => ({ projectId }), [projectId]);
138
- return {
139
- state,
140
- derived,
141
- actions: {
142
- refreshContext,
143
- setContext,
144
- askAssistant,
145
- createDemoRule,
146
- upsertRuleVersion,
147
- approveRuleVersion,
148
- publishSnapshot,
149
- simulateHighRiskChangeAndApprove
150
- }
151
- };
152
- }
153
-
154
- // src/ui/PolicySafeKnowledgeAssistantDashboard.tsx
155
- import {
156
- Button,
157
- ErrorState,
158
- LoaderBlock,
159
- StatCard,
160
- StatCardGroup
161
- } from "@contractspec/lib.design-system";
162
- import { Card } from "@contractspec/lib.ui-kit-web/ui/card";
163
- import { Input } from "@contractspec/lib.ui-kit-web/ui/input";
164
- import {
165
- Select,
166
- SelectContent,
167
- SelectItem,
168
- SelectTrigger,
169
- SelectValue
170
- } from "@contractspec/lib.ui-kit-web/ui/select";
171
- import { Textarea } from "@contractspec/lib.ui-kit-web/ui/textarea";
172
- import { useCallback as useCallback2, useMemo as useMemo2, useState as useState2 } from "react";
173
- import { jsxDEV } from "react/jsx-dev-runtime";
174
- "use client";
175
- function PolicySafeKnowledgeAssistantDashboard() {
176
- const { state, actions } = usePolicySafeKnowledgeAssistant();
177
- const [question, setQuestion] = useState2("reporting obligations");
178
- const [content, setContent] = useState2("EU: Reporting obligations v2 (updated)");
179
- const [locale, setLocale] = useState2("en-GB");
180
- const [jurisdiction, setJurisdiction] = useState2("EU");
181
- const [allowedScope, setAllowedScope] = useState2("education_only");
182
- const snapshotId = state.context?.kbSnapshotId ?? state.lastSnapshotId ?? null;
183
- const stats = useMemo2(() => {
184
- return [
185
- { label: "Locale", value: state.context?.locale ?? "\u2014" },
186
- { label: "Jurisdiction", value: state.context?.jurisdiction ?? "\u2014" },
187
- { label: "Scope", value: state.context?.allowedScope ?? "\u2014" },
188
- { label: "KB Snapshot", value: snapshotId ?? "\u2014" }
189
- ];
190
- }, [
191
- snapshotId,
192
- state.context?.allowedScope,
193
- state.context?.jurisdiction,
194
- state.context?.locale
195
- ]);
196
- const handleSetContext = useCallback2(async () => {
197
- await actions.setContext({ locale, jurisdiction, allowedScope });
198
- }, [actions, allowedScope, jurisdiction, locale]);
199
- const handleAsk = useCallback2(async () => {
200
- await actions.askAssistant(question);
201
- }, [actions, question]);
202
- const handleAdminPublishFlow = useCallback2(async () => {
203
- const ruleId = state.lastRuleId ?? await actions.createDemoRule();
204
- const rvId = await actions.upsertRuleVersion({ ruleId, content });
205
- await actions.approveRuleVersion(rvId);
206
- await actions.simulateHighRiskChangeAndApprove(rvId);
207
- await actions.publishSnapshot();
208
- }, [actions, content, state.lastRuleId]);
209
- if (state.loading && !state.context) {
210
- return /* @__PURE__ */ jsxDEV(LoaderBlock, {
211
- label: "Loading demo..."
212
- }, undefined, false, undefined, this);
213
- }
214
- if (state.error) {
215
- return /* @__PURE__ */ jsxDEV(ErrorState, {
216
- title: "Failed to load demo",
217
- description: state.error.message,
218
- onRetry: actions.refreshContext,
219
- retryLabel: "Retry"
220
- }, undefined, false, undefined, this);
221
- }
222
- return /* @__PURE__ */ jsxDEV("div", {
223
- className: "space-y-6",
224
- children: [
225
- /* @__PURE__ */ jsxDEV(StatCardGroup, {
226
- children: stats.map((s) => /* @__PURE__ */ jsxDEV(StatCard, {
227
- label: s.label,
228
- value: String(s.value)
229
- }, s.label, false, undefined, this))
230
- }, undefined, false, undefined, this),
231
- /* @__PURE__ */ jsxDEV(Card, {
232
- className: "p-4",
233
- children: [
234
- /* @__PURE__ */ jsxDEV("h3", {
235
- className: "font-semibold text-lg",
236
- children: "1) Onboarding (explicit locale + jurisdiction)"
237
- }, undefined, false, undefined, this),
238
- /* @__PURE__ */ jsxDEV("div", {
239
- className: "mt-3 grid gap-3 md:grid-cols-3",
240
- children: [
241
- /* @__PURE__ */ jsxDEV("div", {
242
- children: [
243
- /* @__PURE__ */ jsxDEV("div", {
244
- className: "mb-1 font-semibold text-muted-foreground text-xs uppercase tracking-wide",
245
- children: "Locale"
246
- }, undefined, false, undefined, this),
247
- /* @__PURE__ */ jsxDEV(Input, {
248
- value: locale,
249
- onChange: (e) => setLocale(e.target.value)
250
- }, undefined, false, undefined, this)
251
- ]
252
- }, undefined, true, undefined, this),
253
- /* @__PURE__ */ jsxDEV("div", {
254
- children: [
255
- /* @__PURE__ */ jsxDEV("div", {
256
- className: "mb-1 font-semibold text-muted-foreground text-xs uppercase tracking-wide",
257
- children: "Jurisdiction"
258
- }, undefined, false, undefined, this),
259
- /* @__PURE__ */ jsxDEV(Input, {
260
- value: jurisdiction,
261
- onChange: (e) => setJurisdiction(e.target.value)
262
- }, undefined, false, undefined, this)
263
- ]
264
- }, undefined, true, undefined, this),
265
- /* @__PURE__ */ jsxDEV("div", {
266
- children: [
267
- /* @__PURE__ */ jsxDEV("div", {
268
- className: "mb-1 font-semibold text-muted-foreground text-xs uppercase tracking-wide",
269
- children: "Allowed scope"
270
- }, undefined, false, undefined, this),
271
- /* @__PURE__ */ jsxDEV(Select, {
272
- value: allowedScope,
273
- onValueChange: (v) => setAllowedScope(v),
274
- children: [
275
- /* @__PURE__ */ jsxDEV(SelectTrigger, {
276
- children: /* @__PURE__ */ jsxDEV(SelectValue, {
277
- placeholder: "Select scope"
278
- }, undefined, false, undefined, this)
279
- }, undefined, false, undefined, this),
280
- /* @__PURE__ */ jsxDEV(SelectContent, {
281
- children: [
282
- /* @__PURE__ */ jsxDEV(SelectItem, {
283
- value: "education_only",
284
- children: "education_only"
285
- }, undefined, false, undefined, this),
286
- /* @__PURE__ */ jsxDEV(SelectItem, {
287
- value: "generic_info",
288
- children: "generic_info"
289
- }, undefined, false, undefined, this),
290
- /* @__PURE__ */ jsxDEV(SelectItem, {
291
- value: "escalation_required",
292
- children: "escalation_required"
293
- }, undefined, false, undefined, this)
294
- ]
295
- }, undefined, true, undefined, this)
296
- ]
297
- }, undefined, true, undefined, this)
298
- ]
299
- }, undefined, true, undefined, this)
300
- ]
301
- }, undefined, true, undefined, this),
302
- /* @__PURE__ */ jsxDEV("div", {
303
- className: "mt-4 flex gap-2",
304
- children: [
305
- /* @__PURE__ */ jsxDEV(Button, {
306
- onPress: handleSetContext,
307
- children: "Save context"
308
- }, undefined, false, undefined, this),
309
- /* @__PURE__ */ jsxDEV(Button, {
310
- variant: "outline",
311
- onPress: actions.refreshContext,
312
- children: "Refresh"
313
- }, undefined, false, undefined, this)
314
- ]
315
- }, undefined, true, undefined, this)
316
- ]
317
- }, undefined, true, undefined, this),
318
- /* @__PURE__ */ jsxDEV(Card, {
319
- className: "p-4",
320
- children: [
321
- /* @__PURE__ */ jsxDEV("h3", {
322
- className: "font-semibold text-lg",
323
- children: "2) Ask the assistant (must cite KB snapshot)"
324
- }, undefined, false, undefined, this),
325
- /* @__PURE__ */ jsxDEV("div", {
326
- className: "mt-3 flex flex-col gap-3",
327
- children: [
328
- /* @__PURE__ */ jsxDEV(Input, {
329
- value: question,
330
- onChange: (e) => setQuestion(e.target.value)
331
- }, undefined, false, undefined, this),
332
- /* @__PURE__ */ jsxDEV("div", {
333
- className: "flex gap-2",
334
- children: /* @__PURE__ */ jsxDEV(Button, {
335
- onPress: handleAsk,
336
- children: "Ask"
337
- }, undefined, false, undefined, this)
338
- }, undefined, false, undefined, this)
339
- ]
340
- }, undefined, true, undefined, this),
341
- state.lastAnswer ? /* @__PURE__ */ jsxDEV("div", {
342
- className: "mt-4 space-y-3",
343
- children: [
344
- state.lastAnswer.refused ? /* @__PURE__ */ jsxDEV("div", {
345
- className: "text-red-600 text-sm",
346
- children: [
347
- "Refused: ",
348
- state.lastAnswer.refusalReason ?? "UNKNOWN"
349
- ]
350
- }, undefined, true, undefined, this) : null,
351
- state.lastAnswer.sections.map((s, idx) => /* @__PURE__ */ jsxDEV("div", {
352
- children: [
353
- /* @__PURE__ */ jsxDEV("div", {
354
- className: "font-semibold text-sm",
355
- children: s.heading
356
- }, undefined, false, undefined, this),
357
- /* @__PURE__ */ jsxDEV("div", {
358
- className: "text-muted-foreground text-sm",
359
- children: s.body
360
- }, undefined, false, undefined, this)
361
- ]
362
- }, `${s.heading}-${idx}`, true, undefined, this)),
363
- /* @__PURE__ */ jsxDEV("div", {
364
- className: "font-semibold text-sm",
365
- children: "Citations"
366
- }, undefined, false, undefined, this),
367
- /* @__PURE__ */ jsxDEV("ul", {
368
- className: "list-disc pl-5 text-muted-foreground text-sm",
369
- children: state.lastAnswer.citations.map((c) => /* @__PURE__ */ jsxDEV("li", {
370
- children: [
371
- c.kbSnapshotId,
372
- " \u2014 ",
373
- c.sourceId
374
- ]
375
- }, `${c.kbSnapshotId}-${c.sourceId}`, true, undefined, this))
376
- }, undefined, false, undefined, this)
377
- ]
378
- }, undefined, true, undefined, this) : null
379
- ]
380
- }, undefined, true, undefined, this),
381
- /* @__PURE__ */ jsxDEV(Card, {
382
- className: "p-4",
383
- children: [
384
- /* @__PURE__ */ jsxDEV("h3", {
385
- className: "font-semibold text-lg",
386
- children: "3) Admin: publish a new snapshot (HITL)"
387
- }, undefined, false, undefined, this),
388
- /* @__PURE__ */ jsxDEV("div", {
389
- className: "mt-3 space-y-3",
390
- children: [
391
- /* @__PURE__ */ jsxDEV(Textarea, {
392
- value: content,
393
- onChange: (e) => setContent(e.target.value)
394
- }, undefined, false, undefined, this),
395
- /* @__PURE__ */ jsxDEV(Button, {
396
- onPress: handleAdminPublishFlow,
397
- children: "Simulate change \u2192 review \u2192 approve \u2192 publish snapshot"
398
- }, undefined, false, undefined, this)
399
- ]
400
- }, undefined, true, undefined, this)
401
- ]
402
- }, undefined, true, undefined, this),
403
- /* @__PURE__ */ jsxDEV(Card, {
404
- className: "p-4",
405
- children: [
406
- /* @__PURE__ */ jsxDEV("h3", {
407
- className: "font-semibold text-lg",
408
- children: "4) Learning hub (patterns)"
409
- }, undefined, false, undefined, this),
410
- /* @__PURE__ */ jsxDEV("p", {
411
- className: "mt-2 text-muted-foreground text-sm",
412
- children: "This template includes drills, ambient coach, and quests as reusable Learning Journey tracks. The interactive learning UI is demonstrated in dedicated Learning Journey examples."
413
- }, undefined, false, undefined, this)
414
- ]
415
- }, undefined, true, undefined, this)
416
- ]
417
- }, undefined, true, undefined, this);
418
- }
419
- export {
420
- PolicySafeKnowledgeAssistantDashboard
421
- };
2
+ import{useTemplateRuntime as f}from"@contractspec/lib.example-shared-ui";import{useCallback as G,useEffect as m,useMemo as A,useState as k}from"react";function v(O){if(!O||typeof O!=="object")return!1;let z=O;return typeof z.kbSnapshotId==="string"&&typeof z.sourceId==="string"}function I(O){if(!Array.isArray(O))return[];return O.filter(v).map((z)=>({kbSnapshotId:z.kbSnapshotId,sourceId:z.sourceId,excerpt:z.excerpt}))}function g(){let{handlers:O,projectId:z}=f(),Z=O.policySafeKnowledgeAssistant,[F,$]=k({context:null,loading:!0,error:null,lastAnswer:null,lastRuleId:null,lastRuleVersionId:null,lastSnapshotId:null,lastReviewTaskId:null}),H=G(async()=>{try{$((Y)=>({...Y,loading:!0,error:null}));let X=await Z.getUserContext({projectId:z});$((Y)=>({...Y,context:{locale:X.locale,jurisdiction:X.jurisdiction,allowedScope:X.allowedScope,kbSnapshotId:X.kbSnapshotId},loading:!1}))}catch(X){$((Y)=>({...Y,loading:!1,error:X instanceof Error?X:Error("Unknown error")}))}},[Z,z]);m(()=>{H()},[H]);let J=G(async(X)=>{let Y=await Z.setUserContext({projectId:z,...X});$((E)=>({...E,context:{locale:Y.locale,jurisdiction:Y.jurisdiction,allowedScope:Y.allowedScope,kbSnapshotId:Y.kbSnapshotId}}))},[Z,z]),K=G(async(X)=>{let Y=await Z.answer({projectId:z,question:X}),E=Y;$((W)=>({...W,lastAnswer:{refused:E.refused,refusalReason:E.refusalReason,sections:E.sections,citations:I(Y.citations)}}))},[Z,z]),M=G(async()=>{let X=await Z.createRule({projectId:z,jurisdiction:F.context?.jurisdiction??"EU",topicKey:"tax_reporting"});return $((Y)=>({...Y,lastRuleId:X.id})),X.id},[Z,z,F.context?.jurisdiction]),R=G(async(X)=>{let Y=await Z.upsertRuleVersion({projectId:z,ruleId:X.ruleId,content:X.content,sourceRefs:[{sourceDocumentId:"src_demo",excerpt:"demo excerpt"}]});return $((E)=>({...E,lastRuleVersionId:Y.id})),Y.id},[Z,z]),Q=G(async(X)=>{await Z.approveRuleVersion({ruleVersionId:X,approver:"demo_expert"})},[Z]),P=G(async()=>{let X=await Z.publishSnapshot({projectId:z,jurisdiction:F.context?.jurisdiction??"EU",asOfDate:new Date("2026-02-01T00:00:00.000Z")});return $((Y)=>({...Y,lastSnapshotId:X.id})),await H(),X.id},[Z,z,H,F.context?.jurisdiction]),L=G(async(X)=>{let Y=await Z.createChangeCandidate({projectId:z,jurisdiction:F.context?.jurisdiction??"EU",diffSummary:"Simulated change (demo)",riskLevel:"high",proposedRuleVersionIds:[X]}),E=await Z.createReviewTask({changeCandidateId:Y.id});return $((W)=>({...W,lastReviewTaskId:E.id})),await Z.submitDecision({reviewTaskId:E.id,decision:"approve",decidedByRole:"expert",decidedBy:"demo_expert"}),await Z.publishIfReady({jurisdiction:F.context?.jurisdiction??"EU"}),E.id},[Z,z,F.context?.jurisdiction]),b=A(()=>({projectId:z}),[z]);return{state:F,derived:b,actions:{refreshContext:H,setContext:J,askAssistant:K,createDemoRule:M,upsertRuleVersion:R,approveRuleVersion:Q,publishSnapshot:P,simulateHighRiskChangeAndApprove:L}}}import{Button as U,ErrorState as h,LoaderBlock as w,StatCard as C,StatCardGroup as S}from"@contractspec/lib.design-system";import{Card as y}from"@contractspec/lib.ui-kit-web/ui/card";import{Input as q}from"@contractspec/lib.ui-kit-web/ui/input";import{Select as d,SelectContent as p,SelectItem as B,SelectTrigger as u,SelectValue as j}from"@contractspec/lib.ui-kit-web/ui/select";import{Textarea as l}from"@contractspec/lib.ui-kit-web/ui/textarea";import{useCallback as V,useMemo as c,useState as D}from"react";import{jsx as N,jsxs as _}from"react/jsx-runtime";function Nz(){let{state:O,actions:z}=g(),[Z,F]=D("reporting obligations"),[$,H]=D("EU: Reporting obligations v2 (updated)"),[J,K]=D("en-GB"),[M,R]=D("EU"),[Q,P]=D("education_only"),L=O.context?.kbSnapshotId??O.lastSnapshotId??null,b=c(()=>{return[{label:"Locale",value:O.context?.locale??"\u2014"},{label:"Jurisdiction",value:O.context?.jurisdiction??"\u2014"},{label:"Scope",value:O.context?.allowedScope??"\u2014"},{label:"KB Snapshot",value:L??"\u2014"}]},[L,O.context?.allowedScope,O.context?.jurisdiction,O.context?.locale]),X=V(async()=>{await z.setContext({locale:J,jurisdiction:M,allowedScope:Q})},[z,Q,M,J]),Y=V(async()=>{await z.askAssistant(Z)},[z,Z]),E=V(async()=>{let W=O.lastRuleId??await z.createDemoRule(),T=await z.upsertRuleVersion({ruleId:W,content:$});await z.approveRuleVersion(T),await z.simulateHighRiskChangeAndApprove(T),await z.publishSnapshot()},[z,$,O.lastRuleId]);if(O.loading&&!O.context)return N(w,{label:"Loading demo..."});if(O.error)return N(h,{title:"Failed to load demo",description:O.error.message,onRetry:z.refreshContext,retryLabel:"Retry"});return _("div",{className:"space-y-6",children:[N(S,{children:b.map((W)=>N(C,{label:W.label,value:String(W.value)},W.label))}),_(y,{className:"p-4",children:[N("h3",{className:"font-semibold text-lg",children:"1) Onboarding (explicit locale + jurisdiction)"}),_("div",{className:"mt-3 grid gap-3 md:grid-cols-3",children:[_("div",{children:[N("div",{className:"mb-1 font-semibold text-muted-foreground text-xs uppercase tracking-wide",children:"Locale"}),N(q,{value:J,onChange:(W)=>K(W.target.value)})]}),_("div",{children:[N("div",{className:"mb-1 font-semibold text-muted-foreground text-xs uppercase tracking-wide",children:"Jurisdiction"}),N(q,{value:M,onChange:(W)=>R(W.target.value)})]}),_("div",{children:[N("div",{className:"mb-1 font-semibold text-muted-foreground text-xs uppercase tracking-wide",children:"Allowed scope"}),_(d,{value:Q,onValueChange:(W)=>P(W),children:[N(u,{children:N(j,{placeholder:"Select scope"})}),_(p,{children:[N(B,{value:"education_only",children:"education_only"}),N(B,{value:"generic_info",children:"generic_info"}),N(B,{value:"escalation_required",children:"escalation_required"})]})]})]})]}),_("div",{className:"mt-4 flex gap-2",children:[N(U,{onPress:X,children:"Save context"}),N(U,{variant:"outline",onPress:z.refreshContext,children:"Refresh"})]})]}),_(y,{className:"p-4",children:[N("h3",{className:"font-semibold text-lg",children:"2) Ask the assistant (must cite KB snapshot)"}),_("div",{className:"mt-3 flex flex-col gap-3",children:[N(q,{value:Z,onChange:(W)=>F(W.target.value)}),N("div",{className:"flex gap-2",children:N(U,{onPress:Y,children:"Ask"})})]}),O.lastAnswer?_("div",{className:"mt-4 space-y-3",children:[O.lastAnswer.refused?_("div",{className:"text-red-600 text-sm",children:["Refused: ",O.lastAnswer.refusalReason??"UNKNOWN"]}):null,O.lastAnswer.sections.map((W,T)=>_("div",{children:[N("div",{className:"font-semibold text-sm",children:W.heading}),N("div",{className:"text-muted-foreground text-sm",children:W.body})]},`${W.heading}-${T}`)),N("div",{className:"font-semibold text-sm",children:"Citations"}),N("ul",{className:"list-disc pl-5 text-muted-foreground text-sm",children:O.lastAnswer.citations.map((W)=>_("li",{children:[W.kbSnapshotId," \u2014 ",W.sourceId]},`${W.kbSnapshotId}-${W.sourceId}`))})]}):null]}),_(y,{className:"p-4",children:[N("h3",{className:"font-semibold text-lg",children:"3) Admin: publish a new snapshot (HITL)"}),_("div",{className:"mt-3 space-y-3",children:[N(l,{value:$,onChange:(W)=>H(W.target.value)}),N(U,{onPress:E,children:"Simulate change \u2192 review \u2192 approve \u2192 publish snapshot"})]})]}),_(y,{className:"p-4",children:[N("h3",{className:"font-semibold text-lg",children:"4) Learning hub (patterns)"}),N("p",{className:"mt-2 text-muted-foreground text-sm",children:"This template includes drills, ambient coach, and quests as reusable Learning Journey tracks. The interactive learning UI is demonstrated in dedicated Learning Journey examples."})]})]})}export{Nz as PolicySafeKnowledgeAssistantDashboard};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contractspec/example.policy-safe-knowledge-assistant",
3
- "version": "3.7.17",
3
+ "version": "3.7.19",
4
4
  "description": "All-in-one template example: policy-safe knowledge assistant with locale/jurisdiction gating, versioned KB snapshots, HITL update pipeline, and learning hub.",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",
@@ -113,23 +113,23 @@
113
113
  "dev": "contractspec-bun-build dev",
114
114
  "clean": "rimraf dist .turbo",
115
115
  "lint": "bun lint:fix",
116
- "lint:fix": "biome check --write --unsafe --only=nursery/useSortedClasses . && biome check --write .",
117
- "lint:check": "biome check .",
116
+ "lint:fix": "node ../../../scripts/biome.cjs check --write --unsafe --only=nursery/useSortedClasses . && node ../../../scripts/biome.cjs check --write .",
117
+ "lint:check": "node ../../../scripts/biome.cjs check .",
118
118
  "test": "bun test",
119
119
  "prebuild": "contractspec-bun-build prebuild",
120
120
  "typecheck": "tsc --noEmit"
121
121
  },
122
122
  "dependencies": {
123
- "@contractspec/example.kb-update-pipeline": "3.7.17",
124
- "@contractspec/example.learning-patterns": "3.7.17",
125
- "@contractspec/example.locale-jurisdiction-gate": "3.7.17",
126
- "@contractspec/example.versioned-knowledge-base": "3.7.17",
127
- "@contractspec/lib.contracts-spec": "5.1.0",
128
- "@contractspec/lib.design-system": "3.8.10",
129
- "@contractspec/lib.example-shared-ui": "6.0.17",
123
+ "@contractspec/example.kb-update-pipeline": "3.7.19",
124
+ "@contractspec/example.learning-patterns": "3.7.19",
125
+ "@contractspec/example.locale-jurisdiction-gate": "3.7.19",
126
+ "@contractspec/example.versioned-knowledge-base": "3.7.19",
127
+ "@contractspec/lib.contracts-spec": "5.3.0",
128
+ "@contractspec/lib.design-system": "3.9.0",
129
+ "@contractspec/lib.example-shared-ui": "6.0.19",
130
130
  "@contractspec/lib.runtime-sandbox": "2.7.14",
131
- "@contractspec/lib.ui-kit-web": "3.9.9",
132
- "@contractspec/module.learning-journey": "3.7.16",
131
+ "@contractspec/lib.ui-kit-web": "3.10.0",
132
+ "@contractspec/module.learning-journey": "3.7.18",
133
133
  "react": "19.2.0",
134
134
  "react-dom": "19.2.0"
135
135
  },
@@ -138,7 +138,7 @@
138
138
  "typescript": "^5.9.3",
139
139
  "@types/react": "^19.2.14",
140
140
  "@types/react-dom": "^19.2.2",
141
- "@contractspec/tool.bun": "3.7.13"
141
+ "@contractspec/tool.bun": "3.7.14"
142
142
  },
143
143
  "publishConfig": {
144
144
  "access": "public",