@agimon-ai/doompi-read 0.0.1-alpha.54 → 0.0.1-alpha.56

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.
@@ -157,10 +157,10 @@ var read_mcp_default = (0, _agimon_ai_doompi_core_mcpFacet.defineMcpTool)(create
157
157
  //#endregion
158
158
  //#region generated/mcp.ts
159
159
  const at = (value, context) => typeof value === "function" ? value(context) : value;
160
- const via = (identity, value) => ({
160
+ const via = (identity, value) => value === void 0 ? void 0 : {
161
161
  ...identity,
162
162
  ...value
163
- });
163
+ };
164
164
  const mcp = (0, _agimon_ai_doompi_core_mcpFacet.defineMcpPlugin)({
165
165
  name: "@agimon-ai/doompi-read",
166
166
  session: (context) => ({ get tools() {
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.cjs","names":["Type","loadPiImageSettings","resizeImage","formatDimensionNote","resolveReadInputPath","readFile","displayPath","isWritableFile","decodeUtf8","splitLines","formatFileHeader","computeFileTag","formatTaggedLine","DEFAULT_MAX_BYTES","truncateLine","truncateHead","formatSize","defineMcpTool","defineMcpPlugin","toolRead"],"sources":["../../src/schemas/readTool.ts","../../src/services/readImage/index.ts","../../src/services/readTool/index.ts","../../src/extensions/workspaces/sessions/(backend)/tool/read.mcp.ts","../../generated/mcp.ts"],"sourcesContent":["import { type Static, Type } from 'typebox';\n\nexport const ReadParamsSchema = Type.Object({\n path: Type.String({ description: 'Path to the file to read.' }),\n offset: Type.Optional(Type.Integer({ minimum: 1, description: 'One-based line offset.' })),\n limit: Type.Optional(Type.Integer({ minimum: 1, description: 'Maximum number of lines to return.' })),\n});\n\nexport type ReadParams = Static<typeof ReadParamsSchema>;\n","import { loadPiImageSettings, type PiImageSettings } from '@agimon-ai/doompi-config/piConfig';\n\nconst OMITTED_NOTE = '[Image omitted: could not be resized below the inline image size limit.]';\n\nexport interface ReadTextPart {\n type: 'text';\n text: string;\n}\n\nexport interface ReadImagePart {\n type: 'image';\n data: string;\n mimeType: string;\n}\n\nexport type ReadContentPart = ReadTextPart | ReadImagePart;\n\nexport interface ReadImageResizeResult {\n readonly data: string;\n readonly mimeType: string;\n readonly originalWidth: number;\n readonly originalHeight: number;\n readonly width: number;\n readonly height: number;\n readonly wasResized: boolean;\n}\n\nexport interface ReadImageResizeOperations {\n resize(\n inputBytes: Uint8Array,\n mimeType: string,\n options: { readonly maxWidth: number; readonly maxHeight: number },\n ): Promise<ReadImageResizeResult | null>;\n formatDimensionNote(result: ReadImageResizeResult): string | undefined;\n}\n\nexport function imageLimits(): PiImageSettings {\n return loadPiImageSettings();\n}\n\nexport async function applyImageLimits(\n content: ReadContentPart[],\n limits: PiImageSettings,\n operations: ReadImageResizeOperations,\n): Promise<ReadContentPart[]> {\n if (!limits.autoResize || !content.some((part) => part.type === 'image')) return content;\n const resolved: ReadContentPart[] = [];\n for (const part of content) {\n if (part.type !== 'image') {\n resolved.push(part);\n continue;\n }\n const resized = await operations.resize(Buffer.from(part.data, 'base64'), part.mimeType, {\n maxWidth: limits.maxDimension,\n maxHeight: limits.maxDimension,\n });\n if (!resized) {\n resolved.push({ type: 'text', text: OMITTED_NOTE });\n continue;\n }\n resolved.push({ type: 'image', data: resized.data, mimeType: resized.mimeType });\n const note = operations.formatDimensionNote(resized);\n if (note) resolved.push({ type: 'text', text: note });\n }\n return resolved;\n}\n","import { readFile } from 'node:fs/promises';\n\nimport type {\n DoomHeadlessExecutionContext,\n DoomHeadlessTool,\n DoomHeadlessToolResult,\n} from '@agimon-ai/doompi-core/headless';\nimport { formatFileHeader, formatTaggedLine, splitLines } from '@agimon-ai/doompi-hashline';\nimport {\n computeFileTag,\n decodeUtf8,\n displayPath,\n isWritableFile,\n resolveReadInputPath,\n} from '@agimon-ai/doompi-hashline/files';\nimport {\n DEFAULT_MAX_BYTES,\n formatDimensionNote,\n formatSize,\n resizeImage,\n truncateHead,\n truncateLine,\n type ReadToolDetails,\n} from '@earendil-works/pi-coding-agent';\n\nimport { ReadParamsSchema, type ReadParams } from '../../schemas/readTool';\nimport {\n applyImageLimits,\n imageLimits,\n type ReadContentPart,\n type ReadImageResizeOperations,\n type ReadTextPart,\n} from '../readImage';\n\nconst resizeOperations: ReadImageResizeOperations = {\n resize: resizeImage,\n formatDimensionNote: (result) => formatDimensionNote(result),\n};\n\nexport interface ReadToolResult {\n content: ReadContentPart[];\n details?: ReadToolDetails;\n}\n\ninterface ReadTextToolResult {\n content: ReadTextPart[];\n details?: ReadToolDetails;\n}\n\nexport function assertNotAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) throw new Error('Operation aborted');\n}\n\nexport function isImagePath(filePath: string): string | undefined {\n const extension = filePath.toLowerCase().match(/\\.([a-z0-9]+)$/u)?.[1];\n if (!extension) return undefined;\n const mimeTypes: Record<string, string> = {\n avif: 'image/avif',\n gif: 'image/gif',\n jpeg: 'image/jpeg',\n jpg: 'image/jpeg',\n png: 'image/png',\n webp: 'image/webp',\n };\n return mimeTypes[extension];\n}\n\nexport async function executeHeadlessRead(\n params: ReadParams,\n cwd: string,\n signal: AbortSignal | undefined,\n): Promise<ReadToolResult> {\n assertNotAborted(signal);\n const absolutePath = await resolveReadInputPath(params.path, cwd);\n const bytes = await readFile(absolutePath);\n assertNotAborted(signal);\n const mimeType = isImagePath(absolutePath);\n if (mimeType) {\n const content: ReadContentPart[] = [\n { type: 'text', text: `Read image file ${displayPath(absolutePath, cwd)} [${mimeType}]` },\n { type: 'image', data: bytes.toString('base64'), mimeType },\n ];\n return { content: await applyImageLimits(content, imageLimits(), resizeOperations) };\n }\n if (!(await isWritableFile(absolutePath))) {\n return { content: [{ type: 'text', text: decodeUtf8(bytes, displayPath(absolutePath, cwd)) }] };\n }\n return createTaggedReadResult(bytes, displayPath(absolutePath, cwd), params);\n}\n\nexport function createTaggedReadResult(bytes: Buffer, path: string, params: ReadParams): ReadTextToolResult {\n const lines = splitLines(decodeUtf8(bytes, path));\n const startIndex = params.offset === undefined ? 0 : params.offset - 1;\n if (startIndex >= lines.length) {\n throw new Error(`Offset ${params.offset} is beyond end of file (${lines.length} lines total).`);\n }\n\n const endIndex = params.limit === undefined ? lines.length : Math.min(lines.length, startIndex + params.limit);\n const selected = lines.slice(startIndex, endIndex);\n const header = formatFileHeader(path, computeFileTag(bytes));\n const compactedLines: number[] = [];\n const headerBytes = Buffer.byteLength(header, 'utf8') + 1;\n const tagged = selected.map((line, index) => {\n const lineNumber = startIndex + index + 1;\n const full = formatTaggedLine(line, lineNumber);\n if (Buffer.byteLength(full, 'utf8') <= DEFAULT_MAX_BYTES - headerBytes) return full;\n compactedLines.push(lineNumber);\n return formatTaggedLine(truncateLine(line).text, lineNumber, '', line);\n });\n const truncation = truncateHead([header, ...tagged].join('\\n'));\n let text = truncation.content;\n let details: ReadToolDetails | undefined;\n\n if (truncation.truncated) {\n const shownLines = Math.max(0, truncation.outputLines - 1);\n const nextOffset = startIndex + shownLines + 1;\n const reason = truncation.truncatedBy === 'bytes' ? `, ${formatSize(DEFAULT_MAX_BYTES)} limit` : '';\n text += `\\n\\n[Showing ${shownLines} anchored lines${reason}. Use offset=${nextOffset} to continue.]`;\n details = { truncation };\n } else {\n const notices: string[] = [];\n if (compactedLines.length > 0) {\n notices.push(`Lines ${compactedLines.join(', ')} shown compactly. Their anchors hash the full original lines`);\n }\n if (endIndex < lines.length) {\n notices.push(`${lines.length - endIndex} more lines in file. Use offset=${endIndex + 1} to continue`);\n }\n if (notices.length > 0) text += `\\n\\n[${notices.join('. ')}.]`;\n }\n\n return { content: [{ type: 'text', text }], details };\n}\n\nexport function isImageRead(content: readonly { readonly type: string; readonly text?: string }[]): boolean {\n return content.some((part) => part.type === 'image' || part.text?.startsWith('Read image file') === true);\n}\n\nexport function createHeadlessReadTool(): DoomHeadlessTool<typeof ReadParamsSchema> {\n return {\n name: 'read',\n label: 'read',\n description:\n 'Read a writable text file with an exact-byte file tag and stable line anchors. Non-writable files and images return native-compatible content. Text is truncated to 50.0KB.',\n promptSnippet: 'Read file contents with snapshot-bound line anchors',\n promptGuidelines: [\n 'Use read before edit. When hashline metadata is present, preserve the @file hash and anchors such as 5#abc exactly.',\n 'Continue large reads with offset until the required anchored lines are visible.',\n ],\n parameters: ReadParamsSchema,\n executionMode: 'parallel',\n execute: async (\n _toolCallId: string,\n params: ReadParams,\n signal: AbortSignal | undefined,\n _onUpdate: ((result: DoomHeadlessToolResult) => void) | undefined,\n context: DoomHeadlessExecutionContext,\n ) => executeHeadlessRead(params, context.cwd, signal),\n };\n}\n","import { defineMcpTool } from '@agimon-ai/doompi-core/mcpFacet';\n\nimport { createHeadlessReadTool } from '../../../../../services/readTool';\n\nexport default defineMcpTool(createHeadlessReadTool);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { defineMcpPlugin, type DoomMcpSessionPlugin } from '@agimon-ai/doompi-core/mcpFacet';\n\nimport toolRead from '../src/extensions/workspaces/sessions/(backend)/tool/read.mcp';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T => ({ ...identity, ...(value as object) }) as T;\n\nexport const mcp = defineMcpPlugin({\n name: '@agimon-ai/doompi-read',\n session: (context) => ({\n get tools(): DoomMcpSessionPlugin['tools'] { return [via({ name: 'read' }, at(toolRead, context))]; },\n }) satisfies DoomMcpSessionPlugin,\n});\n\nexport default mcp;\n"],"mappings":"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"}
1
+ {"version":3,"file":"mcp.cjs","names":["Type","loadPiImageSettings","resizeImage","formatDimensionNote","resolveReadInputPath","readFile","displayPath","isWritableFile","decodeUtf8","splitLines","formatFileHeader","computeFileTag","formatTaggedLine","DEFAULT_MAX_BYTES","truncateLine","truncateHead","formatSize","defineMcpTool","defineMcpPlugin","toolRead"],"sources":["../../src/schemas/readTool.ts","../../src/services/readImage/index.ts","../../src/services/readTool/index.ts","../../src/extensions/workspaces/sessions/(backend)/tool/read.mcp.ts","../../generated/mcp.ts"],"sourcesContent":["import { type Static, Type } from 'typebox';\n\nexport const ReadParamsSchema = Type.Object({\n path: Type.String({ description: 'Path to the file to read.' }),\n offset: Type.Optional(Type.Integer({ minimum: 1, description: 'One-based line offset.' })),\n limit: Type.Optional(Type.Integer({ minimum: 1, description: 'Maximum number of lines to return.' })),\n});\n\nexport type ReadParams = Static<typeof ReadParamsSchema>;\n","import { loadPiImageSettings, type PiImageSettings } from '@agimon-ai/doompi-config/piConfig';\n\nconst OMITTED_NOTE = '[Image omitted: could not be resized below the inline image size limit.]';\n\nexport interface ReadTextPart {\n type: 'text';\n text: string;\n}\n\nexport interface ReadImagePart {\n type: 'image';\n data: string;\n mimeType: string;\n}\n\nexport type ReadContentPart = ReadTextPart | ReadImagePart;\n\nexport interface ReadImageResizeResult {\n readonly data: string;\n readonly mimeType: string;\n readonly originalWidth: number;\n readonly originalHeight: number;\n readonly width: number;\n readonly height: number;\n readonly wasResized: boolean;\n}\n\nexport interface ReadImageResizeOperations {\n resize(\n inputBytes: Uint8Array,\n mimeType: string,\n options: { readonly maxWidth: number; readonly maxHeight: number },\n ): Promise<ReadImageResizeResult | null>;\n formatDimensionNote(result: ReadImageResizeResult): string | undefined;\n}\n\nexport function imageLimits(): PiImageSettings {\n return loadPiImageSettings();\n}\n\nexport async function applyImageLimits(\n content: ReadContentPart[],\n limits: PiImageSettings,\n operations: ReadImageResizeOperations,\n): Promise<ReadContentPart[]> {\n if (!limits.autoResize || !content.some((part) => part.type === 'image')) return content;\n const resolved: ReadContentPart[] = [];\n for (const part of content) {\n if (part.type !== 'image') {\n resolved.push(part);\n continue;\n }\n const resized = await operations.resize(Buffer.from(part.data, 'base64'), part.mimeType, {\n maxWidth: limits.maxDimension,\n maxHeight: limits.maxDimension,\n });\n if (!resized) {\n resolved.push({ type: 'text', text: OMITTED_NOTE });\n continue;\n }\n resolved.push({ type: 'image', data: resized.data, mimeType: resized.mimeType });\n const note = operations.formatDimensionNote(resized);\n if (note) resolved.push({ type: 'text', text: note });\n }\n return resolved;\n}\n","import { readFile } from 'node:fs/promises';\n\nimport type {\n DoomHeadlessExecutionContext,\n DoomHeadlessTool,\n DoomHeadlessToolResult,\n} from '@agimon-ai/doompi-core/headless';\nimport { formatFileHeader, formatTaggedLine, splitLines } from '@agimon-ai/doompi-hashline';\nimport {\n computeFileTag,\n decodeUtf8,\n displayPath,\n isWritableFile,\n resolveReadInputPath,\n} from '@agimon-ai/doompi-hashline/files';\nimport {\n DEFAULT_MAX_BYTES,\n formatDimensionNote,\n formatSize,\n resizeImage,\n truncateHead,\n truncateLine,\n type ReadToolDetails,\n} from '@earendil-works/pi-coding-agent';\n\nimport { ReadParamsSchema, type ReadParams } from '../../schemas/readTool';\nimport {\n applyImageLimits,\n imageLimits,\n type ReadContentPart,\n type ReadImageResizeOperations,\n type ReadTextPart,\n} from '../readImage';\n\nconst resizeOperations: ReadImageResizeOperations = {\n resize: resizeImage,\n formatDimensionNote: (result) => formatDimensionNote(result),\n};\n\nexport interface ReadToolResult {\n content: ReadContentPart[];\n details?: ReadToolDetails;\n}\n\ninterface ReadTextToolResult {\n content: ReadTextPart[];\n details?: ReadToolDetails;\n}\n\nexport function assertNotAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) throw new Error('Operation aborted');\n}\n\nexport function isImagePath(filePath: string): string | undefined {\n const extension = filePath.toLowerCase().match(/\\.([a-z0-9]+)$/u)?.[1];\n if (!extension) return undefined;\n const mimeTypes: Record<string, string> = {\n avif: 'image/avif',\n gif: 'image/gif',\n jpeg: 'image/jpeg',\n jpg: 'image/jpeg',\n png: 'image/png',\n webp: 'image/webp',\n };\n return mimeTypes[extension];\n}\n\nexport async function executeHeadlessRead(\n params: ReadParams,\n cwd: string,\n signal: AbortSignal | undefined,\n): Promise<ReadToolResult> {\n assertNotAborted(signal);\n const absolutePath = await resolveReadInputPath(params.path, cwd);\n const bytes = await readFile(absolutePath);\n assertNotAborted(signal);\n const mimeType = isImagePath(absolutePath);\n if (mimeType) {\n const content: ReadContentPart[] = [\n { type: 'text', text: `Read image file ${displayPath(absolutePath, cwd)} [${mimeType}]` },\n { type: 'image', data: bytes.toString('base64'), mimeType },\n ];\n return { content: await applyImageLimits(content, imageLimits(), resizeOperations) };\n }\n if (!(await isWritableFile(absolutePath))) {\n return { content: [{ type: 'text', text: decodeUtf8(bytes, displayPath(absolutePath, cwd)) }] };\n }\n return createTaggedReadResult(bytes, displayPath(absolutePath, cwd), params);\n}\n\nexport function createTaggedReadResult(bytes: Buffer, path: string, params: ReadParams): ReadTextToolResult {\n const lines = splitLines(decodeUtf8(bytes, path));\n const startIndex = params.offset === undefined ? 0 : params.offset - 1;\n if (startIndex >= lines.length) {\n throw new Error(`Offset ${params.offset} is beyond end of file (${lines.length} lines total).`);\n }\n\n const endIndex = params.limit === undefined ? lines.length : Math.min(lines.length, startIndex + params.limit);\n const selected = lines.slice(startIndex, endIndex);\n const header = formatFileHeader(path, computeFileTag(bytes));\n const compactedLines: number[] = [];\n const headerBytes = Buffer.byteLength(header, 'utf8') + 1;\n const tagged = selected.map((line, index) => {\n const lineNumber = startIndex + index + 1;\n const full = formatTaggedLine(line, lineNumber);\n if (Buffer.byteLength(full, 'utf8') <= DEFAULT_MAX_BYTES - headerBytes) return full;\n compactedLines.push(lineNumber);\n return formatTaggedLine(truncateLine(line).text, lineNumber, '', line);\n });\n const truncation = truncateHead([header, ...tagged].join('\\n'));\n let text = truncation.content;\n let details: ReadToolDetails | undefined;\n\n if (truncation.truncated) {\n const shownLines = Math.max(0, truncation.outputLines - 1);\n const nextOffset = startIndex + shownLines + 1;\n const reason = truncation.truncatedBy === 'bytes' ? `, ${formatSize(DEFAULT_MAX_BYTES)} limit` : '';\n text += `\\n\\n[Showing ${shownLines} anchored lines${reason}. Use offset=${nextOffset} to continue.]`;\n details = { truncation };\n } else {\n const notices: string[] = [];\n if (compactedLines.length > 0) {\n notices.push(`Lines ${compactedLines.join(', ')} shown compactly. Their anchors hash the full original lines`);\n }\n if (endIndex < lines.length) {\n notices.push(`${lines.length - endIndex} more lines in file. Use offset=${endIndex + 1} to continue`);\n }\n if (notices.length > 0) text += `\\n\\n[${notices.join('. ')}.]`;\n }\n\n return { content: [{ type: 'text', text }], details };\n}\n\nexport function isImageRead(content: readonly { readonly type: string; readonly text?: string }[]): boolean {\n return content.some((part) => part.type === 'image' || part.text?.startsWith('Read image file') === true);\n}\n\nexport function createHeadlessReadTool(): DoomHeadlessTool<typeof ReadParamsSchema> {\n return {\n name: 'read',\n label: 'read',\n description:\n 'Read a writable text file with an exact-byte file tag and stable line anchors. Non-writable files and images return native-compatible content. Text is truncated to 50.0KB.',\n promptSnippet: 'Read file contents with snapshot-bound line anchors',\n promptGuidelines: [\n 'Use read before edit. When hashline metadata is present, preserve the @file hash and anchors such as 5#abc exactly.',\n 'Continue large reads with offset until the required anchored lines are visible.',\n ],\n parameters: ReadParamsSchema,\n executionMode: 'parallel',\n execute: async (\n _toolCallId: string,\n params: ReadParams,\n signal: AbortSignal | undefined,\n _onUpdate: ((result: DoomHeadlessToolResult) => void) | undefined,\n context: DoomHeadlessExecutionContext,\n ) => executeHeadlessRead(params, context.cwd, signal),\n };\n}\n","import { defineMcpTool } from '@agimon-ai/doompi-core/mcpFacet';\n\nimport { createHeadlessReadTool } from '../../../../../services/readTool';\n\nexport default defineMcpTool(createHeadlessReadTool);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { defineMcpPlugin, type DoomMcpSessionPlugin } from '@agimon-ai/doompi-core/mcpFacet';\n\nimport toolRead from '../src/extensions/workspaces/sessions/(backend)/tool/read.mcp';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const mcp = defineMcpPlugin({\n name: '@agimon-ai/doompi-read',\n session: (context) => ({\n get tools(): DoomMcpSessionPlugin['tools'] { return [via({ name: 'read' }, at(toolRead, context))]; },\n }) satisfies DoomMcpSessionPlugin,\n});\n\nexport default mcp;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.d.mts","names":[],"sources":["../../generated/mcp.ts"],"mappings":";qBAUa,+CAAG"}
1
+ {"version":3,"file":"mcp.d.mts","names":[],"sources":["../../generated/mcp.ts"],"mappings":";qBAWa,+CAAG"}
@@ -153,10 +153,10 @@ var read_mcp_default = defineMcpTool(createHeadlessReadTool);
153
153
  //#endregion
154
154
  //#region generated/mcp.ts
155
155
  const at = (value, context) => typeof value === "function" ? value(context) : value;
156
- const via = (identity, value) => ({
156
+ const via = (identity, value) => value === void 0 ? void 0 : {
157
157
  ...identity,
158
158
  ...value
159
- });
159
+ };
160
160
  const mcp = defineMcpPlugin({
161
161
  name: "@agimon-ai/doompi-read",
162
162
  session: (context) => ({ get tools() {
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.mjs","names":["toolRead"],"sources":["../../src/schemas/readTool.ts","../../src/services/readImage/index.ts","../../src/services/readTool/index.ts","../../src/extensions/workspaces/sessions/(backend)/tool/read.mcp.ts","../../generated/mcp.ts"],"sourcesContent":["import { type Static, Type } from 'typebox';\n\nexport const ReadParamsSchema = Type.Object({\n path: Type.String({ description: 'Path to the file to read.' }),\n offset: Type.Optional(Type.Integer({ minimum: 1, description: 'One-based line offset.' })),\n limit: Type.Optional(Type.Integer({ minimum: 1, description: 'Maximum number of lines to return.' })),\n});\n\nexport type ReadParams = Static<typeof ReadParamsSchema>;\n","import { loadPiImageSettings, type PiImageSettings } from '@agimon-ai/doompi-config/piConfig';\n\nconst OMITTED_NOTE = '[Image omitted: could not be resized below the inline image size limit.]';\n\nexport interface ReadTextPart {\n type: 'text';\n text: string;\n}\n\nexport interface ReadImagePart {\n type: 'image';\n data: string;\n mimeType: string;\n}\n\nexport type ReadContentPart = ReadTextPart | ReadImagePart;\n\nexport interface ReadImageResizeResult {\n readonly data: string;\n readonly mimeType: string;\n readonly originalWidth: number;\n readonly originalHeight: number;\n readonly width: number;\n readonly height: number;\n readonly wasResized: boolean;\n}\n\nexport interface ReadImageResizeOperations {\n resize(\n inputBytes: Uint8Array,\n mimeType: string,\n options: { readonly maxWidth: number; readonly maxHeight: number },\n ): Promise<ReadImageResizeResult | null>;\n formatDimensionNote(result: ReadImageResizeResult): string | undefined;\n}\n\nexport function imageLimits(): PiImageSettings {\n return loadPiImageSettings();\n}\n\nexport async function applyImageLimits(\n content: ReadContentPart[],\n limits: PiImageSettings,\n operations: ReadImageResizeOperations,\n): Promise<ReadContentPart[]> {\n if (!limits.autoResize || !content.some((part) => part.type === 'image')) return content;\n const resolved: ReadContentPart[] = [];\n for (const part of content) {\n if (part.type !== 'image') {\n resolved.push(part);\n continue;\n }\n const resized = await operations.resize(Buffer.from(part.data, 'base64'), part.mimeType, {\n maxWidth: limits.maxDimension,\n maxHeight: limits.maxDimension,\n });\n if (!resized) {\n resolved.push({ type: 'text', text: OMITTED_NOTE });\n continue;\n }\n resolved.push({ type: 'image', data: resized.data, mimeType: resized.mimeType });\n const note = operations.formatDimensionNote(resized);\n if (note) resolved.push({ type: 'text', text: note });\n }\n return resolved;\n}\n","import { readFile } from 'node:fs/promises';\n\nimport type {\n DoomHeadlessExecutionContext,\n DoomHeadlessTool,\n DoomHeadlessToolResult,\n} from '@agimon-ai/doompi-core/headless';\nimport { formatFileHeader, formatTaggedLine, splitLines } from '@agimon-ai/doompi-hashline';\nimport {\n computeFileTag,\n decodeUtf8,\n displayPath,\n isWritableFile,\n resolveReadInputPath,\n} from '@agimon-ai/doompi-hashline/files';\nimport {\n DEFAULT_MAX_BYTES,\n formatDimensionNote,\n formatSize,\n resizeImage,\n truncateHead,\n truncateLine,\n type ReadToolDetails,\n} from '@earendil-works/pi-coding-agent';\n\nimport { ReadParamsSchema, type ReadParams } from '../../schemas/readTool';\nimport {\n applyImageLimits,\n imageLimits,\n type ReadContentPart,\n type ReadImageResizeOperations,\n type ReadTextPart,\n} from '../readImage';\n\nconst resizeOperations: ReadImageResizeOperations = {\n resize: resizeImage,\n formatDimensionNote: (result) => formatDimensionNote(result),\n};\n\nexport interface ReadToolResult {\n content: ReadContentPart[];\n details?: ReadToolDetails;\n}\n\ninterface ReadTextToolResult {\n content: ReadTextPart[];\n details?: ReadToolDetails;\n}\n\nexport function assertNotAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) throw new Error('Operation aborted');\n}\n\nexport function isImagePath(filePath: string): string | undefined {\n const extension = filePath.toLowerCase().match(/\\.([a-z0-9]+)$/u)?.[1];\n if (!extension) return undefined;\n const mimeTypes: Record<string, string> = {\n avif: 'image/avif',\n gif: 'image/gif',\n jpeg: 'image/jpeg',\n jpg: 'image/jpeg',\n png: 'image/png',\n webp: 'image/webp',\n };\n return mimeTypes[extension];\n}\n\nexport async function executeHeadlessRead(\n params: ReadParams,\n cwd: string,\n signal: AbortSignal | undefined,\n): Promise<ReadToolResult> {\n assertNotAborted(signal);\n const absolutePath = await resolveReadInputPath(params.path, cwd);\n const bytes = await readFile(absolutePath);\n assertNotAborted(signal);\n const mimeType = isImagePath(absolutePath);\n if (mimeType) {\n const content: ReadContentPart[] = [\n { type: 'text', text: `Read image file ${displayPath(absolutePath, cwd)} [${mimeType}]` },\n { type: 'image', data: bytes.toString('base64'), mimeType },\n ];\n return { content: await applyImageLimits(content, imageLimits(), resizeOperations) };\n }\n if (!(await isWritableFile(absolutePath))) {\n return { content: [{ type: 'text', text: decodeUtf8(bytes, displayPath(absolutePath, cwd)) }] };\n }\n return createTaggedReadResult(bytes, displayPath(absolutePath, cwd), params);\n}\n\nexport function createTaggedReadResult(bytes: Buffer, path: string, params: ReadParams): ReadTextToolResult {\n const lines = splitLines(decodeUtf8(bytes, path));\n const startIndex = params.offset === undefined ? 0 : params.offset - 1;\n if (startIndex >= lines.length) {\n throw new Error(`Offset ${params.offset} is beyond end of file (${lines.length} lines total).`);\n }\n\n const endIndex = params.limit === undefined ? lines.length : Math.min(lines.length, startIndex + params.limit);\n const selected = lines.slice(startIndex, endIndex);\n const header = formatFileHeader(path, computeFileTag(bytes));\n const compactedLines: number[] = [];\n const headerBytes = Buffer.byteLength(header, 'utf8') + 1;\n const tagged = selected.map((line, index) => {\n const lineNumber = startIndex + index + 1;\n const full = formatTaggedLine(line, lineNumber);\n if (Buffer.byteLength(full, 'utf8') <= DEFAULT_MAX_BYTES - headerBytes) return full;\n compactedLines.push(lineNumber);\n return formatTaggedLine(truncateLine(line).text, lineNumber, '', line);\n });\n const truncation = truncateHead([header, ...tagged].join('\\n'));\n let text = truncation.content;\n let details: ReadToolDetails | undefined;\n\n if (truncation.truncated) {\n const shownLines = Math.max(0, truncation.outputLines - 1);\n const nextOffset = startIndex + shownLines + 1;\n const reason = truncation.truncatedBy === 'bytes' ? `, ${formatSize(DEFAULT_MAX_BYTES)} limit` : '';\n text += `\\n\\n[Showing ${shownLines} anchored lines${reason}. Use offset=${nextOffset} to continue.]`;\n details = { truncation };\n } else {\n const notices: string[] = [];\n if (compactedLines.length > 0) {\n notices.push(`Lines ${compactedLines.join(', ')} shown compactly. Their anchors hash the full original lines`);\n }\n if (endIndex < lines.length) {\n notices.push(`${lines.length - endIndex} more lines in file. Use offset=${endIndex + 1} to continue`);\n }\n if (notices.length > 0) text += `\\n\\n[${notices.join('. ')}.]`;\n }\n\n return { content: [{ type: 'text', text }], details };\n}\n\nexport function isImageRead(content: readonly { readonly type: string; readonly text?: string }[]): boolean {\n return content.some((part) => part.type === 'image' || part.text?.startsWith('Read image file') === true);\n}\n\nexport function createHeadlessReadTool(): DoomHeadlessTool<typeof ReadParamsSchema> {\n return {\n name: 'read',\n label: 'read',\n description:\n 'Read a writable text file with an exact-byte file tag and stable line anchors. Non-writable files and images return native-compatible content. Text is truncated to 50.0KB.',\n promptSnippet: 'Read file contents with snapshot-bound line anchors',\n promptGuidelines: [\n 'Use read before edit. When hashline metadata is present, preserve the @file hash and anchors such as 5#abc exactly.',\n 'Continue large reads with offset until the required anchored lines are visible.',\n ],\n parameters: ReadParamsSchema,\n executionMode: 'parallel',\n execute: async (\n _toolCallId: string,\n params: ReadParams,\n signal: AbortSignal | undefined,\n _onUpdate: ((result: DoomHeadlessToolResult) => void) | undefined,\n context: DoomHeadlessExecutionContext,\n ) => executeHeadlessRead(params, context.cwd, signal),\n };\n}\n","import { defineMcpTool } from '@agimon-ai/doompi-core/mcpFacet';\n\nimport { createHeadlessReadTool } from '../../../../../services/readTool';\n\nexport default defineMcpTool(createHeadlessReadTool);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { defineMcpPlugin, type DoomMcpSessionPlugin } from '@agimon-ai/doompi-core/mcpFacet';\n\nimport toolRead from '../src/extensions/workspaces/sessions/(backend)/tool/read.mcp';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T => ({ ...identity, ...(value as object) }) as T;\n\nexport const mcp = defineMcpPlugin({\n name: '@agimon-ai/doompi-read',\n session: (context) => ({\n get tools(): DoomMcpSessionPlugin['tools'] { return [via({ name: 'read' }, at(toolRead, context))]; },\n }) satisfies DoomMcpSessionPlugin,\n});\n\nexport default mcp;\n"],"mappings":"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"}
1
+ {"version":3,"file":"mcp.mjs","names":["toolRead"],"sources":["../../src/schemas/readTool.ts","../../src/services/readImage/index.ts","../../src/services/readTool/index.ts","../../src/extensions/workspaces/sessions/(backend)/tool/read.mcp.ts","../../generated/mcp.ts"],"sourcesContent":["import { type Static, Type } from 'typebox';\n\nexport const ReadParamsSchema = Type.Object({\n path: Type.String({ description: 'Path to the file to read.' }),\n offset: Type.Optional(Type.Integer({ minimum: 1, description: 'One-based line offset.' })),\n limit: Type.Optional(Type.Integer({ minimum: 1, description: 'Maximum number of lines to return.' })),\n});\n\nexport type ReadParams = Static<typeof ReadParamsSchema>;\n","import { loadPiImageSettings, type PiImageSettings } from '@agimon-ai/doompi-config/piConfig';\n\nconst OMITTED_NOTE = '[Image omitted: could not be resized below the inline image size limit.]';\n\nexport interface ReadTextPart {\n type: 'text';\n text: string;\n}\n\nexport interface ReadImagePart {\n type: 'image';\n data: string;\n mimeType: string;\n}\n\nexport type ReadContentPart = ReadTextPart | ReadImagePart;\n\nexport interface ReadImageResizeResult {\n readonly data: string;\n readonly mimeType: string;\n readonly originalWidth: number;\n readonly originalHeight: number;\n readonly width: number;\n readonly height: number;\n readonly wasResized: boolean;\n}\n\nexport interface ReadImageResizeOperations {\n resize(\n inputBytes: Uint8Array,\n mimeType: string,\n options: { readonly maxWidth: number; readonly maxHeight: number },\n ): Promise<ReadImageResizeResult | null>;\n formatDimensionNote(result: ReadImageResizeResult): string | undefined;\n}\n\nexport function imageLimits(): PiImageSettings {\n return loadPiImageSettings();\n}\n\nexport async function applyImageLimits(\n content: ReadContentPart[],\n limits: PiImageSettings,\n operations: ReadImageResizeOperations,\n): Promise<ReadContentPart[]> {\n if (!limits.autoResize || !content.some((part) => part.type === 'image')) return content;\n const resolved: ReadContentPart[] = [];\n for (const part of content) {\n if (part.type !== 'image') {\n resolved.push(part);\n continue;\n }\n const resized = await operations.resize(Buffer.from(part.data, 'base64'), part.mimeType, {\n maxWidth: limits.maxDimension,\n maxHeight: limits.maxDimension,\n });\n if (!resized) {\n resolved.push({ type: 'text', text: OMITTED_NOTE });\n continue;\n }\n resolved.push({ type: 'image', data: resized.data, mimeType: resized.mimeType });\n const note = operations.formatDimensionNote(resized);\n if (note) resolved.push({ type: 'text', text: note });\n }\n return resolved;\n}\n","import { readFile } from 'node:fs/promises';\n\nimport type {\n DoomHeadlessExecutionContext,\n DoomHeadlessTool,\n DoomHeadlessToolResult,\n} from '@agimon-ai/doompi-core/headless';\nimport { formatFileHeader, formatTaggedLine, splitLines } from '@agimon-ai/doompi-hashline';\nimport {\n computeFileTag,\n decodeUtf8,\n displayPath,\n isWritableFile,\n resolveReadInputPath,\n} from '@agimon-ai/doompi-hashline/files';\nimport {\n DEFAULT_MAX_BYTES,\n formatDimensionNote,\n formatSize,\n resizeImage,\n truncateHead,\n truncateLine,\n type ReadToolDetails,\n} from '@earendil-works/pi-coding-agent';\n\nimport { ReadParamsSchema, type ReadParams } from '../../schemas/readTool';\nimport {\n applyImageLimits,\n imageLimits,\n type ReadContentPart,\n type ReadImageResizeOperations,\n type ReadTextPart,\n} from '../readImage';\n\nconst resizeOperations: ReadImageResizeOperations = {\n resize: resizeImage,\n formatDimensionNote: (result) => formatDimensionNote(result),\n};\n\nexport interface ReadToolResult {\n content: ReadContentPart[];\n details?: ReadToolDetails;\n}\n\ninterface ReadTextToolResult {\n content: ReadTextPart[];\n details?: ReadToolDetails;\n}\n\nexport function assertNotAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) throw new Error('Operation aborted');\n}\n\nexport function isImagePath(filePath: string): string | undefined {\n const extension = filePath.toLowerCase().match(/\\.([a-z0-9]+)$/u)?.[1];\n if (!extension) return undefined;\n const mimeTypes: Record<string, string> = {\n avif: 'image/avif',\n gif: 'image/gif',\n jpeg: 'image/jpeg',\n jpg: 'image/jpeg',\n png: 'image/png',\n webp: 'image/webp',\n };\n return mimeTypes[extension];\n}\n\nexport async function executeHeadlessRead(\n params: ReadParams,\n cwd: string,\n signal: AbortSignal | undefined,\n): Promise<ReadToolResult> {\n assertNotAborted(signal);\n const absolutePath = await resolveReadInputPath(params.path, cwd);\n const bytes = await readFile(absolutePath);\n assertNotAborted(signal);\n const mimeType = isImagePath(absolutePath);\n if (mimeType) {\n const content: ReadContentPart[] = [\n { type: 'text', text: `Read image file ${displayPath(absolutePath, cwd)} [${mimeType}]` },\n { type: 'image', data: bytes.toString('base64'), mimeType },\n ];\n return { content: await applyImageLimits(content, imageLimits(), resizeOperations) };\n }\n if (!(await isWritableFile(absolutePath))) {\n return { content: [{ type: 'text', text: decodeUtf8(bytes, displayPath(absolutePath, cwd)) }] };\n }\n return createTaggedReadResult(bytes, displayPath(absolutePath, cwd), params);\n}\n\nexport function createTaggedReadResult(bytes: Buffer, path: string, params: ReadParams): ReadTextToolResult {\n const lines = splitLines(decodeUtf8(bytes, path));\n const startIndex = params.offset === undefined ? 0 : params.offset - 1;\n if (startIndex >= lines.length) {\n throw new Error(`Offset ${params.offset} is beyond end of file (${lines.length} lines total).`);\n }\n\n const endIndex = params.limit === undefined ? lines.length : Math.min(lines.length, startIndex + params.limit);\n const selected = lines.slice(startIndex, endIndex);\n const header = formatFileHeader(path, computeFileTag(bytes));\n const compactedLines: number[] = [];\n const headerBytes = Buffer.byteLength(header, 'utf8') + 1;\n const tagged = selected.map((line, index) => {\n const lineNumber = startIndex + index + 1;\n const full = formatTaggedLine(line, lineNumber);\n if (Buffer.byteLength(full, 'utf8') <= DEFAULT_MAX_BYTES - headerBytes) return full;\n compactedLines.push(lineNumber);\n return formatTaggedLine(truncateLine(line).text, lineNumber, '', line);\n });\n const truncation = truncateHead([header, ...tagged].join('\\n'));\n let text = truncation.content;\n let details: ReadToolDetails | undefined;\n\n if (truncation.truncated) {\n const shownLines = Math.max(0, truncation.outputLines - 1);\n const nextOffset = startIndex + shownLines + 1;\n const reason = truncation.truncatedBy === 'bytes' ? `, ${formatSize(DEFAULT_MAX_BYTES)} limit` : '';\n text += `\\n\\n[Showing ${shownLines} anchored lines${reason}. Use offset=${nextOffset} to continue.]`;\n details = { truncation };\n } else {\n const notices: string[] = [];\n if (compactedLines.length > 0) {\n notices.push(`Lines ${compactedLines.join(', ')} shown compactly. Their anchors hash the full original lines`);\n }\n if (endIndex < lines.length) {\n notices.push(`${lines.length - endIndex} more lines in file. Use offset=${endIndex + 1} to continue`);\n }\n if (notices.length > 0) text += `\\n\\n[${notices.join('. ')}.]`;\n }\n\n return { content: [{ type: 'text', text }], details };\n}\n\nexport function isImageRead(content: readonly { readonly type: string; readonly text?: string }[]): boolean {\n return content.some((part) => part.type === 'image' || part.text?.startsWith('Read image file') === true);\n}\n\nexport function createHeadlessReadTool(): DoomHeadlessTool<typeof ReadParamsSchema> {\n return {\n name: 'read',\n label: 'read',\n description:\n 'Read a writable text file with an exact-byte file tag and stable line anchors. Non-writable files and images return native-compatible content. Text is truncated to 50.0KB.',\n promptSnippet: 'Read file contents with snapshot-bound line anchors',\n promptGuidelines: [\n 'Use read before edit. When hashline metadata is present, preserve the @file hash and anchors such as 5#abc exactly.',\n 'Continue large reads with offset until the required anchored lines are visible.',\n ],\n parameters: ReadParamsSchema,\n executionMode: 'parallel',\n execute: async (\n _toolCallId: string,\n params: ReadParams,\n signal: AbortSignal | undefined,\n _onUpdate: ((result: DoomHeadlessToolResult) => void) | undefined,\n context: DoomHeadlessExecutionContext,\n ) => executeHeadlessRead(params, context.cwd, signal),\n };\n}\n","import { defineMcpTool } from '@agimon-ai/doompi-core/mcpFacet';\n\nimport { createHeadlessReadTool } from '../../../../../services/readTool';\n\nexport default defineMcpTool(createHeadlessReadTool);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { defineMcpPlugin, type DoomMcpSessionPlugin } from '@agimon-ai/doompi-core/mcpFacet';\n\nimport toolRead from '../src/extensions/workspaces/sessions/(backend)/tool/read.mcp';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const mcp = defineMcpPlugin({\n name: '@agimon-ai/doompi-read',\n session: (context) => ({\n get tools(): DoomMcpSessionPlugin['tools'] { return [via({ name: 'read' }, at(toolRead, context))]; },\n }) satisfies DoomMcpSessionPlugin,\n});\n\nexport default mcp;\n"],"mappings":"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"}
@@ -66,10 +66,10 @@ var read_cli_default = (0, _agimon_ai_doompi_core_piExtension.definePiToolRender
66
66
  //#endregion
67
67
  //#region generated/pi.ts
68
68
  const at = (value, context) => typeof value === "function" ? value(context) : value;
69
- const via = (identity, value) => ({
69
+ const via = (identity, value) => value === void 0 ? void 0 : {
70
70
  ...identity,
71
71
  ...value
72
- });
72
+ };
73
73
  const extension = (0, _agimon_ai_doompi_core_piExtension.definePiExtension)("@agimon-ai/doompi-read", (context) => ({ ...(0, _agimon_ai_doompi_core_piExtension.piToolContributions)("@agimon-ai/doompi-read", [via({ name: "read" }, (0, _agimon_ai_doompi_core_piExtension.withPiRenderers)(at(read_cli_default$1, context), at(read_cli_default, context)))]) }));
74
74
  //#endregion
75
75
  exports.default = extension;
@@ -1 +1 @@
1
- {"version":3,"file":"pi.cjs","names":["resizeImage","formatDimensionNote","isWritableFile","formatSize","DEFAULT_MAX_BYTES","ReadParamsSchema","resolveReadInputPath","createReadToolDefinition","isImageRead","applyImageLimits","imageLimits","readFile","createTaggedReadResult","displayPath","definePiTool","renderHashlineCall","renderHashlineResult","definePiToolRenderer","definePiExtension","piToolContributions","withPiRenderers","toolRead","renderRead"],"sources":["../../src/extensions/workspaces/sessions/(backend)/tool/_lib/readTool.ts","../../src/extensions/workspaces/sessions/(backend)/tool/read.cli.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/_lib/readRenderer.cli.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/read.cli.ts","../../generated/pi.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\n\nimport { isWritableFile, displayPath, resolveReadInputPath } from '@agimon-ai/doompi-hashline/files';\nimport {\n createReadToolDefinition,\n DEFAULT_MAX_BYTES,\n formatDimensionNote,\n formatSize,\n resizeImage,\n type AgentToolResult,\n type ToolDefinition,\n} from '@earendil-works/pi-coding-agent';\n\nimport { ReadParamsSchema, type ReadParams } from '../../../../../../schemas/readTool';\nimport { applyImageLimits, imageLimits, type ReadImageResizeOperations } from '../../../../../../services/readImage';\nimport { assertNotAborted, createTaggedReadResult, isImageRead } from '../../../../../../services/readTool';\n\ntype WritableCheck = (path: string) => Promise<boolean>;\n\nconst resizeOperations: ReadImageResizeOperations = {\n resize: resizeImage,\n formatDimensionNote: (result) => formatDimensionNote(result),\n};\n\nexport function createHashlineReadTool(\n writable: WritableCheck = isWritableFile,\n): ToolDefinition<typeof ReadParamsSchema> {\n return {\n name: 'read',\n label: 'read',\n description: `Read a writable text file with an exact-byte file tag and stable line anchors. Non-writable files and images retain Pi's native behavior. Text is truncated to ${formatSize(DEFAULT_MAX_BYTES)}.`,\n promptSnippet: 'Read file contents with snapshot-bound line anchors',\n promptGuidelines: [\n 'Use read before edit. When hashline metadata is present, preserve the @file hash and anchors such as 5#abc exactly.',\n 'Continue large reads with offset until the required anchored lines are visible.',\n ],\n parameters: ReadParamsSchema,\n executionMode: 'parallel',\n async execute(toolCallId, params, signal, onUpdate, ctx) {\n const input = params as ReadParams;\n assertNotAborted(signal);\n const absolutePath = await resolveReadInputPath(input.path, ctx.cwd);\n const nativeRead = createReadToolDefinition(ctx.cwd, { autoResizeImages: false });\n const nativeResult = await nativeRead.execute(\n toolCallId,\n { ...input, path: absolutePath },\n signal,\n onUpdate,\n ctx,\n );\n if (isImageRead(nativeResult.content)) {\n assertNotAborted(signal);\n return {\n ...nativeResult,\n content: await applyImageLimits(nativeResult.content, imageLimits(), resizeOperations),\n };\n }\n\n assertNotAborted(signal);\n const canEdit = await writable(absolutePath);\n assertNotAborted(signal);\n if (!canEdit) return nativeResult;\n const bytes = await readFile(absolutePath);\n assertNotAborted(signal);\n return createTaggedReadResult(\n bytes,\n displayPath(absolutePath, ctx.cwd),\n input,\n ) as unknown as AgentToolResult<unknown>;\n },\n };\n}\n","import { definePiTool } from '@agimon-ai/doompi-core/piExtension';\n\nimport { createHashlineReadTool } from './_lib/readTool';\n\nexport default definePiTool(createHashlineReadTool(), { overrides: true });\n","import type { PiToolRenderers } from '@agimon-ai/doompi-core/piExtension';\nimport { renderHashlineCall, renderHashlineResult } from '@agimon-ai/doompi-ui/hashlineRendering';\n\nimport { ReadParamsSchema, type ReadParams } from '../../../../../../schemas/readTool';\n\nexport const readRenderer: PiToolRenderers<typeof ReadParamsSchema> = {\n renderShell: 'self',\n renderCall(args, theme) {\n const input = args as ReadParams;\n const details = [\n input.offset === undefined ? undefined : `from ${input.offset}`,\n input.limit === undefined ? undefined : `${input.limit} lines`,\n ].filter((value): value is string => value !== undefined);\n return renderHashlineCall('read', input.path, details, theme);\n },\n renderResult(result, options, theme, context) {\n return renderHashlineResult(result, options, theme, context, 'read');\n },\n};\n","import { definePiToolRenderer } from '@agimon-ai/doompi-core/piExtension';\n\nimport { readRenderer } from './_lib/readRenderer.cli';\n\nexport default definePiToolRenderer(readRenderer);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { definePiExtension, piToolContributions, withPiRenderers, type PiPluginContext } from '@agimon-ai/doompi-core/piExtension';\n\nimport toolRead from '../src/extensions/workspaces/sessions/(backend)/tool/read.cli';\nimport renderRead from '../src/extensions/workspaces/sessions/(frontend)/tool/read.cli';\n\ntype OptionsOf<T> = T extends (context: PiPluginContext<infer Options>) => unknown ? Options : never;\ntype InferredOptions = Exclude<OptionsOf<typeof toolRead>, undefined>;\ntype Intersect<Union> =\n (Union extends unknown ? (value: Union) => void : never) extends (value: infer Value) => void ? Value : never;\ntype ExtensionOptions = [InferredOptions] extends [never] ? undefined : Intersect<InferredOptions>;\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T => ({ ...identity, ...(value as object) }) as T;\n\nexport const extension = definePiExtension<ExtensionOptions>('@agimon-ai/doompi-read', (context) => ({\n ...piToolContributions('@agimon-ai/doompi-read', [via({ name: 'read' }, withPiRenderers(at(toolRead, context), at(renderRead, context)))]),\n}));\n\nexport default extension;\n"],"mappings":";;;;;;;;;;;AAmBA,MAAM,mBAA8C;CAClD,QAAQA,gCAAAA;CACR,sBAAsB,YAAA,GAAWC,gCAAAA,oBAAAA,CAAoB,MAAM;AAC7D;AAEA,SAAgB,uBACd,WAA0BC,iCAAAA,gBACe;CACzC,OAAO;EACL,MAAM;EACN,OAAO;EACP,aAAa,mKAAA,GAAkKC,gCAAAA,WAAAA,CAAWC,gCAAAA,iBAAiB,EAAE;EAC7M,eAAe;EACf,kBAAkB,CAChB,uHACA,iFACF;EACA,YAAYC,iBAAAA;EACZ,eAAe;EACf,MAAM,QAAQ,YAAY,QAAQ,QAAQ,UAAU,KAAK;GACvD,MAAM,QAAQ;GACd,iBAAA,iBAAiB,MAAM;GACvB,MAAM,eAAe,OAAA,GAAMC,iCAAAA,qBAAAA,CAAqB,MAAM,MAAM,IAAI,GAAG;GAEnE,MAAM,eAAe,OAAA,GADFC,gCAAAA,yBAAAA,CAAyB,IAAI,KAAK,EAAE,kBAAkB,MAAM,CAC3C,CAAC,CAAC,QACpC,YACA;IAAE,GAAG;IAAO,MAAM;GAAa,GAC/B,QACA,UACA,GACF;GACA,IAAIC,iBAAAA,YAAY,aAAa,OAAO,GAAG;IACrC,iBAAA,iBAAiB,MAAM;IACvB,OAAO;KACL,GAAG;KACH,SAAS,MAAMC,iBAAAA,iBAAiB,aAAa,SAASC,iBAAAA,YAAY,GAAG,gBAAgB;IACvF;GACF;GAEA,iBAAA,iBAAiB,MAAM;GACvB,MAAM,UAAU,MAAM,SAAS,YAAY;GAC3C,iBAAA,iBAAiB,MAAM;GACvB,IAAI,CAAC,SAAS,OAAO;GACrB,MAAM,QAAQ,OAAA,GAAMC,iBAAAA,SAAAA,CAAS,YAAY;GACzC,iBAAA,iBAAiB,MAAM;GACvB,OAAOC,iBAAAA,uBACL,QAAA,GACAC,iCAAAA,YAAAA,CAAY,cAAc,IAAI,GAAG,GACjC,KACF;EACF;CACF;AACF;;;ACnEA,IAAA,sBAAA,GAAeC,mCAAAA,aAAAA,CAAa,uBAAuB,GAAG,EAAE,WAAW,KAAK,CAAC;;;AEAzE,IAAA,oBAAA,GAAeG,mCAAAA,qBAAAA,CAAqB;CDElC,aAAa;CACb,WAAW,MAAM,OAAO;EACtB,MAAM,QAAQ;EACd,MAAM,UAAU,CACd,MAAM,WAAW,KAAA,IAAY,KAAA,IAAY,QAAQ,MAAM,UACvD,MAAM,UAAU,KAAA,IAAY,KAAA,IAAY,GAAG,MAAM,MAAM,OACzD,CAAC,CAAC,QAAQ,UAA2B,UAAU,KAAA,CAAS;EACxD,QAAA,GAAOF,uCAAAA,mBAAAA,CAAmB,QAAQ,MAAM,MAAM,SAAS,KAAK;CAC9D;CACA,aAAa,QAAQ,SAAS,OAAO,SAAS;EAC5C,QAAA,GAAOC,uCAAAA,qBAAAA,CAAqB,QAAQ,SAAS,OAAO,SAAS,MAAM;CACrE;ACbkC,CAAY;;;ACShD,MAAM,MAAY,OAA0B,YAC1C,OAAO,UAAU,aAAc,MAAwB,OAAO,IAAI;AACpE,MAAM,OAAU,UAAmC,WAAuB;CAAE,GAAG;CAAU,GAAI;AAAiB;AAE9G,MAAa,aAAA,GAAYE,mCAAAA,kBAAAA,CAAoC,2BAA2B,aAAa,EACnG,IAAA,GAAGC,mCAAAA,oBAAAA,CAAoB,0BAA0B,CAAC,IAAI,EAAE,MAAM,OAAO,IAAA,GAAGC,mCAAAA,gBAAAA,CAAgB,GAAGC,oBAAU,OAAO,GAAG,GAAGC,kBAAY,OAAO,CAAC,CAAC,CAAC,CAAC,EAC3I,EAAE"}
1
+ {"version":3,"file":"pi.cjs","names":["resizeImage","formatDimensionNote","isWritableFile","formatSize","DEFAULT_MAX_BYTES","ReadParamsSchema","resolveReadInputPath","createReadToolDefinition","isImageRead","applyImageLimits","imageLimits","readFile","createTaggedReadResult","displayPath","definePiTool","renderHashlineCall","renderHashlineResult","definePiToolRenderer","definePiExtension","piToolContributions","withPiRenderers","toolRead","renderRead"],"sources":["../../src/extensions/workspaces/sessions/(backend)/tool/_lib/readTool.ts","../../src/extensions/workspaces/sessions/(backend)/tool/read.cli.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/_lib/readRenderer.cli.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/read.cli.ts","../../generated/pi.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\n\nimport { isWritableFile, displayPath, resolveReadInputPath } from '@agimon-ai/doompi-hashline/files';\nimport {\n createReadToolDefinition,\n DEFAULT_MAX_BYTES,\n formatDimensionNote,\n formatSize,\n resizeImage,\n type AgentToolResult,\n type ToolDefinition,\n} from '@earendil-works/pi-coding-agent';\n\nimport { ReadParamsSchema, type ReadParams } from '../../../../../../schemas/readTool';\nimport { applyImageLimits, imageLimits, type ReadImageResizeOperations } from '../../../../../../services/readImage';\nimport { assertNotAborted, createTaggedReadResult, isImageRead } from '../../../../../../services/readTool';\n\ntype WritableCheck = (path: string) => Promise<boolean>;\n\nconst resizeOperations: ReadImageResizeOperations = {\n resize: resizeImage,\n formatDimensionNote: (result) => formatDimensionNote(result),\n};\n\nexport function createHashlineReadTool(\n writable: WritableCheck = isWritableFile,\n): ToolDefinition<typeof ReadParamsSchema> {\n return {\n name: 'read',\n label: 'read',\n description: `Read a writable text file with an exact-byte file tag and stable line anchors. Non-writable files and images retain Pi's native behavior. Text is truncated to ${formatSize(DEFAULT_MAX_BYTES)}.`,\n promptSnippet: 'Read file contents with snapshot-bound line anchors',\n promptGuidelines: [\n 'Use read before edit. When hashline metadata is present, preserve the @file hash and anchors such as 5#abc exactly.',\n 'Continue large reads with offset until the required anchored lines are visible.',\n ],\n parameters: ReadParamsSchema,\n executionMode: 'parallel',\n async execute(toolCallId, params, signal, onUpdate, ctx) {\n const input = params as ReadParams;\n assertNotAborted(signal);\n const absolutePath = await resolveReadInputPath(input.path, ctx.cwd);\n const nativeRead = createReadToolDefinition(ctx.cwd, { autoResizeImages: false });\n const nativeResult = await nativeRead.execute(\n toolCallId,\n { ...input, path: absolutePath },\n signal,\n onUpdate,\n ctx,\n );\n if (isImageRead(nativeResult.content)) {\n assertNotAborted(signal);\n return {\n ...nativeResult,\n content: await applyImageLimits(nativeResult.content, imageLimits(), resizeOperations),\n };\n }\n\n assertNotAborted(signal);\n const canEdit = await writable(absolutePath);\n assertNotAborted(signal);\n if (!canEdit) return nativeResult;\n const bytes = await readFile(absolutePath);\n assertNotAborted(signal);\n return createTaggedReadResult(\n bytes,\n displayPath(absolutePath, ctx.cwd),\n input,\n ) as unknown as AgentToolResult<unknown>;\n },\n };\n}\n","import { definePiTool } from '@agimon-ai/doompi-core/piExtension';\n\nimport { createHashlineReadTool } from './_lib/readTool';\n\nexport default definePiTool(createHashlineReadTool(), { overrides: true });\n","import type { PiToolRenderers } from '@agimon-ai/doompi-core/piExtension';\nimport { renderHashlineCall, renderHashlineResult } from '@agimon-ai/doompi-ui/hashlineRendering';\n\nimport { ReadParamsSchema, type ReadParams } from '../../../../../../schemas/readTool';\n\nexport const readRenderer: PiToolRenderers<typeof ReadParamsSchema> = {\n renderShell: 'self',\n renderCall(args, theme) {\n const input = args as ReadParams;\n const details = [\n input.offset === undefined ? undefined : `from ${input.offset}`,\n input.limit === undefined ? undefined : `${input.limit} lines`,\n ].filter((value): value is string => value !== undefined);\n return renderHashlineCall('read', input.path, details, theme);\n },\n renderResult(result, options, theme, context) {\n return renderHashlineResult(result, options, theme, context, 'read');\n },\n};\n","import { definePiToolRenderer } from '@agimon-ai/doompi-core/piExtension';\n\nimport { readRenderer } from './_lib/readRenderer.cli';\n\nexport default definePiToolRenderer(readRenderer);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { definePiExtension, piToolContributions, withPiRenderers, type PiPluginContext } from '@agimon-ai/doompi-core/piExtension';\n\nimport toolRead from '../src/extensions/workspaces/sessions/(backend)/tool/read.cli';\nimport renderRead from '../src/extensions/workspaces/sessions/(frontend)/tool/read.cli';\n\ntype OptionsOf<T> = T extends (context: PiPluginContext<infer Options>) => unknown ? Options : never;\ntype InferredOptions = Exclude<OptionsOf<typeof toolRead>, undefined>;\ntype Intersect<Union> =\n (Union extends unknown ? (value: Union) => void : never) extends (value: infer Value) => void ? Value : never;\ntype ExtensionOptions = [InferredOptions] extends [never] ? undefined : Intersect<InferredOptions>;\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const extension = definePiExtension<ExtensionOptions>('@agimon-ai/doompi-read', (context) => ({\n ...piToolContributions('@agimon-ai/doompi-read', [via({ name: 'read' }, withPiRenderers(at(toolRead, context), at(renderRead, context)))]),\n}));\n\nexport default extension;\n"],"mappings":";;;;;;;;;;;AAmBA,MAAM,mBAA8C;CAClD,QAAQA,gCAAAA;CACR,sBAAsB,YAAA,GAAWC,gCAAAA,oBAAAA,CAAoB,MAAM;AAC7D;AAEA,SAAgB,uBACd,WAA0BC,iCAAAA,gBACe;CACzC,OAAO;EACL,MAAM;EACN,OAAO;EACP,aAAa,mKAAA,GAAkKC,gCAAAA,WAAAA,CAAWC,gCAAAA,iBAAiB,EAAE;EAC7M,eAAe;EACf,kBAAkB,CAChB,uHACA,iFACF;EACA,YAAYC,iBAAAA;EACZ,eAAe;EACf,MAAM,QAAQ,YAAY,QAAQ,QAAQ,UAAU,KAAK;GACvD,MAAM,QAAQ;GACd,iBAAA,iBAAiB,MAAM;GACvB,MAAM,eAAe,OAAA,GAAMC,iCAAAA,qBAAAA,CAAqB,MAAM,MAAM,IAAI,GAAG;GAEnE,MAAM,eAAe,OAAA,GADFC,gCAAAA,yBAAAA,CAAyB,IAAI,KAAK,EAAE,kBAAkB,MAAM,CAC3C,CAAC,CAAC,QACpC,YACA;IAAE,GAAG;IAAO,MAAM;GAAa,GAC/B,QACA,UACA,GACF;GACA,IAAIC,iBAAAA,YAAY,aAAa,OAAO,GAAG;IACrC,iBAAA,iBAAiB,MAAM;IACvB,OAAO;KACL,GAAG;KACH,SAAS,MAAMC,iBAAAA,iBAAiB,aAAa,SAASC,iBAAAA,YAAY,GAAG,gBAAgB;IACvF;GACF;GAEA,iBAAA,iBAAiB,MAAM;GACvB,MAAM,UAAU,MAAM,SAAS,YAAY;GAC3C,iBAAA,iBAAiB,MAAM;GACvB,IAAI,CAAC,SAAS,OAAO;GACrB,MAAM,QAAQ,OAAA,GAAMC,iBAAAA,SAAAA,CAAS,YAAY;GACzC,iBAAA,iBAAiB,MAAM;GACvB,OAAOC,iBAAAA,uBACL,QAAA,GACAC,iCAAAA,YAAAA,CAAY,cAAc,IAAI,GAAG,GACjC,KACF;EACF;CACF;AACF;;;ACnEA,IAAA,sBAAA,GAAeC,mCAAAA,aAAAA,CAAa,uBAAuB,GAAG,EAAE,WAAW,KAAK,CAAC;;;AEAzE,IAAA,oBAAA,GAAeG,mCAAAA,qBAAAA,CAAqB;CDElC,aAAa;CACb,WAAW,MAAM,OAAO;EACtB,MAAM,QAAQ;EACd,MAAM,UAAU,CACd,MAAM,WAAW,KAAA,IAAY,KAAA,IAAY,QAAQ,MAAM,UACvD,MAAM,UAAU,KAAA,IAAY,KAAA,IAAY,GAAG,MAAM,MAAM,OACzD,CAAC,CAAC,QAAQ,UAA2B,UAAU,KAAA,CAAS;EACxD,QAAA,GAAOF,uCAAAA,mBAAAA,CAAmB,QAAQ,MAAM,MAAM,SAAS,KAAK;CAC9D;CACA,aAAa,QAAQ,SAAS,OAAO,SAAS;EAC5C,QAAA,GAAOC,uCAAAA,qBAAAA,CAAqB,QAAQ,SAAS,OAAO,SAAS,MAAM;CACrE;ACbkC,CAAY;;;ACShD,MAAM,MAAY,OAA0B,YAC1C,OAAO,UAAU,aAAc,MAAwB,OAAO,IAAI;AACpE,MAAM,OAAU,UAAmC,UAChD,UAAU,KAAA,IAAY,KAAA,IAAY;CAAE,GAAG;CAAU,GAAI;AAAiB;AAEzE,MAAa,aAAA,GAAYE,mCAAAA,kBAAAA,CAAoC,2BAA2B,aAAa,EACnG,IAAA,GAAGC,mCAAAA,oBAAAA,CAAoB,0BAA0B,CAAC,IAAI,EAAE,MAAM,OAAO,IAAA,GAAGC,mCAAAA,gBAAAA,CAAgB,GAAGC,oBAAU,OAAO,GAAG,GAAGC,kBAAY,OAAO,CAAC,CAAC,CAAC,CAAC,EAC3I,EAAE"}
@@ -1 +1 @@
1
- {"version":3,"file":"pi.d.mts","names":[],"sources":["../../generated/pi.ts"],"mappings":";qBAiBa,+DAAS"}
1
+ {"version":3,"file":"pi.d.mts","names":[],"sources":["../../generated/pi.ts"],"mappings":";qBAkBa,+DAAS"}
@@ -62,10 +62,10 @@ var read_cli_default = definePiToolRenderer({
62
62
  //#endregion
63
63
  //#region generated/pi.ts
64
64
  const at = (value, context) => typeof value === "function" ? value(context) : value;
65
- const via = (identity, value) => ({
65
+ const via = (identity, value) => value === void 0 ? void 0 : {
66
66
  ...identity,
67
67
  ...value
68
- });
68
+ };
69
69
  const extension = definePiExtension("@agimon-ai/doompi-read", (context) => ({ ...piToolContributions("@agimon-ai/doompi-read", [via({ name: "read" }, withPiRenderers(at(read_cli_default$1, context), at(read_cli_default, context)))]) }));
70
70
  //#endregion
71
71
  export { extension as default, extension };
@@ -1 +1 @@
1
- {"version":3,"file":"pi.mjs","names":["toolRead","renderRead"],"sources":["../../src/extensions/workspaces/sessions/(backend)/tool/_lib/readTool.ts","../../src/extensions/workspaces/sessions/(backend)/tool/read.cli.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/_lib/readRenderer.cli.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/read.cli.ts","../../generated/pi.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\n\nimport { isWritableFile, displayPath, resolveReadInputPath } from '@agimon-ai/doompi-hashline/files';\nimport {\n createReadToolDefinition,\n DEFAULT_MAX_BYTES,\n formatDimensionNote,\n formatSize,\n resizeImage,\n type AgentToolResult,\n type ToolDefinition,\n} from '@earendil-works/pi-coding-agent';\n\nimport { ReadParamsSchema, type ReadParams } from '../../../../../../schemas/readTool';\nimport { applyImageLimits, imageLimits, type ReadImageResizeOperations } from '../../../../../../services/readImage';\nimport { assertNotAborted, createTaggedReadResult, isImageRead } from '../../../../../../services/readTool';\n\ntype WritableCheck = (path: string) => Promise<boolean>;\n\nconst resizeOperations: ReadImageResizeOperations = {\n resize: resizeImage,\n formatDimensionNote: (result) => formatDimensionNote(result),\n};\n\nexport function createHashlineReadTool(\n writable: WritableCheck = isWritableFile,\n): ToolDefinition<typeof ReadParamsSchema> {\n return {\n name: 'read',\n label: 'read',\n description: `Read a writable text file with an exact-byte file tag and stable line anchors. Non-writable files and images retain Pi's native behavior. Text is truncated to ${formatSize(DEFAULT_MAX_BYTES)}.`,\n promptSnippet: 'Read file contents with snapshot-bound line anchors',\n promptGuidelines: [\n 'Use read before edit. When hashline metadata is present, preserve the @file hash and anchors such as 5#abc exactly.',\n 'Continue large reads with offset until the required anchored lines are visible.',\n ],\n parameters: ReadParamsSchema,\n executionMode: 'parallel',\n async execute(toolCallId, params, signal, onUpdate, ctx) {\n const input = params as ReadParams;\n assertNotAborted(signal);\n const absolutePath = await resolveReadInputPath(input.path, ctx.cwd);\n const nativeRead = createReadToolDefinition(ctx.cwd, { autoResizeImages: false });\n const nativeResult = await nativeRead.execute(\n toolCallId,\n { ...input, path: absolutePath },\n signal,\n onUpdate,\n ctx,\n );\n if (isImageRead(nativeResult.content)) {\n assertNotAborted(signal);\n return {\n ...nativeResult,\n content: await applyImageLimits(nativeResult.content, imageLimits(), resizeOperations),\n };\n }\n\n assertNotAborted(signal);\n const canEdit = await writable(absolutePath);\n assertNotAborted(signal);\n if (!canEdit) return nativeResult;\n const bytes = await readFile(absolutePath);\n assertNotAborted(signal);\n return createTaggedReadResult(\n bytes,\n displayPath(absolutePath, ctx.cwd),\n input,\n ) as unknown as AgentToolResult<unknown>;\n },\n };\n}\n","import { definePiTool } from '@agimon-ai/doompi-core/piExtension';\n\nimport { createHashlineReadTool } from './_lib/readTool';\n\nexport default definePiTool(createHashlineReadTool(), { overrides: true });\n","import type { PiToolRenderers } from '@agimon-ai/doompi-core/piExtension';\nimport { renderHashlineCall, renderHashlineResult } from '@agimon-ai/doompi-ui/hashlineRendering';\n\nimport { ReadParamsSchema, type ReadParams } from '../../../../../../schemas/readTool';\n\nexport const readRenderer: PiToolRenderers<typeof ReadParamsSchema> = {\n renderShell: 'self',\n renderCall(args, theme) {\n const input = args as ReadParams;\n const details = [\n input.offset === undefined ? undefined : `from ${input.offset}`,\n input.limit === undefined ? undefined : `${input.limit} lines`,\n ].filter((value): value is string => value !== undefined);\n return renderHashlineCall('read', input.path, details, theme);\n },\n renderResult(result, options, theme, context) {\n return renderHashlineResult(result, options, theme, context, 'read');\n },\n};\n","import { definePiToolRenderer } from '@agimon-ai/doompi-core/piExtension';\n\nimport { readRenderer } from './_lib/readRenderer.cli';\n\nexport default definePiToolRenderer(readRenderer);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { definePiExtension, piToolContributions, withPiRenderers, type PiPluginContext } from '@agimon-ai/doompi-core/piExtension';\n\nimport toolRead from '../src/extensions/workspaces/sessions/(backend)/tool/read.cli';\nimport renderRead from '../src/extensions/workspaces/sessions/(frontend)/tool/read.cli';\n\ntype OptionsOf<T> = T extends (context: PiPluginContext<infer Options>) => unknown ? Options : never;\ntype InferredOptions = Exclude<OptionsOf<typeof toolRead>, undefined>;\ntype Intersect<Union> =\n (Union extends unknown ? (value: Union) => void : never) extends (value: infer Value) => void ? Value : never;\ntype ExtensionOptions = [InferredOptions] extends [never] ? undefined : Intersect<InferredOptions>;\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T => ({ ...identity, ...(value as object) }) as T;\n\nexport const extension = definePiExtension<ExtensionOptions>('@agimon-ai/doompi-read', (context) => ({\n ...piToolContributions('@agimon-ai/doompi-read', [via({ name: 'read' }, withPiRenderers(at(toolRead, context), at(renderRead, context)))]),\n}));\n\nexport default extension;\n"],"mappings":";;;;;;;AAmBA,MAAM,mBAA8C;CAClD,QAAQ;CACR,sBAAsB,WAAW,oBAAoB,MAAM;AAC7D;AAEA,SAAgB,uBACd,WAA0B,gBACe;CACzC,OAAO;EACL,MAAM;EACN,OAAO;EACP,aAAa,kKAAkK,WAAW,iBAAiB,EAAE;EAC7M,eAAe;EACf,kBAAkB,CAChB,uHACA,iFACF;EACA,YAAY;EACZ,eAAe;EACf,MAAM,QAAQ,YAAY,QAAQ,QAAQ,UAAU,KAAK;GACvD,MAAM,QAAQ;GACd,iBAAiB,MAAM;GACvB,MAAM,eAAe,MAAM,qBAAqB,MAAM,MAAM,IAAI,GAAG;GAEnE,MAAM,eAAe,MADF,yBAAyB,IAAI,KAAK,EAAE,kBAAkB,MAAM,CAC3C,CAAC,CAAC,QACpC,YACA;IAAE,GAAG;IAAO,MAAM;GAAa,GAC/B,QACA,UACA,GACF;GACA,IAAI,YAAY,aAAa,OAAO,GAAG;IACrC,iBAAiB,MAAM;IACvB,OAAO;KACL,GAAG;KACH,SAAS,MAAM,iBAAiB,aAAa,SAAS,YAAY,GAAG,gBAAgB;IACvF;GACF;GAEA,iBAAiB,MAAM;GACvB,MAAM,UAAU,MAAM,SAAS,YAAY;GAC3C,iBAAiB,MAAM;GACvB,IAAI,CAAC,SAAS,OAAO;GACrB,MAAM,QAAQ,MAAM,SAAS,YAAY;GACzC,iBAAiB,MAAM;GACvB,OAAO,uBACL,OACA,YAAY,cAAc,IAAI,GAAG,GACjC,KACF;EACF;CACF;AACF;;;ACnEA,IAAA,qBAAe,aAAa,uBAAuB,GAAG,EAAE,WAAW,KAAK,CAAC;;;AEAzE,IAAA,mBAAe,qBAAqB;CDElC,aAAa;CACb,WAAW,MAAM,OAAO;EACtB,MAAM,QAAQ;EACd,MAAM,UAAU,CACd,MAAM,WAAW,KAAA,IAAY,KAAA,IAAY,QAAQ,MAAM,UACvD,MAAM,UAAU,KAAA,IAAY,KAAA,IAAY,GAAG,MAAM,MAAM,OACzD,CAAC,CAAC,QAAQ,UAA2B,UAAU,KAAA,CAAS;EACxD,OAAO,mBAAmB,QAAQ,MAAM,MAAM,SAAS,KAAK;CAC9D;CACA,aAAa,QAAQ,SAAS,OAAO,SAAS;EAC5C,OAAO,qBAAqB,QAAQ,SAAS,OAAO,SAAS,MAAM;CACrE;ACbkC,CAAY;;;ACShD,MAAM,MAAY,OAA0B,YAC1C,OAAO,UAAU,aAAc,MAAwB,OAAO,IAAI;AACpE,MAAM,OAAU,UAAmC,WAAuB;CAAE,GAAG;CAAU,GAAI;AAAiB;AAE9G,MAAa,YAAY,kBAAoC,2BAA2B,aAAa,EACnG,GAAG,oBAAoB,0BAA0B,CAAC,IAAI,EAAE,MAAM,OAAO,GAAG,gBAAgB,GAAGA,oBAAU,OAAO,GAAG,GAAGC,kBAAY,OAAO,CAAC,CAAC,CAAC,CAAC,EAC3I,EAAE"}
1
+ {"version":3,"file":"pi.mjs","names":["toolRead","renderRead"],"sources":["../../src/extensions/workspaces/sessions/(backend)/tool/_lib/readTool.ts","../../src/extensions/workspaces/sessions/(backend)/tool/read.cli.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/_lib/readRenderer.cli.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/read.cli.ts","../../generated/pi.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\n\nimport { isWritableFile, displayPath, resolveReadInputPath } from '@agimon-ai/doompi-hashline/files';\nimport {\n createReadToolDefinition,\n DEFAULT_MAX_BYTES,\n formatDimensionNote,\n formatSize,\n resizeImage,\n type AgentToolResult,\n type ToolDefinition,\n} from '@earendil-works/pi-coding-agent';\n\nimport { ReadParamsSchema, type ReadParams } from '../../../../../../schemas/readTool';\nimport { applyImageLimits, imageLimits, type ReadImageResizeOperations } from '../../../../../../services/readImage';\nimport { assertNotAborted, createTaggedReadResult, isImageRead } from '../../../../../../services/readTool';\n\ntype WritableCheck = (path: string) => Promise<boolean>;\n\nconst resizeOperations: ReadImageResizeOperations = {\n resize: resizeImage,\n formatDimensionNote: (result) => formatDimensionNote(result),\n};\n\nexport function createHashlineReadTool(\n writable: WritableCheck = isWritableFile,\n): ToolDefinition<typeof ReadParamsSchema> {\n return {\n name: 'read',\n label: 'read',\n description: `Read a writable text file with an exact-byte file tag and stable line anchors. Non-writable files and images retain Pi's native behavior. Text is truncated to ${formatSize(DEFAULT_MAX_BYTES)}.`,\n promptSnippet: 'Read file contents with snapshot-bound line anchors',\n promptGuidelines: [\n 'Use read before edit. When hashline metadata is present, preserve the @file hash and anchors such as 5#abc exactly.',\n 'Continue large reads with offset until the required anchored lines are visible.',\n ],\n parameters: ReadParamsSchema,\n executionMode: 'parallel',\n async execute(toolCallId, params, signal, onUpdate, ctx) {\n const input = params as ReadParams;\n assertNotAborted(signal);\n const absolutePath = await resolveReadInputPath(input.path, ctx.cwd);\n const nativeRead = createReadToolDefinition(ctx.cwd, { autoResizeImages: false });\n const nativeResult = await nativeRead.execute(\n toolCallId,\n { ...input, path: absolutePath },\n signal,\n onUpdate,\n ctx,\n );\n if (isImageRead(nativeResult.content)) {\n assertNotAborted(signal);\n return {\n ...nativeResult,\n content: await applyImageLimits(nativeResult.content, imageLimits(), resizeOperations),\n };\n }\n\n assertNotAborted(signal);\n const canEdit = await writable(absolutePath);\n assertNotAborted(signal);\n if (!canEdit) return nativeResult;\n const bytes = await readFile(absolutePath);\n assertNotAborted(signal);\n return createTaggedReadResult(\n bytes,\n displayPath(absolutePath, ctx.cwd),\n input,\n ) as unknown as AgentToolResult<unknown>;\n },\n };\n}\n","import { definePiTool } from '@agimon-ai/doompi-core/piExtension';\n\nimport { createHashlineReadTool } from './_lib/readTool';\n\nexport default definePiTool(createHashlineReadTool(), { overrides: true });\n","import type { PiToolRenderers } from '@agimon-ai/doompi-core/piExtension';\nimport { renderHashlineCall, renderHashlineResult } from '@agimon-ai/doompi-ui/hashlineRendering';\n\nimport { ReadParamsSchema, type ReadParams } from '../../../../../../schemas/readTool';\n\nexport const readRenderer: PiToolRenderers<typeof ReadParamsSchema> = {\n renderShell: 'self',\n renderCall(args, theme) {\n const input = args as ReadParams;\n const details = [\n input.offset === undefined ? undefined : `from ${input.offset}`,\n input.limit === undefined ? undefined : `${input.limit} lines`,\n ].filter((value): value is string => value !== undefined);\n return renderHashlineCall('read', input.path, details, theme);\n },\n renderResult(result, options, theme, context) {\n return renderHashlineResult(result, options, theme, context, 'read');\n },\n};\n","import { definePiToolRenderer } from '@agimon-ai/doompi-core/piExtension';\n\nimport { readRenderer } from './_lib/readRenderer.cli';\n\nexport default definePiToolRenderer(readRenderer);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { definePiExtension, piToolContributions, withPiRenderers, type PiPluginContext } from '@agimon-ai/doompi-core/piExtension';\n\nimport toolRead from '../src/extensions/workspaces/sessions/(backend)/tool/read.cli';\nimport renderRead from '../src/extensions/workspaces/sessions/(frontend)/tool/read.cli';\n\ntype OptionsOf<T> = T extends (context: PiPluginContext<infer Options>) => unknown ? Options : never;\ntype InferredOptions = Exclude<OptionsOf<typeof toolRead>, undefined>;\ntype Intersect<Union> =\n (Union extends unknown ? (value: Union) => void : never) extends (value: infer Value) => void ? Value : never;\ntype ExtensionOptions = [InferredOptions] extends [never] ? undefined : Intersect<InferredOptions>;\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const extension = definePiExtension<ExtensionOptions>('@agimon-ai/doompi-read', (context) => ({\n ...piToolContributions('@agimon-ai/doompi-read', [via({ name: 'read' }, withPiRenderers(at(toolRead, context), at(renderRead, context)))]),\n}));\n\nexport default extension;\n"],"mappings":";;;;;;;AAmBA,MAAM,mBAA8C;CAClD,QAAQ;CACR,sBAAsB,WAAW,oBAAoB,MAAM;AAC7D;AAEA,SAAgB,uBACd,WAA0B,gBACe;CACzC,OAAO;EACL,MAAM;EACN,OAAO;EACP,aAAa,kKAAkK,WAAW,iBAAiB,EAAE;EAC7M,eAAe;EACf,kBAAkB,CAChB,uHACA,iFACF;EACA,YAAY;EACZ,eAAe;EACf,MAAM,QAAQ,YAAY,QAAQ,QAAQ,UAAU,KAAK;GACvD,MAAM,QAAQ;GACd,iBAAiB,MAAM;GACvB,MAAM,eAAe,MAAM,qBAAqB,MAAM,MAAM,IAAI,GAAG;GAEnE,MAAM,eAAe,MADF,yBAAyB,IAAI,KAAK,EAAE,kBAAkB,MAAM,CAC3C,CAAC,CAAC,QACpC,YACA;IAAE,GAAG;IAAO,MAAM;GAAa,GAC/B,QACA,UACA,GACF;GACA,IAAI,YAAY,aAAa,OAAO,GAAG;IACrC,iBAAiB,MAAM;IACvB,OAAO;KACL,GAAG;KACH,SAAS,MAAM,iBAAiB,aAAa,SAAS,YAAY,GAAG,gBAAgB;IACvF;GACF;GAEA,iBAAiB,MAAM;GACvB,MAAM,UAAU,MAAM,SAAS,YAAY;GAC3C,iBAAiB,MAAM;GACvB,IAAI,CAAC,SAAS,OAAO;GACrB,MAAM,QAAQ,MAAM,SAAS,YAAY;GACzC,iBAAiB,MAAM;GACvB,OAAO,uBACL,OACA,YAAY,cAAc,IAAI,GAAG,GACjC,KACF;EACF;CACF;AACF;;;ACnEA,IAAA,qBAAe,aAAa,uBAAuB,GAAG,EAAE,WAAW,KAAK,CAAC;;;AEAzE,IAAA,mBAAe,qBAAqB;CDElC,aAAa;CACb,WAAW,MAAM,OAAO;EACtB,MAAM,QAAQ;EACd,MAAM,UAAU,CACd,MAAM,WAAW,KAAA,IAAY,KAAA,IAAY,QAAQ,MAAM,UACvD,MAAM,UAAU,KAAA,IAAY,KAAA,IAAY,GAAG,MAAM,MAAM,OACzD,CAAC,CAAC,QAAQ,UAA2B,UAAU,KAAA,CAAS;EACxD,OAAO,mBAAmB,QAAQ,MAAM,MAAM,SAAS,KAAK;CAC9D;CACA,aAAa,QAAQ,SAAS,OAAO,SAAS;EAC5C,OAAO,qBAAqB,QAAQ,SAAS,OAAO,SAAS,MAAM;CACrE;ACbkC,CAAY;;;ACShD,MAAM,MAAY,OAA0B,YAC1C,OAAO,UAAU,aAAc,MAAwB,OAAO,IAAI;AACpE,MAAM,OAAU,UAAmC,UAChD,UAAU,KAAA,IAAY,KAAA,IAAY;CAAE,GAAG;CAAU,GAAI;AAAiB;AAEzE,MAAa,YAAY,kBAAoC,2BAA2B,aAAa,EACnG,GAAG,oBAAoB,0BAA0B,CAAC,IAAI,EAAE,MAAM,OAAO,GAAG,gBAAgB,GAAGA,oBAAU,OAAO,GAAG,GAAGC,kBAAY,OAAO,CAAC,CAAC,CAAC,CAAC,EAC3I,EAAE"}
@@ -9,10 +9,10 @@ var read_server_default = (0, require("@agimon-ai/doompi-core/extensionFile").de
9
9
  //#endregion
10
10
  //#region generated/server.ts
11
11
  const at = (value, context) => typeof value === "function" ? value(context) : value;
12
- const via = (identity, value) => ({
12
+ const via = (identity, value) => value === void 0 ? void 0 : {
13
13
  ...identity,
14
14
  ...value
15
- });
15
+ };
16
16
  const facet = (0, _agimon_ai_doompi_core_serverFacet.defineServerPlugin)({
17
17
  name: "@agimon-ai/doompi-read",
18
18
  session: (context) => ({ get tools() {
@@ -1 +1 @@
1
- {"version":3,"file":"server.cjs","names":["defineServerTool","createHeadlessReadTool","defineServerPlugin","toolRead"],"sources":["../../src/extensions/workspaces/sessions/(backend)/tool/read.server.ts","../../generated/server.ts"],"sourcesContent":["import { defineServerTool } from '@agimon-ai/doompi-core/extensionFile';\n\nimport { createHeadlessReadTool } from '../../../../../services/readTool';\n\nexport default defineServerTool(createHeadlessReadTool);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { defineServerPlugin, type DoomServerSessionPlugin } from '@agimon-ai/doompi-core/serverFacet';\n\nimport toolRead from '../src/extensions/workspaces/sessions/(backend)/tool/read.server';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T => ({ ...identity, ...(value as object) }) as T;\n\nexport const facet = defineServerPlugin({\n name: '@agimon-ai/doompi-read',\n session: (context) => ({\n get tools(): DoomServerSessionPlugin['tools'] { return [via({ name: 'read' }, at(toolRead, context))]; },\n }),\n});\n\nexport default facet;\n"],"mappings":";;;;;;;AAIA,IAAA,uBAAA,iDAAeA,CAAAA,CAAAA,iBAAAA,CAAiBC,iBAAAA,sBAAsB;;;ACEtD,MAAM,MAAY,OAA0B,YAC1C,OAAO,UAAU,aAAc,MAAwB,OAAO,IAAI;AACpE,MAAM,OAAU,UAAmC,WAAuB;CAAE,GAAG;CAAU,GAAI;AAAiB;AAE9G,MAAa,SAAA,GAAQC,mCAAAA,mBAAAA,CAAmB;CACtC,MAAM;CACN,UAAU,aAAa,EACrB,IAAI,QAA0C;EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,OAAO,GAAG,GAAGC,qBAAU,OAAO,CAAC,CAAC;CAAG,EACzG;AACF,CAAC"}
1
+ {"version":3,"file":"server.cjs","names":["defineServerTool","createHeadlessReadTool","defineServerPlugin","toolRead"],"sources":["../../src/extensions/workspaces/sessions/(backend)/tool/read.server.ts","../../generated/server.ts"],"sourcesContent":["import { defineServerTool } from '@agimon-ai/doompi-core/extensionFile';\n\nimport { createHeadlessReadTool } from '../../../../../services/readTool';\n\nexport default defineServerTool(createHeadlessReadTool);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { defineServerPlugin, type DoomServerSessionPlugin } from '@agimon-ai/doompi-core/serverFacet';\n\nimport toolRead from '../src/extensions/workspaces/sessions/(backend)/tool/read.server';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const facet = defineServerPlugin({\n name: '@agimon-ai/doompi-read',\n session: (context) => ({\n get tools(): DoomServerSessionPlugin['tools'] { return [via({ name: 'read' }, at(toolRead, context))]; },\n }),\n});\n\nexport default facet;\n"],"mappings":";;;;;;;AAIA,IAAA,uBAAA,iDAAeA,CAAAA,CAAAA,iBAAAA,CAAiBC,iBAAAA,sBAAsB;;;ACEtD,MAAM,MAAY,OAA0B,YAC1C,OAAO,UAAU,aAAc,MAAwB,OAAO,IAAI;AACpE,MAAM,OAAU,UAAmC,UAChD,UAAU,KAAA,IAAY,KAAA,IAAY;CAAE,GAAG;CAAU,GAAI;AAAiB;AAEzE,MAAa,SAAA,GAAQC,mCAAAA,mBAAAA,CAAmB;CACtC,MAAM;CACN,UAAU,aAAa,EACrB,IAAI,QAA0C;EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,OAAO,GAAG,GAAGC,qBAAU,OAAO,CAAC,CAAC;CAAG,EACzG;AACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.mts","names":[],"sources":["../../generated/server.ts"],"mappings":";qBAUa,oDAAK"}
1
+ {"version":3,"file":"server.d.mts","names":[],"sources":["../../generated/server.ts"],"mappings":";qBAWa,oDAAK"}
@@ -6,10 +6,10 @@ var read_server_default = defineServerTool(createHeadlessReadTool);
6
6
  //#endregion
7
7
  //#region generated/server.ts
8
8
  const at = (value, context) => typeof value === "function" ? value(context) : value;
9
- const via = (identity, value) => ({
9
+ const via = (identity, value) => value === void 0 ? void 0 : {
10
10
  ...identity,
11
11
  ...value
12
- });
12
+ };
13
13
  const facet = defineServerPlugin({
14
14
  name: "@agimon-ai/doompi-read",
15
15
  session: (context) => ({ get tools() {
@@ -1 +1 @@
1
- {"version":3,"file":"server.mjs","names":["toolRead"],"sources":["../../src/extensions/workspaces/sessions/(backend)/tool/read.server.ts","../../generated/server.ts"],"sourcesContent":["import { defineServerTool } from '@agimon-ai/doompi-core/extensionFile';\n\nimport { createHeadlessReadTool } from '../../../../../services/readTool';\n\nexport default defineServerTool(createHeadlessReadTool);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { defineServerPlugin, type DoomServerSessionPlugin } from '@agimon-ai/doompi-core/serverFacet';\n\nimport toolRead from '../src/extensions/workspaces/sessions/(backend)/tool/read.server';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T => ({ ...identity, ...(value as object) }) as T;\n\nexport const facet = defineServerPlugin({\n name: '@agimon-ai/doompi-read',\n session: (context) => ({\n get tools(): DoomServerSessionPlugin['tools'] { return [via({ name: 'read' }, at(toolRead, context))]; },\n }),\n});\n\nexport default facet;\n"],"mappings":";;;;AAIA,IAAA,sBAAe,iBAAiB,sBAAsB;;;ACEtD,MAAM,MAAY,OAA0B,YAC1C,OAAO,UAAU,aAAc,MAAwB,OAAO,IAAI;AACpE,MAAM,OAAU,UAAmC,WAAuB;CAAE,GAAG;CAAU,GAAI;AAAiB;AAE9G,MAAa,QAAQ,mBAAmB;CACtC,MAAM;CACN,UAAU,aAAa,EACrB,IAAI,QAA0C;EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,OAAO,GAAG,GAAGA,qBAAU,OAAO,CAAC,CAAC;CAAG,EACzG;AACF,CAAC"}
1
+ {"version":3,"file":"server.mjs","names":["toolRead"],"sources":["../../src/extensions/workspaces/sessions/(backend)/tool/read.server.ts","../../generated/server.ts"],"sourcesContent":["import { defineServerTool } from '@agimon-ai/doompi-core/extensionFile';\n\nimport { createHeadlessReadTool } from '../../../../../services/readTool';\n\nexport default defineServerTool(createHeadlessReadTool);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { defineServerPlugin, type DoomServerSessionPlugin } from '@agimon-ai/doompi-core/serverFacet';\n\nimport toolRead from '../src/extensions/workspaces/sessions/(backend)/tool/read.server';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const facet = defineServerPlugin({\n name: '@agimon-ai/doompi-read',\n session: (context) => ({\n get tools(): DoomServerSessionPlugin['tools'] { return [via({ name: 'read' }, at(toolRead, context))]; },\n }),\n});\n\nexport default facet;\n"],"mappings":";;;;AAIA,IAAA,sBAAe,iBAAiB,sBAAsB;;;ACEtD,MAAM,MAAY,OAA0B,YAC1C,OAAO,UAAU,aAAc,MAAwB,OAAO,IAAI;AACpE,MAAM,OAAU,UAAmC,UAChD,UAAU,KAAA,IAAY,KAAA,IAAY;CAAE,GAAG;CAAU,GAAI;AAAiB;AAEzE,MAAa,QAAQ,mBAAmB;CACtC,MAAM;CACN,UAAU,aAAa,EACrB,IAAI,QAA0C;EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,OAAO,GAAG,GAAGA,qBAAU,OAAO,CAAC,CAAC;CAAG,EACzG;AACF,CAAC"}
@@ -118,10 +118,10 @@ function ReadToolMessage({ args, result, output, running, isError, fileTabFor, o
118
118
  var read_web_default = defineToolRenderer({ message: ReadToolMessage });
119
119
  //#endregion
120
120
  //#region generated/web.ts
121
- const via = (identity, value) => ({
121
+ const via = (identity, value) => value === void 0 ? void 0 : {
122
122
  ...identity,
123
123
  ...value
124
- });
124
+ };
125
125
  const webPlugin = defineWebPlugin({
126
126
  id: "read",
127
127
  session: { get toolRenderers() {
@@ -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":["import { compactDetails } from '@agimon-ai/doompi-web-components';\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: compactDetails([\n offset === undefined ? undefined : `from ${offset}`,\n limit === undefined ? undefined : `${limit} lines`,\n ]),\n };\n}\n","import type { ToolMessageRenderProps } from '@agimon-ai/doompi-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/doompi-web-components';\n\nimport { readCallView } from '../_lib/readToolView';\n\nconst IMAGE_MIME_TYPES = new Set(['image/png', 'image/jpeg', 'image/gif', 'image/webp']);\n\nfunction 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/**\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-doom-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-doom-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-doom-border-soft object-contain\"\n />\n </a>\n );\n })}\n {body.notice !== undefined ? <span className=\"text-doom-faint\">{body.notice}</span> : null}\n </MessageItemBody>\n )\n ) : null}\n </>\n );\n }}\n </MessageItem>\n );\n}\n","import { defineToolRenderer } from '@agimon-ai/doompi-core/web';\n\nimport { ReadToolMessage } from './_components/ReadToolMessage';\n\nexport default defineToolRenderer({ message: ReadToolMessage });\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { defineWebPlugin, type WebPluginContributions } from '@agimon-ai/doompi-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 => ({ ...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":";;;;AAQA,SAAS,eAAe,OAAoC;CAC1D,OAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,IAAI,QAAQ,KAAA;AACvE;;AAGA,SAAgB,aAAa,MAAuD;CAClF,MAAM,SAAS,eAAe,KAAK,MAAM;CACzC,MAAM,QAAQ,eAAe,KAAK,KAAK;CACvC,OAAO;EACL,MAAM,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO;EAClD,SAAS,eAAe,CACtB,WAAW,KAAA,IAAY,KAAA,IAAY,QAAQ,UAC3C,UAAU,KAAA,IAAY,KAAA,IAAY,GAAG,MAAM,OAC7C,CAAC;CACH;AACF;;;ACRA,MAAM,mCAAmB,IAAI,IAAI;CAAC;CAAa;CAAc;CAAa;AAAY,CAAC;AAEvF,SAAS,aAAa,SAAwE;CAC5F,OAAO,QAAQ,SAAS,UAAU;EAChC,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,GAAG,OAAO,CAAC;EACjF,MAAM,QAAQ;EACd,OAAO,MAAM,SAAS,WACpB,OAAO,MAAM,SAAS,YACtB,OAAO,MAAM,aAAa,YAC1B,iBAAiB,IAAI,MAAM,QAAQ,IACjC,CAAC;GAAE,MAAM,MAAM;GAAM,UAAU,MAAM;EAAS,CAAC,IAC/C,CAAC;CACP,CAAC;AACH;;;;;;;AAOA,SAAgB,gBAAgB,EAC9B,MACA,QACA,QACA,SACA,SACA,YACA,oBACyB;CACzB,MAAM,OAAO,aAAa,IAAI;CAC9B,MAAM,SAAS,aAAa,QAAQ,WAAW,CAAC,CAAC;CAGjD,MAAM,MAAM,WAAW,KAAK,IAAI;CAChC,MAAM,OAAO,WAAW,QAAQ,UAAU,OAAO,aAAa,QAAQ,QAAQ,QAAQ,IAAI;CAC1F,OACE,oBAAC,aAAD;EAAa,MAAM,SAAS;GAAE;GAAS;EAAQ,CAAC;EAAG,YAAA;EAAW,iBAAiB;EAC3E,WAAA,EAAE,eAAe;GACjB,OACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,mBAAD;IAAmB,OAAM;IACvB,UAAA,qBAAC,QAAD;KAAM,eAAY;KAAiB,WAAU;KAA7C,UAAA,CACE,oBAAC,cAAD;MACE,MAAM,KAAK;MACX,GAAK,QAAQ,KAAA,IAAY,CAAC,IAAI,EAAE,cAAc,iBAAiB,GAAG,EAAE;KACrE,CAAA,GACA,KAAK,QAAQ,SAAS,IACrB,qBAAC,QAAD;MAAM,WAAU;MAAhB,UAAA,CAA2C,MAAG,KAAK,QAAQ,KAAK,KAAK,CAAQ;KAC3E,CAAA,IAAA,IACA;;GACW,CAAA,GAClB,WACC,UACE,qBAAC,iBAAD;IAAiB,eAAY;IAAmB,WAAU;IAA1D,UAAA,CACE,oBAAC,mBAAD;KAAmB,MAAK;KAAQ,UAAA;IAAyB,CAAA,GACxD,gBAAgB,QAAQ,MAAM,CAAC,CAAC,KAAK,MAAM,UAC1C,oBAAC,QAAD;KAAuC,WAAU;KAC9C,UAAA;IACG,GAFK,GAAG,OAAO,KAAK,EAAE,GAAG,MAEzB,CACP,CACc;GACf,CAAA,IAAA,SAAS,OACX,UACE,oBAAC,iBAAD;IAAiB,eAAY;IAC3B,UAAA,oBAAC,mBAAD;KAAmB,MAAK;KAAU,UAAA;IAA0B,CAAA;GAC7C,CAAA,IACf,OACF,KAAK,MAAM,WAAW,KAAK,KAAK,WAAW,KAAA,KAAa,OAAO,WAAW,IAAI,OAChF,qBAAC,iBAAD;IAAiB,eAAY;IAAmB,WAAU;IAA1D,UAAA;KAGE,oBAAC,eAAD;MAAe,OAAO,KAAK;MAAO,QAAQ,KAAK;MAAQ,MAAM,KAAK;KAAO,CAAA;KACxE,OAAO,KAAK,OAAO,UAAU;MAC5B,MAAM,MAAM,QAAQ,MAAM,SAAS,UAAU,MAAM;MACnD,OACE,oBAAC,KAAD;OAEE,MAAM;OACN,QAAO;OACP,KAAI;OACJ,WAAU;OAEV,UAAA,oBAAC,OAAD;QACE,KAAK;QACL,KAAK,eAAe,OAAO,QAAQ,CAAC;QACpC,eAAY;QACZ,WAAU;OACX,CAAA;MACA,GAZI,GAAG,MAAM,SAAS,GAAG,OAAO,KAAK,GAYrC;KAEP,CAAC;KACA,KAAK,WAAW,KAAA,IAAY,oBAAC,QAAD;MAAM,WAAU;MAAmB,UAAA,KAAK;KAAa,CAAA,IAAI;IACvE;GAEjB,CAAA,IAAA,IACJ,EAAA,CAAA;EAEN;CACW,CAAA;AAEjB;;;AC/GA,IAAA,mBAAe,mBAAmB,EAAE,SAAS,gBAAgB,CAAC;;;ACC9D,MAAM,OAAU,UAAmC,WAAuB;CAAE,GAAG;CAAU,GAAI;AAAiB;AAE9G,MAAa,YAAY,gBAAgB;CACvC,IAAI;CACJ,SAAS,EACP,IAAI,gBAAyD;EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,GAAGA,gBAAQ,CAAC;CAAG,EAC9G;AACF,CAAC"}
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":["import { compactDetails } from '@agimon-ai/doompi-web-components';\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: compactDetails([\n offset === undefined ? undefined : `from ${offset}`,\n limit === undefined ? undefined : `${limit} lines`,\n ]),\n };\n}\n","import type { ToolMessageRenderProps } from '@agimon-ai/doompi-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/doompi-web-components';\n\nimport { readCallView } from '../_lib/readToolView';\n\nconst IMAGE_MIME_TYPES = new Set(['image/png', 'image/jpeg', 'image/gif', 'image/webp']);\n\nfunction 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/**\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-doom-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-doom-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-doom-border-soft object-contain\"\n />\n </a>\n );\n })}\n {body.notice !== undefined ? <span className=\"text-doom-faint\">{body.notice}</span> : null}\n </MessageItemBody>\n )\n ) : null}\n </>\n );\n }}\n </MessageItem>\n );\n}\n","import { defineToolRenderer } from '@agimon-ai/doompi-core/web';\n\nimport { ReadToolMessage } from './_components/ReadToolMessage';\n\nexport default defineToolRenderer({ message: ReadToolMessage });\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { defineWebPlugin, type WebPluginContributions } from '@agimon-ai/doompi-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/doompi-read",
3
- "version": "0.0.1-alpha.54",
3
+ "version": "0.0.1-alpha.56",
4
4
  "description": "Snapshot-bound hashline read tool for Pi and DoomPi.",
5
5
  "keywords": [
6
6
  "ai",
@@ -62,16 +62,16 @@
62
62
  "access": "public"
63
63
  },
64
64
  "dependencies": {
65
- "@agimon-ai/doompi-config": "0.0.1-alpha.81",
66
- "@agimon-ai/doompi-core": "0.0.1-alpha.82",
67
- "@agimon-ai/doompi-hashline": "0.0.1-alpha.51",
68
- "@agimon-ai/doompi-ui": "0.0.1-alpha.82",
69
- "@agimon-ai/doompi-web-components": "0.0.1-alpha.40",
65
+ "@agimon-ai/doompi-config": "0.0.1-alpha.83",
66
+ "@agimon-ai/doompi-core": "0.0.1-alpha.84",
67
+ "@agimon-ai/doompi-hashline": "0.0.1-alpha.52",
68
+ "@agimon-ai/doompi-ui": "0.0.1-alpha.84",
69
+ "@agimon-ai/doompi-web-components": "0.0.1-alpha.42",
70
70
  "@deepseek-ai/cordis": "4.0.2",
71
71
  "typebox": "1.3.34"
72
72
  },
73
73
  "devDependencies": {
74
- "@agimon-ai/doompi-build": "0.0.1-alpha.11",
74
+ "@agimon-ai/doompi-build": "0.0.1-alpha.12",
75
75
  "@earendil-works/pi-coding-agent": "0.87.1",
76
76
  "@earendil-works/pi-tui": "0.87.1",
77
77
  "@tanstack/react-store": "0.11.1",