@gajae-code/coding-agent 0.11.11 → 0.12.1
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 +131 -4
- package/dist/types/async/job-manager.d.ts +17 -3
- package/dist/types/cli/read-cli.d.ts +1 -0
- package/dist/types/commands/deep-interview.d.ts +9 -0
- package/dist/types/commands/harness.d.ts +22 -0
- package/dist/types/commands/read.d.ts +6 -0
- package/dist/types/config/model-registry.d.ts +4 -0
- package/dist/types/config/provider-auth-health.d.ts +14 -0
- package/dist/types/config/provider-ranking.d.ts +59 -0
- package/dist/types/config/settings-schema.d.ts +83 -1
- package/dist/types/config/settings.d.ts +2 -0
- package/dist/types/exa/mcp-client.d.ts +10 -1
- package/dist/types/exec/bash-executor.d.ts +45 -12
- package/dist/types/extensibility/extensions/types.d.ts +38 -4
- package/dist/types/extensibility/gjc-plugins/index.d.ts +12 -2
- package/dist/types/extensibility/gjc-plugins/installer.d.ts +63 -7
- package/dist/types/extensibility/gjc-plugins/lifecycle-reconciliation.d.ts +55 -0
- package/dist/types/extensibility/gjc-plugins/lifecycle.d.ts +64 -0
- package/dist/types/extensibility/gjc-plugins/runtime-quarantine.d.ts +67 -0
- package/dist/types/extensibility/gjc-plugins/session-validation.d.ts +3 -1
- package/dist/types/extensibility/gjc-plugins/types.d.ts +124 -0
- package/dist/types/extensibility/shared-events.d.ts +6 -0
- package/dist/types/gjc-runtime/deep-interview-ambiguity.d.ts +5 -12
- package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +17 -32
- package/dist/types/gjc-runtime/deep-interview-stage.d.ts +37 -0
- package/dist/types/gjc-runtime/deep-interview-state.d.ts +4 -135
- package/dist/types/gjc-runtime/gc-runtime.d.ts +1 -1
- package/dist/types/gjc-runtime/launch-tmux.d.ts +1 -0
- package/dist/types/gjc-runtime/memory-guard-owner-claims.d.ts +47 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +70 -1
- package/dist/types/gjc-runtime/state-writer.d.ts +5 -46
- package/dist/types/gjc-runtime/team-launch.d.ts +1 -1
- package/dist/types/gjc-runtime/team-runtime.d.ts +27 -1
- package/dist/types/gjc-runtime/team-store.d.ts +12 -0
- package/dist/types/gjc-runtime/team-worker-heartbeat.d.ts +43 -0
- package/dist/types/gjc-runtime/team-worker-memory-guard.d.ts +92 -0
- package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +17 -0
- package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +8 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +31 -80
- package/dist/types/gjc-runtime/workflow-manifest.d.ts +3 -5
- package/dist/types/internal-urls/local-root-gc.d.ts +2 -0
- package/dist/types/main.d.ts +1 -1
- package/dist/types/memories/index.d.ts +2 -0
- package/dist/types/modes/acp/acp-agent.d.ts +10 -19
- package/dist/types/modes/components/assistant-message.d.ts +3 -1
- package/dist/types/modes/components/gjc-bundle-settings.d.ts +34 -0
- package/dist/types/modes/components/irc-sidebar.d.ts +41 -0
- package/dist/types/modes/components/notifications-settings-editor.d.ts +1 -0
- package/dist/types/modes/components/read-tool-group.d.ts +4 -4
- package/dist/types/modes/components/session-observer-overlay.d.ts +22 -0
- package/dist/types/modes/components/settings-selector.d.ts +11 -0
- package/dist/types/modes/components/status-line/gh.d.ts +5 -0
- package/dist/types/modes/components/tool-execution.d.ts +8 -0
- package/dist/types/modes/components/transcript-viewer-overlay.d.ts +18 -1
- package/dist/types/modes/controllers/event-controller.d.ts +3 -0
- package/dist/types/modes/interactive-mode.d.ts +2 -0
- package/dist/types/modes/irc-observation-ledger.d.ts +17 -1
- package/dist/types/modes/types.d.ts +2 -0
- package/dist/types/modes/utils/ui-helpers.d.ts +16 -0
- package/dist/types/reminders/star-reminder.d.ts +3 -13
- package/dist/types/runtime-mcp/manager.d.ts +1 -0
- package/dist/types/runtime-mcp/smithery-auth.d.ts +5 -0
- package/dist/types/sdk/acp/adapter.d.ts +3 -1
- package/dist/types/sdk/broker/lifecycle.d.ts +5 -0
- package/dist/types/sdk/broker/transport.d.ts +2 -0
- package/dist/types/sdk/bus/attachment-registry.d.ts +1 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +4 -1
- package/dist/types/sdk/bus/config.d.ts +6 -2
- package/dist/types/sdk/bus/control-drain-lease.d.ts +52 -0
- package/dist/types/sdk/bus/index.d.ts +44 -1
- package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +44 -0
- package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +4 -0
- package/dist/types/sdk/bus/prompt-reconciliation.d.ts +2 -1
- package/dist/types/sdk/bus/reconciliation-store.d.ts +69 -0
- package/dist/types/sdk/bus/rich-draft.d.ts +1 -0
- package/dist/types/sdk/bus/rich-render.d.ts +2 -0
- package/dist/types/sdk/bus/telegram-adoption-intent.d.ts +165 -0
- package/dist/types/sdk/bus/telegram-cli.d.ts +12 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +11 -4
- package/dist/types/sdk/bus/telegram-daemon.d.ts +25 -1
- package/dist/types/sdk/bus/telegram-reference.d.ts +11 -1
- package/dist/types/sdk/bus/threaded-render.d.ts +3 -2
- package/dist/types/sdk/bus/topic-registry.d.ts +11 -1
- package/dist/types/sdk/host/control/operations.d.ts +1 -1
- package/dist/types/sdk/host/host.d.ts +2 -0
- package/dist/types/sdk/host/query/handlers.d.ts +5 -0
- package/dist/types/sdk/host/query/revision-store.d.ts +2 -0
- package/dist/types/sdk/host/reverse-leases.d.ts +1 -1
- package/dist/types/sdk/prompt-status.d.ts +23 -3
- package/dist/types/sdk/session.d.ts +6 -0
- package/dist/types/session/agent-session.d.ts +82 -12
- package/dist/types/session/artifacts.d.ts +8 -0
- package/dist/types/session/blob-store.d.ts +57 -4
- package/dist/types/session/internal/managed-session-storage.d.ts +8 -1
- package/dist/types/session/memory-guard-checkpoint-participant.d.ts +69 -0
- package/dist/types/session/session-manager.d.ts +48 -19
- package/dist/types/session/session-storage.d.ts +4 -0
- package/dist/types/session/streaming-output.d.ts +96 -12
- package/dist/types/setup/credential-import.d.ts +12 -0
- package/dist/types/skill-state/active-state.d.ts +12 -4
- package/dist/types/skill-state/workflow-hud.d.ts +9 -0
- package/dist/types/task/executor.d.ts +3 -2
- package/dist/types/task/index.d.ts +3 -1
- package/dist/types/task/provider-retry-status.d.ts +8 -0
- package/dist/types/task/receipt.d.ts +7 -1
- package/dist/types/task/types.d.ts +23 -0
- package/dist/types/tools/ask-answer-registry.d.ts +2 -2
- package/dist/types/tools/bash-interactive.d.ts +4 -1
- package/dist/types/tools/bash.d.ts +3 -1
- package/dist/types/tools/browser/launch.d.ts +7 -0
- package/dist/types/tools/fetch.d.ts +17 -1
- package/dist/types/tools/image-gen.d.ts +4 -0
- package/dist/types/tools/index.d.ts +4 -0
- package/dist/types/tools/output-meta.d.ts +44 -3
- package/dist/types/tools/path-utils.d.ts +1 -0
- package/dist/types/tools/read-internals.d.ts +12 -0
- package/dist/types/tools/read.d.ts +45 -7
- package/dist/types/tools/resource-gc.d.ts +4 -0
- package/dist/types/tools/review.d.ts +5 -7
- package/dist/types/tools/subagent.d.ts +2 -0
- package/dist/types/tools/tool-result.d.ts +7 -1
- package/dist/types/utils/gh.d.ts +13 -0
- package/dist/types/utils/image-resize.d.ts +1 -0
- package/dist/types/web/search/providers/kimi.d.ts +2 -0
- package/dist/types/web/search/providers/searxng.d.ts +7 -0
- package/dist/types/web/search/providers/xai.d.ts +2 -0
- package/package.json +11 -13
- package/scripts/acp-conformance-agent.ts +218 -0
- package/scripts/benchmark-sticky-viewport-pr1.ts +239 -0
- package/scripts/capture-gjc-bundle-settings.ts +306 -0
- package/scripts/capture-sticky-viewport-showcase.ts +292 -0
- package/scripts/generate-sdk-operation-inventory.ts +5 -0
- package/scripts/resident-memory-bench.ts +1341 -0
- package/scripts/run-acp-conformance.ts +285 -0
- package/scripts/verify-gjc-sdk-canonicalization.ts +122 -18
- package/scripts/verify-sticky-viewport-showcase.ts +611 -0
- package/src/async/job-manager.ts +78 -20
- package/src/capability/index.ts +8 -0
- package/src/cli/fast-help.ts +1 -1
- package/src/cli/plugin-cli.ts +176 -18
- package/src/cli/read-cli.ts +2 -1
- package/src/cli.ts +1 -0
- package/src/commands/deep-interview.ts +29 -9
- package/src/commands/harness.ts +35 -12
- package/src/commands/read.ts +11 -2
- package/src/commands/team.ts +20 -2
- package/src/config/file-lock.ts +11 -2
- package/src/config/model-registry.ts +21 -2
- package/src/config/provider-auth-health.ts +42 -0
- package/src/config/provider-ranking.ts +119 -0
- package/src/config/settings-schema.ts +74 -1
- package/src/config/settings.ts +246 -108
- package/src/coordinator-mcp/question-gate-codec.ts +1 -1
- package/src/coordinator-mcp/server.ts +5 -12
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +230 -82
- package/src/defaults/gjc/skills/ralplan/SKILL.md +77 -41
- package/src/defaults/gjc/skills/team/SKILL.md +3 -1
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +62 -39
- package/src/defaults/gjc/skills/ultragoal/validation-batch-contracts.md +12 -0
- package/src/defaults/gjc-defaults.ts +4 -4
- package/src/eval/py/executor.ts +7 -2
- package/src/exa/mcp-client.ts +12 -3
- package/src/exec/bash-executor.ts +144 -27
- package/src/extensibility/extensions/runner.ts +15 -0
- package/src/extensibility/extensions/types.ts +46 -5
- package/src/extensibility/gjc-plugins/constrained-hooks.ts +8 -2
- package/src/extensibility/gjc-plugins/index.ts +19 -2
- package/src/extensibility/gjc-plugins/installer.ts +189 -50
- package/src/extensibility/gjc-plugins/lifecycle-reconciliation.ts +199 -0
- package/src/extensibility/gjc-plugins/lifecycle.ts +626 -0
- package/src/extensibility/gjc-plugins/observability.ts +3 -3
- package/src/extensibility/gjc-plugins/prompt-appendix.ts +5 -1
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +12 -2
- package/src/extensibility/gjc-plugins/runtime-quarantine.ts +121 -0
- package/src/extensibility/gjc-plugins/schema.ts +84 -12
- package/src/extensibility/gjc-plugins/session-validation.ts +9 -3
- package/src/extensibility/gjc-plugins/types.ts +141 -0
- package/src/extensibility/gjc-plugins/validation.ts +9 -0
- package/src/extensibility/shared-events.ts +5 -0
- package/src/gjc-runtime/deep-interview-ambiguity.ts +47 -82
- package/src/gjc-runtime/deep-interview-recorder.ts +227 -310
- package/src/gjc-runtime/deep-interview-runtime.ts +109 -270
- package/src/gjc-runtime/deep-interview-stage.ts +1016 -0
- package/src/gjc-runtime/deep-interview-state.ts +12 -943
- package/src/gjc-runtime/gc-render.ts +1 -0
- package/src/gjc-runtime/gc-runtime.ts +11 -1
- package/src/gjc-runtime/launch-tmux.ts +25 -6
- package/src/gjc-runtime/managed-owner-admission.ts +1 -1
- package/src/gjc-runtime/memory-guard-owner-claims.ts +389 -0
- package/src/gjc-runtime/ralplan-runtime.ts +1149 -98
- package/src/gjc-runtime/state-runtime.ts +2 -1
- package/src/gjc-runtime/state-writer.ts +70 -222
- package/src/gjc-runtime/team-launch.ts +42 -5
- package/src/gjc-runtime/team-runtime.ts +1085 -40
- package/src/gjc-runtime/team-store.ts +32 -0
- package/src/gjc-runtime/team-worker-heartbeat.ts +149 -0
- package/src/gjc-runtime/team-worker-memory-guard.ts +363 -0
- package/src/gjc-runtime/team-workers.ts +1 -0
- package/src/gjc-runtime/tmux-owner-isolation.ts +28 -0
- package/src/gjc-runtime/tmux-sessions.ts +58 -13
- package/src/gjc-runtime/ultragoal-receipt-freshness.ts +20 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +414 -618
- package/src/gjc-runtime/workflow-manifest.generated.json +105 -449
- package/src/gjc-runtime/workflow-manifest.ts +38 -247
- package/src/hooks/native-skill-hook.ts +17 -4
- package/src/hooks/skill-state.ts +1 -23
- package/src/internal-urls/docs-index.generated.ts +21 -22
- package/src/internal-urls/local-root-gc.ts +127 -0
- package/src/main.ts +9 -5
- package/src/memories/index.ts +10 -0
- package/src/modes/DESIGN.md +98 -0
- package/src/modes/acp/acp-agent.ts +339 -191
- package/src/modes/acp/acp-event-mapper.ts +14 -7
- package/src/modes/acp/acp-mode.ts +39 -3
- package/src/modes/components/assistant-message.ts +123 -22
- package/src/modes/components/gjc-bundle-settings.ts +508 -0
- package/src/modes/components/irc-sidebar.ts +176 -62
- package/src/modes/components/model-selector.ts +61 -4
- package/src/modes/components/notifications-settings-editor.ts +12 -1
- package/src/modes/components/oauth-selector.ts +96 -28
- package/src/modes/components/read-tool-group.ts +82 -14
- package/src/modes/components/session-observer-overlay.ts +457 -83
- package/src/modes/components/settings-selector.ts +116 -23
- package/src/modes/components/status-line/gh.ts +16 -0
- package/src/modes/components/tool-execution.ts +138 -27
- package/src/modes/components/tool-status-header.ts +3 -14
- package/src/modes/components/transcript-viewer-overlay.ts +99 -24
- package/src/modes/controllers/command-controller.ts +4 -0
- package/src/modes/controllers/event-controller.ts +109 -27
- package/src/modes/controllers/extension-ui-controller.ts +26 -2
- package/src/modes/controllers/input-controller.ts +18 -3
- package/src/modes/controllers/selector-controller.ts +127 -36
- package/src/modes/interactive-mode.ts +62 -3
- package/src/modes/irc-observation-ledger.ts +71 -15
- package/src/modes/runtime-init.ts +22 -2
- package/src/modes/types.ts +2 -0
- package/src/modes/utils/ui-helpers.ts +94 -1
- package/src/prompts/agent-fragments/ralplan-persistence.md +4 -3
- package/src/prompts/agents/architect.md +9 -1
- package/src/prompts/agents/critic.md +9 -0
- package/src/prompts/system/eager-todo.md +8 -4
- package/src/prompts/system/system-prompt.md +11 -5
- package/src/prompts/tools/bash.md +5 -5
- package/src/prompts/tools/read.md +4 -2
- package/src/prompts/tools/search-tool-bm25.md +5 -0
- package/src/prompts/tools/task.md +1 -1
- package/src/reminders/star-reminder.ts +4 -42
- package/src/runtime-mcp/manager.ts +19 -4
- package/src/runtime-mcp/smithery-auth.ts +17 -2
- package/src/runtime-mcp/smithery-connect.ts +11 -1
- package/src/sdk/acp/adapter.ts +22 -6
- package/src/sdk/broker/lifecycle.ts +25 -6
- package/src/sdk/broker/transport.ts +35 -3
- package/src/sdk/bus/attachment-registry.ts +5 -1
- package/src/sdk/bus/chat-daemon-cli.ts +4 -39
- package/src/sdk/bus/chat-daemon-control.ts +6 -3
- package/src/sdk/bus/config.ts +18 -2
- package/src/sdk/bus/control-drain-lease.ts +104 -0
- package/src/sdk/bus/index.ts +984 -146
- package/src/sdk/bus/kind-aware-reconciliation.ts +317 -0
- package/src/sdk/bus/lifecycle-commands.ts +4 -1
- package/src/sdk/bus/lifecycle-control-runtime.ts +403 -88
- package/src/sdk/bus/prompt-reconciliation.ts +2 -1
- package/src/sdk/bus/reconciliation-store.ts +303 -0
- package/src/sdk/bus/rich-draft.ts +1 -1
- package/src/sdk/bus/rich-render.ts +2 -2
- package/src/sdk/bus/telegram-adoption-intent.ts +574 -0
- package/src/sdk/bus/telegram-cli.ts +33 -8
- package/src/sdk/bus/telegram-daemon-cli.ts +1 -0
- package/src/sdk/bus/telegram-daemon-contract.ts +11 -4
- package/src/sdk/bus/telegram-daemon.ts +916 -23
- package/src/sdk/bus/telegram-reference.ts +40 -3
- package/src/sdk/bus/threaded-render.ts +48 -3
- package/src/sdk/bus/topic-registry.ts +20 -0
- package/src/sdk/host/control/dispatch.ts +5 -1
- package/src/sdk/host/control/operations.ts +1 -1
- package/src/sdk/host/host.ts +23 -1
- package/src/sdk/host/query/handlers.ts +55 -0
- package/src/sdk/host/query/revision-store.ts +36 -2
- package/src/sdk/host/reverse-leases.ts +44 -7
- package/src/sdk/mcp/server.ts +46 -18
- package/src/sdk/prompt-status.ts +16 -3
- package/src/sdk/protocol/operation-inventory.generated.json +51 -0
- package/src/sdk/protocol/operation-registry.ts +7 -2
- package/src/sdk/session.ts +101 -10
- package/src/session/agent-session.ts +1286 -220
- package/src/session/artifacts.ts +22 -0
- package/src/session/auth-broker-config.ts +10 -3
- package/src/session/blob-store.ts +915 -24
- package/src/session/internal/managed-session-scope.ts +44 -6
- package/src/session/internal/managed-session-storage.ts +48 -6
- package/src/session/memory-guard-checkpoint-participant.ts +131 -0
- package/src/session/session-manager.ts +2364 -438
- package/src/session/session-storage.ts +9 -1
- package/src/session/streaming-output.ts +500 -111
- package/src/setup/credential-import.ts +75 -13
- package/src/setup/provider-onboarding.ts +19 -4
- package/src/skill-state/active-state.ts +32 -10
- package/src/skill-state/workflow-hud.ts +42 -2
- package/src/skill-state/workflow-mutation-guard.ts +560 -8
- package/src/task/executor.ts +122 -39
- package/src/task/index.ts +23 -14
- package/src/task/provider-retry-status.ts +16 -0
- package/src/task/receipt.ts +23 -7
- package/src/task/render.ts +6 -2
- package/src/task/types.ts +108 -0
- package/src/tools/ask-answer-registry.ts +12 -6
- package/src/tools/ask.ts +169 -118
- package/src/tools/ast-edit.ts +1 -0
- package/src/tools/ast-grep.ts +1 -0
- package/src/tools/bash-interactive.ts +8 -3
- package/src/tools/bash.ts +503 -60
- package/src/tools/browser/launch.ts +41 -6
- package/src/tools/fetch.ts +114 -23
- package/src/tools/find.ts +1 -0
- package/src/tools/image-gen.ts +29 -5
- package/src/tools/index.ts +4 -0
- package/src/tools/output-meta.ts +281 -20
- package/src/tools/path-utils.ts +8 -3
- package/src/tools/read-internals.ts +44 -0
- package/src/tools/read.ts +1560 -310
- package/src/tools/resource-gc.ts +182 -18
- package/src/tools/review.ts +5 -7
- package/src/tools/search.ts +1 -0
- package/src/tools/subagent-render.ts +6 -2
- package/src/tools/subagent.ts +6 -0
- package/src/tools/telegram-send.ts +6 -3
- package/src/tools/tool-result.ts +14 -1
- package/src/utils/gh.ts +39 -0
- package/src/utils/image-resize.ts +3 -0
- package/src/web/search/providers/anthropic.ts +4 -4
- package/src/web/search/providers/codex.ts +1 -1
- package/src/web/search/providers/kimi.ts +15 -5
- package/src/web/search/providers/searxng.ts +47 -4
- package/src/web/search/providers/xai.ts +7 -2
- package/dist/types/gjc-runtime/deep-interview-draft.d.ts +0 -8
- package/dist/types/gjc-runtime/deep-interview-payload.d.ts +0 -41
- package/dist/types/gjc-runtime/deep-interview-repair.d.ts +0 -17
- package/dist/types/gjc-runtime/ultragoal-pipeline.d.ts +0 -23
- package/src/defaults/gjc/skills/ultragoal/pipeline-validation-contracts.md +0 -30
- package/src/gjc-runtime/deep-interview-draft.ts +0 -843
- package/src/gjc-runtime/deep-interview-payload.ts +0 -262
- package/src/gjc-runtime/deep-interview-repair.ts +0 -1674
- package/src/gjc-runtime/ultragoal-pipeline.ts +0 -306
package/src/tools/output-meta.ts
CHANGED
|
@@ -16,7 +16,15 @@ import { getDefault, type Settings } from "../config/settings";
|
|
|
16
16
|
import { formatGroupedDiagnosticMessages } from "../lsp/utils";
|
|
17
17
|
import type { Theme } from "../modes/theme/theme";
|
|
18
18
|
import { sessionArtifactCapability } from "../session/session-manager";
|
|
19
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
formatMiddleElisionMarker,
|
|
21
|
+
type OutputSummary,
|
|
22
|
+
type ReadWindow,
|
|
23
|
+
type TruncationResult,
|
|
24
|
+
truncateMiddle,
|
|
25
|
+
truncateTail,
|
|
26
|
+
} from "../session/streaming-output";
|
|
27
|
+
|
|
20
28
|
import { formatBytes, wrapBrackets } from "./render-utils";
|
|
21
29
|
import { renderError } from "./tool-errors";
|
|
22
30
|
|
|
@@ -25,6 +33,9 @@ import { renderError } from "./tool-errors";
|
|
|
25
33
|
*/
|
|
26
34
|
export interface TruncationMeta {
|
|
27
35
|
direction: "head" | "tail" | "middle";
|
|
36
|
+
/** Coordinate basis for shown/head/tail ranges. Omitted means file coordinates; "window" is the selected-range coordinate system. */
|
|
37
|
+
rangeBase?: "file" | "window";
|
|
38
|
+
noticeOwner?: "body";
|
|
28
39
|
truncatedBy: "lines" | "bytes" | "middle";
|
|
29
40
|
totalLines: number;
|
|
30
41
|
totalBytes: number;
|
|
@@ -36,12 +47,18 @@ export interface TruncationMeta {
|
|
|
36
47
|
/** Head/tail line ranges shown when direction === "middle". */
|
|
37
48
|
headRange?: { start: number; end: number };
|
|
38
49
|
tailRange?: { start: number; end: number };
|
|
50
|
+
/** Partial source-line preview retained by a directional window. */
|
|
51
|
+
partialLine?: { line: number; bytes: number; sourceBytes: number };
|
|
39
52
|
/** Bytes elided from the middle. */
|
|
40
53
|
elidedBytes?: number;
|
|
41
54
|
/** Lines elided from the middle. */
|
|
42
55
|
elidedLines?: number;
|
|
43
|
-
/** Artifact ID
|
|
56
|
+
/** Artifact ID when output was persisted; completeness is tracked separately below. */
|
|
44
57
|
artifactId?: string;
|
|
58
|
+
/** Bytes omitted from an artifact after its hard storage cap was reached. */
|
|
59
|
+
artifactTruncatedBytes?: number;
|
|
60
|
+
/** Bounded diagnostic when artifact writer creation, write, or finalization failed. */
|
|
61
|
+
artifactFailureDiagnostic?: string;
|
|
45
62
|
/** Next offset for pagination (head truncation only) */
|
|
46
63
|
nextOffset?: number;
|
|
47
64
|
}
|
|
@@ -91,12 +108,15 @@ export interface TruncationOptions {
|
|
|
91
108
|
startLine?: number;
|
|
92
109
|
totalFileLines?: number;
|
|
93
110
|
artifactId?: string;
|
|
111
|
+
maxBytes?: number;
|
|
112
|
+
noticeOwner?: "body";
|
|
94
113
|
}
|
|
95
114
|
|
|
96
115
|
export interface TruncationSummaryOptions {
|
|
97
116
|
direction: "head" | "tail" | "middle";
|
|
98
117
|
startLine?: number;
|
|
99
118
|
totalFileLines?: number;
|
|
119
|
+
noticeOwner?: "body";
|
|
100
120
|
}
|
|
101
121
|
|
|
102
122
|
export interface TruncationTextOptions {
|
|
@@ -105,6 +125,7 @@ export interface TruncationTextOptions {
|
|
|
105
125
|
totalBytes?: number;
|
|
106
126
|
maxBytes?: number;
|
|
107
127
|
artifactId?: string;
|
|
128
|
+
noticeOwner?: "body";
|
|
108
129
|
}
|
|
109
130
|
|
|
110
131
|
/**
|
|
@@ -126,7 +147,7 @@ export class OutputMetaBuilder {
|
|
|
126
147
|
truncation(result: TruncationResult, options: TruncationOptions): this {
|
|
127
148
|
if (!result.truncated) return this;
|
|
128
149
|
|
|
129
|
-
const { direction, startLine = 1, totalFileLines, artifactId } = options;
|
|
150
|
+
const { direction, startLine = 1, totalFileLines, artifactId, noticeOwner, maxBytes } = options;
|
|
130
151
|
const outputLines = result.outputLines ?? result.totalLines;
|
|
131
152
|
const outputBytes = result.outputBytes ?? result.totalBytes;
|
|
132
153
|
const isMiddle = direction === "middle" || result.truncatedBy === "middle";
|
|
@@ -137,6 +158,7 @@ export class OutputMetaBuilder {
|
|
|
137
158
|
: "bytes";
|
|
138
159
|
|
|
139
160
|
const effectiveTotalLines = totalFileLines ?? result.totalLines;
|
|
161
|
+
const owner = noticeOwner !== undefined ? { noticeOwner } : {};
|
|
140
162
|
|
|
141
163
|
if (isMiddle) {
|
|
142
164
|
const elidedLines = result.elidedLines ?? Math.max(0, effectiveTotalLines - outputLines);
|
|
@@ -150,10 +172,12 @@ export class OutputMetaBuilder {
|
|
|
150
172
|
this.#meta.truncation = {
|
|
151
173
|
direction: "middle",
|
|
152
174
|
truncatedBy: "middle",
|
|
175
|
+
...owner,
|
|
153
176
|
totalLines: effectiveTotalLines,
|
|
154
177
|
totalBytes: result.totalBytes,
|
|
155
178
|
outputLines,
|
|
156
179
|
outputBytes,
|
|
180
|
+
...(maxBytes !== undefined ? { maxBytes } : {}),
|
|
157
181
|
headRange: headLines > 0 ? { start: 1, end: headLines } : undefined,
|
|
158
182
|
tailRange:
|
|
159
183
|
tailLines > 0 ? { start: effectiveTotalLines - tailLines + 1, end: effectiveTotalLines } : undefined,
|
|
@@ -178,10 +202,12 @@ export class OutputMetaBuilder {
|
|
|
178
202
|
this.#meta.truncation = {
|
|
179
203
|
direction,
|
|
180
204
|
truncatedBy,
|
|
205
|
+
...owner,
|
|
181
206
|
totalLines: effectiveTotalLines,
|
|
182
207
|
totalBytes: result.totalBytes,
|
|
183
208
|
outputLines,
|
|
184
209
|
outputBytes,
|
|
210
|
+
...(maxBytes !== undefined ? { maxBytes } : {}),
|
|
185
211
|
shownRange: { start: shownStart, end: shownEnd },
|
|
186
212
|
artifactId,
|
|
187
213
|
nextOffset: direction === "head" ? shownEnd + 1 : undefined,
|
|
@@ -190,12 +216,141 @@ export class OutputMetaBuilder {
|
|
|
190
216
|
return this;
|
|
191
217
|
}
|
|
192
218
|
|
|
193
|
-
/** Add
|
|
194
|
-
|
|
195
|
-
|
|
219
|
+
/** Add metadata from the actual head/tail windows retained by middle truncation. */
|
|
220
|
+
truncationWindows(
|
|
221
|
+
windows: ReadWindow,
|
|
222
|
+
options: {
|
|
223
|
+
artifactId?: string;
|
|
224
|
+
noticeOwner?: "body";
|
|
225
|
+
maxBytes?: number;
|
|
226
|
+
rangeBase?: "file" | "window";
|
|
227
|
+
} = {},
|
|
228
|
+
): this {
|
|
229
|
+
if (windows.kind === "full") return this;
|
|
230
|
+
|
|
231
|
+
const { artifactId, noticeOwner, rangeBase } = options;
|
|
232
|
+
const maxBytes = options.maxBytes ?? (windows as ReadWindow & { maxBytes?: number }).maxBytes;
|
|
233
|
+
const outputLinesOverride = (windows as ReadWindow & { outputLinesOverride?: number }).outputLinesOverride;
|
|
234
|
+
const outputBytesOverride = (windows as ReadWindow & { outputBytesOverride?: number }).outputBytesOverride;
|
|
235
|
+
const owner = noticeOwner !== undefined ? { noticeOwner } : {};
|
|
236
|
+
const rangeBaseMeta = rangeBase !== undefined ? { rangeBase } : {};
|
|
237
|
+
const hiddenReason = (windows as ReadWindow & { truncatedBy?: "lines" | "bytes" | "middle" }).truncatedBy;
|
|
238
|
+
const fallbackTruncatedBy: "lines" | "bytes" = hiddenReason === "bytes" ? "bytes" : "lines";
|
|
239
|
+
const partialTail = windows.tail?.kind === "partial-line" ? windows.tail : undefined;
|
|
240
|
+
if (partialTail) {
|
|
241
|
+
const headBytes = windows.head?.bytes ?? 0;
|
|
242
|
+
const separatorBytes = windows.head ? 1 : 0;
|
|
243
|
+
const markerBytes =
|
|
244
|
+
windows.elidedLines > 0
|
|
245
|
+
? Buffer.byteLength(formatMiddleElisionMarker(windows.elidedLines, windows.elidedBytes), "utf-8") + 1
|
|
246
|
+
: 0;
|
|
247
|
+
this.#meta.truncation = {
|
|
248
|
+
direction: windows.kind === "tail-only" ? "tail" : "middle",
|
|
249
|
+
truncatedBy: "bytes",
|
|
250
|
+
...owner,
|
|
251
|
+
...rangeBaseMeta,
|
|
252
|
+
totalLines: windows.totalLines,
|
|
253
|
+
totalBytes: windows.totalBytes,
|
|
254
|
+
outputLines:
|
|
255
|
+
outputLinesOverride ??
|
|
256
|
+
(windows.head
|
|
257
|
+
? windows.head.lines + partialTail.lines + (windows.elidedLines > 0 ? 1 : 0)
|
|
258
|
+
: partialTail.lines),
|
|
259
|
+
outputBytes: outputBytesOverride ?? headBytes + partialTail.bytes + separatorBytes + markerBytes,
|
|
260
|
+
...(maxBytes !== undefined ? { maxBytes } : {}),
|
|
261
|
+
partialLine: {
|
|
262
|
+
line: partialTail.origin.startLine,
|
|
263
|
+
bytes: partialTail.bytes,
|
|
264
|
+
sourceBytes: partialTail.sourceLineBytes,
|
|
265
|
+
},
|
|
266
|
+
artifactId,
|
|
267
|
+
};
|
|
268
|
+
return this;
|
|
269
|
+
}
|
|
196
270
|
|
|
197
|
-
|
|
271
|
+
if (windows.kind === "head-only" && windows.head) {
|
|
272
|
+
const { head } = windows;
|
|
273
|
+
this.#meta.truncation = {
|
|
274
|
+
direction: "head",
|
|
275
|
+
truncatedBy: fallbackTruncatedBy,
|
|
276
|
+
...owner,
|
|
277
|
+
...rangeBaseMeta,
|
|
278
|
+
totalLines: windows.totalLines,
|
|
279
|
+
totalBytes: windows.totalBytes,
|
|
280
|
+
outputLines: outputLinesOverride ?? head.lines,
|
|
281
|
+
outputBytes: outputBytesOverride ?? head.bytes,
|
|
282
|
+
...(maxBytes !== undefined ? { maxBytes } : {}),
|
|
283
|
+
shownRange: { start: head.origin.startLine, end: head.origin.endLine },
|
|
284
|
+
artifactId,
|
|
285
|
+
nextOffset: head.origin.endLine + 1,
|
|
286
|
+
};
|
|
287
|
+
return this;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (windows.kind === "tail-only" && windows.tail) {
|
|
291
|
+
const { tail } = windows;
|
|
292
|
+
this.#meta.truncation = {
|
|
293
|
+
direction: "tail",
|
|
294
|
+
truncatedBy: fallbackTruncatedBy,
|
|
295
|
+
...owner,
|
|
296
|
+
...rangeBaseMeta,
|
|
297
|
+
totalLines: windows.totalLines,
|
|
298
|
+
totalBytes: windows.totalBytes,
|
|
299
|
+
outputLines: outputLinesOverride ?? tail.lines,
|
|
300
|
+
outputBytes: outputBytesOverride ?? tail.bytes,
|
|
301
|
+
...(maxBytes !== undefined ? { maxBytes } : {}),
|
|
302
|
+
shownRange: { start: tail.origin.startLine, end: tail.origin.endLine },
|
|
303
|
+
artifactId,
|
|
304
|
+
};
|
|
305
|
+
return this;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const { head, tail } = windows;
|
|
309
|
+
if (!head || !tail) return this;
|
|
310
|
+
const marker = formatMiddleElisionMarker(windows.elidedLines, windows.elidedBytes);
|
|
311
|
+
this.#meta.truncation = {
|
|
312
|
+
direction: "middle",
|
|
313
|
+
truncatedBy: "middle",
|
|
314
|
+
...owner,
|
|
315
|
+
...rangeBaseMeta,
|
|
316
|
+
totalLines: windows.totalLines,
|
|
317
|
+
totalBytes: windows.totalBytes,
|
|
318
|
+
outputLines: head.lines + tail.lines + 1,
|
|
319
|
+
outputBytes: head.bytes + tail.bytes + Buffer.byteLength(marker, "utf-8") + 2,
|
|
320
|
+
...(maxBytes !== undefined ? { maxBytes } : {}),
|
|
321
|
+
headRange: { start: head.origin.startLine, end: head.origin.endLine },
|
|
322
|
+
tailRange: { start: tail.origin.startLine, end: tail.origin.endLine },
|
|
323
|
+
elidedLines: windows.elidedLines,
|
|
324
|
+
elidedBytes: windows.elidedBytes,
|
|
325
|
+
artifactId,
|
|
326
|
+
};
|
|
327
|
+
return this;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/** Add truncation info from OutputSummary. No-op if not truncated or artifact evidence is absent. */
|
|
331
|
+
truncationFromSummary(summary: OutputSummary, options: TruncationSummaryOptions): this {
|
|
332
|
+
const artifactFailureDiagnostic = summary.artifactFailureDiagnostic;
|
|
333
|
+
const artifactTruncatedBytes =
|
|
334
|
+
summary.artifactTruncatedBytes != null && summary.artifactTruncatedBytes > 0
|
|
335
|
+
? summary.artifactTruncatedBytes
|
|
336
|
+
: undefined;
|
|
337
|
+
const hasArtifactEvidence =
|
|
338
|
+
summary.artifactId !== undefined ||
|
|
339
|
+
artifactFailureDiagnostic !== undefined ||
|
|
340
|
+
artifactTruncatedBytes !== undefined;
|
|
341
|
+
if (!summary.truncated && !hasArtifactEvidence) return this;
|
|
342
|
+
|
|
343
|
+
const { direction, startLine = 1, totalFileLines, noticeOwner } = options;
|
|
198
344
|
const totalLines = totalFileLines ?? summary.totalLines;
|
|
345
|
+
const bodyHasArtifact =
|
|
346
|
+
summary.artifactId !== undefined && summary.output.includes(`artifact://${summary.artifactId}`);
|
|
347
|
+
const bodyOwnsArtifact =
|
|
348
|
+
bodyHasArtifact &&
|
|
349
|
+
(artifactTruncatedBytes === undefined ||
|
|
350
|
+
(summary.artifactId !== undefined &&
|
|
351
|
+
summary.output.includes(formatArtifactReference(summary.artifactId, artifactTruncatedBytes))));
|
|
352
|
+
const owner =
|
|
353
|
+
noticeOwner !== undefined ? { noticeOwner } : bodyOwnsArtifact ? { noticeOwner: "body" as const } : {};
|
|
199
354
|
|
|
200
355
|
// Middle elision: the sink retained head + tail with an elision marker.
|
|
201
356
|
if (summary.elidedBytes != null && summary.elidedBytes > 0) {
|
|
@@ -206,6 +361,7 @@ export class OutputMetaBuilder {
|
|
|
206
361
|
this.#meta.truncation = {
|
|
207
362
|
direction: "middle",
|
|
208
363
|
truncatedBy: "middle",
|
|
364
|
+
...owner,
|
|
209
365
|
totalLines,
|
|
210
366
|
totalBytes: summary.totalBytes,
|
|
211
367
|
outputLines: summary.outputLines,
|
|
@@ -215,6 +371,8 @@ export class OutputMetaBuilder {
|
|
|
215
371
|
elidedBytes: summary.elidedBytes,
|
|
216
372
|
elidedLines,
|
|
217
373
|
artifactId: summary.artifactId,
|
|
374
|
+
artifactTruncatedBytes,
|
|
375
|
+
artifactFailureDiagnostic,
|
|
218
376
|
};
|
|
219
377
|
return this;
|
|
220
378
|
}
|
|
@@ -240,12 +398,15 @@ export class OutputMetaBuilder {
|
|
|
240
398
|
this.#meta.truncation = {
|
|
241
399
|
direction,
|
|
242
400
|
truncatedBy,
|
|
401
|
+
...owner,
|
|
243
402
|
totalLines,
|
|
244
403
|
totalBytes: summary.totalBytes,
|
|
245
404
|
outputLines: summary.outputLines,
|
|
246
405
|
outputBytes: summary.outputBytes,
|
|
247
406
|
shownRange: { start: shownStart, end: shownEnd },
|
|
248
407
|
artifactId: summary.artifactId,
|
|
408
|
+
artifactTruncatedBytes,
|
|
409
|
+
artifactFailureDiagnostic,
|
|
249
410
|
nextOffset: direction === "head" ? shownEnd + 1 : undefined,
|
|
250
411
|
};
|
|
251
412
|
|
|
@@ -285,6 +446,7 @@ export class OutputMetaBuilder {
|
|
|
285
446
|
this.#meta.truncation = {
|
|
286
447
|
direction: options.direction,
|
|
287
448
|
truncatedBy,
|
|
449
|
+
...(options.noticeOwner !== undefined ? { noticeOwner: options.noticeOwner } : {}),
|
|
288
450
|
totalLines,
|
|
289
451
|
totalBytes,
|
|
290
452
|
outputLines,
|
|
@@ -387,7 +549,56 @@ export function formatFullOutputReference(artifactId: string): string {
|
|
|
387
549
|
return `Read artifact://${artifactId} for full output`;
|
|
388
550
|
}
|
|
389
551
|
|
|
552
|
+
/**
|
|
553
|
+
* Format an artifact reference without claiming completeness when storage was hard-capped.
|
|
554
|
+
*/
|
|
555
|
+
export function formatArtifactReference(artifactId: string, artifactTruncatedBytes?: number): string {
|
|
556
|
+
if (artifactTruncatedBytes != null && artifactTruncatedBytes > 0) {
|
|
557
|
+
return `Read artifact://${artifactId} for retained output (at least ${formatBytes(artifactTruncatedBytes)} omitted by the artifact storage cap)`;
|
|
558
|
+
}
|
|
559
|
+
return formatFullOutputReference(artifactId);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
function formatTruncationArtifactNotice(truncation: TruncationMeta): string {
|
|
563
|
+
const reference = truncation.artifactId
|
|
564
|
+
? formatArtifactReference(truncation.artifactId, truncation.artifactTruncatedBytes)
|
|
565
|
+
: undefined;
|
|
566
|
+
if (truncation.artifactFailureDiagnostic) {
|
|
567
|
+
const failure = `Artifact storage failed: ${truncation.artifactFailureDiagnostic}`;
|
|
568
|
+
if (reference) return `${reference}; ${failure}`;
|
|
569
|
+
return failure;
|
|
570
|
+
}
|
|
571
|
+
if (reference) return reference;
|
|
572
|
+
return `Artifact storage omitted at least ${formatBytes(truncation.artifactTruncatedBytes ?? 0)}; no artifact reference is available`;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
function hasArtifactNotice(truncation: TruncationMeta): boolean {
|
|
576
|
+
return (
|
|
577
|
+
truncation.artifactId != null ||
|
|
578
|
+
(truncation.artifactTruncatedBytes ?? 0) > 0 ||
|
|
579
|
+
truncation.artifactFailureDiagnostic != null
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
function formatTruncationRangeTotal(truncation: TruncationMeta): string {
|
|
584
|
+
return truncation.rangeBase === "window"
|
|
585
|
+
? `the selected ${truncation.totalLines}-line range`
|
|
586
|
+
: `${truncation.totalLines}`;
|
|
587
|
+
}
|
|
588
|
+
|
|
390
589
|
export function formatTruncationMetaNotice(truncation: TruncationMeta): string {
|
|
590
|
+
const rangeTotal = formatTruncationRangeTotal(truncation);
|
|
591
|
+
if (truncation.partialLine) {
|
|
592
|
+
let notice = `Showing last ${formatBytes(truncation.partialLine.bytes)} of line ${truncation.partialLine.line} of ${rangeTotal}`;
|
|
593
|
+
if (truncation.partialLine.sourceBytes > truncation.partialLine.bytes) {
|
|
594
|
+
notice += ` (line is ${formatBytes(truncation.partialLine.sourceBytes)})`;
|
|
595
|
+
}
|
|
596
|
+
if (hasArtifactNotice(truncation)) {
|
|
597
|
+
notice += `. ${formatTruncationArtifactNotice(truncation)}`;
|
|
598
|
+
}
|
|
599
|
+
return notice;
|
|
600
|
+
}
|
|
601
|
+
|
|
391
602
|
let notice: string;
|
|
392
603
|
|
|
393
604
|
if (truncation.direction === "middle") {
|
|
@@ -398,22 +609,24 @@ export function formatTruncationMetaNotice(truncation: TruncationMeta): string {
|
|
|
398
609
|
const elidedLines = truncation.elidedLines ?? Math.max(0, totalLines - truncation.outputLines);
|
|
399
610
|
const headPart = head ? `lines ${head.start}-${head.end}` : "";
|
|
400
611
|
const tailPart = tail ? `${tail.start}-${tail.end}` : "";
|
|
401
|
-
if (
|
|
402
|
-
notice = `Showing
|
|
612
|
+
if (head && tail && elidedLines === 0 && head.start === tail.start && head.end === tail.end) {
|
|
613
|
+
notice = `Showing head and tail of line ${head.start} of ${rangeTotal}; ${formatBytes(elidedBytes)} middle bytes elided`;
|
|
614
|
+
} else if (headPart && tailPart) {
|
|
615
|
+
notice = `Showing ${headPart} and ${tailPart} of ${rangeTotal}; ${elidedLines.toLocaleString()} middle line${elidedLines === 1 ? "" : "s"} (${formatBytes(elidedBytes)}) elided`;
|
|
403
616
|
} else {
|
|
404
|
-
notice = `Showing ${truncation.outputLines} of ${
|
|
617
|
+
notice = `Showing ${truncation.outputLines} of ${rangeTotal}${truncation.rangeBase === "window" ? "" : " lines"}; ${formatBytes(elidedBytes)} middle bytes elided`;
|
|
405
618
|
}
|
|
406
|
-
if (truncation
|
|
407
|
-
notice += `. ${
|
|
619
|
+
if (hasArtifactNotice(truncation)) {
|
|
620
|
+
notice += `. ${formatTruncationArtifactNotice(truncation)}`;
|
|
408
621
|
}
|
|
409
622
|
return notice;
|
|
410
623
|
}
|
|
411
624
|
|
|
412
625
|
const range = truncation.shownRange;
|
|
413
626
|
if (range && range.end >= range.start) {
|
|
414
|
-
notice = `Showing lines ${range.start}-${range.end} of ${
|
|
627
|
+
notice = `Showing lines ${range.start}-${range.end} of ${rangeTotal}`;
|
|
415
628
|
} else {
|
|
416
|
-
notice = `Showing ${truncation.outputLines} of ${truncation.
|
|
629
|
+
notice = `Showing ${truncation.outputLines} of ${rangeTotal}${truncation.rangeBase === "window" ? "" : " lines"}`;
|
|
417
630
|
}
|
|
418
631
|
|
|
419
632
|
if (truncation.truncatedBy === "bytes") {
|
|
@@ -425,8 +638,8 @@ export function formatTruncationMetaNotice(truncation: TruncationMeta): string {
|
|
|
425
638
|
notice += `. Use :${truncation.nextOffset} to continue`;
|
|
426
639
|
}
|
|
427
640
|
|
|
428
|
-
if (truncation
|
|
429
|
-
notice += `. ${
|
|
641
|
+
if (hasArtifactNotice(truncation)) {
|
|
642
|
+
notice += `. ${formatTruncationArtifactNotice(truncation)}`;
|
|
430
643
|
}
|
|
431
644
|
|
|
432
645
|
return notice;
|
|
@@ -450,7 +663,7 @@ export function formatOutputNotice(meta: OutputMeta | undefined): string {
|
|
|
450
663
|
const parts: string[] = [];
|
|
451
664
|
|
|
452
665
|
// Truncation notice
|
|
453
|
-
if (meta.truncation) {
|
|
666
|
+
if (meta.truncation && meta.truncation.noticeOwner !== "body") {
|
|
454
667
|
parts.push(formatTruncationMetaNotice(meta.truncation));
|
|
455
668
|
}
|
|
456
669
|
|
|
@@ -487,8 +700,25 @@ export function formatOutputNotice(meta: OutputMeta | undefined): string {
|
|
|
487
700
|
* Returns null if no truncation metadata present.
|
|
488
701
|
*/
|
|
489
702
|
export function formatStyledTruncationWarning(meta: OutputMeta | undefined, theme: Theme): string | null {
|
|
490
|
-
|
|
491
|
-
|
|
703
|
+
const truncation = meta?.truncation;
|
|
704
|
+
if (!truncation) return null;
|
|
705
|
+
if (
|
|
706
|
+
truncation.noticeOwner === "body" &&
|
|
707
|
+
truncation.totalBytes === truncation.outputBytes &&
|
|
708
|
+
truncation.totalLines === truncation.outputLines
|
|
709
|
+
) {
|
|
710
|
+
return null;
|
|
711
|
+
}
|
|
712
|
+
const warningMeta =
|
|
713
|
+
truncation.noticeOwner === "body"
|
|
714
|
+
? {
|
|
715
|
+
...truncation,
|
|
716
|
+
artifactId: undefined,
|
|
717
|
+
artifactTruncatedBytes: undefined,
|
|
718
|
+
artifactFailureDiagnostic: undefined,
|
|
719
|
+
}
|
|
720
|
+
: truncation;
|
|
721
|
+
const message = formatTruncationMetaNotice(warningMeta);
|
|
492
722
|
return theme.fg("warning", wrapBrackets(message, theme));
|
|
493
723
|
}
|
|
494
724
|
|
|
@@ -580,6 +810,25 @@ export function resolveOutputSinkHeadBytes(s: Settings | undefined): number {
|
|
|
580
810
|
return getSpillConfig(s).headBytes;
|
|
581
811
|
}
|
|
582
812
|
|
|
813
|
+
export const BASH_DEFAULT_OUTPUT_TAIL_BYTES = 1024;
|
|
814
|
+
|
|
815
|
+
/**
|
|
816
|
+
* Bash uses a deliberately small tail window to nudge callers toward focused
|
|
817
|
+
* commands and dedicated search tools. An explicitly configured shared tail
|
|
818
|
+
* budget still wins.
|
|
819
|
+
*/
|
|
820
|
+
export function resolveBashOutputSinkTailBytes(s: Settings): number {
|
|
821
|
+
return s.has("tools.artifactTailBytes") ? s.get("tools.artifactTailBytes") * 1024 : BASH_DEFAULT_OUTPUT_TAIL_BYTES;
|
|
822
|
+
}
|
|
823
|
+
/**
|
|
824
|
+
* Bash keeps only the tail unless the user explicitly opts into the shared
|
|
825
|
+
* head-retention setting. Schema defaults still apply to other streaming
|
|
826
|
+
* tools without silently turning Bash back into middle-elision mode.
|
|
827
|
+
*/
|
|
828
|
+
export function resolveBashOutputSinkHeadBytes(s: Settings): number {
|
|
829
|
+
return s.has("tools.artifactHeadBytes") ? resolveOutputSinkHeadBytes(s) : 0;
|
|
830
|
+
}
|
|
831
|
+
|
|
583
832
|
/**
|
|
584
833
|
* Resolve the per-line column cap from session settings. Shared by streaming
|
|
585
834
|
* executors (bash/python/ssh/eval via OutputSink) and the `read` tool's
|
|
@@ -710,6 +959,17 @@ async function spillLargeResultToArtifact(
|
|
|
710
959
|
return { ...result, content: newContent, details: newDetails };
|
|
711
960
|
}
|
|
712
961
|
|
|
962
|
+
const BODY_TRUNCATION_FOOTER_KEY = "__bodyTruncationFooter";
|
|
963
|
+
|
|
964
|
+
function stripBodyOwnedTruncationFooter(text: string, details: unknown): string {
|
|
965
|
+
const footer = (details as { [BODY_TRUNCATION_FOOTER_KEY]?: unknown } | undefined)?.[BODY_TRUNCATION_FOOTER_KEY];
|
|
966
|
+
if (typeof footer !== "string" || footer.length === 0) return text;
|
|
967
|
+
const trimmedText = text.trimEnd();
|
|
968
|
+
const trimmedFooter = footer.trim();
|
|
969
|
+
if (!trimmedText.endsWith(trimmedFooter)) return text;
|
|
970
|
+
return trimmedText.slice(0, -trimmedFooter.length).trimEnd();
|
|
971
|
+
}
|
|
972
|
+
|
|
713
973
|
/**
|
|
714
974
|
* Absolute inline-size backstop enforced after {@link spillLargeResultToArtifact}.
|
|
715
975
|
*
|
|
@@ -738,7 +998,8 @@ async function enforceInlineResultBackstop(
|
|
|
738
998
|
}
|
|
739
999
|
if (textParts.length === 0) return result;
|
|
740
1000
|
|
|
741
|
-
const
|
|
1001
|
+
const renderedText = textParts.length === 1 ? textParts[0] : textParts.join("\n");
|
|
1002
|
+
const fullText = stripBodyOwnedTruncationFooter(renderedText, result.details);
|
|
742
1003
|
const totalBytes = Buffer.byteLength(fullText, "utf-8");
|
|
743
1004
|
if (totalBytes <= maxInlineBytes) return result;
|
|
744
1005
|
|
package/src/tools/path-utils.ts
CHANGED
|
@@ -33,7 +33,11 @@ function normalizeUnicodeSpaces(str: string): string {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
function tryMacOSScreenshotPath(filePath: string): string {
|
|
36
|
-
|
|
36
|
+
// macOS writes a narrow no-break space before AM/PM, but the model normalizes it
|
|
37
|
+
// to a plain space. The original name is not always `…PM.png`: attachment paths
|
|
38
|
+
// append a timestamp (`…PM-1785075812409.png`), so match any non-alphanumeric
|
|
39
|
+
// separator or end of segment rather than a literal dot.
|
|
40
|
+
return filePath.replace(/ (AM|PM)(?=[^A-Za-z0-9/]|$)/g, `${NARROW_NO_BREAK_SPACE}$1`);
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
function tryNFDVariant(filePath: string): string {
|
|
@@ -633,6 +637,7 @@ export interface ToolScopeOptions {
|
|
|
633
637
|
rawPaths: string[];
|
|
634
638
|
cwd: string;
|
|
635
639
|
getArtifactsDir?: () => string | null;
|
|
640
|
+
getAuthorizedArtifactsDirs?: () => readonly string[];
|
|
636
641
|
/** Verb used in the "Cannot {action} internal URL without a backing file: …" message. */
|
|
637
642
|
internalUrlAction: string;
|
|
638
643
|
/** Collect absolute paths flagged immutable by their internal-URL handler. */
|
|
@@ -663,7 +668,7 @@ export interface ToolScopeResolution {
|
|
|
663
668
|
* 5. stat the resolved base path so callers can branch on directory vs file scope.
|
|
664
669
|
*/
|
|
665
670
|
export async function resolveToolSearchScope(opts: ToolScopeOptions): Promise<ToolScopeResolution> {
|
|
666
|
-
const { rawPaths: inputs, cwd, internalUrlAction, getArtifactsDir } = opts;
|
|
671
|
+
const { rawPaths: inputs, cwd, internalUrlAction, getArtifactsDir, getAuthorizedArtifactsDirs } = opts;
|
|
667
672
|
const rawPaths = inputs.map(normalizePathLikeInput);
|
|
668
673
|
if (rawPaths.some(rawPath => rawPath.length === 0)) {
|
|
669
674
|
throw new ToolError("`paths` must contain non-empty paths or globs");
|
|
@@ -679,7 +684,7 @@ export async function resolveToolSearchScope(opts: ToolScopeOptions): Promise<To
|
|
|
679
684
|
if (hasGlobPathChars(rawPath)) {
|
|
680
685
|
throw new ToolError(`Glob patterns are not supported for internal URLs: ${rawPath}`);
|
|
681
686
|
}
|
|
682
|
-
const resource = await internalRouter.resolve(rawPath, { cwd, getArtifactsDir });
|
|
687
|
+
const resource = await internalRouter.resolve(rawPath, { cwd, getArtifactsDir, getAuthorizedArtifactsDirs });
|
|
683
688
|
if (!resource.sourcePath) {
|
|
684
689
|
throw new ToolError(`Cannot ${internalUrlAction} internal URL without a backing file: ${rawPath}`);
|
|
685
690
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Settings } from "../config/settings";
|
|
2
|
+
import type { TruncationDirection } from "../session/streaming-output";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Read execution routes that have distinct truncation-default contracts.
|
|
6
|
+
* Routes that share the same default are grouped only when their truncation
|
|
7
|
+
* policy is identical; selection and rendering remain owned by read.ts.
|
|
8
|
+
*/
|
|
9
|
+
export type ReadRoute =
|
|
10
|
+
| "local-bare-stream"
|
|
11
|
+
| "local-bare-acp"
|
|
12
|
+
| "archive-member-bare"
|
|
13
|
+
| "local-range"
|
|
14
|
+
| "local-multi-range"
|
|
15
|
+
| "local-raw"
|
|
16
|
+
| "local-summary"
|
|
17
|
+
| "url-reader"
|
|
18
|
+
| "url-cache-page"
|
|
19
|
+
| "dir-local"
|
|
20
|
+
| "dir-archive"
|
|
21
|
+
| "sqlite-list"
|
|
22
|
+
| "sqlite-rows"
|
|
23
|
+
| "converted";
|
|
24
|
+
|
|
25
|
+
/** Resolve the configured default for a route; explicit parameters bypass it. */
|
|
26
|
+
export function pathDefault(route: ReadRoute, settings: Settings): TruncationDirection {
|
|
27
|
+
switch (route) {
|
|
28
|
+
case "local-bare-stream":
|
|
29
|
+
case "local-bare-acp":
|
|
30
|
+
case "archive-member-bare":
|
|
31
|
+
return settings.get("read.truncation") ?? "last";
|
|
32
|
+
default:
|
|
33
|
+
return "head";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Resolve the effective caller-facing direction with explicit precedence. */
|
|
38
|
+
export function resolveEffectiveDirection(
|
|
39
|
+
explicitParam: TruncationDirection | undefined,
|
|
40
|
+
route: ReadRoute,
|
|
41
|
+
settings: Settings,
|
|
42
|
+
): TruncationDirection {
|
|
43
|
+
return explicitParam !== undefined ? explicitParam : pathDefault(route, settings);
|
|
44
|
+
}
|