@kolisachint/hoocode-agent 0.4.162 → 0.4.163
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +0 -9
- package/dist/cli/args.js.map +1 -1
- package/dist/config.d.ts +0 -40
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -50
- package/dist/config.js.map +1 -1
- package/dist/core/agent-frontmatter.d.ts +0 -28
- package/dist/core/agent-frontmatter.d.ts.map +1 -1
- package/dist/core/agent-frontmatter.js.map +1 -1
- package/dist/core/auth-guidance.d.ts +0 -1
- package/dist/core/auth-guidance.d.ts.map +1 -1
- package/dist/core/auth-guidance.js +1 -1
- package/dist/core/auth-guidance.js.map +1 -1
- package/dist/core/embsearch/chunker.d.ts +0 -2
- package/dist/core/embsearch/chunker.d.ts.map +1 -1
- package/dist/core/embsearch/chunker.js +1 -1
- package/dist/core/embsearch/chunker.js.map +1 -1
- package/dist/core/embsearch/index-meta.d.ts +0 -2
- package/dist/core/embsearch/index-meta.d.ts.map +1 -1
- package/dist/core/embsearch/index-meta.js +0 -6
- package/dist/core/embsearch/index-meta.js.map +1 -1
- package/dist/core/export-html/ansi-to-html.d.ts +0 -4
- package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
- package/dist/core/export-html/ansi-to-html.js +1 -1
- package/dist/core/export-html/ansi-to-html.js.map +1 -1
- package/dist/core/extensions/index.d.ts +3 -3
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/plugins/authoring.d.ts +2 -2
- package/dist/core/extensions/plugins/authoring.d.ts.map +1 -1
- package/dist/core/extensions/plugins/authoring.js +0 -0
- package/dist/core/extensions/plugins/authoring.js.map +1 -1
- package/dist/core/extensions/plugins/formats/index.d.ts +2 -6
- package/dist/core/extensions/plugins/formats/index.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/index.js +2 -3
- package/dist/core/extensions/plugins/formats/index.js.map +1 -1
- package/dist/core/extensions/plugins/formats/shared.d.ts +0 -2
- package/dist/core/extensions/plugins/formats/shared.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/shared.js +1 -1
- package/dist/core/extensions/plugins/formats/shared.js.map +1 -1
- package/dist/core/extensions/plugins/formats/types.d.ts +4 -3
- package/dist/core/extensions/plugins/formats/types.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/types.js.map +1 -1
- package/dist/core/extensions/plugins/install.d.ts +0 -2
- package/dist/core/extensions/plugins/install.d.ts.map +1 -1
- package/dist/core/extensions/plugins/install.js +1 -1
- package/dist/core/extensions/plugins/install.js.map +1 -1
- package/dist/core/extensions/plugins/manifest.d.ts +0 -6
- package/dist/core/extensions/plugins/manifest.d.ts.map +1 -1
- package/dist/core/extensions/plugins/manifest.js +0 -6
- package/dist/core/extensions/plugins/manifest.js.map +1 -1
- package/dist/core/extensions/plugins/marketplace.d.ts +3 -3
- package/dist/core/extensions/plugins/marketplace.d.ts.map +1 -1
- package/dist/core/extensions/plugins/marketplace.js.map +1 -1
- package/dist/core/extensions/types.d.ts +28 -28
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/keybindings.d.ts +3 -3
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-resolver.d.ts +0 -7
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +0 -56
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/package-resource-discovery.d.ts +0 -10
- package/dist/core/package-resource-discovery.d.ts.map +1 -1
- package/dist/core/package-resource-discovery.js +7 -7
- package/dist/core/package-resource-discovery.js.map +1 -1
- package/dist/core/provider-health.d.ts +0 -2
- package/dist/core/provider-health.d.ts.map +1 -1
- package/dist/core/provider-health.js +1 -1
- package/dist/core/provider-health.js.map +1 -1
- package/dist/core/resolve-config-value.d.ts +0 -4
- package/dist/core/resolve-config-value.d.ts.map +1 -1
- package/dist/core/resolve-config-value.js +0 -15
- package/dist/core/resolve-config-value.js.map +1 -1
- package/dist/core/sdk.d.ts +3 -7
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +3 -3
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/search/eval.d.ts +0 -3
- package/dist/core/search/eval.d.ts.map +1 -1
- package/dist/core/search/eval.js +1 -1
- package/dist/core/search/eval.js.map +1 -1
- package/dist/core/search/types.d.ts +2 -1
- package/dist/core/search/types.d.ts.map +1 -1
- package/dist/core/search/types.js.map +1 -1
- package/dist/core/session-cwd.d.ts +0 -1
- package/dist/core/session-cwd.d.ts.map +1 -1
- package/dist/core/session-cwd.js +1 -1
- package/dist/core/session-cwd.js.map +1 -1
- package/dist/core/settings-manager.d.ts +2 -3
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +0 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/settings-types.d.ts +9 -8
- package/dist/core/settings-types.d.ts.map +1 -1
- package/dist/core/settings-types.js.map +1 -1
- package/dist/core/subagent-inbox.d.ts +1 -3
- package/dist/core/subagent-inbox.d.ts.map +1 -1
- package/dist/core/subagent-inbox.js +1 -1
- package/dist/core/subagent-inbox.js.map +1 -1
- package/dist/core/subagent-pool.d.ts +0 -13
- package/dist/core/subagent-pool.d.ts.map +1 -1
- package/dist/core/subagent-pool.js +2 -2
- package/dist/core/subagent-pool.js.map +1 -1
- package/dist/core/task-store.d.ts +3 -3
- package/dist/core/task-store.d.ts.map +1 -1
- package/dist/core/task-store.js.map +1 -1
- package/dist/core/team-auto.d.ts +0 -2
- package/dist/core/team-auto.d.ts.map +1 -1
- package/dist/core/team-auto.js +1 -1
- package/dist/core/team-auto.js.map +1 -1
- package/dist/core/token-budget.d.ts +0 -13
- package/dist/core/token-budget.d.ts.map +1 -1
- package/dist/core/token-budget.js.map +1 -1
- package/dist/core/tools/browser/browser-continue.d.ts +1 -2
- package/dist/core/tools/browser/browser-continue.d.ts.map +1 -1
- package/dist/core/tools/browser/browser-continue.js.map +1 -1
- package/dist/core/tools/browser/browser-run.d.ts +1 -2
- package/dist/core/tools/browser/browser-run.d.ts.map +1 -1
- package/dist/core/tools/browser/browser-run.js.map +1 -1
- package/dist/core/tools/browser/browsertools-shared.d.ts +1 -14
- package/dist/core/tools/browser/browsertools-shared.d.ts.map +1 -1
- package/dist/core/tools/browser/browsertools-shared.js +4 -4
- package/dist/core/tools/browser/browsertools-shared.js.map +1 -1
- package/dist/core/tools/browser/index.d.ts +2 -2
- package/dist/core/tools/browser/index.d.ts.map +1 -1
- package/dist/core/tools/browser/index.js +2 -2
- package/dist/core/tools/browser/index.js.map +1 -1
- package/dist/core/tools/doc/docedit.d.ts +1 -2
- package/dist/core/tools/doc/docedit.d.ts.map +1 -1
- package/dist/core/tools/doc/docedit.js.map +1 -1
- package/dist/core/tools/doc/docgrep.d.ts +1 -2
- package/dist/core/tools/doc/docgrep.d.ts.map +1 -1
- package/dist/core/tools/doc/docgrep.js.map +1 -1
- package/dist/core/tools/doc/docpeek.d.ts +1 -2
- package/dist/core/tools/doc/docpeek.d.ts.map +1 -1
- package/dist/core/tools/doc/docpeek.js.map +1 -1
- package/dist/core/tools/doc/docread.d.ts +1 -2
- package/dist/core/tools/doc/docread.d.ts.map +1 -1
- package/dist/core/tools/doc/docread.js.map +1 -1
- package/dist/core/tools/doc/docscan.d.ts +1 -2
- package/dist/core/tools/doc/docscan.d.ts.map +1 -1
- package/dist/core/tools/doc/docscan.js.map +1 -1
- package/dist/core/tools/doc/docwrite.d.ts +1 -2
- package/dist/core/tools/doc/docwrite.d.ts.map +1 -1
- package/dist/core/tools/doc/docwrite.js.map +1 -1
- package/dist/core/tools/doc/index.d.ts +6 -6
- package/dist/core/tools/doc/index.d.ts.map +1 -1
- package/dist/core/tools/doc/index.js +6 -6
- package/dist/core/tools/doc/index.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts +0 -38
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js +2 -9
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/filetools-shared.d.ts +7 -10
- package/dist/core/tools/filetools-shared.d.ts.map +1 -1
- package/dist/core/tools/filetools-shared.js +2 -2
- package/dist/core/tools/filetools-shared.js.map +1 -1
- package/dist/core/tools/index.d.ts +0 -4
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +0 -7
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/native-search.d.ts +3 -2
- package/dist/core/tools/native-search.d.ts.map +1 -1
- package/dist/core/tools/native-search.js.map +1 -1
- package/dist/core/tools/path-utils.d.ts +0 -10
- package/dist/core/tools/path-utils.d.ts.map +1 -1
- package/dist/core/tools/path-utils.js +2 -2
- package/dist/core/tools/path-utils.js.map +1 -1
- package/dist/core/tools/plugins.d.ts +1 -20
- package/dist/core/tools/plugins.d.ts.map +1 -1
- package/dist/core/tools/plugins.js +2 -2
- package/dist/core/tools/plugins.js.map +1 -1
- package/dist/core/tools/propose-plugin.d.ts +0 -12
- package/dist/core/tools/propose-plugin.d.ts.map +1 -1
- package/dist/core/tools/propose-plugin.js +0 -1
- package/dist/core/tools/propose-plugin.js.map +1 -1
- package/dist/core/tools/read-dedup.d.ts +0 -2
- package/dist/core/tools/read-dedup.d.ts.map +1 -1
- package/dist/core/tools/read-dedup.js +1 -1
- package/dist/core/tools/read-dedup.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts +0 -5
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/search.d.ts +1 -4
- package/dist/core/tools/search.d.ts.map +1 -1
- package/dist/core/tools/search.js +0 -4
- package/dist/core/tools/search.js.map +1 -1
- package/dist/core/tools/webfetch.d.ts +1 -2
- package/dist/core/tools/webfetch.d.ts.map +1 -1
- package/dist/core/tools/webfetch.js.map +1 -1
- package/dist/core/tools/websearch.d.ts +1 -2
- package/dist/core/tools/websearch.d.ts.map +1 -1
- package/dist/core/tools/websearch.js.map +1 -1
- package/dist/core/tools/webtools-shared.d.ts +3 -5
- package/dist/core/tools/webtools-shared.d.ts.map +1 -1
- package/dist/core/tools/webtools-shared.js +1 -1
- package/dist/core/tools/webtools-shared.js.map +1 -1
- package/dist/core/warm-subagent-pool-instance.d.ts +0 -4
- package/dist/core/warm-subagent-pool-instance.d.ts.map +1 -1
- package/dist/core/warm-subagent-pool-instance.js +0 -10
- package/dist/core/warm-subagent-pool-instance.js.map +1 -1
- package/dist/core/wordmark.d.ts +1 -9
- package/dist/core/wordmark.d.ts.map +1 -1
- package/dist/core/wordmark.js +2 -26
- package/dist/core/wordmark.js.map +1 -1
- package/dist/extensions/core/config.d.ts +4 -3
- package/dist/extensions/core/config.d.ts.map +1 -1
- package/dist/extensions/core/config.js.map +1 -1
- package/dist/extensions/core/mcp-loader.d.ts +0 -18
- package/dist/extensions/core/mcp-loader.d.ts.map +1 -1
- package/dist/extensions/core/mcp-loader.js.map +1 -1
- package/dist/extensions/core/prompt-reactive/policy.d.ts +0 -8
- package/dist/extensions/core/prompt-reactive/policy.d.ts.map +1 -1
- package/dist/extensions/core/prompt-reactive/policy.js +1 -1
- package/dist/extensions/core/prompt-reactive/policy.js.map +1 -1
- package/dist/migrations.d.ts +0 -16
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +2 -2
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/brand.d.ts +0 -4
- package/dist/modes/interactive/brand.d.ts.map +1 -1
- package/dist/modes/interactive/brand.js +0 -4
- package/dist/modes/interactive/brand.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +0 -4
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +0 -5
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/read-output.d.ts +0 -9
- package/dist/modes/interactive/components/read-output.d.ts.map +1 -1
- package/dist/modes/interactive/components/read-output.js +0 -20
- package/dist/modes/interactive/components/read-output.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.d.ts +0 -17
- package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.js +2 -2
- package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +4 -13
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/login-controller.d.ts +1 -1
- package/dist/modes/interactive/login-controller.d.ts.map +1 -1
- package/dist/modes/interactive/login-controller.js +1 -1
- package/dist/modes/interactive/login-controller.js.map +1 -1
- package/dist/modes/interactive/resource-display.d.ts +0 -20
- package/dist/modes/interactive/resource-display.d.ts.map +1 -1
- package/dist/modes/interactive/resource-display.js +7 -7
- package/dist/modes/interactive/resource-display.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts +0 -4
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +0 -7
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts +0 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +0 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js +3 -0
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/package-manager-cli.d.ts +0 -1
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/utils/changelog.d.ts +0 -4
- package/dist/utils/changelog.d.ts.map +1 -1
- package/dist/utils/changelog.js +1 -1
- package/dist/utils/changelog.js.map +1 -1
- package/dist/utils/clipboard-native.d.ts +1 -1
- package/dist/utils/clipboard-native.d.ts.map +1 -1
- package/dist/utils/clipboard-native.js.map +1 -1
- package/dist/utils/paths.d.ts +0 -2
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +1 -1
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/plan/parser.d.ts +5 -4
- package/dist/utils/plan/parser.d.ts.map +1 -1
- package/dist/utils/plan/parser.js.map +1 -1
- package/dist/utils/tools-manager.d.ts +0 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +1 -1
- package/dist/utils/tools-manager.js.map +1 -1
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +4 -7
- package/dist/core/index.d.ts +0 -12
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js +0 -12
- package/dist/core/index.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docedit.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/doc/docedit.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAEjE,OAAO,
|
|
1
|
+
{"version":3,"file":"docedit.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/doc/docedit.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAEjE,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAEhE,OAAO,EACN,KAAK,OAAO,EAUZ,MAAM,wBAAwB,CAAC;AAMhC,QAAA,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;EAKjB,CAAC;AAIH,MAAM,WAAW,kBAAkB;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IAClC,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAYD,wBAAgB,2BAA2B,CAC1C,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,kBAAkB,GAC1B,cAAc,CAAC,OAAO,aAAa,EAAE,kBAAkB,GAAG,SAAS,CAAC,CAmGtE;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC,OAAO,aAAa,CAAC,CAE5G","sourcesContent":["import { mkdtempSync, renameSync, rmSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { basename, join } from \"node:path\";\nimport type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Container, Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { APP_NAME } from \"../../../config.js\";\nimport { theme as appTheme } from \"../../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition } from \"../../extensions/types.js\";\nimport { withFileMutationQueue } from \"../file-mutation-queue.js\";\nimport {\n\ttype DocNode,\n\tensureExtractRecord,\n\textractDocument,\n\tfindNodeById,\n\tinvalidateExtractRecord,\n\tpatchOpNodeId,\n\tpatchOpsSchema,\n\treconstructDocument,\n\tStalePatchError,\n\ttoPatch,\n} from \"../filetools-shared.js\";\nimport { resolveReadPath } from \"../path-utils.js\";\nimport { invalidArgText, shortenPath, str } from \"../render-utils.js\";\nimport { wrapToolDefinition } from \"../tool-definition-wrapper.js\";\nimport { renderEnvelopeText } from \"./docread.js\";\n\nconst docEditSchema = Type.Object({\n\tpath: Type.String({\n\t\tdescription: \"Path to the document to edit in place. Must have been opened with DocRead first.\",\n\t}),\n\tpatch: patchOpsSchema,\n});\n\ntype DocEditToolInput = Static<typeof docEditSchema>;\n\nexport interface DocEditToolDetails {\n\tops?: number;\n\taffected?: DocNode[];\n}\n\nexport interface DocEditToolOptions {\n\t/** Timeout (seconds) for the filetools invocations. */\n\ttimeoutSecs?: number;\n}\n\nfunction formatDocEditCall(args: { path?: string; patch?: unknown[] } | undefined): string {\n\tconst path = str(args?.path);\n\tconst pathDisplay =\n\t\tpath === null ? invalidArgText(appTheme) : path ? shortenPath(path) : appTheme.fg(\"toolOutput\", \"...\");\n\tlet text = appTheme.fg(\"toolTitle\", appTheme.bold(\"DocEdit \")) + appTheme.fg(\"accent\", pathDisplay);\n\tconst ops = Array.isArray(args?.patch) ? args.patch.length : undefined;\n\tif (ops !== undefined) text += appTheme.fg(\"muted\", ` (${ops} op${ops === 1 ? \"\" : \"s\"})`);\n\treturn text;\n}\n\nexport function createDocEditToolDefinition(\n\tcwd: string,\n\toptions?: DocEditToolOptions,\n): ToolDefinition<typeof docEditSchema, DocEditToolDetails | undefined> {\n\treturn {\n\t\tname: \"DocEdit\",\n\t\tlabel: \"DocEdit\",\n\t\tdescription:\n\t\t\t\"Apply an id-based patch to a structured/binary document IN PLACE, losslessly. Targets node ids from a DocRead extract; if the cache is missing or the file changed on disk (e.g. an external script rewrote it) the document is re-extracted automatically, so a separate DocRead is not required. If the patch references ids that no longer exist, the call fails and returns the current structure with fresh ids so you can re-issue. Untouched bytes are preserved exactly; the file is re-extracted after the write so ids stay current for further edits. This is the canonical way to edit these formats: never fall back to ad-hoc scripts (python/openpyxl, docx, PyPDF2, unzip, sed) to rewrite them — that bypasses the lossless id-map and corrupts the file. Off by default; enabled with --enable-filetools.\",\n\t\tpromptSnippet: \"Patch a structured/binary document in place by node id\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use DocEdit to modify a document opened with DocRead; pass a patch of id-based ops (replace/add/remove) targeting the #ids from the extract. It edits in place and re-extracts.\",\n\t\t\t\"Keep patches minimal — only the ops you actually need. DocEdit re-extracts after writing and refreshes ids, so do not DocRead again between edits; the full extract is token-heavy. Reach for a fresh writable DocRead only when ids have gone stale and the failure output isn't enough to continue.\",\n\t\t],\n\t\tparameters: docEditSchema,\n\t\tasync execute(_toolCallId, { path, patch }: DocEditToolInput, signal?: AbortSignal) {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\n\t\t\treturn withFileMutationQueue(absolutePath, async () => {\n\t\t\t\t// Resolve affected nodes from the pre-reconstruct extract: the patch's\n\t\t\t\t// ids are valid against THIS extract, and a later re-extract\n\t\t\t\t// regenerates ids that would not match the patch. reconstructDocument\n\t\t\t\t// auto-extracts when the cache is missing/stale, so capture the record\n\t\t\t\t// the same way to stay in sync with what the patch is applied against.\n\t\t\t\tconst preRecord = await ensureExtractRecord(absolutePath, cwd, signal, {\n\t\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t\t});\n\t\t\t\tconst affectedIds = new Set<string>();\n\t\t\t\tfor (const op of toPatch(patch).patch) {\n\t\t\t\t\tconst id = patchOpNodeId(op);\n\t\t\t\t\tif (id) affectedIds.add(id);\n\t\t\t\t}\n\t\t\t\tconst affectedNodes: DocNode[] = [];\n\t\t\t\tfor (const id of affectedIds) {\n\t\t\t\t\tconst node = findNodeById(preRecord.envelope.structure, id);\n\t\t\t\t\tif (node) affectedNodes.push(node);\n\t\t\t\t}\n\n\t\t\t\t// Reconstruct to a temp file, then atomically swap it into place so a\n\t\t\t\t// failed reconstruct never leaves a half-written document behind.\n\t\t\t\tconst stageDir = mkdtempSync(join(tmpdir(), `${APP_NAME}-docedit-`));\n\t\t\t\tconst stagePath = join(stageDir, basename(absolutePath));\n\t\t\t\ttry {\n\t\t\t\t\tawait reconstructDocument(absolutePath, toPatch(patch), stagePath, cwd, signal, {\n\t\t\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t\t\t});\n\t\t\t\t\trenameSync(stagePath, absolutePath);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tif (err instanceof StalePatchError) {\n\t\t\t\t\t\t// The document was rewritten out-of-band: the cache auto-refreshed\n\t\t\t\t\t\t// but the patch targets ids that no longer exist. Surface the\n\t\t\t\t\t\t// current structure so the agent can re-issue without a DocRead.\n\t\t\t\t\t\tthrow new Error(`${err.message}\\n\\n${renderEnvelopeText(err.envelope, false)}`);\n\t\t\t\t\t}\n\t\t\t\t\tthrow err;\n\t\t\t\t} finally {\n\t\t\t\t\trmSync(stageDir, { recursive: true, force: true });\n\t\t\t\t}\n\n\t\t\t\t// The source changed, so the cached id-map is stale. Re-extract to\n\t\t\t\t// refresh ids for subsequent edits (best-effort; a failure here does\n\t\t\t\t// not undo the successful write).\n\t\t\t\tinvalidateExtractRecord(absolutePath);\n\t\t\t\ttry {\n\t\t\t\t\tawait extractDocument(absolutePath, cwd, signal, { timeoutSecs: options?.timeoutSecs });\n\t\t\t\t} catch {\n\t\t\t\t\t// Re-extract failure leaves no cached record; the next DocEdit will\n\t\t\t\t\t// auto-extract (or fall back to DocRead), which is the correct path.\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext: `Applied ${patch.length} op${patch.length === 1 ? \"\" : \"s\"} to ${path} (re-extracted; ids refreshed).`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { ops: patch.length, affected: affectedNodes.length > 0 ? affectedNodes : undefined },\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDocEditCall(args));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, _options, _theme, context) {\n\t\t\tif (!context.isError) {\n\t\t\t\tconst component = (context.lastComponent as Container | undefined) ?? new Container();\n\t\t\t\tcomponent.clear();\n\t\t\t\treturn component;\n\t\t\t}\n\t\t\tconst output = (result.content as Array<{ type: string; text?: string }>)\n\t\t\t\t.filter((c) => c.type === \"text\")\n\t\t\t\t.map((c) => c.text || \"\")\n\t\t\t\t.join(\"\\n\");\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(output ? `\\n${appTheme.fg(\"error\", output)}` : \"\");\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDocEditTool(cwd: string, options?: DocEditToolOptions): AgentTool<typeof docEditSchema> {\n\treturn wrapToolDefinition(createDocEditToolDefinition(cwd, options));\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docedit.js","sourceRoot":"","sources":["../../../../src/core/tools/doc/docedit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,KAAK,IAAI,QAAQ,EAAE,MAAM,2CAA2C,CAAC;AAE9E,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAEN,mBAAmB,EACnB,eAAe,EACf,YAAY,EACZ,uBAAuB,EACvB,aAAa,EACb,cAAc,EACd,mBAAmB,EACnB,eAAe,EACf,OAAO,GACP,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElD,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC;IACjC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC;QACjB,WAAW,EAAE,kFAAkF;KAC/F,CAAC;IACF,KAAK,EAAE,cAAc;CACrB,CAAC,CAAC;AAcH,SAAS,iBAAiB,CAAC,IAAsD,EAAU;IAC1F,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC7B,MAAM,WAAW,GAChB,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IACxG,IAAI,IAAI,GAAG,QAAQ,CAAC,EAAE,CAAC,WAAW,EAAE,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IACpG,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IACvE,IAAI,GAAG,KAAK,SAAS;QAAE,IAAI,IAAI,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;IAC3F,OAAO,IAAI,CAAC;AAAA,CACZ;AAED,MAAM,UAAU,2BAA2B,CAC1C,GAAW,EACX,OAA4B,EAC2C;IACvE,OAAO;QACN,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,SAAS;QAChB,WAAW,EACV,+xBAA6xB;QAC9xB,aAAa,EAAE,wDAAwD;QACvE,gBAAgB,EAAE;YACjB,iLAAiL;YACjL,ySAAuS;SACvS;QACD,UAAU,EAAE,aAAa;QACzB,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,KAAK,EAAoB,EAAE,MAAoB,EAAE;YACnF,IAAI,MAAM,EAAE,OAAO;gBAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;YAC1D,MAAM,YAAY,GAAG,eAAe,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YAEhD,OAAO,qBAAqB,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE,CAAC;gBACtD,uEAAuE;gBACvE,6DAA6D;gBAC7D,sEAAsE;gBACtE,uEAAuE;gBACvE,uEAAuE;gBACvE,MAAM,SAAS,GAAG,MAAM,mBAAmB,CAAC,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE;oBACtE,WAAW,EAAE,OAAO,EAAE,WAAW;iBACjC,CAAC,CAAC;gBACH,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU,CAAC;gBACtC,KAAK,MAAM,EAAE,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC;oBACvC,MAAM,EAAE,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC;oBAC7B,IAAI,EAAE;wBAAE,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC7B,CAAC;gBACD,MAAM,aAAa,GAAc,EAAE,CAAC;gBACpC,KAAK,MAAM,EAAE,IAAI,WAAW,EAAE,CAAC;oBAC9B,MAAM,IAAI,GAAG,YAAY,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;oBAC5D,IAAI,IAAI;wBAAE,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACpC,CAAC;gBAED,sEAAsE;gBACtE,kEAAkE;gBAClE,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,GAAG,QAAQ,WAAW,CAAC,CAAC,CAAC;gBACrE,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;gBACzD,IAAI,CAAC;oBACJ,MAAM,mBAAmB,CAAC,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE;wBAC/E,WAAW,EAAE,OAAO,EAAE,WAAW;qBACjC,CAAC,CAAC;oBACH,UAAU,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;gBACrC,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACd,IAAI,GAAG,YAAY,eAAe,EAAE,CAAC;wBACpC,mEAAmE;wBACnE,8DAA8D;wBAC9D,iEAAiE;wBACjE,MAAM,IAAI,KAAK,CAAC,GAAG,GAAG,CAAC,OAAO,OAAO,kBAAkB,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;oBACjF,CAAC;oBACD,MAAM,GAAG,CAAC;gBACX,CAAC;wBAAS,CAAC;oBACV,MAAM,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBACpD,CAAC;gBAED,mEAAmE;gBACnE,qEAAqE;gBACrE,kCAAkC;gBAClC,uBAAuB,CAAC,YAAY,CAAC,CAAC;gBACtC,IAAI,CAAC;oBACJ,MAAM,eAAe,CAAC,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;gBACzF,CAAC;gBAAC,MAAM,CAAC;oBACR,oEAAoE;oBACpE,qEAAqE;gBACtE,CAAC;gBAED,OAAO;oBACN,OAAO,EAAE;wBACR;4BACC,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,WAAW,KAAK,CAAC,MAAM,MAAM,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,iCAAiC;yBAC5G;qBACD;oBACD,OAAO,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,EAAE;iBAC9F,CAAC;YAAA,CACF,CAAC,CAAC;QAAA,CACH;QACD,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE;YACjC,MAAM,IAAI,GAAI,OAAO,CAAC,aAAkC,IAAI,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YAC/E,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC;YACtC,OAAO,IAAI,CAAC;QAAA,CACZ;QACD,YAAY,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE;YAC/C,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;gBACtB,MAAM,SAAS,GAAI,OAAO,CAAC,aAAuC,IAAI,IAAI,SAAS,EAAE,CAAC;gBACtF,SAAS,CAAC,KAAK,EAAE,CAAC;gBAClB,OAAO,SAAS,CAAC;YAClB,CAAC;YACD,MAAM,MAAM,GAAI,MAAM,CAAC,OAAkD;iBACvE,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;iBAChC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;iBACxB,IAAI,CAAC,IAAI,CAAC,CAAC;YACb,MAAM,IAAI,GAAI,OAAO,CAAC,aAAkC,IAAI,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YAC/E,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAChE,OAAO,IAAI,CAAC;QAAA,CACZ;KACD,CAAC;AAAA,CACF;AAED,MAAM,UAAU,iBAAiB,CAAC,GAAW,EAAE,OAA4B,EAAmC;IAC7G,OAAO,kBAAkB,CAAC,2BAA2B,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;AAAA,CACrE","sourcesContent":["import { mkdtempSync, renameSync, rmSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { basename, join } from \"node:path\";\nimport type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Container, Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { APP_NAME } from \"../../../config.js\";\nimport { theme as appTheme } from \"../../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition } from \"../../extensions/types.js\";\nimport { withFileMutationQueue } from \"../file-mutation-queue.js\";\nimport {\n\ttype DocNode,\n\tensureExtractRecord,\n\textractDocument,\n\tfindNodeById,\n\tinvalidateExtractRecord,\n\tpatchOpNodeId,\n\tpatchOpsSchema,\n\treconstructDocument,\n\tStalePatchError,\n\ttoPatch,\n} from \"../filetools-shared.js\";\nimport { resolveReadPath } from \"../path-utils.js\";\nimport { invalidArgText, shortenPath, str } from \"../render-utils.js\";\nimport { wrapToolDefinition } from \"../tool-definition-wrapper.js\";\nimport { renderEnvelopeText } from \"./docread.js\";\n\nconst docEditSchema = Type.Object({\n\tpath: Type.String({\n\t\tdescription: \"Path to the document to edit in place. Must have been opened with DocRead first.\",\n\t}),\n\tpatch: patchOpsSchema,\n});\n\nexport type DocEditToolInput = Static<typeof docEditSchema>;\n\nexport interface DocEditToolDetails {\n\tops?: number;\n\taffected?: DocNode[];\n}\n\nexport interface DocEditToolOptions {\n\t/** Timeout (seconds) for the filetools invocations. */\n\ttimeoutSecs?: number;\n}\n\nfunction formatDocEditCall(args: { path?: string; patch?: unknown[] } | undefined): string {\n\tconst path = str(args?.path);\n\tconst pathDisplay =\n\t\tpath === null ? invalidArgText(appTheme) : path ? shortenPath(path) : appTheme.fg(\"toolOutput\", \"...\");\n\tlet text = appTheme.fg(\"toolTitle\", appTheme.bold(\"DocEdit \")) + appTheme.fg(\"accent\", pathDisplay);\n\tconst ops = Array.isArray(args?.patch) ? args.patch.length : undefined;\n\tif (ops !== undefined) text += appTheme.fg(\"muted\", ` (${ops} op${ops === 1 ? \"\" : \"s\"})`);\n\treturn text;\n}\n\nexport function createDocEditToolDefinition(\n\tcwd: string,\n\toptions?: DocEditToolOptions,\n): ToolDefinition<typeof docEditSchema, DocEditToolDetails | undefined> {\n\treturn {\n\t\tname: \"DocEdit\",\n\t\tlabel: \"DocEdit\",\n\t\tdescription:\n\t\t\t\"Apply an id-based patch to a structured/binary document IN PLACE, losslessly. Targets node ids from a DocRead extract; if the cache is missing or the file changed on disk (e.g. an external script rewrote it) the document is re-extracted automatically, so a separate DocRead is not required. If the patch references ids that no longer exist, the call fails and returns the current structure with fresh ids so you can re-issue. Untouched bytes are preserved exactly; the file is re-extracted after the write so ids stay current for further edits. This is the canonical way to edit these formats: never fall back to ad-hoc scripts (python/openpyxl, docx, PyPDF2, unzip, sed) to rewrite them — that bypasses the lossless id-map and corrupts the file. Off by default; enabled with --enable-filetools.\",\n\t\tpromptSnippet: \"Patch a structured/binary document in place by node id\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use DocEdit to modify a document opened with DocRead; pass a patch of id-based ops (replace/add/remove) targeting the #ids from the extract. It edits in place and re-extracts.\",\n\t\t\t\"Keep patches minimal — only the ops you actually need. DocEdit re-extracts after writing and refreshes ids, so do not DocRead again between edits; the full extract is token-heavy. Reach for a fresh writable DocRead only when ids have gone stale and the failure output isn't enough to continue.\",\n\t\t],\n\t\tparameters: docEditSchema,\n\t\tasync execute(_toolCallId, { path, patch }: DocEditToolInput, signal?: AbortSignal) {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\n\t\t\treturn withFileMutationQueue(absolutePath, async () => {\n\t\t\t\t// Resolve affected nodes from the pre-reconstruct extract: the patch's\n\t\t\t\t// ids are valid against THIS extract, and a later re-extract\n\t\t\t\t// regenerates ids that would not match the patch. reconstructDocument\n\t\t\t\t// auto-extracts when the cache is missing/stale, so capture the record\n\t\t\t\t// the same way to stay in sync with what the patch is applied against.\n\t\t\t\tconst preRecord = await ensureExtractRecord(absolutePath, cwd, signal, {\n\t\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t\t});\n\t\t\t\tconst affectedIds = new Set<string>();\n\t\t\t\tfor (const op of toPatch(patch).patch) {\n\t\t\t\t\tconst id = patchOpNodeId(op);\n\t\t\t\t\tif (id) affectedIds.add(id);\n\t\t\t\t}\n\t\t\t\tconst affectedNodes: DocNode[] = [];\n\t\t\t\tfor (const id of affectedIds) {\n\t\t\t\t\tconst node = findNodeById(preRecord.envelope.structure, id);\n\t\t\t\t\tif (node) affectedNodes.push(node);\n\t\t\t\t}\n\n\t\t\t\t// Reconstruct to a temp file, then atomically swap it into place so a\n\t\t\t\t// failed reconstruct never leaves a half-written document behind.\n\t\t\t\tconst stageDir = mkdtempSync(join(tmpdir(), `${APP_NAME}-docedit-`));\n\t\t\t\tconst stagePath = join(stageDir, basename(absolutePath));\n\t\t\t\ttry {\n\t\t\t\t\tawait reconstructDocument(absolutePath, toPatch(patch), stagePath, cwd, signal, {\n\t\t\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t\t\t});\n\t\t\t\t\trenameSync(stagePath, absolutePath);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tif (err instanceof StalePatchError) {\n\t\t\t\t\t\t// The document was rewritten out-of-band: the cache auto-refreshed\n\t\t\t\t\t\t// but the patch targets ids that no longer exist. Surface the\n\t\t\t\t\t\t// current structure so the agent can re-issue without a DocRead.\n\t\t\t\t\t\tthrow new Error(`${err.message}\\n\\n${renderEnvelopeText(err.envelope, false)}`);\n\t\t\t\t\t}\n\t\t\t\t\tthrow err;\n\t\t\t\t} finally {\n\t\t\t\t\trmSync(stageDir, { recursive: true, force: true });\n\t\t\t\t}\n\n\t\t\t\t// The source changed, so the cached id-map is stale. Re-extract to\n\t\t\t\t// refresh ids for subsequent edits (best-effort; a failure here does\n\t\t\t\t// not undo the successful write).\n\t\t\t\tinvalidateExtractRecord(absolutePath);\n\t\t\t\ttry {\n\t\t\t\t\tawait extractDocument(absolutePath, cwd, signal, { timeoutSecs: options?.timeoutSecs });\n\t\t\t\t} catch {\n\t\t\t\t\t// Re-extract failure leaves no cached record; the next DocEdit will\n\t\t\t\t\t// auto-extract (or fall back to DocRead), which is the correct path.\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext: `Applied ${patch.length} op${patch.length === 1 ? \"\" : \"s\"} to ${path} (re-extracted; ids refreshed).`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { ops: patch.length, affected: affectedNodes.length > 0 ? affectedNodes : undefined },\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDocEditCall(args));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, _options, _theme, context) {\n\t\t\tif (!context.isError) {\n\t\t\t\tconst component = (context.lastComponent as Container | undefined) ?? new Container();\n\t\t\t\tcomponent.clear();\n\t\t\t\treturn component;\n\t\t\t}\n\t\t\tconst output = (result.content as Array<{ type: string; text?: string }>)\n\t\t\t\t.filter((c) => c.type === \"text\")\n\t\t\t\t.map((c) => c.text || \"\")\n\t\t\t\t.join(\"\\n\");\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(output ? `\\n${appTheme.fg(\"error\", output)}` : \"\");\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDocEditTool(cwd: string, options?: DocEditToolOptions): AgentTool<typeof docEditSchema> {\n\treturn wrapToolDefinition(createDocEditToolDefinition(cwd, options));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"docedit.js","sourceRoot":"","sources":["../../../../src/core/tools/doc/docedit.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdtempSync, renameSync, rmSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { basename, join } from \"node:path\";\nimport type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Container, Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { APP_NAME } from \"../../../config.js\";\nimport { theme as appTheme } from \"../../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition } from \"../../extensions/types.js\";\nimport { withFileMutationQueue } from \"../file-mutation-queue.js\";\nimport {\n\ttype DocNode,\n\tensureExtractRecord,\n\textractDocument,\n\tfindNodeById,\n\tinvalidateExtractRecord,\n\tpatchOpNodeId,\n\tpatchOpsSchema,\n\treconstructDocument,\n\tStalePatchError,\n\ttoPatch,\n} from \"../filetools-shared.js\";\nimport { resolveReadPath } from \"../path-utils.js\";\nimport { invalidArgText, shortenPath, str } from \"../render-utils.js\";\nimport { wrapToolDefinition } from \"../tool-definition-wrapper.js\";\nimport { renderEnvelopeText } from \"./docread.js\";\n\nconst docEditSchema = Type.Object({\n\tpath: Type.String({\n\t\tdescription: \"Path to the document to edit in place. Must have been opened with DocRead first.\",\n\t}),\n\tpatch: patchOpsSchema,\n});\n\ntype DocEditToolInput = Static<typeof docEditSchema>;\n\nexport interface DocEditToolDetails {\n\tops?: number;\n\taffected?: DocNode[];\n}\n\nexport interface DocEditToolOptions {\n\t/** Timeout (seconds) for the filetools invocations. */\n\ttimeoutSecs?: number;\n}\n\nfunction formatDocEditCall(args: { path?: string; patch?: unknown[] } | undefined): string {\n\tconst path = str(args?.path);\n\tconst pathDisplay =\n\t\tpath === null ? invalidArgText(appTheme) : path ? shortenPath(path) : appTheme.fg(\"toolOutput\", \"...\");\n\tlet text = appTheme.fg(\"toolTitle\", appTheme.bold(\"DocEdit \")) + appTheme.fg(\"accent\", pathDisplay);\n\tconst ops = Array.isArray(args?.patch) ? args.patch.length : undefined;\n\tif (ops !== undefined) text += appTheme.fg(\"muted\", ` (${ops} op${ops === 1 ? \"\" : \"s\"})`);\n\treturn text;\n}\n\nexport function createDocEditToolDefinition(\n\tcwd: string,\n\toptions?: DocEditToolOptions,\n): ToolDefinition<typeof docEditSchema, DocEditToolDetails | undefined> {\n\treturn {\n\t\tname: \"DocEdit\",\n\t\tlabel: \"DocEdit\",\n\t\tdescription:\n\t\t\t\"Apply an id-based patch to a structured/binary document IN PLACE, losslessly. Targets node ids from a DocRead extract; if the cache is missing or the file changed on disk (e.g. an external script rewrote it) the document is re-extracted automatically, so a separate DocRead is not required. If the patch references ids that no longer exist, the call fails and returns the current structure with fresh ids so you can re-issue. Untouched bytes are preserved exactly; the file is re-extracted after the write so ids stay current for further edits. This is the canonical way to edit these formats: never fall back to ad-hoc scripts (python/openpyxl, docx, PyPDF2, unzip, sed) to rewrite them — that bypasses the lossless id-map and corrupts the file. Off by default; enabled with --enable-filetools.\",\n\t\tpromptSnippet: \"Patch a structured/binary document in place by node id\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use DocEdit to modify a document opened with DocRead; pass a patch of id-based ops (replace/add/remove) targeting the #ids from the extract. It edits in place and re-extracts.\",\n\t\t\t\"Keep patches minimal — only the ops you actually need. DocEdit re-extracts after writing and refreshes ids, so do not DocRead again between edits; the full extract is token-heavy. Reach for a fresh writable DocRead only when ids have gone stale and the failure output isn't enough to continue.\",\n\t\t],\n\t\tparameters: docEditSchema,\n\t\tasync execute(_toolCallId, { path, patch }: DocEditToolInput, signal?: AbortSignal) {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\n\t\t\treturn withFileMutationQueue(absolutePath, async () => {\n\t\t\t\t// Resolve affected nodes from the pre-reconstruct extract: the patch's\n\t\t\t\t// ids are valid against THIS extract, and a later re-extract\n\t\t\t\t// regenerates ids that would not match the patch. reconstructDocument\n\t\t\t\t// auto-extracts when the cache is missing/stale, so capture the record\n\t\t\t\t// the same way to stay in sync with what the patch is applied against.\n\t\t\t\tconst preRecord = await ensureExtractRecord(absolutePath, cwd, signal, {\n\t\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t\t});\n\t\t\t\tconst affectedIds = new Set<string>();\n\t\t\t\tfor (const op of toPatch(patch).patch) {\n\t\t\t\t\tconst id = patchOpNodeId(op);\n\t\t\t\t\tif (id) affectedIds.add(id);\n\t\t\t\t}\n\t\t\t\tconst affectedNodes: DocNode[] = [];\n\t\t\t\tfor (const id of affectedIds) {\n\t\t\t\t\tconst node = findNodeById(preRecord.envelope.structure, id);\n\t\t\t\t\tif (node) affectedNodes.push(node);\n\t\t\t\t}\n\n\t\t\t\t// Reconstruct to a temp file, then atomically swap it into place so a\n\t\t\t\t// failed reconstruct never leaves a half-written document behind.\n\t\t\t\tconst stageDir = mkdtempSync(join(tmpdir(), `${APP_NAME}-docedit-`));\n\t\t\t\tconst stagePath = join(stageDir, basename(absolutePath));\n\t\t\t\ttry {\n\t\t\t\t\tawait reconstructDocument(absolutePath, toPatch(patch), stagePath, cwd, signal, {\n\t\t\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t\t\t});\n\t\t\t\t\trenameSync(stagePath, absolutePath);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tif (err instanceof StalePatchError) {\n\t\t\t\t\t\t// The document was rewritten out-of-band: the cache auto-refreshed\n\t\t\t\t\t\t// but the patch targets ids that no longer exist. Surface the\n\t\t\t\t\t\t// current structure so the agent can re-issue without a DocRead.\n\t\t\t\t\t\tthrow new Error(`${err.message}\\n\\n${renderEnvelopeText(err.envelope, false)}`);\n\t\t\t\t\t}\n\t\t\t\t\tthrow err;\n\t\t\t\t} finally {\n\t\t\t\t\trmSync(stageDir, { recursive: true, force: true });\n\t\t\t\t}\n\n\t\t\t\t// The source changed, so the cached id-map is stale. Re-extract to\n\t\t\t\t// refresh ids for subsequent edits (best-effort; a failure here does\n\t\t\t\t// not undo the successful write).\n\t\t\t\tinvalidateExtractRecord(absolutePath);\n\t\t\t\ttry {\n\t\t\t\t\tawait extractDocument(absolutePath, cwd, signal, { timeoutSecs: options?.timeoutSecs });\n\t\t\t\t} catch {\n\t\t\t\t\t// Re-extract failure leaves no cached record; the next DocEdit will\n\t\t\t\t\t// auto-extract (or fall back to DocRead), which is the correct path.\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext: `Applied ${patch.length} op${patch.length === 1 ? \"\" : \"s\"} to ${path} (re-extracted; ids refreshed).`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { ops: patch.length, affected: affectedNodes.length > 0 ? affectedNodes : undefined },\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDocEditCall(args));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, _options, _theme, context) {\n\t\t\tif (!context.isError) {\n\t\t\t\tconst component = (context.lastComponent as Container | undefined) ?? new Container();\n\t\t\t\tcomponent.clear();\n\t\t\t\treturn component;\n\t\t\t}\n\t\t\tconst output = (result.content as Array<{ type: string; text?: string }>)\n\t\t\t\t.filter((c) => c.type === \"text\")\n\t\t\t\t.map((c) => c.text || \"\")\n\t\t\t\t.join(\"\\n\");\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(output ? `\\n${appTheme.fg(\"error\", output)}` : \"\");\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDocEditTool(cwd: string, options?: DocEditToolOptions): AgentTool<typeof docEditSchema> {\n\treturn wrapToolDefinition(createDocEditToolDefinition(cwd, options));\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AgentTool } from "@kolisachint/hoocode-agent-core";
|
|
2
|
-
import {
|
|
2
|
+
import { Type } from "typebox";
|
|
3
3
|
import type { ToolDefinition } from "../../extensions/types.js";
|
|
4
4
|
import { type GrepView } from "../filetools-shared.js";
|
|
5
5
|
declare const docGrepSchema: Type.TObject<{
|
|
@@ -8,7 +8,6 @@ declare const docGrepSchema: Type.TObject<{
|
|
|
8
8
|
ignoreCase: Type.TOptional<Type.TBoolean>;
|
|
9
9
|
limit: Type.TOptional<Type.TNumber>;
|
|
10
10
|
}>;
|
|
11
|
-
export type DocGrepToolInput = Static<typeof docGrepSchema>;
|
|
12
11
|
export interface DocGrepToolDetails {
|
|
13
12
|
pattern?: string;
|
|
14
13
|
matches?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docgrep.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/doc/docgrep.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAEjE,OAAO,
|
|
1
|
+
{"version":3,"file":"docgrep.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/doc/docgrep.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAEjE,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,2BAA2B,CAAC;AACzF,OAAO,EAAE,KAAK,QAAQ,EAA6C,MAAM,wBAAwB,CAAC;AAKlG,QAAA,MAAM,aAAa;;;;;EAUjB,CAAC;AAIH,MAAM,WAAW,kBAAkB;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IAClC,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAcrD;AAgCD,wBAAgB,2BAA2B,CAC1C,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,kBAAkB,GAC1B,cAAc,CAAC,OAAO,aAAa,EAAE,kBAAkB,GAAG,SAAS,CAAC,CAsCtE;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC,OAAO,aAAa,CAAC,CAE5G","sourcesContent":["import type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../../modes/interactive/components/keybinding-hints.js\";\nimport { theme as appTheme } from \"../../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../../extensions/types.js\";\nimport { type GrepView, grepDocument, truncateRenderToTokenBudget } from \"../filetools-shared.js\";\nimport { resolveReadPath } from \"../path-utils.js\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"../render-utils.js\";\nimport { wrapToolDefinition } from \"../tool-definition-wrapper.js\";\n\nconst docGrepSchema = Type.Object({\n\tpath: Type.String({\n\t\tdescription:\n\t\t\t\"Path to the document to search (relative or absolute). XML, drawio, OOXML (docx/xlsx/pptx), or PDF.\",\n\t}),\n\tpattern: Type.String({\n\t\tdescription: \"Literal substring to match per line (NOT a regex).\",\n\t}),\n\tignoreCase: Type.Optional(Type.Boolean({ description: \"Case-insensitive matching. Default false.\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Stop after N matches. Default: all matches.\" })),\n});\n\ntype DocGrepToolInput = Static<typeof docGrepSchema>;\n\nexport interface DocGrepToolDetails {\n\tpattern?: string;\n\tmatches?: number;\n}\n\nexport interface DocGrepToolOptions {\n\t/** Timeout (seconds) for the filetools invocation. */\n\ttimeoutSecs?: number;\n}\n\n/**\n * Render grep matches as `#block_id:line :: \"snippet\"` lines. Each block id\n * feeds straight back into DocPeek (to hydrate) or a DocEdit patch.\n */\nexport function renderGrepView(view: GrepView): string {\n\tconst header = `grep ${JSON.stringify(view.pattern)} — ${view.returned} match${view.returned === 1 ? \"\" : \"es\"}`;\n\tif (view.matches.length === 0) return header;\n\tconst lines: string[] = [header, \"\"];\n\tfor (const m of view.matches) {\n\t\tconst flag = m.writable ? \"\" : \" (read-only)\";\n\t\tlines.push(`#${m.block_id}:${m.line}${flag} :: ${JSON.stringify(m.snippet)}`);\n\t}\n\tconst { text, droppedLines } = truncateRenderToTokenBudget(lines);\n\tif (droppedLines === 0) return text;\n\treturn (\n\t\t`${text}\\n\\n[Truncated: ${droppedLines} more match line${droppedLines === 1 ? \"\" : \"s\"} omitted; ` +\n\t\t`re-run with a smaller limit or a more specific pattern.]`\n\t);\n}\n\nfunction formatDocGrepCall(args: { path?: string; pattern?: string; ignoreCase?: boolean } | undefined): string {\n\tconst path = str(args?.path);\n\tconst pathDisplay =\n\t\tpath === null ? invalidArgText(appTheme) : path ? shortenPath(path) : appTheme.fg(\"toolOutput\", \"...\");\n\tlet text = appTheme.fg(\"toolTitle\", appTheme.bold(\"DocGrep \"));\n\tconst pattern = str(args?.pattern);\n\tif (pattern) text += `${appTheme.fg(\"accent\", JSON.stringify(pattern))} ${appTheme.fg(\"muted\", \"in\")} `;\n\ttext += appTheme.fg(\"accent\", pathDisplay);\n\tif (args?.ignoreCase) text += appTheme.fg(\"muted\", \" (i)\");\n\treturn text;\n}\n\nfunction formatDocGrepResult(\n\tresult: { content: Array<{ type: string; text?: string }> },\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result as any, showImages).trim();\n\tif (!output) return \"\";\n\tconst lines = output.split(\"\\n\");\n\tconst maxLines = options.expanded ? lines.length : 15;\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\tlet text = `\\n${displayLines.map((line) => appTheme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\tif (remaining > 0) {\n\t\ttext += `${appTheme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t}\n\treturn text;\n}\n\nexport function createDocGrepToolDefinition(\n\tcwd: string,\n\toptions?: DocGrepToolOptions,\n): ToolDefinition<typeof docGrepSchema, DocGrepToolDetails | undefined> {\n\treturn {\n\t\tname: \"DocGrep\",\n\t\tlabel: \"DocGrep\",\n\t\tdescription:\n\t\t\t\"Locate blocks in a structured/binary document (XML, drawio, docx/xlsx/pptx, PDF) by literal text, WITHOUT hydrating the whole document. Returns each match as an editable el_ node #id, line number, and snippet. Those el_ #ids target a DocEdit/DocWrite patch directly — DocGrep is the fast path from 'find text' to 'edit it' (far cheaper than a full DocRead). Off by default; enabled with --enable-filetools.\",\n\t\tpromptSnippet: \"Find blocks in a structured/binary document by literal text, without hydrating it\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use DocGrep to find where something is in a large structured/binary document instead of reading it all: it returns editable el_ node #ids + snippets for a literal substring match. Patch those el_ #ids straight with DocEdit/DocWrite.\",\n\t\t\t\"DocGrep's el_ #ids are the edit id-space; they are NOT DocPeek's structural-path ids. To read more context around a match, DocScan/DocPeek by structural path instead.\",\n\t\t\t\"pattern is a literal substring (not a regex); pass ignoreCase for case-insensitive matching.\",\n\t\t\t\"Works across all supported formats including spreadsheet cell values (xlsx) and slide text (pptx); patch a matched el_ #id with DocEdit, or read more context with DocPeek.\",\n\t\t],\n\t\tparameters: docGrepSchema,\n\t\tasync execute(_toolCallId, { path, pattern, ignoreCase, limit }: DocGrepToolInput, signal?: AbortSignal) {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\t\t\tconst view = await grepDocument(absolutePath, pattern, cwd, signal, {\n\t\t\t\tignoreCase,\n\t\t\t\tlimit,\n\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: renderGrepView(view) }],\n\t\t\t\tdetails: { pattern: view.pattern, matches: view.returned },\n\t\t\t};\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDocGrepCall(args));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDocGrepResult(result as any, options, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDocGrepTool(cwd: string, options?: DocGrepToolOptions): AgentTool<typeof docGrepSchema> {\n\treturn wrapToolDefinition(createDocGrepToolDefinition(cwd, options));\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docgrep.js","sourceRoot":"","sources":["../../../../src/core/tools/doc/docgrep.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../../modes/interactive/components/keybinding-hints.js\";\nimport { theme as appTheme } from \"../../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../../extensions/types.js\";\nimport { type GrepView, grepDocument, truncateRenderToTokenBudget } from \"../filetools-shared.js\";\nimport { resolveReadPath } from \"../path-utils.js\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"../render-utils.js\";\nimport { wrapToolDefinition } from \"../tool-definition-wrapper.js\";\n\nconst docGrepSchema = Type.Object({\n\tpath: Type.String({\n\t\tdescription:\n\t\t\t\"Path to the document to search (relative or absolute). XML, drawio, OOXML (docx/xlsx/pptx), or PDF.\",\n\t}),\n\tpattern: Type.String({\n\t\tdescription: \"Literal substring to match per line (NOT a regex).\",\n\t}),\n\tignoreCase: Type.Optional(Type.Boolean({ description: \"Case-insensitive matching. Default false.\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Stop after N matches. Default: all matches.\" })),\n});\n\nexport type DocGrepToolInput = Static<typeof docGrepSchema>;\n\nexport interface DocGrepToolDetails {\n\tpattern?: string;\n\tmatches?: number;\n}\n\nexport interface DocGrepToolOptions {\n\t/** Timeout (seconds) for the filetools invocation. */\n\ttimeoutSecs?: number;\n}\n\n/**\n * Render grep matches as `#block_id:line :: \"snippet\"` lines. Each block id\n * feeds straight back into DocPeek (to hydrate) or a DocEdit patch.\n */\nexport function renderGrepView(view: GrepView): string {\n\tconst header = `grep ${JSON.stringify(view.pattern)} — ${view.returned} match${view.returned === 1 ? \"\" : \"es\"}`;\n\tif (view.matches.length === 0) return header;\n\tconst lines: string[] = [header, \"\"];\n\tfor (const m of view.matches) {\n\t\tconst flag = m.writable ? \"\" : \" (read-only)\";\n\t\tlines.push(`#${m.block_id}:${m.line}${flag} :: ${JSON.stringify(m.snippet)}`);\n\t}\n\tconst { text, droppedLines } = truncateRenderToTokenBudget(lines);\n\tif (droppedLines === 0) return text;\n\treturn (\n\t\t`${text}\\n\\n[Truncated: ${droppedLines} more match line${droppedLines === 1 ? \"\" : \"s\"} omitted; ` +\n\t\t`re-run with a smaller limit or a more specific pattern.]`\n\t);\n}\n\nfunction formatDocGrepCall(args: { path?: string; pattern?: string; ignoreCase?: boolean } | undefined): string {\n\tconst path = str(args?.path);\n\tconst pathDisplay =\n\t\tpath === null ? invalidArgText(appTheme) : path ? shortenPath(path) : appTheme.fg(\"toolOutput\", \"...\");\n\tlet text = appTheme.fg(\"toolTitle\", appTheme.bold(\"DocGrep \"));\n\tconst pattern = str(args?.pattern);\n\tif (pattern) text += `${appTheme.fg(\"accent\", JSON.stringify(pattern))} ${appTheme.fg(\"muted\", \"in\")} `;\n\ttext += appTheme.fg(\"accent\", pathDisplay);\n\tif (args?.ignoreCase) text += appTheme.fg(\"muted\", \" (i)\");\n\treturn text;\n}\n\nfunction formatDocGrepResult(\n\tresult: { content: Array<{ type: string; text?: string }> },\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result as any, showImages).trim();\n\tif (!output) return \"\";\n\tconst lines = output.split(\"\\n\");\n\tconst maxLines = options.expanded ? lines.length : 15;\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\tlet text = `\\n${displayLines.map((line) => appTheme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\tif (remaining > 0) {\n\t\ttext += `${appTheme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t}\n\treturn text;\n}\n\nexport function createDocGrepToolDefinition(\n\tcwd: string,\n\toptions?: DocGrepToolOptions,\n): ToolDefinition<typeof docGrepSchema, DocGrepToolDetails | undefined> {\n\treturn {\n\t\tname: \"DocGrep\",\n\t\tlabel: \"DocGrep\",\n\t\tdescription:\n\t\t\t\"Locate blocks in a structured/binary document (XML, drawio, docx/xlsx/pptx, PDF) by literal text, WITHOUT hydrating the whole document. Returns each match as an editable el_ node #id, line number, and snippet. Those el_ #ids target a DocEdit/DocWrite patch directly — DocGrep is the fast path from 'find text' to 'edit it' (far cheaper than a full DocRead). Off by default; enabled with --enable-filetools.\",\n\t\tpromptSnippet: \"Find blocks in a structured/binary document by literal text, without hydrating it\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use DocGrep to find where something is in a large structured/binary document instead of reading it all: it returns editable el_ node #ids + snippets for a literal substring match. Patch those el_ #ids straight with DocEdit/DocWrite.\",\n\t\t\t\"DocGrep's el_ #ids are the edit id-space; they are NOT DocPeek's structural-path ids. To read more context around a match, DocScan/DocPeek by structural path instead.\",\n\t\t\t\"pattern is a literal substring (not a regex); pass ignoreCase for case-insensitive matching.\",\n\t\t\t\"Works across all supported formats including spreadsheet cell values (xlsx) and slide text (pptx); patch a matched el_ #id with DocEdit, or read more context with DocPeek.\",\n\t\t],\n\t\tparameters: docGrepSchema,\n\t\tasync execute(_toolCallId, { path, pattern, ignoreCase, limit }: DocGrepToolInput, signal?: AbortSignal) {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\t\t\tconst view = await grepDocument(absolutePath, pattern, cwd, signal, {\n\t\t\t\tignoreCase,\n\t\t\t\tlimit,\n\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: renderGrepView(view) }],\n\t\t\t\tdetails: { pattern: view.pattern, matches: view.returned },\n\t\t\t};\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDocGrepCall(args));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDocGrepResult(result as any, options, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDocGrepTool(cwd: string, options?: DocGrepToolOptions): AgentTool<typeof docGrepSchema> {\n\treturn wrapToolDefinition(createDocGrepToolDefinition(cwd, options));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"docgrep.js","sourceRoot":"","sources":["../../../../src/core/tools/doc/docgrep.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../../modes/interactive/components/keybinding-hints.js\";\nimport { theme as appTheme } from \"../../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../../extensions/types.js\";\nimport { type GrepView, grepDocument, truncateRenderToTokenBudget } from \"../filetools-shared.js\";\nimport { resolveReadPath } from \"../path-utils.js\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"../render-utils.js\";\nimport { wrapToolDefinition } from \"../tool-definition-wrapper.js\";\n\nconst docGrepSchema = Type.Object({\n\tpath: Type.String({\n\t\tdescription:\n\t\t\t\"Path to the document to search (relative or absolute). XML, drawio, OOXML (docx/xlsx/pptx), or PDF.\",\n\t}),\n\tpattern: Type.String({\n\t\tdescription: \"Literal substring to match per line (NOT a regex).\",\n\t}),\n\tignoreCase: Type.Optional(Type.Boolean({ description: \"Case-insensitive matching. Default false.\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Stop after N matches. Default: all matches.\" })),\n});\n\ntype DocGrepToolInput = Static<typeof docGrepSchema>;\n\nexport interface DocGrepToolDetails {\n\tpattern?: string;\n\tmatches?: number;\n}\n\nexport interface DocGrepToolOptions {\n\t/** Timeout (seconds) for the filetools invocation. */\n\ttimeoutSecs?: number;\n}\n\n/**\n * Render grep matches as `#block_id:line :: \"snippet\"` lines. Each block id\n * feeds straight back into DocPeek (to hydrate) or a DocEdit patch.\n */\nexport function renderGrepView(view: GrepView): string {\n\tconst header = `grep ${JSON.stringify(view.pattern)} — ${view.returned} match${view.returned === 1 ? \"\" : \"es\"}`;\n\tif (view.matches.length === 0) return header;\n\tconst lines: string[] = [header, \"\"];\n\tfor (const m of view.matches) {\n\t\tconst flag = m.writable ? \"\" : \" (read-only)\";\n\t\tlines.push(`#${m.block_id}:${m.line}${flag} :: ${JSON.stringify(m.snippet)}`);\n\t}\n\tconst { text, droppedLines } = truncateRenderToTokenBudget(lines);\n\tif (droppedLines === 0) return text;\n\treturn (\n\t\t`${text}\\n\\n[Truncated: ${droppedLines} more match line${droppedLines === 1 ? \"\" : \"s\"} omitted; ` +\n\t\t`re-run with a smaller limit or a more specific pattern.]`\n\t);\n}\n\nfunction formatDocGrepCall(args: { path?: string; pattern?: string; ignoreCase?: boolean } | undefined): string {\n\tconst path = str(args?.path);\n\tconst pathDisplay =\n\t\tpath === null ? invalidArgText(appTheme) : path ? shortenPath(path) : appTheme.fg(\"toolOutput\", \"...\");\n\tlet text = appTheme.fg(\"toolTitle\", appTheme.bold(\"DocGrep \"));\n\tconst pattern = str(args?.pattern);\n\tif (pattern) text += `${appTheme.fg(\"accent\", JSON.stringify(pattern))} ${appTheme.fg(\"muted\", \"in\")} `;\n\ttext += appTheme.fg(\"accent\", pathDisplay);\n\tif (args?.ignoreCase) text += appTheme.fg(\"muted\", \" (i)\");\n\treturn text;\n}\n\nfunction formatDocGrepResult(\n\tresult: { content: Array<{ type: string; text?: string }> },\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result as any, showImages).trim();\n\tif (!output) return \"\";\n\tconst lines = output.split(\"\\n\");\n\tconst maxLines = options.expanded ? lines.length : 15;\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\tlet text = `\\n${displayLines.map((line) => appTheme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\tif (remaining > 0) {\n\t\ttext += `${appTheme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t}\n\treturn text;\n}\n\nexport function createDocGrepToolDefinition(\n\tcwd: string,\n\toptions?: DocGrepToolOptions,\n): ToolDefinition<typeof docGrepSchema, DocGrepToolDetails | undefined> {\n\treturn {\n\t\tname: \"DocGrep\",\n\t\tlabel: \"DocGrep\",\n\t\tdescription:\n\t\t\t\"Locate blocks in a structured/binary document (XML, drawio, docx/xlsx/pptx, PDF) by literal text, WITHOUT hydrating the whole document. Returns each match as an editable el_ node #id, line number, and snippet. Those el_ #ids target a DocEdit/DocWrite patch directly — DocGrep is the fast path from 'find text' to 'edit it' (far cheaper than a full DocRead). Off by default; enabled with --enable-filetools.\",\n\t\tpromptSnippet: \"Find blocks in a structured/binary document by literal text, without hydrating it\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use DocGrep to find where something is in a large structured/binary document instead of reading it all: it returns editable el_ node #ids + snippets for a literal substring match. Patch those el_ #ids straight with DocEdit/DocWrite.\",\n\t\t\t\"DocGrep's el_ #ids are the edit id-space; they are NOT DocPeek's structural-path ids. To read more context around a match, DocScan/DocPeek by structural path instead.\",\n\t\t\t\"pattern is a literal substring (not a regex); pass ignoreCase for case-insensitive matching.\",\n\t\t\t\"Works across all supported formats including spreadsheet cell values (xlsx) and slide text (pptx); patch a matched el_ #id with DocEdit, or read more context with DocPeek.\",\n\t\t],\n\t\tparameters: docGrepSchema,\n\t\tasync execute(_toolCallId, { path, pattern, ignoreCase, limit }: DocGrepToolInput, signal?: AbortSignal) {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\t\t\tconst view = await grepDocument(absolutePath, pattern, cwd, signal, {\n\t\t\t\tignoreCase,\n\t\t\t\tlimit,\n\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: renderGrepView(view) }],\n\t\t\t\tdetails: { pattern: view.pattern, matches: view.returned },\n\t\t\t};\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDocGrepCall(args));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDocGrepResult(result as any, options, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDocGrepTool(cwd: string, options?: DocGrepToolOptions): AgentTool<typeof docGrepSchema> {\n\treturn wrapToolDefinition(createDocGrepToolDefinition(cwd, options));\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AgentTool } from "@kolisachint/hoocode-agent-core";
|
|
2
|
-
import {
|
|
2
|
+
import { Type } from "typebox";
|
|
3
3
|
import type { ToolDefinition } from "../../extensions/types.js";
|
|
4
4
|
import { type ReadView } from "../filetools-shared.js";
|
|
5
5
|
declare const docPeekSchema: Type.TObject<{
|
|
@@ -8,7 +8,6 @@ declare const docPeekSchema: Type.TObject<{
|
|
|
8
8
|
offset: Type.TOptional<Type.TNumber>;
|
|
9
9
|
limit: Type.TOptional<Type.TNumber>;
|
|
10
10
|
}>;
|
|
11
|
-
export type DocPeekToolInput = Static<typeof docPeekSchema>;
|
|
12
11
|
export interface DocPeekToolDetails {
|
|
13
12
|
returned?: number;
|
|
14
13
|
total?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docpeek.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/doc/docpeek.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAEjE,OAAO,
|
|
1
|
+
{"version":3,"file":"docpeek.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/doc/docpeek.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAEjE,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,2BAA2B,CAAC;AACzF,OAAO,EACN,KAAK,QAAQ,EAIb,MAAM,wBAAwB,CAAC;AAKhC,QAAA,MAAM,aAAa;;;;;EAYjB,CAAC;AAIH,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IAClC,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,uFAAuF;AACvF,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAmBrD;AAuCD,wBAAgB,2BAA2B,CAC1C,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,kBAAkB,GAC1B,cAAc,CAAC,OAAO,aAAa,EAAE,kBAAkB,GAAG,SAAS,CAAC,CAuCtE;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC,OAAO,aAAa,CAAC,CAE5G","sourcesContent":["import type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../../modes/interactive/components/keybinding-hints.js\";\nimport { theme as appTheme } from \"../../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../../extensions/types.js\";\nimport {\n\ttype ReadView,\n\treadDocumentBlocks,\n\trenderDocNodeLines,\n\ttruncateRenderToTokenBudget,\n} from \"../filetools-shared.js\";\nimport { resolveReadPath } from \"../path-utils.js\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"../render-utils.js\";\nimport { wrapToolDefinition } from \"../tool-definition-wrapper.js\";\n\nconst docPeekSchema = Type.Object({\n\tpath: Type.String({\n\t\tdescription: \"Path to the document to read (relative or absolute). XML, drawio, OOXML (docx/xlsx/pptx), or PDF.\",\n\t}),\n\tid: Type.Optional(\n\t\tType.Array(Type.String(), {\n\t\t\tdescription:\n\t\t\t\t\"Block id(s) to hydrate — use the EXACT ids returned by a prior DocScan (e.g. 'node[title:0]', 'paragraph[3]', 'page[1]'); do NOT hand-construct sub-ranges (an invented 'rows[0-2]' returns nothing — pass the exact 'rows[0-99]' DocScan emitted). These are DocScan's path ids, not DocGrep's el_ node ids. Omit to read a paginated slice of all blocks.\",\n\t\t}),\n\t),\n\toffset: Type.Optional(Type.Number({ description: \"Pagination start when no ids are given. Default 0.\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Pagination size when no ids are given. Default: all remaining.\" })),\n});\n\ntype DocPeekToolInput = Static<typeof docPeekSchema>;\n\nexport interface DocPeekToolDetails {\n\treturned?: number;\n\ttotal?: number;\n}\n\nexport interface DocPeekToolOptions {\n\t/** Timeout (seconds) for the filetools invocation. */\n\ttimeoutSecs?: number;\n}\n\n/** Render hydrated read blocks using the same id-addressed node dialect as DocRead. */\nexport function renderReadView(view: ReadView): string {\n\tconst header = `document — ${view.returned}/${view.total} blocks (offset ${view.offset})`;\n\tconst lines: string[] = [header, \"\", ...renderDocNodeLines(view.nodes)];\n\tconst { text, droppedLines } = truncateRenderToTokenBudget(lines);\n\tconst seen = view.offset + view.returned;\n\tconst remaining = view.total - seen;\n\tconst parts = [text];\n\tif (droppedLines > 0) {\n\t\tparts.push(\n\t\t\t`\\n[Truncated: ${droppedLines} more node line${droppedLines === 1 ? \"\" : \"s\"} omitted; ` +\n\t\t\t\t`request fewer ids or a smaller limit.]`,\n\t\t);\n\t}\n\tif (remaining > 0) {\n\t\tparts.push(\n\t\t\t`\\n[${remaining} more block${remaining === 1 ? \"\" : \"s\"} not shown — re-run with offset:${seen} to continue.]`,\n\t\t);\n\t}\n\treturn parts.join(\"\\n\");\n}\n\nfunction formatDocPeekCall(\n\targs: { path?: string; id?: string[]; offset?: number; limit?: number } | undefined,\n): string {\n\tconst path = str(args?.path);\n\tconst pathDisplay =\n\t\tpath === null ? invalidArgText(appTheme) : path ? shortenPath(path) : appTheme.fg(\"toolOutput\", \"...\");\n\tlet text = appTheme.fg(\"toolTitle\", appTheme.bold(\"DocPeek \")) + appTheme.fg(\"accent\", pathDisplay);\n\tconst ids = Array.isArray(args?.id) ? args.id.length : 0;\n\tif (ids > 0) {\n\t\ttext += appTheme.fg(\"muted\", ` (${ids} id${ids === 1 ? \"\" : \"s\"})`);\n\t} else {\n\t\tconst range: string[] = [];\n\t\tif (args?.offset !== undefined) range.push(`offset ${args.offset}`);\n\t\tif (args?.limit !== undefined) range.push(`limit ${args.limit}`);\n\t\tif (range.length > 0) text += appTheme.fg(\"muted\", ` (${range.join(\", \")})`);\n\t}\n\treturn text;\n}\n\nfunction formatDocPeekResult(\n\tresult: { content: Array<{ type: string; text?: string }> },\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result as any, showImages).trim();\n\tif (!output) return \"\";\n\tconst lines = output.split(\"\\n\");\n\tconst maxLines = options.expanded ? lines.length : 15;\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\tlet text = `\\n${displayLines.map((line) => appTheme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\tif (remaining > 0) {\n\t\ttext += `${appTheme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t}\n\treturn text;\n}\n\nexport function createDocPeekToolDefinition(\n\tcwd: string,\n\toptions?: DocPeekToolOptions,\n): ToolDefinition<typeof docPeekSchema, DocPeekToolDetails | undefined> {\n\treturn {\n\t\tname: \"DocPeek\",\n\t\tlabel: \"DocPeek\",\n\t\tdescription:\n\t\t\t\"Hydrate specific blocks of a structured/binary document (XML, drawio, docx/xlsx/pptx, PDF) by structural-path id — the read half of the token-sensitive loop. Pass the path ids from a prior DocScan (e.g. node[title:0]) to read only those blocks (or omit ids to page through all with offset/limit), instead of dumping the whole document with DocRead. The hydrated nodes carry the editable el_ #ids, which you then patch with DocEdit/DocWrite. Read-only. Off by default; enabled with --enable-filetools.\",\n\t\tpromptSnippet: \"Read only specific blocks of a structured/binary document by id\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use DocPeek to read just the blocks you need (by structural-path id from DocScan, e.g. node[title:0]) instead of a full DocRead — it is much cheaper in tokens. Omit ids and use offset/limit to page through a large document.\",\n\t\t\t\"Pass the EXACT ids DocScan returned; DocPeek does not accept invented sub-ranges (e.g. rows[0-2] when DocScan emitted rows[0-99]).\",\n\t\t\t\"DocPeek takes DocScan's path ids, NOT DocGrep's el_ node ids. The nodes it returns carry the editable el_ #ids — patch those with DocEdit/DocWrite (which auto-extract). If you already have an el_ id from DocGrep, go straight to DocEdit; you do not need DocPeek.\",\n\t\t\t\"Works across all supported formats including spreadsheet cells (hydrating a sheet's rows[a-b] block returns the cell values) and slide text (pptx).\",\n\t\t],\n\t\tparameters: docPeekSchema,\n\t\tasync execute(_toolCallId, { path, id, offset, limit }: DocPeekToolInput, signal?: AbortSignal) {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\t\t\tconst view = await readDocumentBlocks(absolutePath, cwd, signal, {\n\t\t\t\tids: id,\n\t\t\t\toffset,\n\t\t\t\tlimit,\n\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: renderReadView(view) }],\n\t\t\t\tdetails: { returned: view.returned, total: view.total },\n\t\t\t};\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDocPeekCall(args));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDocPeekResult(result as any, options, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDocPeekTool(cwd: string, options?: DocPeekToolOptions): AgentTool<typeof docPeekSchema> {\n\treturn wrapToolDefinition(createDocPeekToolDefinition(cwd, options));\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docpeek.js","sourceRoot":"","sources":["../../../../src/core/tools/doc/docpeek.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../../modes/interactive/components/keybinding-hints.js\";\nimport { theme as appTheme } from \"../../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../../extensions/types.js\";\nimport {\n\ttype ReadView,\n\treadDocumentBlocks,\n\trenderDocNodeLines,\n\ttruncateRenderToTokenBudget,\n} from \"../filetools-shared.js\";\nimport { resolveReadPath } from \"../path-utils.js\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"../render-utils.js\";\nimport { wrapToolDefinition } from \"../tool-definition-wrapper.js\";\n\nconst docPeekSchema = Type.Object({\n\tpath: Type.String({\n\t\tdescription: \"Path to the document to read (relative or absolute). XML, drawio, OOXML (docx/xlsx/pptx), or PDF.\",\n\t}),\n\tid: Type.Optional(\n\t\tType.Array(Type.String(), {\n\t\t\tdescription:\n\t\t\t\t\"Block id(s) to hydrate — use the EXACT ids returned by a prior DocScan (e.g. 'node[title:0]', 'paragraph[3]', 'page[1]'); do NOT hand-construct sub-ranges (an invented 'rows[0-2]' returns nothing — pass the exact 'rows[0-99]' DocScan emitted). These are DocScan's path ids, not DocGrep's el_ node ids. Omit to read a paginated slice of all blocks.\",\n\t\t}),\n\t),\n\toffset: Type.Optional(Type.Number({ description: \"Pagination start when no ids are given. Default 0.\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Pagination size when no ids are given. Default: all remaining.\" })),\n});\n\nexport type DocPeekToolInput = Static<typeof docPeekSchema>;\n\nexport interface DocPeekToolDetails {\n\treturned?: number;\n\ttotal?: number;\n}\n\nexport interface DocPeekToolOptions {\n\t/** Timeout (seconds) for the filetools invocation. */\n\ttimeoutSecs?: number;\n}\n\n/** Render hydrated read blocks using the same id-addressed node dialect as DocRead. */\nexport function renderReadView(view: ReadView): string {\n\tconst header = `document — ${view.returned}/${view.total} blocks (offset ${view.offset})`;\n\tconst lines: string[] = [header, \"\", ...renderDocNodeLines(view.nodes)];\n\tconst { text, droppedLines } = truncateRenderToTokenBudget(lines);\n\tconst seen = view.offset + view.returned;\n\tconst remaining = view.total - seen;\n\tconst parts = [text];\n\tif (droppedLines > 0) {\n\t\tparts.push(\n\t\t\t`\\n[Truncated: ${droppedLines} more node line${droppedLines === 1 ? \"\" : \"s\"} omitted; ` +\n\t\t\t\t`request fewer ids or a smaller limit.]`,\n\t\t);\n\t}\n\tif (remaining > 0) {\n\t\tparts.push(\n\t\t\t`\\n[${remaining} more block${remaining === 1 ? \"\" : \"s\"} not shown — re-run with offset:${seen} to continue.]`,\n\t\t);\n\t}\n\treturn parts.join(\"\\n\");\n}\n\nfunction formatDocPeekCall(\n\targs: { path?: string; id?: string[]; offset?: number; limit?: number } | undefined,\n): string {\n\tconst path = str(args?.path);\n\tconst pathDisplay =\n\t\tpath === null ? invalidArgText(appTheme) : path ? shortenPath(path) : appTheme.fg(\"toolOutput\", \"...\");\n\tlet text = appTheme.fg(\"toolTitle\", appTheme.bold(\"DocPeek \")) + appTheme.fg(\"accent\", pathDisplay);\n\tconst ids = Array.isArray(args?.id) ? args.id.length : 0;\n\tif (ids > 0) {\n\t\ttext += appTheme.fg(\"muted\", ` (${ids} id${ids === 1 ? \"\" : \"s\"})`);\n\t} else {\n\t\tconst range: string[] = [];\n\t\tif (args?.offset !== undefined) range.push(`offset ${args.offset}`);\n\t\tif (args?.limit !== undefined) range.push(`limit ${args.limit}`);\n\t\tif (range.length > 0) text += appTheme.fg(\"muted\", ` (${range.join(\", \")})`);\n\t}\n\treturn text;\n}\n\nfunction formatDocPeekResult(\n\tresult: { content: Array<{ type: string; text?: string }> },\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result as any, showImages).trim();\n\tif (!output) return \"\";\n\tconst lines = output.split(\"\\n\");\n\tconst maxLines = options.expanded ? lines.length : 15;\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\tlet text = `\\n${displayLines.map((line) => appTheme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\tif (remaining > 0) {\n\t\ttext += `${appTheme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t}\n\treturn text;\n}\n\nexport function createDocPeekToolDefinition(\n\tcwd: string,\n\toptions?: DocPeekToolOptions,\n): ToolDefinition<typeof docPeekSchema, DocPeekToolDetails | undefined> {\n\treturn {\n\t\tname: \"DocPeek\",\n\t\tlabel: \"DocPeek\",\n\t\tdescription:\n\t\t\t\"Hydrate specific blocks of a structured/binary document (XML, drawio, docx/xlsx/pptx, PDF) by structural-path id — the read half of the token-sensitive loop. Pass the path ids from a prior DocScan (e.g. node[title:0]) to read only those blocks (or omit ids to page through all with offset/limit), instead of dumping the whole document with DocRead. The hydrated nodes carry the editable el_ #ids, which you then patch with DocEdit/DocWrite. Read-only. Off by default; enabled with --enable-filetools.\",\n\t\tpromptSnippet: \"Read only specific blocks of a structured/binary document by id\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use DocPeek to read just the blocks you need (by structural-path id from DocScan, e.g. node[title:0]) instead of a full DocRead — it is much cheaper in tokens. Omit ids and use offset/limit to page through a large document.\",\n\t\t\t\"Pass the EXACT ids DocScan returned; DocPeek does not accept invented sub-ranges (e.g. rows[0-2] when DocScan emitted rows[0-99]).\",\n\t\t\t\"DocPeek takes DocScan's path ids, NOT DocGrep's el_ node ids. The nodes it returns carry the editable el_ #ids — patch those with DocEdit/DocWrite (which auto-extract). If you already have an el_ id from DocGrep, go straight to DocEdit; you do not need DocPeek.\",\n\t\t\t\"Works across all supported formats including spreadsheet cells (hydrating a sheet's rows[a-b] block returns the cell values) and slide text (pptx).\",\n\t\t],\n\t\tparameters: docPeekSchema,\n\t\tasync execute(_toolCallId, { path, id, offset, limit }: DocPeekToolInput, signal?: AbortSignal) {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\t\t\tconst view = await readDocumentBlocks(absolutePath, cwd, signal, {\n\t\t\t\tids: id,\n\t\t\t\toffset,\n\t\t\t\tlimit,\n\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: renderReadView(view) }],\n\t\t\t\tdetails: { returned: view.returned, total: view.total },\n\t\t\t};\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDocPeekCall(args));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDocPeekResult(result as any, options, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDocPeekTool(cwd: string, options?: DocPeekToolOptions): AgentTool<typeof docPeekSchema> {\n\treturn wrapToolDefinition(createDocPeekToolDefinition(cwd, options));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"docpeek.js","sourceRoot":"","sources":["../../../../src/core/tools/doc/docpeek.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../../modes/interactive/components/keybinding-hints.js\";\nimport { theme as appTheme } from \"../../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../../extensions/types.js\";\nimport {\n\ttype ReadView,\n\treadDocumentBlocks,\n\trenderDocNodeLines,\n\ttruncateRenderToTokenBudget,\n} from \"../filetools-shared.js\";\nimport { resolveReadPath } from \"../path-utils.js\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"../render-utils.js\";\nimport { wrapToolDefinition } from \"../tool-definition-wrapper.js\";\n\nconst docPeekSchema = Type.Object({\n\tpath: Type.String({\n\t\tdescription: \"Path to the document to read (relative or absolute). XML, drawio, OOXML (docx/xlsx/pptx), or PDF.\",\n\t}),\n\tid: Type.Optional(\n\t\tType.Array(Type.String(), {\n\t\t\tdescription:\n\t\t\t\t\"Block id(s) to hydrate — use the EXACT ids returned by a prior DocScan (e.g. 'node[title:0]', 'paragraph[3]', 'page[1]'); do NOT hand-construct sub-ranges (an invented 'rows[0-2]' returns nothing — pass the exact 'rows[0-99]' DocScan emitted). These are DocScan's path ids, not DocGrep's el_ node ids. Omit to read a paginated slice of all blocks.\",\n\t\t}),\n\t),\n\toffset: Type.Optional(Type.Number({ description: \"Pagination start when no ids are given. Default 0.\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Pagination size when no ids are given. Default: all remaining.\" })),\n});\n\ntype DocPeekToolInput = Static<typeof docPeekSchema>;\n\nexport interface DocPeekToolDetails {\n\treturned?: number;\n\ttotal?: number;\n}\n\nexport interface DocPeekToolOptions {\n\t/** Timeout (seconds) for the filetools invocation. */\n\ttimeoutSecs?: number;\n}\n\n/** Render hydrated read blocks using the same id-addressed node dialect as DocRead. */\nexport function renderReadView(view: ReadView): string {\n\tconst header = `document — ${view.returned}/${view.total} blocks (offset ${view.offset})`;\n\tconst lines: string[] = [header, \"\", ...renderDocNodeLines(view.nodes)];\n\tconst { text, droppedLines } = truncateRenderToTokenBudget(lines);\n\tconst seen = view.offset + view.returned;\n\tconst remaining = view.total - seen;\n\tconst parts = [text];\n\tif (droppedLines > 0) {\n\t\tparts.push(\n\t\t\t`\\n[Truncated: ${droppedLines} more node line${droppedLines === 1 ? \"\" : \"s\"} omitted; ` +\n\t\t\t\t`request fewer ids or a smaller limit.]`,\n\t\t);\n\t}\n\tif (remaining > 0) {\n\t\tparts.push(\n\t\t\t`\\n[${remaining} more block${remaining === 1 ? \"\" : \"s\"} not shown — re-run with offset:${seen} to continue.]`,\n\t\t);\n\t}\n\treturn parts.join(\"\\n\");\n}\n\nfunction formatDocPeekCall(\n\targs: { path?: string; id?: string[]; offset?: number; limit?: number } | undefined,\n): string {\n\tconst path = str(args?.path);\n\tconst pathDisplay =\n\t\tpath === null ? invalidArgText(appTheme) : path ? shortenPath(path) : appTheme.fg(\"toolOutput\", \"...\");\n\tlet text = appTheme.fg(\"toolTitle\", appTheme.bold(\"DocPeek \")) + appTheme.fg(\"accent\", pathDisplay);\n\tconst ids = Array.isArray(args?.id) ? args.id.length : 0;\n\tif (ids > 0) {\n\t\ttext += appTheme.fg(\"muted\", ` (${ids} id${ids === 1 ? \"\" : \"s\"})`);\n\t} else {\n\t\tconst range: string[] = [];\n\t\tif (args?.offset !== undefined) range.push(`offset ${args.offset}`);\n\t\tif (args?.limit !== undefined) range.push(`limit ${args.limit}`);\n\t\tif (range.length > 0) text += appTheme.fg(\"muted\", ` (${range.join(\", \")})`);\n\t}\n\treturn text;\n}\n\nfunction formatDocPeekResult(\n\tresult: { content: Array<{ type: string; text?: string }> },\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result as any, showImages).trim();\n\tif (!output) return \"\";\n\tconst lines = output.split(\"\\n\");\n\tconst maxLines = options.expanded ? lines.length : 15;\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\tlet text = `\\n${displayLines.map((line) => appTheme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\tif (remaining > 0) {\n\t\ttext += `${appTheme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t}\n\treturn text;\n}\n\nexport function createDocPeekToolDefinition(\n\tcwd: string,\n\toptions?: DocPeekToolOptions,\n): ToolDefinition<typeof docPeekSchema, DocPeekToolDetails | undefined> {\n\treturn {\n\t\tname: \"DocPeek\",\n\t\tlabel: \"DocPeek\",\n\t\tdescription:\n\t\t\t\"Hydrate specific blocks of a structured/binary document (XML, drawio, docx/xlsx/pptx, PDF) by structural-path id — the read half of the token-sensitive loop. Pass the path ids from a prior DocScan (e.g. node[title:0]) to read only those blocks (or omit ids to page through all with offset/limit), instead of dumping the whole document with DocRead. The hydrated nodes carry the editable el_ #ids, which you then patch with DocEdit/DocWrite. Read-only. Off by default; enabled with --enable-filetools.\",\n\t\tpromptSnippet: \"Read only specific blocks of a structured/binary document by id\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use DocPeek to read just the blocks you need (by structural-path id from DocScan, e.g. node[title:0]) instead of a full DocRead — it is much cheaper in tokens. Omit ids and use offset/limit to page through a large document.\",\n\t\t\t\"Pass the EXACT ids DocScan returned; DocPeek does not accept invented sub-ranges (e.g. rows[0-2] when DocScan emitted rows[0-99]).\",\n\t\t\t\"DocPeek takes DocScan's path ids, NOT DocGrep's el_ node ids. The nodes it returns carry the editable el_ #ids — patch those with DocEdit/DocWrite (which auto-extract). If you already have an el_ id from DocGrep, go straight to DocEdit; you do not need DocPeek.\",\n\t\t\t\"Works across all supported formats including spreadsheet cells (hydrating a sheet's rows[a-b] block returns the cell values) and slide text (pptx).\",\n\t\t],\n\t\tparameters: docPeekSchema,\n\t\tasync execute(_toolCallId, { path, id, offset, limit }: DocPeekToolInput, signal?: AbortSignal) {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\t\t\tconst view = await readDocumentBlocks(absolutePath, cwd, signal, {\n\t\t\t\tids: id,\n\t\t\t\toffset,\n\t\t\t\tlimit,\n\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: renderReadView(view) }],\n\t\t\t\tdetails: { returned: view.returned, total: view.total },\n\t\t\t};\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDocPeekCall(args));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDocPeekResult(result as any, options, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDocPeekTool(cwd: string, options?: DocPeekToolOptions): AgentTool<typeof docPeekSchema> {\n\treturn wrapToolDefinition(createDocPeekToolDefinition(cwd, options));\n}\n"]}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import type { AgentTool } from "@kolisachint/hoocode-agent-core";
|
|
2
|
-
import {
|
|
2
|
+
import { Type } from "typebox";
|
|
3
3
|
import type { ToolDefinition } from "../../extensions/types.js";
|
|
4
4
|
import { type Envelope } from "../filetools-shared.js";
|
|
5
5
|
declare const docReadSchema: Type.TObject<{
|
|
6
6
|
path: Type.TString;
|
|
7
7
|
readonly: Type.TOptional<Type.TBoolean>;
|
|
8
8
|
}>;
|
|
9
|
-
export type DocReadToolInput = Static<typeof docReadSchema>;
|
|
10
9
|
export interface DocReadToolDetails {
|
|
11
10
|
type?: string;
|
|
12
11
|
fidelity?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docread.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/doc/docread.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAEjE,OAAO,
|
|
1
|
+
{"version":3,"file":"docread.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/doc/docread.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAEjE,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,2BAA2B,CAAC;AACzF,OAAO,EAGN,KAAK,QAAQ,EAIb,MAAM,wBAAwB,CAAC;AAKhC,QAAA,MAAM,aAAa;;;EAWjB,CAAC;AAIH,MAAM,WAAW,kBAAkB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IAClC,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAUD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAiB5F;AA6BD,wBAAgB,2BAA2B,CAC1C,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,kBAAkB,GAC1B,cAAc,CAAC,OAAO,aAAa,EAAE,kBAAkB,GAAG,SAAS,CAAC,CAyCtE;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC,OAAO,aAAa,CAAC,CAE5G","sourcesContent":["import type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../../modes/interactive/components/keybinding-hints.js\";\nimport { theme as appTheme } from \"../../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../../extensions/types.js\";\nimport {\n\tDOCREAD_MAX_RENDER_TOKENS,\n\ttype DocNode,\n\ttype Envelope,\n\textractDocument,\n\trenderDocNodeLines,\n\ttruncateRenderToTokenBudget,\n} from \"../filetools-shared.js\";\nimport { resolveReadPath } from \"../path-utils.js\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"../render-utils.js\";\nimport { wrapToolDefinition } from \"../tool-definition-wrapper.js\";\n\nconst docReadSchema = Type.Object({\n\tpath: Type.String({\n\t\tdescription:\n\t\t\t\"Path to the document to extract (relative or absolute). XML, drawio, OOXML (docx/xlsx/pptx), or PDF.\",\n\t}),\n\treadonly: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"Analysis-only projection: strips node ids for a smaller view that CANNOT be edited. Omit (default false) when you intend to DocEdit/DocWrite afterwards.\",\n\t\t}),\n\t),\n});\n\ntype DocReadToolInput = Static<typeof docReadSchema>;\n\nexport interface DocReadToolDetails {\n\ttype?: string;\n\tfidelity?: string;\n\twritable?: boolean;\n\tnodeCount?: number;\n}\n\nexport interface DocReadToolOptions {\n\t/** Timeout (seconds) for the filetools invocation. */\n\ttimeoutSecs?: number;\n}\n\nfunction countNodes(nodes: DocNode[]): number {\n\tlet total = 0;\n\tfor (const node of nodes) {\n\t\ttotal += 1 + (node.children ? countNodes(node.children) : 0);\n\t}\n\treturn total;\n}\n\n/**\n * Render the envelope as compact, id-addressed text the model edits against.\n * Each line carries the node id so DocEdit/DocWrite patches can target it.\n *\n * The filetools binary has no pagination, so a dense document can project into\n * a huge dump. We truncate the rendered view to a token budget and append an\n * actionable notice instead of flooding the model context.\n */\nexport function renderEnvelopeText(envelope: Envelope, readonly: boolean | undefined): string {\n\tconst header =\n\t\t`document ${envelope.source.path} [${envelope.source.type}, ${envelope.fidelity}, ` +\n\t\t`${envelope.writable ? \"writable\" : \"read-only\"}]`;\n\tconst lines: string[] = [header, \"\", ...renderDocNodeLines(envelope.structure)];\n\n\tconst { text, droppedLines } = truncateRenderToTokenBudget(lines);\n\tif (droppedLines === 0) return text;\n\n\tconst hint = readonly\n\t\t? \"narrow to a smaller or more targeted file\"\n\t\t: \"re-run with readonly:true for a smaller analysis-only view, or target a smaller file\";\n\treturn (\n\t\t`${text}\\n\\n[Truncated: document exceeds the ~${DOCREAD_MAX_RENDER_TOKENS} token render budget; ` +\n\t\t`${droppedLines} more node line${droppedLines === 1 ? \"\" : \"s\"} omitted. The ids shown are still valid for ` +\n\t\t`DocEdit/DocWrite — ${hint}.]`\n\t);\n}\n\nfunction formatDocReadCall(args: { path?: string; readonly?: boolean } | undefined): string {\n\tconst path = str(args?.path);\n\tconst pathDisplay =\n\t\tpath === null ? invalidArgText(appTheme) : path ? shortenPath(path) : appTheme.fg(\"toolOutput\", \"...\");\n\tlet text = appTheme.fg(\"toolTitle\", appTheme.bold(\"DocRead \")) + appTheme.fg(\"accent\", pathDisplay);\n\tif (args?.readonly) text += appTheme.fg(\"muted\", \" (readonly)\");\n\treturn text;\n}\n\nfunction formatDocReadResult(\n\tresult: { content: Array<{ type: string; text?: string }>; details?: DocReadToolDetails },\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result as any, showImages).trim();\n\tif (!output) return \"\";\n\tconst lines = output.split(\"\\n\");\n\tconst maxLines = options.expanded ? lines.length : 15;\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\tlet text = `\\n${displayLines.map((line) => appTheme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\tif (remaining > 0) {\n\t\ttext += `${appTheme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t}\n\treturn text;\n}\n\nexport function createDocReadToolDefinition(\n\tcwd: string,\n\toptions?: DocReadToolOptions,\n): ToolDefinition<typeof docReadSchema, DocReadToolDetails | undefined> {\n\treturn {\n\t\tname: \"DocRead\",\n\t\tlabel: \"DocRead\",\n\t\tdescription:\n\t\t\t\"Extract a structured or binary document (XML, drawio, docx/xlsx/pptx, PDF) into editable, id-addressed JSON the agent can patch losslessly. Each node has a stable #id; edit with DocEdit (in place) or DocWrite (to a new path), passing a patch that targets those ids. This is the canonical way to read and edit these formats: never fall back to ad-hoc scripts (python/openpyxl, docx, PyPDF2, unzip, sed) to parse or rewrite them — that loses the lossless id-map and corrupts formatting. Off by default; enabled with --enable-filetools.\",\n\t\tpromptSnippet: \"Extract a structured/binary document into editable, id-addressed JSON\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use DocRead to open structured/binary documents (XML, drawio, docx/xlsx/pptx, PDF) instead of read; it returns id-addressed nodes you can patch with DocEdit/DocWrite. Never fall back to ad-hoc scripts (python/openpyxl, docx, PyPDF2, unzip, sed) to parse or edit these formats — that loses the lossless id-map and corrupts the file.\",\n\t\t\t\"Flow: scan first, edit second. To understand a document, start with DocRead readonly:true — an analysis-only projection that strips node ids and is much cheaper in tokens. Only do a full (writable) DocRead when you actually intend to edit, since that view carries the whole id-map and is token-heavy.\",\n\t\t\t\"Read once, then edit. A writable DocRead establishes the id-map; DocEdit/DocWrite re-extract on their own, so do not re-run DocRead between edits. If a patch targets stale ids the edit fails and returns the current structure with fresh ids to re-issue against.\",\n\t\t],\n\t\tparameters: docReadSchema,\n\t\tasync execute(_toolCallId, { path, readonly }: DocReadToolInput, signal?: AbortSignal) {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\t\t\tconst envelope = await extractDocument(absolutePath, cwd, signal, {\n\t\t\t\treadonly,\n\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: renderEnvelopeText(envelope, readonly) }],\n\t\t\t\tdetails: {\n\t\t\t\t\ttype: envelope.source.type,\n\t\t\t\t\tfidelity: envelope.fidelity,\n\t\t\t\t\twritable: envelope.writable,\n\t\t\t\t\tnodeCount: countNodes(envelope.structure),\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDocReadCall(args));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDocReadResult(result as any, options, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDocReadTool(cwd: string, options?: DocReadToolOptions): AgentTool<typeof docReadSchema> {\n\treturn wrapToolDefinition(createDocReadToolDefinition(cwd, options));\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docread.js","sourceRoot":"","sources":["../../../../src/core/tools/doc/docread.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../../modes/interactive/components/keybinding-hints.js\";\nimport { theme as appTheme } from \"../../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../../extensions/types.js\";\nimport {\n\tDOCREAD_MAX_RENDER_TOKENS,\n\ttype DocNode,\n\ttype Envelope,\n\textractDocument,\n\trenderDocNodeLines,\n\ttruncateRenderToTokenBudget,\n} from \"../filetools-shared.js\";\nimport { resolveReadPath } from \"../path-utils.js\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"../render-utils.js\";\nimport { wrapToolDefinition } from \"../tool-definition-wrapper.js\";\n\nconst docReadSchema = Type.Object({\n\tpath: Type.String({\n\t\tdescription:\n\t\t\t\"Path to the document to extract (relative or absolute). XML, drawio, OOXML (docx/xlsx/pptx), or PDF.\",\n\t}),\n\treadonly: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"Analysis-only projection: strips node ids for a smaller view that CANNOT be edited. Omit (default false) when you intend to DocEdit/DocWrite afterwards.\",\n\t\t}),\n\t),\n});\n\nexport type DocReadToolInput = Static<typeof docReadSchema>;\n\nexport interface DocReadToolDetails {\n\ttype?: string;\n\tfidelity?: string;\n\twritable?: boolean;\n\tnodeCount?: number;\n}\n\nexport interface DocReadToolOptions {\n\t/** Timeout (seconds) for the filetools invocation. */\n\ttimeoutSecs?: number;\n}\n\nfunction countNodes(nodes: DocNode[]): number {\n\tlet total = 0;\n\tfor (const node of nodes) {\n\t\ttotal += 1 + (node.children ? countNodes(node.children) : 0);\n\t}\n\treturn total;\n}\n\n/**\n * Render the envelope as compact, id-addressed text the model edits against.\n * Each line carries the node id so DocEdit/DocWrite patches can target it.\n *\n * The filetools binary has no pagination, so a dense document can project into\n * a huge dump. We truncate the rendered view to a token budget and append an\n * actionable notice instead of flooding the model context.\n */\nexport function renderEnvelopeText(envelope: Envelope, readonly: boolean | undefined): string {\n\tconst header =\n\t\t`document ${envelope.source.path} [${envelope.source.type}, ${envelope.fidelity}, ` +\n\t\t`${envelope.writable ? \"writable\" : \"read-only\"}]`;\n\tconst lines: string[] = [header, \"\", ...renderDocNodeLines(envelope.structure)];\n\n\tconst { text, droppedLines } = truncateRenderToTokenBudget(lines);\n\tif (droppedLines === 0) return text;\n\n\tconst hint = readonly\n\t\t? \"narrow to a smaller or more targeted file\"\n\t\t: \"re-run with readonly:true for a smaller analysis-only view, or target a smaller file\";\n\treturn (\n\t\t`${text}\\n\\n[Truncated: document exceeds the ~${DOCREAD_MAX_RENDER_TOKENS} token render budget; ` +\n\t\t`${droppedLines} more node line${droppedLines === 1 ? \"\" : \"s\"} omitted. The ids shown are still valid for ` +\n\t\t`DocEdit/DocWrite — ${hint}.]`\n\t);\n}\n\nfunction formatDocReadCall(args: { path?: string; readonly?: boolean } | undefined): string {\n\tconst path = str(args?.path);\n\tconst pathDisplay =\n\t\tpath === null ? invalidArgText(appTheme) : path ? shortenPath(path) : appTheme.fg(\"toolOutput\", \"...\");\n\tlet text = appTheme.fg(\"toolTitle\", appTheme.bold(\"DocRead \")) + appTheme.fg(\"accent\", pathDisplay);\n\tif (args?.readonly) text += appTheme.fg(\"muted\", \" (readonly)\");\n\treturn text;\n}\n\nfunction formatDocReadResult(\n\tresult: { content: Array<{ type: string; text?: string }>; details?: DocReadToolDetails },\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result as any, showImages).trim();\n\tif (!output) return \"\";\n\tconst lines = output.split(\"\\n\");\n\tconst maxLines = options.expanded ? lines.length : 15;\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\tlet text = `\\n${displayLines.map((line) => appTheme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\tif (remaining > 0) {\n\t\ttext += `${appTheme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t}\n\treturn text;\n}\n\nexport function createDocReadToolDefinition(\n\tcwd: string,\n\toptions?: DocReadToolOptions,\n): ToolDefinition<typeof docReadSchema, DocReadToolDetails | undefined> {\n\treturn {\n\t\tname: \"DocRead\",\n\t\tlabel: \"DocRead\",\n\t\tdescription:\n\t\t\t\"Extract a structured or binary document (XML, drawio, docx/xlsx/pptx, PDF) into editable, id-addressed JSON the agent can patch losslessly. Each node has a stable #id; edit with DocEdit (in place) or DocWrite (to a new path), passing a patch that targets those ids. This is the canonical way to read and edit these formats: never fall back to ad-hoc scripts (python/openpyxl, docx, PyPDF2, unzip, sed) to parse or rewrite them — that loses the lossless id-map and corrupts formatting. Off by default; enabled with --enable-filetools.\",\n\t\tpromptSnippet: \"Extract a structured/binary document into editable, id-addressed JSON\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use DocRead to open structured/binary documents (XML, drawio, docx/xlsx/pptx, PDF) instead of read; it returns id-addressed nodes you can patch with DocEdit/DocWrite. Never fall back to ad-hoc scripts (python/openpyxl, docx, PyPDF2, unzip, sed) to parse or edit these formats — that loses the lossless id-map and corrupts the file.\",\n\t\t\t\"Flow: scan first, edit second. To understand a document, start with DocRead readonly:true — an analysis-only projection that strips node ids and is much cheaper in tokens. Only do a full (writable) DocRead when you actually intend to edit, since that view carries the whole id-map and is token-heavy.\",\n\t\t\t\"Read once, then edit. A writable DocRead establishes the id-map; DocEdit/DocWrite re-extract on their own, so do not re-run DocRead between edits. If a patch targets stale ids the edit fails and returns the current structure with fresh ids to re-issue against.\",\n\t\t],\n\t\tparameters: docReadSchema,\n\t\tasync execute(_toolCallId, { path, readonly }: DocReadToolInput, signal?: AbortSignal) {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\t\t\tconst envelope = await extractDocument(absolutePath, cwd, signal, {\n\t\t\t\treadonly,\n\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: renderEnvelopeText(envelope, readonly) }],\n\t\t\t\tdetails: {\n\t\t\t\t\ttype: envelope.source.type,\n\t\t\t\t\tfidelity: envelope.fidelity,\n\t\t\t\t\twritable: envelope.writable,\n\t\t\t\t\tnodeCount: countNodes(envelope.structure),\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDocReadCall(args));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDocReadResult(result as any, options, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDocReadTool(cwd: string, options?: DocReadToolOptions): AgentTool<typeof docReadSchema> {\n\treturn wrapToolDefinition(createDocReadToolDefinition(cwd, options));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"docread.js","sourceRoot":"","sources":["../../../../src/core/tools/doc/docread.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../../modes/interactive/components/keybinding-hints.js\";\nimport { theme as appTheme } from \"../../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../../extensions/types.js\";\nimport {\n\tDOCREAD_MAX_RENDER_TOKENS,\n\ttype DocNode,\n\ttype Envelope,\n\textractDocument,\n\trenderDocNodeLines,\n\ttruncateRenderToTokenBudget,\n} from \"../filetools-shared.js\";\nimport { resolveReadPath } from \"../path-utils.js\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"../render-utils.js\";\nimport { wrapToolDefinition } from \"../tool-definition-wrapper.js\";\n\nconst docReadSchema = Type.Object({\n\tpath: Type.String({\n\t\tdescription:\n\t\t\t\"Path to the document to extract (relative or absolute). XML, drawio, OOXML (docx/xlsx/pptx), or PDF.\",\n\t}),\n\treadonly: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"Analysis-only projection: strips node ids for a smaller view that CANNOT be edited. Omit (default false) when you intend to DocEdit/DocWrite afterwards.\",\n\t\t}),\n\t),\n});\n\ntype DocReadToolInput = Static<typeof docReadSchema>;\n\nexport interface DocReadToolDetails {\n\ttype?: string;\n\tfidelity?: string;\n\twritable?: boolean;\n\tnodeCount?: number;\n}\n\nexport interface DocReadToolOptions {\n\t/** Timeout (seconds) for the filetools invocation. */\n\ttimeoutSecs?: number;\n}\n\nfunction countNodes(nodes: DocNode[]): number {\n\tlet total = 0;\n\tfor (const node of nodes) {\n\t\ttotal += 1 + (node.children ? countNodes(node.children) : 0);\n\t}\n\treturn total;\n}\n\n/**\n * Render the envelope as compact, id-addressed text the model edits against.\n * Each line carries the node id so DocEdit/DocWrite patches can target it.\n *\n * The filetools binary has no pagination, so a dense document can project into\n * a huge dump. We truncate the rendered view to a token budget and append an\n * actionable notice instead of flooding the model context.\n */\nexport function renderEnvelopeText(envelope: Envelope, readonly: boolean | undefined): string {\n\tconst header =\n\t\t`document ${envelope.source.path} [${envelope.source.type}, ${envelope.fidelity}, ` +\n\t\t`${envelope.writable ? \"writable\" : \"read-only\"}]`;\n\tconst lines: string[] = [header, \"\", ...renderDocNodeLines(envelope.structure)];\n\n\tconst { text, droppedLines } = truncateRenderToTokenBudget(lines);\n\tif (droppedLines === 0) return text;\n\n\tconst hint = readonly\n\t\t? \"narrow to a smaller or more targeted file\"\n\t\t: \"re-run with readonly:true for a smaller analysis-only view, or target a smaller file\";\n\treturn (\n\t\t`${text}\\n\\n[Truncated: document exceeds the ~${DOCREAD_MAX_RENDER_TOKENS} token render budget; ` +\n\t\t`${droppedLines} more node line${droppedLines === 1 ? \"\" : \"s\"} omitted. The ids shown are still valid for ` +\n\t\t`DocEdit/DocWrite — ${hint}.]`\n\t);\n}\n\nfunction formatDocReadCall(args: { path?: string; readonly?: boolean } | undefined): string {\n\tconst path = str(args?.path);\n\tconst pathDisplay =\n\t\tpath === null ? invalidArgText(appTheme) : path ? shortenPath(path) : appTheme.fg(\"toolOutput\", \"...\");\n\tlet text = appTheme.fg(\"toolTitle\", appTheme.bold(\"DocRead \")) + appTheme.fg(\"accent\", pathDisplay);\n\tif (args?.readonly) text += appTheme.fg(\"muted\", \" (readonly)\");\n\treturn text;\n}\n\nfunction formatDocReadResult(\n\tresult: { content: Array<{ type: string; text?: string }>; details?: DocReadToolDetails },\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result as any, showImages).trim();\n\tif (!output) return \"\";\n\tconst lines = output.split(\"\\n\");\n\tconst maxLines = options.expanded ? lines.length : 15;\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\tlet text = `\\n${displayLines.map((line) => appTheme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\tif (remaining > 0) {\n\t\ttext += `${appTheme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t}\n\treturn text;\n}\n\nexport function createDocReadToolDefinition(\n\tcwd: string,\n\toptions?: DocReadToolOptions,\n): ToolDefinition<typeof docReadSchema, DocReadToolDetails | undefined> {\n\treturn {\n\t\tname: \"DocRead\",\n\t\tlabel: \"DocRead\",\n\t\tdescription:\n\t\t\t\"Extract a structured or binary document (XML, drawio, docx/xlsx/pptx, PDF) into editable, id-addressed JSON the agent can patch losslessly. Each node has a stable #id; edit with DocEdit (in place) or DocWrite (to a new path), passing a patch that targets those ids. This is the canonical way to read and edit these formats: never fall back to ad-hoc scripts (python/openpyxl, docx, PyPDF2, unzip, sed) to parse or rewrite them — that loses the lossless id-map and corrupts formatting. Off by default; enabled with --enable-filetools.\",\n\t\tpromptSnippet: \"Extract a structured/binary document into editable, id-addressed JSON\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use DocRead to open structured/binary documents (XML, drawio, docx/xlsx/pptx, PDF) instead of read; it returns id-addressed nodes you can patch with DocEdit/DocWrite. Never fall back to ad-hoc scripts (python/openpyxl, docx, PyPDF2, unzip, sed) to parse or edit these formats — that loses the lossless id-map and corrupts the file.\",\n\t\t\t\"Flow: scan first, edit second. To understand a document, start with DocRead readonly:true — an analysis-only projection that strips node ids and is much cheaper in tokens. Only do a full (writable) DocRead when you actually intend to edit, since that view carries the whole id-map and is token-heavy.\",\n\t\t\t\"Read once, then edit. A writable DocRead establishes the id-map; DocEdit/DocWrite re-extract on their own, so do not re-run DocRead between edits. If a patch targets stale ids the edit fails and returns the current structure with fresh ids to re-issue against.\",\n\t\t],\n\t\tparameters: docReadSchema,\n\t\tasync execute(_toolCallId, { path, readonly }: DocReadToolInput, signal?: AbortSignal) {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\t\t\tconst envelope = await extractDocument(absolutePath, cwd, signal, {\n\t\t\t\treadonly,\n\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: renderEnvelopeText(envelope, readonly) }],\n\t\t\t\tdetails: {\n\t\t\t\t\ttype: envelope.source.type,\n\t\t\t\t\tfidelity: envelope.fidelity,\n\t\t\t\t\twritable: envelope.writable,\n\t\t\t\t\tnodeCount: countNodes(envelope.structure),\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDocReadCall(args));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDocReadResult(result as any, options, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDocReadTool(cwd: string, options?: DocReadToolOptions): AgentTool<typeof docReadSchema> {\n\treturn wrapToolDefinition(createDocReadToolDefinition(cwd, options));\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AgentTool } from "@kolisachint/hoocode-agent-core";
|
|
2
|
-
import {
|
|
2
|
+
import { Type } from "typebox";
|
|
3
3
|
import type { ToolDefinition } from "../../extensions/types.js";
|
|
4
4
|
import { type ScanView } from "../filetools-shared.js";
|
|
5
5
|
declare const docScanSchema: Type.TObject<{
|
|
@@ -7,7 +7,6 @@ declare const docScanSchema: Type.TObject<{
|
|
|
7
7
|
offset: Type.TOptional<Type.TNumber>;
|
|
8
8
|
limit: Type.TOptional<Type.TNumber>;
|
|
9
9
|
}>;
|
|
10
|
-
export type DocScanToolInput = Static<typeof docScanSchema>;
|
|
11
10
|
export interface DocScanToolDetails {
|
|
12
11
|
fileType?: string;
|
|
13
12
|
returned?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docscan.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/doc/docscan.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAEjE,OAAO,
|
|
1
|
+
{"version":3,"file":"docscan.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/doc/docscan.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAEjE,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,2BAA2B,CAAC;AACzF,OAAO,EAAE,KAAK,QAAQ,EAA6C,MAAM,wBAAwB,CAAC;AAKlG,QAAA,MAAM,aAAa;;;;EAMjB,CAAC;AAIH,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IAClC,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CA2BrD;AAgCD,wBAAgB,2BAA2B,CAC1C,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,kBAAkB,GAC1B,cAAc,CAAC,OAAO,aAAa,EAAE,kBAAkB,GAAG,SAAS,CAAC,CAoCtE;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC,OAAO,aAAa,CAAC,CAE5G","sourcesContent":["import type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../../modes/interactive/components/keybinding-hints.js\";\nimport { theme as appTheme } from \"../../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../../extensions/types.js\";\nimport { type ScanView, scanDocument, truncateRenderToTokenBudget } from \"../filetools-shared.js\";\nimport { resolveReadPath } from \"../path-utils.js\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"../render-utils.js\";\nimport { wrapToolDefinition } from \"../tool-definition-wrapper.js\";\n\nconst docScanSchema = Type.Object({\n\tpath: Type.String({\n\t\tdescription: \"Path to the document to scan (relative or absolute). XML, drawio, OOXML (docx/xlsx/pptx), or PDF.\",\n\t}),\n\toffset: Type.Optional(Type.Number({ description: \"Skip the first N blocks (pagination). Default 0.\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of blocks to return. Default: all remaining.\" })),\n});\n\ntype DocScanToolInput = Static<typeof docScanSchema>;\n\nexport interface DocScanToolDetails {\n\tfileType?: string;\n\treturned?: number;\n\ttotal?: number;\n}\n\nexport interface DocScanToolOptions {\n\t/** Timeout (seconds) for the filetools invocation. */\n\ttimeoutSecs?: number;\n}\n\n/**\n * Render a scan manifest as compact, id-addressed preview lines. Each line\n * carries the block id (feeds DocPeek/DocGrep) plus a section label, token\n * estimate, and a short preview — structure without hydrating full content.\n */\nexport function renderScanView(view: ScanView): string {\n\tconst header =\n\t\t`document ${view.file_type} — ${view.returned}/${view.total} blocks ` +\n\t\t`(offset ${view.offset}, ~${view.total_tokens} tok total)`;\n\tconst lines: string[] = [header, \"\"];\n\tfor (const block of view.blocks) {\n\t\tconst section = block.section_name ? ` ${block.section_name}#${block.section_number}` : \"\";\n\t\tconst preview = block.preview ? ` :: ${JSON.stringify(block.preview)}` : \"\";\n\t\tlines.push(`#${block.id} [${block.block_type}]${section} ~${block.token_estimate}tok${preview}`);\n\t}\n\n\tconst { text, droppedLines } = truncateRenderToTokenBudget(lines);\n\tconst seen = view.offset + view.returned;\n\tconst remaining = view.total - seen;\n\tconst parts = [text];\n\tif (droppedLines > 0) {\n\t\tparts.push(\n\t\t\t`\\n[Truncated: ${droppedLines} more block line${droppedLines === 1 ? \"\" : \"s\"} omitted from this render. ` +\n\t\t\t\t`Re-run with a tighter limit, or DocGrep/DocPeek to target.]`,\n\t\t);\n\t}\n\tif (remaining > 0) {\n\t\tparts.push(\n\t\t\t`\\n[${remaining} more block${remaining === 1 ? \"\" : \"s\"} not shown — re-run with offset:${seen} to continue.]`,\n\t\t);\n\t}\n\treturn parts.join(\"\\n\");\n}\n\nfunction formatDocScanCall(args: { path?: string; offset?: number; limit?: number } | undefined): string {\n\tconst path = str(args?.path);\n\tconst pathDisplay =\n\t\tpath === null ? invalidArgText(appTheme) : path ? shortenPath(path) : appTheme.fg(\"toolOutput\", \"...\");\n\tlet text = appTheme.fg(\"toolTitle\", appTheme.bold(\"DocScan \")) + appTheme.fg(\"accent\", pathDisplay);\n\tconst range: string[] = [];\n\tif (args?.offset !== undefined) range.push(`offset ${args.offset}`);\n\tif (args?.limit !== undefined) range.push(`limit ${args.limit}`);\n\tif (range.length > 0) text += appTheme.fg(\"muted\", ` (${range.join(\", \")})`);\n\treturn text;\n}\n\nfunction formatDocScanResult(\n\tresult: { content: Array<{ type: string; text?: string }> },\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result as any, showImages).trim();\n\tif (!output) return \"\";\n\tconst lines = output.split(\"\\n\");\n\tconst maxLines = options.expanded ? lines.length : 15;\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\tlet text = `\\n${displayLines.map((line) => appTheme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\tif (remaining > 0) {\n\t\ttext += `${appTheme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t}\n\treturn text;\n}\n\nexport function createDocScanToolDefinition(\n\tcwd: string,\n\toptions?: DocScanToolOptions,\n): ToolDefinition<typeof docScanSchema, DocScanToolDetails | undefined> {\n\treturn {\n\t\tname: \"DocScan\",\n\t\tlabel: \"DocScan\",\n\t\tdescription:\n\t\t\t\"Cheaply outline a structured/binary document (XML, drawio, docx/xlsx/pptx, PDF) without hydrating it: returns a paginated manifest of blocks, each with a structural-path id, type, section label, token estimate, and a short preview. This is the cheap first step of the token-sensitive loop — far smaller than a full DocRead. Pass the path ids it returns to DocPeek to hydrate just those blocks (the hydrated nodes carry the editable el_ #ids for DocEdit). Off by default; enabled with --enable-filetools.\",\n\t\tpromptSnippet: \"Outline a structured/binary document into a cheap, paginated block manifest\",\n\t\tpromptGuidelines: [\n\t\t\t\"Start here for large structured/binary documents instead of a full DocRead: DocScan returns a paginated outline (structural-path block ids + previews) that is much cheaper in tokens. Page through it with offset/limit.\",\n\t\t\t\"Flow: DocScan to see structure → DocPeek the path ids you want (hydrates them and reveals their editable el_ #ids) → DocEdit. Or jump straight in with DocGrep, which finds blocks by text and returns editable el_ #ids directly.\",\n\t\t],\n\t\tparameters: docScanSchema,\n\t\tasync execute(_toolCallId, { path, offset, limit }: DocScanToolInput, signal?: AbortSignal) {\n\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\n\t\t\tconst view = await scanDocument(absolutePath, cwd, signal, {\n\t\t\t\toffset,\n\t\t\t\tlimit,\n\t\t\t\ttimeoutSecs: options?.timeoutSecs,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: renderScanView(view) }],\n\t\t\t\tdetails: { fileType: view.file_type, returned: view.returned, total: view.total },\n\t\t\t};\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDocScanCall(args));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatDocScanResult(result as any, options, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createDocScanTool(cwd: string, options?: DocScanToolOptions): AgentTool<typeof docScanSchema> {\n\treturn wrapToolDefinition(createDocScanToolDefinition(cwd, options));\n}\n"]}
|