@voybio/ace-swarm 0.2.0 → 0.2.2
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 +15 -15
- package/assets/agent-state/EVIDENCE_LOG.md +1 -1
- package/assets/agent-state/STATUS.md +2 -2
- package/dist/ace-autonomy.js +38 -1
- package/dist/ace-context.js +8 -0
- package/dist/ace-server-instructions.js +55 -19
- package/dist/ace-state-resolver.d.ts +18 -0
- package/dist/ace-state-resolver.js +106 -0
- package/dist/cli.js +67 -0
- package/dist/handoff-registry.js +11 -7
- package/dist/helpers.js +74 -8
- package/dist/job-scheduler.js +94 -44
- package/dist/run-ledger.js +3 -4
- package/dist/server.d.ts +1 -1
- package/dist/server.js +1 -1
- package/dist/shared.d.ts +1 -1
- package/dist/status-events.js +12 -14
- package/dist/store/bootstrap-store.js +20 -9
- package/dist/store/materializers/context-snapshot-materializer.d.ts +10 -0
- package/dist/store/materializers/context-snapshot-materializer.js +51 -0
- package/dist/store/materializers/host-file-materializer.d.ts +6 -0
- package/dist/store/materializers/host-file-materializer.js +13 -0
- package/dist/store/materializers/projection-manager.d.ts +14 -0
- package/dist/store/materializers/projection-manager.js +73 -0
- package/dist/store/materializers/scheduler-projection-materializer.d.ts +16 -0
- package/dist/store/materializers/scheduler-projection-materializer.js +48 -0
- package/dist/store/repositories/context-snapshot-repository.d.ts +46 -0
- package/dist/store/repositories/context-snapshot-repository.js +105 -0
- package/dist/store/repositories/local-model-runtime-repository.d.ts +98 -0
- package/dist/store/repositories/local-model-runtime-repository.js +165 -0
- package/dist/store/repositories/scheduler-repository.d.ts +21 -39
- package/dist/store/repositories/scheduler-repository.js +123 -93
- package/dist/store/repositories/todo-repository.d.ts +4 -0
- package/dist/store/repositories/todo-repository.js +50 -0
- package/dist/store/state-reader.d.ts +8 -1
- package/dist/store/state-reader.js +12 -1
- package/dist/store/store-artifacts.js +31 -5
- package/dist/store/store-authority-audit.d.ts +30 -0
- package/dist/store/store-authority-audit.js +448 -0
- package/dist/store/types.d.ts +2 -0
- package/dist/store/types.js +1 -0
- package/dist/todo-state.js +179 -11
- package/dist/tools-files.js +2 -1
- package/dist/tools-framework.js +60 -0
- package/dist/tools-memory.js +69 -34
- package/dist/tools-todo.js +1 -1
- package/dist/tui/agent-worker.d.ts +1 -1
- package/dist/tui/agent-worker.js +5 -3
- package/dist/tui/chat.d.ts +19 -0
- package/dist/tui/chat.js +275 -9
- package/dist/tui/commands.d.ts +2 -0
- package/dist/tui/commands.js +62 -0
- package/dist/tui/dashboard.d.ts +5 -0
- package/dist/tui/dashboard.js +38 -2
- package/dist/tui/index.d.ts +5 -0
- package/dist/tui/index.js +146 -2
- package/dist/tui/input.js +5 -0
- package/dist/tui/layout.d.ts +24 -0
- package/dist/tui/layout.js +76 -2
- package/dist/tui/local-model-contract.d.ts +50 -0
- package/dist/tui/local-model-contract.js +272 -0
- package/dist/vericify-bridge.js +3 -4
- package/dist/vericify-context.js +18 -6
- package/package.json +1 -1
package/dist/tui/index.js
CHANGED
|
@@ -18,6 +18,8 @@ import { detectColorLevel, write, cursor, screen, fg, style } from "./renderer.j
|
|
|
18
18
|
import { ALL_AGENTS, WORKSPACE_ROOT } from "../helpers.js";
|
|
19
19
|
import { backfillHandoffsIntoScheduler } from "../tools-handoff.js";
|
|
20
20
|
import { DEFAULT_OLLAMA_MODEL, inferProviderFromModel, normalizeLocalBaseUrl, } from "./provider-discovery.js";
|
|
21
|
+
import { resolveAceStateLayout } from "../ace-state-resolver.js";
|
|
22
|
+
import { withLocalModelRuntimeRepository, } from "../store/repositories/local-model-runtime-repository.js";
|
|
21
23
|
const DASHBOARD_CONTROLS = ["provider", "model", "chat", "logs", "refresh"];
|
|
22
24
|
// ── TUI Application ─────────────────────────────────────────────────
|
|
23
25
|
export class AceTui {
|
|
@@ -48,6 +50,8 @@ export class AceTui {
|
|
|
48
50
|
messageQueue = [];
|
|
49
51
|
workspaceRoot;
|
|
50
52
|
providerBaseUrls = new Map();
|
|
53
|
+
latestRuntimeStatus = null;
|
|
54
|
+
pendingCloseTabId = null;
|
|
51
55
|
constructor(options = {}) {
|
|
52
56
|
const workspaceRoot = options.workspaceRoot ?? WORKSPACE_ROOT;
|
|
53
57
|
this.workspaceRoot = workspaceRoot;
|
|
@@ -218,17 +222,19 @@ export class AceTui {
|
|
|
218
222
|
});
|
|
219
223
|
// Dashboard: state updated
|
|
220
224
|
this.dashboard.on("updated", () => {
|
|
225
|
+
this.latestRuntimeStatus = this.dashboard.getLatestRuntimeStatus() ?? null;
|
|
221
226
|
const active = this.tabs.getActiveTab();
|
|
222
227
|
if (active.type === "dashboard") {
|
|
223
228
|
this.renderActiveView();
|
|
224
229
|
}
|
|
230
|
+
this.renderStatusBar();
|
|
225
231
|
});
|
|
226
232
|
// Dashboard: discovered providers from the store → feed into TUI provider controls
|
|
227
233
|
this.dashboard.on("providers", (discovered) => {
|
|
228
234
|
for (const d of discovered) {
|
|
229
235
|
this.ensureProvider(d.provider);
|
|
230
|
-
if (d.
|
|
231
|
-
this.setProviderBaseUrl(d.provider, d.
|
|
236
|
+
if (d.endpoint)
|
|
237
|
+
this.setProviderBaseUrl(d.provider, d.endpoint);
|
|
232
238
|
if (d.models && d.models.length > 0)
|
|
233
239
|
this.setProviderModels(d.provider, d.models, false);
|
|
234
240
|
}
|
|
@@ -286,6 +292,9 @@ export class AceTui {
|
|
|
286
292
|
case "l":
|
|
287
293
|
this.clearView();
|
|
288
294
|
return;
|
|
295
|
+
case "w":
|
|
296
|
+
this.closeCurrentTab();
|
|
297
|
+
return;
|
|
289
298
|
}
|
|
290
299
|
}
|
|
291
300
|
// Alt+number → switch tab
|
|
@@ -479,6 +488,7 @@ export class AceTui {
|
|
|
479
488
|
renderStatusBar() {
|
|
480
489
|
const snap = this.telemetry.getSnapshot();
|
|
481
490
|
const agentTokens = this.agentRunner.getTotalTokens();
|
|
491
|
+
const runtimeStatus = this.getActiveRuntimeStatus();
|
|
482
492
|
const state = {
|
|
483
493
|
taskState: this.getTaskState(),
|
|
484
494
|
provider: this.provider,
|
|
@@ -486,6 +496,29 @@ export class AceTui {
|
|
|
486
496
|
tokensIn: snap.tokensIn + agentTokens.input,
|
|
487
497
|
tokensOut: snap.tokensOut + agentTokens.output,
|
|
488
498
|
startTime: this.startTime,
|
|
499
|
+
activeTabLabel: this.tabs.getActiveTab().label,
|
|
500
|
+
sessionId: runtimeStatus?.session_id,
|
|
501
|
+
turnCount: runtimeStatus?.turn_count,
|
|
502
|
+
preflightState: runtimeStatus?.preflight_state,
|
|
503
|
+
agentName: runtimeStatus?.role,
|
|
504
|
+
taskName: runtimeStatus?.current_task,
|
|
505
|
+
bridgeStatus: runtimeStatus?.bridge_status,
|
|
506
|
+
activeTool: runtimeStatus?.active_tool,
|
|
507
|
+
blockedReason: runtimeStatus?.blocked_reason,
|
|
508
|
+
nextAction: runtimeStatus?.recommended_next_action,
|
|
509
|
+
approvalState: runtimeStatus?.approval_state,
|
|
510
|
+
retryState: runtimeStatus?.retry_state
|
|
511
|
+
? `attempt ${runtimeStatus.retry_state.attempt}${typeof runtimeStatus.retry_state.max_attempts === "number"
|
|
512
|
+
? `/${runtimeStatus.retry_state.max_attempts}`
|
|
513
|
+
: ""}`
|
|
514
|
+
: undefined,
|
|
515
|
+
pollState: runtimeStatus?.poll_state
|
|
516
|
+
? runtimeStatus.poll_state.active
|
|
517
|
+
? `active${typeof runtimeStatus.poll_state.interval_ms === "number"
|
|
518
|
+
? `/${runtimeStatus.poll_state.interval_ms}ms`
|
|
519
|
+
: ""}`
|
|
520
|
+
: "paused"
|
|
521
|
+
: undefined,
|
|
489
522
|
};
|
|
490
523
|
this.layout.renderStatusBar(state);
|
|
491
524
|
}
|
|
@@ -495,6 +528,17 @@ export class AceTui {
|
|
|
495
528
|
this.layout.renderInputLine(this.input.getBuffer(), this.input.getCursorPos(), mode, prompt);
|
|
496
529
|
}
|
|
497
530
|
getTaskState() {
|
|
531
|
+
const runtimeStatus = this.getActiveRuntimeStatus();
|
|
532
|
+
if (runtimeStatus &&
|
|
533
|
+
["blocked", "failed", "needs_input", "approval_pending"].includes(runtimeStatus.bridge_status)) {
|
|
534
|
+
return "blocked";
|
|
535
|
+
}
|
|
536
|
+
if (runtimeStatus &&
|
|
537
|
+
(runtimeStatus.bridge_status === "retrying" ||
|
|
538
|
+
runtimeStatus.bridge_status === "running" ||
|
|
539
|
+
Boolean(runtimeStatus.active_tool))) {
|
|
540
|
+
return "running";
|
|
541
|
+
}
|
|
498
542
|
if (this.activeChatSession?.isStreaming())
|
|
499
543
|
return "running";
|
|
500
544
|
if (this.agentRunner.getActiveCount() > 0)
|
|
@@ -503,6 +547,7 @@ export class AceTui {
|
|
|
503
547
|
}
|
|
504
548
|
syncTabState() {
|
|
505
549
|
const tab = this.tabs.getActiveTab();
|
|
550
|
+
this.pendingCloseTabId = null;
|
|
506
551
|
// Update active chat session pointer
|
|
507
552
|
if (tab.type === "chat") {
|
|
508
553
|
this.activeChatSession = this.chatSessions.get(tab.id) ?? null;
|
|
@@ -527,6 +572,13 @@ export class AceTui {
|
|
|
527
572
|
const now = Date.now();
|
|
528
573
|
this.messageQueue = this.messageQueue.filter(m => m.expiry > now);
|
|
529
574
|
}
|
|
575
|
+
getActiveRuntimeStatus() {
|
|
576
|
+
const activeTab = this.tabs.getActiveTab();
|
|
577
|
+
if (activeTab.type === "chat") {
|
|
578
|
+
return this.chatSessions.get(activeTab.id)?.getCurrentRuntimeStatus() ?? this.latestRuntimeStatus;
|
|
579
|
+
}
|
|
580
|
+
return this.latestRuntimeStatus;
|
|
581
|
+
}
|
|
530
582
|
normalizeProvider(provider) {
|
|
531
583
|
if (!provider)
|
|
532
584
|
return undefined;
|
|
@@ -901,6 +953,25 @@ export class AceTui {
|
|
|
901
953
|
this.renderStatusBar();
|
|
902
954
|
this.renderInputArea();
|
|
903
955
|
});
|
|
956
|
+
session.on("runtime_status", (status) => {
|
|
957
|
+
this.latestRuntimeStatus = status;
|
|
958
|
+
if (this.tabs.getActiveTab().id === tab.id || this.tabs.getActiveTab().type === "dashboard") {
|
|
959
|
+
this.renderActiveView();
|
|
960
|
+
}
|
|
961
|
+
this.renderStatusBar();
|
|
962
|
+
});
|
|
963
|
+
session.on("tool_call", (tool) => {
|
|
964
|
+
this.dashboard.addEvent("bridge", `tool call → ${tool}`);
|
|
965
|
+
if (this.tabs.getActiveTab().type === "dashboard") {
|
|
966
|
+
this.renderActiveView();
|
|
967
|
+
}
|
|
968
|
+
});
|
|
969
|
+
session.on("tool_result", (tool, toolResult) => {
|
|
970
|
+
this.dashboard.addEvent("bridge", `${toolResult.ok ? "tool ok" : "tool error"} → ${tool}: ${toolResult.summary}`);
|
|
971
|
+
if (this.tabs.getActiveTab().type === "dashboard") {
|
|
972
|
+
this.renderActiveView();
|
|
973
|
+
}
|
|
974
|
+
});
|
|
904
975
|
session.on("error", (msg) => {
|
|
905
976
|
this.showMessage(msg, "error");
|
|
906
977
|
});
|
|
@@ -917,6 +988,19 @@ export class AceTui {
|
|
|
917
988
|
}
|
|
918
989
|
closeCurrentTab() {
|
|
919
990
|
const tab = this.tabs.getActiveTab();
|
|
991
|
+
if (!tab.closeable) {
|
|
992
|
+
this.showMessage(`Tab '${tab.label}' cannot be closed.`, "warn");
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
if (tab.type === "chat") {
|
|
996
|
+
const session = this.chatSessions.get(tab.id);
|
|
997
|
+
if (session?.hasMeaningfulTranscript() && this.pendingCloseTabId !== tab.id) {
|
|
998
|
+
this.pendingCloseTabId = tab.id;
|
|
999
|
+
this.showMessage("Chat has transcript state. Use /archive to persist it, or close again to discard.", "warn");
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
this.pendingCloseTabId = null;
|
|
920
1004
|
// Clean up chat session if closing a chat tab
|
|
921
1005
|
if (tab.type === "chat") {
|
|
922
1006
|
const session = this.chatSessions.get(tab.id);
|
|
@@ -933,6 +1017,51 @@ export class AceTui {
|
|
|
933
1017
|
this.syncTabState();
|
|
934
1018
|
this.fullRender();
|
|
935
1019
|
}
|
|
1020
|
+
async archiveCurrentTab() {
|
|
1021
|
+
const tab = this.tabs.getActiveTab();
|
|
1022
|
+
if (tab.type !== "chat") {
|
|
1023
|
+
this.showMessage("Archive is available only for chat tabs.", "warn");
|
|
1024
|
+
return;
|
|
1025
|
+
}
|
|
1026
|
+
const session = this.chatSessions.get(tab.id);
|
|
1027
|
+
if (!session) {
|
|
1028
|
+
this.showMessage("Chat session not found for archive.", "error");
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
1031
|
+
if (!session.hasMeaningfulTranscript()) {
|
|
1032
|
+
this.showMessage("Chat is empty. Closing without archive.", "info");
|
|
1033
|
+
this.pendingCloseTabId = tab.id;
|
|
1034
|
+
this.closeCurrentTab();
|
|
1035
|
+
return;
|
|
1036
|
+
}
|
|
1037
|
+
const runtimeStatus = session.getCurrentRuntimeStatus();
|
|
1038
|
+
await withLocalModelRuntimeRepository(this.workspaceRoot, async (repo) => {
|
|
1039
|
+
await repo.archiveChat({
|
|
1040
|
+
session_id: session.getSessionId(),
|
|
1041
|
+
tab_id: tab.id,
|
|
1042
|
+
label: tab.label,
|
|
1043
|
+
provider: session.getProvider(),
|
|
1044
|
+
model: session.getModel(),
|
|
1045
|
+
created_at: session.getCreatedAt(),
|
|
1046
|
+
last_active_at: session.getLastActiveAt(),
|
|
1047
|
+
transcript_excerpt: session.getTranscriptExcerpt(),
|
|
1048
|
+
transcript_summary: session.getTranscriptSummary(),
|
|
1049
|
+
ace_context: {
|
|
1050
|
+
resolved_layout_mode: resolveAceStateLayout(this.workspaceRoot).physicalMode,
|
|
1051
|
+
role: runtimeStatus?.role,
|
|
1052
|
+
bridge_status: runtimeStatus?.bridge_status ?? "done",
|
|
1053
|
+
active_tool: runtimeStatus?.active_tool,
|
|
1054
|
+
blocked_reason: runtimeStatus?.blocked_reason,
|
|
1055
|
+
approval_state: runtimeStatus?.approval_state,
|
|
1056
|
+
retry_state: runtimeStatus?.retry_state,
|
|
1057
|
+
recommended_next_action: runtimeStatus?.recommended_next_action,
|
|
1058
|
+
},
|
|
1059
|
+
});
|
|
1060
|
+
});
|
|
1061
|
+
this.showMessage(`Archived chat '${tab.label}'.`, "info");
|
|
1062
|
+
this.pendingCloseTabId = tab.id;
|
|
1063
|
+
this.closeCurrentTab();
|
|
1064
|
+
}
|
|
936
1065
|
showMessage(text, level = "info") {
|
|
937
1066
|
const colorFn = level === "error" ? fg.red : level === "warn" ? fg.yellow : fg.gray;
|
|
938
1067
|
const prefix = level === "error" ? "ERROR" : level === "warn" ? "WARN" : "INFO";
|
|
@@ -967,6 +1096,20 @@ export class AceTui {
|
|
|
967
1096
|
this.layout.fullRedraw();
|
|
968
1097
|
this.fullRender();
|
|
969
1098
|
}
|
|
1099
|
+
setApprovalState(state) {
|
|
1100
|
+
const session = this.activeChatSession;
|
|
1101
|
+
if (!session) {
|
|
1102
|
+
this.showMessage("No active chat runtime to update approval state.", "warn");
|
|
1103
|
+
return false;
|
|
1104
|
+
}
|
|
1105
|
+
const ok = session.setApprovalState(state);
|
|
1106
|
+
if (!ok) {
|
|
1107
|
+
this.showMessage("No active runtime packet to update approval state.", "warn");
|
|
1108
|
+
return false;
|
|
1109
|
+
}
|
|
1110
|
+
this.renderStatusBar();
|
|
1111
|
+
return true;
|
|
1112
|
+
}
|
|
970
1113
|
getStatus() {
|
|
971
1114
|
const snap = this.telemetry.getSnapshot();
|
|
972
1115
|
return {
|
|
@@ -979,6 +1122,7 @@ export class AceTui {
|
|
|
979
1122
|
requests: snap.requestCount,
|
|
980
1123
|
activeAgents: this.agentRunner.getActiveCount(),
|
|
981
1124
|
tabs: this.tabs.getTabs().length,
|
|
1125
|
+
bridgeStatus: this.latestRuntimeStatus?.bridge_status,
|
|
982
1126
|
};
|
|
983
1127
|
}
|
|
984
1128
|
quit() {
|
package/dist/tui/input.js
CHANGED
|
@@ -101,6 +101,11 @@ export class InputHandler extends EventEmitter {
|
|
|
101
101
|
this.emit("key", { name: "l", sequence: ch, ctrl: true, meta: false, shift: false });
|
|
102
102
|
continue;
|
|
103
103
|
}
|
|
104
|
+
// Ctrl+W — close/archive current tab
|
|
105
|
+
if (code === 23) {
|
|
106
|
+
this.emit("key", { name: "w", sequence: ch, ctrl: true, meta: false, shift: false });
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
104
109
|
// Tab
|
|
105
110
|
if (code === 9) {
|
|
106
111
|
if ((this.mode === "command" || this.mode === "chat") && this.buffer.length > 0) {
|
package/dist/tui/layout.d.ts
CHANGED
|
@@ -24,6 +24,17 @@ export interface StatusBarState {
|
|
|
24
24
|
tokensIn: number;
|
|
25
25
|
tokensOut: number;
|
|
26
26
|
startTime: number;
|
|
27
|
+
activeTabLabel?: string;
|
|
28
|
+
sessionId?: string;
|
|
29
|
+
turnCount?: number;
|
|
30
|
+
preflightState?: string;
|
|
31
|
+
bridgeStatus?: string;
|
|
32
|
+
activeTool?: string;
|
|
33
|
+
blockedReason?: string;
|
|
34
|
+
nextAction?: string;
|
|
35
|
+
approvalState?: string;
|
|
36
|
+
retryState?: string;
|
|
37
|
+
pollState?: string;
|
|
27
38
|
taskName?: string;
|
|
28
39
|
agentName?: string;
|
|
29
40
|
}
|
|
@@ -44,6 +55,17 @@ export interface DashboardControlState {
|
|
|
44
55
|
selectedIndex: number;
|
|
45
56
|
items: DashboardControlItem[];
|
|
46
57
|
}
|
|
58
|
+
export declare function formatRuntimeStatusSummary(state: Pick<StatusBarState, "sessionId" | "turnCount" | "preflightState" | "taskName" | "agentName" | "approvalState" | "retryState" | "pollState">): string | undefined;
|
|
59
|
+
interface RuntimeStatusSummary {
|
|
60
|
+
bridge_status: string;
|
|
61
|
+
preflight_state: string;
|
|
62
|
+
role?: string;
|
|
63
|
+
approval_state?: string;
|
|
64
|
+
active_tool?: string;
|
|
65
|
+
active_tool_role?: string;
|
|
66
|
+
recommended_next_action?: string;
|
|
67
|
+
blocked_reason?: string;
|
|
68
|
+
}
|
|
47
69
|
export declare class LayoutManager {
|
|
48
70
|
private zones;
|
|
49
71
|
private cols;
|
|
@@ -94,6 +116,7 @@ export interface DashboardData {
|
|
|
94
116
|
tokensIn: number;
|
|
95
117
|
tokensOut: number;
|
|
96
118
|
tokensPerSec: number;
|
|
119
|
+
runtimeStatus?: RuntimeStatusSummary;
|
|
97
120
|
tasks: TaskItem[];
|
|
98
121
|
events: ActivityEvent[];
|
|
99
122
|
}
|
|
@@ -113,4 +136,5 @@ export interface ChatMessage {
|
|
|
113
136
|
timestamp?: number;
|
|
114
137
|
tokens?: number;
|
|
115
138
|
}
|
|
139
|
+
export {};
|
|
116
140
|
//# sourceMappingURL=layout.d.ts.map
|
package/dist/tui/layout.js
CHANGED
|
@@ -5,6 +5,34 @@
|
|
|
5
5
|
* Arttime-inspired: defined zones for each UI element.
|
|
6
6
|
*/
|
|
7
7
|
import { getTermSize, write, writeAt, drawBox, clearRegion, cursor, screen, style, fg, bg, padRight, truncate, visibleWidth, box, symbols, formatTime, formatElapsed, formatNumber, hline, } from "./renderer.js";
|
|
8
|
+
export function formatRuntimeStatusSummary(state) {
|
|
9
|
+
const parts = [];
|
|
10
|
+
if (state.sessionId) {
|
|
11
|
+
parts.push(`sid:${truncate(state.sessionId, 10)}`);
|
|
12
|
+
}
|
|
13
|
+
if (typeof state.turnCount === "number") {
|
|
14
|
+
parts.push(`turn:${state.turnCount}`);
|
|
15
|
+
}
|
|
16
|
+
if (state.agentName) {
|
|
17
|
+
parts.push(`role:${truncate(state.agentName, 12)}`);
|
|
18
|
+
}
|
|
19
|
+
if (state.taskName) {
|
|
20
|
+
parts.push(`task:${truncate(state.taskName, 18)}`);
|
|
21
|
+
}
|
|
22
|
+
if (state.preflightState) {
|
|
23
|
+
parts.push(`pf:${state.preflightState}`);
|
|
24
|
+
}
|
|
25
|
+
if (state.approvalState) {
|
|
26
|
+
parts.push(`approval:${state.approvalState}`);
|
|
27
|
+
}
|
|
28
|
+
if (state.retryState) {
|
|
29
|
+
parts.push(`retry:${state.retryState}`);
|
|
30
|
+
}
|
|
31
|
+
if (state.pollState) {
|
|
32
|
+
parts.push(`poll:${state.pollState}`);
|
|
33
|
+
}
|
|
34
|
+
return parts.length > 0 ? parts.join(" ") : undefined;
|
|
35
|
+
}
|
|
8
36
|
// ── Layout manager ───────────────────────────────────────────────────
|
|
9
37
|
export class LayoutManager {
|
|
10
38
|
zones;
|
|
@@ -116,12 +144,39 @@ export class LayoutManager {
|
|
|
116
144
|
stateIndicator = `${fg.red}${style.bold}${symbols.bullet} OVERDUE${style.reset}`;
|
|
117
145
|
break;
|
|
118
146
|
}
|
|
147
|
+
if (state.bridgeStatus === "approval_pending") {
|
|
148
|
+
stateIndicator = `${fg.yellow}${symbols.bullet} approval${style.reset}`;
|
|
149
|
+
}
|
|
150
|
+
else if (state.bridgeStatus === "retrying") {
|
|
151
|
+
stateIndicator = `${fg.yellow}${symbols.bullet} retrying${style.reset}`;
|
|
152
|
+
}
|
|
153
|
+
else if (state.bridgeStatus === "needs_input") {
|
|
154
|
+
stateIndicator = `${fg.yellow}${symbols.bullet} needs_input${style.reset}`;
|
|
155
|
+
}
|
|
156
|
+
if (state.activeTool) {
|
|
157
|
+
stateIndicator = `${fg.green}${symbols.bullet} ${state.activeTool}${style.reset}`;
|
|
158
|
+
}
|
|
159
|
+
const tabSeg = state.activeTabLabel
|
|
160
|
+
? `${fg.gray}tab: ${fg.white}${state.activeTabLabel}${style.reset}`
|
|
161
|
+
: undefined;
|
|
119
162
|
const providerSeg = `${fg.cyan}provider: ${fg.brightCyan}${state.provider}${style.reset}`;
|
|
120
163
|
const modelSeg = `${fg.cyan}model: ${fg.brightCyan}${state.model}${style.reset}`;
|
|
164
|
+
const runtimeSummary = formatRuntimeStatusSummary(state);
|
|
165
|
+
const runtimeSeg = runtimeSummary
|
|
166
|
+
? `${fg.gray}${runtimeSummary}${style.reset}`
|
|
167
|
+
: undefined;
|
|
121
168
|
const tokenSeg = `${fg.gray}tokens: ${fg.white}${formatNumber(state.tokensIn)}/${formatNumber(state.tokensOut)}${style.reset}`;
|
|
122
169
|
const timeSeg = `${fg.gray}${elapsed}${style.reset}`;
|
|
123
170
|
const clockSeg = `${fg.gray}${style.underline}${time}${style.reset}`;
|
|
124
|
-
const
|
|
171
|
+
const contextSeg = state.blockedReason
|
|
172
|
+
? `${fg.red}${truncate(state.blockedReason, Math.max(18, Math.floor(this.cols * 0.22)))}${style.reset}`
|
|
173
|
+
: state.nextAction
|
|
174
|
+
? `${fg.gray}next: ${fg.white}${truncate(state.nextAction, Math.max(18, Math.floor(this.cols * 0.18)))}${style.reset}`
|
|
175
|
+
: state.bridgeStatus
|
|
176
|
+
? `${fg.gray}${state.bridgeStatus}${style.reset}`
|
|
177
|
+
: undefined;
|
|
178
|
+
const segments = [stateIndicator, tabSeg, providerSeg, modelSeg, runtimeSeg, contextSeg, tokenSeg, timeSeg, clockSeg]
|
|
179
|
+
.filter((segment) => Boolean(segment));
|
|
125
180
|
const sep = ` ${fg.gray}│${style.reset} `;
|
|
126
181
|
const line = ` ${segments.join(sep)} `;
|
|
127
182
|
// Clear and write
|
|
@@ -198,13 +253,32 @@ export class LayoutManager {
|
|
|
198
253
|
renderStatusPanel(x, y, w, h, data) {
|
|
199
254
|
const lines = [
|
|
200
255
|
`${fg.gray}Phase: ${fg.brightWhite}${data.phase}`,
|
|
256
|
+
data.runtimeStatus?.bridge_status
|
|
257
|
+
? `${fg.gray}Bridge: ${fg.brightYellow}${data.runtimeStatus.bridge_status}`
|
|
258
|
+
: undefined,
|
|
259
|
+
data.runtimeStatus?.preflight_state
|
|
260
|
+
? `${fg.gray}Preflt: ${data.runtimeStatus.preflight_state === "blocked"
|
|
261
|
+
? fg.brightRed
|
|
262
|
+
: data.runtimeStatus.preflight_state === "attention_required"
|
|
263
|
+
? fg.yellow
|
|
264
|
+
: fg.brightGreen}${data.runtimeStatus.preflight_state}`
|
|
265
|
+
: undefined,
|
|
266
|
+
data.runtimeStatus?.role
|
|
267
|
+
? `${fg.gray}Role: ${fg.brightCyan}${data.runtimeStatus.role}`
|
|
268
|
+
: undefined,
|
|
269
|
+
data.runtimeStatus?.blocked_reason
|
|
270
|
+
? `${fg.gray}Blocker: ${fg.brightRed}${data.runtimeStatus.blocked_reason}`
|
|
271
|
+
: undefined,
|
|
272
|
+
data.runtimeStatus?.recommended_next_action
|
|
273
|
+
? `${fg.gray}Next: ${fg.white}${data.runtimeStatus.recommended_next_action}`
|
|
274
|
+
: undefined,
|
|
201
275
|
`${fg.gray}Provider:${fg.brightCyan} ${padRight(data.provider, 8)}`,
|
|
202
276
|
`${fg.gray}Model: ${fg.brightCyan}${data.model}`,
|
|
203
277
|
`${fg.gray}Agents: ${fg.brightGreen}${data.activeAgents}${fg.gray}/${data.totalAgents} active`,
|
|
204
278
|
`${fg.gray}Uptime: ${fg.white}${formatElapsed(Date.now() - data.startTime)}`,
|
|
205
279
|
`${fg.gray}Tokens: ${fg.white}${formatNumber(data.tokensIn)} in / ${formatNumber(data.tokensOut)} out`,
|
|
206
280
|
`${fg.gray}Speed: ${fg.white}${data.tokensPerSec.toFixed(0)} tok/s`,
|
|
207
|
-
];
|
|
281
|
+
].filter((line) => Boolean(line));
|
|
208
282
|
for (let i = 0; i < Math.min(lines.length, h); i++) {
|
|
209
283
|
writeAt(x, y + i, truncate(lines[i] + style.reset, w));
|
|
210
284
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type AceStateResolution } from "../ace-state-resolver.js";
|
|
2
|
+
import type { AceRuntimeStatusPacket, AceSessionActivationLedger, AceSessionContinuityRecord } from "../store/repositories/local-model-runtime-repository.js";
|
|
3
|
+
export interface AcePreflightPacket {
|
|
4
|
+
session_id: string;
|
|
5
|
+
workspace_root: string;
|
|
6
|
+
state_resolution: AceStateResolution;
|
|
7
|
+
preflight_state: "ready" | "attention_required" | "blocked";
|
|
8
|
+
bridge_status: "running" | "needs_input" | "approval_pending" | "retrying" | "blocked" | "failed" | "done";
|
|
9
|
+
quartet_health: "healthy" | "thin" | "incomplete" | "contradictory";
|
|
10
|
+
task_contract_health: "healthy" | "thin" | "blocked";
|
|
11
|
+
recommended_role?: string;
|
|
12
|
+
recommended_next_action?: string;
|
|
13
|
+
blockers: string[];
|
|
14
|
+
warnings: string[];
|
|
15
|
+
recall_summary?: string;
|
|
16
|
+
should_synthesize_plan: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface StartupNudge {
|
|
19
|
+
id: string;
|
|
20
|
+
text: string;
|
|
21
|
+
recommended_action: string;
|
|
22
|
+
}
|
|
23
|
+
export declare function shouldSynthesizeShortPlan(task: string): boolean;
|
|
24
|
+
export declare function buildAcePreflightPacket(input: {
|
|
25
|
+
sessionId: string;
|
|
26
|
+
workspaceRoot: string;
|
|
27
|
+
task: string;
|
|
28
|
+
preferredRole?: string;
|
|
29
|
+
}): AcePreflightPacket;
|
|
30
|
+
export declare function nextActivationLedger(sessionId: string, current: AceSessionActivationLedger | undefined, recommendedAction: string | undefined): AceSessionActivationLedger;
|
|
31
|
+
export declare function buildStartupNudge(preflight: AcePreflightPacket, ledger: AceSessionActivationLedger): StartupNudge | undefined;
|
|
32
|
+
export declare function buildBridgeTaskInput(conversation: string, preflight: AcePreflightPacket): string;
|
|
33
|
+
export declare function mapBridgeResultToRuntimeStatus(input: {
|
|
34
|
+
current: AceRuntimeStatusPacket;
|
|
35
|
+
summary: string;
|
|
36
|
+
toolNames: string[];
|
|
37
|
+
}): AceRuntimeStatusPacket;
|
|
38
|
+
export declare function buildContinuityRecord(input: {
|
|
39
|
+
preflight: AcePreflightPacket;
|
|
40
|
+
role: string;
|
|
41
|
+
activeTool?: string;
|
|
42
|
+
bridgeStatus: AceRuntimeStatusPacket["bridge_status"];
|
|
43
|
+
evidenceRefs?: string[];
|
|
44
|
+
}): AceSessionContinuityRecord;
|
|
45
|
+
export declare function containsVerificationLanguage(text: string): boolean;
|
|
46
|
+
export declare function hasEvidenceLikeTool(toolNames: readonly string[]): boolean;
|
|
47
|
+
export declare function applyEvidenceGuardrail(summary: string, toolNames: readonly string[]): string;
|
|
48
|
+
export declare function readRuntimeWorkflowHint(workspaceRoot: string): string | undefined;
|
|
49
|
+
export declare function readStatusHint(workspaceRoot: string): string | undefined;
|
|
50
|
+
//# sourceMappingURL=local-model-contract.d.ts.map
|