mixdog 0.8.0 → 0.9.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/README.md +47 -23
- package/package.json +33 -27
- package/scripts/_test-folder-dialog.mjs +30 -0
- package/scripts/agent-parallel-smoke.mjs +388 -0
- package/scripts/agent-tag-reuse-smoke.mjs +183 -0
- package/scripts/background-task-meta-smoke.mjs +38 -0
- package/scripts/boot-smoke.mjs +52 -9
- package/scripts/build-runtime-linux.sh +348 -0
- package/scripts/build-runtime-macos.sh +217 -0
- package/scripts/build-runtime-windows.ps1 +242 -0
- package/scripts/compact-active-turn-test.mjs +68 -0
- package/scripts/compact-smoke.mjs +859 -129
- package/scripts/compact-trigger-migration-smoke.mjs +187 -0
- package/scripts/fix-brief-fn.mjs +35 -0
- package/scripts/fix-format-tool-surface.mjs +24 -0
- package/scripts/fix-tool-exec-visible.mjs +42 -0
- package/scripts/generate-runtime-manifest.mjs +166 -0
- package/scripts/hook-bus-test.mjs +330 -0
- package/scripts/lead-workflow-smoke.mjs +33 -39
- package/scripts/live-worker-smoke.mjs +43 -37
- package/scripts/llm-trace-summary.mjs +315 -0
- package/scripts/memory-meta-concurrency-test.mjs +20 -0
- package/scripts/output-style-smoke.mjs +56 -15
- package/scripts/parent-abort-link-test.mjs +44 -0
- package/scripts/patch-agent-brief.mjs +48 -0
- package/scripts/patch-app.mjs +21 -0
- package/scripts/patch-app2.mjs +18 -0
- package/scripts/patch-dist-brief.mjs +96 -0
- package/scripts/patch-tool-exec.mjs +70 -0
- package/scripts/pretool-ask-runtime-test.mjs +54 -0
- package/scripts/provider-toolcall-test.mjs +376 -0
- package/scripts/reactive-compact-persist-smoke.mjs +124 -0
- package/scripts/sanitize-tool-pairs-test.mjs +260 -0
- package/scripts/session-context-bench.mjs +344 -0
- package/scripts/session-ingest-smoke.mjs +177 -0
- package/scripts/set-effort-config-test.mjs +41 -0
- package/scripts/smoke-runtime-negative.ps1 +106 -0
- package/scripts/smoke-runtime-negative.sh +97 -0
- package/scripts/smoke.mjs +25 -0
- package/scripts/tool-result-hook-test.mjs +48 -0
- package/scripts/tool-smoke.mjs +1223 -95
- package/scripts/toolcall-args-test.mjs +150 -0
- package/scripts/tui-background-failure-smoke.mjs +73 -0
- package/scripts/usage-metrics-epoch-smoke.mjs +114 -0
- package/src/agents/debugger/AGENT.md +8 -0
- package/src/agents/explore/AGENT.md +4 -0
- package/src/agents/heavy-worker/AGENT.md +9 -3
- package/src/agents/maintainer/AGENT.md +4 -0
- package/src/agents/reviewer/AGENT.md +8 -0
- package/src/agents/scheduler-task/AGENT.md +12 -0
- package/src/agents/scheduler-task/agent.json +6 -0
- package/src/agents/webhook-handler/AGENT.md +12 -0
- package/src/agents/webhook-handler/agent.json +6 -0
- package/src/agents/worker/AGENT.md +9 -3
- package/src/app.mjs +77 -3
- package/src/defaults/hidden-roles.json +17 -12
- package/src/headless-role.mjs +117 -0
- package/src/help.mjs +30 -0
- package/src/hooks/lib/permission-evaluator.cjs +11 -475
- package/src/lib/keychain-cjs.cjs +9 -1
- package/src/lib/mixdog-debug.cjs +0 -7
- package/src/lib/rules-builder.cjs +240 -96
- package/src/lib/text-utils.cjs +1 -1
- package/src/mixdog-session-runtime.mjs +2325 -450
- package/src/output-styles/default.md +12 -28
- package/src/output-styles/extreme-simple.md +9 -6
- package/src/output-styles/simple.md +22 -9
- package/src/repl.mjs +118 -59
- package/src/rules/agent/00-common.md +15 -0
- package/src/rules/{bridge → agent}/20-skip-protocol.md +1 -2
- package/src/rules/agent/30-explorer.md +22 -0
- package/src/rules/{bridge → agent}/40-cycle1-agent.md +7 -0
- package/src/rules/{bridge → agent}/41-cycle2-agent.md +7 -0
- package/src/rules/{bridge → agent}/42-cycle3-agent.md +7 -0
- package/src/rules/lead/01-general.md +9 -5
- package/src/rules/lead/04-workflow.md +51 -12
- package/src/rules/lead/lead-tool.md +6 -0
- package/src/rules/shared/01-tool.md +12 -1
- package/src/runtime/agent/orchestrator/activity-bus.mjs +7 -18
- package/src/runtime/agent/orchestrator/agent-owner.mjs +11 -0
- package/src/runtime/agent/orchestrator/{smart-bridge/bridge-llm.mjs → agent-runtime/agent-dispatch.mjs} +138 -111
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +94 -0
- package/src/runtime/agent/orchestrator/{smart-bridge → agent-runtime}/cache-strategy.mjs +32 -23
- package/src/runtime/agent/orchestrator/{smart-bridge → agent-runtime}/session-builder.mjs +33 -27
- package/src/runtime/agent/orchestrator/{bridge-trace.mjs → agent-trace.mjs} +132 -81
- package/src/runtime/agent/orchestrator/cache-mtime.mjs +0 -21
- package/src/runtime/agent/orchestrator/config.mjs +174 -55
- package/src/runtime/agent/orchestrator/context/collect.mjs +195 -487
- package/src/runtime/agent/orchestrator/dispatch-persist.mjs +1 -1
- package/src/runtime/agent/orchestrator/internal-roles.mjs +77 -29
- package/src/runtime/agent/orchestrator/internal-tools.mjs +5 -6
- package/src/runtime/agent/orchestrator/mcp/client.mjs +15 -9
- package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +377 -243
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +146 -93
- package/src/runtime/agent/orchestrator/providers/api-usage.mjs +236 -4
- package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +49 -0
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +58 -13
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +67 -149
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +132 -2
- package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +45 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +61 -116
- package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +25 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +79 -255
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +221 -70
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +477 -147
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +343 -496
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +6 -6
- package/src/runtime/agent/orchestrator/providers/registry.mjs +88 -51
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +31 -11
- package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +41 -8
- package/src/runtime/agent/orchestrator/session/cache/post-edit-marks.mjs +4 -4
- package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/compact.mjs +1173 -267
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +199 -36
- package/src/runtime/agent/orchestrator/session/loop.mjs +851 -674
- package/src/runtime/agent/orchestrator/session/manager.mjs +1593 -466
- package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +107 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +291 -46
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +2 -2
- package/src/runtime/agent/orchestrator/stall-policy.mjs +31 -16
- package/src/runtime/agent/orchestrator/tool-loop-guard.mjs +3 -219
- package/src/runtime/agent/orchestrator/tools/bash-session.mjs +34 -7
- package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +19 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +9 -9
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +60 -37
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +21 -2
- package/src/runtime/agent/orchestrator/tools/builtin/device-paths.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -7
- package/src/runtime/agent/orchestrator/tools/builtin/glob-walk.mjs +1 -3
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +36 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-args.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-constants.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +5 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-image-resize.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +4 -36
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +2 -40
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +148 -27
- package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +43 -75
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +90 -20
- package/src/runtime/agent/orchestrator/tools/builtin/snapshot-store.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +59 -5
- package/src/runtime/agent/orchestrator/tools/code-graph-state.mjs +86 -0
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +11 -11
- package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4106 -4019
- package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +33 -4
- package/src/runtime/agent/orchestrator/tools/patch.mjs +90 -6
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +6 -4
- package/src/runtime/agent/orchestrator/tools/result-compression.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +8 -1
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -4
- package/src/runtime/channels/index.mjs +152 -24
- package/src/runtime/channels/lib/scheduler.mjs +18 -14
- package/src/runtime/channels/lib/session-discovery.mjs +3 -2
- package/src/runtime/channels/lib/tool-format.mjs +0 -2
- package/src/runtime/channels/lib/transcript-discovery.mjs +3 -2
- package/src/runtime/channels/lib/webhook.mjs +1 -1
- package/src/runtime/channels/tool-defs.mjs +29 -29
- package/src/runtime/memory/index.mjs +635 -107
- package/src/runtime/memory/lib/agent-ipc.mjs +29 -12
- package/src/runtime/memory/lib/core-memory-store.mjs +2 -2
- package/src/runtime/memory/lib/embedding-model-config.mjs +55 -0
- package/src/runtime/memory/lib/embedding-provider.mjs +31 -4
- package/src/runtime/memory/lib/embedding-worker.mjs +19 -10
- package/src/runtime/memory/lib/memory-cycle1.mjs +38 -17
- package/src/runtime/memory/lib/memory-cycle2.mjs +6 -7
- package/src/runtime/memory/lib/memory-cycle3.mjs +4 -4
- package/src/runtime/memory/lib/memory-ops-policy.mjs +2 -1
- package/src/runtime/memory/lib/memory-session-merge.mjs +38 -0
- package/src/runtime/memory/lib/memory.mjs +88 -9
- package/src/runtime/memory/lib/model-profile.mjs +1 -1
- package/src/runtime/memory/lib/pg/adapter.mjs +15 -1
- package/src/runtime/memory/lib/pg/supervisor.mjs +12 -0
- package/src/runtime/memory/lib/runtime-fetcher.mjs +37 -3
- package/src/runtime/memory/lib/session-ingest.mjs +194 -0
- package/src/runtime/memory/lib/trace-store.mjs +96 -51
- package/src/runtime/memory/tool-defs.mjs +46 -37
- package/src/runtime/search/index.mjs +102 -466
- package/src/runtime/search/lib/web-tools.mjs +45 -25
- package/src/runtime/search/tool-defs.mjs +16 -23
- package/src/runtime/shared/abort-controller.mjs +1 -1
- package/src/runtime/shared/atomic-file.mjs +4 -3
- package/src/runtime/shared/background-tasks.mjs +122 -11
- package/src/runtime/shared/child-spawn-gate.mjs +145 -0
- package/src/runtime/shared/config.mjs +7 -4
- package/src/runtime/shared/err-text.mjs +131 -4
- package/src/runtime/shared/llm/cost.mjs +2 -2
- package/src/runtime/shared/llm/http-agent.mjs +23 -7
- package/src/runtime/shared/llm/index.mjs +34 -11
- package/src/runtime/shared/llm/usage-log.mjs +4 -4
- package/src/runtime/shared/markdown-frontmatter.mjs +56 -0
- package/src/runtime/shared/singleton-owner.mjs +104 -0
- package/src/runtime/shared/tool-execution-contract.mjs +199 -20
- package/src/runtime/shared/tool-execution-contract.test.mjs +183 -0
- package/src/runtime/shared/tool-surface.mjs +624 -98
- package/src/runtime/shared/user-data-guard.mjs +0 -2
- package/src/standalone/agent-task-status.mjs +203 -0
- package/src/standalone/agent-task-status.test.mjs +76 -0
- package/src/standalone/agent-tool.mjs +1913 -0
- package/src/standalone/channel-worker.mjs +370 -14
- package/src/standalone/explore-tool.mjs +165 -70
- package/src/standalone/folder-dialog.mjs +314 -0
- package/src/standalone/hook-bus.mjs +898 -22
- package/src/standalone/memory-runtime-proxy.mjs +320 -0
- package/src/standalone/projects.mjs +226 -0
- package/src/standalone/provider-admin.mjs +41 -24
- package/src/standalone/seeds.mjs +2 -69
- package/src/standalone/usage-dashboard.mjs +96 -8
- package/src/tui/App.jsx +4798 -2153
- package/src/tui/components/AnsiText.jsx +39 -28
- package/src/tui/components/ContextPanel.jsx +87 -29
- package/src/tui/components/Markdown.jsx +43 -77
- package/src/tui/components/MarkdownTable.jsx +9 -184
- package/src/tui/components/Message.jsx +28 -11
- package/src/tui/components/Picker.jsx +95 -56
- package/src/tui/components/PromptInput.jsx +367 -239
- package/src/tui/components/QueuedCommands.jsx +1 -1
- package/src/tui/components/SlashCommandPalette.jsx +27 -21
- package/src/tui/components/Spinner.jsx +67 -38
- package/src/tui/components/StatusLine.jsx +606 -38
- package/src/tui/components/TextEntryPanel.jsx +128 -9
- package/src/tui/components/ToolExecution.jsx +617 -368
- package/src/tui/components/TurnDone.jsx +3 -3
- package/src/tui/components/UsagePanel.jsx +3 -5
- package/src/tui/components/tool-output-format.mjs +365 -0
- package/src/tui/components/tool-output-format.test.mjs +220 -0
- package/src/tui/dist/index.mjs +8915 -2418
- package/src/tui/engine-runtime-notification.test.mjs +115 -0
- package/src/tui/engine-tool-result-text.test.mjs +75 -0
- package/src/tui/engine.mjs +1455 -279
- package/src/tui/figures.mjs +21 -40
- package/src/tui/index.jsx +75 -31
- package/src/tui/input-editing.mjs +25 -0
- package/src/tui/markdown/format-token.mjs +511 -68
- package/src/tui/markdown/format-token.test.mjs +216 -0
- package/src/tui/markdown/render-ansi.mjs +94 -0
- package/src/tui/markdown/render-ansi.test.mjs +108 -0
- package/src/tui/markdown/stream-fence.mjs +34 -0
- package/src/tui/markdown/stream-fence.test.mjs +26 -0
- package/src/tui/markdown/table-layout.mjs +250 -0
- package/src/tui/paste-attachments.mjs +0 -7
- package/src/tui/spinner-verbs.mjs +1 -2
- package/src/tui/statusline-ansi-bridge.mjs +172 -0
- package/src/tui/statusline-ansi-bridge.test.mjs +159 -0
- package/src/tui/theme.mjs +746 -24
- package/src/tui/time-format.mjs +1 -1
- package/src/tui/transcript-tool-failures.mjs +67 -0
- package/src/tui/transcript-tool-failures.test.mjs +111 -0
- package/src/ui/ansi.mjs +1 -2
- package/src/ui/markdown.mjs +85 -26
- package/src/ui/markdown.test.mjs +70 -0
- package/src/ui/model-display.mjs +121 -0
- package/src/ui/session-stats.mjs +44 -0
- package/src/ui/statusline-context-label.test.mjs +15 -0
- package/src/ui/statusline.mjs +386 -178
- package/src/ui/tool-card.mjs +3 -16
- package/src/vendor/statusline/bin/statusline-lib.mjs +8 -4
- package/src/vendor/statusline/bin/statusline-route.mjs +169 -37
- package/src/vendor/statusline/bin/statusline-route.test.mjs +80 -0
- package/src/vendor/statusline/scripts/lib/gateway-settings.mjs +3 -3
- package/src/vendor/statusline/src/gateway/claude-current.mjs +1 -1
- package/src/vendor/statusline/src/gateway/route-meta.mjs +44 -6
- package/src/vendor/statusline/src/gateway/session-routes.mjs +1 -1
- package/src/workflows/default/WORKFLOW.md +12 -5
- package/src/workflows/default/workflow.json +0 -1
- package/src/workflows/solo/WORKFLOW.md +15 -0
- package/src/workflows/solo/workflow.json +7 -0
- package/vendor/ink/build/output.js +6 -1
- package/src/agents/scheduler-task.md +0 -3
- package/src/agents/web-researcher/AGENT.md +0 -3
- package/src/agents/web-researcher/agent.json +0 -6
- package/src/agents/webhook-handler.md +0 -3
- package/src/rules/bridge/00-common.md +0 -5
- package/src/rules/bridge/30-explorer.md +0 -4
- package/src/rules/lead/00-tool-lead.md +0 -5
- package/src/rules/shared/00-language.md +0 -3
- package/src/runtime/agent/orchestrator/tools/builtin/native-edit-runner.mjs +0 -110
- package/src/runtime/agent/orchestrator/tools/mutation-content-cache.mjs +0 -67
- package/src/runtime/memory/lib/bridge-trace-queries.mjs +0 -120
- package/src/runtime/shared/llm/pid-cleanup.mjs +0 -27
- package/src/standalone/bridge-tool.mjs +0 -1414
- package/src/tui/runtime/shared/process-shutdown.mjs +0 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {
|
|
4
|
+
getSessionRuntime,
|
|
5
|
+
linkParentSignalToSession,
|
|
6
|
+
markSessionCancelled,
|
|
7
|
+
markSessionError,
|
|
8
|
+
} from '../src/runtime/agent/orchestrator/session/manager.mjs';
|
|
9
|
+
|
|
10
|
+
test('markSessionError drops parent AbortSignal listener but keeps runtime entry', () => {
|
|
11
|
+
const sessionId = `parent-abort-error-${Date.now()}`;
|
|
12
|
+
const parent = new AbortController();
|
|
13
|
+
linkParentSignalToSession(sessionId, parent.signal);
|
|
14
|
+
const runtime = getSessionRuntime(sessionId);
|
|
15
|
+
assert.ok(runtime?.parentAbortLink?.signal === parent.signal);
|
|
16
|
+
assert.equal(typeof runtime.parentAbortLink.listener, 'function');
|
|
17
|
+
|
|
18
|
+
markSessionError(sessionId, 'boom');
|
|
19
|
+
|
|
20
|
+
assert.equal(getSessionRuntime(sessionId)?.parentAbortLink, null);
|
|
21
|
+
assert.equal(getSessionRuntime(sessionId)?.stage, 'error');
|
|
22
|
+
let childAborted = false;
|
|
23
|
+
runtime.controller.signal.addEventListener('abort', () => { childAborted = true; }, { once: true });
|
|
24
|
+
parent.abort();
|
|
25
|
+
assert.equal(childAborted, false);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('markSessionCancelled drops parent AbortSignal listener but keeps runtime entry', () => {
|
|
29
|
+
const sessionId = `parent-abort-cancel-${Date.now()}`;
|
|
30
|
+
const parent = new AbortController();
|
|
31
|
+
linkParentSignalToSession(sessionId, parent.signal);
|
|
32
|
+
const runtime = getSessionRuntime(sessionId);
|
|
33
|
+
assert.ok(runtime?.parentAbortLink);
|
|
34
|
+
|
|
35
|
+
markSessionCancelled(sessionId);
|
|
36
|
+
|
|
37
|
+
assert.equal(getSessionRuntime(sessionId)?.parentAbortLink, null);
|
|
38
|
+
assert.equal(getSessionRuntime(sessionId)?.stage, 'done');
|
|
39
|
+
let childAborted = false;
|
|
40
|
+
runtime.controller.signal.addEventListener('abort', () => { childAborted = true; }, { once: true });
|
|
41
|
+
parent.abort();
|
|
42
|
+
assert.equal(childAborted, false);
|
|
43
|
+
});
|
|
44
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
const p = "src/runtime/shared/tool-surface.mjs";
|
|
3
|
+
let s = fs.readFileSync(p, "utf8");
|
|
4
|
+
if (s.includes("summarizeAgentSurfaceBrief")) { console.log("skip"); process.exit(0); }
|
|
5
|
+
const insert = `/** Collapsed agent/worker surface card: one-line brief under the header (30-40 chars). */
|
|
6
|
+
export const AGENT_SURFACE_BRIEF_MAX = 40;
|
|
7
|
+
|
|
8
|
+
export function summarizeAgentSurfaceBrief(name, args, resultText, { isError = false, isResponse = false } = {}) {
|
|
9
|
+
const a = parseToolArgs(args);
|
|
10
|
+
const action = String(a?.type || a?.action || "").toLowerCase();
|
|
11
|
+
const text = String(resultText ?? "").trim();
|
|
12
|
+
|
|
13
|
+
if (isResponse && text) {
|
|
14
|
+
const fromResult = summarizeToolResult(name, args, text, isError);
|
|
15
|
+
if (fromResult) return truncateSingleLine(stripInlineMarkdown(fromResult), AGENT_SURFACE_BRIEF_MAX);
|
|
16
|
+
const line = firstAgentResultLine(text);
|
|
17
|
+
if (line) return truncateSingleLine(stripInlineMarkdown(line), AGENT_SURFACE_BRIEF_MAX);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const outbound = firstText(a?.prompt, a?.message);
|
|
21
|
+
if (outbound && (action === "spawn" || action === "send" || !action)) {
|
|
22
|
+
return truncateSingleLine(outbound, AGENT_SURFACE_BRIEF_MAX);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if ((action === "spawn" || action === "send") && text && !isResponse) {
|
|
26
|
+
const fromResult = summarizeToolResult(name, args, text, isError);
|
|
27
|
+
if (fromResult) return truncateSingleLine(stripInlineMarkdown(fromResult), AGENT_SURFACE_BRIEF_MAX);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return "";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
`;
|
|
34
|
+
const needle = `export function formatToolSurface(name, args, opts = {}) {
|
|
35
|
+
const parsed = parseToolArgs(args);
|
|
36
|
+
return {
|
|
37
|
+
label: displayToolName(name, parsed),
|
|
38
|
+
summary: summarizeToolArgs(name, parsed, opts),
|
|
39
|
+
normalizedName: normalizeToolName(name),
|
|
40
|
+
args: parsed,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function pluralize`;
|
|
45
|
+
if (!s.includes(needle)) throw new Error("needle not found");
|
|
46
|
+
s = s.replace(needle, insert + "function pluralize");
|
|
47
|
+
fs.writeFileSync(p, s);
|
|
48
|
+
console.log("tool-surface ok");
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
const p = "src/tui/App.jsx";
|
|
3
|
+
let s = fs.readFileSync(p, "utf8");
|
|
4
|
+
const old = ` // EVERY agent card is a single header row whether pending or completed —
|
|
5
|
+
// ToolExecution drops the ⎿ body for all of them AND the pending-delay
|
|
6
|
+
// placeholder reserves only 1 row for agent surfaces — so reserve
|
|
7
|
+
// exactly 1 row regardless of pending/hasResult. Otherwise the estimate
|
|
8
|
+
// (2) and the real render (1) diverge and the viewport jumps.
|
|
9
|
+
if (isSkillSurface || isAgentSurface) return 1;`;
|
|
10
|
+
const neu = ` // Skill loads are a single header row; agent cards are header + brief.
|
|
11
|
+
if (isSkillSurface) return 1;
|
|
12
|
+
if (isAgentSurface) return 2;`;
|
|
13
|
+
if (s.includes(old)) {
|
|
14
|
+
s = s.replace(old, neu);
|
|
15
|
+
fs.writeFileSync(p, s);
|
|
16
|
+
console.log("App ok");
|
|
17
|
+
} else if (s.includes("if (isAgentSurface) return 2")) {
|
|
18
|
+
console.log("App already");
|
|
19
|
+
} else {
|
|
20
|
+
throw new Error("App block not found");
|
|
21
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
const p = "src/tui/App.jsx";
|
|
3
|
+
let s = fs.readFileSync(p, "utf8");
|
|
4
|
+
const old = ` if (isSkillSurface || isAgentSurface) return 1;`;
|
|
5
|
+
const neu = ` if (isSkillSurface) return 1;
|
|
6
|
+
if (isAgentSurface) return 2;`;
|
|
7
|
+
if (s.includes(old) && !s.includes("if (isAgentSurface) return 2")) {
|
|
8
|
+
s = s.replace(old, neu);
|
|
9
|
+
const commentOld = ` // EVERY agent card is a single header row whether pending or completed —
|
|
10
|
+
// ToolExecution drops the ⎿ body for all of them AND the pending-delay
|
|
11
|
+
// placeholder reserves only 1 row for agent surfaces — so reserve
|
|
12
|
+
// exactly 1 row regardless of pending/hasResult. Otherwise the estimate
|
|
13
|
+
// (2) and the real render (1) diverge and the viewport jumps.`;
|
|
14
|
+
const commentNeu = ` // Skill loads are a single header row; agent cards are header + brief.`;
|
|
15
|
+
s = s.replace(commentOld, commentNeu);
|
|
16
|
+
fs.writeFileSync(p, s);
|
|
17
|
+
console.log("App ok");
|
|
18
|
+
} else { console.log("App skip or done"); }
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
const p = "src/tui/dist/index.mjs";
|
|
3
|
+
let s = fs.readFileSync(p, "utf8");
|
|
4
|
+
|
|
5
|
+
const helpers = `const AGENT_SURFACE_BRIEF_MAX = 40;
|
|
6
|
+
function truncateAgentSurfaceBrief(value, max = AGENT_SURFACE_BRIEF_MAX) {
|
|
7
|
+
const text = String(value ?? "").replace(/\\s+/g, " ").trim();
|
|
8
|
+
if (!text) return "";
|
|
9
|
+
if (text.length <= max) return text;
|
|
10
|
+
return \`\${text.slice(0, Math.max(1, max - 1))}…\`;
|
|
11
|
+
}
|
|
12
|
+
function summarizeAgentSurfaceBrief(name, args, resultText, { isError = false, isResponse = false } = {}) {
|
|
13
|
+
const a = parseToolArgs(args);
|
|
14
|
+
const action = String(a?.type || a?.action || "").toLowerCase();
|
|
15
|
+
const text = String(resultText ?? "").trim();
|
|
16
|
+
|
|
17
|
+
if (isResponse && text) {
|
|
18
|
+
const fromResult = summarizeToolResult(name, args, text, isError);
|
|
19
|
+
if (fromResult) return truncateAgentSurfaceBrief(stripInlineMarkdown(fromResult));
|
|
20
|
+
const line = firstAgentResultLine(text);
|
|
21
|
+
if (line) return truncateAgentSurfaceBrief(stripInlineMarkdown(line));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const outbound = firstText(a?.prompt, a?.message);
|
|
25
|
+
if (outbound && (action === "spawn" || action === "send" || !action)) {
|
|
26
|
+
return truncateAgentSurfaceBrief(outbound);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if ((action === "spawn" || action === "send") && text && !isResponse) {
|
|
30
|
+
const fromResult = summarizeToolResult(name, args, text, isError);
|
|
31
|
+
if (fromResult) return truncateAgentSurfaceBrief(stripInlineMarkdown(fromResult));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return "";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
if (!s.includes("function summarizeAgentSurfaceBrief")) {
|
|
40
|
+
const needle = `function formatToolSurface(name, args, opts = {}) {
|
|
41
|
+
const parsed = parseToolArgs(args);
|
|
42
|
+
return {
|
|
43
|
+
label: displayToolName(name, parsed),
|
|
44
|
+
summary: summarizeToolArgs(name, parsed, opts),
|
|
45
|
+
normalizedName: normalizeToolName(name),
|
|
46
|
+
args: parsed
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function pluralize`;
|
|
50
|
+
if (!s.includes(needle)) throw new Error("formatToolSurface needle missing");
|
|
51
|
+
s = s.replace(needle, `function formatToolSurface(name, args, opts = {}) {
|
|
52
|
+
const parsed = parseToolArgs(args);
|
|
53
|
+
return {
|
|
54
|
+
label: displayToolName(name, parsed),
|
|
55
|
+
summary: summarizeToolArgs(name, parsed, opts),
|
|
56
|
+
normalizedName: normalizeToolName(name),
|
|
57
|
+
args: parsed
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
` + helpers + `function pluralize`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const oldVisible = ` const isAgentSurfaceCard = isAgentTool(normalizedName);
|
|
64
|
+
const visibleDetailLines = (isAgentSurfaceCard || isSkillSurface) && !showRawResult ? [] : detailLines;`;
|
|
65
|
+
const newVisible = ` const isAgentSurfaceCard = isAgentTool(normalizedName);
|
|
66
|
+
const agentSurfaceBriefRaw = isAgentSurfaceCard && !showRawResult
|
|
67
|
+
? summarizeAgentSurfaceBrief(name, parsedArgs, displayedResultText || "", { isError, isResponse: isAgentResponse })
|
|
68
|
+
: "";
|
|
69
|
+
const agentSurfaceBrief = agentSurfaceBriefRaw
|
|
70
|
+
? truncateToWidth(agentSurfaceBriefRaw, Math.min(AGENT_SURFACE_BRIEF_MAX, maxResultChars))
|
|
71
|
+
: "";
|
|
72
|
+
let visibleDetailLines = detailLines;
|
|
73
|
+
if (isSkillSurface && !showRawResult) {
|
|
74
|
+
visibleDetailLines = [];
|
|
75
|
+
} else if (isAgentSurfaceCard && !showRawResult) {
|
|
76
|
+
const agentDetailFallback = collapsedDetail
|
|
77
|
+
|| (pending ? (pendingDetailPlaceholder || "Running") : "Finished");
|
|
78
|
+
const agentDetailLine = agentSurfaceBrief
|
|
79
|
+
|| truncateToWidth(String(agentDetailFallback), Math.min(AGENT_SURFACE_BRIEF_MAX, maxResultChars));
|
|
80
|
+
visibleDetailLines = [agentDetailLine];
|
|
81
|
+
}`;
|
|
82
|
+
if (s.includes(oldVisible)) s = s.replace(oldVisible, newVisible);
|
|
83
|
+
else if (!s.includes("agentSurfaceBriefRaw")) throw new Error("visibleDetailLines block missing");
|
|
84
|
+
|
|
85
|
+
s = s.replace(
|
|
86
|
+
"const placeholderSingleRow = !aggregate && (SKILL_SURFACE_NAMES.has(placeholderNormalizedName) || isAgentTool(placeholderNormalizedName));",
|
|
87
|
+
"const placeholderSingleRow = !aggregate && SKILL_SURFACE_NAMES.has(placeholderNormalizedName);"
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
s = s.replace(
|
|
91
|
+
" if (isSkillSurface || isAgentSurface) return 1;",
|
|
92
|
+
" if (isSkillSurface) return 1;\n if (isAgentSurface) return 2;"
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
fs.writeFileSync(p, s);
|
|
96
|
+
console.log("dist patched");
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
const p = "src/tui/components/ToolExecution.jsx";
|
|
3
|
+
let s = fs.readFileSync(p, "utf8");
|
|
4
|
+
if (!s.includes("summarizeAgentSurfaceBrief,")) {
|
|
5
|
+
s = s.replace(
|
|
6
|
+
" displayModelName,\n} from '../../runtime/shared/tool-surface.mjs';",
|
|
7
|
+
" displayModelName,\n summarizeAgentSurfaceBrief,\n AGENT_SURFACE_BRIEF_MAX,\n} from '../../runtime/shared/tool-surface.mjs';",
|
|
8
|
+
);
|
|
9
|
+
}
|
|
10
|
+
s = s.replace(
|
|
11
|
+
` // Skill surfaces AND agent surfaces both collapse to a single header row in
|
|
12
|
+
// estimateTranscriptItemRows (agent cards drop their ⎿ body entirely), so
|
|
13
|
+
// the pending-delay placeholder must reserve exactly 1 row for them too —
|
|
14
|
+
// otherwise the card paints 2 blank rows for ~1s then snaps to 1 ("튐").
|
|
15
|
+
const placeholderSingleRow = !aggregate
|
|
16
|
+
&& (SKILL_SURFACE_NAMES.has(placeholderNormalizedName) || isAgentTool(placeholderNormalizedName));`,
|
|
17
|
+
` // Skill surfaces collapse to a single header row; agent surfaces reserve
|
|
18
|
+
// header + one brief detail row (see estimateTranscriptItemRows).
|
|
19
|
+
const placeholderSingleRow = !aggregate && SKILL_SURFACE_NAMES.has(placeholderNormalizedName);`,
|
|
20
|
+
);
|
|
21
|
+
const oldBlock = ` // Every agent card is a single header row when collapsed: spawn/send/response/
|
|
22
|
+
// status/list/cancel/close/cleanup all fold their context into the header
|
|
23
|
+
// label, so the ⎿ detail body (response summary, "agents: N …" worker list,
|
|
24
|
+
// status metadata) is dropped unless the user expands with ctrl+o.
|
|
25
|
+
const isAgentSurfaceCard = isAgentTool(normalizedName);
|
|
26
|
+
// Skill loads carry the skill name in the header already
|
|
27
|
+
// ("Loaded 1 skill (name)"); the collapsed detail row just repeats it, so
|
|
28
|
+
// drop it and keep the card a single line. Expanding (ctrl+o) still shows the
|
|
29
|
+
// full skill body via the raw-result path.
|
|
30
|
+
// Agent responses now identify the responder in the header itself
|
|
31
|
+
// ("Heavy Worker (Opus 4.8)"); the collapsed body just echoed the response
|
|
32
|
+
// summary ("All green. Done."), so drop it and keep the card a single line.
|
|
33
|
+
// ctrl+o expand (showRawResult) still surfaces the full response body.
|
|
34
|
+
// Suppression is COLLAPSED-ONLY: agent/skill cards hide their ⎿ body when
|
|
35
|
+
// collapsed, but once the user expands (showRawResult) the raw body — the
|
|
36
|
+
// response, the "agents: N …" worker list, the status metadata — must render.
|
|
37
|
+
const visibleDetailLines = ((isAgentSurfaceCard || isSkillSurface) && !showRawResult)
|
|
38
|
+
? []
|
|
39
|
+
: detailLines;`;
|
|
40
|
+
const newBlock = ` const isAgentSurfaceCard = isAgentTool(normalizedName);
|
|
41
|
+
const agentSurfaceBriefRaw = isAgentSurfaceCard && !showRawResult
|
|
42
|
+
? summarizeAgentSurfaceBrief(name, parsedArgs, displayedResultText || '', { isError, isResponse: isAgentResponse })
|
|
43
|
+
: '';
|
|
44
|
+
const agentSurfaceBrief = agentSurfaceBriefRaw
|
|
45
|
+
? truncateToWidth(agentSurfaceBriefRaw, Math.min(AGENT_SURFACE_BRIEF_MAX, maxResultChars))
|
|
46
|
+
: '';
|
|
47
|
+
// Skill loads carry the skill name in the header already
|
|
48
|
+
// ("Loaded 1 skill (name)"); the collapsed detail row just repeats it, so
|
|
49
|
+
// drop it and keep the card a single line. Expanding (ctrl+o) still shows the
|
|
50
|
+
// full skill body via the raw-result path.
|
|
51
|
+
// Agent spawn/send/response cards show a tight brief under the ⎿ gutter when
|
|
52
|
+
// collapsed; ctrl+o expand still surfaces the full body.
|
|
53
|
+
let visibleDetailLines = detailLines;
|
|
54
|
+
if (isSkillSurface && !showRawResult) {
|
|
55
|
+
visibleDetailLines = [];
|
|
56
|
+
} else if (isAgentSurfaceCard && !showRawResult) {
|
|
57
|
+
if (agentSurfaceBrief) {
|
|
58
|
+
visibleDetailLines = [agentSurfaceBrief];
|
|
59
|
+
} else if (pending) {
|
|
60
|
+
visibleDetailLines = [pendingDetailPlaceholder || 'Running'];
|
|
61
|
+
} else {
|
|
62
|
+
visibleDetailLines = [];
|
|
63
|
+
}
|
|
64
|
+
}`;
|
|
65
|
+
if (!s.includes("agentSurfaceBriefRaw")) {
|
|
66
|
+
if (!s.includes(oldBlock)) throw new Error("ToolExecution block not found");
|
|
67
|
+
s = s.replace(oldBlock, newBlock);
|
|
68
|
+
}
|
|
69
|
+
fs.writeFileSync(p, s);
|
|
70
|
+
console.log("ToolExecution ok");
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
|
|
2
|
+
import test from 'node:test';
|
|
3
|
+
import assert from 'node:assert/strict';
|
|
4
|
+
import {
|
|
5
|
+
approvalGranted,
|
|
6
|
+
formatMissingToolApprovalUiDenial,
|
|
7
|
+
resolvePreToolAskApproval,
|
|
8
|
+
} from '../src/runtime/agent/orchestrator/session/loop.mjs';
|
|
9
|
+
|
|
10
|
+
test('PreToolUse ask without approval callback returns explicit denial', async () => {
|
|
11
|
+
const outcome = await resolvePreToolAskApproval({
|
|
12
|
+
toolName: 'shell',
|
|
13
|
+
args: { command: 'echo hi' },
|
|
14
|
+
cwd: '/tmp',
|
|
15
|
+
sessionId: 'sess_test',
|
|
16
|
+
toolCallId: 'call_1',
|
|
17
|
+
askReason: 'needs human approval',
|
|
18
|
+
toolApprovalHook: undefined,
|
|
19
|
+
});
|
|
20
|
+
assert.equal(outcome.approval, undefined);
|
|
21
|
+
assert.match(outcome.denial, /approval required but no approval UI is available/);
|
|
22
|
+
assert.match(outcome.denial, /needs human approval/);
|
|
23
|
+
assert.equal(
|
|
24
|
+
outcome.denial,
|
|
25
|
+
formatMissingToolApprovalUiDenial('shell', 'needs human approval'),
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('PreToolUse ask with rejected approval returns structured denial', async () => {
|
|
30
|
+
const outcome = await resolvePreToolAskApproval({
|
|
31
|
+
toolName: 'read',
|
|
32
|
+
args: { path: 'README.md' },
|
|
33
|
+
cwd: '/tmp',
|
|
34
|
+
sessionId: 'sess_test',
|
|
35
|
+
toolCallId: 'call_2',
|
|
36
|
+
askReason: 'confirm read',
|
|
37
|
+
toolApprovalHook: async () => ({ approved: false, reason: 'user declined' }),
|
|
38
|
+
});
|
|
39
|
+
assert.match(outcome.denial, /denied by hook: user declined/);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('PreToolUse ask with granted approval allows tool execution', async () => {
|
|
43
|
+
const outcome = await resolvePreToolAskApproval({
|
|
44
|
+
toolName: 'grep',
|
|
45
|
+
args: { pattern: 'foo' },
|
|
46
|
+
cwd: '/tmp',
|
|
47
|
+
sessionId: 'sess_test',
|
|
48
|
+
toolCallId: 'call_3',
|
|
49
|
+
askReason: 'confirm grep',
|
|
50
|
+
toolApprovalHook: async () => ({ approved: true }),
|
|
51
|
+
});
|
|
52
|
+
assert.equal(outcome.denial, undefined);
|
|
53
|
+
assert.equal(approvalGranted(outcome.approval), true);
|
|
54
|
+
});
|