open-multi-agent-kit 0.96.1 → 0.97.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/README.md +14 -2
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +1 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/commands/resource-doctor-cli.d.ts +22 -0
- package/dist/commands/resource-doctor-cli.d.ts.map +1 -0
- package/dist/commands/resource-doctor-cli.js +98 -0
- package/dist/commands/resource-doctor-cli.js.map +1 -0
- package/dist/core/agent-session.d.ts +46 -2
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +373 -12
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/attachment-store.d.ts +39 -0
- package/dist/core/attachment-store.d.ts.map +1 -0
- package/dist/core/attachment-store.js +81 -0
- package/dist/core/attachment-store.js.map +1 -0
- package/dist/core/command-safety.d.ts +8 -0
- package/dist/core/command-safety.d.ts.map +1 -1
- package/dist/core/command-safety.js +140 -14
- package/dist/core/command-safety.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +6 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +35 -1
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/completion-sound.d.ts +109 -0
- package/dist/core/completion-sound.d.ts.map +1 -0
- package/dist/core/completion-sound.js +165 -0
- package/dist/core/completion-sound.js.map +1 -0
- package/dist/core/context-budget-governor-v2.d.ts +1 -1
- package/dist/core/context-budget-governor-v2.d.ts.map +1 -1
- package/dist/core/context-budget-governor-v2.js +1 -1
- package/dist/core/context-budget-governor-v2.js.map +1 -1
- package/dist/core/context-budget-system-prompt-items.d.ts.map +1 -1
- package/dist/core/context-budget-system-prompt-items.js +2 -2
- package/dist/core/context-budget-system-prompt-items.js.map +1 -1
- package/dist/core/context-budget-v2-cache-keys.d.ts +3 -0
- package/dist/core/context-budget-v2-cache-keys.d.ts.map +1 -1
- package/dist/core/context-budget-v2-cache-keys.js +2 -0
- package/dist/core/context-budget-v2-cache-keys.js.map +1 -1
- package/dist/core/context-budget-v2-plan-cache-keys.d.ts.map +1 -1
- package/dist/core/context-budget-v2-plan-cache-keys.js +3 -0
- package/dist/core/context-budget-v2-plan-cache-keys.js.map +1 -1
- package/dist/core/context-budget-v2-planner.d.ts.map +1 -1
- package/dist/core/context-budget-v2-planner.js +2 -1
- package/dist/core/context-budget-v2-planner.js.map +1 -1
- package/dist/core/context-budget-v2-scoring.d.ts +17 -0
- package/dist/core/context-budget-v2-scoring.d.ts.map +1 -1
- package/dist/core/context-budget-v2-scoring.js +25 -8
- package/dist/core/context-budget-v2-scoring.js.map +1 -1
- package/dist/core/context-budget-v2-selection.d.ts +2 -2
- package/dist/core/context-budget-v2-selection.d.ts.map +1 -1
- package/dist/core/context-budget-v2-selection.js +18 -1
- package/dist/core/context-budget-v2-selection.js.map +1 -1
- package/dist/core/context-budget-v2-types.d.ts +17 -0
- package/dist/core/context-budget-v2-types.d.ts.map +1 -1
- package/dist/core/context-budget-v2-types.js +15 -0
- package/dist/core/context-budget-v2-types.js.map +1 -1
- package/dist/core/extensions/builtin/command-safety-gate.d.ts +3 -1
- package/dist/core/extensions/builtin/command-safety-gate.d.ts.map +1 -1
- package/dist/core/extensions/builtin/command-safety-gate.js +7 -0
- package/dist/core/extensions/builtin/command-safety-gate.js.map +1 -1
- package/dist/core/extensions/types.d.ts +12 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/host-resource-probe.d.ts +63 -0
- package/dist/core/host-resource-probe.d.ts.map +1 -0
- package/dist/core/host-resource-probe.js +126 -0
- package/dist/core/host-resource-probe.js.map +1 -0
- package/dist/core/host-resource-snapshot.d.ts +54 -0
- package/dist/core/host-resource-snapshot.d.ts.map +1 -0
- package/dist/core/host-resource-snapshot.js +139 -0
- package/dist/core/host-resource-snapshot.js.map +1 -0
- package/dist/core/model-registry.d.ts +8 -3
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +71 -1
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/package-doctor-source-scan.d.ts +9 -0
- package/dist/core/package-doctor-source-scan.d.ts.map +1 -1
- package/dist/core/package-doctor-source-scan.js +77 -4
- package/dist/core/package-doctor-source-scan.js.map +1 -1
- package/dist/core/prompt-attachment.d.ts +51 -0
- package/dist/core/prompt-attachment.d.ts.map +1 -0
- package/dist/core/prompt-attachment.js +186 -0
- package/dist/core/prompt-attachment.js.map +1 -0
- package/dist/core/prompt-settlement.d.ts +81 -0
- package/dist/core/prompt-settlement.d.ts.map +1 -0
- package/dist/core/prompt-settlement.js +84 -0
- package/dist/core/prompt-settlement.js.map +1 -0
- package/dist/core/provider-resilience.d.ts +28 -0
- package/dist/core/provider-resilience.d.ts.map +1 -1
- package/dist/core/provider-resilience.js +51 -1
- package/dist/core/provider-resilience.js.map +1 -1
- package/dist/core/provider-retry.d.ts +7 -0
- package/dist/core/provider-retry.d.ts.map +1 -1
- package/dist/core/provider-retry.js +24 -0
- package/dist/core/provider-retry.js.map +1 -1
- package/dist/core/provider-usage.d.ts +15 -2
- package/dist/core/provider-usage.d.ts.map +1 -1
- package/dist/core/provider-usage.js +176 -2
- package/dist/core/provider-usage.js.map +1 -1
- package/dist/core/reasoning-router-promotion.d.ts +84 -0
- package/dist/core/reasoning-router-promotion.d.ts.map +1 -0
- package/dist/core/reasoning-router-promotion.js +92 -0
- package/dist/core/reasoning-router-promotion.js.map +1 -0
- package/dist/core/reasoning-router-resolver.d.ts.map +1 -1
- package/dist/core/reasoning-router-resolver.js +1 -1
- package/dist/core/reasoning-router-resolver.js.map +1 -1
- package/dist/core/resource-admission-config.d.ts +55 -0
- package/dist/core/resource-admission-config.d.ts.map +1 -0
- package/dist/core/resource-admission-config.js +97 -0
- package/dist/core/resource-admission-config.js.map +1 -0
- package/dist/core/resource-admission.d.ts +81 -0
- package/dist/core/resource-admission.d.ts.map +1 -0
- package/dist/core/resource-admission.js +128 -0
- package/dist/core/resource-admission.js.map +1 -0
- package/dist/core/resource-governor-format.d.ts +50 -0
- package/dist/core/resource-governor-format.d.ts.map +1 -0
- package/dist/core/resource-governor-format.js +113 -0
- package/dist/core/resource-governor-format.js.map +1 -0
- package/dist/core/resource-governor-settings.d.ts +56 -0
- package/dist/core/resource-governor-settings.d.ts.map +1 -0
- package/dist/core/resource-governor-settings.js +89 -0
- package/dist/core/resource-governor-settings.js.map +1 -0
- package/dist/core/resource-observation-journal.d.ts +74 -0
- package/dist/core/resource-observation-journal.d.ts.map +1 -0
- package/dist/core/resource-observation-journal.js +198 -0
- package/dist/core/resource-observation-journal.js.map +1 -0
- package/dist/core/resource-safety-gate.d.ts +54 -0
- package/dist/core/resource-safety-gate.d.ts.map +1 -0
- package/dist/core/resource-safety-gate.js +51 -0
- package/dist/core/resource-safety-gate.js.map +1 -0
- package/dist/core/run-journal.d.ts.map +1 -1
- package/dist/core/run-journal.js +13 -1
- package/dist/core/run-journal.js.map +1 -1
- package/dist/core/run-resource-lease.d.ts +73 -0
- package/dist/core/run-resource-lease.d.ts.map +1 -0
- package/dist/core/run-resource-lease.js +78 -0
- package/dist/core/run-resource-lease.js.map +1 -0
- package/dist/core/session-bash-service.d.ts +12 -0
- package/dist/core/session-bash-service.d.ts.map +1 -1
- package/dist/core/session-bash-service.js +18 -3
- package/dist/core/session-bash-service.js.map +1 -1
- package/dist/core/session-system-prompt.d.ts +2 -0
- package/dist/core/session-system-prompt.d.ts.map +1 -1
- package/dist/core/session-system-prompt.js +2 -0
- package/dist/core/session-system-prompt.js.map +1 -1
- package/dist/core/session-termination.d.ts +8 -3
- package/dist/core/session-termination.d.ts.map +1 -1
- package/dist/core/session-termination.js +40 -3
- package/dist/core/session-termination.js.map +1 -1
- package/dist/core/settings-manager.d.ts +12 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +36 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/subagent-lane-launcher.d.ts +64 -0
- package/dist/core/subagent-lane-launcher.d.ts.map +1 -0
- package/dist/core/subagent-lane-launcher.js +107 -0
- package/dist/core/subagent-lane-launcher.js.map +1 -0
- package/dist/core/system-cpu-sampler.d.ts +45 -0
- package/dist/core/system-cpu-sampler.d.ts.map +1 -0
- package/dist/core/system-cpu-sampler.js +95 -0
- package/dist/core/system-cpu-sampler.js.map +1 -0
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +5 -8
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +3 -7
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +13 -48
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +1 -34
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/workload-classifier.d.ts +32 -0
- package/dist/core/workload-classifier.d.ts.map +1 -0
- package/dist/core/workload-classifier.js +66 -0
- package/dist/core/workload-classifier.js.map +1 -0
- package/dist/core/workload-family-matcher.d.ts +3 -0
- package/dist/core/workload-family-matcher.d.ts.map +1 -0
- package/dist/core/workload-family-matcher.js +126 -0
- package/dist/core/workload-family-matcher.js.map +1 -0
- package/dist/core/workload-permit-pool.d.ts +78 -0
- package/dist/core/workload-permit-pool.d.ts.map +1 -0
- package/dist/core/workload-permit-pool.js +138 -0
- package/dist/core/workload-permit-pool.js.map +1 -0
- package/dist/core/workload-shard-executor.d.ts +68 -0
- package/dist/core/workload-shard-executor.d.ts.map +1 -0
- package/dist/core/workload-shard-executor.js +156 -0
- package/dist/core/workload-shard-executor.js.map +1 -0
- package/dist/core/workload-shard-plan.d.ts +81 -0
- package/dist/core/workload-shard-plan.d.ts.map +1 -0
- package/dist/core/workload-shard-plan.js +183 -0
- package/dist/core/workload-shard-plan.js.map +1 -0
- package/dist/core/workload-shard-runner.d.ts +11 -0
- package/dist/core/workload-shard-runner.d.ts.map +1 -0
- package/dist/core/workload-shard-runner.js +98 -0
- package/dist/core/workload-shard-runner.js.map +1 -0
- package/dist/core/workload-shard-store.d.ts +44 -0
- package/dist/core/workload-shard-store.d.ts.map +1 -0
- package/dist/core/workload-shard-store.js +189 -0
- package/dist/core/workload-shard-store.js.map +1 -0
- package/dist/core/workload-sharders.d.ts +47 -0
- package/dist/core/workload-sharders.d.ts.map +1 -0
- package/dist/core/workload-sharders.js +162 -0
- package/dist/core/workload-sharders.js.map +1 -0
- package/dist/core/workload-shell-scan.d.ts +12 -0
- package/dist/core/workload-shell-scan.d.ts.map +1 -0
- package/dist/core/workload-shell-scan.js +79 -0
- package/dist/core/workload-shell-scan.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +6 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/attachment-strip.d.ts +21 -0
- package/dist/modes/interactive/components/attachment-strip.d.ts.map +1 -0
- package/dist/modes/interactive/components/attachment-strip.js +136 -0
- package/dist/modes/interactive/components/attachment-strip.js.map +1 -0
- package/dist/modes/interactive/components/footer.d.ts +6 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +26 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/status-sidebar.d.ts.map +1 -1
- package/dist/modes/interactive/components/status-sidebar.js +12 -1
- package/dist/modes/interactive/components/status-sidebar.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +27 -4
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +255 -53
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/compaction.md +1 -1
- package/docs/extensions.md +12 -3
- package/docs/index.md +4 -1
- package/docs/metrics.md +74 -2
- package/docs/provider-resilience.md +11 -0
- package/docs/providers.md +1 -1
- package/docs/sdk.md +4 -0
- package/docs/settings.md +64 -2
- package/docs/skills.md +16 -0
- package/docs/usage.md +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/subagent/agent-capability-router.test.ts +7 -0
- package/examples/extensions/subagent/domain-profiles.ts +0 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +18 -18
- package/package.json +8 -10
- package/dist/core/tools/omp-pure-seams.d.ts +0 -41
- package/dist/core/tools/omp-pure-seams.d.ts.map +0 -1
- package/dist/core/tools/omp-pure-seams.js +0 -142
- package/dist/core/tools/omp-pure-seams.js.map +0 -1
- package/dist/core/tools/omp-seam-runtime.d.ts +0 -100
- package/dist/core/tools/omp-seam-runtime.d.ts.map +0 -1
- package/dist/core/tools/omp-seam-runtime.js +0 -40
- package/dist/core/tools/omp-seam-runtime.js.map +0 -1
|
@@ -3,25 +3,31 @@
|
|
|
3
3
|
* allow: SIZE_OK - legacy TUI coordinator; this change only adds a two-line CONTROL status bridge.
|
|
4
4
|
* Handles TUI rendering and user interaction, delegating business logic to AgentSession.
|
|
5
5
|
*/
|
|
6
|
-
import * as crypto from "node:crypto";
|
|
7
6
|
import * as fs from "node:fs";
|
|
8
7
|
import * as os from "node:os";
|
|
9
8
|
import * as path from "node:path";
|
|
10
9
|
import { spawn, spawnSync } from "child_process";
|
|
11
10
|
import { getProviders, } from "omk-ai";
|
|
11
|
+
import { AttachmentStore } from "../../core/attachment-store.js";
|
|
12
|
+
import { describePromptImageAttachment } from "../../core/prompt-attachment.js";
|
|
13
|
+
import { createAttachmentStrip } from "./components/attachment-strip.js";
|
|
12
14
|
import { CombinedAutocompleteProvider, Container, fuzzyFilter, getCapabilities, hyperlink, Loader, Markdown, matchesKey, ProcessTerminal, Spacer, setKeybindings, Text, TruncatedText, TUI, visibleWidth, } from "omk-tui";
|
|
13
15
|
import { APP_NAME, APP_TITLE, getAgentDir, getAuthPath, getDebugLogPath, getDocsPath, getShareViewerUrl, VERSION, } from "../../config.js";
|
|
14
16
|
import { parseSkillBlock } from "../../core/agent-session.js";
|
|
15
17
|
import { SessionImportFileNotFoundError } from "../../core/agent-session-runtime.js";
|
|
16
18
|
import { parseBangInvocation } from "../../core/bang-skill-invocation.js";
|
|
19
|
+
import { CompletionSoundService, resolveCompletionSoundSettings, selectCompletionSoundCandidates, } from "../../core/completion-sound.js";
|
|
17
20
|
import { FooterDataProvider } from "../../core/footer-data-provider.js";
|
|
18
21
|
import { OMK_GITHUB_REPOSITORY_URL } from "../../core/github-repository.js";
|
|
22
|
+
import { captureHostResourceSnapshot } from "../../core/host-resource-snapshot.js";
|
|
19
23
|
import { configureHttpDispatcher, formatHttpIdleTimeoutMs } from "../../core/http-dispatcher.js";
|
|
20
24
|
import { KeybindingsManager } from "../../core/keybindings.js";
|
|
21
25
|
import { createCompactionSummaryMessage } from "../../core/messages.js";
|
|
22
26
|
import { defaultModelPerProvider, findExactModelReferenceMatch, resolveModelScope } from "../../core/model-resolver.js";
|
|
23
27
|
import { DefaultPackageManager } from "../../core/package-manager.js";
|
|
24
28
|
import { BUILT_IN_PROVIDER_DISPLAY_NAMES } from "../../core/provider-display-names.js";
|
|
29
|
+
import { decideResourceAdmission } from "../../core/resource-admission.js";
|
|
30
|
+
import { formatResourcePolicyLines, formatResourceProbeLines, formatResourceSummaryLines, resolveResourceGovernorSettings, } from "../../core/resource-governor-settings.js";
|
|
25
31
|
import { formatMissingSessionCwdPrompt, MissingSessionCwdError } from "../../core/session-cwd.js";
|
|
26
32
|
import { SessionManager } from "../../core/session-manager.js";
|
|
27
33
|
import { formatSessionTermination } from "../../core/session-termination.js";
|
|
@@ -29,7 +35,7 @@ import { BUILTIN_SLASH_COMMANDS } from "../../core/slash-commands.js";
|
|
|
29
35
|
import { isInstallTelemetryEnabled } from "../../core/telemetry.js";
|
|
30
36
|
import { getChangelogPath, getNewEntries, parseChangelog } from "../../utils/changelog.js";
|
|
31
37
|
import { copyToClipboard } from "../../utils/clipboard.js";
|
|
32
|
-
import {
|
|
38
|
+
import { readClipboardImage } from "../../utils/clipboard-image.js";
|
|
33
39
|
import { parseGitUrl } from "../../utils/git.js";
|
|
34
40
|
import { openBrowser } from "../../utils/open-browser.js";
|
|
35
41
|
import { getCwdRelativePath } from "../../utils/paths.js";
|
|
@@ -215,7 +221,11 @@ export class InteractiveMode {
|
|
|
215
221
|
version;
|
|
216
222
|
isInitialized = false;
|
|
217
223
|
onInputCallback;
|
|
218
|
-
|
|
224
|
+
pendingPromptPayloads = [];
|
|
225
|
+
attachmentStore = new AttachmentStore();
|
|
226
|
+
draftAttachmentIds = [];
|
|
227
|
+
attachmentStripContainer = new Container();
|
|
228
|
+
interactiveLoopActive = true;
|
|
219
229
|
loadingAnimation = undefined;
|
|
220
230
|
// Wall-clock start of the current agent turn, for the working loader elapsed suffix
|
|
221
231
|
workingStartedAt = undefined;
|
|
@@ -648,6 +658,7 @@ export class InteractiveMode {
|
|
|
648
658
|
this.ui.addChild(this.statusContainer);
|
|
649
659
|
this.renderWidgets(); // Initialize with default spacer
|
|
650
660
|
this.ui.addChild(this.widgetContainerAbove);
|
|
661
|
+
this.ui.addChild(this.attachmentStripContainer);
|
|
651
662
|
this.ui.addChild(this.editorContainer);
|
|
652
663
|
this.ui.addChild(this.widgetContainerBelow);
|
|
653
664
|
this.ui.addChild(this.noticeContainer);
|
|
@@ -776,13 +787,17 @@ export class InteractiveMode {
|
|
|
776
787
|
}
|
|
777
788
|
}
|
|
778
789
|
// Main interactive loop
|
|
779
|
-
while (
|
|
780
|
-
const
|
|
790
|
+
while (this.interactiveLoopActive) {
|
|
791
|
+
const payload = await this.getUserInput();
|
|
781
792
|
const previousTermination = this.session.lastTermination;
|
|
782
793
|
try {
|
|
783
|
-
await this.session.prompt(
|
|
794
|
+
await this.session.prompt(payload.text, payload.images ? { images: payload.images } : undefined);
|
|
795
|
+
// Acceptance: release exactly the attachments that were sent.
|
|
796
|
+
if (payload.imageIds && payload.imageIds.length > 0)
|
|
797
|
+
this.consumeDraftAttachments(payload.imageIds);
|
|
784
798
|
}
|
|
785
799
|
catch (error) {
|
|
800
|
+
// Preflight/model failure: attachments stay attached for retry.
|
|
786
801
|
this.showPromptError(error, previousTermination);
|
|
787
802
|
}
|
|
788
803
|
}
|
|
@@ -1230,9 +1245,10 @@ export class InteractiveMode {
|
|
|
1230
1245
|
const body = visibleLabels.length > 0 ? `${visibleLabels.join(", ")}${suffix}` : "(none)";
|
|
1231
1246
|
return theme.fg("dim", ` ${body}`);
|
|
1232
1247
|
};
|
|
1233
|
-
const addLoadedSection = (name, collapsedBody, expandedBody
|
|
1248
|
+
const addLoadedSection = (name, collapsedBody, expandedBody, color = "mdHeading") => {
|
|
1249
|
+
const resolvedExpandedBody = expandedBody ?? collapsedBody;
|
|
1234
1250
|
const getCollapsedBody = typeof collapsedBody === "function" ? collapsedBody : () => collapsedBody;
|
|
1235
|
-
const getExpandedBody = typeof
|
|
1251
|
+
const getExpandedBody = typeof resolvedExpandedBody === "function" ? resolvedExpandedBody : () => resolvedExpandedBody;
|
|
1236
1252
|
const section = new ExpandableText(() => `${sectionHeader(name, color)}\n${getCollapsedBody()}`, () => `${sectionHeader(name, color)}\n${getExpandedBody()}`, this.getStartupExpansionState(), 0, 0);
|
|
1237
1253
|
this.chatContainer.addChild(section);
|
|
1238
1254
|
this.chatContainer.addChild(new Spacer(1));
|
|
@@ -2212,18 +2228,98 @@ export class InteractiveMode {
|
|
|
2212
2228
|
if (!image) {
|
|
2213
2229
|
return;
|
|
2214
2230
|
}
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
this.
|
|
2231
|
+
let attachment;
|
|
2232
|
+
try {
|
|
2233
|
+
attachment = this.attachmentStore.put(new Uint8Array(image.bytes), "clipboard");
|
|
2234
|
+
}
|
|
2235
|
+
catch (error) {
|
|
2236
|
+
this.showWarning(error instanceof Error ? error.message : String(error));
|
|
2237
|
+
return;
|
|
2238
|
+
}
|
|
2239
|
+
this.draftAttachmentIds.push(attachment.id);
|
|
2240
|
+
this.refreshAttachmentStrip();
|
|
2224
2241
|
}
|
|
2225
|
-
catch {
|
|
2226
|
-
|
|
2242
|
+
catch (error) {
|
|
2243
|
+
this.showWarning(`Clipboard paste failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
/** Rebuild the preview strip above the editor from the current draft ids. */
|
|
2247
|
+
refreshAttachmentStrip() {
|
|
2248
|
+
this.attachmentStripContainer.clear();
|
|
2249
|
+
const items = this.draftAttachmentIds
|
|
2250
|
+
.map((id) => this.attachmentStore.get(id))
|
|
2251
|
+
.filter((item) => item !== undefined);
|
|
2252
|
+
if (items.length > 0) {
|
|
2253
|
+
this.attachmentStripContainer.addChild(createAttachmentStrip(items, (id) => this.attachmentStore.getBytes(id)));
|
|
2254
|
+
}
|
|
2255
|
+
this.ui.requestRender();
|
|
2256
|
+
}
|
|
2257
|
+
materializeDraftImages(ids) {
|
|
2258
|
+
return this.attachmentStore.materializeImages(ids);
|
|
2259
|
+
}
|
|
2260
|
+
/** Release exactly the attachments that were accepted with a sent prompt. */
|
|
2261
|
+
consumeDraftAttachments(ids) {
|
|
2262
|
+
for (const id of ids) {
|
|
2263
|
+
this.attachmentStore.remove(id);
|
|
2264
|
+
const index = this.draftAttachmentIds.indexOf(id);
|
|
2265
|
+
if (index >= 0)
|
|
2266
|
+
this.draftAttachmentIds.splice(index, 1);
|
|
2267
|
+
}
|
|
2268
|
+
this.refreshAttachmentStrip();
|
|
2269
|
+
}
|
|
2270
|
+
clearDraftAttachments() {
|
|
2271
|
+
this.draftAttachmentIds = [];
|
|
2272
|
+
this.attachmentStore.clear();
|
|
2273
|
+
this.refreshAttachmentStrip();
|
|
2274
|
+
}
|
|
2275
|
+
removeLastDraftAttachment() {
|
|
2276
|
+
const id = this.draftAttachmentIds.pop();
|
|
2277
|
+
if (id)
|
|
2278
|
+
this.attachmentStore.remove(id);
|
|
2279
|
+
this.refreshAttachmentStrip();
|
|
2280
|
+
}
|
|
2281
|
+
isVisionCapable() {
|
|
2282
|
+
const model = this.session.model;
|
|
2283
|
+
return Array.isArray(model?.input) ? model.input.includes("image") : true;
|
|
2284
|
+
}
|
|
2285
|
+
handleAttachCommand(argument) {
|
|
2286
|
+
const [verb, rest] = argument.split(/\s+/);
|
|
2287
|
+
switch (verb ?? "") {
|
|
2288
|
+
case "":
|
|
2289
|
+
case "list": {
|
|
2290
|
+
const items = this.draftAttachmentIds
|
|
2291
|
+
.map((id) => this.attachmentStore.get(id))
|
|
2292
|
+
.filter((item) => item !== undefined);
|
|
2293
|
+
if (items.length === 0) {
|
|
2294
|
+
this.showStatus("No image attachments.");
|
|
2295
|
+
}
|
|
2296
|
+
else {
|
|
2297
|
+
this.showStatus(items.map((item, index) => `${index + 1}. ${describePromptImageAttachment(item)}`).join(" · "));
|
|
2298
|
+
}
|
|
2299
|
+
break;
|
|
2300
|
+
}
|
|
2301
|
+
case "clear":
|
|
2302
|
+
this.clearDraftAttachments();
|
|
2303
|
+
this.showStatus("Image attachments cleared.");
|
|
2304
|
+
break;
|
|
2305
|
+
case "remove":
|
|
2306
|
+
case "rm": {
|
|
2307
|
+
const position = Number.parseInt(rest ?? "", 10);
|
|
2308
|
+
if (Number.isFinite(position) && position >= 1 && position <= this.draftAttachmentIds.length) {
|
|
2309
|
+
const id = this.draftAttachmentIds.splice(position - 1, 1)[0];
|
|
2310
|
+
if (id)
|
|
2311
|
+
this.attachmentStore.remove(id);
|
|
2312
|
+
}
|
|
2313
|
+
else {
|
|
2314
|
+
this.removeLastDraftAttachment();
|
|
2315
|
+
}
|
|
2316
|
+
this.refreshAttachmentStrip();
|
|
2317
|
+
this.showStatus("Image attachment removed.");
|
|
2318
|
+
break;
|
|
2319
|
+
}
|
|
2320
|
+
default:
|
|
2321
|
+
this.showStatus("Usage: /attach [list|clear|remove [n]]");
|
|
2322
|
+
break;
|
|
2227
2323
|
}
|
|
2228
2324
|
}
|
|
2229
2325
|
parseBangInput(text) {
|
|
@@ -2241,9 +2337,16 @@ export class InteractiveMode {
|
|
|
2241
2337
|
setupEditorSubmitHandler() {
|
|
2242
2338
|
this.defaultEditor.onSubmit = async (text) => {
|
|
2243
2339
|
text = text.trim();
|
|
2244
|
-
|
|
2340
|
+
const draftImageIds = [...(this.draftAttachmentIds ?? [])];
|
|
2341
|
+
const hasAttachments = draftImageIds.length > 0;
|
|
2342
|
+
if (!text && !hasAttachments)
|
|
2245
2343
|
return;
|
|
2246
2344
|
// Handle commands
|
|
2345
|
+
if (text === "/attach" || text.startsWith("/attach ")) {
|
|
2346
|
+
this.editor.setText("");
|
|
2347
|
+
this.handleAttachCommand(text.slice("/attach".length).trim());
|
|
2348
|
+
return;
|
|
2349
|
+
}
|
|
2247
2350
|
if (text === "/settings") {
|
|
2248
2351
|
this.showSettingsSelector();
|
|
2249
2352
|
this.editor.setText("");
|
|
@@ -2296,6 +2399,11 @@ export class InteractiveMode {
|
|
|
2296
2399
|
this.editor.setText("");
|
|
2297
2400
|
return;
|
|
2298
2401
|
}
|
|
2402
|
+
if (text === "/resource" || text.startsWith("/resource ")) {
|
|
2403
|
+
this.editor.setText("");
|
|
2404
|
+
await this.handleResourceCommand(text);
|
|
2405
|
+
return;
|
|
2406
|
+
}
|
|
2299
2407
|
if (text === "/star") {
|
|
2300
2408
|
this.handleStarCommand();
|
|
2301
2409
|
return true;
|
|
@@ -2400,8 +2508,26 @@ export class InteractiveMode {
|
|
|
2400
2508
|
return;
|
|
2401
2509
|
}
|
|
2402
2510
|
}
|
|
2511
|
+
let draftImages;
|
|
2512
|
+
if (hasAttachments) {
|
|
2513
|
+
try {
|
|
2514
|
+
draftImages = this.materializeDraftImages(draftImageIds);
|
|
2515
|
+
}
|
|
2516
|
+
catch (error) {
|
|
2517
|
+
this.showWarning(error instanceof Error ? error.message : String(error));
|
|
2518
|
+
return;
|
|
2519
|
+
}
|
|
2520
|
+
if (!this.isVisionCapable()) {
|
|
2521
|
+
this.showWarning("The selected model cannot accept images. Switch model (/model) or run /attach clear.");
|
|
2522
|
+
return;
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2403
2525
|
// Queue input during compaction (extension commands execute immediately)
|
|
2404
2526
|
if (this.session.isCompacting) {
|
|
2527
|
+
if (hasAttachments) {
|
|
2528
|
+
this.showWarning("Attachments are held while compaction finishes — resubmit after it completes.");
|
|
2529
|
+
return;
|
|
2530
|
+
}
|
|
2405
2531
|
if (this.isExtensionCommand(text)) {
|
|
2406
2532
|
this.editor.addToHistory?.(text);
|
|
2407
2533
|
this.editor.setText("");
|
|
@@ -2417,7 +2543,10 @@ export class InteractiveMode {
|
|
|
2417
2543
|
if (this.session.isStreaming) {
|
|
2418
2544
|
this.editor.addToHistory?.(text);
|
|
2419
2545
|
this.editor.setText("");
|
|
2420
|
-
await this.session.prompt(text, { streamingBehavior: "steer" });
|
|
2546
|
+
await this.session.prompt(text, draftImages ? { images: draftImages, streamingBehavior: "steer" } : { streamingBehavior: "steer" });
|
|
2547
|
+
// Queued without throwing: acceptance — release exactly what was sent.
|
|
2548
|
+
if (draftImageIds.length > 0)
|
|
2549
|
+
this.consumeDraftAttachments(draftImageIds);
|
|
2421
2550
|
this.updatePendingMessagesDisplay();
|
|
2422
2551
|
this.ui.requestRender();
|
|
2423
2552
|
return;
|
|
@@ -2425,11 +2554,14 @@ export class InteractiveMode {
|
|
|
2425
2554
|
// Normal message submission
|
|
2426
2555
|
// First, move any pending bash components to chat
|
|
2427
2556
|
this.flushPendingBashComponents();
|
|
2557
|
+
const payload = draftImages
|
|
2558
|
+
? { text, images: draftImages, imageIds: draftImageIds }
|
|
2559
|
+
: { text };
|
|
2428
2560
|
if (this.onInputCallback) {
|
|
2429
|
-
this.onInputCallback(
|
|
2561
|
+
this.onInputCallback(payload);
|
|
2430
2562
|
}
|
|
2431
2563
|
else {
|
|
2432
|
-
this.
|
|
2564
|
+
this.pendingPromptPayloads.push(payload);
|
|
2433
2565
|
}
|
|
2434
2566
|
this.editor.addToHistory?.(text);
|
|
2435
2567
|
};
|
|
@@ -2445,6 +2577,13 @@ export class InteractiveMode {
|
|
|
2445
2577
|
}
|
|
2446
2578
|
this.footer.invalidate();
|
|
2447
2579
|
switch (event.type) {
|
|
2580
|
+
case "prompt_settled":
|
|
2581
|
+
// §17 (M4): fire-and-forget — the sound must never delay the prompt
|
|
2582
|
+
// path or change outcomes; failures are diagnostics only.
|
|
2583
|
+
void this._completionSoundService()
|
|
2584
|
+
.handleSettled(event)
|
|
2585
|
+
.then((result) => this.session.recordCompletionSoundResult(event.promptRunId, result));
|
|
2586
|
+
break;
|
|
2448
2587
|
case "agent_start":
|
|
2449
2588
|
this.workingStartedAt = Date.now();
|
|
2450
2589
|
this.pendingTools.clear();
|
|
@@ -2962,14 +3101,14 @@ export class InteractiveMode {
|
|
|
2962
3101
|
}
|
|
2963
3102
|
}
|
|
2964
3103
|
async getUserInput() {
|
|
2965
|
-
const
|
|
2966
|
-
if (
|
|
2967
|
-
return
|
|
3104
|
+
const queuedPayload = this.pendingPromptPayloads.shift();
|
|
3105
|
+
if (queuedPayload !== undefined) {
|
|
3106
|
+
return queuedPayload;
|
|
2968
3107
|
}
|
|
2969
3108
|
return new Promise((resolve) => {
|
|
2970
|
-
this.onInputCallback = (
|
|
3109
|
+
this.onInputCallback = (payload) => {
|
|
2971
3110
|
this.onInputCallback = undefined;
|
|
2972
|
-
resolve(
|
|
3111
|
+
resolve(payload);
|
|
2973
3112
|
};
|
|
2974
3113
|
});
|
|
2975
3114
|
}
|
|
@@ -3012,6 +3151,7 @@ export class InteractiveMode {
|
|
|
3012
3151
|
*/
|
|
3013
3152
|
isShuttingDown = false;
|
|
3014
3153
|
async shutdown(options) {
|
|
3154
|
+
this.interactiveLoopActive = false;
|
|
3015
3155
|
if (this.isShuttingDown)
|
|
3016
3156
|
return;
|
|
3017
3157
|
this.isShuttingDown = true;
|
|
@@ -4853,6 +4993,71 @@ export class InteractiveMode {
|
|
|
4853
4993
|
this.chatContainer.addChild(new Text(theme.fg("dim", `Session name set: ${name}`), 1, 0));
|
|
4854
4994
|
this.ui.requestRender();
|
|
4855
4995
|
}
|
|
4996
|
+
/**
|
|
4997
|
+
* `/resource [probe|policy]` (roadmap §19.1, observe-only in this release):
|
|
4998
|
+
* summary shows pressure/action/effective caps, `probe` shows verbose local
|
|
4999
|
+
* host details, `policy` shows mode/thresholds/caps. Permits and shards
|
|
5000
|
+
* views arrive with their subsystems (M3/M5).
|
|
5001
|
+
*/
|
|
5002
|
+
async handleResourceCommand(text) {
|
|
5003
|
+
const subcommand = text.replace(/^\/resource\s*/, "").trim();
|
|
5004
|
+
if (subcommand !== "" && subcommand !== "probe" && subcommand !== "policy") {
|
|
5005
|
+
this.showWarning("Usage: /resource [probe|policy]");
|
|
5006
|
+
this.ui.requestRender();
|
|
5007
|
+
return;
|
|
5008
|
+
}
|
|
5009
|
+
const resolved = resolveResourceGovernorSettings(this.settingsManager.getResourceGovernorSettings());
|
|
5010
|
+
const lines = [];
|
|
5011
|
+
if (subcommand === "policy") {
|
|
5012
|
+
lines.push(theme.bold("Resource Policy"), "", ...formatResourcePolicyLines(resolved));
|
|
5013
|
+
}
|
|
5014
|
+
else {
|
|
5015
|
+
const snapshot = await captureHostResourceSnapshot({
|
|
5016
|
+
maxProbeMs: resolved.maxProbeMs,
|
|
5017
|
+
cpuSampleMs: resolved.cpuSampleMs,
|
|
5018
|
+
});
|
|
5019
|
+
if (subcommand === "probe") {
|
|
5020
|
+
lines.push(theme.bold("Resource Probe"), "", ...formatResourceProbeLines(snapshot));
|
|
5021
|
+
}
|
|
5022
|
+
else {
|
|
5023
|
+
const decision = decideResourceAdmission({
|
|
5024
|
+
snapshot,
|
|
5025
|
+
config: resolved.admission,
|
|
5026
|
+
configuredCaps: {
|
|
5027
|
+
maxToolConcurrency: this.settingsManager.getAgentRuntimeSettings().maxToolConcurrency,
|
|
5028
|
+
},
|
|
5029
|
+
});
|
|
5030
|
+
lines.push(theme.bold("Resource Status"), "", ...formatResourceSummaryLines(resolved.mode, decision));
|
|
5031
|
+
}
|
|
5032
|
+
for (const error of resolved.errors) {
|
|
5033
|
+
lines.push(theme.fg("dim", `settings error: ${error}`));
|
|
5034
|
+
}
|
|
5035
|
+
}
|
|
5036
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
5037
|
+
this.chatContainer.addChild(new Text(lines.join("\n"), 1, 0));
|
|
5038
|
+
this.ui.requestRender();
|
|
5039
|
+
}
|
|
5040
|
+
_completionSound;
|
|
5041
|
+
/** §17.4: sounds play only on this interactive TTY surface, never RPC/JSON/print/CI. */
|
|
5042
|
+
_completionSoundService() {
|
|
5043
|
+
this._completionSound ??= new CompletionSoundService({
|
|
5044
|
+
getSettings: () => this.settingsManager.getNotificationSettings().completionSound,
|
|
5045
|
+
surface: () => ({
|
|
5046
|
+
isTui: true,
|
|
5047
|
+
isTty: process.stdout.isTTY === true,
|
|
5048
|
+
isCi: process.env.CI !== undefined && process.env.CI !== "",
|
|
5049
|
+
}),
|
|
5050
|
+
candidates: () => {
|
|
5051
|
+
const resolved = resolveCompletionSoundSettings(this.settingsManager.getNotificationSettings().completionSound);
|
|
5052
|
+
return selectCompletionSoundCandidates({
|
|
5053
|
+
platform: process.platform,
|
|
5054
|
+
isWsl: process.platform === "linux" && /microsoft/i.test(os.release()),
|
|
5055
|
+
terminalBellFallback: resolved.terminalBellFallback,
|
|
5056
|
+
});
|
|
5057
|
+
},
|
|
5058
|
+
});
|
|
5059
|
+
return this._completionSound;
|
|
5060
|
+
}
|
|
4856
5061
|
handleSessionCommand() {
|
|
4857
5062
|
const stats = this.session.getSessionStats();
|
|
4858
5063
|
const sessionName = this.sessionManager.getSessionName();
|
|
@@ -4941,34 +5146,31 @@ export class InteractiveMode {
|
|
|
4941
5146
|
/**
|
|
4942
5147
|
* Get capitalized display string for an editor keybinding action.
|
|
4943
5148
|
*/
|
|
4944
|
-
getEditorKeyDisplay(action) {
|
|
4945
|
-
return keyDisplayText(action);
|
|
4946
|
-
}
|
|
4947
5149
|
handleHotkeysCommand() {
|
|
4948
5150
|
// Navigation keybindings
|
|
4949
|
-
const cursorUp =
|
|
4950
|
-
const cursorDown =
|
|
4951
|
-
const cursorLeft =
|
|
4952
|
-
const cursorRight =
|
|
4953
|
-
const cursorWordLeft =
|
|
4954
|
-
const cursorWordRight =
|
|
4955
|
-
const cursorLineStart =
|
|
4956
|
-
const cursorLineEnd =
|
|
4957
|
-
const jumpForward =
|
|
4958
|
-
const jumpBackward =
|
|
4959
|
-
const pageUp =
|
|
4960
|
-
const pageDown =
|
|
5151
|
+
const cursorUp = keyDisplayText("tui.editor.cursorUp");
|
|
5152
|
+
const cursorDown = keyDisplayText("tui.editor.cursorDown");
|
|
5153
|
+
const cursorLeft = keyDisplayText("tui.editor.cursorLeft");
|
|
5154
|
+
const cursorRight = keyDisplayText("tui.editor.cursorRight");
|
|
5155
|
+
const cursorWordLeft = keyDisplayText("tui.editor.cursorWordLeft");
|
|
5156
|
+
const cursorWordRight = keyDisplayText("tui.editor.cursorWordRight");
|
|
5157
|
+
const cursorLineStart = keyDisplayText("tui.editor.cursorLineStart");
|
|
5158
|
+
const cursorLineEnd = keyDisplayText("tui.editor.cursorLineEnd");
|
|
5159
|
+
const jumpForward = keyDisplayText("tui.editor.jumpForward");
|
|
5160
|
+
const jumpBackward = keyDisplayText("tui.editor.jumpBackward");
|
|
5161
|
+
const pageUp = keyDisplayText("tui.editor.pageUp");
|
|
5162
|
+
const pageDown = keyDisplayText("tui.editor.pageDown");
|
|
4961
5163
|
// Editing keybindings
|
|
4962
|
-
const submit =
|
|
4963
|
-
const newLine =
|
|
4964
|
-
const deleteWordBackward =
|
|
4965
|
-
const deleteWordForward =
|
|
4966
|
-
const deleteToLineStart =
|
|
4967
|
-
const deleteToLineEnd =
|
|
4968
|
-
const yank =
|
|
4969
|
-
const yankPop =
|
|
4970
|
-
const undo =
|
|
4971
|
-
const tab =
|
|
5164
|
+
const submit = keyDisplayText("tui.input.submit");
|
|
5165
|
+
const newLine = keyDisplayText("tui.input.newLine");
|
|
5166
|
+
const deleteWordBackward = keyDisplayText("tui.editor.deleteWordBackward");
|
|
5167
|
+
const deleteWordForward = keyDisplayText("tui.editor.deleteWordForward");
|
|
5168
|
+
const deleteToLineStart = keyDisplayText("tui.editor.deleteToLineStart");
|
|
5169
|
+
const deleteToLineEnd = keyDisplayText("tui.editor.deleteToLineEnd");
|
|
5170
|
+
const yank = keyDisplayText("tui.editor.yank");
|
|
5171
|
+
const yankPop = keyDisplayText("tui.editor.yankPop");
|
|
5172
|
+
const undo = keyDisplayText("tui.editor.undo");
|
|
5173
|
+
const tab = keyDisplayText("tui.input.tab");
|
|
4972
5174
|
// App keybindings
|
|
4973
5175
|
const interrupt = this.getAppKeyDisplay("app.interrupt");
|
|
4974
5176
|
const clear = this.getAppKeyDisplay("app.clear");
|