@oh-my-pi/pi-coding-agent 16.0.10 → 16.1.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 +57 -0
- package/dist/cli.js +3344 -3371
- package/dist/types/advisor/index.d.ts +1 -0
- package/dist/types/advisor/transcript-recorder.d.ts +52 -0
- package/dist/types/commit/agentic/agent.d.ts +1 -1
- package/dist/types/config/settings-schema.d.ts +14 -8
- package/dist/types/edit/file-snapshot-store.d.ts +1 -1
- package/dist/types/extensibility/extensions/types.d.ts +7 -0
- package/dist/types/modes/components/__tests__/skill-message.test.d.ts +1 -0
- package/dist/types/modes/components/agent-hub.d.ts +6 -1
- package/dist/types/modes/components/agent-transcript-viewer.d.ts +39 -0
- package/dist/types/modes/components/assistant-message.d.ts +8 -0
- package/dist/types/modes/components/cache-invalidation-marker.d.ts +34 -0
- package/dist/types/modes/components/chat-transcript-builder.d.ts +42 -0
- package/dist/types/modes/components/compaction-summary-message.d.ts +14 -1
- package/dist/types/modes/components/index.d.ts +0 -1
- package/dist/types/modes/components/message-frame.d.ts +6 -4
- package/dist/types/modes/controllers/command-controller.d.ts +3 -2
- package/dist/types/modes/interactive-mode.d.ts +4 -2
- package/dist/types/modes/theme/theme.d.ts +7 -1
- package/dist/types/modes/types.d.ts +9 -2
- package/dist/types/registry/agent-registry.d.ts +10 -3
- package/dist/types/sdk.d.ts +1 -1
- package/dist/types/session/agent-session.d.ts +20 -1
- package/dist/types/session/compact-modes.d.ts +60 -0
- package/dist/types/session/session-context.d.ts +7 -0
- package/dist/types/session/session-dump-format.d.ts +1 -0
- package/dist/types/session/streaming-output.d.ts +0 -2
- package/dist/types/session/tool-choice-queue.d.ts +14 -0
- package/dist/types/system-prompt.d.ts +3 -3
- package/dist/types/tools/__tests__/json-tree.test.d.ts +1 -0
- package/dist/types/tools/index.d.ts +4 -0
- package/dist/types/tools/resolve.d.ts +15 -5
- package/package.json +12 -12
- package/src/advisor/index.ts +1 -0
- package/src/advisor/transcript-recorder.ts +136 -0
- package/src/cli/stats-cli.ts +2 -11
- package/src/collab/host.ts +25 -13
- package/src/commit/agentic/agent.ts +2 -1
- package/src/commit/agentic/tools/git-file-diff.ts +2 -2
- package/src/commit/changelog/index.ts +1 -1
- package/src/commit/map-reduce/map-phase.ts +1 -1
- package/src/commit/map-reduce/utils.ts +1 -1
- package/src/config/settings-schema.ts +16 -9
- package/src/config/settings.ts +0 -6
- package/src/debug/log-viewer.ts +4 -4
- package/src/debug/raw-sse.ts +4 -4
- package/src/edit/file-snapshot-store.ts +1 -1
- package/src/edit/renderer.ts +9 -9
- package/src/eval/js/tool-bridge.ts +3 -2
- package/src/eval/py/prelude.py +3 -2
- package/src/export/html/tool-views.generated.js +28 -28
- package/src/extensibility/extensions/types.ts +7 -0
- package/src/hindsight/mental-models.ts +1 -1
- package/src/internal-urls/docs-index.generated.txt +1 -1
- package/src/internal-urls/history-protocol.ts +8 -3
- package/src/irc/bus.ts +8 -0
- package/src/lsp/index.ts +2 -2
- package/src/lsp/render.ts +7 -7
- package/src/main.ts +4 -1
- package/src/modes/acp/acp-agent.ts +63 -0
- package/src/modes/components/__tests__/skill-message.test.ts +92 -0
- package/src/modes/components/agent-dashboard.ts +1 -1
- package/src/modes/components/agent-hub.ts +97 -920
- package/src/modes/components/agent-transcript-viewer.ts +461 -0
- package/src/modes/components/assistant-message.ts +21 -0
- package/src/modes/components/cache-invalidation-marker.ts +84 -0
- package/src/modes/components/chat-transcript-builder.ts +476 -0
- package/src/modes/components/compaction-summary-message.ts +29 -1
- package/src/modes/components/custom-message.ts +4 -1
- package/src/modes/components/diff.ts +12 -35
- package/src/modes/components/dynamic-border.ts +1 -1
- package/src/modes/components/extensions/extension-dashboard.ts +1 -1
- package/src/modes/components/extensions/inspector-panel.ts +5 -5
- package/src/modes/components/hook-selector.ts +2 -2
- package/src/modes/components/index.ts +0 -1
- package/src/modes/components/message-frame.ts +10 -6
- package/src/modes/components/model-selector.ts +2 -2
- package/src/modes/components/overlay-box.ts +10 -9
- package/src/modes/components/skill-message.ts +39 -19
- package/src/modes/components/tiny-title-download-progress.ts +1 -1
- package/src/modes/components/welcome.ts +1 -1
- package/src/modes/controllers/command-controller.ts +12 -2
- package/src/modes/controllers/event-controller.ts +15 -1
- package/src/modes/controllers/input-controller.ts +8 -1
- package/src/modes/controllers/selector-controller.ts +11 -1
- package/src/modes/interactive-mode.ts +13 -3
- package/src/modes/theme/theme.ts +14 -0
- package/src/modes/types.ts +9 -2
- package/src/modes/utils/ui-helpers.ts +20 -2
- package/src/prompts/steering/user-interjection.md +3 -4
- package/src/prompts/tools/read.md +1 -1
- package/src/registry/agent-registry.ts +13 -4
- package/src/sdk.ts +9 -7
- package/src/session/agent-session.ts +182 -16
- package/src/session/compact-modes.ts +105 -0
- package/src/session/messages.ts +7 -9
- package/src/session/session-context.ts +54 -7
- package/src/session/session-dump-format.ts +4 -2
- package/src/session/session-history-format.ts +1 -1
- package/src/session/snapcompact-inline.ts +2 -2
- package/src/session/streaming-output.ts +5 -5
- package/src/session/tool-choice-queue.ts +59 -0
- package/src/slash-commands/builtin-registry.ts +16 -4
- package/src/system-prompt.ts +10 -9
- package/src/task/executor.ts +1 -1
- package/src/task/output-manager.ts +5 -0
- package/src/tools/__tests__/json-tree.test.ts +35 -0
- package/src/tools/approval.ts +1 -1
- package/src/tools/bash-interactive.ts +4 -4
- package/src/tools/bash.ts +0 -1
- package/src/tools/browser.ts +0 -1
- package/src/tools/eval.ts +1 -1
- package/src/tools/gh.ts +1 -1
- package/src/tools/index.ts +4 -0
- package/src/tools/irc.ts +1 -1
- package/src/tools/json-tree.ts +22 -5
- package/src/tools/read.ts +5 -6
- package/src/tools/resolve.ts +66 -41
- package/src/tui/output-block.ts +9 -9
- package/src/web/scrapers/firefox-addons.ts +1 -1
- package/src/web/scrapers/github.ts +1 -1
- package/src/web/scrapers/go-pkg.ts +2 -2
- package/src/web/scrapers/metacpan.ts +2 -2
- package/src/web/scrapers/nvd.ts +2 -2
- package/src/web/scrapers/ollama.ts +1 -1
- package/src/web/scrapers/opencorporates.ts +1 -1
- package/src/web/scrapers/pub-dev.ts +1 -1
- package/src/web/scrapers/repology.ts +1 -1
- package/src/web/scrapers/sourcegraph.ts +1 -1
- package/src/web/scrapers/terraform.ts +6 -6
- package/src/web/scrapers/wikidata.ts +2 -2
- package/src/workspace-tree.ts +1 -1
- package/dist/types/modes/components/branch-summary-message.d.ts +0 -13
- package/src/modes/components/branch-summary-message.ts +0 -46
package/src/tools/gh.ts
CHANGED
|
@@ -2179,7 +2179,7 @@ function formatPrFiles(files: GhPrFile[] | undefined): string[] {
|
|
|
2179
2179
|
}
|
|
2180
2180
|
|
|
2181
2181
|
if (files.length > FILE_PREVIEW_LIMIT) {
|
|
2182
|
-
lines.push(
|
|
2182
|
+
lines.push(`[…${files.length - FILE_PREVIEW_LIMIT} files elided…]`);
|
|
2183
2183
|
}
|
|
2184
2184
|
|
|
2185
2185
|
return lines;
|
package/src/tools/index.ts
CHANGED
|
@@ -312,6 +312,10 @@ export interface ToolSession {
|
|
|
312
312
|
steer?(message: { customType: string; content: string; details?: unknown }): void;
|
|
313
313
|
/** Peek the currently in-flight tool-choice queue directive's invocation handler. Used by the `resolve` tool to dispatch to the pending action. */
|
|
314
314
|
peekQueueInvoker?(): ((input: unknown) => Promise<unknown> | unknown) | undefined;
|
|
315
|
+
/** Peek the most-recently registered non-forcing pending preview invoker. The `resolve`
|
|
316
|
+
* tool dispatches to it so a staged preview resolves WITHOUT forcing tool_choice — the
|
|
317
|
+
* agent-loop's SoftToolRequirement lifecycle owns reminder injection and escalation. */
|
|
318
|
+
peekPendingInvoker?(): ((input: unknown) => Promise<unknown> | unknown) | undefined;
|
|
315
319
|
/** Peek the long-lived "standing" resolve handler registered by a mode (e.g. plan mode).
|
|
316
320
|
* Consulted by the `resolve` tool as a fallback when no queue invoker is in flight,
|
|
317
321
|
* letting modes accept `resolve` invocations without forcing the tool choice every turn. */
|
package/src/tools/irc.ts
CHANGED
|
@@ -182,7 +182,7 @@ export class IrcTool implements AgentTool<typeof ircSchema, IrcDetails> {
|
|
|
182
182
|
const bus = IrcBus.global();
|
|
183
183
|
const peers = registry
|
|
184
184
|
.list()
|
|
185
|
-
.filter(ref => ref.id !== senderId && ref.status !== "aborted")
|
|
185
|
+
.filter(ref => ref.id !== senderId && ref.status !== "aborted" && ref.kind !== "advisor")
|
|
186
186
|
.map(ref => ({
|
|
187
187
|
id: ref.id,
|
|
188
188
|
displayName: ref.displayName,
|
package/src/tools/json-tree.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* JSON tree rendering utilities shared across tool renderers.
|
|
3
3
|
*/
|
|
4
|
-
import { INTENT_FIELD } from "@oh-my-pi/pi-
|
|
4
|
+
import { INTENT_FIELD } from "@oh-my-pi/pi-wire";
|
|
5
5
|
import type { Theme } from "../modes/theme/theme";
|
|
6
6
|
import { truncateToWidth } from "./render-utils";
|
|
7
7
|
|
|
@@ -19,6 +19,8 @@ const ARGS_INLINE_PAIR_SEP = ", ";
|
|
|
19
19
|
const ARGS_INLINE_PAIR_SEP_WIDTH = Bun.stringWidth(ARGS_INLINE_PAIR_SEP);
|
|
20
20
|
const ARGS_INLINE_MORE = "…";
|
|
21
21
|
const ARGS_INLINE_MORE_WIDTH = Bun.stringWidth(ARGS_INLINE_MORE);
|
|
22
|
+
/** Minimal value footprint (quotes + a couple chars) reserved for each not-yet-rendered key. */
|
|
23
|
+
const ARGS_INLINE_TAIL_VALUE_RESERVE = 4;
|
|
22
24
|
|
|
23
25
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
24
26
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
@@ -49,10 +51,15 @@ export function formatScalar(value: unknown, maxLen: number): string {
|
|
|
49
51
|
* Format args inline for collapsed view.
|
|
50
52
|
*/
|
|
51
53
|
export function formatArgsInline(args: Record<string, unknown>, maxWidth: number): string {
|
|
52
|
-
|
|
53
|
-
let width = 0;
|
|
54
|
+
const keys: string[] = [];
|
|
54
55
|
for (const key in args) {
|
|
55
56
|
if (key in HIDDEN_ARG_KEYS) continue;
|
|
57
|
+
keys.push(key);
|
|
58
|
+
}
|
|
59
|
+
let result = "";
|
|
60
|
+
let width = 0;
|
|
61
|
+
for (let i = 0; i < keys.length; i++) {
|
|
62
|
+
const key = keys[i];
|
|
56
63
|
const value = args[key];
|
|
57
64
|
const sep = width > 0 ? ARGS_INLINE_PAIR_SEP : "";
|
|
58
65
|
const sepW = width > 0 ? ARGS_INLINE_PAIR_SEP_WIDTH : 0;
|
|
@@ -61,11 +68,21 @@ export function formatArgsInline(args: Record<string, unknown>, maxWidth: number
|
|
|
61
68
|
if (cap <= 0) {
|
|
62
69
|
return `${result}${ARGS_INLINE_MORE}`;
|
|
63
70
|
}
|
|
64
|
-
|
|
71
|
+
// Reserve each still-pending key's minimal footprint (sep + name + `=` +
|
|
72
|
+
// a short value) so a long value can't starve the keys that follow it.
|
|
73
|
+
let tailReserve = 0;
|
|
74
|
+
for (let j = i + 1; j < keys.length; j++) {
|
|
75
|
+
tailReserve += ARGS_INLINE_PAIR_SEP_WIDTH + Bun.stringWidth(keys[j]) + 1 + ARGS_INLINE_TAIL_VALUE_RESERVE;
|
|
76
|
+
}
|
|
77
|
+
// Budget the whole `key=value` piece against the width left after the
|
|
78
|
+
// tail reserve, then back out the value's share. The last key reserves
|
|
79
|
+
// nothing and fills the line.
|
|
80
|
+
const pieceBudget = Math.min(cap, maxWidth - current - tailReserve);
|
|
81
|
+
const valueMaxLen = Math.max(1, pieceBudget - Bun.stringWidth(key) - 3);
|
|
65
82
|
const valueStr = formatScalar(value, valueMaxLen);
|
|
66
83
|
const piece = `${key}=${valueStr}`;
|
|
67
84
|
const pieceW = Bun.stringWidth(piece);
|
|
68
|
-
if (pieceW >
|
|
85
|
+
if (pieceW > pieceBudget) {
|
|
69
86
|
return `${result}${sep}${truncateToWidth(piece, cap)}`;
|
|
70
87
|
}
|
|
71
88
|
result += sep + piece;
|
package/src/tools/read.ts
CHANGED
|
@@ -275,7 +275,7 @@ function formatMergedBraceLine(
|
|
|
275
275
|
shouldAddHashLines: boolean,
|
|
276
276
|
shouldAddLineNumbers: boolean,
|
|
277
277
|
): { model: string; display: string } {
|
|
278
|
-
const merged = `${headText.trimEnd()}
|
|
278
|
+
const merged = `${headText.trimEnd()} … ${tailText.trim()}`;
|
|
279
279
|
if (shouldAddHashLines) {
|
|
280
280
|
return { model: `${startLine}-${endLine}:${merged}`, display: merged };
|
|
281
281
|
}
|
|
@@ -315,7 +315,7 @@ const FOOTER_RANGE_SAMPLES = 2;
|
|
|
315
315
|
|
|
316
316
|
/**
|
|
317
317
|
* Footer appended to summarized reads telling the model how to recover the
|
|
318
|
-
* elided body. Without this hint, agents either ignore the
|
|
318
|
+
* elided body. Without this hint, agents either ignore the `…`/`{ … }`
|
|
319
319
|
* markers or burn a turn guessing the right selector (see issue #1046). The
|
|
320
320
|
* footer demonstrates the multi-range selector syntax with concrete sample
|
|
321
321
|
* ranges drawn from the actual elision so the model re-reads only what it
|
|
@@ -327,7 +327,6 @@ function formatSummaryElisionFooter(
|
|
|
327
327
|
elidedLines: number,
|
|
328
328
|
): string {
|
|
329
329
|
if (elidedRanges.length === 0) return "";
|
|
330
|
-
const lineWord = elidedLines === 1 ? "line" : "lines";
|
|
331
330
|
const sampleCount = Math.min(elidedRanges.length, FOOTER_RANGE_SAMPLES);
|
|
332
331
|
const selector = elidedRanges
|
|
333
332
|
.slice(0, sampleCount)
|
|
@@ -335,7 +334,7 @@ function formatSummaryElisionFooter(
|
|
|
335
334
|
.join(",");
|
|
336
335
|
const example = `${readPath}:${selector}`;
|
|
337
336
|
const tail = elidedRanges.length > sampleCount ? `, e.g. ${example}` : ` with ${example}`;
|
|
338
|
-
return `[
|
|
337
|
+
return `[…${elidedLines}ln elided; re-read needed ranges${tail}]`;
|
|
339
338
|
}
|
|
340
339
|
const READ_CHUNK_SIZE = 8 * 1024;
|
|
341
340
|
|
|
@@ -1904,8 +1903,8 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
|
|
|
1904
1903
|
let elidedLines = 0;
|
|
1905
1904
|
for (const unit of units) {
|
|
1906
1905
|
if (unit.kind === "elided") {
|
|
1907
|
-
modelParts.push("
|
|
1908
|
-
displayParts.push("
|
|
1906
|
+
modelParts.push("…");
|
|
1907
|
+
displayParts.push("…");
|
|
1909
1908
|
elidedRanges.push({ start: unit.startLine, end: unit.endLine });
|
|
1910
1909
|
elidedLines += unit.endLine - unit.startLine + 1;
|
|
1911
1910
|
continue;
|
package/src/tools/resolve.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
AgentTool,
|
|
3
|
+
AgentToolContext,
|
|
4
|
+
AgentToolResult,
|
|
5
|
+
AgentToolUpdateCallback,
|
|
6
|
+
CustomMessage,
|
|
7
|
+
} from "@oh-my-pi/pi-agent-core";
|
|
2
8
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
3
9
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
4
10
|
import { prompt, untilAborted } from "@oh-my-pi/pi-utils";
|
|
@@ -28,11 +34,18 @@ export interface ResolveToolDetails {
|
|
|
28
34
|
sourceResultDetails?: unknown;
|
|
29
35
|
}
|
|
30
36
|
|
|
37
|
+
/** Monotonic suffix making each staged preview's pending-invoker id UNIQUE, so
|
|
38
|
+
* stacked previews never clobber one another by label. */
|
|
39
|
+
let pendingPreviewSeq = 0;
|
|
40
|
+
|
|
31
41
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
42
|
+
* Register a non-forcing resolve-protocol handler for a staged preview. Wraps the
|
|
43
|
+
* caller's apply/reject into an onInvoked closure (matching the resolve schema) and
|
|
44
|
+
* stores it on the tool-choice queue's pending-invoker registry under a UNIQUE id.
|
|
45
|
+
* The `resolve` tool dispatches to it; the agent-loop's SoftToolRequirement
|
|
46
|
+
* lifecycle injects the preview reminder and escalates to a forced `resolve` only
|
|
47
|
+
* if the model declines — so a compliant turn pays ZERO tool_choice change (no
|
|
48
|
+
* prompt-cache messages-cache invalidation).
|
|
36
49
|
*
|
|
37
50
|
* This is the canonical entry point for any tool that wants preview/apply
|
|
38
51
|
* semantics. No session-level abstraction is needed: callers pass their
|
|
@@ -48,46 +61,55 @@ export function queueResolveHandler(
|
|
|
48
61
|
},
|
|
49
62
|
): void {
|
|
50
63
|
const queue = session.getToolChoiceQueue?.();
|
|
51
|
-
|
|
52
|
-
if (!queue || !forced || typeof forced === "string") return;
|
|
64
|
+
if (!queue) return;
|
|
53
65
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
customType: "resolve-reminder",
|
|
57
|
-
content: [
|
|
58
|
-
"<system-reminder>",
|
|
59
|
-
"This is a preview. Call the `resolve` tool to apply or discard these changes.",
|
|
60
|
-
"</system-reminder>",
|
|
61
|
-
].join("\n"),
|
|
62
|
-
details: { toolName: options.sourceToolName },
|
|
63
|
-
});
|
|
64
|
-
};
|
|
66
|
+
// Unique per preview: stacked/sequential previews each get their own entry.
|
|
67
|
+
const id = `pending-action:${options.sourceToolName}:${pendingPreviewSeq++}`;
|
|
65
68
|
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
// Apply threw (e.g. ast_edit overlapping replacements). Re-push the
|
|
79
|
-
// same directive so the preview remains pending and the model can
|
|
80
|
-
// `discard` or fix-and-retry on the next turn instead of being
|
|
81
|
-
// stranded with no pending action to address.
|
|
82
|
-
pushDirective();
|
|
83
|
-
steerReminder();
|
|
84
|
-
},
|
|
85
|
-
}),
|
|
69
|
+
const onInvoked = async (input: unknown): Promise<AgentToolResult<unknown>> => {
|
|
70
|
+
const result = await runResolveInvocation(input as ResolveParams, {
|
|
71
|
+
sourceToolName: options.sourceToolName,
|
|
72
|
+
label: options.label,
|
|
73
|
+
apply: options.apply,
|
|
74
|
+
reject: options.reject,
|
|
75
|
+
onApplyError: () => {
|
|
76
|
+
// Apply threw (e.g. ast_edit overlapping replacements). Keep the preview
|
|
77
|
+
// pending under the SAME id so the model can `discard` or fix-and-retry;
|
|
78
|
+
// runResolveInvocation rethrows, so the success-path removal below is skipped.
|
|
79
|
+
queue.registerPendingInvoker(id, options.sourceToolName, onInvoked);
|
|
80
|
+
},
|
|
86
81
|
});
|
|
82
|
+
// Resolved (apply succeeded, or discard): consume the staged action exactly once.
|
|
83
|
+
queue.removePendingInvoker(id);
|
|
84
|
+
return result;
|
|
87
85
|
};
|
|
88
86
|
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
// NON-FORCING: register so `resolve` can dispatch here WITHOUT changing
|
|
88
|
+
// tool_choice. The agent-loop injects the reminder (from the SoftToolRequirement
|
|
89
|
+
// the session builds) and forces a resolve turn only on non-compliance.
|
|
90
|
+
queue.registerPendingInvoker(id, options.sourceToolName, onInvoked);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The canonical preview reminder. The resolve mechanism owns the wording; the
|
|
95
|
+
* agent-loop delivers it via the session's `SoftToolRequirement.reminder` (injected
|
|
96
|
+
* once per pending-preview head) instead of a host-side steer, so it lands as a
|
|
97
|
+
* stable mid-history append and never churns the cached prefix.
|
|
98
|
+
*/
|
|
99
|
+
export function buildResolveReminderMessage(sourceToolName: string): CustomMessage {
|
|
100
|
+
return {
|
|
101
|
+
role: "custom",
|
|
102
|
+
customType: "resolve-reminder",
|
|
103
|
+
content: [
|
|
104
|
+
"<system-reminder>",
|
|
105
|
+
"This is a preview. Call the `resolve` tool to apply or discard these changes.",
|
|
106
|
+
"</system-reminder>",
|
|
107
|
+
].join("\n"),
|
|
108
|
+
display: false,
|
|
109
|
+
details: { toolName: sourceToolName },
|
|
110
|
+
attribution: "agent",
|
|
111
|
+
timestamp: Date.now(),
|
|
112
|
+
};
|
|
91
113
|
}
|
|
92
114
|
|
|
93
115
|
/**
|
|
@@ -185,7 +207,10 @@ export class ResolveTool implements AgentTool<typeof resolveSchema, ResolveToolD
|
|
|
185
207
|
_context?: AgentToolContext,
|
|
186
208
|
): Promise<AgentToolResult<ResolveToolDetails>> {
|
|
187
209
|
return untilAborted(signal, async () => {
|
|
188
|
-
const invoker =
|
|
210
|
+
const invoker =
|
|
211
|
+
this.session.peekQueueInvoker?.() ??
|
|
212
|
+
this.session.peekPendingInvoker?.() ??
|
|
213
|
+
this.session.peekStandingResolveHandler?.();
|
|
189
214
|
if (!invoker) {
|
|
190
215
|
// `discard` is a request to cancel/abort a staged action. When nothing is
|
|
191
216
|
// pending, the desired end-state (no staged change) already holds, so honor
|
package/src/tui/output-block.ts
CHANGED
|
@@ -48,8 +48,8 @@ function normalizeContentPaddingLeft(value: number | undefined): number {
|
|
|
48
48
|
|
|
49
49
|
export function renderOutputBlock(options: OutputBlockOptions, theme: Theme): string[] {
|
|
50
50
|
const { header, headerMeta, state, sections = [], width, applyBg = true } = options;
|
|
51
|
-
const h = theme.
|
|
52
|
-
const v = theme.
|
|
51
|
+
const h = theme.boxRound.horizontal;
|
|
52
|
+
const v = theme.boxRound.vertical;
|
|
53
53
|
const cap = h.repeat(3);
|
|
54
54
|
const lineWidth = Math.max(0, width);
|
|
55
55
|
// Border colors: running/pending use accent, success uses dim (gray), error/warning keep their colors
|
|
@@ -84,8 +84,8 @@ export function renderOutputBlock(options: OutputBlockOptions, theme: Theme): st
|
|
|
84
84
|
const rows: BlockRow[] = [];
|
|
85
85
|
rows.push({
|
|
86
86
|
kind: "bar",
|
|
87
|
-
leftChar: theme.
|
|
88
|
-
rightChar: theme.
|
|
87
|
+
leftChar: theme.boxRound.topLeft,
|
|
88
|
+
rightChar: theme.boxRound.topRight,
|
|
89
89
|
label: header,
|
|
90
90
|
meta: headerMeta,
|
|
91
91
|
});
|
|
@@ -99,15 +99,15 @@ export function renderOutputBlock(options: OutputBlockOptions, theme: Theme): st
|
|
|
99
99
|
if (section.label) {
|
|
100
100
|
rows.push({
|
|
101
101
|
kind: "bar",
|
|
102
|
-
leftChar: theme.
|
|
103
|
-
rightChar: theme.
|
|
102
|
+
leftChar: theme.boxRound.teeRight,
|
|
103
|
+
rightChar: theme.boxRound.teeLeft,
|
|
104
104
|
label: section.label,
|
|
105
105
|
});
|
|
106
106
|
} else if (section.separator && sectionIndex > 0) {
|
|
107
107
|
rows.push({
|
|
108
108
|
kind: "bar",
|
|
109
|
-
leftChar: theme.
|
|
110
|
-
rightChar: theme.
|
|
109
|
+
leftChar: theme.boxRound.teeRight,
|
|
110
|
+
rightChar: theme.boxRound.teeLeft,
|
|
111
111
|
});
|
|
112
112
|
}
|
|
113
113
|
const allLines = section.lines.flatMap(l => l.split("\n"));
|
|
@@ -126,7 +126,7 @@ export function renderOutputBlock(options: OutputBlockOptions, theme: Theme): st
|
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
rows.push({ kind: "bottom", leftChar: theme.
|
|
129
|
+
rows.push({ kind: "bottom", leftChar: theme.boxRound.bottomLeft, rightChar: theme.boxRound.bottomRight });
|
|
130
130
|
|
|
131
131
|
const H = rows.length;
|
|
132
132
|
|
|
@@ -173,7 +173,7 @@ export const handleFirefoxAddons: SpecialHandler = async (
|
|
|
173
173
|
md += `- ${permission}\n`;
|
|
174
174
|
}
|
|
175
175
|
if (permissions.length > preview.length) {
|
|
176
|
-
md += `\n
|
|
176
|
+
md += `\n[…${permissions.length - preview.length} permissions elided…]\n`;
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
179
|
|
|
@@ -211,7 +211,7 @@ export const handleGoPkg: SpecialHandler = async (
|
|
|
211
211
|
sections.push(exported.slice(0, 50).join("\n"));
|
|
212
212
|
if (exported.length > 50) {
|
|
213
213
|
notes.push(`showing 50 of ${exported.length} exports`);
|
|
214
|
-
sections.push(`\n
|
|
214
|
+
sections.push(`\n[…${exported.length - 50} exports elided…]`);
|
|
215
215
|
}
|
|
216
216
|
sections.push("");
|
|
217
217
|
}
|
|
@@ -240,7 +240,7 @@ export const handleGoPkg: SpecialHandler = async (
|
|
|
240
240
|
sections.push(imports.slice(0, 20).join("\n"));
|
|
241
241
|
if (imports.length > 20) {
|
|
242
242
|
notes.push(`showing 20 of ${imports.length} imports`);
|
|
243
|
-
sections.push(`\n
|
|
243
|
+
sections.push(`\n[…${imports.length - 20} imports elided…]`);
|
|
244
244
|
}
|
|
245
245
|
sections.push("");
|
|
246
246
|
}
|
|
@@ -162,7 +162,7 @@ function formatModuleMarkdown(module: ModuleResponse, release: ReleaseResponse |
|
|
|
162
162
|
md += "\n";
|
|
163
163
|
}
|
|
164
164
|
if (runtimeDeps.length > 20) {
|
|
165
|
-
md += `\n
|
|
165
|
+
md += `\n[…${runtimeDeps.length - 20} dependencies elided…]\n`;
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
}
|
|
@@ -212,7 +212,7 @@ function formatReleaseMarkdown(release: ReleaseResponse): string {
|
|
|
212
212
|
md += "\n";
|
|
213
213
|
}
|
|
214
214
|
if (runtimeDeps.length > 20) {
|
|
215
|
-
md += `\n
|
|
215
|
+
md += `\n[…${runtimeDeps.length - 20} dependencies elided…]\n`;
|
|
216
216
|
}
|
|
217
217
|
}
|
|
218
218
|
|
package/src/web/scrapers/nvd.ts
CHANGED
|
@@ -182,7 +182,7 @@ export const handleNvd: SpecialHandler = async (
|
|
|
182
182
|
md += `- \`${cpe}\`\n`;
|
|
183
183
|
}
|
|
184
184
|
if (cpes.length > 20) {
|
|
185
|
-
md += `\n
|
|
185
|
+
md += `\n[…${cpes.length - 20} CPEs elided…]\n`;
|
|
186
186
|
}
|
|
187
187
|
md += "\n";
|
|
188
188
|
}
|
|
@@ -195,7 +195,7 @@ export const handleNvd: SpecialHandler = async (
|
|
|
195
195
|
md += `- ${ref.url}${tags}\n`;
|
|
196
196
|
}
|
|
197
197
|
if (vuln.references.length > 15) {
|
|
198
|
-
md += `\n
|
|
198
|
+
md += `\n[…${vuln.references.length - 15} references elided…]\n`;
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
201
|
|
|
@@ -139,7 +139,7 @@ function formatTagList(tags: string[], maxItems: number): string {
|
|
|
139
139
|
const limited = tags.slice(0, maxItems);
|
|
140
140
|
const formatted = limited.map(tag => `\`${tag}\``).join(", ");
|
|
141
141
|
if (tags.length > maxItems) {
|
|
142
|
-
return `${formatted}
|
|
142
|
+
return `${formatted} […${tags.length - maxItems} tags elided…]`;
|
|
143
143
|
}
|
|
144
144
|
return formatted;
|
|
145
145
|
}
|
|
@@ -216,7 +216,7 @@ export const handleOpenCorporates: SpecialHandler = async (
|
|
|
216
216
|
md += "\n";
|
|
217
217
|
}
|
|
218
218
|
if (inactiveOfficers.length > 10) {
|
|
219
|
-
md += `\n
|
|
219
|
+
md += `\n[…${inactiveOfficers.length - 10} former officers elided…]\n`;
|
|
220
220
|
}
|
|
221
221
|
md += "\n";
|
|
222
222
|
}
|
|
@@ -109,7 +109,7 @@ export const handlePubDev: SpecialHandler = async (url: string, timeout: number,
|
|
|
109
109
|
md += "\n";
|
|
110
110
|
}
|
|
111
111
|
if (deps.length > 20) {
|
|
112
|
-
md += `\n
|
|
112
|
+
md += `\n[…${deps.length - 20} dependencies elided…]\n`;
|
|
113
113
|
}
|
|
114
114
|
md += "\n";
|
|
115
115
|
}
|
|
@@ -239,7 +239,7 @@ export const handleRepology: SpecialHandler = async (
|
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
if (packages.length > 15) {
|
|
242
|
-
md += `\n
|
|
242
|
+
md += `\n[…${packages.length - 15} repositories elided…]\n`;
|
|
243
243
|
}
|
|
244
244
|
|
|
245
245
|
md += `\n---\n\n[View on Repology](${url})\n`;
|
|
@@ -294,7 +294,7 @@ async function renderSearch(
|
|
|
294
294
|
}
|
|
295
295
|
|
|
296
296
|
if (results.length > maxResults) {
|
|
297
|
-
md +=
|
|
297
|
+
md += `[…${results.length - maxResults} results elided…]\n`;
|
|
298
298
|
}
|
|
299
299
|
|
|
300
300
|
return { content: md, ok: true };
|
|
@@ -150,7 +150,7 @@ async function handleModuleUrl(
|
|
|
150
150
|
md += `| ${input.name} | \`${type}\` | ${required} | ${desc} |\n`;
|
|
151
151
|
}
|
|
152
152
|
if (inputs.length > 30) {
|
|
153
|
-
md += `\n
|
|
153
|
+
md += `\n[…${inputs.length - 30} inputs elided…]\n`;
|
|
154
154
|
}
|
|
155
155
|
md += "\n";
|
|
156
156
|
}
|
|
@@ -165,7 +165,7 @@ async function handleModuleUrl(
|
|
|
165
165
|
md += "\n";
|
|
166
166
|
}
|
|
167
167
|
if (outputs.length > 20) {
|
|
168
|
-
md += `\n
|
|
168
|
+
md += `\n[…${outputs.length - 20} outputs elided…]\n`;
|
|
169
169
|
}
|
|
170
170
|
md += "\n";
|
|
171
171
|
}
|
|
@@ -180,7 +180,7 @@ async function handleModuleUrl(
|
|
|
180
180
|
md += "\n";
|
|
181
181
|
}
|
|
182
182
|
if (deps.length > 15) {
|
|
183
|
-
md += `\n
|
|
183
|
+
md += `\n[…${deps.length - 15} dependencies elided…]\n`;
|
|
184
184
|
}
|
|
185
185
|
md += "\n";
|
|
186
186
|
}
|
|
@@ -193,7 +193,7 @@ async function handleModuleUrl(
|
|
|
193
193
|
md += `- \`${res.type}\` (${res.name})\n`;
|
|
194
194
|
}
|
|
195
195
|
if (resources.length > 20) {
|
|
196
|
-
md += `\n
|
|
196
|
+
md += `\n[…${resources.length - 20} resources elided…]\n`;
|
|
197
197
|
}
|
|
198
198
|
md += "\n";
|
|
199
199
|
}
|
|
@@ -205,7 +205,7 @@ async function handleModuleUrl(
|
|
|
205
205
|
md += `- **${sub.name}**: \`${sub.path}\`\n`;
|
|
206
206
|
}
|
|
207
207
|
if (mod.submodules.length > 10) {
|
|
208
|
-
md += `\n
|
|
208
|
+
md += `\n[…${mod.submodules.length - 10} submodules elided…]\n`;
|
|
209
209
|
}
|
|
210
210
|
}
|
|
211
211
|
|
|
@@ -267,7 +267,7 @@ async function handleProviderUrl(
|
|
|
267
267
|
md += `- [${doc.title}](https://registry.terraform.io/providers/${namespace}/${type}/latest/docs/${doc.category}/${doc.slug})\n`;
|
|
268
268
|
}
|
|
269
269
|
if (docs.length > 15) {
|
|
270
|
-
md += `\n
|
|
270
|
+
md += `\n[…${docs.length - 15} documents elided…]\n`;
|
|
271
271
|
}
|
|
272
272
|
md += "\n";
|
|
273
273
|
}
|
|
@@ -169,7 +169,7 @@ export const handleWikidata: SpecialHandler = async (
|
|
|
169
169
|
if (values.length > 0) {
|
|
170
170
|
// Limit values shown per property
|
|
171
171
|
const displayValues = values.slice(0, 10);
|
|
172
|
-
const overflow = values.length > 10 ? `
|
|
172
|
+
const overflow = values.length > 10 ? ` […${values.length - 10} values elided…]` : "";
|
|
173
173
|
processedProperties.push(`- **${propLabel}:** ${displayValues.join(", ")}${overflow}`);
|
|
174
174
|
}
|
|
175
175
|
}
|
|
@@ -187,7 +187,7 @@ export const handleWikidata: SpecialHandler = async (
|
|
|
187
187
|
const maxProps = 50;
|
|
188
188
|
md += processedProperties.slice(0, maxProps).join("\n");
|
|
189
189
|
if (processedProperties.length > maxProps) {
|
|
190
|
-
md += `\n\n
|
|
190
|
+
md += `\n\n[…${processedProperties.length - maxProps} properties elided…]`;
|
|
191
191
|
}
|
|
192
192
|
md += "\n";
|
|
193
193
|
}
|
package/src/workspace-tree.ts
CHANGED
|
@@ -298,7 +298,7 @@ function applyLineCap(
|
|
|
298
298
|
const removed = new Set(removable.map(item => item.index));
|
|
299
299
|
const kept = lines.filter((_, index) => !removed.has(index));
|
|
300
300
|
kept.push({
|
|
301
|
-
label:
|
|
301
|
+
label: `[…${removable.length}ln elided…]`,
|
|
302
302
|
depth: 0,
|
|
303
303
|
isRoot: false,
|
|
304
304
|
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { Box } from "@oh-my-pi/pi-tui";
|
|
2
|
-
import type { BranchSummaryMessage } from "../../session/messages";
|
|
3
|
-
/**
|
|
4
|
-
* Component that renders a branch summary message with collapsed/expanded state.
|
|
5
|
-
* Uses same background color as hook messages for visual consistency.
|
|
6
|
-
*/
|
|
7
|
-
export declare class BranchSummaryMessageComponent extends Box {
|
|
8
|
-
#private;
|
|
9
|
-
private readonly message;
|
|
10
|
-
constructor(message: BranchSummaryMessage);
|
|
11
|
-
setExpanded(expanded: boolean): void;
|
|
12
|
-
invalidate(): void;
|
|
13
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { Box, Markdown, Spacer, Text } from "@oh-my-pi/pi-tui";
|
|
2
|
-
import { getMarkdownTheme, theme } from "../../modes/theme/theme";
|
|
3
|
-
import type { BranchSummaryMessage } from "../../session/messages";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Component that renders a branch summary message with collapsed/expanded state.
|
|
7
|
-
* Uses same background color as hook messages for visual consistency.
|
|
8
|
-
*/
|
|
9
|
-
export class BranchSummaryMessageComponent extends Box {
|
|
10
|
-
#expanded = false;
|
|
11
|
-
|
|
12
|
-
constructor(private readonly message: BranchSummaryMessage) {
|
|
13
|
-
super(1, 1, t => theme.bg("customMessageBg", t));
|
|
14
|
-
this.setIgnoreTight(true);
|
|
15
|
-
this.#updateDisplay();
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
setExpanded(expanded: boolean): void {
|
|
19
|
-
this.#expanded = expanded;
|
|
20
|
-
this.#updateDisplay();
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
override invalidate(): void {
|
|
24
|
-
super.invalidate();
|
|
25
|
-
this.#updateDisplay();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
#updateDisplay(): void {
|
|
29
|
-
this.clear();
|
|
30
|
-
|
|
31
|
-
const label = theme.fg("customMessageLabel", theme.bold("[branch]"));
|
|
32
|
-
this.addChild(new Text(label, 0, 0));
|
|
33
|
-
this.addChild(new Spacer(1));
|
|
34
|
-
|
|
35
|
-
if (this.#expanded) {
|
|
36
|
-
const header = "**Branch Summary**\n\n";
|
|
37
|
-
this.addChild(
|
|
38
|
-
new Markdown(header + this.message.summary, 0, 0, getMarkdownTheme(), {
|
|
39
|
-
color: (text: string) => theme.fg("customMessageText", text),
|
|
40
|
-
}),
|
|
41
|
-
);
|
|
42
|
-
} else {
|
|
43
|
-
this.addChild(new Text(theme.fg("customMessageText", "Branch summary (ctrl+o to expand)"), 0, 0));
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|