@agimon-ai/po-read 0.0.0-alpha.21 → 0.0.0-alpha.23
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.
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { defineNativePlugin, defineToolRenderer } from "@agimon-ai/po-core/native";
|
|
2
|
+
import { View } from "react-native-unistyles/components/native/View";
|
|
3
|
+
import { Text } from "react-native-unistyles/components/native/Text";
|
|
4
|
+
import { Image } from "react-native-unistyles/components/native/Image";
|
|
5
|
+
import { HashlineLines, MessageItem, MessageItemBody, MessageItemHeader, MessageItemStatus, ToolPathLink, fontOf, hashlineBody, resultTextLines, toolTone } from "@agimon-ai/po-native-components";
|
|
6
|
+
import { StyleSheet } from "react-native-unistyles";
|
|
7
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
//#region src/extensions/workspaces/sessions/(frontend)/tool/_lib/readToolView.ts
|
|
9
|
+
function optionalNumber(value) {
|
|
10
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
11
|
+
}
|
|
12
|
+
/** What the read call heading shows: the path, then the offset and limit when given. */
|
|
13
|
+
function readCallView(args) {
|
|
14
|
+
const offset = optionalNumber(args.offset);
|
|
15
|
+
const limit = optionalNumber(args.limit);
|
|
16
|
+
return {
|
|
17
|
+
path: typeof args.path === "string" ? args.path : "",
|
|
18
|
+
details: [offset === void 0 ? void 0 : `from ${offset}`, limit === void 0 ? void 0 : `${limit} lines`].filter((value) => value !== void 0 && value.length > 0)
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const IMAGE_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
22
|
+
"image/png",
|
|
23
|
+
"image/jpeg",
|
|
24
|
+
"image/gif",
|
|
25
|
+
"image/webp"
|
|
26
|
+
]);
|
|
27
|
+
/** The image blocks a read returned, limited to the formats both cards can draw. */
|
|
28
|
+
function resultImages(content) {
|
|
29
|
+
return content.flatMap((block) => {
|
|
30
|
+
if (typeof block !== "object" || block === null || Array.isArray(block)) return [];
|
|
31
|
+
const value = block;
|
|
32
|
+
return value.type === "image" && typeof value.data === "string" && typeof value.mimeType === "string" && IMAGE_MIME_TYPES.has(value.mimeType) ? [{
|
|
33
|
+
data: value.data,
|
|
34
|
+
mimeType: value.mimeType
|
|
35
|
+
}] : [];
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region src/extensions/workspaces/sessions/(frontend)/tool/_components/ReadToolMessage.native.tsx
|
|
40
|
+
/** Height an image result gets in the card; the web caps it at 24rem. */
|
|
41
|
+
const IMAGE_HEIGHT = 240;
|
|
42
|
+
/**
|
|
43
|
+
* The read tool's timeline item on native, as the web's ReadToolMessage: the
|
|
44
|
+
* path and range in the header and, once expanded, the anchored lines with a
|
|
45
|
+
* line-number gutter and any image the read returned, or the tool's message
|
|
46
|
+
* in red when the read failed.
|
|
47
|
+
*
|
|
48
|
+
* ponytail: an image is drawn in the card and does not open full size; the
|
|
49
|
+
* web opens it in a new tab. Route it through renderMediaPreview if asked.
|
|
50
|
+
*/
|
|
51
|
+
function ReadToolMessage({ args, result, output, running, isError, fileTabFor, openTransientTab }) {
|
|
52
|
+
const view = readCallView(args);
|
|
53
|
+
const images = resultImages(result?.content ?? []);
|
|
54
|
+
const tab = fileTabFor(view.path);
|
|
55
|
+
const body = result === null || isError ? null : hashlineBody(result, output, "read", true);
|
|
56
|
+
return /* @__PURE__ */ jsx(MessageItem, {
|
|
57
|
+
tone: toolTone({
|
|
58
|
+
running,
|
|
59
|
+
isError
|
|
60
|
+
}),
|
|
61
|
+
expandable: true,
|
|
62
|
+
defaultExpanded: false,
|
|
63
|
+
children: ({ expanded }) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(MessageItemHeader, {
|
|
64
|
+
title: "read",
|
|
65
|
+
children: /* @__PURE__ */ jsxs(View, {
|
|
66
|
+
testID: "tool-call-read",
|
|
67
|
+
style: styles.summary,
|
|
68
|
+
children: [/* @__PURE__ */ jsx(ToolPathLink, {
|
|
69
|
+
path: view.path,
|
|
70
|
+
...tab === void 0 ? {} : { onOpen: () => openTransientTab(tab) }
|
|
71
|
+
}), view.details.length > 0 ? /* @__PURE__ */ jsxs(Text, {
|
|
72
|
+
numberOfLines: 1,
|
|
73
|
+
style: [styles.sans, styles.detail],
|
|
74
|
+
children: ["· ", view.details.join(" · ")]
|
|
75
|
+
}) : null]
|
|
76
|
+
})
|
|
77
|
+
}), expanded ? isError ? /* @__PURE__ */ jsxs(MessageItemBody, {
|
|
78
|
+
testID: "tool-result-read",
|
|
79
|
+
children: [/* @__PURE__ */ jsx(MessageItemStatus, {
|
|
80
|
+
tone: "error",
|
|
81
|
+
children: "failed"
|
|
82
|
+
}), resultTextLines(result, output).map((line, index) => /* @__PURE__ */ jsx(Text, {
|
|
83
|
+
selectable: true,
|
|
84
|
+
style: [styles.sans, styles.error],
|
|
85
|
+
children: line
|
|
86
|
+
}, `${String(index)}-${line}`))]
|
|
87
|
+
}) : body === null ? running ? /* @__PURE__ */ jsx(MessageItemBody, {
|
|
88
|
+
testID: "tool-result-read",
|
|
89
|
+
children: /* @__PURE__ */ jsx(MessageItemStatus, {
|
|
90
|
+
tone: "running",
|
|
91
|
+
children: "running"
|
|
92
|
+
})
|
|
93
|
+
}) : null : body.shown.length === 0 && body.notice === void 0 && images.length === 0 ? null : /* @__PURE__ */ jsxs(MessageItemBody, {
|
|
94
|
+
testID: "tool-result-read",
|
|
95
|
+
children: [
|
|
96
|
+
/* @__PURE__ */ jsx(HashlineLines, {
|
|
97
|
+
lines: body.shown,
|
|
98
|
+
gutter: body.gutter,
|
|
99
|
+
path: view.path
|
|
100
|
+
}),
|
|
101
|
+
images.map((image, index) => /* @__PURE__ */ jsx(Image, {
|
|
102
|
+
source: { uri: `data:${image.mimeType};base64,${image.data}` },
|
|
103
|
+
accessibilityLabel: `Read result ${String(index + 1)}`,
|
|
104
|
+
testID: "tool-result-read-image",
|
|
105
|
+
resizeMode: "contain",
|
|
106
|
+
style: styles.image
|
|
107
|
+
}, `${image.mimeType}:${String(index)}`)),
|
|
108
|
+
body.notice !== void 0 ? /* @__PURE__ */ jsx(Text, {
|
|
109
|
+
style: [styles.sans, styles.detail],
|
|
110
|
+
children: body.notice
|
|
111
|
+
}) : null
|
|
112
|
+
]
|
|
113
|
+
}) : null] })
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
const styles = StyleSheet.create((theme) => ({
|
|
117
|
+
summary: {
|
|
118
|
+
flex: 1,
|
|
119
|
+
flexDirection: "row",
|
|
120
|
+
alignItems: "center",
|
|
121
|
+
gap: theme.spacing(2),
|
|
122
|
+
minWidth: 0,
|
|
123
|
+
uni__dependencies: [0]
|
|
124
|
+
},
|
|
125
|
+
sans: {
|
|
126
|
+
fontFamily: fontOf(theme.fontFamily.sans),
|
|
127
|
+
fontSize: theme.fontSize.base,
|
|
128
|
+
lineHeight: theme.lineHeight.base,
|
|
129
|
+
uni__dependencies: [0]
|
|
130
|
+
},
|
|
131
|
+
detail: {
|
|
132
|
+
flexShrink: 1,
|
|
133
|
+
color: theme.colors.faint,
|
|
134
|
+
uni__dependencies: [0]
|
|
135
|
+
},
|
|
136
|
+
error: {
|
|
137
|
+
color: theme.colors.red,
|
|
138
|
+
uni__dependencies: [0]
|
|
139
|
+
},
|
|
140
|
+
image: {
|
|
141
|
+
width: "100%",
|
|
142
|
+
height: IMAGE_HEIGHT,
|
|
143
|
+
borderRadius: theme.borderRadius.md,
|
|
144
|
+
borderWidth: 1,
|
|
145
|
+
borderColor: theme.colors["border-soft"],
|
|
146
|
+
uni__dependencies: [0]
|
|
147
|
+
}
|
|
148
|
+
}));
|
|
149
|
+
//#endregion
|
|
150
|
+
//#region src/extensions/workspaces/sessions/(frontend)/tool/read.native.tsx
|
|
151
|
+
var read_native_default = defineToolRenderer({ message: ReadToolMessage });
|
|
152
|
+
//#endregion
|
|
153
|
+
//#region generated/native.ts
|
|
154
|
+
const via = (identity, value) => value === void 0 ? void 0 : {
|
|
155
|
+
...identity,
|
|
156
|
+
...value
|
|
157
|
+
};
|
|
158
|
+
const nativePlugin = defineNativePlugin({
|
|
159
|
+
id: "read",
|
|
160
|
+
session: { get toolRenderers() {
|
|
161
|
+
return [via({ tools: ["read"] }, read_native_default)];
|
|
162
|
+
} }
|
|
163
|
+
});
|
|
164
|
+
//#endregion
|
|
165
|
+
export { nativePlugin };
|
|
166
|
+
|
|
167
|
+
//# sourceMappingURL=native.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native.mjs","names":["ToolMessageRenderProps","fontOf","HashlineLines","hashlineBody","MessageItem","MessageItemBody","MessageItemHeader","MessageItemStatus","resultTextLines","ToolPathLink","toolTone","PoNativeTheme","StyleSheet","readCallView","resultImages","IMAGE_HEIGHT","ReadToolMessage","args","result","output","running","isError","fileTabFor","openTransientTab","view","images","content","tab","path","body","expanded","styles","summary","undefined","onOpen","details","length","sans","detail","join","map","line","index","String","error","shown","notice","gutter","image","mimeType","uri","data","create","theme","flex","flexDirection","alignItems","gap","spacing","minWidth","uni__dependencies","fontFamily","fontSize","base","lineHeight","flexShrink","color","colors","faint","red","width","height","borderRadius","md","borderWidth","borderColor","toolRead"],"sources":["../../src/extensions/workspaces/sessions/(frontend)/tool/_lib/readToolView.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/_components/ReadToolMessage.native.tsx","../../src/extensions/workspaces/sessions/(frontend)/tool/read.native.tsx","../../generated/native.ts"],"sourcesContent":["// Imports nothing at runtime: the web and native cards share it, and the native\n// bundle may not load the web component library.\n\nexport interface ReadCallView {\n readonly path: string;\n /** `from N` and `N lines`, as the TUI's call heading lists them. */\n readonly details: readonly string[];\n}\n\nfunction optionalNumber(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\n/** What the read call heading shows: the path, then the offset and limit when given. */\nexport function readCallView(args: Readonly<Record<string, unknown>>): ReadCallView {\n const offset = optionalNumber(args.offset);\n const limit = optionalNumber(args.limit);\n return {\n path: typeof args.path === 'string' ? args.path : '',\n details: [\n offset === undefined ? undefined : `from ${offset}`,\n limit === undefined ? undefined : `${limit} lines`,\n ].filter((value): value is string => value !== undefined && value.length > 0),\n };\n}\n\nconst IMAGE_MIME_TYPES = new Set(['image/png', 'image/jpeg', 'image/gif', 'image/webp']);\n\n/** The image blocks a read returned, limited to the formats both cards can draw. */\nexport function resultImages(content: readonly unknown[]): Array<{ data: string; mimeType: string }> {\n return content.flatMap((block) => {\n if (typeof block !== 'object' || block === null || Array.isArray(block)) return [];\n const value = block as Record<string, unknown>;\n return value.type === 'image' &&\n typeof value.data === 'string' &&\n typeof value.mimeType === 'string' &&\n IMAGE_MIME_TYPES.has(value.mimeType)\n ? [{ data: value.data, mimeType: value.mimeType }]\n : [];\n });\n}\n","import type { ToolMessageRenderProps } from '@agimon-ai/po-core/native';\nimport {\n fontOf,\n HashlineLines,\n hashlineBody,\n MessageItem,\n MessageItemBody,\n MessageItemHeader,\n MessageItemStatus,\n resultTextLines,\n ToolPathLink,\n toolTone,\n} from '@agimon-ai/po-native-components';\nimport type { PoNativeTheme } from '@agimon-ai/po-web-components/nativeTheme';\nimport { Image, Text, View } from 'react-native';\nimport { StyleSheet } from 'react-native-unistyles';\n\nimport { readCallView, resultImages } from '../_lib/readToolView';\n\n/** Height an image result gets in the card; the web caps it at 24rem. */\nconst IMAGE_HEIGHT = 240;\n\n/**\n * The read tool's timeline item on native, as the web's ReadToolMessage: the\n * path and range in the header and, once expanded, the anchored lines with a\n * line-number gutter and any image the read returned, or the tool's message\n * in red when the read failed.\n *\n * ponytail: an image is drawn in the card and does not open full size; the\n * web opens it in a new tab. Route it through renderMediaPreview if asked.\n */\nexport function ReadToolMessage({\n args,\n result,\n output,\n running,\n isError,\n fileTabFor,\n openTransientTab,\n}: ToolMessageRenderProps) {\n const view = readCallView(args);\n const images = resultImages(result?.content ?? []);\n const tab = fileTabFor(view.path);\n const body = result === null || isError ? null : hashlineBody(result, output, 'read', true);\n return (\n <MessageItem tone={toolTone({ running, isError })} expandable defaultExpanded={false}>\n {({ expanded }) => (\n <>\n <MessageItemHeader title=\"read\">\n <View testID=\"tool-call-read\" style={styles.summary}>\n <ToolPathLink path={view.path} {...(tab === undefined ? {} : { onOpen: () => openTransientTab(tab) })} />\n {view.details.length > 0 ? (\n <Text numberOfLines={1} style={[styles.sans, styles.detail]}>\n · {view.details.join(' · ')}\n </Text>\n ) : null}\n </View>\n </MessageItemHeader>\n {expanded ? (\n isError ? (\n <MessageItemBody testID=\"tool-result-read\">\n <MessageItemStatus tone=\"error\">failed</MessageItemStatus>\n {resultTextLines(result, output).map((line, index) => (\n <Text key={`${String(index)}-${line}`} selectable style={[styles.sans, styles.error]}>\n {line}\n </Text>\n ))}\n </MessageItemBody>\n ) : body === null ? (\n running ? (\n <MessageItemBody testID=\"tool-result-read\">\n <MessageItemStatus tone=\"running\">running</MessageItemStatus>\n </MessageItemBody>\n ) : null\n ) : body.shown.length === 0 && body.notice === undefined && images.length === 0 ? null : (\n <MessageItemBody testID=\"tool-result-read\">\n <HashlineLines lines={body.shown} gutter={body.gutter} path={view.path} />\n {images.map((image, index) => (\n <Image\n key={`${image.mimeType}:${String(index)}`}\n source={{ uri: `data:${image.mimeType};base64,${image.data}` }}\n accessibilityLabel={`Read result ${String(index + 1)}`}\n testID=\"tool-result-read-image\"\n resizeMode=\"contain\"\n style={styles.image}\n />\n ))}\n {body.notice !== undefined ? <Text style={[styles.sans, styles.detail]}>{body.notice}</Text> : null}\n </MessageItemBody>\n )\n ) : null}\n </>\n )}\n </MessageItem>\n );\n}\n\nconst styles = StyleSheet.create((theme: PoNativeTheme) => ({\n summary: { flex: 1, flexDirection: 'row', alignItems: 'center', gap: theme.spacing(2), minWidth: 0 },\n sans: {\n fontFamily: fontOf(theme.fontFamily.sans),\n fontSize: theme.fontSize.base,\n lineHeight: theme.lineHeight.base,\n },\n detail: { flexShrink: 1, color: theme.colors.faint },\n error: { color: theme.colors.red },\n image: {\n width: '100%',\n height: IMAGE_HEIGHT,\n borderRadius: theme.borderRadius.md,\n borderWidth: 1,\n borderColor: theme.colors['border-soft'],\n },\n}));\n","import { defineToolRenderer } from '@agimon-ai/po-core/native';\n\nimport { ReadToolMessage } from './_components/ReadToolMessage.native';\n\nexport default defineToolRenderer({ message: ReadToolMessage });\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineNativePlugin, type WebPluginContributions } from '@agimon-ai/po-core/native';\n\nimport toolRead from '../src/extensions/workspaces/sessions/(frontend)/tool/read.native';\n\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const nativePlugin = defineNativePlugin({\n id: 'read',\n session: {\n get toolRenderers(): WebPluginContributions['toolRenderers'] { return [via({ tools: ['read'] }, toolRead)]; },\n },\n});\n"],"mappings":"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"}
|
package/dist/extensions/web.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineToolRenderer, defineWebPlugin } from "@agimon-ai/po-core/web";
|
|
2
|
-
import { HashlineLines, MessageItem, MessageItemBody, MessageItemHeader, MessageItemStatus, ToolPathLink,
|
|
2
|
+
import { HashlineLines, MessageItem, MessageItemBody, MessageItemHeader, MessageItemStatus, ToolPathLink, hashlineBody, resultTextLines, toolTone } from "@agimon-ai/po-web-components";
|
|
3
3
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
//#region src/extensions/workspaces/sessions/(frontend)/tool/_lib/readToolView.ts
|
|
5
5
|
function optionalNumber(value) {
|
|
@@ -11,17 +11,16 @@ function readCallView(args) {
|
|
|
11
11
|
const limit = optionalNumber(args.limit);
|
|
12
12
|
return {
|
|
13
13
|
path: typeof args.path === "string" ? args.path : "",
|
|
14
|
-
details:
|
|
14
|
+
details: [offset === void 0 ? void 0 : `from ${offset}`, limit === void 0 ? void 0 : `${limit} lines`].filter((value) => value !== void 0 && value.length > 0)
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
|
-
//#endregion
|
|
18
|
-
//#region src/extensions/workspaces/sessions/(frontend)/tool/_components/ReadToolMessage.tsx
|
|
19
17
|
const IMAGE_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
20
18
|
"image/png",
|
|
21
19
|
"image/jpeg",
|
|
22
20
|
"image/gif",
|
|
23
21
|
"image/webp"
|
|
24
22
|
]);
|
|
23
|
+
/** The image blocks a read returned, limited to the formats both cards can draw. */
|
|
25
24
|
function resultImages(content) {
|
|
26
25
|
return content.flatMap((block) => {
|
|
27
26
|
if (typeof block !== "object" || block === null || Array.isArray(block)) return [];
|
|
@@ -32,6 +31,8 @@ function resultImages(content) {
|
|
|
32
31
|
}] : [];
|
|
33
32
|
});
|
|
34
33
|
}
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/extensions/workspaces/sessions/(frontend)/tool/_components/ReadToolMessage.tsx
|
|
35
36
|
/**
|
|
36
37
|
* The read tool's timeline item, the web half of its renderCall and
|
|
37
38
|
* renderResult: the call summary in the header and, when expanded, the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web.mjs","names":["toolRead"],"sources":["../../src/extensions/workspaces/sessions/(frontend)/tool/_lib/readToolView.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/_components/ReadToolMessage.tsx","../../src/extensions/workspaces/sessions/(frontend)/tool/read.web.tsx","../../generated/web.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"web.mjs","names":["toolRead"],"sources":["../../src/extensions/workspaces/sessions/(frontend)/tool/_lib/readToolView.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/_components/ReadToolMessage.tsx","../../src/extensions/workspaces/sessions/(frontend)/tool/read.web.tsx","../../generated/web.ts"],"sourcesContent":["// Imports nothing at runtime: the web and native cards share it, and the native\n// bundle may not load the web component library.\n\nexport interface ReadCallView {\n readonly path: string;\n /** `from N` and `N lines`, as the TUI's call heading lists them. */\n readonly details: readonly string[];\n}\n\nfunction optionalNumber(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\n/** What the read call heading shows: the path, then the offset and limit when given. */\nexport function readCallView(args: Readonly<Record<string, unknown>>): ReadCallView {\n const offset = optionalNumber(args.offset);\n const limit = optionalNumber(args.limit);\n return {\n path: typeof args.path === 'string' ? args.path : '',\n details: [\n offset === undefined ? undefined : `from ${offset}`,\n limit === undefined ? undefined : `${limit} lines`,\n ].filter((value): value is string => value !== undefined && value.length > 0),\n };\n}\n\nconst IMAGE_MIME_TYPES = new Set(['image/png', 'image/jpeg', 'image/gif', 'image/webp']);\n\n/** The image blocks a read returned, limited to the formats both cards can draw. */\nexport function resultImages(content: readonly unknown[]): Array<{ data: string; mimeType: string }> {\n return content.flatMap((block) => {\n if (typeof block !== 'object' || block === null || Array.isArray(block)) return [];\n const value = block as Record<string, unknown>;\n return value.type === 'image' &&\n typeof value.data === 'string' &&\n typeof value.mimeType === 'string' &&\n IMAGE_MIME_TYPES.has(value.mimeType)\n ? [{ data: value.data, mimeType: value.mimeType }]\n : [];\n });\n}\n","import type { ToolMessageRenderProps } from '@agimon-ai/po-core/web';\nimport {\n HashlineLines,\n hashlineBody,\n MessageItem,\n MessageItemBody,\n MessageItemHeader,\n MessageItemStatus,\n resultTextLines,\n ToolPathLink,\n toolTone,\n} from '@agimon-ai/po-web-components';\n\nimport { readCallView, resultImages } from '../_lib/readToolView';\n\n/**\n * The read tool's timeline item, the web half of its renderCall and\n * renderResult: the call summary in the header and, when expanded, the\n * anchored lines with a line-number gutter in the body. A failure shows the\n * tool's message in red inside the expanded body instead.\n */\nexport function ReadToolMessage({\n args,\n result,\n output,\n running,\n isError,\n fileTabFor,\n openTransientTab,\n}: ToolMessageRenderProps) {\n const view = readCallView(args);\n const images = resultImages(result?.content ?? []);\n // A read is the one call whose file the session usually has not changed, so\n // this is the link that opens it read-only rather than in its history.\n const tab = fileTabFor(view.path);\n const body = result === null || isError ? null : hashlineBody(result, output, 'read', true);\n return (\n <MessageItem tone={toolTone({ running, isError })} expandable defaultExpanded={false}>\n {({ expanded }) => {\n return (\n <>\n <MessageItemHeader title=\"read\">\n <span data-testid=\"tool-call-read\" className=\"flex min-w-0 flex-1 items-center gap-2\">\n <ToolPathLink\n path={view.path}\n {...(tab === undefined ? {} : { onOpen: () => openTransientTab(tab) })}\n />\n {view.details.length > 0 ? (\n <span className=\"shrink-0 text-po-faint\">· {view.details.join(' · ')}</span>\n ) : null}\n </span>\n </MessageItemHeader>\n {expanded ? (\n isError ? (\n <MessageItemBody data-testid=\"tool-result-read\" className=\"flex flex-col\">\n <MessageItemStatus tone=\"error\">failed</MessageItemStatus>\n {resultTextLines(result, output).map((line, index) => (\n <span key={`${String(index)}-${line}`} className=\"whitespace-pre-wrap break-words text-po-red\">\n {line}\n </span>\n ))}\n </MessageItemBody>\n ) : body === null ? (\n running ? (\n <MessageItemBody data-testid=\"tool-result-read\">\n <MessageItemStatus tone=\"running\">running</MessageItemStatus>\n </MessageItemBody>\n ) : null\n ) : body.shown.length === 0 && body.notice === undefined && images.length === 0 ? null : (\n <MessageItemBody data-testid=\"tool-result-read\" className=\"flex flex-col gap-1\">\n {/* A read body is one file with no heading of its own, so the\n call's path is what names the grammar for it. */}\n <HashlineLines lines={body.shown} gutter={body.gutter} path={view.path} />\n {images.map((image, index) => {\n const url = `data:${image.mimeType};base64,${image.data}`;\n return (\n <a\n key={`${image.mimeType}:${String(index)}`}\n href={url}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"self-start\"\n >\n <img\n src={url}\n alt={`Read result ${String(index + 1)}`}\n data-testid=\"tool-result-read-image\"\n className=\"h-auto max-h-96 max-w-full rounded-md border border-po-border-soft object-contain\"\n />\n </a>\n );\n })}\n {body.notice !== undefined ? <span className=\"text-po-faint\">{body.notice}</span> : null}\n </MessageItemBody>\n )\n ) : null}\n </>\n );\n }}\n </MessageItem>\n );\n}\n","import { defineToolRenderer } from '@agimon-ai/po-core/web';\n\nimport { ReadToolMessage } from './_components/ReadToolMessage';\n\nexport default defineToolRenderer({ message: ReadToolMessage });\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineWebPlugin, type WebPluginContributions } from '@agimon-ai/po-core/web';\n\nimport toolRead from '../src/extensions/workspaces/sessions/(frontend)/tool/read.web';\n\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const webPlugin = defineWebPlugin({\n id: 'read',\n session: {\n get toolRenderers(): WebPluginContributions['toolRenderers'] { return [via({ tools: ['read'] }, toolRead)]; },\n },\n});\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agimon-ai/po-read",
|
|
3
|
-
"version": "0.0.0-alpha.
|
|
3
|
+
"version": "0.0.0-alpha.23",
|
|
4
4
|
"description": "Snapshot-bound hashline read tool for Pi and Po.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -43,6 +43,9 @@
|
|
|
43
43
|
"import": "./dist/apiContracts.mjs",
|
|
44
44
|
"require": "./dist/apiContracts.cjs"
|
|
45
45
|
},
|
|
46
|
+
"./extensions/native": {
|
|
47
|
+
"import": "./dist/extensions/native.mjs"
|
|
48
|
+
},
|
|
46
49
|
"./extensions/server": {
|
|
47
50
|
"types": "./dist/extensions/server.d.mts",
|
|
48
51
|
"import": "./dist/extensions/server.mjs",
|
|
@@ -57,16 +60,17 @@
|
|
|
57
60
|
"access": "public"
|
|
58
61
|
},
|
|
59
62
|
"dependencies": {
|
|
60
|
-
"@agimon-ai/po-config": "0.0.0-alpha.
|
|
61
|
-
"@agimon-ai/po-core": "0.0.0-alpha.
|
|
62
|
-
"@agimon-ai/po-hashline": "0.0.0-alpha.
|
|
63
|
-
"@agimon-ai/po-ui": "0.0.0-alpha.
|
|
64
|
-
"@agimon-ai/po-web-components": "0.0.0-alpha.
|
|
63
|
+
"@agimon-ai/po-config": "0.0.0-alpha.23",
|
|
64
|
+
"@agimon-ai/po-core": "0.0.0-alpha.23",
|
|
65
|
+
"@agimon-ai/po-hashline": "0.0.0-alpha.23",
|
|
66
|
+
"@agimon-ai/po-ui": "0.0.0-alpha.23",
|
|
67
|
+
"@agimon-ai/po-web-components": "0.0.0-alpha.23",
|
|
65
68
|
"@deepseek-ai/cordis": "4.0.5",
|
|
66
69
|
"typebox": "1.3.37"
|
|
67
70
|
},
|
|
68
71
|
"devDependencies": {
|
|
69
|
-
"@agimon-ai/po-build": "0.0.0-alpha.
|
|
72
|
+
"@agimon-ai/po-build": "0.0.0-alpha.23",
|
|
73
|
+
"@agimon-ai/po-native-components": "0.0.0-alpha.23",
|
|
70
74
|
"@earendil-works/pi-coding-agent": "1.3.0",
|
|
71
75
|
"@tanstack/react-store": "0.11.2",
|
|
72
76
|
"@tanstack/store": "0.11.2",
|
|
@@ -75,16 +79,30 @@
|
|
|
75
79
|
"@vitest/coverage-v8": "5.0.4",
|
|
76
80
|
"react": "19.3.0",
|
|
77
81
|
"react-dom": "19.3.0",
|
|
82
|
+
"react-native": "0.86.3",
|
|
83
|
+
"react-native-unistyles": "3.5.3",
|
|
78
84
|
"tsdown": "0.23.1",
|
|
79
85
|
"typescript": "7.0.2",
|
|
80
86
|
"vitest": "5.0.4"
|
|
81
87
|
},
|
|
82
88
|
"peerDependencies": {
|
|
83
|
-
"@
|
|
89
|
+
"@agimon-ai/po-native-components": "0.0.0-alpha.23",
|
|
90
|
+
"@earendil-works/pi-coding-agent": "1.3.0",
|
|
91
|
+
"react-native": "0.86.3",
|
|
92
|
+
"react-native-unistyles": "^3.5.3"
|
|
84
93
|
},
|
|
85
94
|
"peerDependenciesMeta": {
|
|
86
95
|
"@earendil-works/pi-coding-agent": {
|
|
87
96
|
"optional": true
|
|
97
|
+
},
|
|
98
|
+
"@agimon-ai/po-native-components": {
|
|
99
|
+
"optional": true
|
|
100
|
+
},
|
|
101
|
+
"react-native": {
|
|
102
|
+
"optional": true
|
|
103
|
+
},
|
|
104
|
+
"react-native-unistyles": {
|
|
105
|
+
"optional": true
|
|
88
106
|
}
|
|
89
107
|
},
|
|
90
108
|
"engines": {
|
|
@@ -104,6 +122,14 @@
|
|
|
104
122
|
]
|
|
105
123
|
}
|
|
106
124
|
},
|
|
125
|
+
"poNative": {
|
|
126
|
+
"pluginId": "read",
|
|
127
|
+
"channels": [],
|
|
128
|
+
"client": "./dist/extensions/native.mjs",
|
|
129
|
+
"scopes": [
|
|
130
|
+
"session"
|
|
131
|
+
]
|
|
132
|
+
},
|
|
107
133
|
"poServer": {
|
|
108
134
|
"entry": "./generated/server.ts",
|
|
109
135
|
"dist": "./dist/extensions/server.mjs",
|
|
@@ -127,7 +153,7 @@
|
|
|
127
153
|
"build": "tsdown && tsdown --config tsdown.mcp.config.ts",
|
|
128
154
|
"build:mcp": "tsdown --config tsdown.mcp.config.ts",
|
|
129
155
|
"test": "vitest --run",
|
|
130
|
-
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.web.json && tsc --noEmit -p tsconfig.mcp.json",
|
|
156
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.web.json && tsc --noEmit -p tsconfig.native.json && tsc --noEmit -p tsconfig.mcp.json",
|
|
131
157
|
"lint": "oxlint . && oxfmt . --check",
|
|
132
158
|
"fixcode": "oxlint . --fix && oxfmt ."
|
|
133
159
|
}
|