@agimon-ai/doompi-web-contracts 0.0.1-alpha.11
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/LICENSE +22 -0
- package/README.md +47 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +7 -0
- package/dist/index.d.mts +7 -0
- package/dist/index.mjs +1 -0
- package/dist/services/define.cjs +2 -0
- package/dist/services/define.cjs.map +1 -0
- package/dist/services/define.d.cts +20 -0
- package/dist/services/define.d.cts.map +1 -0
- package/dist/services/define.d.mts +20 -0
- package/dist/services/define.d.mts.map +1 -0
- package/dist/services/define.mjs +2 -0
- package/dist/services/define.mjs.map +1 -0
- package/dist/services/globalStore.cjs +2 -0
- package/dist/services/globalStore.cjs.map +1 -0
- package/dist/services/globalStore.d.cts +7 -0
- package/dist/services/globalStore.d.cts.map +1 -0
- package/dist/services/globalStore.d.mts +7 -0
- package/dist/services/globalStore.d.mts.map +1 -0
- package/dist/services/globalStore.mjs +2 -0
- package/dist/services/globalStore.mjs.map +1 -0
- package/dist/services/sessionStore.cjs +2 -0
- package/dist/services/sessionStore.cjs.map +1 -0
- package/dist/services/sessionStore.d.cts +15 -0
- package/dist/services/sessionStore.d.cts.map +1 -0
- package/dist/services/sessionStore.d.mts +15 -0
- package/dist/services/sessionStore.d.mts.map +1 -0
- package/dist/services/sessionStore.mjs +2 -0
- package/dist/services/sessionStore.mjs.map +1 -0
- package/dist/services/testing/channels.cjs +2 -0
- package/dist/services/testing/channels.cjs.map +1 -0
- package/dist/services/testing/channels.d.cts +52 -0
- package/dist/services/testing/channels.d.cts.map +1 -0
- package/dist/services/testing/channels.d.mts +52 -0
- package/dist/services/testing/channels.d.mts.map +1 -0
- package/dist/services/testing/channels.mjs +2 -0
- package/dist/services/testing/channels.mjs.map +1 -0
- package/dist/services/testing/render.cjs +2 -0
- package/dist/services/testing/render.cjs.map +1 -0
- package/dist/services/testing/render.d.cts +32 -0
- package/dist/services/testing/render.d.cts.map +1 -0
- package/dist/services/testing/render.d.mts +32 -0
- package/dist/services/testing/render.d.mts.map +1 -0
- package/dist/services/testing/render.mjs +2 -0
- package/dist/services/testing/render.mjs.map +1 -0
- package/dist/services/testing/slotProps.cjs +2 -0
- package/dist/services/testing/slotProps.cjs.map +1 -0
- package/dist/services/testing/slotProps.d.cts +59 -0
- package/dist/services/testing/slotProps.d.cts.map +1 -0
- package/dist/services/testing/slotProps.d.mts +59 -0
- package/dist/services/testing/slotProps.d.mts.map +1 -0
- package/dist/services/testing/slotProps.mjs +2 -0
- package/dist/services/testing/slotProps.mjs.map +1 -0
- package/dist/services/toolResult.cjs +7 -0
- package/dist/services/toolResult.cjs.map +1 -0
- package/dist/services/toolResult.d.cts +15 -0
- package/dist/services/toolResult.d.cts.map +1 -0
- package/dist/services/toolResult.d.mts +15 -0
- package/dist/services/toolResult.d.mts.map +1 -0
- package/dist/services/toolResult.mjs +7 -0
- package/dist/services/toolResult.mjs.map +1 -0
- package/dist/testing.cjs +1 -0
- package/dist/testing.d.cts +4 -0
- package/dist/testing.d.mts +4 -0
- package/dist/testing.mjs +1 -0
- package/dist/types/webHub.d.cts +77 -0
- package/dist/types/webHub.d.cts.map +1 -0
- package/dist/types/webHub.d.mts +77 -0
- package/dist/types/webHub.d.mts.map +1 -0
- package/dist/types/webPlugin.d.cts +552 -0
- package/dist/types/webPlugin.d.cts.map +1 -0
- package/dist/types/webPlugin.d.mts +552 -0
- package/dist/types/webPlugin.d.mts.map +1 -0
- package/package.json +85 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { SlotDataFill, ThreadViewOptions, ToolMessageRenderProps, ToolResultView, WebPluginSlotProps } from "../../types/webPlugin.cjs";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
//#region src/services/testing/slotProps.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* The props the cockpit hands a plugin's components, built for a test.
|
|
6
|
+
*
|
|
7
|
+
* A plugin component takes fifteen props and reads three of them. Written out
|
|
8
|
+
* by hand in each test, the other twelve are noise that goes stale the moment
|
|
9
|
+
* the contract grows a member; written as a cast, the component compiles
|
|
10
|
+
* against props the host never sends. This builds all of them, records what the
|
|
11
|
+
* component did with the actions, and lets a test override the two or three it
|
|
12
|
+
* cares about.
|
|
13
|
+
*/
|
|
14
|
+
interface RecordedSlotAction {
|
|
15
|
+
action: 'appendComposerDraft' | 'openTab' | 'openTransientTab' | 'closeTransientTab' | 'sendSessionFrame';
|
|
16
|
+
/** The tab id, the transient tab's id, or the target session of a frame or composer append. */
|
|
17
|
+
target: string | null;
|
|
18
|
+
/** The text passed to `appendComposerDraft`. */
|
|
19
|
+
text?: string;
|
|
20
|
+
/** The frame a component sent, for `sendSessionFrame`. */
|
|
21
|
+
frame?: Record<string, unknown>;
|
|
22
|
+
}
|
|
23
|
+
interface SlotPropsFixture {
|
|
24
|
+
props: WebPluginSlotProps;
|
|
25
|
+
/** Everything the component did through its props, in order. */
|
|
26
|
+
readonly actions: readonly RecordedSlotAction[];
|
|
27
|
+
/** Frames the component sent, which is what most assertions want. */
|
|
28
|
+
frames(): readonly Record<string, unknown>[];
|
|
29
|
+
}
|
|
30
|
+
interface SlotPropsOptions {
|
|
31
|
+
sessionId?: string | null;
|
|
32
|
+
statuses?: Readonly<Record<string, string>>;
|
|
33
|
+
/** Component fills this slot owner should see; keyed by slot name. */
|
|
34
|
+
slotContent?: Readonly<Record<string, ReactNode>>;
|
|
35
|
+
/** Data fills this slot owner should read back, keyed by slot name. */
|
|
36
|
+
slotData?: Readonly<Record<string, readonly SlotDataFill[]>>;
|
|
37
|
+
/** What `renderThread` returns for a plugin that renders one. */
|
|
38
|
+
thread?: (threadId: string, options?: ThreadViewOptions) => ReactNode;
|
|
39
|
+
}
|
|
40
|
+
declare function slotPropsFixture(options?: SlotPropsOptions): SlotPropsFixture;
|
|
41
|
+
interface ToolMessagePropsOptions extends SlotPropsOptions {
|
|
42
|
+
toolCallId?: string;
|
|
43
|
+
toolName: string;
|
|
44
|
+
args?: Record<string, unknown>;
|
|
45
|
+
/** The newest result; null is what the host sends before any output. */
|
|
46
|
+
result?: ToolResultView | null;
|
|
47
|
+
/** The result's text blocks joined, as the host's own fallback item shows them. */
|
|
48
|
+
output?: string;
|
|
49
|
+
running?: boolean;
|
|
50
|
+
isError?: boolean;
|
|
51
|
+
}
|
|
52
|
+
interface ToolMessagePropsFixture extends Omit<SlotPropsFixture, 'props'> {
|
|
53
|
+
props: ToolMessageRenderProps;
|
|
54
|
+
}
|
|
55
|
+
/** The props a tool's timeline item receives, in any of its four states. */
|
|
56
|
+
declare function toolMessagePropsFixture(options: ToolMessagePropsOptions): ToolMessagePropsFixture;
|
|
57
|
+
//#endregion
|
|
58
|
+
export { RecordedSlotAction, SlotPropsFixture, SlotPropsOptions, ToolMessagePropsFixture, ToolMessagePropsOptions, slotPropsFixture, toolMessagePropsFixture };
|
|
59
|
+
//# sourceMappingURL=slotProps.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slotProps.d.cts","names":[],"sources":["../../../src/services/testing/slotProps.ts"],"mappings":";;;;;;;;;;;;;UAsBiB;EACf;;EAEA;;EAEA;;EAEA,QAAQ;;UAGO;EACf,OAAO;;WAEE,kBAAkB;;EAE3B,mBAAmB;;UAGJ;EACf;EACA,WAAW,SAAS;;EAEpB,cAAc,SAAS,eAAe;;EAEtC,WAAW,SAAS,wBAAwB;;EAE5C,UAAU,kBAAkB,UAAU,sBAAsB;;iBAK9C,iBAAiB,UAAS,mBAAwB;UAmCjD,gCAAgC;EAC/C;EACA;EACA,OAAO;;EAEP,SAAS;;EAET;EACA;EACA;;UAGe,gCAAgC,KAAK;EACpD,OAAO;;;iBAMO,wBAAwB,SAAS,0BAA0B"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { SlotDataFill, ThreadViewOptions, ToolMessageRenderProps, ToolResultView, WebPluginSlotProps } from "../../types/webPlugin.mjs";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
//#region src/services/testing/slotProps.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* The props the cockpit hands a plugin's components, built for a test.
|
|
6
|
+
*
|
|
7
|
+
* A plugin component takes fifteen props and reads three of them. Written out
|
|
8
|
+
* by hand in each test, the other twelve are noise that goes stale the moment
|
|
9
|
+
* the contract grows a member; written as a cast, the component compiles
|
|
10
|
+
* against props the host never sends. This builds all of them, records what the
|
|
11
|
+
* component did with the actions, and lets a test override the two or three it
|
|
12
|
+
* cares about.
|
|
13
|
+
*/
|
|
14
|
+
interface RecordedSlotAction {
|
|
15
|
+
action: 'appendComposerDraft' | 'openTab' | 'openTransientTab' | 'closeTransientTab' | 'sendSessionFrame';
|
|
16
|
+
/** The tab id, the transient tab's id, or the target session of a frame or composer append. */
|
|
17
|
+
target: string | null;
|
|
18
|
+
/** The text passed to `appendComposerDraft`. */
|
|
19
|
+
text?: string;
|
|
20
|
+
/** The frame a component sent, for `sendSessionFrame`. */
|
|
21
|
+
frame?: Record<string, unknown>;
|
|
22
|
+
}
|
|
23
|
+
interface SlotPropsFixture {
|
|
24
|
+
props: WebPluginSlotProps;
|
|
25
|
+
/** Everything the component did through its props, in order. */
|
|
26
|
+
readonly actions: readonly RecordedSlotAction[];
|
|
27
|
+
/** Frames the component sent, which is what most assertions want. */
|
|
28
|
+
frames(): readonly Record<string, unknown>[];
|
|
29
|
+
}
|
|
30
|
+
interface SlotPropsOptions {
|
|
31
|
+
sessionId?: string | null;
|
|
32
|
+
statuses?: Readonly<Record<string, string>>;
|
|
33
|
+
/** Component fills this slot owner should see; keyed by slot name. */
|
|
34
|
+
slotContent?: Readonly<Record<string, ReactNode>>;
|
|
35
|
+
/** Data fills this slot owner should read back, keyed by slot name. */
|
|
36
|
+
slotData?: Readonly<Record<string, readonly SlotDataFill[]>>;
|
|
37
|
+
/** What `renderThread` returns for a plugin that renders one. */
|
|
38
|
+
thread?: (threadId: string, options?: ThreadViewOptions) => ReactNode;
|
|
39
|
+
}
|
|
40
|
+
declare function slotPropsFixture(options?: SlotPropsOptions): SlotPropsFixture;
|
|
41
|
+
interface ToolMessagePropsOptions extends SlotPropsOptions {
|
|
42
|
+
toolCallId?: string;
|
|
43
|
+
toolName: string;
|
|
44
|
+
args?: Record<string, unknown>;
|
|
45
|
+
/** The newest result; null is what the host sends before any output. */
|
|
46
|
+
result?: ToolResultView | null;
|
|
47
|
+
/** The result's text blocks joined, as the host's own fallback item shows them. */
|
|
48
|
+
output?: string;
|
|
49
|
+
running?: boolean;
|
|
50
|
+
isError?: boolean;
|
|
51
|
+
}
|
|
52
|
+
interface ToolMessagePropsFixture extends Omit<SlotPropsFixture, 'props'> {
|
|
53
|
+
props: ToolMessageRenderProps;
|
|
54
|
+
}
|
|
55
|
+
/** The props a tool's timeline item receives, in any of its four states. */
|
|
56
|
+
declare function toolMessagePropsFixture(options: ToolMessagePropsOptions): ToolMessagePropsFixture;
|
|
57
|
+
//#endregion
|
|
58
|
+
export { RecordedSlotAction, SlotPropsFixture, SlotPropsOptions, ToolMessagePropsFixture, ToolMessagePropsOptions, slotPropsFixture, toolMessagePropsFixture };
|
|
59
|
+
//# sourceMappingURL=slotProps.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slotProps.d.mts","names":[],"sources":["../../../src/services/testing/slotProps.ts"],"mappings":";;;;;;;;;;;;;UAsBiB;EACf;;EAEA;;EAEA;;EAEA,QAAQ;;UAGO;EACf,OAAO;;WAEE,kBAAkB;;EAE3B,mBAAmB;;UAGJ;EACf;EACA,WAAW,SAAS;;EAEpB,cAAc,SAAS,eAAe;;EAEtC,WAAW,SAAS,wBAAwB;;EAE5C,UAAU,kBAAkB,UAAU,sBAAsB;;iBAK9C,iBAAiB,UAAS,mBAAwB;UAmCjD,gCAAgC;EAC/C;EACA;EACA,OAAO;;EAEP,SAAS;;EAET;EACA;EACA;;UAGe,gCAAgC,KAAK;EACpD,OAAO;;;iBAMO,wBAAwB,SAAS,0BAA0B"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function e(e={}){let t=[],n={sessionId:e.sessionId===void 0?`s1`:e.sessionId,statuses:e.statuses??{},openTab:e=>{t.push({action:`openTab`,target:e})},openTransientTab:e=>{t.push({action:`openTransientTab`,target:e.id})},closeTransientTab:e=>{t.push({action:`closeTransientTab`,target:e})},appendComposerDraft:e=>{t.push({action:`appendComposerDraft`,target:n.sessionId,text:e})},sendSessionFrame:(e,n)=>{t.push({action:`sendSessionFrame`,target:e,frame:n})},renderThread:(t,n)=>e.thread?.(t,n)??null,renderSlot:t=>e.slotContent?.[t]??null,slotData:t=>e.slotData?.[t.slot]??[]};return{props:n,actions:t,frames:()=>t.flatMap(e=>e.frame?[e.frame]:[])}}function t(t){let n=e(t),r=t.result===void 0?null:t.result;return{...n,props:{...n.props,toolCallId:t.toolCallId??`call-1`,toolName:t.toolName,args:t.args??{},result:r,output:t.output??``,running:t.running??!1,isError:t.isError??!1}}}export{e as slotPropsFixture,t as toolMessagePropsFixture};
|
|
2
|
+
//# sourceMappingURL=slotProps.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slotProps.mjs","names":[],"sources":["../../../src/services/testing/slotProps.ts"],"sourcesContent":["import type { ReactNode } from 'react';\nimport type {\n SlotDataFill,\n SlotDeclaration,\n ThreadViewOptions,\n ToolMessageRenderProps,\n ToolResultView,\n TransientTab,\n WebPluginSlotProps,\n} from '../../types/webPlugin.ts';\n\n/**\n * The props the cockpit hands a plugin's components, built for a test.\n *\n * A plugin component takes fifteen props and reads three of them. Written out\n * by hand in each test, the other twelve are noise that goes stale the moment\n * the contract grows a member; written as a cast, the component compiles\n * against props the host never sends. This builds all of them, records what the\n * component did with the actions, and lets a test override the two or three it\n * cares about.\n */\n\nexport interface RecordedSlotAction {\n action: 'appendComposerDraft' | 'openTab' | 'openTransientTab' | 'closeTransientTab' | 'sendSessionFrame';\n /** The tab id, the transient tab's id, or the target session of a frame or composer append. */\n target: string | null;\n /** The text passed to `appendComposerDraft`. */\n text?: string;\n /** The frame a component sent, for `sendSessionFrame`. */\n frame?: Record<string, unknown>;\n}\n\nexport interface SlotPropsFixture {\n props: WebPluginSlotProps;\n /** Everything the component did through its props, in order. */\n readonly actions: readonly RecordedSlotAction[];\n /** Frames the component sent, which is what most assertions want. */\n frames(): readonly Record<string, unknown>[];\n}\n\nexport interface SlotPropsOptions {\n sessionId?: string | null;\n statuses?: Readonly<Record<string, string>>;\n /** Component fills this slot owner should see; keyed by slot name. */\n slotContent?: Readonly<Record<string, ReactNode>>;\n /** Data fills this slot owner should read back, keyed by slot name. */\n slotData?: Readonly<Record<string, readonly SlotDataFill[]>>;\n /** What `renderThread` returns for a plugin that renders one. */\n thread?: (threadId: string, options?: ThreadViewOptions) => ReactNode;\n}\n\nconst DEFAULT_SESSION_ID = 's1';\n\nexport function slotPropsFixture(options: SlotPropsOptions = {}): SlotPropsFixture {\n const actions: RecordedSlotAction[] = [];\n const props: WebPluginSlotProps = {\n sessionId: options.sessionId === undefined ? DEFAULT_SESSION_ID : options.sessionId,\n statuses: options.statuses ?? {},\n openTab: (tabId) => {\n actions.push({ action: 'openTab', target: tabId });\n },\n openTransientTab: (tab: TransientTab) => {\n actions.push({ action: 'openTransientTab', target: tab.id });\n },\n closeTransientTab: (tabId: string) => {\n actions.push({ action: 'closeTransientTab', target: tabId });\n },\n appendComposerDraft: (text) => {\n actions.push({ action: 'appendComposerDraft', target: props.sessionId, text });\n },\n sendSessionFrame: (sessionId, frame) => {\n actions.push({ action: 'sendSessionFrame', target: sessionId, frame });\n },\n renderThread: (threadId, threadOptions) => options.thread?.(threadId, threadOptions) ?? null,\n renderSlot: (slot) => options.slotContent?.[slot] ?? null,\n // The host resolves fills by slot name and hands the owner its own typed\n // view, so a test declares them by name too.\n slotData: <Data>(slot: SlotDeclaration<Data>) =>\n (options.slotData?.[slot.slot] ?? []) as readonly SlotDataFill<Data>[],\n };\n\n return {\n props,\n actions,\n frames: () => actions.flatMap((entry) => (entry.frame ? [entry.frame] : [])),\n };\n}\n\nexport interface ToolMessagePropsOptions extends SlotPropsOptions {\n toolCallId?: string;\n toolName: string;\n args?: Record<string, unknown>;\n /** The newest result; null is what the host sends before any output. */\n result?: ToolResultView | null;\n /** The result's text blocks joined, as the host's own fallback item shows them. */\n output?: string;\n running?: boolean;\n isError?: boolean;\n}\n\nexport interface ToolMessagePropsFixture extends Omit<SlotPropsFixture, 'props'> {\n props: ToolMessageRenderProps;\n}\n\nconst DEFAULT_TOOL_CALL_ID = 'call-1';\n\n/** The props a tool's timeline item receives, in any of its four states. */\nexport function toolMessagePropsFixture(options: ToolMessagePropsOptions): ToolMessagePropsFixture {\n const base = slotPropsFixture(options);\n const result = options.result === undefined ? null : options.result;\n return {\n ...base,\n props: {\n ...base.props,\n toolCallId: options.toolCallId ?? DEFAULT_TOOL_CALL_ID,\n toolName: options.toolName,\n args: options.args ?? {},\n result,\n output: options.output ?? '',\n running: options.running ?? false,\n isError: options.isError ?? false,\n },\n };\n}\n"],"mappings":"AAqDA,SAAgB,EAAiB,EAA4B,CAAC,EAAqB,CACjF,IAAM,EAAgC,CAAC,EACjC,EAA4B,CAChC,UAAW,EAAQ,YAAc,IAAA,GAAY,KAAqB,EAAQ,UAC1E,SAAU,EAAQ,UAAY,CAAC,EAC/B,QAAU,GAAU,CAClB,EAAQ,KAAK,CAAE,OAAQ,UAAW,OAAQ,CAAM,CAAC,CACnD,EACA,iBAAmB,GAAsB,CACvC,EAAQ,KAAK,CAAE,OAAQ,mBAAoB,OAAQ,EAAI,EAAG,CAAC,CAC7D,EACA,kBAAoB,GAAkB,CACpC,EAAQ,KAAK,CAAE,OAAQ,oBAAqB,OAAQ,CAAM,CAAC,CAC7D,EACA,oBAAsB,GAAS,CAC7B,EAAQ,KAAK,CAAE,OAAQ,sBAAuB,OAAQ,EAAM,UAAW,MAAK,CAAC,CAC/E,EACA,kBAAmB,EAAW,IAAU,CACtC,EAAQ,KAAK,CAAE,OAAQ,mBAAoB,OAAQ,EAAW,OAAM,CAAC,CACvE,EACA,cAAe,EAAU,IAAkB,EAAQ,SAAS,EAAU,CAAa,GAAK,KACxF,WAAa,GAAS,EAAQ,cAAc,IAAS,KAGrD,SAAiB,GACd,EAAQ,WAAW,EAAK,OAAS,CAAC,CACvC,EAEA,MAAO,CACL,QACA,UACA,WAAc,EAAQ,QAAS,GAAW,EAAM,MAAQ,CAAC,EAAM,KAAK,EAAI,CAAC,CAAE,CAC7E,CACF,CAqBA,SAAgB,EAAwB,EAA2D,CACjG,IAAM,EAAO,EAAiB,CAAO,EAC/B,EAAS,EAAQ,SAAW,IAAA,GAAY,KAAO,EAAQ,OAC7D,MAAO,CACL,GAAG,EACH,MAAO,CACL,GAAG,EAAK,MACR,WAAY,EAAQ,YAAc,SAClC,SAAU,EAAQ,SAClB,KAAM,EAAQ,MAAQ,CAAC,EACvB,SACA,OAAQ,EAAQ,QAAU,GAC1B,QAAS,EAAQ,SAAW,GAC5B,QAAS,EAAQ,SAAW,EAC9B,CACF,CACF"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
function e(e){return typeof e==`object`&&!!e&&e.type===`text`&&typeof e.text==`string`}function t(t){return t.filter(e).map(e=>e.text).join(`
|
|
2
|
+
`)}function n(e){let n=t(e);if(n.length===0)return[];let r=n.replaceAll(`\r
|
|
3
|
+
`,`
|
|
4
|
+
`).replaceAll(`\r`,`
|
|
5
|
+
`).replaceAll(` `,` `).split(`
|
|
6
|
+
`);for(;r.length>0&&r.at(-1)?.trim()===``;)r.pop();return r}exports.toolResultText=t,exports.toolResultTextLines=n;
|
|
7
|
+
//# sourceMappingURL=toolResult.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolResult.cjs","names":[],"sources":["../../src/services/toolResult.ts"],"sourcesContent":["/**\n * The text of a tool result, the way every tool card reads it: the `text`\n * content blocks joined with newlines, non-text blocks (images) dropped.\n */\n\nconst TAB = '\\t';\nconst TAB_WIDTH = ' ';\n\nfunction isTextBlock(block: unknown): block is { type: 'text'; text: string } {\n return (\n typeof block === 'object' &&\n block !== null &&\n (block as { type?: unknown }).type === 'text' &&\n typeof (block as { text?: unknown }).text === 'string'\n );\n}\n\n/** The text blocks of a result's content, joined with newlines. */\nexport function toolResultText(content: readonly unknown[]): string {\n return content\n .filter(isTextBlock)\n .map((block) => block.text)\n .join('\\n');\n}\n\n/**\n * toolResultText as lines a card can count and clip: tabs widened, CRLF\n * folded, trailing blank lines dropped, and no lines at all for no text.\n */\nexport function toolResultTextLines(content: readonly unknown[]): string[] {\n const text = toolResultText(content);\n if (text.length === 0) return [];\n const lines = text.replaceAll('\\r\\n', '\\n').replaceAll('\\r', '\\n').replaceAll(TAB, TAB_WIDTH).split('\\n');\n while (lines.length > 0 && lines.at(-1)?.trim() === '') lines.pop();\n return lines;\n}\n"],"mappings":"AAQA,SAAS,EAAY,EAAyD,CAC5E,OACE,OAAO,GAAU,YACjB,GACC,EAA6B,OAAS,QACvC,OAAQ,EAA6B,MAAS,QAElD,CAGA,SAAgB,EAAe,EAAqC,CAClE,OAAO,EACJ,OAAO,CAAW,CAAC,CACnB,IAAK,GAAU,EAAM,IAAI,CAAC,CAC1B,KAAK;CAAI,CACd,CAMA,SAAgB,EAAoB,EAAuC,CACzE,IAAM,EAAO,EAAe,CAAO,EACnC,GAAI,EAAK,SAAW,EAAG,MAAO,CAAC,EAC/B,IAAM,EAAQ,EAAK,WAAW;EAAQ;CAAI,CAAC,CAAC,WAAW,KAAM;CAAI,CAAC,CAAC,WAAW,IAAK,IAAS,CAAC,CAAC,MAAM;CAAI,EACxG,KAAO,EAAM,OAAS,GAAK,EAAM,GAAG,EAAE,CAAC,EAAE,KAAK,IAAM,IAAI,EAAM,IAAI,EAClE,OAAO,CACT"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/services/toolResult.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The text of a tool result, the way every tool card reads it: the `text`
|
|
4
|
+
* content blocks joined with newlines, non-text blocks (images) dropped.
|
|
5
|
+
*/
|
|
6
|
+
/** The text blocks of a result's content, joined with newlines. */
|
|
7
|
+
declare function toolResultText(content: readonly unknown[]): string;
|
|
8
|
+
/**
|
|
9
|
+
* toolResultText as lines a card can count and clip: tabs widened, CRLF
|
|
10
|
+
* folded, trailing blank lines dropped, and no lines at all for no text.
|
|
11
|
+
*/
|
|
12
|
+
declare function toolResultTextLines(content: readonly unknown[]): string[];
|
|
13
|
+
//#endregion
|
|
14
|
+
export { toolResultText, toolResultTextLines };
|
|
15
|
+
//# sourceMappingURL=toolResult.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolResult.d.cts","names":[],"sources":["../../src/services/toolResult.ts"],"mappings":";;;;;;iBAkBgB,eAAe;;;;;iBAWf,oBAAoB"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/services/toolResult.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The text of a tool result, the way every tool card reads it: the `text`
|
|
4
|
+
* content blocks joined with newlines, non-text blocks (images) dropped.
|
|
5
|
+
*/
|
|
6
|
+
/** The text blocks of a result's content, joined with newlines. */
|
|
7
|
+
declare function toolResultText(content: readonly unknown[]): string;
|
|
8
|
+
/**
|
|
9
|
+
* toolResultText as lines a card can count and clip: tabs widened, CRLF
|
|
10
|
+
* folded, trailing blank lines dropped, and no lines at all for no text.
|
|
11
|
+
*/
|
|
12
|
+
declare function toolResultTextLines(content: readonly unknown[]): string[];
|
|
13
|
+
//#endregion
|
|
14
|
+
export { toolResultText, toolResultTextLines };
|
|
15
|
+
//# sourceMappingURL=toolResult.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolResult.d.mts","names":[],"sources":["../../src/services/toolResult.ts"],"mappings":";;;;;;iBAkBgB,eAAe;;;;;iBAWf,oBAAoB"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
function e(e){return typeof e==`object`&&!!e&&e.type===`text`&&typeof e.text==`string`}function t(t){return t.filter(e).map(e=>e.text).join(`
|
|
2
|
+
`)}function n(e){let n=t(e);if(n.length===0)return[];let r=n.replaceAll(`\r
|
|
3
|
+
`,`
|
|
4
|
+
`).replaceAll(`\r`,`
|
|
5
|
+
`).replaceAll(` `,` `).split(`
|
|
6
|
+
`);for(;r.length>0&&r.at(-1)?.trim()===``;)r.pop();return r}export{t as toolResultText,n as toolResultTextLines};
|
|
7
|
+
//# sourceMappingURL=toolResult.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolResult.mjs","names":[],"sources":["../../src/services/toolResult.ts"],"sourcesContent":["/**\n * The text of a tool result, the way every tool card reads it: the `text`\n * content blocks joined with newlines, non-text blocks (images) dropped.\n */\n\nconst TAB = '\\t';\nconst TAB_WIDTH = ' ';\n\nfunction isTextBlock(block: unknown): block is { type: 'text'; text: string } {\n return (\n typeof block === 'object' &&\n block !== null &&\n (block as { type?: unknown }).type === 'text' &&\n typeof (block as { text?: unknown }).text === 'string'\n );\n}\n\n/** The text blocks of a result's content, joined with newlines. */\nexport function toolResultText(content: readonly unknown[]): string {\n return content\n .filter(isTextBlock)\n .map((block) => block.text)\n .join('\\n');\n}\n\n/**\n * toolResultText as lines a card can count and clip: tabs widened, CRLF\n * folded, trailing blank lines dropped, and no lines at all for no text.\n */\nexport function toolResultTextLines(content: readonly unknown[]): string[] {\n const text = toolResultText(content);\n if (text.length === 0) return [];\n const lines = text.replaceAll('\\r\\n', '\\n').replaceAll('\\r', '\\n').replaceAll(TAB, TAB_WIDTH).split('\\n');\n while (lines.length > 0 && lines.at(-1)?.trim() === '') lines.pop();\n return lines;\n}\n"],"mappings":"AAQA,SAAS,EAAY,EAAyD,CAC5E,OACE,OAAO,GAAU,YACjB,GACC,EAA6B,OAAS,QACvC,OAAQ,EAA6B,MAAS,QAElD,CAGA,SAAgB,EAAe,EAAqC,CAClE,OAAO,EACJ,OAAO,CAAW,CAAC,CACnB,IAAK,GAAU,EAAM,IAAI,CAAC,CAC1B,KAAK;CAAI,CACd,CAMA,SAAgB,EAAoB,EAAuC,CACzE,IAAM,EAAO,EAAe,CAAO,EACnC,GAAI,EAAK,SAAW,EAAG,MAAO,CAAC,EAC/B,IAAM,EAAQ,EAAK,WAAW;EAAQ;CAAI,CAAC,CAAC,WAAW,KAAM;CAAI,CAAC,CAAC,WAAW,IAAK,IAAS,CAAC,CAAC,MAAM;CAAI,EACxG,KAAO,EAAM,OAAS,GAAK,EAAM,GAAG,EAAE,CAAC,EAAE,KAAK,IAAM,IAAI,EAAM,IAAI,EAClE,OAAO,CACT"}
|
package/dist/testing.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./services/testing/channels.cjs"),t=require("./services/testing/render.cjs"),n=require("./services/testing/slotProps.cjs");exports.driveChannel=e.driveChannel,exports.hubChannelHarness=e.hubChannelHarness,exports.renderPlugin=t.renderPlugin,exports.slotPropsFixture=n.slotPropsFixture,exports.toolMessagePropsFixture=n.toolMessagePropsFixture;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ChannelDelivery, HubChannelHarness, HubChannelHarnessOptions, driveChannel, hubChannelHarness } from "./services/testing/channels.cjs";
|
|
2
|
+
import { RenderedPlugin, renderPlugin } from "./services/testing/render.cjs";
|
|
3
|
+
import { RecordedSlotAction, SlotPropsFixture, SlotPropsOptions, ToolMessagePropsFixture, ToolMessagePropsOptions, slotPropsFixture, toolMessagePropsFixture } from "./services/testing/slotProps.cjs";
|
|
4
|
+
export { type ChannelDelivery, type HubChannelHarness, type HubChannelHarnessOptions, type RecordedSlotAction, type RenderedPlugin, type SlotPropsFixture, type SlotPropsOptions, type ToolMessagePropsFixture, type ToolMessagePropsOptions, driveChannel, hubChannelHarness, renderPlugin, slotPropsFixture, toolMessagePropsFixture };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ChannelDelivery, HubChannelHarness, HubChannelHarnessOptions, driveChannel, hubChannelHarness } from "./services/testing/channels.mjs";
|
|
2
|
+
import { RenderedPlugin, renderPlugin } from "./services/testing/render.mjs";
|
|
3
|
+
import { RecordedSlotAction, SlotPropsFixture, SlotPropsOptions, ToolMessagePropsFixture, ToolMessagePropsOptions, slotPropsFixture, toolMessagePropsFixture } from "./services/testing/slotProps.mjs";
|
|
4
|
+
export { type ChannelDelivery, type HubChannelHarness, type HubChannelHarnessOptions, type RecordedSlotAction, type RenderedPlugin, type SlotPropsFixture, type SlotPropsOptions, type ToolMessagePropsFixture, type ToolMessagePropsOptions, driveChannel, hubChannelHarness, renderPlugin, slotPropsFixture, toolMessagePropsFixture };
|
package/dist/testing.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{driveChannel as e,hubChannelHarness as t}from"./services/testing/channels.mjs";import{renderPlugin as n}from"./services/testing/render.mjs";import{slotPropsFixture as r,toolMessagePropsFixture as i}from"./services/testing/slotProps.mjs";export{e as driveChannel,t as hubChannelHarness,n as renderPlugin,r as slotPropsFixture,i as toolMessagePropsFixture};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
//#region src/types/webHub.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The wire shape and the hub-server half of the DoomPi web plugin contract.
|
|
4
|
+
*
|
|
5
|
+
* A plugin package's hub entry exports `webHubChannels: readonly
|
|
6
|
+
* WebHubChannel[]`. The cockpit hub imports server contracts type-only, so
|
|
7
|
+
* this module must stay free of runtime values beyond plain types.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Per-plugin session data on the page socket. The channel name IS the frame
|
|
11
|
+
* type; the page routes by registry lookup and drops unknown types.
|
|
12
|
+
*/
|
|
13
|
+
interface ChannelFrame {
|
|
14
|
+
type: string;
|
|
15
|
+
sessionId: string;
|
|
16
|
+
payload: unknown;
|
|
17
|
+
}
|
|
18
|
+
interface HubSessionScope {
|
|
19
|
+
sessionId: string;
|
|
20
|
+
/** The session's working directory, for repo-scoped data sources. */
|
|
21
|
+
cwd: string;
|
|
22
|
+
}
|
|
23
|
+
interface HubSessionApiRequest {
|
|
24
|
+
basePath: string;
|
|
25
|
+
path: string;
|
|
26
|
+
method: string;
|
|
27
|
+
body?: string | Uint8Array<ArrayBuffer> | null;
|
|
28
|
+
signal?: AbortSignal;
|
|
29
|
+
}
|
|
30
|
+
interface HubChannelConnection {
|
|
31
|
+
/** Opaque for one page socket lifetime. */
|
|
32
|
+
connectionId: string;
|
|
33
|
+
}
|
|
34
|
+
/** What the hub hands a channel when it starts. */
|
|
35
|
+
interface HubChannelHost {
|
|
36
|
+
/** Every session the hub currently manages. */
|
|
37
|
+
sessions(): readonly HubSessionScope[];
|
|
38
|
+
/** Live fan-out to the session's page subscribers. */
|
|
39
|
+
publish(sessionId: string, payload: unknown): void;
|
|
40
|
+
/** Delivers only to the authenticated page socket named by connectionId. */
|
|
41
|
+
publishToConnection?(connectionId: string, sessionId: string, payload: unknown): boolean;
|
|
42
|
+
/** Authenticated machine-local transport to a session package API. */
|
|
43
|
+
requestSessionApi(scope: HubSessionScope, request: HubSessionApiRequest): Promise<Response>;
|
|
44
|
+
onNotice(message: string): void;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* One running data source. `payloadFor` answers the subscribe-time snapshot;
|
|
48
|
+
* undefined means no frame. The optional session hooks cover per-session
|
|
49
|
+
* sources; a hub-wide source may ignore them and filter inside itself.
|
|
50
|
+
*/
|
|
51
|
+
interface HubChannelSource {
|
|
52
|
+
/** unknown already admits undefined; a literal undefined result means no frame. */
|
|
53
|
+
payloadFor(scope: HubSessionScope): unknown;
|
|
54
|
+
sessionAdded?(scope: HubSessionScope): void;
|
|
55
|
+
sessionRemoved?(sessionId: string): void;
|
|
56
|
+
/**
|
|
57
|
+
* The Pi session journal (an absolute .jsonl path) behind one thread of a
|
|
58
|
+
* session, such as a subagent run; the hub tails it for the page. Undefined
|
|
59
|
+
* means not this source's thread, or not known yet: the hub keeps asking.
|
|
60
|
+
*/
|
|
61
|
+
threadJournal?(scope: HubSessionScope, threadId: string): string | undefined;
|
|
62
|
+
close(): void;
|
|
63
|
+
}
|
|
64
|
+
interface WebHubChannel {
|
|
65
|
+
/** Wire frame type; globally unique across every loaded plugin. */
|
|
66
|
+
frameType: string;
|
|
67
|
+
start(host: HubChannelHost): HubChannelSource;
|
|
68
|
+
/** Allows an authenticated connection to acknowledge targeted frames after its session subscription changes. */
|
|
69
|
+
receiveWithoutSubscription?: boolean;
|
|
70
|
+
/** Receives only frames matching frameType and a live session scope. */
|
|
71
|
+
receive?(scope: HubSessionScope, payload: unknown, connection: HubChannelConnection): void;
|
|
72
|
+
/** The authenticated page socket has closed. */
|
|
73
|
+
disconnected?(connection: HubChannelConnection): void;
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
export { ChannelFrame, HubChannelConnection, HubChannelHost, HubChannelSource, HubSessionApiRequest, HubSessionScope, WebHubChannel };
|
|
77
|
+
//# sourceMappingURL=webHub.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webHub.d.cts","names":[],"sources":["../../src/types/webHub.ts"],"mappings":";;;;;;;;;;;;UAYiB;EACf;EACA;EACA;;UAGe;EACf;;EAEA;;UAGe;EACf;EACA;EACA;EACA,gBAAgB,WAAW;EAC3B,SAAS;;UAGM;;EAEf;;;UAIe;;EAEf,qBAAqB;;EAErB,QAAQ,mBAAmB;;EAE3B,qBAAqB,sBAAsB,mBAAmB;;EAE9D,kBAAkB,OAAO,iBAAiB,SAAS,uBAAuB,QAAQ;EAClF,SAAS;;;;;;;UAQM;;EAEf,WAAW,OAAO;EAClB,cAAc,OAAO;EACrB,gBAAgB;;;;;;EAMhB,eAAe,OAAO,iBAAiB;EACvC;;UAGe;;EAEf;EACA,MAAM,MAAM,iBAAiB;;EAE7B;;EAEA,SAAS,OAAO,iBAAiB,kBAAkB,YAAY;;EAE/D,cAAc,YAAY"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
//#region src/types/webHub.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The wire shape and the hub-server half of the DoomPi web plugin contract.
|
|
4
|
+
*
|
|
5
|
+
* A plugin package's hub entry exports `webHubChannels: readonly
|
|
6
|
+
* WebHubChannel[]`. The cockpit hub imports server contracts type-only, so
|
|
7
|
+
* this module must stay free of runtime values beyond plain types.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Per-plugin session data on the page socket. The channel name IS the frame
|
|
11
|
+
* type; the page routes by registry lookup and drops unknown types.
|
|
12
|
+
*/
|
|
13
|
+
interface ChannelFrame {
|
|
14
|
+
type: string;
|
|
15
|
+
sessionId: string;
|
|
16
|
+
payload: unknown;
|
|
17
|
+
}
|
|
18
|
+
interface HubSessionScope {
|
|
19
|
+
sessionId: string;
|
|
20
|
+
/** The session's working directory, for repo-scoped data sources. */
|
|
21
|
+
cwd: string;
|
|
22
|
+
}
|
|
23
|
+
interface HubSessionApiRequest {
|
|
24
|
+
basePath: string;
|
|
25
|
+
path: string;
|
|
26
|
+
method: string;
|
|
27
|
+
body?: string | Uint8Array<ArrayBuffer> | null;
|
|
28
|
+
signal?: AbortSignal;
|
|
29
|
+
}
|
|
30
|
+
interface HubChannelConnection {
|
|
31
|
+
/** Opaque for one page socket lifetime. */
|
|
32
|
+
connectionId: string;
|
|
33
|
+
}
|
|
34
|
+
/** What the hub hands a channel when it starts. */
|
|
35
|
+
interface HubChannelHost {
|
|
36
|
+
/** Every session the hub currently manages. */
|
|
37
|
+
sessions(): readonly HubSessionScope[];
|
|
38
|
+
/** Live fan-out to the session's page subscribers. */
|
|
39
|
+
publish(sessionId: string, payload: unknown): void;
|
|
40
|
+
/** Delivers only to the authenticated page socket named by connectionId. */
|
|
41
|
+
publishToConnection?(connectionId: string, sessionId: string, payload: unknown): boolean;
|
|
42
|
+
/** Authenticated machine-local transport to a session package API. */
|
|
43
|
+
requestSessionApi(scope: HubSessionScope, request: HubSessionApiRequest): Promise<Response>;
|
|
44
|
+
onNotice(message: string): void;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* One running data source. `payloadFor` answers the subscribe-time snapshot;
|
|
48
|
+
* undefined means no frame. The optional session hooks cover per-session
|
|
49
|
+
* sources; a hub-wide source may ignore them and filter inside itself.
|
|
50
|
+
*/
|
|
51
|
+
interface HubChannelSource {
|
|
52
|
+
/** unknown already admits undefined; a literal undefined result means no frame. */
|
|
53
|
+
payloadFor(scope: HubSessionScope): unknown;
|
|
54
|
+
sessionAdded?(scope: HubSessionScope): void;
|
|
55
|
+
sessionRemoved?(sessionId: string): void;
|
|
56
|
+
/**
|
|
57
|
+
* The Pi session journal (an absolute .jsonl path) behind one thread of a
|
|
58
|
+
* session, such as a subagent run; the hub tails it for the page. Undefined
|
|
59
|
+
* means not this source's thread, or not known yet: the hub keeps asking.
|
|
60
|
+
*/
|
|
61
|
+
threadJournal?(scope: HubSessionScope, threadId: string): string | undefined;
|
|
62
|
+
close(): void;
|
|
63
|
+
}
|
|
64
|
+
interface WebHubChannel {
|
|
65
|
+
/** Wire frame type; globally unique across every loaded plugin. */
|
|
66
|
+
frameType: string;
|
|
67
|
+
start(host: HubChannelHost): HubChannelSource;
|
|
68
|
+
/** Allows an authenticated connection to acknowledge targeted frames after its session subscription changes. */
|
|
69
|
+
receiveWithoutSubscription?: boolean;
|
|
70
|
+
/** Receives only frames matching frameType and a live session scope. */
|
|
71
|
+
receive?(scope: HubSessionScope, payload: unknown, connection: HubChannelConnection): void;
|
|
72
|
+
/** The authenticated page socket has closed. */
|
|
73
|
+
disconnected?(connection: HubChannelConnection): void;
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
export { ChannelFrame, HubChannelConnection, HubChannelHost, HubChannelSource, HubSessionApiRequest, HubSessionScope, WebHubChannel };
|
|
77
|
+
//# sourceMappingURL=webHub.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webHub.d.mts","names":[],"sources":["../../src/types/webHub.ts"],"mappings":";;;;;;;;;;;;UAYiB;EACf;EACA;EACA;;UAGe;EACf;;EAEA;;UAGe;EACf;EACA;EACA;EACA,gBAAgB,WAAW;EAC3B,SAAS;;UAGM;;EAEf;;;UAIe;;EAEf,qBAAqB;;EAErB,QAAQ,mBAAmB;;EAE3B,qBAAqB,sBAAsB,mBAAmB;;EAE9D,kBAAkB,OAAO,iBAAiB,SAAS,uBAAuB,QAAQ;EAClF,SAAS;;;;;;;UAQM;;EAEf,WAAW,OAAO;EAClB,cAAc,OAAO;EACrB,gBAAgB;;;;;;EAMhB,eAAe,OAAO,iBAAiB;EACvC;;UAGe;;EAEf;EACA,MAAM,MAAM,iBAAiB;;EAE7B;;EAEA,SAAS,OAAO,iBAAiB,kBAAkB,YAAY;;EAE/D,cAAc,YAAY"}
|