@oh-my-pi/pi-coding-agent 12.18.3 → 12.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +47 -0
- package/package.json +7 -7
- package/src/async/index.ts +1 -0
- package/src/async/job-manager.ts +341 -0
- package/src/cli/file-processor.ts +3 -3
- package/src/cli/list-models.ts +3 -17
- package/src/cli/stats-cli.ts +3 -22
- package/src/cli/web-search-cli.ts +8 -16
- package/src/commit/agentic/agent.ts +6 -9
- package/src/commit/agentic/index.ts +44 -50
- package/src/commit/agentic/state.ts +0 -9
- package/src/commit/agentic/tools/propose-commit.ts +1 -30
- package/src/commit/agentic/tools/schemas.ts +31 -0
- package/src/commit/agentic/tools/split-commit.ts +1 -30
- package/src/commit/agentic/validation.ts +1 -18
- package/src/commit/analysis/conventional.ts +3 -50
- package/src/commit/analysis/summary.ts +2 -13
- package/src/commit/changelog/detect.ts +4 -1
- package/src/commit/changelog/generate.ts +2 -25
- package/src/commit/changelog/index.ts +1 -2
- package/src/commit/cli.ts +4 -12
- package/src/commit/map-reduce/reduce-phase.ts +2 -43
- package/src/commit/pipeline.ts +7 -15
- package/src/commit/utils.ts +44 -0
- package/src/config/prompt-templates.ts +1 -81
- package/src/config/settings-schema.ts +20 -1
- package/src/config.ts +2 -3
- package/src/debug/index.ts +1 -6
- package/src/debug/system-info.ts +2 -6
- package/src/discovery/builtin.ts +5 -9
- package/src/discovery/helpers.ts +0 -26
- package/src/discovery/ssh.ts +1 -8
- package/src/exa/company.ts +8 -39
- package/src/exa/factory.ts +64 -0
- package/src/exa/index.ts +0 -16
- package/src/exa/linkedin.ts +8 -39
- package/src/exa/mcp-client.ts +0 -64
- package/src/exa/researcher.ts +17 -59
- package/src/exa/search.ts +30 -154
- package/src/extensibility/custom-tools/loader.ts +3 -41
- package/src/extensibility/extensions/loader.ts +2 -9
- package/src/extensibility/hooks/loader.ts +3 -20
- package/src/extensibility/hooks/runner.ts +3 -19
- package/src/extensibility/plugins/installer.ts +2 -1
- package/src/extensibility/plugins/loader.ts +29 -117
- package/src/extensibility/skills.ts +2 -89
- package/src/extensibility/slash-commands.ts +1 -63
- package/src/extensibility/utils.ts +38 -0
- package/src/index.ts +9 -25
- package/src/internal-urls/index.ts +1 -0
- package/src/internal-urls/jobs-protocol.ts +118 -0
- package/src/ipy/kernel.ts +2 -0
- package/src/lsp/config.ts +1 -5
- package/src/lsp/lspmux.ts +0 -17
- package/src/lsp/utils.ts +2 -24
- package/src/main.ts +16 -24
- package/src/mcp/client.ts +1 -46
- package/src/mcp/render.ts +8 -1
- package/src/mcp/tool-cache.ts +1 -5
- package/src/mcp/transports/http.ts +2 -7
- package/src/mcp/transports/stdio.ts +2 -7
- package/src/modes/components/bash-execution.ts +2 -16
- package/src/modes/components/extensions/inspector-panel.ts +8 -18
- package/src/modes/components/footer.ts +10 -50
- package/src/modes/components/model-selector.ts +2 -21
- package/src/modes/components/python-execution.ts +2 -16
- package/src/modes/components/settings-selector.ts +1 -10
- package/src/modes/components/status-line/segments.ts +8 -25
- package/src/modes/components/status-line.ts +14 -31
- package/src/modes/components/tool-execution.ts +8 -2
- package/src/modes/controllers/command-controller.ts +71 -30
- package/src/modes/controllers/event-controller.ts +34 -4
- package/src/modes/controllers/mcp-command-controller.ts +3 -34
- package/src/modes/controllers/selector-controller.ts +2 -2
- package/src/modes/controllers/ssh-command-controller.ts +3 -34
- package/src/modes/interactive-mode.ts +6 -2
- package/src/modes/rpc/rpc-client.ts +1 -5
- package/src/modes/shared.ts +73 -0
- package/src/modes/types.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +26 -2
- package/src/patch/index.ts +4 -4
- package/src/patch/normalize.ts +22 -65
- package/src/patch/shared.ts +16 -16
- package/src/prompts/system/custom-system-prompt.md +0 -10
- package/src/prompts/system/system-prompt.md +69 -89
- package/src/prompts/tools/async-result.md +5 -0
- package/src/prompts/tools/bash.md +5 -0
- package/src/prompts/tools/cancel-job.md +7 -0
- package/src/prompts/tools/poll-jobs.md +7 -0
- package/src/prompts/tools/task.md +4 -0
- package/src/sdk.ts +70 -6
- package/src/session/agent-session.ts +40 -6
- package/src/session/agent-storage.ts +69 -278
- package/src/session/auth-storage.ts +14 -1430
- package/src/session/session-manager.ts +69 -5
- package/src/session/session-storage.ts +1 -5
- package/src/session/streaming-output.ts +637 -76
- package/src/slash-commands/builtin-registry.ts +8 -0
- package/src/ssh/connection-manager.ts +4 -12
- package/src/ssh/sshfs-mount.ts +3 -7
- package/src/ssh/utils.ts +8 -0
- package/src/system-prompt.ts +24 -90
- package/src/task/executor.ts +11 -1
- package/src/task/index.ts +258 -13
- package/src/task/parallel.ts +32 -0
- package/src/task/render.ts +15 -7
- package/src/task/types.ts +5 -0
- package/src/tools/ask.ts +4 -7
- package/src/tools/bash-interactive.ts +4 -5
- package/src/tools/bash.ts +125 -41
- package/src/tools/cancel-job.ts +93 -0
- package/src/tools/fetch.ts +7 -27
- package/src/tools/find.ts +3 -3
- package/src/tools/gemini-image.ts +15 -14
- package/src/tools/grep.ts +3 -3
- package/src/tools/index.ts +13 -29
- package/src/tools/json-tree.ts +12 -1
- package/src/tools/jtd-to-json-schema.ts +10 -74
- package/src/tools/jtd-to-typescript.ts +10 -72
- package/src/tools/jtd-utils.ts +102 -0
- package/src/tools/notebook.ts +4 -9
- package/src/tools/output-meta.ts +52 -26
- package/src/tools/path-utils.ts +13 -7
- package/src/tools/poll-jobs.ts +178 -0
- package/src/tools/python.ts +32 -35
- package/src/tools/read.ts +61 -82
- package/src/tools/render-utils.ts +8 -159
- package/src/tools/ssh.ts +7 -20
- package/src/tools/submit-result.ts +1 -1
- package/src/tools/tool-errors.ts +0 -30
- package/src/tools/tool-result.ts +1 -2
- package/src/tools/write.ts +8 -10
- package/src/tui/code-cell.ts +8 -3
- package/src/tui/status-line.ts +4 -4
- package/src/tui/types.ts +0 -1
- package/src/tui/utils.ts +1 -14
- package/src/utils/command-args.ts +76 -0
- package/src/utils/file-mentions.ts +15 -19
- package/src/utils/frontmatter.ts +5 -10
- package/src/utils/shell-snapshot.ts +0 -11
- package/src/utils/title-generator.ts +0 -12
- package/src/web/scrapers/artifacthub.ts +7 -16
- package/src/web/scrapers/arxiv.ts +3 -8
- package/src/web/scrapers/aur.ts +8 -22
- package/src/web/scrapers/biorxiv.ts +5 -14
- package/src/web/scrapers/bluesky.ts +13 -36
- package/src/web/scrapers/brew.ts +5 -10
- package/src/web/scrapers/cheatsh.ts +2 -12
- package/src/web/scrapers/chocolatey.ts +63 -26
- package/src/web/scrapers/choosealicense.ts +3 -18
- package/src/web/scrapers/cisa-kev.ts +4 -18
- package/src/web/scrapers/clojars.ts +6 -33
- package/src/web/scrapers/coingecko.ts +25 -33
- package/src/web/scrapers/crates-io.ts +7 -26
- package/src/web/scrapers/crossref.ts +4 -18
- package/src/web/scrapers/devto.ts +11 -41
- package/src/web/scrapers/discogs.ts +7 -10
- package/src/web/scrapers/discourse.ts +6 -31
- package/src/web/scrapers/dockerhub.ts +12 -35
- package/src/web/scrapers/fdroid.ts +8 -33
- package/src/web/scrapers/firefox-addons.ts +10 -34
- package/src/web/scrapers/flathub.ts +7 -24
- package/src/web/scrapers/github-gist.ts +2 -12
- package/src/web/scrapers/github.ts +9 -47
- package/src/web/scrapers/gitlab.ts +130 -185
- package/src/web/scrapers/go-pkg.ts +12 -22
- package/src/web/scrapers/hackage.ts +88 -43
- package/src/web/scrapers/hackernews.ts +25 -45
- package/src/web/scrapers/hex.ts +19 -36
- package/src/web/scrapers/huggingface.ts +26 -91
- package/src/web/scrapers/iacr.ts +3 -8
- package/src/web/scrapers/jetbrains-marketplace.ts +9 -20
- package/src/web/scrapers/lemmy.ts +5 -23
- package/src/web/scrapers/lobsters.ts +16 -28
- package/src/web/scrapers/mastodon.ts +24 -43
- package/src/web/scrapers/maven.ts +6 -21
- package/src/web/scrapers/mdn.ts +7 -11
- package/src/web/scrapers/metacpan.ts +9 -41
- package/src/web/scrapers/musicbrainz.ts +4 -28
- package/src/web/scrapers/npm.ts +8 -25
- package/src/web/scrapers/nuget.ts +14 -37
- package/src/web/scrapers/nvd.ts +6 -28
- package/src/web/scrapers/ollama.ts +7 -34
- package/src/web/scrapers/open-vsx.ts +5 -19
- package/src/web/scrapers/opencorporates.ts +30 -14
- package/src/web/scrapers/openlibrary.ts +49 -33
- package/src/web/scrapers/orcid.ts +4 -18
- package/src/web/scrapers/osv.ts +7 -24
- package/src/web/scrapers/packagist.ts +9 -24
- package/src/web/scrapers/pub-dev.ts +7 -50
- package/src/web/scrapers/pubmed.ts +54 -21
- package/src/web/scrapers/pypi.ts +8 -26
- package/src/web/scrapers/rawg.ts +11 -19
- package/src/web/scrapers/readthedocs.ts +4 -9
- package/src/web/scrapers/reddit.ts +5 -15
- package/src/web/scrapers/repology.ts +8 -20
- package/src/web/scrapers/rfc.ts +5 -14
- package/src/web/scrapers/rubygems.ts +6 -21
- package/src/web/scrapers/searchcode.ts +8 -36
- package/src/web/scrapers/sec-edgar.ts +4 -18
- package/src/web/scrapers/semantic-scholar.ts +15 -35
- package/src/web/scrapers/snapcraft.ts +5 -19
- package/src/web/scrapers/sourcegraph.ts +5 -43
- package/src/web/scrapers/spdx.ts +4 -18
- package/src/web/scrapers/spotify.ts +4 -23
- package/src/web/scrapers/stackoverflow.ts +8 -13
- package/src/web/scrapers/terraform.ts +9 -37
- package/src/web/scrapers/tldr.ts +3 -7
- package/src/web/scrapers/twitter.ts +3 -7
- package/src/web/scrapers/types.ts +105 -27
- package/src/web/scrapers/utils.ts +97 -103
- package/src/web/scrapers/vimeo.ts +7 -27
- package/src/web/scrapers/vscode-marketplace.ts +8 -17
- package/src/web/scrapers/w3c.ts +6 -14
- package/src/web/scrapers/wikidata.ts +5 -19
- package/src/web/scrapers/wikipedia.ts +2 -12
- package/src/web/scrapers/youtube.ts +5 -34
- package/src/web/search/index.ts +0 -9
- package/src/web/search/providers/anthropic.ts +3 -2
- package/src/web/search/providers/brave.ts +3 -18
- package/src/web/search/providers/exa.ts +1 -12
- package/src/web/search/providers/kimi.ts +5 -44
- package/src/web/search/providers/perplexity.ts +1 -12
- package/src/web/search/providers/synthetic.ts +3 -26
- package/src/web/search/providers/utils.ts +36 -0
- package/src/web/search/providers/zai.ts +9 -50
- package/src/web/search/types.ts +0 -28
- package/src/web/search/utils.ts +17 -0
- package/src/tools/output-utils.ts +0 -63
- package/src/tools/truncate.ts +0 -385
- package/src/web/search/auth.ts +0 -178
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as os from "node:os";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { getAntigravityHeaders, getEnvApiKey, StringEnum } from "@oh-my-pi/pi-ai";
|
|
4
|
-
import { $env, ptree, readSseJson, Snowflake, untilAborted } from "@oh-my-pi/pi-utils";
|
|
4
|
+
import { $env, isEnoent, ptree, readSseJson, Snowflake, untilAborted } from "@oh-my-pi/pi-utils";
|
|
5
5
|
import { type Static, Type } from "@sinclair/typebox";
|
|
6
6
|
import type { ModelRegistry } from "../config/model-registry";
|
|
7
7
|
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
@@ -428,21 +428,22 @@ async function findImageApiKey(modelRegistry?: ModelRegistry): Promise<ImageApiK
|
|
|
428
428
|
|
|
429
429
|
async function loadImageFromPath(imagePath: string, cwd: string): Promise<InlineImageData> {
|
|
430
430
|
const resolved = resolveReadPath(imagePath, cwd);
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
throw new Error(`Image file too large: ${imagePath}`);
|
|
437
|
-
}
|
|
431
|
+
try {
|
|
432
|
+
const buffer = await Bun.file(resolved).bytes();
|
|
433
|
+
if (buffer.length > MAX_IMAGE_SIZE) {
|
|
434
|
+
throw new Error(`Image file too large: ${imagePath}`);
|
|
435
|
+
}
|
|
438
436
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
437
|
+
const mimeType = await detectSupportedImageMimeTypeFromFile(resolved);
|
|
438
|
+
if (!mimeType) {
|
|
439
|
+
throw new Error(`Unsupported image type: ${imagePath}`);
|
|
440
|
+
}
|
|
443
441
|
|
|
444
|
-
|
|
445
|
-
|
|
442
|
+
return { data: buffer.toBase64(), mimeType };
|
|
443
|
+
} catch (err) {
|
|
444
|
+
if (isEnoent(err)) throw new Error(`Image file not found: ${imagePath}`);
|
|
445
|
+
throw err;
|
|
446
|
+
}
|
|
446
447
|
}
|
|
447
448
|
|
|
448
449
|
async function resolveInputImage(input: ImageInput, cwd: string): Promise<InlineImageData> {
|
package/src/tools/grep.ts
CHANGED
|
@@ -11,15 +11,15 @@ import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
|
11
11
|
import type { Theme } from "../modes/theme/theme";
|
|
12
12
|
import { computeLineHash } from "../patch/hashline";
|
|
13
13
|
import grepDescription from "../prompts/tools/grep.md" with { type: "text" };
|
|
14
|
+
import { DEFAULT_MAX_COLUMN, type TruncationResult, truncateHead } from "../session/streaming-output";
|
|
14
15
|
import { Ellipsis, Hasher, type RenderCache, renderStatusLine, renderTreeList, truncateToWidth } from "../tui";
|
|
15
16
|
import { resolveFileDisplayMode } from "../utils/file-display-mode";
|
|
16
17
|
import type { ToolSession } from ".";
|
|
17
|
-
import type
|
|
18
|
+
import { formatFullOutputReference, type OutputMeta } from "./output-meta";
|
|
18
19
|
import { resolveToCwd } from "./path-utils";
|
|
19
20
|
import { formatCount, formatEmptyMessage, formatErrorMessage, PREVIEW_LIMITS } from "./render-utils";
|
|
20
21
|
import { ToolError } from "./tool-errors";
|
|
21
22
|
import { toolResult } from "./tool-result";
|
|
22
|
-
import { DEFAULT_MAX_COLUMN, type TruncationResult, truncateHead } from "./truncate";
|
|
23
23
|
|
|
24
24
|
const grepSchema = Type.Object({
|
|
25
25
|
pattern: Type.String({ description: "Regex pattern to search for" }),
|
|
@@ -452,7 +452,7 @@ export const grepToolRenderer = {
|
|
|
452
452
|
if (limits?.resultLimit) truncationReasons.push(`limit ${limits.resultLimit.reached} results`);
|
|
453
453
|
if (truncation) truncationReasons.push(truncation.truncatedBy === "lines" ? "line limit" : "size limit");
|
|
454
454
|
if (limits?.columnTruncated) truncationReasons.push(`line length ${limits.columnTruncated.maxColumn}`);
|
|
455
|
-
if (truncation?.artifactId) truncationReasons.push(
|
|
455
|
+
if (truncation?.artifactId) truncationReasons.push(formatFullOutputReference(truncation.artifactId));
|
|
456
456
|
|
|
457
457
|
const extraLines =
|
|
458
458
|
truncationReasons.length > 0 ? [uiTheme.fg("warning", `truncated: ${truncationReasons.join(", ")}`)] : [];
|
package/src/tools/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AgentTool } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import { $env, logger } from "@oh-my-pi/pi-utils";
|
|
3
|
+
import type { AsyncJobManager } from "../async";
|
|
3
4
|
import type { PromptTemplate } from "../config/prompt-templates";
|
|
4
5
|
import type { Settings } from "../config/settings";
|
|
5
6
|
import type { Skill } from "../extensibility/skills";
|
|
@@ -9,7 +10,6 @@ import { checkPythonKernelAvailability } from "../ipy/kernel";
|
|
|
9
10
|
import { LspTool } from "../lsp";
|
|
10
11
|
import { EditTool } from "../patch";
|
|
11
12
|
import type { PlanModeState } from "../plan-mode/state";
|
|
12
|
-
import type { ArtifactManager } from "../session/artifacts";
|
|
13
13
|
import { TaskTool } from "../task";
|
|
14
14
|
import type { AgentOutputManager } from "../task/output-manager";
|
|
15
15
|
import type { EventBus } from "../utils/event-bus";
|
|
@@ -18,12 +18,14 @@ import { AskTool } from "./ask";
|
|
|
18
18
|
import { BashTool } from "./bash";
|
|
19
19
|
import { BrowserTool } from "./browser";
|
|
20
20
|
import { CalculatorTool } from "./calculator";
|
|
21
|
+
import { CancelJobTool } from "./cancel-job";
|
|
21
22
|
import { ExitPlanModeTool } from "./exit-plan-mode";
|
|
22
23
|
import { FetchTool } from "./fetch";
|
|
23
24
|
import { FindTool } from "./find";
|
|
24
25
|
import { GrepTool } from "./grep";
|
|
25
26
|
import { NotebookTool } from "./notebook";
|
|
26
27
|
import { wrapToolWithMetaNotice } from "./output-meta";
|
|
28
|
+
import { PollJobsTool } from "./poll-jobs";
|
|
27
29
|
import { PythonTool } from "./python";
|
|
28
30
|
import { ReadTool } from "./read";
|
|
29
31
|
import { reportFindingTool } from "./review";
|
|
@@ -48,49 +50,27 @@ export {
|
|
|
48
50
|
warmupLspServers,
|
|
49
51
|
} from "../lsp";
|
|
50
52
|
export { EditTool, type EditToolDetails } from "../patch";
|
|
53
|
+
export * from "../session/streaming-output";
|
|
51
54
|
export { BUNDLED_AGENTS, TaskTool } from "../task";
|
|
52
|
-
export
|
|
53
|
-
companySearchTools,
|
|
54
|
-
exaSearchTools,
|
|
55
|
-
getSearchTools,
|
|
56
|
-
type SearchProvider,
|
|
57
|
-
type SearchResponse,
|
|
58
|
-
SearchTool,
|
|
59
|
-
type SearchToolsOptions,
|
|
60
|
-
setPreferredSearchProvider,
|
|
61
|
-
webSearchCodeContextTool,
|
|
62
|
-
webSearchCompanyTool,
|
|
63
|
-
webSearchCrawlTool,
|
|
64
|
-
webSearchCustomTool,
|
|
65
|
-
webSearchDeepTool,
|
|
66
|
-
webSearchLinkedinTool,
|
|
67
|
-
} from "../web/search";
|
|
55
|
+
export * from "../web/search";
|
|
68
56
|
export { AskTool, type AskToolDetails } from "./ask";
|
|
69
57
|
export { BashTool, type BashToolDetails, type BashToolInput, type BashToolOptions } from "./bash";
|
|
70
58
|
export { BrowserTool, type BrowserToolDetails } from "./browser";
|
|
71
59
|
export { CalculatorTool, type CalculatorToolDetails } from "./calculator";
|
|
60
|
+
export { CancelJobTool, type CancelJobToolDetails } from "./cancel-job";
|
|
72
61
|
export { type ExitPlanModeDetails, ExitPlanModeTool } from "./exit-plan-mode";
|
|
73
62
|
export { FetchTool, type FetchToolDetails } from "./fetch";
|
|
74
63
|
export { type FindOperations, FindTool, type FindToolDetails, type FindToolInput, type FindToolOptions } from "./find";
|
|
75
64
|
export { setPreferredImageProvider } from "./gemini-image";
|
|
76
65
|
export { GrepTool, type GrepToolDetails, type GrepToolInput } from "./grep";
|
|
77
66
|
export { NotebookTool, type NotebookToolDetails } from "./notebook";
|
|
67
|
+
export { PollJobsTool, type PollJobsToolDetails } from "./poll-jobs";
|
|
78
68
|
export { PythonTool, type PythonToolDetails, type PythonToolOptions } from "./python";
|
|
79
69
|
export { ReadTool, type ReadToolDetails, type ReadToolInput } from "./read";
|
|
80
70
|
export { reportFindingTool, type SubmitReviewDetails } from "./review";
|
|
81
71
|
export { loadSshTool, type SSHToolDetails, SshTool } from "./ssh";
|
|
82
72
|
export { SubmitResultTool } from "./submit-result";
|
|
83
73
|
export { type TodoItem, TodoWriteTool, type TodoWriteToolDetails } from "./todo-write";
|
|
84
|
-
export {
|
|
85
|
-
DEFAULT_MAX_BYTES,
|
|
86
|
-
DEFAULT_MAX_LINES,
|
|
87
|
-
formatSize,
|
|
88
|
-
type TruncationOptions,
|
|
89
|
-
type TruncationResult,
|
|
90
|
-
truncateHead,
|
|
91
|
-
truncateLine,
|
|
92
|
-
truncateTail,
|
|
93
|
-
} from "./truncate";
|
|
94
74
|
export { WriteTool, type WriteToolDetails, type WriteToolInput } from "./write";
|
|
95
75
|
|
|
96
76
|
/** Tool type (AgentTool from pi-ai) */
|
|
@@ -132,10 +112,10 @@ export interface ToolSession {
|
|
|
132
112
|
getSessionFile: () => string | null;
|
|
133
113
|
/** Get session ID */
|
|
134
114
|
getSessionId?: () => string | null;
|
|
135
|
-
/** Cached artifact manager (allocated per ToolSession) */
|
|
136
|
-
artifactManager?: ArtifactManager;
|
|
137
115
|
/** Get artifacts directory for artifact:// URLs and $ARTIFACTS env var */
|
|
138
116
|
getArtifactsDir?: () => string | null;
|
|
117
|
+
/** Allocate a new artifact path and ID for session-scoped truncated output. */
|
|
118
|
+
allocateOutputArtifact?: (toolType: string) => Promise<{ id?: string; path?: string }>;
|
|
139
119
|
/** Get session spawns */
|
|
140
120
|
getSessionSpawns: () => string | null;
|
|
141
121
|
/** Get resolved model string if explicitly set for this session */
|
|
@@ -152,6 +132,8 @@ export interface ToolSession {
|
|
|
152
132
|
internalRouter?: InternalUrlRouter;
|
|
153
133
|
/** Agent output manager for unique agent:// IDs across task invocations */
|
|
154
134
|
agentOutputManager?: AgentOutputManager;
|
|
135
|
+
/** Async background job manager for bash/task async execution */
|
|
136
|
+
asyncJobManager?: AsyncJobManager;
|
|
155
137
|
/** Settings instance for passing to subagents */
|
|
156
138
|
settings: Settings;
|
|
157
139
|
/** Plan mode state (if active) */
|
|
@@ -176,6 +158,8 @@ export const BUILTIN_TOOLS: Record<string, ToolFactory> = {
|
|
|
176
158
|
read: s => new ReadTool(s),
|
|
177
159
|
browser: s => new BrowserTool(s),
|
|
178
160
|
task: TaskTool.create,
|
|
161
|
+
cancel_job: CancelJobTool.createIf,
|
|
162
|
+
poll_jobs: PollJobsTool.createIf,
|
|
179
163
|
todo_write: s => new TodoWriteTool(s),
|
|
180
164
|
fetch: s => new FetchTool(s),
|
|
181
165
|
web_search: s => new SearchTool(s),
|
package/src/tools/json-tree.ts
CHANGED
|
@@ -12,6 +12,17 @@ export const JSON_TREE_MAX_LINES_EXPANDED = 200;
|
|
|
12
12
|
export const JSON_TREE_SCALAR_LEN_COLLAPSED = 60;
|
|
13
13
|
export const JSON_TREE_SCALAR_LEN_EXPANDED = 2000;
|
|
14
14
|
|
|
15
|
+
/** Keys injected by the harness that should not be displayed to users */
|
|
16
|
+
const HIDDEN_ARG_KEYS = new Set(["agent__intent"]);
|
|
17
|
+
|
|
18
|
+
/** Strip harness-internal keys from tool args for display */
|
|
19
|
+
export function stripInternalArgs(args: Record<string, unknown>): Record<string, unknown> {
|
|
20
|
+
const result: Record<string, unknown> = {};
|
|
21
|
+
for (const [key, value] of Object.entries(args)) {
|
|
22
|
+
if (!HIDDEN_ARG_KEYS.has(key)) result[key] = value;
|
|
23
|
+
}
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
15
26
|
/**
|
|
16
27
|
* Format a scalar value for inline display.
|
|
17
28
|
*/
|
|
@@ -37,7 +48,7 @@ export function formatScalar(value: unknown, maxLen: number): string {
|
|
|
37
48
|
* Format args inline for collapsed view.
|
|
38
49
|
*/
|
|
39
50
|
export function formatArgsInline(args: Record<string, unknown>, maxWidth: number): string {
|
|
40
|
-
const entries = Object.entries(args);
|
|
51
|
+
const entries = Object.entries(args).filter(([k]) => !HIDDEN_ARG_KEYS.has(k));
|
|
41
52
|
if (entries.length === 0) return "";
|
|
42
53
|
|
|
43
54
|
// Single arg: show key=value
|
|
@@ -8,52 +8,16 @@
|
|
|
8
8
|
* @see https://datatracker.ietf.org/doc/html/rfc8927
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
type JTDPrimitive
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
| "int32"
|
|
22
|
-
| "uint32";
|
|
23
|
-
|
|
24
|
-
interface JTDType {
|
|
25
|
-
type: JTDPrimitive;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
interface JTDEnum {
|
|
29
|
-
enum: string[];
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
interface JTDElements {
|
|
33
|
-
elements: JTDSchema;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
interface JTDValues {
|
|
37
|
-
values: JTDSchema;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
interface JTDProperties {
|
|
41
|
-
properties?: Record<string, JTDSchema>;
|
|
42
|
-
optionalProperties?: Record<string, JTDSchema>;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
interface JTDDiscriminator {
|
|
46
|
-
discriminator: string;
|
|
47
|
-
mapping: Record<string, JTDProperties>;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
interface JTDRef {
|
|
51
|
-
ref: string;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
interface JTDEmpty {}
|
|
55
|
-
|
|
56
|
-
type JTDSchema = JTDType | JTDEnum | JTDElements | JTDValues | JTDProperties | JTDDiscriminator | JTDRef | JTDEmpty;
|
|
11
|
+
import type { JTDPrimitive } from "./jtd-utils.js";
|
|
12
|
+
import {
|
|
13
|
+
isJTDDiscriminator,
|
|
14
|
+
isJTDElements,
|
|
15
|
+
isJTDEnum,
|
|
16
|
+
isJTDProperties,
|
|
17
|
+
isJTDRef,
|
|
18
|
+
isJTDType,
|
|
19
|
+
isJTDValues,
|
|
20
|
+
} from "./jtd-utils.js";
|
|
57
21
|
|
|
58
22
|
const primitiveMap: Record<JTDPrimitive, string> = {
|
|
59
23
|
boolean: "boolean",
|
|
@@ -69,34 +33,6 @@ const primitiveMap: Record<JTDPrimitive, string> = {
|
|
|
69
33
|
uint32: "integer",
|
|
70
34
|
};
|
|
71
35
|
|
|
72
|
-
function isJTDType(schema: unknown): schema is JTDType {
|
|
73
|
-
return typeof schema === "object" && schema !== null && "type" in schema;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function isJTDEnum(schema: unknown): schema is JTDEnum {
|
|
77
|
-
return typeof schema === "object" && schema !== null && "enum" in schema;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function isJTDElements(schema: unknown): schema is JTDElements {
|
|
81
|
-
return typeof schema === "object" && schema !== null && "elements" in schema;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function isJTDValues(schema: unknown): schema is JTDValues {
|
|
85
|
-
return typeof schema === "object" && schema !== null && "values" in schema;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function isJTDProperties(schema: unknown): schema is JTDProperties {
|
|
89
|
-
return typeof schema === "object" && schema !== null && ("properties" in schema || "optionalProperties" in schema);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function isJTDDiscriminator(schema: unknown): schema is JTDDiscriminator {
|
|
93
|
-
return typeof schema === "object" && schema !== null && "discriminator" in schema;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function isJTDRef(schema: unknown): schema is JTDRef {
|
|
97
|
-
return typeof schema === "object" && schema !== null && "ref" in schema;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
36
|
function convertSchema(schema: unknown): unknown {
|
|
101
37
|
if (schema === null || typeof schema !== "object") {
|
|
102
38
|
return {};
|
|
@@ -5,50 +5,16 @@
|
|
|
5
5
|
* helping models understand expected output structure.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
type JTDPrimitive
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
| "int32"
|
|
19
|
-
| "uint32";
|
|
20
|
-
|
|
21
|
-
interface JTDType {
|
|
22
|
-
type: JTDPrimitive;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
interface JTDEnum {
|
|
26
|
-
enum: string[];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
interface JTDElements {
|
|
30
|
-
elements: JTDSchema;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
interface JTDValues {
|
|
34
|
-
values: JTDSchema;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
interface JTDProperties {
|
|
38
|
-
properties?: Record<string, JTDSchema>;
|
|
39
|
-
optionalProperties?: Record<string, JTDSchema>;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
interface JTDDiscriminator {
|
|
43
|
-
discriminator: string;
|
|
44
|
-
mapping: Record<string, JTDProperties>;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
interface JTDRef {
|
|
48
|
-
ref: string;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
type JTDSchema = JTDType | JTDEnum | JTDElements | JTDValues | JTDProperties | JTDDiscriminator | JTDRef | object;
|
|
8
|
+
import type { JTDPrimitive } from "./jtd-utils.js";
|
|
9
|
+
import {
|
|
10
|
+
isJTDDiscriminator,
|
|
11
|
+
isJTDElements,
|
|
12
|
+
isJTDEnum,
|
|
13
|
+
isJTDProperties,
|
|
14
|
+
isJTDRef,
|
|
15
|
+
isJTDType,
|
|
16
|
+
isJTDValues,
|
|
17
|
+
} from "./jtd-utils.js";
|
|
52
18
|
|
|
53
19
|
const primitiveMap: Record<JTDPrimitive, string> = {
|
|
54
20
|
boolean: "boolean",
|
|
@@ -64,34 +30,6 @@ const primitiveMap: Record<JTDPrimitive, string> = {
|
|
|
64
30
|
uint32: "number",
|
|
65
31
|
};
|
|
66
32
|
|
|
67
|
-
function isJTDType(schema: unknown): schema is JTDType {
|
|
68
|
-
return typeof schema === "object" && schema !== null && "type" in schema;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function isJTDEnum(schema: unknown): schema is JTDEnum {
|
|
72
|
-
return typeof schema === "object" && schema !== null && "enum" in schema && Array.isArray((schema as JTDEnum).enum);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function isJTDElements(schema: unknown): schema is JTDElements {
|
|
76
|
-
return typeof schema === "object" && schema !== null && "elements" in schema;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function isJTDValues(schema: unknown): schema is JTDValues {
|
|
80
|
-
return typeof schema === "object" && schema !== null && "values" in schema;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function isJTDProperties(schema: unknown): schema is JTDProperties {
|
|
84
|
-
return typeof schema === "object" && schema !== null && ("properties" in schema || "optionalProperties" in schema);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function isJTDDiscriminator(schema: unknown): schema is JTDDiscriminator {
|
|
88
|
-
return typeof schema === "object" && schema !== null && "discriminator" in schema && "mapping" in schema;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function isJTDRef(schema: unknown): schema is JTDRef {
|
|
92
|
-
return typeof schema === "object" && schema !== null && "ref" in schema;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
33
|
function convertToTypeScript(schema: unknown, inline = false): string {
|
|
96
34
|
if (schema === null || schema === undefined || (typeof schema === "object" && Object.keys(schema).length === 0)) {
|
|
97
35
|
return "unknown";
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON Type Definition (JTD) utility types and guards.
|
|
3
|
+
*
|
|
4
|
+
* Shared type definitions and type guard functions for JTD schema validation.
|
|
5
|
+
*
|
|
6
|
+
* @see https://jsontypedef.com/
|
|
7
|
+
* @see https://datatracker.ietf.org/doc/html/rfc8927
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export type JTDPrimitive =
|
|
11
|
+
| "boolean"
|
|
12
|
+
| "string"
|
|
13
|
+
| "timestamp"
|
|
14
|
+
| "float32"
|
|
15
|
+
| "float64"
|
|
16
|
+
| "int8"
|
|
17
|
+
| "uint8"
|
|
18
|
+
| "int16"
|
|
19
|
+
| "uint16"
|
|
20
|
+
| "int32"
|
|
21
|
+
| "uint32";
|
|
22
|
+
|
|
23
|
+
export interface JTDType {
|
|
24
|
+
type: JTDPrimitive;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface JTDEnum {
|
|
28
|
+
enum: string[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface JTDElements {
|
|
32
|
+
elements: JTDSchema;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface JTDValues {
|
|
36
|
+
values: JTDSchema;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface JTDProperties {
|
|
40
|
+
properties?: Record<string, JTDSchema>;
|
|
41
|
+
optionalProperties?: Record<string, JTDSchema>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface JTDDiscriminator {
|
|
45
|
+
discriminator: string;
|
|
46
|
+
mapping: Record<string, JTDProperties>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface JTDRef {
|
|
50
|
+
ref: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface JTDEmpty {}
|
|
54
|
+
|
|
55
|
+
export type JTDSchema =
|
|
56
|
+
| JTDType
|
|
57
|
+
| JTDEnum
|
|
58
|
+
| JTDElements
|
|
59
|
+
| JTDValues
|
|
60
|
+
| JTDProperties
|
|
61
|
+
| JTDDiscriminator
|
|
62
|
+
| JTDRef
|
|
63
|
+
| JTDEmpty;
|
|
64
|
+
|
|
65
|
+
// Type guards
|
|
66
|
+
|
|
67
|
+
export function isJTDType(schema: unknown): schema is JTDType {
|
|
68
|
+
return typeof schema === "object" && schema !== null && "type" in schema;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function isJTDEnum(schema: unknown): schema is JTDEnum {
|
|
72
|
+
return typeof schema === "object" && schema !== null && "enum" in schema && Array.isArray(schema.enum);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function isJTDElements(schema: unknown): schema is JTDElements {
|
|
76
|
+
return typeof schema === "object" && schema !== null && "elements" in schema;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function isJTDValues(schema: unknown): schema is JTDValues {
|
|
80
|
+
return typeof schema === "object" && schema !== null && "values" in schema;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function isJTDProperties(schema: unknown): schema is JTDProperties {
|
|
84
|
+
return typeof schema === "object" && schema !== null && ("properties" in schema || "optionalProperties" in schema);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function isJTDDiscriminator(schema: unknown): schema is JTDDiscriminator {
|
|
88
|
+
return (
|
|
89
|
+
typeof schema === "object" &&
|
|
90
|
+
schema !== null &&
|
|
91
|
+
"discriminator" in schema &&
|
|
92
|
+
"mapping" in schema &&
|
|
93
|
+
typeof schema.discriminator === "string" &&
|
|
94
|
+
typeof schema.mapping === "object" &&
|
|
95
|
+
schema.mapping !== null &&
|
|
96
|
+
!Array.isArray(schema.mapping)
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function isJTDRef(schema: unknown): schema is JTDRef {
|
|
101
|
+
return typeof schema === "object" && schema !== null && "ref" in schema;
|
|
102
|
+
}
|
package/src/tools/notebook.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallb
|
|
|
2
2
|
import { StringEnum } from "@oh-my-pi/pi-ai";
|
|
3
3
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
4
4
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
5
|
-
import { untilAborted } from "@oh-my-pi/pi-utils";
|
|
5
|
+
import { isEnoent, untilAborted } from "@oh-my-pi/pi-utils";
|
|
6
6
|
import { type Static, Type } from "@sinclair/typebox";
|
|
7
7
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
8
8
|
import type { Theme } from "../modes/theme/theme";
|
|
@@ -80,17 +80,12 @@ export class NotebookTool implements AgentTool<typeof notebookSchema, NotebookTo
|
|
|
80
80
|
const absolutePath = resolveToCwd(notebook_path, this.session.cwd);
|
|
81
81
|
|
|
82
82
|
return untilAborted(signal, async () => {
|
|
83
|
-
// Check if file exists
|
|
84
|
-
const file = Bun.file(absolutePath);
|
|
85
|
-
if (!(await file.exists())) {
|
|
86
|
-
throw new Error(`Notebook not found: ${notebook_path}`);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
83
|
// Read and parse notebook
|
|
90
84
|
let notebook: Notebook;
|
|
91
85
|
try {
|
|
92
|
-
notebook = await file.json();
|
|
93
|
-
} catch {
|
|
86
|
+
notebook = await Bun.file(absolutePath).json();
|
|
87
|
+
} catch (err) {
|
|
88
|
+
if (isEnoent(err)) throw new Error(`Notebook not found: ${notebook_path}`);
|
|
94
89
|
throw new Error(`Invalid JSON in notebook: ${notebook_path}`);
|
|
95
90
|
}
|
|
96
91
|
|
package/src/tools/output-meta.ts
CHANGED
|
@@ -12,10 +12,10 @@ import type {
|
|
|
12
12
|
AgentToolUpdateCallback,
|
|
13
13
|
} from "@oh-my-pi/pi-agent-core";
|
|
14
14
|
import type { ImageContent, TextContent } from "@oh-my-pi/pi-ai";
|
|
15
|
-
import type {
|
|
15
|
+
import type { Theme } from "../modes/theme/theme";
|
|
16
|
+
import type { OutputSummary, TruncationResult } from "../session/streaming-output";
|
|
17
|
+
import { formatBytes, wrapBrackets } from "./render-utils";
|
|
16
18
|
import { renderError } from "./tool-errors";
|
|
17
|
-
import type { TruncationResult } from "./truncate";
|
|
18
|
-
import { formatSize } from "./truncate";
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Truncation metadata for the output notice.
|
|
@@ -313,6 +313,44 @@ export function outputMeta(): OutputMetaBuilder {
|
|
|
313
313
|
// Notice formatting
|
|
314
314
|
// =============================================================================
|
|
315
315
|
|
|
316
|
+
export function formatFullOutputReference(artifactId: string): string {
|
|
317
|
+
return `Full output: artifact://${artifactId}`;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export function formatTruncationMetaNotice(truncation: TruncationMeta): string {
|
|
321
|
+
const range = truncation.shownRange;
|
|
322
|
+
let notice: string;
|
|
323
|
+
|
|
324
|
+
if (range && range.end >= range.start) {
|
|
325
|
+
notice = `Showing lines ${range.start}-${range.end} of ${truncation.totalLines}`;
|
|
326
|
+
} else {
|
|
327
|
+
notice = `Showing ${truncation.outputLines} of ${truncation.totalLines} lines`;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (truncation.truncatedBy === "bytes") {
|
|
331
|
+
const maxBytes = truncation.maxBytes ?? truncation.outputBytes;
|
|
332
|
+
notice += ` (${formatBytes(maxBytes)} limit)`;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (truncation.nextOffset != null) {
|
|
336
|
+
notice += `. Use offset=${truncation.nextOffset} to continue`;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (truncation.artifactId != null) {
|
|
340
|
+
notice += `. ${formatFullOutputReference(truncation.artifactId)}`;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return notice;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Format styled artifact reference with warning color and brackets.
|
|
348
|
+
* For TUI rendering of truncation warnings.
|
|
349
|
+
*/
|
|
350
|
+
export function formatStyledArtifactReference(artifactId: string, theme: Theme): string {
|
|
351
|
+
return theme.fg("warning", formatFullOutputReference(artifactId));
|
|
352
|
+
}
|
|
353
|
+
|
|
316
354
|
/**
|
|
317
355
|
* Format notices from OutputMeta for LLM consumption.
|
|
318
356
|
* Returns empty string if no notices needed.
|
|
@@ -324,29 +362,7 @@ export function formatOutputNotice(meta: OutputMeta | undefined): string {
|
|
|
324
362
|
|
|
325
363
|
// Truncation notice
|
|
326
364
|
if (meta.truncation) {
|
|
327
|
-
|
|
328
|
-
const range = t.shownRange;
|
|
329
|
-
let notice: string;
|
|
330
|
-
|
|
331
|
-
if (range && range.end >= range.start) {
|
|
332
|
-
notice = `Showing lines ${range.start}-${range.end} of ${t.totalLines}`;
|
|
333
|
-
} else {
|
|
334
|
-
notice = `Showing ${t.outputLines} of ${t.totalLines} lines`;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
if (t.truncatedBy === "bytes") {
|
|
338
|
-
const maxBytes = t.maxBytes ?? t.outputBytes;
|
|
339
|
-
notice += ` (${formatSize(maxBytes)} limit)`;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
if (t.nextOffset != null) {
|
|
343
|
-
notice += `. Use offset=${t.nextOffset} to continue`;
|
|
344
|
-
}
|
|
345
|
-
if (t.artifactId != null) {
|
|
346
|
-
notice += `. Full: artifact://${t.artifactId}`;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
parts.push(notice);
|
|
365
|
+
parts.push(formatTruncationMetaNotice(meta.truncation));
|
|
350
366
|
}
|
|
351
367
|
|
|
352
368
|
// Limit notices
|
|
@@ -377,6 +393,16 @@ export function formatOutputNotice(meta: OutputMeta | undefined): string {
|
|
|
377
393
|
return notice + diagnosticsNotice;
|
|
378
394
|
}
|
|
379
395
|
|
|
396
|
+
/**
|
|
397
|
+
* Format a styled truncation warning message.
|
|
398
|
+
* Returns null if no truncation metadata present.
|
|
399
|
+
*/
|
|
400
|
+
export function formatStyledTruncationWarning(meta: OutputMeta | undefined, theme: Theme): string | null {
|
|
401
|
+
if (!meta?.truncation) return null;
|
|
402
|
+
const message = formatTruncationMetaNotice(meta.truncation);
|
|
403
|
+
return theme.fg("warning", wrapBrackets(message, theme));
|
|
404
|
+
}
|
|
405
|
+
|
|
380
406
|
// =============================================================================
|
|
381
407
|
// Tool wrapper
|
|
382
408
|
// =============================================================================
|
package/src/tools/path-utils.ts
CHANGED
|
@@ -58,15 +58,21 @@ function normalizeAtPrefix(filePath: string): string {
|
|
|
58
58
|
return filePath;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
export function
|
|
62
|
-
const
|
|
63
|
-
if (
|
|
64
|
-
|
|
61
|
+
export function expandTilde(filePath: string, home?: string): string {
|
|
62
|
+
const h = home ?? os.homedir();
|
|
63
|
+
if (filePath === "~") return h;
|
|
64
|
+
if (filePath.startsWith("~/") || filePath.startsWith("~\\")) {
|
|
65
|
+
return h + filePath.slice(1);
|
|
65
66
|
}
|
|
66
|
-
if (
|
|
67
|
-
return
|
|
67
|
+
if (filePath.startsWith("~")) {
|
|
68
|
+
return path.join(h, filePath.slice(1));
|
|
68
69
|
}
|
|
69
|
-
return
|
|
70
|
+
return filePath;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function expandPath(filePath: string): string {
|
|
74
|
+
const normalized = normalizeUnicodeSpaces(normalizeAtPrefix(filePath));
|
|
75
|
+
return expandTilde(normalized);
|
|
70
76
|
}
|
|
71
77
|
|
|
72
78
|
/**
|