@recombine-ai/bosun 0.13.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/bosun.js +7 -0
- package/build/client/_app/immutable/assets/0.b0jhAoSC.css +1 -0
- package/build/client/_app/immutable/assets/0.b0jhAoSC.css.br +0 -0
- package/build/client/_app/immutable/assets/0.b0jhAoSC.css.gz +0 -0
- package/build/client/_app/immutable/chunks/BTX1tKMW.js +1 -0
- package/build/client/_app/immutable/chunks/BTX1tKMW.js.br +0 -0
- package/build/client/_app/immutable/chunks/BTX1tKMW.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BVxLHCs8.js +1 -0
- package/build/client/_app/immutable/chunks/BVxLHCs8.js.br +0 -0
- package/build/client/_app/immutable/chunks/BVxLHCs8.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{De8YgKS3.js → ChVBNPUb.js} +1 -1
- package/build/client/_app/immutable/chunks/ChVBNPUb.js.br +0 -0
- package/build/client/_app/immutable/chunks/ChVBNPUb.js.gz +0 -0
- package/build/client/_app/immutable/chunks/E9rdsnHb.js +1 -0
- package/build/client/_app/immutable/chunks/E9rdsnHb.js.br +0 -0
- package/build/client/_app/immutable/chunks/E9rdsnHb.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Z1_c4us_.js +3 -0
- package/build/client/_app/immutable/chunks/Z1_c4us_.js.br +0 -0
- package/build/client/_app/immutable/chunks/Z1_c4us_.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{Bj8jfBTi.js → lmnC3bvv.js} +1 -1
- package/build/client/_app/immutable/chunks/lmnC3bvv.js.br +0 -0
- package/build/client/_app/immutable/chunks/lmnC3bvv.js.gz +0 -0
- package/build/client/_app/immutable/entry/{app.DK_wVDeR.js → app.BY5DP2K_.js} +2 -2
- package/build/client/_app/immutable/entry/app.BY5DP2K_.js.br +0 -0
- package/build/client/_app/immutable/entry/app.BY5DP2K_.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.BeIIwvvV.js +1 -0
- package/build/client/_app/immutable/entry/start.BeIIwvvV.js.br +0 -0
- package/build/client/_app/immutable/entry/start.BeIIwvvV.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{0.5fEbn14Q.js → 0.Cao0LJwW.js} +1 -1
- package/build/client/_app/immutable/nodes/0.Cao0LJwW.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.Cao0LJwW.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{1.CJrSN8zL.js → 1.Kjgu6yxL.js} +1 -1
- package/build/client/_app/immutable/nodes/1.Kjgu6yxL.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.Kjgu6yxL.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{10.SZwTlOEA.js → 10.yW2mHq85.js} +1 -1
- package/build/client/_app/immutable/nodes/10.yW2mHq85.js.br +0 -0
- package/build/client/_app/immutable/nodes/10.yW2mHq85.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{17.D-KFl7Vk.js → 17.COHkD98p.js} +3 -3
- package/build/client/_app/immutable/nodes/17.COHkD98p.js.br +0 -0
- package/build/client/_app/immutable/nodes/17.COHkD98p.js.gz +0 -0
- package/build/client/_app/immutable/nodes/18.DQVit7Md.js +11 -0
- package/build/client/_app/immutable/nodes/18.DQVit7Md.js.br +0 -0
- package/build/client/_app/immutable/nodes/18.DQVit7Md.js.gz +0 -0
- package/build/client/_app/immutable/nodes/2.DVwYttKv.js +35 -0
- package/build/client/_app/immutable/nodes/2.DVwYttKv.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.DVwYttKv.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{3.B1RGTOJ8.js → 3.BhmyTb3R.js} +1 -1
- package/build/client/_app/immutable/nodes/3.BhmyTb3R.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.BhmyTb3R.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{4.D2jcIUpD.js → 4.CxATX0ci.js} +1 -1
- package/build/client/_app/immutable/nodes/4.CxATX0ci.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.CxATX0ci.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{5.CUyCIyRd.js → 5.Dal1qxB1.js} +1 -1
- package/build/client/_app/immutable/nodes/5.Dal1qxB1.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.Dal1qxB1.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{6.B8HsGA2V.js → 6.iAOxBhJw.js} +1 -1
- package/build/client/_app/immutable/nodes/6.iAOxBhJw.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.iAOxBhJw.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{8.jY56-_OU.js → 8.DFhKu3dp.js} +1 -1
- package/build/client/_app/immutable/nodes/8.DFhKu3dp.js.br +0 -0
- package/build/client/_app/immutable/nodes/8.DFhKu3dp.js.gz +0 -0
- package/build/client/_app/immutable/nodes/9.DRIEv5m9.js +2 -0
- package/build/client/_app/immutable/nodes/9.DRIEv5m9.js.br +0 -0
- package/build/client/_app/immutable/nodes/9.DRIEv5m9.js.gz +0 -0
- package/build/client/_app/version.json +1 -1
- package/build/client/_app/version.json.br +0 -0
- package/build/client/_app/version.json.gz +0 -0
- package/build/server/chunks/{0-4QCErf9j.js → 0-CIzAMtA3.js} +3 -3
- package/build/server/chunks/{0-4QCErf9j.js.map → 0-CIzAMtA3.js.map} +1 -1
- package/build/server/chunks/{1-Dsjy8Hzc.js → 1-D1heuNbf.js} +2 -2
- package/build/server/chunks/{1-Dsjy8Hzc.js.map → 1-D1heuNbf.js.map} +1 -1
- package/build/server/chunks/{10-8061c8ui.js → 10-CjLtjXyZ.js} +2 -2
- package/build/server/chunks/{10-8061c8ui.js.map → 10-CjLtjXyZ.js.map} +1 -1
- package/build/server/chunks/{17-3_5wsIEX.js → 17-DklEmmOx.js} +4 -4
- package/build/server/chunks/{17-3_5wsIEX.js.map → 17-DklEmmOx.js.map} +1 -1
- package/build/server/chunks/{18-D73Mw140.js → 18-BJS-eRcz.js} +4 -4
- package/build/server/chunks/18-BJS-eRcz.js.map +1 -0
- package/build/server/chunks/{2-DM0VjzFi.js → 2-DCrAVYXs.js} +4 -4
- package/build/server/chunks/2-DCrAVYXs.js.map +1 -0
- package/build/server/chunks/{3-B3zlFGkL.js → 3-BpTqa4DU.js} +2 -2
- package/build/server/chunks/{3-B3zlFGkL.js.map → 3-BpTqa4DU.js.map} +1 -1
- package/build/server/chunks/{4-tESdMZpI.js → 4-B7GjwQzI.js} +2 -2
- package/build/server/chunks/{4-tESdMZpI.js.map → 4-B7GjwQzI.js.map} +1 -1
- package/build/server/chunks/{5-BJMTlq4U.js → 5-XjS__bcp.js} +2 -2
- package/build/server/chunks/{5-BJMTlq4U.js.map → 5-XjS__bcp.js.map} +1 -1
- package/build/server/chunks/{6-CDK2Aia6.js → 6-DWkWptmB.js} +2 -2
- package/build/server/chunks/{6-CDK2Aia6.js.map → 6-DWkWptmB.js.map} +1 -1
- package/build/server/chunks/{8-BJbDytoU.js → 8-_swAx6gL.js} +2 -2
- package/build/server/chunks/{8-BJbDytoU.js.map → 8-_swAx6gL.js.map} +1 -1
- package/build/server/chunks/{9-BNfIeSqk.js → 9-NEe24O4u.js} +4 -4
- package/build/server/chunks/9-NEe24O4u.js.map +1 -0
- package/build/server/chunks/{ChatStepTrace-DQL3qlna.js → ChatStepTrace-CX2Zolmp.js} +21 -8
- package/build/server/chunks/ChatStepTrace-CX2Zolmp.js.map +1 -0
- package/build/server/chunks/{_layout.svelte-DK7yl8vI.js → _layout.svelte-PtdpfgwJ.js} +66 -4
- package/build/server/chunks/_layout.svelte-PtdpfgwJ.js.map +1 -0
- package/build/server/chunks/{_page.svelte-ZWNBigwS.js → _page.svelte-C3gizoSD.js} +7 -4
- package/build/server/chunks/_page.svelte-C3gizoSD.js.map +1 -0
- package/build/server/chunks/{_page.svelte-D6bSXGHX.js → _page.svelte-CoCBnE2l.js} +8 -5
- package/build/server/chunks/_page.svelte-CoCBnE2l.js.map +1 -0
- package/build/server/chunks/{_page.svelte-ej3vdYeF.js → _page.svelte-DZvcjON6.js} +3 -2
- package/build/server/chunks/_page.svelte-DZvcjON6.js.map +1 -0
- package/build/server/chunks/steps-DzZCg39h.js +8 -0
- package/build/server/chunks/steps-DzZCg39h.js.map +1 -0
- package/build/server/index.js +1 -1
- package/build/server/index.js.map +1 -1
- package/build/server/manifest.js +13 -13
- package/build/server/manifest.js.map +1 -1
- package/package.json +4 -4
- package/src/backend/lib/backend-restart.ts +15 -0
- package/src/backend/roleplay/router.ts +42 -5
- package/src/backend/roleplay/schema-file.spec.ts +38 -0
- package/src/backend/roleplay/schema-file.ts +33 -0
- package/src/backend/tests/academy.ts +4 -2
- package/src/backend/tests/analyze.ts +2 -1
- package/src/backend/tests/emulate-agents.ts +13 -21
- package/src/backend/tests/pii-sanitized-test-drafts.spec.ts +162 -0
- package/src/backend/tests/pii-sanitized-test-drafts.ts +106 -0
- package/src/backend/tests/pii-sanitizer.spec.ts +145 -0
- package/src/backend/tests/pii-sanitizer.ts +171 -0
- package/src/backend/tests/router.ts +37 -0
- package/src/lib/agent-catalog.ts +4 -0
- package/src/lib/agents-context.ts +8 -0
- package/src/lib/api-telescope/client.ts +174 -0
- package/src/lib/api-telescope/index.ts +4 -0
- package/src/lib/api-telescope/latency-timeline-view-state.spec.ts +25 -0
- package/src/lib/api-telescope/latency-timeline-view-state.ts +86 -0
- package/src/lib/api-telescope/latency.ts +252 -0
- package/src/lib/api-telescope/source-selection.ts +20 -0
- package/src/lib/api-telescope/sources.server.ts +94 -0
- package/src/lib/api-telescope/types.ts +143 -0
- package/src/lib/components/Button.svelte +62 -0
- package/src/lib/components/CollapseExpand.svelte +425 -0
- package/src/lib/components/CopyTracesDropdown.svelte +118 -0
- package/src/lib/components/Dialog.svelte +69 -0
- package/src/lib/components/Dropdown.svelte +111 -0
- package/src/lib/components/History.svelte +174 -0
- package/src/lib/components/Icon.svelte +94 -0
- package/src/lib/components/Input.svelte +43 -0
- package/src/lib/components/Link.svelte +45 -0
- package/src/lib/components/Modal.svelte +45 -0
- package/src/lib/components/Panel.svelte +12 -0
- package/src/lib/components/PopoverModal.svelte +34 -0
- package/src/lib/components/Popper.svelte +109 -0
- package/src/lib/components/Tab.svelte +91 -0
- package/src/lib/components/Tabs.svelte +140 -0
- package/src/lib/components/agent-colors.ts +70 -0
- package/src/lib/dom/text-selection.ts +97 -0
- package/src/lib/edit/edit-vm.spec.ts +115 -0
- package/src/lib/edit/edit-vm.ts +169 -0
- package/src/lib/edit/edit-workspace-context.ts +56 -0
- package/src/lib/edit/highlight-styles.spec.ts +14 -0
- package/src/lib/edit/prompt-highlighter.spec.ts +80 -0
- package/src/lib/edit/prompt-highlighter.ts +155 -0
- package/src/lib/edit/quote-matching.ts +97 -0
- package/src/lib/monaco/bosun-theme.ts +125 -0
- package/src/lib/monaco/font.ts +2 -0
- package/src/lib/monaco-workers.ts +28 -0
- package/src/lib/steps.ts +19 -0
- package/src/lib/tests/pii-sanitized-test-draft.ts +50 -0
- package/src/lib/trpc-client.ts +16 -0
- package/src/lib/ws-client.ts +144 -0
- package/src/lib/ws-message.ts +150 -0
- package/build/client/_app/immutable/assets/0.B-Br6U4N.css +0 -1
- package/build/client/_app/immutable/assets/0.B-Br6U4N.css.br +0 -0
- package/build/client/_app/immutable/assets/0.B-Br6U4N.css.gz +0 -0
- package/build/client/_app/immutable/chunks/BOuo-4gP.js +0 -1
- package/build/client/_app/immutable/chunks/BOuo-4gP.js.br +0 -0
- package/build/client/_app/immutable/chunks/BOuo-4gP.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Bj8jfBTi.js.br +0 -0
- package/build/client/_app/immutable/chunks/Bj8jfBTi.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CX0Ekq8t.js +0 -1
- package/build/client/_app/immutable/chunks/CX0Ekq8t.js.br +0 -0
- package/build/client/_app/immutable/chunks/CX0Ekq8t.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Cyj62X2W.js +0 -2
- package/build/client/_app/immutable/chunks/Cyj62X2W.js.br +0 -0
- package/build/client/_app/immutable/chunks/Cyj62X2W.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DSDSeO7L.js +0 -1
- package/build/client/_app/immutable/chunks/DSDSeO7L.js.br +0 -0
- package/build/client/_app/immutable/chunks/DSDSeO7L.js.gz +0 -0
- package/build/client/_app/immutable/chunks/De8YgKS3.js.br +0 -1
- package/build/client/_app/immutable/chunks/De8YgKS3.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.DK_wVDeR.js.br +0 -0
- package/build/client/_app/immutable/entry/app.DK_wVDeR.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.xQy-2aGo.js +0 -1
- package/build/client/_app/immutable/entry/start.xQy-2aGo.js.br +0 -2
- package/build/client/_app/immutable/entry/start.xQy-2aGo.js.gz +0 -0
- package/build/client/_app/immutable/nodes/0.5fEbn14Q.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.5fEbn14Q.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.CJrSN8zL.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.CJrSN8zL.js.gz +0 -0
- package/build/client/_app/immutable/nodes/10.SZwTlOEA.js.br +0 -0
- package/build/client/_app/immutable/nodes/10.SZwTlOEA.js.gz +0 -0
- package/build/client/_app/immutable/nodes/17.D-KFl7Vk.js.br +0 -0
- package/build/client/_app/immutable/nodes/17.D-KFl7Vk.js.gz +0 -0
- package/build/client/_app/immutable/nodes/18.DqRdJY9A.js +0 -11
- package/build/client/_app/immutable/nodes/18.DqRdJY9A.js.br +0 -0
- package/build/client/_app/immutable/nodes/18.DqRdJY9A.js.gz +0 -0
- package/build/client/_app/immutable/nodes/2.B3Uuk25v.js +0 -35
- package/build/client/_app/immutable/nodes/2.B3Uuk25v.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.B3Uuk25v.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.B1RGTOJ8.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.B1RGTOJ8.js.gz +0 -0
- package/build/client/_app/immutable/nodes/4.D2jcIUpD.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.D2jcIUpD.js.gz +0 -0
- package/build/client/_app/immutable/nodes/5.CUyCIyRd.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.CUyCIyRd.js.gz +0 -0
- package/build/client/_app/immutable/nodes/6.B8HsGA2V.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.B8HsGA2V.js.gz +0 -0
- package/build/client/_app/immutable/nodes/8.jY56-_OU.js.br +0 -0
- package/build/client/_app/immutable/nodes/8.jY56-_OU.js.gz +0 -0
- package/build/client/_app/immutable/nodes/9.v5dX6L9n.js +0 -2
- package/build/client/_app/immutable/nodes/9.v5dX6L9n.js.br +0 -0
- package/build/client/_app/immutable/nodes/9.v5dX6L9n.js.gz +0 -0
- package/build/server/chunks/18-D73Mw140.js.map +0 -1
- package/build/server/chunks/2-DM0VjzFi.js.map +0 -1
- package/build/server/chunks/9-BNfIeSqk.js.map +0 -1
- package/build/server/chunks/ChatStepTrace-DQL3qlna.js.map +0 -1
- package/build/server/chunks/_layout.svelte-DK7yl8vI.js.map +0 -1
- package/build/server/chunks/_page.svelte-D6bSXGHX.js.map +0 -1
- package/build/server/chunks/_page.svelte-ZWNBigwS.js.map +0 -1
- package/build/server/chunks/_page.svelte-ej3vdYeF.js.map +0 -1
- /package/build/client/_app/immutable/assets/{Popper.CLTyHc88.css → steps.CLTyHc88.css} +0 -0
- /package/build/client/_app/immutable/assets/{Popper.CLTyHc88.css.br → steps.CLTyHc88.css.br} +0 -0
- /package/build/client/_app/immutable/assets/{Popper.CLTyHc88.css.gz → steps.CLTyHc88.css.gz} +0 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { createPromptHighlighter } from './prompt-highlighter'
|
|
4
|
+
|
|
5
|
+
function positionAt(text: string, offset: number): { lineNumber: number; column: number } {
|
|
6
|
+
const clamped = Math.max(0, Math.min(text.length, offset))
|
|
7
|
+
const before = text.slice(0, clamped)
|
|
8
|
+
const lineNumber = before.split('\n').length
|
|
9
|
+
const lastNl = before.lastIndexOf('\n')
|
|
10
|
+
const column = clamped - (lastNl === -1 ? 0 : lastNl + 1) + 1
|
|
11
|
+
return { lineNumber, column }
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
class Range {
|
|
15
|
+
constructor(
|
|
16
|
+
public startLineNumber: number,
|
|
17
|
+
public startColumn: number,
|
|
18
|
+
public endLineNumber: number,
|
|
19
|
+
public endColumn: number
|
|
20
|
+
) {}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe('prompt-highlighter', () => {
|
|
24
|
+
it('adds overview ruler marks and can focus next occurrence', () => {
|
|
25
|
+
const text = 'hello world\nhello again'
|
|
26
|
+
const model = {
|
|
27
|
+
getValue: () => text,
|
|
28
|
+
getPositionAt: (offset: number) => positionAt(text, offset)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const highlightCollection = { set: vi.fn(), clear: vi.fn() }
|
|
32
|
+
const focusCollection = { set: vi.fn(), clear: vi.fn() }
|
|
33
|
+
const collections = [highlightCollection, focusCollection]
|
|
34
|
+
|
|
35
|
+
const editor = {
|
|
36
|
+
getModel: () => model,
|
|
37
|
+
createDecorationsCollection: vi.fn(() => collections.shift()),
|
|
38
|
+
onDidChangeModelContent: vi.fn(() => ({ dispose: vi.fn() })),
|
|
39
|
+
setSelection: vi.fn(),
|
|
40
|
+
revealRangeInCenter: vi.fn(),
|
|
41
|
+
focus: vi.fn()
|
|
42
|
+
} as any
|
|
43
|
+
|
|
44
|
+
const monaco = {
|
|
45
|
+
Range,
|
|
46
|
+
editor: {
|
|
47
|
+
ScrollType: { Smooth: 0 },
|
|
48
|
+
OverviewRulerLane: { Center: 2 }
|
|
49
|
+
}
|
|
50
|
+
} as any
|
|
51
|
+
|
|
52
|
+
const highlighter = createPromptHighlighter(editor, monaco)
|
|
53
|
+
|
|
54
|
+
highlighter.setHighlights({
|
|
55
|
+
quotes: [{ quote: 'hello', count: 3 }],
|
|
56
|
+
focusQuote: null,
|
|
57
|
+
focusNonce: 0
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
expect(highlightCollection.set).toHaveBeenCalledTimes(1)
|
|
61
|
+
const decorations = highlightCollection.set.mock.calls[0][0]
|
|
62
|
+
expect(decorations).toHaveLength(2)
|
|
63
|
+
expect(decorations[0].options.inlineClassName).toContain('analysis-quote-l3')
|
|
64
|
+
expect(decorations[0].options.overviewRuler.position).toBe(
|
|
65
|
+
monaco.editor.OverviewRulerLane.Center
|
|
66
|
+
)
|
|
67
|
+
expect(decorations[0].options.overviewRuler.color).toContain('rgba(220, 38, 38')
|
|
68
|
+
|
|
69
|
+
highlighter.setHighlights({
|
|
70
|
+
quotes: [{ quote: 'hello', count: 3 }],
|
|
71
|
+
focusQuote: 'hello',
|
|
72
|
+
focusNonce: 1
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
expect(focusCollection.set).toHaveBeenCalledTimes(1)
|
|
76
|
+
expect(editor.revealRangeInCenter).toHaveBeenCalledTimes(1)
|
|
77
|
+
expect(editor.setSelection).toHaveBeenCalledTimes(1)
|
|
78
|
+
expect(editor.focus).toHaveBeenCalledTimes(1)
|
|
79
|
+
})
|
|
80
|
+
})
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import type * as Monaco from 'monaco-editor'
|
|
2
|
+
|
|
3
|
+
import type { PromptHighlights, QuoteCount } from './edit-vm'
|
|
4
|
+
import type { OffsetRange } from './quote-matching'
|
|
5
|
+
import { findAllOverlappingBestEffort } from './quote-matching'
|
|
6
|
+
|
|
7
|
+
export interface PromptHighlighter {
|
|
8
|
+
setHighlights: (highlights: PromptHighlights | null) => void
|
|
9
|
+
dispose: () => void
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function createPromptHighlighter(
|
|
13
|
+
editor: Monaco.editor.IStandaloneCodeEditor,
|
|
14
|
+
monaco: typeof import('monaco-editor')
|
|
15
|
+
): PromptHighlighter {
|
|
16
|
+
const highlightDecorations = editor.createDecorationsCollection()
|
|
17
|
+
const focusDecorations = editor.createDecorationsCollection()
|
|
18
|
+
|
|
19
|
+
let currentHighlights: PromptHighlights | null = null
|
|
20
|
+
let highlightRangesByQuote = new Map<string, OffsetRange[]>()
|
|
21
|
+
let cursorByQuote = new Map<string, number>()
|
|
22
|
+
let lastHandledFocusNonce = 0
|
|
23
|
+
|
|
24
|
+
function resetCaches() {
|
|
25
|
+
highlightRangesByQuote = new Map()
|
|
26
|
+
cursorByQuote = new Map()
|
|
27
|
+
lastHandledFocusNonce = 0
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function clamp(n: number, min: number, max: number): number {
|
|
31
|
+
if (Number.isNaN(n)) return min
|
|
32
|
+
return Math.max(min, Math.min(max, n))
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function overviewColorForLevel(level: number): string {
|
|
36
|
+
const l = clamp(level, 1, 10)
|
|
37
|
+
// Use a slightly higher opacity than the inline background so marks are visible in the overview ruler.
|
|
38
|
+
const alpha = clamp(0.22 + l * 0.06, 0.28, 0.82)
|
|
39
|
+
return `rgba(220, 38, 38, ${alpha})`
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function getHighlightRanges(quote: string, text: string): OffsetRange[] {
|
|
43
|
+
const q = String(quote ?? '')
|
|
44
|
+
if (!q) return []
|
|
45
|
+
const cached = highlightRangesByQuote.get(q)
|
|
46
|
+
if (cached) return cached
|
|
47
|
+
const found = findAllOverlappingBestEffort(text, q)
|
|
48
|
+
highlightRangesByQuote.set(q, found)
|
|
49
|
+
return found
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function updateHighlightDecorations(quotes: QuoteCount[]) {
|
|
53
|
+
const model = editor.getModel()
|
|
54
|
+
if (!model) return
|
|
55
|
+
|
|
56
|
+
const text = model.getValue() ?? ''
|
|
57
|
+
const decorations: Monaco.editor.IModelDeltaDecoration[] = []
|
|
58
|
+
|
|
59
|
+
// Weaker highlights first so stronger quotes can visually dominate overlaps.
|
|
60
|
+
const ordered = [...(quotes || [])].sort((a, b) => (a.count || 0) - (b.count || 0))
|
|
61
|
+
for (const q of ordered) {
|
|
62
|
+
const quote = String(q.quote || '')
|
|
63
|
+
if (!quote) continue
|
|
64
|
+
const level = clamp(Number(q.count || 0), 1, 10)
|
|
65
|
+
const color = overviewColorForLevel(level)
|
|
66
|
+
const matches = getHighlightRanges(quote, text)
|
|
67
|
+
for (const m of matches) {
|
|
68
|
+
const startPos = model.getPositionAt(m.start)
|
|
69
|
+
const endPos = model.getPositionAt(m.end)
|
|
70
|
+
decorations.push({
|
|
71
|
+
range: new monaco.Range(
|
|
72
|
+
startPos.lineNumber,
|
|
73
|
+
startPos.column,
|
|
74
|
+
endPos.lineNumber,
|
|
75
|
+
endPos.column
|
|
76
|
+
),
|
|
77
|
+
options: {
|
|
78
|
+
inlineClassName: `analysis-quote analysis-quote-l${level}`,
|
|
79
|
+
overviewRuler: { color, position: monaco.editor.OverviewRulerLane.Center }
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
highlightDecorations.set(decorations)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function revealNextOccurrence(quote: string) {
|
|
89
|
+
const model = editor.getModel()
|
|
90
|
+
if (!model) return
|
|
91
|
+
|
|
92
|
+
const text = model.getValue() ?? ''
|
|
93
|
+
const occurrences = getHighlightRanges(quote, text)
|
|
94
|
+
if (occurrences.length === 0) return
|
|
95
|
+
|
|
96
|
+
const current = cursorByQuote.get(quote) ?? -1
|
|
97
|
+
const nextIdx = (current + 1) % occurrences.length
|
|
98
|
+
cursorByQuote.set(quote, nextIdx)
|
|
99
|
+
|
|
100
|
+
const chosen = occurrences[nextIdx]
|
|
101
|
+
const startPos = model.getPositionAt(chosen.start)
|
|
102
|
+
const endPos = model.getPositionAt(chosen.end)
|
|
103
|
+
const range = new monaco.Range(
|
|
104
|
+
startPos.lineNumber,
|
|
105
|
+
startPos.column,
|
|
106
|
+
endPos.lineNumber,
|
|
107
|
+
endPos.column
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
focusDecorations.set([{ range, options: { inlineClassName: 'analysis-quote-focus' } }])
|
|
111
|
+
editor.setSelection(range)
|
|
112
|
+
editor.revealRangeInCenter(range, monaco.editor.ScrollType.Smooth)
|
|
113
|
+
editor.focus()
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function applyHighlights(next: PromptHighlights | null) {
|
|
117
|
+
currentHighlights = next
|
|
118
|
+
if (!currentHighlights) {
|
|
119
|
+
highlightDecorations.clear()
|
|
120
|
+
focusDecorations.clear()
|
|
121
|
+
resetCaches()
|
|
122
|
+
return
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
updateHighlightDecorations(currentHighlights.quotes || [])
|
|
126
|
+
|
|
127
|
+
if (currentHighlights.focusQuote && currentHighlights.focusNonce !== lastHandledFocusNonce) {
|
|
128
|
+
lastHandledFocusNonce = currentHighlights.focusNonce
|
|
129
|
+
revealNextOccurrence(currentHighlights.focusQuote)
|
|
130
|
+
} else if (!currentHighlights.focusQuote) {
|
|
131
|
+
focusDecorations.clear()
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const onDidChange = editor.onDidChangeModelContent(() => {
|
|
136
|
+
if (!currentHighlights) return
|
|
137
|
+
highlightRangesByQuote = new Map()
|
|
138
|
+
focusDecorations.clear()
|
|
139
|
+
updateHighlightDecorations(currentHighlights.quotes || [])
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
setHighlights: applyHighlights,
|
|
144
|
+
dispose: () => {
|
|
145
|
+
try {
|
|
146
|
+
onDidChange.dispose()
|
|
147
|
+
highlightDecorations.clear()
|
|
148
|
+
focusDecorations.clear()
|
|
149
|
+
} finally {
|
|
150
|
+
currentHighlights = null
|
|
151
|
+
resetCaches()
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
export type OffsetRange = { start: number; end: number }
|
|
2
|
+
|
|
3
|
+
export function findAllOverlappingBestEffort(haystack: string, needle: string): OffsetRange[] {
|
|
4
|
+
const text = String(haystack ?? '')
|
|
5
|
+
const variants = buildNeedleVariants(needle)
|
|
6
|
+
const normalizedText = normalizeForMatching(text)
|
|
7
|
+
|
|
8
|
+
for (const variant of variants) {
|
|
9
|
+
const exact = findAllOverlappingExact(text, variant)
|
|
10
|
+
if (exact.length > 0) return exact
|
|
11
|
+
|
|
12
|
+
const flexible = findAllOverlappingFlexible(text, variant)
|
|
13
|
+
if (flexible.length > 0) return flexible
|
|
14
|
+
|
|
15
|
+
const normalizedNeedle = normalizeForMatching(variant)
|
|
16
|
+
if (normalizedText !== text || normalizedNeedle !== variant) {
|
|
17
|
+
const exactNorm = findAllOverlappingExact(normalizedText, normalizedNeedle)
|
|
18
|
+
if (exactNorm.length > 0) return exactNorm
|
|
19
|
+
|
|
20
|
+
const flexibleNorm = findAllOverlappingFlexible(normalizedText, normalizedNeedle)
|
|
21
|
+
if (flexibleNorm.length > 0) return flexibleNorm
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return []
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function findAllOverlappingExact(haystack: string, needle: string): OffsetRange[] {
|
|
29
|
+
const n = String(needle ?? '')
|
|
30
|
+
if (!n) return []
|
|
31
|
+
|
|
32
|
+
const out: OffsetRange[] = []
|
|
33
|
+
let idx = 0
|
|
34
|
+
while (idx <= haystack.length - n.length) {
|
|
35
|
+
const found = haystack.indexOf(n, idx)
|
|
36
|
+
if (found === -1) break
|
|
37
|
+
out.push({ start: found, end: found + n.length })
|
|
38
|
+
idx = found + 1
|
|
39
|
+
}
|
|
40
|
+
return out
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Whitespace-insensitive overlap matching: treats any whitespace run in the quote as `\\s+` in the prompt.
|
|
44
|
+
export function findAllOverlappingFlexible(haystack: string, needle: string): OffsetRange[] {
|
|
45
|
+
const raw = String(needle ?? '')
|
|
46
|
+
if (!raw.trim()) return []
|
|
47
|
+
|
|
48
|
+
const pattern = escapeRegex(raw).replace(/\s+/g, '\\s+')
|
|
49
|
+
let re: RegExp
|
|
50
|
+
try {
|
|
51
|
+
re = new RegExp(`(?=(${pattern}))`, 'gu')
|
|
52
|
+
} catch {
|
|
53
|
+
return []
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const out: OffsetRange[] = []
|
|
57
|
+
let m: RegExpExecArray | null
|
|
58
|
+
while ((m = re.exec(haystack)) !== null) {
|
|
59
|
+
const start = m.index
|
|
60
|
+
const matched = m[1] ?? ''
|
|
61
|
+
const end = start + matched.length
|
|
62
|
+
if (end > start) out.push({ start, end })
|
|
63
|
+
if (re.lastIndex === start) re.lastIndex += 1
|
|
64
|
+
}
|
|
65
|
+
return out
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function buildNeedleVariants(raw: string): string[] {
|
|
69
|
+
const base = String(raw ?? '')
|
|
70
|
+
const trimmed = base.trim()
|
|
71
|
+
const variants = new Set<string>()
|
|
72
|
+
for (const v of [base, trimmed]) {
|
|
73
|
+
if (v) variants.add(v)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Common "model-added" prefixes (bullets/numbering) that can break exact matching.
|
|
77
|
+
const noBullet = trimmed.replace(/^[-*•]\s+/, '')
|
|
78
|
+
if (noBullet && noBullet !== trimmed) variants.add(noBullet)
|
|
79
|
+
const noNumbering = trimmed.replace(/^(?:\(?\d+\)?[.)]|[a-zA-Z][.)])\s+/, '')
|
|
80
|
+
if (noNumbering && noNumbering !== trimmed) variants.add(noNumbering)
|
|
81
|
+
|
|
82
|
+
return [...variants].filter((v) => v.trim().length > 0)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Length-preserving normalization for matching across punctuation variants.
|
|
86
|
+
export function normalizeForMatching(text: string): string {
|
|
87
|
+
return String(text ?? '')
|
|
88
|
+
.replace(/\r/g, '\n')
|
|
89
|
+
.replace(/[\u00A0\u2007\u202F\u2009\u200A\u200B\uFEFF]/g, ' ')
|
|
90
|
+
.replace(/[\u201C\u201D\u201E\u00AB\u00BB]/g, '"')
|
|
91
|
+
.replace(/[\u2018\u2019]/g, "'")
|
|
92
|
+
.replace(/[\u2013\u2014]/g, '-')
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function escapeRegex(text: string): string {
|
|
96
|
+
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
97
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type * as Monaco from 'monaco-editor'
|
|
2
|
+
|
|
3
|
+
export interface PromptDecorations {
|
|
4
|
+
update: () => void
|
|
5
|
+
dispose: () => void
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function createPromptDecorations(
|
|
9
|
+
monaco: typeof Monaco,
|
|
10
|
+
editor: Monaco.editor.IStandaloneCodeEditor
|
|
11
|
+
) {
|
|
12
|
+
const collection = editor.createDecorationsCollection()
|
|
13
|
+
|
|
14
|
+
function update() {
|
|
15
|
+
const model = editor.getModel()
|
|
16
|
+
if (!model) return
|
|
17
|
+
|
|
18
|
+
const decorations: Monaco.editor.IModelDeltaDecoration[] = []
|
|
19
|
+
const lineCount = model.getLineCount()
|
|
20
|
+
|
|
21
|
+
for (let lineNumber = 1; lineNumber <= lineCount; lineNumber++) {
|
|
22
|
+
const lineText = model.getLineContent(lineNumber)
|
|
23
|
+
|
|
24
|
+
// Headings
|
|
25
|
+
const match = /^(#+)\s/.exec(lineText)
|
|
26
|
+
if (match) {
|
|
27
|
+
const level = match[1].length
|
|
28
|
+
let cls = 'prompt-heading-3'
|
|
29
|
+
|
|
30
|
+
if (level === 1) {
|
|
31
|
+
cls = 'prompt-heading-1'
|
|
32
|
+
} else if (level === 2) {
|
|
33
|
+
cls = 'prompt-heading-2'
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
decorations.push({
|
|
37
|
+
range: new monaco.Range(lineNumber, 1, lineNumber, lineText.length + 1),
|
|
38
|
+
options: {
|
|
39
|
+
isWholeLine: true,
|
|
40
|
+
inlineClassName: cls
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Symbols '#' and '*'
|
|
46
|
+
for (let column = 1; column <= lineText.length; column++) {
|
|
47
|
+
const ch = lineText[column - 1]
|
|
48
|
+
if (ch === '#' || ch === '*') {
|
|
49
|
+
decorations.push({
|
|
50
|
+
range: new monaco.Range(lineNumber, column, lineNumber, column + 1),
|
|
51
|
+
options: {
|
|
52
|
+
inlineClassName: 'prompt-symbol'
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Subnumbers
|
|
59
|
+
const subMatch = lineText.match(/^(\s+)(\d+(?:\.\d+)+\.?)(?=[\s)]|$)/)
|
|
60
|
+
if (subMatch) {
|
|
61
|
+
const leading = subMatch[1]
|
|
62
|
+
const numberText = subMatch[2]
|
|
63
|
+
|
|
64
|
+
const startColumn = leading.length + 1
|
|
65
|
+
const endColumn = startColumn + numberText.length
|
|
66
|
+
|
|
67
|
+
decorations.push({
|
|
68
|
+
range: new monaco.Range(lineNumber, startColumn, lineNumber, endColumn),
|
|
69
|
+
options: {
|
|
70
|
+
inlineClassName: 'prompt-subnumber'
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
collection.set(decorations)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function dispose() {
|
|
80
|
+
collection.clear()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return { update, dispose }
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export const bosunDarkTheme: Monaco.editor.IStandaloneThemeData = {
|
|
87
|
+
base: 'vs-dark',
|
|
88
|
+
inherit: true,
|
|
89
|
+
rules: [
|
|
90
|
+
// default text
|
|
91
|
+
{ token: '', foreground: 'DDDDDD' },
|
|
92
|
+
// keywords & others
|
|
93
|
+
{ token: 'string.md', foreground: 'DDDDDD' },
|
|
94
|
+
{ token: 'keyword.md', foreground: '767676' },
|
|
95
|
+
{ token: 'strong.md', foreground: 'DDDDDD', fontStyle: 'bold' },
|
|
96
|
+
{ token: 'string.target.md', foreground: '00B58A' },
|
|
97
|
+
{ token: 'tag.md', foreground: 'CE9178' },
|
|
98
|
+
{ token: 'string.link.md', foreground: '569cd6', fontStyle: 'underline' }
|
|
99
|
+
],
|
|
100
|
+
colors: {
|
|
101
|
+
// editor area
|
|
102
|
+
'editor.background': '#1D1D1D',
|
|
103
|
+
'editor.foreground': '#AFAFAF',
|
|
104
|
+
|
|
105
|
+
// (optional but nice to match)
|
|
106
|
+
'editorLineNumber.foreground': '#636363',
|
|
107
|
+
'editorLineNumber.activeForeground': '#767676',
|
|
108
|
+
'editorCursor.foreground': '#DDDDDD',
|
|
109
|
+
'editor.selectionBackground': '#4B5563D0',
|
|
110
|
+
'editor.inactiveSelectionBackground': '#4B5563A0',
|
|
111
|
+
'editor.lineHighlightBackground': '#FFFFFF08',
|
|
112
|
+
'editorLineNumber.background': '#1D1D1D',
|
|
113
|
+
|
|
114
|
+
// Nunjucks tag highlight (DocumentHighlightProvider)
|
|
115
|
+
'editor.wordHighlightBackground': '#ff480159'
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
let hasDefinedBosunTheme = false
|
|
120
|
+
|
|
121
|
+
export function ensureBosunTheme(monaco: typeof Monaco) {
|
|
122
|
+
if (hasDefinedBosunTheme) return
|
|
123
|
+
monaco.editor.defineTheme('bosun-dark', bosunDarkTheme)
|
|
124
|
+
hasDefinedBosunTheme = true
|
|
125
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
|
|
2
|
+
import CssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker'
|
|
3
|
+
import HtmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'
|
|
4
|
+
import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
|
|
5
|
+
import TsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'
|
|
6
|
+
|
|
7
|
+
export function ensureMonacoWorkers() {
|
|
8
|
+
if (typeof window === 'undefined') return
|
|
9
|
+
|
|
10
|
+
const env = (window as any).MonacoEnvironment as
|
|
11
|
+
| {
|
|
12
|
+
getWorker?: (moduleId: unknown, label: string) => Worker
|
|
13
|
+
}
|
|
14
|
+
| undefined
|
|
15
|
+
|
|
16
|
+
if (env?.getWorker) return
|
|
17
|
+
;(window as any).MonacoEnvironment = {
|
|
18
|
+
...env,
|
|
19
|
+
getWorker: function (_moduleId: unknown, label: string) {
|
|
20
|
+
if (label === 'json') return new JsonWorker()
|
|
21
|
+
if (label === 'css' || label === 'scss' || label === 'less') return new CssWorker()
|
|
22
|
+
if (label === 'html' || label === 'handlebars' || label === 'razor') return new HtmlWorker()
|
|
23
|
+
if (label === 'typescript' || label === 'javascript') return new TsWorker()
|
|
24
|
+
|
|
25
|
+
return new EditorWorker()
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
package/src/lib/steps.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recognises the name of an agent's primary conversational step. This is the single definition of
|
|
3
|
+
* that convention in Bosun — everywhere else should call this rather than test names inline, so the
|
|
4
|
+
* convention can change in one place.
|
|
5
|
+
*
|
|
6
|
+
* Projects name the step `main`, or `main[<anything>]` when they need several variants of it — for
|
|
7
|
+
* example one per region. **The bracket contents are opaque to Bosun.** What a project puts inside
|
|
8
|
+
* is its own business, so Bosun recognises the shape and never parses the inside. It follows that
|
|
9
|
+
* Bosun cannot tell which variant is "active"; where one has to be chosen, it simply takes the
|
|
10
|
+
* first match.
|
|
11
|
+
*
|
|
12
|
+
* `mainReply` is kept as a legacy alias for projects that used it.
|
|
13
|
+
*/
|
|
14
|
+
export function isMainStepName(name: string | null | undefined): boolean {
|
|
15
|
+
if (!name) return false
|
|
16
|
+
if (name === 'main' || name === 'mainReply') return true
|
|
17
|
+
// Require the bracket so unrelated names beginning with "main" (e.g. `maintenance`) don't match.
|
|
18
|
+
return name.startsWith('main[') && name.endsWith(']')
|
|
19
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
export const TraceTestSeedSchema = z
|
|
4
|
+
.object({
|
|
5
|
+
pinned: z.literal('TRUE'),
|
|
6
|
+
step: z.string().optional(),
|
|
7
|
+
evaluation_mode: z.enum(['assertion', 'json-deep-equal']),
|
|
8
|
+
context_mode: z.literal('replace'),
|
|
9
|
+
assertion_type: z.literal('llm-rubric'),
|
|
10
|
+
assertion_value: z.string(),
|
|
11
|
+
conversation: z.string(),
|
|
12
|
+
expected_output: z.string(),
|
|
13
|
+
similarity_threshold: z.string(),
|
|
14
|
+
timeout: z.string(),
|
|
15
|
+
context: z.record(z.unknown()),
|
|
16
|
+
mocks: z.record(z.unknown()).optional()
|
|
17
|
+
})
|
|
18
|
+
.strict()
|
|
19
|
+
|
|
20
|
+
export type TraceTestSeed = z.infer<typeof TraceTestSeedSchema>
|
|
21
|
+
|
|
22
|
+
export const TraceTestReviewContentSchema = TraceTestSeedSchema.pick({
|
|
23
|
+
conversation: true,
|
|
24
|
+
expected_output: true,
|
|
25
|
+
context: true,
|
|
26
|
+
mocks: true
|
|
27
|
+
}).strict()
|
|
28
|
+
|
|
29
|
+
export type TraceTestReviewContent = z.infer<typeof TraceTestReviewContentSchema>
|
|
30
|
+
|
|
31
|
+
export const PIIFindingCategorySchema = z.enum([
|
|
32
|
+
'person',
|
|
33
|
+
'contact',
|
|
34
|
+
'address',
|
|
35
|
+
'date_of_birth',
|
|
36
|
+
'account_identifier',
|
|
37
|
+
'vehicle_identifier',
|
|
38
|
+
'financial',
|
|
39
|
+
'special_category',
|
|
40
|
+
'other'
|
|
41
|
+
])
|
|
42
|
+
|
|
43
|
+
export const PIIFindingSchema = z
|
|
44
|
+
.object({
|
|
45
|
+
category: PIIFindingCategorySchema,
|
|
46
|
+
paths: z.array(z.string())
|
|
47
|
+
})
|
|
48
|
+
.strict()
|
|
49
|
+
|
|
50
|
+
export type PIIFinding = z.infer<typeof PIIFindingSchema>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { env } from '$env/dynamic/public'
|
|
2
|
+
import { createTRPCClient, httpLink } from '@trpc/client'
|
|
3
|
+
import type { AppRouter } from '../backend/server'
|
|
4
|
+
|
|
5
|
+
const trpcUrl =
|
|
6
|
+
env.PUBLIC_TRPC_URL ??
|
|
7
|
+
`http://${env.PUBLIC_TRPC_HOSTNAME ?? 'localhost'}:${env.PUBLIC_TRPC_PORT ?? '2022'}`
|
|
8
|
+
|
|
9
|
+
// ref: https://github.com/trpc/trpc/blob/main/examples/standalone-server/src/client.ts
|
|
10
|
+
export const trpc = createTRPCClient<AppRouter>({
|
|
11
|
+
links: [
|
|
12
|
+
httpLink({
|
|
13
|
+
url: trpcUrl
|
|
14
|
+
})
|
|
15
|
+
]
|
|
16
|
+
})
|