loadtoagent 1.1.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +7 -0
- package/README.md +7 -0
- package/README.zh-CN.md +7 -0
- package/docs/PROVIDER-CONTRACTS.md +23 -1
- package/docs/UI-AUDIT-100.md +118 -0
- package/docs/UI-AUDIT-101-200.md +120 -0
- package/docs/UI-AUDIT-201-300.md +120 -0
- package/main.js +135 -38
- package/package.json +13 -4
- package/preload.js +6 -0
- package/renderer/app-agent-actions.js +125 -53
- package/renderer/app-bootstrap.js +54 -19
- package/renderer/app-dashboard.js +190 -55
- package/renderer/app-drawer-content.js +48 -44
- package/renderer/app-drawer-data.js +26 -13
- package/renderer/app-drawer.js +72 -54
- package/renderer/app-events-dialogs.js +146 -37
- package/renderer/app-events-filters.js +172 -13
- package/renderer/app-events-navigation.js +77 -30
- package/renderer/app-events-sessions.js +156 -9
- package/renderer/app-events.js +2 -1
- package/renderer/app-graph-model.js +20 -38
- package/renderer/app-graph-orchestration.js +15 -13
- package/renderer/app-graph-view.js +228 -113
- package/renderer/app-management.js +211 -0
- package/renderer/app-provider-visibility.js +124 -0
- package/renderer/app-quality.js +568 -0
- package/renderer/app-run-modal.js +103 -33
- package/renderer/app-runtime-overview.js +312 -0
- package/renderer/app-session-render.js +94 -37
- package/renderer/app-tmux-render.js +52 -44
- package/renderer/app.js +153 -75
- package/renderer/i18n-messages.js +833 -16
- package/renderer/i18n.js +104 -0
- package/renderer/index.html +145 -59
- package/renderer/shared.js +17 -0
- package/renderer/styles-agent-map.css +6 -0
- package/renderer/styles-cards.css +26 -0
- package/renderer/styles-components.css +86 -9
- package/renderer/styles-management.css +355 -0
- package/renderer/styles-overlays.css +8 -2
- package/renderer/styles-product.css +24 -16
- package/renderer/styles-quality.css +312 -0
- package/renderer/styles-readability.css +862 -0
- package/renderer/styles-responsive-product.css +84 -12
- package/renderer/styles-responsive-runtime.css +22 -14
- package/renderer/styles-responsive-shell.css +44 -48
- package/renderer/styles-responsive-workflows.css +37 -3
- package/renderer/styles-run-composer.css +5 -0
- package/renderer/styles-runtime-overview.css +285 -0
- package/renderer/styles-settings.css +160 -0
- package/renderer/styles-terminal.css +339 -2
- package/renderer/styles-workflow-map.css +362 -15
- package/renderer/styles-workflows.css +69 -2
- package/renderer/styles.css +27 -12
- package/renderer/terminal-agent.js +17 -13
- package/renderer/terminal-events.js +233 -40
- package/renderer/terminal-workbench.js +165 -77
- package/renderer/terminal.js +341 -34
- package/src/agentMonitor/claudeParser.js +96 -7
- package/src/agentMonitor/codexParser.js +59 -4
- package/src/agentMonitor/executionActivity.js +282 -0
- package/src/agentMonitor/genericParser.js +56 -13
- package/src/agentMonitor/hierarchy.js +17 -0
- package/src/agentMonitor/responseIntent.js +51 -0
- package/src/agentMonitor.js +21 -3
- package/src/agentRunner.js +66 -1
- package/src/attentionNotifier.js +14 -10
- package/src/automationMonitor.js +258 -0
- package/src/contracts.js +10 -1
- package/src/ipc/registerAgentIpc.js +9 -3
- package/src/ipc/registerAppIpc.js +4 -1
- package/src/ipc/registerTerminalIpc.js +12 -6
- package/src/macUpdateHelper.js +210 -0
- package/src/monitorWorker.js +65 -6
- package/src/platformPath.js +80 -0
- package/src/processMonitor.js +80 -22
- package/src/providerVisibilityStore.js +45 -0
- package/src/sessionIntelligence.js +247 -0
- package/src/terminalHost.js +381 -0
- package/src/terminalHostDaemon.js +60 -0
- package/src/terminalManager.js +158 -3
- package/src/updateInstaller.js +175 -0
package/renderer/app.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
window.LoadToAgentAppFactories = window.LoadToAgentAppFactories || {};
|
|
3
3
|
window.LoadToAgentAppFactories.createCore = function createCore(context = {}) {
|
|
4
4
|
const { $, $$, esc, uiLocale, providerLabel, reportRecoverableError } = window.LoadToAgentRendererUtils;
|
|
5
|
+
const t = (key, params) => window.LoadToAgentI18n.t(key, params);
|
|
6
|
+
const observedText = (value) => window.LoadToAgentI18n.observedText(value);
|
|
5
7
|
const PROJECTLESS_WORKSPACE = "__projectless__";
|
|
6
8
|
const state = {
|
|
7
9
|
providers: [],
|
|
@@ -9,16 +11,18 @@ window.LoadToAgentAppFactories.createCore = function createCore(context = {}) {
|
|
|
9
11
|
availability: {},
|
|
10
12
|
workspaces: [],
|
|
11
13
|
snapshot: null,
|
|
14
|
+
rawSnapshot: null,
|
|
12
15
|
activeRuns: [],
|
|
13
16
|
versions: {},
|
|
14
17
|
update: null,
|
|
15
18
|
view: "all",
|
|
16
19
|
providerFilters: new Set(),
|
|
20
|
+
hiddenProviders: new Set(),
|
|
17
21
|
workspace: "all",
|
|
18
22
|
search: "",
|
|
19
23
|
sort: "recent",
|
|
20
24
|
selectedId: null,
|
|
21
|
-
drawerTab: "
|
|
25
|
+
drawerTab: "summary",
|
|
22
26
|
drawerMode: "session",
|
|
23
27
|
runProvider: "claude",
|
|
24
28
|
details: new Map(),
|
|
@@ -27,17 +31,22 @@ window.LoadToAgentAppFactories.createCore = function createCore(context = {}) {
|
|
|
27
31
|
visibleLimit: 30,
|
|
28
32
|
graphFocusId: null,
|
|
29
33
|
graphExpandedProviders: new Set(),
|
|
34
|
+
expandedExecutionSessions: new Set(),
|
|
30
35
|
expandedCompletedSubagents: new Set(),
|
|
31
36
|
expandedTmuxSubagents: new Set(),
|
|
37
|
+
selectedRuntimeLoopId: null,
|
|
32
38
|
tmuxFocus: null,
|
|
33
39
|
agentCommandDrafts: new Map(),
|
|
34
40
|
agentCommandTargets: new Map(),
|
|
35
41
|
agentCommandSending: new Set(),
|
|
36
42
|
stopRequests: new Set(),
|
|
43
|
+
runControlRequests: new Set(),
|
|
44
|
+
managementFilter: "all",
|
|
37
45
|
detailErrors: new Map(),
|
|
46
|
+
disclosureStates: new Map(),
|
|
38
47
|
guideCompleted: new Set(),
|
|
39
|
-
guideExpanded:
|
|
40
|
-
platform: { id: "win32", label: "Windows", localShell: "powershell", localShellLabel: "
|
|
48
|
+
guideExpanded: false,
|
|
49
|
+
platform: { id: "win32", label: "Windows", localShell: "powershell", localShellLabel: t("terminal.windows_shell"), nativeTmux: false },
|
|
41
50
|
};
|
|
42
51
|
Object.defineProperty(state, "provider", {
|
|
43
52
|
enumerable: true,
|
|
@@ -52,9 +61,24 @@ window.LoadToAgentAppFactories.createCore = function createCore(context = {}) {
|
|
|
52
61
|
});
|
|
53
62
|
const motionPreference = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
54
63
|
const motionState = {
|
|
55
|
-
ready: false, modalTimer: 0, toastTimer: 0, drawerTimer: 0, drawerContentTimer: 0,
|
|
56
|
-
drawerRenderKey: "", drawerTab: "", activeDialogTrigger: null,
|
|
64
|
+
ready: false, modalTimer: 0, modalFocusTimer: 0, toastTimer: 0, drawerTimer: 0, drawerContentTimer: 0,
|
|
65
|
+
drawerRenderKey: "", drawerTab: "", activeDialogTrigger: null, dialogGeneration: 0,
|
|
57
66
|
};
|
|
67
|
+
function disclosureElements(root = document) {
|
|
68
|
+
const elements = [];
|
|
69
|
+
if (root instanceof Element && root.matches("details[data-disclosure-key]")) elements.push(root);
|
|
70
|
+
root.querySelectorAll?.("details[data-disclosure-key]").forEach((element) => elements.push(element));
|
|
71
|
+
return elements;
|
|
72
|
+
}
|
|
73
|
+
function rememberDisclosureStates(root = document) {
|
|
74
|
+
disclosureElements(root).forEach((element) => state.disclosureStates.set(element.dataset.disclosureKey, element.open));
|
|
75
|
+
}
|
|
76
|
+
function restoreDisclosureStates(root = document) {
|
|
77
|
+
disclosureElements(root).forEach((element) => {
|
|
78
|
+
const key = element.dataset.disclosureKey;
|
|
79
|
+
if (state.disclosureStates.has(key)) element.open = state.disclosureStates.get(key);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
58
82
|
document.documentElement.dataset.motion = motionPreference.matches ? "reduced" : "full";
|
|
59
83
|
motionPreference.addEventListener("change", (event) => {
|
|
60
84
|
document.documentElement.dataset.motion = event.matches ? "reduced" : "full";
|
|
@@ -128,54 +152,43 @@ window.LoadToAgentAppFactories.createCore = function createCore(context = {}) {
|
|
|
128
152
|
requestAnimationFrame(() => section.classList.add("motion-section-in"));
|
|
129
153
|
});
|
|
130
154
|
}
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
155
|
+
const localizedLookup = (keys) => new Proxy(Object.create(null), {
|
|
156
|
+
get: (_target, property) => keys[property] ? t(keys[property]) : undefined,
|
|
157
|
+
});
|
|
158
|
+
const STATUS = localizedLookup({
|
|
159
|
+
starting: "ui.preparing", running: "ui.working", paused: "management.status.paused", waiting: "app.nav.needs_review", idle: "ui.idle",
|
|
160
|
+
completed: "ui.completed", failed: "ui.problem", cancelled: "ui.stopped",
|
|
161
|
+
});
|
|
162
|
+
const VIEW_TITLES = localizedLookup({
|
|
163
|
+
all: "ui.recent_conversations_and_tasks", active: "ui.active_tasks", waiting: "ui.tasks_needing_review",
|
|
164
|
+
runtime: "runtime.title", terminal: "app.nav.session_terminal", tmux: "app.nav.tmux", settings: "settings.title",
|
|
165
|
+
});
|
|
166
|
+
const VIEW_META_KEYS = {
|
|
167
|
+
all: ["ui.ai_work_overview", "ui.see_all_ai_work_at_a_glance", "ui.active_work_and_items_needing_your_review_appear_first_find"],
|
|
168
|
+
active: ["ui.active_now", "ui.see_which_ai_is_working_now", "ui.see_what_is_being_handled_then_open_a_task_for"],
|
|
169
|
+
waiting: ["ui.your_turn", "ui.handle_items_that_need_your_review_first", "ui.only_tasks_waiting_for_your_response_or_choice_are_shown"],
|
|
170
|
+
runtime: ["runtime.eyebrow", "runtime.title", "runtime.description"],
|
|
171
|
+
terminal: ["ui.continue_an_existing_conversation", "ui.continue_ai_sessions_in_the_terminal", "ui.continue_the_same_task_with_its_previous_conversation_beside_the"],
|
|
172
|
+
tmux: ["ui.advanced_work_tools", "ui.manage_multi_terminal_work_in_one_place", "ui.this_view_is_only_for_existing_tmux_workflows_home_and"],
|
|
173
|
+
settings: ["ui.application_management", "ui.check_versions_and_updates", "ui.compare_the_installed_and_latest_stable_versions_then_download_a"],
|
|
141
174
|
};
|
|
142
|
-
const VIEW_META = {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
subtitle:
|
|
175
|
+
const VIEW_META = new Proxy(Object.create(null), {
|
|
176
|
+
get: (_target, property) => {
|
|
177
|
+
const keys = VIEW_META_KEYS[property];
|
|
178
|
+
return keys ? { eyebrow: t(keys[0]), title: t(keys[1]), subtitle: t(keys[2]) } : undefined;
|
|
146
179
|
},
|
|
147
|
-
|
|
148
|
-
eyebrow: window.LoadToAgentI18n.t("ui.active_now"), title: window.LoadToAgentI18n.t("ui.see_which_ai_is_working_now"),
|
|
149
|
-
subtitle: window.LoadToAgentI18n.t("ui.see_what_is_being_handled_then_open_a_task_for"),
|
|
150
|
-
},
|
|
151
|
-
waiting: {
|
|
152
|
-
eyebrow: window.LoadToAgentI18n.t("ui.your_turn"), title: window.LoadToAgentI18n.t("ui.handle_items_that_need_your_review_first"),
|
|
153
|
-
subtitle: window.LoadToAgentI18n.t("ui.only_tasks_waiting_for_your_response_or_choice_are_shown"),
|
|
154
|
-
},
|
|
155
|
-
terminal: {
|
|
156
|
-
eyebrow: window.LoadToAgentI18n.t("ui.continue_an_existing_conversation"), title: window.LoadToAgentI18n.t("ui.continue_ai_sessions_in_the_terminal"),
|
|
157
|
-
subtitle: window.LoadToAgentI18n.t("ui.continue_the_same_task_with_its_previous_conversation_beside_the"),
|
|
158
|
-
},
|
|
159
|
-
tmux: {
|
|
160
|
-
eyebrow: window.LoadToAgentI18n.t("ui.advanced_work_tools"), title: window.LoadToAgentI18n.t("ui.manage_multi_terminal_work_in_one_place"),
|
|
161
|
-
subtitle: window.LoadToAgentI18n.t("ui.this_view_is_only_for_existing_tmux_workflows_home_and"),
|
|
162
|
-
},
|
|
163
|
-
settings: {
|
|
164
|
-
eyebrow: window.LoadToAgentI18n.t("ui.application_management"), title: window.LoadToAgentI18n.t("ui.check_versions_and_updates"),
|
|
165
|
-
subtitle: window.LoadToAgentI18n.t("ui.compare_the_installed_and_latest_stable_versions_then_download_a"),
|
|
166
|
-
},
|
|
167
|
-
};
|
|
180
|
+
});
|
|
168
181
|
const GUIDE_STORAGE_KEY = "loadtoagent:start-guide:v1";
|
|
169
182
|
const GUIDE_STEPS = ["create", "active", "waiting", "detail"];
|
|
170
183
|
function loadGuideState() {
|
|
171
184
|
try {
|
|
172
185
|
const saved = JSON.parse(localStorage.getItem(GUIDE_STORAGE_KEY) || "{}");
|
|
173
186
|
state.guideCompleted = new Set((saved.completed || []).filter((step) => GUIDE_STEPS.includes(step)));
|
|
174
|
-
state.guideExpanded = saved.expanded
|
|
187
|
+
state.guideExpanded = saved.expanded === true;
|
|
175
188
|
} catch (error) {
|
|
176
189
|
reportRecoverableError("guide-state-load", error);
|
|
177
190
|
state.guideCompleted = new Set();
|
|
178
|
-
state.guideExpanded =
|
|
191
|
+
state.guideExpanded = false;
|
|
179
192
|
}
|
|
180
193
|
}
|
|
181
194
|
function saveGuideState() {
|
|
@@ -226,22 +239,39 @@ window.LoadToAgentAppFactories.createCore = function createCore(context = {}) {
|
|
|
226
239
|
else item.removeAttribute("aria-current");
|
|
227
240
|
});
|
|
228
241
|
const advancedView = ["terminal", "tmux", "settings"].includes(state.view);
|
|
242
|
+
const advancedToolsView = ["runtime", "terminal", "tmux"].includes(state.view);
|
|
243
|
+
if (advancedToolsView) $("#advancedToolsNav")?.setAttribute("open", "");
|
|
244
|
+
$("#advancedToolsNav")?.classList.toggle("active", advancedToolsView);
|
|
229
245
|
$("#mobileMoreBtn")?.classList.toggle("active", advancedView);
|
|
230
246
|
if (advancedView) $("#mobileMoreBtn")?.setAttribute("aria-current", "page");
|
|
231
247
|
else $("#mobileMoreBtn")?.removeAttribute("aria-current");
|
|
232
248
|
}
|
|
233
249
|
function selectView(view, options = {}) {
|
|
234
250
|
state.view = view;
|
|
251
|
+
state.managementFilter = view === "waiting" ? (options.managementFilter || "all") : "all";
|
|
235
252
|
state.visibleLimit = 30;
|
|
236
253
|
if (view === "active" || view === "waiting") markGuideStep(view);
|
|
237
254
|
syncViewChrome();
|
|
238
255
|
context.renderSessions(options.motionKind || "view");
|
|
239
|
-
$("#mobileToolsMenu")
|
|
256
|
+
const mobileToolsMenu = $("#mobileToolsMenu");
|
|
257
|
+
if (mobileToolsMenu && !mobileToolsMenu.classList.contains("hidden")) {
|
|
258
|
+
setDialogOpenState(mobileToolsMenu, false);
|
|
259
|
+
mobileToolsMenu.classList.add("hidden");
|
|
260
|
+
}
|
|
240
261
|
$("#mobileMoreBtn")?.setAttribute("aria-expanded", "false");
|
|
241
262
|
document.querySelector(".main-stage")?.scrollTo({ top: 0, behavior: "auto" });
|
|
242
263
|
if (options.focusMain) $("#mainContent")?.focus({ preventScroll: true });
|
|
264
|
+
const resultCount = ["all", "active", "waiting"].includes(view) && typeof context.filteredSessions === "function"
|
|
265
|
+
? context.filteredSessions().length
|
|
266
|
+
: null;
|
|
267
|
+
announce(resultCount == null
|
|
268
|
+
? t("navigation.view_changed", { view: VIEW_TITLES[view] || view })
|
|
269
|
+
: t("navigation.view_results", { view: VIEW_TITLES[view] || view, count: resultCount }));
|
|
243
270
|
}
|
|
244
271
|
function currentDialog() {
|
|
272
|
+
if (!$("#mobileToolsMenu")?.classList.contains("hidden")) return $("#mobileToolsMenu");
|
|
273
|
+
if (!$("#quickPaletteModal")?.classList.contains("hidden")) return $("#quickPaletteModal");
|
|
274
|
+
if (!$("#shortcutHelpModal")?.classList.contains("hidden")) return $("#shortcutHelpModal");
|
|
245
275
|
if (!$("#runModal").classList.contains("hidden")) return $("#runModal");
|
|
246
276
|
if (!$("#tmuxCreateModal").classList.contains("hidden")) return $("#tmuxCreateModal");
|
|
247
277
|
if ($("#detailDrawer").classList.contains("open")) return $("#detailDrawer");
|
|
@@ -273,14 +303,44 @@ window.LoadToAgentAppFactories.createCore = function createCore(context = {}) {
|
|
|
273
303
|
}
|
|
274
304
|
}
|
|
275
305
|
function rememberDialogTrigger() {
|
|
306
|
+
motionState.dialogGeneration += 1;
|
|
276
307
|
motionState.activeDialogTrigger = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
277
308
|
}
|
|
278
|
-
function restoreDialogTrigger() {
|
|
309
|
+
function restoreDialogTrigger(expectedGeneration = null) {
|
|
310
|
+
if (expectedGeneration != null && expectedGeneration !== motionState.dialogGeneration) return false;
|
|
279
311
|
const trigger = motionState.activeDialogTrigger;
|
|
280
312
|
motionState.activeDialogTrigger = null;
|
|
281
313
|
if (trigger && trigger.isConnected) trigger.focus({ preventScroll: true });
|
|
314
|
+
return true;
|
|
315
|
+
}
|
|
316
|
+
function setDialogOpenState(dialog, open) {
|
|
317
|
+
if (!dialog) return;
|
|
318
|
+
const shell = $("#appShell");
|
|
319
|
+
if (open) {
|
|
320
|
+
dialog.removeAttribute("inert");
|
|
321
|
+
dialog.setAttribute("aria-hidden", "false");
|
|
322
|
+
shell?.setAttribute("inert", "");
|
|
323
|
+
document.body.classList.add("dialog-open");
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
dialog.setAttribute("inert", "");
|
|
327
|
+
dialog.setAttribute("aria-hidden", "true");
|
|
328
|
+
const anotherDialog = [$("#mobileToolsMenu"), $("#runModal"), $("#tmuxCreateModal"), $("#detailDrawer"), $("#quickPaletteModal"), $("#shortcutHelpModal")]
|
|
329
|
+
.some((item) => item && item !== dialog && !item.classList.contains("hidden") && (item.classList.contains("open") || item.matches(".modal-backdrop") || item.id === "mobileToolsMenu"));
|
|
330
|
+
if (!anotherDialog) {
|
|
331
|
+
shell?.removeAttribute("inert");
|
|
332
|
+
document.body.classList.remove("dialog-open");
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
function announce(message) {
|
|
336
|
+
const region = $("#globalStatus");
|
|
337
|
+
if (!region) return;
|
|
338
|
+
region.textContent = "";
|
|
339
|
+
requestAnimationFrame(() => {
|
|
340
|
+
region.textContent = String(message || "");
|
|
341
|
+
});
|
|
282
342
|
}
|
|
283
|
-
window.LoadToAgentA11y = { rememberDialogTrigger, restoreDialogTrigger };
|
|
343
|
+
window.LoadToAgentA11y = { rememberDialogTrigger, restoreDialogTrigger, setDialogOpenState, announce };
|
|
284
344
|
function readablePreview(value, maxCharacters = 120) {
|
|
285
345
|
const full = String(value == null ? "" : value)
|
|
286
346
|
.replace(/\s+/g, " ")
|
|
@@ -292,19 +352,22 @@ window.LoadToAgentAppFactories.createCore = function createCore(context = {}) {
|
|
|
292
352
|
return { full, text: `${sample.slice(0, cut).trimEnd()}…`, truncated: true };
|
|
293
353
|
}
|
|
294
354
|
function memoryCategoryLabel(value) {
|
|
295
|
-
const
|
|
296
|
-
|
|
355
|
+
const keys = {
|
|
356
|
+
insight: "content.memory.insight", convention: "content.memory.convention", failure: "content.memory.failure",
|
|
357
|
+
decision: "content.memory.decision", pattern: "content.memory.pattern",
|
|
358
|
+
};
|
|
359
|
+
return keys[String(value || "").toLowerCase()] ? t(keys[String(value || "").toLowerCase()]) : String(value || t("content.memory.record"));
|
|
297
360
|
}
|
|
298
361
|
function jsonValueHtml(value, depth = 0) {
|
|
299
|
-
if (value == null) return
|
|
300
|
-
if (typeof value === "boolean") return `<span class="json-primitive">${value ? "
|
|
362
|
+
if (value == null) return `<span class="json-empty">${esc(t("content.none"))}</span>`;
|
|
363
|
+
if (typeof value === "boolean") return `<span class="json-primitive">${esc(t(value ? "content.yes" : "content.no"))}</span>`;
|
|
301
364
|
if (typeof value === "number") return `<span class="json-primitive">${esc(value.toLocaleString(uiLocale()))}</span>`;
|
|
302
365
|
if (typeof value === "string") return `<span class="json-string">${esc(value)}</span>`;
|
|
303
366
|
if (depth >= 4) return `<span class="json-string">${esc(JSON.stringify(value))}</span>`;
|
|
304
367
|
if (Array.isArray(value)) {
|
|
305
368
|
const shown = value.slice(0, 40);
|
|
306
369
|
const visibleItems = shown.map((item) => `<li>${jsonValueHtml(item, depth + 1)}</li>`).join("");
|
|
307
|
-
const moreItems = value.length > shown.length ? `<li class="json-more"
|
|
370
|
+
const moreItems = value.length > shown.length ? `<li class="json-more">${esc(t("content.more_items", { count: value.length - shown.length }))}</li>` : "";
|
|
308
371
|
return `<ol class="json-array">${visibleItems}${moreItems}</ol>`;
|
|
309
372
|
}
|
|
310
373
|
const entries = Object.entries(value).slice(0, 40);
|
|
@@ -313,8 +376,8 @@ window.LoadToAgentAppFactories.createCore = function createCore(context = {}) {
|
|
|
313
376
|
function memoryCandidatesHtml(items) {
|
|
314
377
|
return `<div class="memory-candidates">
|
|
315
378
|
<div class="structured-heading">
|
|
316
|
-
<b
|
|
317
|
-
<span>${items.length}
|
|
379
|
+
<b>${esc(t("content.memory.to_save"))}</b>
|
|
380
|
+
<span>${esc(t("common.items", { count: items.length }))}</span>
|
|
318
381
|
</div>${items
|
|
319
382
|
.map(
|
|
320
383
|
(item, index) => `<article class="memory-candidate">
|
|
@@ -323,7 +386,7 @@ window.LoadToAgentAppFactories.createCore = function createCore(context = {}) {
|
|
|
323
386
|
<span class="memory-target">${esc(item.target || "MEMORY")}</span>
|
|
324
387
|
<span class="memory-category">${esc(memoryCategoryLabel(item.category))}</span>
|
|
325
388
|
</header>
|
|
326
|
-
<p>${esc(item.content || "
|
|
389
|
+
<p>${esc(item.content || t("content.empty"))}</p>
|
|
327
390
|
</article>`,
|
|
328
391
|
)
|
|
329
392
|
.join("")}</div>`;
|
|
@@ -385,7 +448,7 @@ window.LoadToAgentAppFactories.createCore = function createCore(context = {}) {
|
|
|
385
448
|
if (fence) output.push(`<pre><code>${esc(code.join("\n"))}</code></pre>`);
|
|
386
449
|
return `<div class="chat-content markdown">${output.join("")}</div>`;
|
|
387
450
|
}
|
|
388
|
-
function roadmapHtml(value) {
|
|
451
|
+
function roadmapHtml(value, disclosureId = "") {
|
|
389
452
|
const text = String(value || "").trim();
|
|
390
453
|
const lines = text
|
|
391
454
|
.replace(/\r\n/g, "\n")
|
|
@@ -396,17 +459,18 @@ window.LoadToAgentAppFactories.createCore = function createCore(context = {}) {
|
|
|
396
459
|
const steps = lines.filter((line) => /^(?:[-*]\s+|\d+[.)]\s+|#{2,3}\s+(?!로드맵|roadmap))/i.test(line));
|
|
397
460
|
if (!hasRoadmapSignal || (text.length < 420 && steps.length < 6)) return "";
|
|
398
461
|
const heading = lines.find((line) => /^#{1,3}\s+/.test(line));
|
|
399
|
-
const title = readablePreview((heading || "
|
|
462
|
+
const title = readablePreview((heading || t("content.roadmap.title")).replace(/^#{1,3}\s+/, ""), 72).text;
|
|
400
463
|
const previewSteps = (steps.length ? steps : lines.filter((line) => !/^#{1,3}\s+/.test(line)))
|
|
401
464
|
.slice(0, 3)
|
|
402
465
|
.map((line) => readablePreview(line.replace(/^(?:[-*]\s+|\d+[.)]\s+|#{2,3}\s+)/, "").replace(/\*\*/g, ""), 92).text);
|
|
403
|
-
const countLabel = steps.length ?
|
|
404
|
-
|
|
466
|
+
const countLabel = steps.length ? t("content.roadmap.steps", { count: steps.length }) : t("content.roadmap.long_plan");
|
|
467
|
+
const disclosureKey = `roadmap:${disclosureId || `${text.length}:${title}`}`;
|
|
468
|
+
return `<details class="chat-roadmap" data-roadmap-collapsed="true" data-disclosure-key="${esc(disclosureKey)}">
|
|
405
469
|
<summary>
|
|
406
470
|
<span class="chat-roadmap-mark" aria-hidden="true">MAP</span>
|
|
407
471
|
<span>
|
|
408
472
|
<b>${esc(title)}</b>
|
|
409
|
-
<small>${esc(countLabel)}
|
|
473
|
+
<small>${esc(t("content.roadmap.collapsed", { count: countLabel }))}</small>
|
|
410
474
|
</span>
|
|
411
475
|
<i aria-hidden="true">↓</i>
|
|
412
476
|
</summary>
|
|
@@ -414,9 +478,9 @@ window.LoadToAgentAppFactories.createCore = function createCore(context = {}) {
|
|
|
414
478
|
<div class="chat-roadmap-full">${markdownHtml(text)}</div>
|
|
415
479
|
</details>`;
|
|
416
480
|
}
|
|
417
|
-
function messageContentHtml(message) {
|
|
481
|
+
function messageContentHtml(message, ownerId = "") {
|
|
418
482
|
const text = String((message && message.text) || "").trim();
|
|
419
|
-
if (!text) return
|
|
483
|
+
if (!text) return `<div class="chat-content empty">${esc(t("content.no_displayable_content"))}</div>`;
|
|
420
484
|
if (/^[\[{]/.test(text) && /[\]}]$/.test(text)) {
|
|
421
485
|
try {
|
|
422
486
|
const parsed = JSON.parse(text);
|
|
@@ -427,14 +491,15 @@ window.LoadToAgentAppFactories.createCore = function createCore(context = {}) {
|
|
|
427
491
|
}
|
|
428
492
|
return `<div class="structured-json">
|
|
429
493
|
<div class="structured-heading">
|
|
430
|
-
<b
|
|
431
|
-
<span>${Array.isArray(parsed) ?
|
|
494
|
+
<b>${esc(t("content.structured_data"))}</b>
|
|
495
|
+
<span>${Array.isArray(parsed) ? esc(t("common.items", { count: parsed.length })) : "JSON"}</span>
|
|
432
496
|
</div>${jsonValueHtml(parsed)}</div>`;
|
|
433
497
|
} catch (_plainChatMessage) {
|
|
434
498
|
// A normal chat message may begin with JSON punctuation without being JSON.
|
|
435
499
|
}
|
|
436
500
|
}
|
|
437
|
-
const
|
|
501
|
+
const messageId = message && (message.id || message.timestamp) || text.length;
|
|
502
|
+
const roadmap = message && message.role === "assistant" ? roadmapHtml(text, `${ownerId}:${messageId}`) : "";
|
|
438
503
|
if (roadmap) return roadmap;
|
|
439
504
|
return markdownHtml(text);
|
|
440
505
|
}
|
|
@@ -480,7 +545,7 @@ window.LoadToAgentAppFactories.createCore = function createCore(context = {}) {
|
|
|
480
545
|
return labels[String(value || "").toLowerCase()] || String(value || window.LoadToAgentI18n.t("ui.assistance"));
|
|
481
546
|
}
|
|
482
547
|
function statusClass(status) {
|
|
483
|
-
return ["running", "waiting", "completed", "failed", "cancelled"].includes(status) ? status : "";
|
|
548
|
+
return ["running", "paused", "waiting", "completed", "failed", "cancelled"].includes(status) ? status : "";
|
|
484
549
|
}
|
|
485
550
|
function currentActivity(session) {
|
|
486
551
|
const items = session.lifecycle || [];
|
|
@@ -488,15 +553,22 @@ window.LoadToAgentAppFactories.createCore = function createCore(context = {}) {
|
|
|
488
553
|
const last = running || items[items.length - 1];
|
|
489
554
|
if (last) {
|
|
490
555
|
return {
|
|
491
|
-
title: last.label ||
|
|
556
|
+
title: observedText(last.label || t("ui.activity")), detail: observedText(last.detail || session.statusDetail || ""), type: last.type || "activity",
|
|
492
557
|
};
|
|
493
558
|
}
|
|
494
559
|
const message = (session.messages || [])[session.messages.length - 1];
|
|
495
|
-
return { title: session.statusDetail ||
|
|
560
|
+
return { title: observedText(session.statusDetail || t("ui.temporarily_idle")), detail: observedText((message && message.text) || ""), type: "activity" };
|
|
496
561
|
}
|
|
497
562
|
function isLiveSession(session) {
|
|
498
563
|
return session && (session.status === "running" || session.status === "starting");
|
|
499
564
|
}
|
|
565
|
+
function isRuntimeLoopSession(session) {
|
|
566
|
+
if (!session || session.parentId || !isLiveSession(session)) return false;
|
|
567
|
+
if (session.loop === true || (session.loop && typeof session.loop === "object")) return true;
|
|
568
|
+
const ids = new Set([String(session.id || ""), String(session.externalId || "")].filter(Boolean));
|
|
569
|
+
return (state.snapshot?.automations || []).some((automation) =>
|
|
570
|
+
automation.enabled && automation.targetThreadId && ids.has(String(automation.targetThreadId)));
|
|
571
|
+
}
|
|
500
572
|
function subagentWorkState(session) {
|
|
501
573
|
if (isLiveSession(session)) return "working";
|
|
502
574
|
if (session && session.status === "failed") return "attention";
|
|
@@ -515,13 +587,13 @@ window.LoadToAgentAppFactories.createCore = function createCore(context = {}) {
|
|
|
515
587
|
try {
|
|
516
588
|
const parsed = JSON.parse(text);
|
|
517
589
|
if (!parsed || Array.isArray(parsed) || typeof parsed !== "object") return text;
|
|
518
|
-
if (parsed.cell_id) return
|
|
519
|
-
if (parsed.command) return
|
|
520
|
-
if (parsed.path || parsed.file_path) return
|
|
521
|
-
if (parsed.prompt) return
|
|
590
|
+
if (parsed.cell_id) return t("activity.waiting_for_result", { wait: parsed.yield_time_ms ? t("activity.max_seconds", { count: Math.round(Number(parsed.yield_time_ms) / 1000) }) : "" });
|
|
591
|
+
if (parsed.command) return t("activity.command", { value: String(parsed.command).replace(/\s+/g, " ").slice(0, 180) });
|
|
592
|
+
if (parsed.path || parsed.file_path) return t("activity.file", { value: parsed.path || parsed.file_path });
|
|
593
|
+
if (parsed.prompt) return t("activity.delegated", { value: String(parsed.prompt).replace(/\s+/g, " ").slice(0, 180) });
|
|
522
594
|
const summary = Object.entries(parsed)
|
|
523
595
|
.slice(0, 3)
|
|
524
|
-
.map(([key, item]) => `${key}: ${typeof item === "object" ? "
|
|
596
|
+
.map(([key, item]) => `${key}: ${typeof item === "object" ? t("activity.structured_data") : item}`)
|
|
525
597
|
.join(" · ");
|
|
526
598
|
return summary || text;
|
|
527
599
|
} catch (_malformedCommandPreview) {
|
|
@@ -532,16 +604,16 @@ window.LoadToAgentAppFactories.createCore = function createCore(context = {}) {
|
|
|
532
604
|
function latestWorkCopy(session) {
|
|
533
605
|
const delegation = session.delegation || {};
|
|
534
606
|
const completedResult = delegation.result || session.result;
|
|
535
|
-
if (session.status === "completed" && completedResult) return
|
|
536
|
-
if (session.status === "completed") return "
|
|
607
|
+
if (session.status === "completed" && completedResult) return t("activity.completed_result", { value: completedResult });
|
|
608
|
+
if (session.status === "completed") return t("activity.completed_returned");
|
|
537
609
|
const activity = currentActivity(session);
|
|
538
610
|
if (activity.detail) return readableActivityDetail(activity.detail);
|
|
539
611
|
const messages = session.messages || [];
|
|
540
612
|
const assistant = [...messages].reverse().find((item) => item.role === "assistant" && item.text);
|
|
541
613
|
if (assistant) return assistant.text;
|
|
542
614
|
const tool = [...messages].reverse().find((item) => item.role === "tool");
|
|
543
|
-
if (tool) return
|
|
544
|
-
return activity.title || session.statusDetail || "
|
|
615
|
+
if (tool) return t("activity.tool_execution", { tool: tool.title || t("session.tool"), value: tool.text || t("activity.waiting_for_result_short") });
|
|
616
|
+
return activity.title || session.statusDetail || t("activity.waiting_for_next");
|
|
545
617
|
}
|
|
546
618
|
function statusIcon(type) {
|
|
547
619
|
if (/tool/.test(type)) return "⌘";
|
|
@@ -558,10 +630,13 @@ window.LoadToAgentAppFactories.createCore = function createCore(context = {}) {
|
|
|
558
630
|
uiLocale,
|
|
559
631
|
providerLabel,
|
|
560
632
|
reportRecoverableError,
|
|
633
|
+
observedText,
|
|
561
634
|
PROJECTLESS_WORKSPACE,
|
|
562
635
|
state,
|
|
563
636
|
motionPreference,
|
|
564
637
|
motionState,
|
|
638
|
+
rememberDisclosureStates,
|
|
639
|
+
restoreDisclosureStates,
|
|
565
640
|
STATUS,
|
|
566
641
|
VIEW_TITLES,
|
|
567
642
|
VIEW_META,
|
|
@@ -582,6 +657,8 @@ window.LoadToAgentAppFactories.createCore = function createCore(context = {}) {
|
|
|
582
657
|
trapDialogFocus,
|
|
583
658
|
rememberDialogTrigger,
|
|
584
659
|
restoreDialogTrigger,
|
|
660
|
+
setDialogOpenState,
|
|
661
|
+
announce,
|
|
585
662
|
readablePreview,
|
|
586
663
|
memoryCategoryLabel,
|
|
587
664
|
jsonValueHtml,
|
|
@@ -600,6 +677,7 @@ window.LoadToAgentAppFactories.createCore = function createCore(context = {}) {
|
|
|
600
677
|
statusClass,
|
|
601
678
|
currentActivity,
|
|
602
679
|
isLiveSession,
|
|
680
|
+
isRuntimeLoopSession,
|
|
603
681
|
subagentWorkState,
|
|
604
682
|
subagentWorkLabel,
|
|
605
683
|
readableActivityDetail,
|