@ouro.bot/cli 0.1.0-alpha.33 → 0.1.0-alpha.331
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 +188 -187
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +3 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +1 -1
- package/changelog.json +1982 -0
- package/dist/arc/attention-types.js +8 -0
- package/dist/arc/cares.js +140 -0
- package/dist/arc/episodes.js +117 -0
- package/dist/arc/intentions.js +133 -0
- package/dist/arc/json-store.js +117 -0
- package/dist/arc/obligations.js +237 -0
- package/dist/arc/packets.js +193 -0
- package/dist/arc/presence.js +185 -0
- package/dist/arc/task-lifecycle.js +65 -0
- package/dist/heart/active-work.js +832 -0
- package/dist/heart/agent-entry.js +37 -2
- package/dist/heart/attachments/image-normalize.js +194 -0
- package/dist/heart/attachments/materialize.js +97 -0
- package/dist/heart/attachments/originals.js +88 -0
- package/dist/heart/attachments/render.js +29 -0
- package/dist/heart/attachments/sources/adapter.js +2 -0
- package/dist/heart/attachments/sources/bluebubbles.js +156 -0
- package/dist/heart/attachments/sources/cli-local-file.js +78 -0
- package/dist/heart/attachments/sources/index.js +16 -0
- package/dist/heart/attachments/store.js +103 -0
- package/dist/heart/attachments/types.js +93 -0
- package/dist/heart/auth/auth-flow.js +463 -0
- package/dist/heart/bridges/manager.js +358 -0
- package/dist/heart/bridges/state-machine.js +135 -0
- package/dist/heart/bridges/store.js +123 -0
- package/dist/heart/bundle-state.js +168 -0
- package/dist/heart/commitments.js +111 -0
- package/dist/heart/config-registry.js +304 -0
- package/dist/heart/config.js +53 -21
- package/dist/heart/core.js +695 -195
- package/dist/heart/cross-chat-delivery.js +131 -0
- package/dist/heart/daemon/agent-config-check.js +149 -0
- package/dist/heart/daemon/agent-discovery.js +79 -3
- package/dist/heart/daemon/agent-service.js +360 -0
- package/dist/heart/daemon/agentic-repair.js +170 -0
- package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
- package/dist/heart/daemon/cadence.js +70 -0
- package/dist/heart/daemon/cli-defaults.js +591 -0
- package/dist/heart/daemon/cli-exec.js +2277 -0
- package/dist/heart/daemon/cli-help.js +306 -0
- package/dist/heart/daemon/cli-parse.js +824 -0
- package/dist/heart/daemon/cli-render-doctor.js +57 -0
- package/dist/heart/daemon/cli-render.js +512 -0
- package/dist/heart/daemon/cli-types.js +8 -0
- package/dist/heart/daemon/daemon-cli.js +29 -1171
- package/dist/heart/daemon/daemon-entry.js +358 -3
- package/dist/heart/daemon/daemon-health.js +141 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +157 -12
- package/dist/heart/daemon/daemon-tombstone.js +236 -0
- package/dist/heart/daemon/daemon.js +751 -58
- package/dist/heart/daemon/doctor-types.js +8 -0
- package/dist/heart/daemon/doctor.js +401 -0
- package/dist/heart/daemon/health-monitor.js +79 -1
- package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
- package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
- package/dist/heart/daemon/http-health-probe.js +80 -0
- package/dist/heart/daemon/inner-status.js +89 -0
- package/dist/heart/daemon/interactive-repair.js +69 -0
- package/dist/heart/daemon/launchd.js +46 -9
- package/dist/heart/daemon/log-tailer.js +82 -12
- package/dist/heart/daemon/logs-prune.js +105 -0
- package/dist/heart/daemon/message-router.js +17 -8
- package/dist/heart/daemon/os-cron-deps.js +134 -0
- package/dist/heart/daemon/ouro-bot-entry.js +1 -1
- package/dist/heart/daemon/process-manager.js +201 -0
- package/dist/heart/daemon/provider-discovery.js +105 -0
- package/dist/heart/daemon/pulse.js +463 -0
- package/dist/heart/daemon/run-hooks.js +2 -0
- package/dist/heart/daemon/runtime-logging.js +67 -16
- package/dist/heart/daemon/runtime-metadata.js +101 -0
- package/dist/heart/daemon/runtime-mode.js +67 -0
- package/dist/heart/daemon/safe-mode.js +161 -0
- package/dist/heart/daemon/sense-manager.js +72 -3
- package/dist/heart/daemon/session-id-resolver.js +131 -0
- package/dist/heart/daemon/skill-management-installer.js +94 -0
- package/dist/heart/daemon/socket-client.js +307 -0
- package/dist/heart/daemon/stale-bundle-prune.js +96 -0
- package/dist/heart/daemon/startup-tui.js +237 -0
- package/dist/heart/daemon/task-scheduler.js +3 -25
- package/dist/heart/daemon/thoughts.js +510 -0
- package/dist/heart/daemon/up-progress.js +135 -0
- package/dist/heart/delegation.js +62 -0
- package/dist/heart/habits/habit-migration.js +181 -0
- package/dist/heart/habits/habit-parser.js +140 -0
- package/dist/heart/habits/habit-scheduler.js +371 -0
- package/dist/heart/{daemon → hatch}/hatch-flow.js +32 -120
- package/dist/heart/{daemon → hatch}/hatch-specialist.js +3 -3
- package/dist/heart/{daemon → hatch}/specialist-prompt.js +10 -7
- package/dist/heart/{daemon → hatch}/specialist-tools.js +49 -3
- package/dist/heart/identity.js +154 -59
- package/dist/heart/kicks.js +2 -20
- package/dist/heart/mcp/mcp-server.js +653 -0
- package/dist/heart/migrate-config.js +127 -0
- package/dist/heart/model-capabilities.js +59 -0
- package/dist/heart/outlook/outlook-http-hooks.js +64 -0
- package/dist/heart/outlook/outlook-http-response.js +7 -0
- package/dist/heart/outlook/outlook-http-routes.js +232 -0
- package/dist/heart/outlook/outlook-http-static.js +99 -0
- package/dist/heart/outlook/outlook-http-transport.js +116 -0
- package/dist/heart/outlook/outlook-http.js +99 -0
- package/dist/heart/outlook/outlook-read.js +28 -0
- package/dist/heart/outlook/outlook-render.js +1032 -0
- package/dist/heart/outlook/outlook-types.js +27 -0
- package/dist/heart/outlook/outlook-view.js +194 -0
- package/dist/heart/outlook/readers/agent-machine.js +355 -0
- package/dist/heart/outlook/readers/continuity-readers.js +332 -0
- package/dist/heart/outlook/readers/runtime-readers.js +660 -0
- package/dist/heart/outlook/readers/sessions.js +231 -0
- package/dist/heart/outlook/readers/shared.js +111 -0
- package/dist/heart/progress-story.js +42 -0
- package/dist/heart/provider-failover.js +135 -0
- package/dist/heart/provider-models.js +81 -0
- package/dist/heart/provider-ping.js +162 -0
- package/dist/heart/providers/anthropic-token.js +163 -0
- package/dist/heart/providers/anthropic.js +169 -46
- package/dist/heart/providers/azure.js +98 -11
- package/dist/heart/providers/error-classification.js +63 -0
- package/dist/heart/providers/github-copilot.js +136 -0
- package/dist/heart/providers/minimax-vlm.js +189 -0
- package/dist/heart/providers/minimax.js +23 -5
- package/dist/heart/providers/openai-codex.js +33 -22
- package/dist/heart/session-activity.js +190 -0
- package/dist/heart/session-events.js +726 -0
- package/dist/heart/session-recall.js +162 -0
- package/dist/heart/start-of-turn-packet.js +341 -0
- package/dist/heart/streaming.js +36 -27
- package/dist/heart/sync.js +332 -0
- package/dist/heart/target-resolution.js +127 -0
- package/dist/heart/tempo.js +93 -0
- package/dist/heart/temporal-view.js +41 -0
- package/dist/heart/tool-activity-callbacks.js +36 -0
- package/dist/heart/tool-description.js +135 -0
- package/dist/heart/tool-friction.js +55 -0
- package/dist/heart/tool-loop.js +200 -0
- package/dist/heart/turn-context.js +358 -0
- package/dist/heart/turn-coordinator.js +28 -0
- package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +1 -1
- package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
- package/dist/heart/{daemon → versioning}/ouro-path-installer.js +78 -35
- package/dist/heart/versioning/ouro-version-manager.js +295 -0
- package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
- package/dist/heart/{daemon → versioning}/update-checker.js +12 -2
- package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
- package/dist/mind/associative-recall.js +137 -66
- package/dist/mind/bundle-manifest.js +7 -1
- package/dist/mind/context.js +89 -93
- package/dist/mind/diary-integrity.js +60 -0
- package/dist/mind/{memory.js → diary.js} +84 -96
- package/dist/mind/embedding-provider.js +60 -0
- package/dist/mind/file-state.js +179 -0
- package/dist/mind/first-impressions.js +14 -1
- package/dist/mind/friends/channel.js +56 -0
- package/dist/mind/friends/group-context.js +144 -0
- package/dist/mind/friends/resolver.js +37 -0
- package/dist/mind/friends/store-file.js +58 -3
- package/dist/mind/friends/trust-explanation.js +74 -0
- package/dist/mind/friends/types.js +8 -0
- package/dist/mind/journal-index.js +161 -0
- package/dist/mind/obligation-steering.js +221 -0
- package/dist/mind/pending.js +74 -7
- package/dist/mind/prompt.js +949 -111
- package/dist/mind/provenance-trust.js +26 -0
- package/dist/mind/scrutiny.js +173 -0
- package/dist/mind/token-estimate.js +8 -12
- package/dist/nerves/cli-logging.js +7 -1
- package/dist/nerves/coverage/audit.js +1 -1
- package/dist/nerves/coverage/file-completeness.js +83 -5
- package/dist/nerves/coverage/run-artifacts.js +1 -1
- package/dist/nerves/event-buffer.js +111 -0
- package/dist/nerves/index.js +224 -4
- package/dist/nerves/observation.js +20 -0
- package/dist/nerves/redact.js +79 -0
- package/dist/nerves/runtime.js +5 -1
- package/dist/outlook-ui/assets/index-IuR4F6y6.js +61 -0
- package/dist/outlook-ui/assets/index-LwChZTgL.css +1 -0
- package/dist/outlook-ui/index.html +15 -0
- package/dist/repertoire/ado-client.js +15 -56
- package/dist/repertoire/ado-semantic.js +11 -10
- package/dist/repertoire/api-client.js +97 -0
- package/dist/repertoire/bitwarden-store.js +319 -0
- package/dist/repertoire/bundle-templates.js +72 -0
- package/dist/repertoire/bw-installer.js +79 -0
- package/dist/repertoire/coding/codex-jsonl.js +64 -0
- package/dist/repertoire/coding/context-pack.js +330 -0
- package/dist/repertoire/coding/feedback.js +197 -30
- package/dist/repertoire/coding/manager.js +158 -9
- package/dist/repertoire/coding/spawner.js +55 -9
- package/dist/repertoire/coding/tools.js +170 -7
- package/dist/repertoire/commerce-errors.js +109 -0
- package/dist/repertoire/commerce-self-test.js +156 -0
- package/dist/repertoire/credential-access.js +527 -0
- package/dist/repertoire/duffel-client.js +185 -0
- package/dist/repertoire/github-client.js +14 -55
- package/dist/repertoire/graph-client.js +11 -52
- package/dist/repertoire/guardrails.js +375 -0
- package/dist/repertoire/mcp-client.js +255 -0
- package/dist/repertoire/mcp-manager.js +305 -0
- package/dist/repertoire/mcp-tools.js +63 -0
- package/dist/repertoire/shell-sessions.js +133 -0
- package/dist/repertoire/skills.js +14 -23
- package/dist/repertoire/stripe-client.js +131 -0
- package/dist/repertoire/tasks/board.js +43 -5
- package/dist/repertoire/tasks/fix.js +182 -0
- package/dist/repertoire/tasks/index.js +28 -10
- package/dist/repertoire/tasks/lifecycle.js +2 -2
- package/dist/repertoire/tasks/parser.js +3 -2
- package/dist/repertoire/tasks/scanner.js +194 -37
- package/dist/repertoire/tasks/transitions.js +16 -79
- package/dist/repertoire/tool-results.js +29 -0
- package/dist/repertoire/tools-attachments.js +316 -0
- package/dist/repertoire/tools-base.js +45 -771
- package/dist/repertoire/tools-bluebubbles.js +1 -0
- package/dist/repertoire/tools-bridge.js +141 -0
- package/dist/repertoire/tools-bundle.js +984 -0
- package/dist/repertoire/tools-config.js +185 -0
- package/dist/repertoire/tools-continuity.js +248 -0
- package/dist/repertoire/tools-credential.js +182 -0
- package/dist/repertoire/tools-files.js +342 -0
- package/dist/repertoire/tools-flight.js +224 -0
- package/dist/repertoire/tools-flow.js +105 -0
- package/dist/repertoire/tools-github.js +1 -7
- package/dist/repertoire/tools-memory.js +376 -0
- package/dist/repertoire/tools-session.js +739 -0
- package/dist/repertoire/tools-shell.js +120 -0
- package/dist/repertoire/tools-stripe.js +180 -0
- package/dist/repertoire/tools-surface.js +243 -0
- package/dist/repertoire/tools-teams.js +12 -62
- package/dist/repertoire/tools-travel.js +125 -0
- package/dist/repertoire/tools-user-profile.js +144 -0
- package/dist/repertoire/tools-vault.js +110 -0
- package/dist/repertoire/tools.js +144 -138
- package/dist/repertoire/travel-api-client.js +360 -0
- package/dist/repertoire/user-profile.js +118 -0
- package/dist/repertoire/vault-setup.js +241 -0
- package/dist/scripts/claude-code-hook.js +41 -0
- package/dist/scripts/claude-code-stop-hook.js +47 -0
- package/dist/senses/attention-queue.js +116 -0
- package/dist/senses/bluebubbles/attachment-cache.js +53 -0
- package/dist/senses/bluebubbles/attachment-download.js +137 -0
- package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +225 -9
- package/dist/senses/bluebubbles/entry.js +13 -0
- package/dist/senses/bluebubbles/inbound-log.js +113 -0
- package/dist/senses/bluebubbles/index.js +1590 -0
- package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
- package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +43 -12
- package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +46 -6
- package/dist/senses/bluebubbles/replay.js +129 -0
- package/dist/senses/bluebubbles/runtime-state.js +109 -0
- package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
- package/dist/senses/cli/bracketed-paste.js +82 -0
- package/dist/senses/cli/image-paste.js +287 -0
- package/dist/senses/cli/image-ref-navigation.js +75 -0
- package/dist/senses/cli/ink-app.js +156 -0
- package/dist/senses/cli/inline-diff.js +64 -0
- package/dist/senses/cli/input-keys.js +174 -0
- package/dist/senses/cli/kill-ring.js +86 -0
- package/dist/senses/cli/message-list.js +51 -0
- package/dist/senses/cli/ouro-tui.js +605 -0
- package/dist/senses/cli/spinner-imperative.js +135 -0
- package/dist/senses/cli/spinner.js +101 -0
- package/dist/senses/cli/status-line.js +60 -0
- package/dist/senses/cli/streaming-markdown.js +526 -0
- package/dist/senses/cli/tool-display.js +83 -0
- package/dist/senses/cli/tool-render.js +85 -0
- package/dist/senses/cli/tui-store.js +240 -0
- package/dist/senses/cli/virtual-list.js +35 -0
- package/dist/senses/cli-entry.js +1 -1
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +595 -246
- package/dist/senses/commands.js +65 -1
- package/dist/senses/continuity.js +94 -0
- package/dist/senses/habit-turn-message.js +108 -0
- package/dist/senses/inner-dialog-worker.js +112 -19
- package/dist/senses/inner-dialog.js +633 -86
- package/dist/senses/pipeline.js +567 -0
- package/dist/senses/shared-turn.js +199 -0
- package/dist/senses/surface-tool.js +68 -0
- package/dist/senses/teams.js +665 -160
- package/dist/senses/trust-gate.js +112 -2
- package/package.json +28 -7
- package/skills/agent-commerce.md +106 -0
- package/skills/browser-navigation.md +110 -0
- package/skills/commerce-setup-guide.md +116 -0
- package/skills/commerce-setup.md +84 -0
- package/skills/configure-dev-tools.md +81 -0
- package/skills/travel-planning.md +138 -0
- package/dist/heart/daemon/subagent-installer.js +0 -134
- package/dist/senses/bluebubbles-entry.js +0 -11
- package/dist/senses/bluebubbles.js +0 -544
- package/dist/senses/debug-activity.js +0 -108
- package/subagents/README.md +0 -73
- package/subagents/work-doer.md +0 -235
- package/subagents/work-merger.md +0 -618
- package/subagents/work-planner.md +0 -382
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
- /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
- /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
- /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
- /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
|
@@ -0,0 +1,1032 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderOutlookApp = renderOutlookApp;
|
|
4
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
5
|
+
const outlook_types_1 = require("./outlook-types");
|
|
6
|
+
function escapeHtml(value) {
|
|
7
|
+
return value
|
|
8
|
+
.replaceAll("&", "&")
|
|
9
|
+
.replaceAll("<", "<")
|
|
10
|
+
.replaceAll(">", ">")
|
|
11
|
+
.replaceAll("\"", """);
|
|
12
|
+
}
|
|
13
|
+
function escapeJsonForHtml(value) {
|
|
14
|
+
return JSON.stringify(value)
|
|
15
|
+
.replaceAll("&", "\\u0026")
|
|
16
|
+
.replaceAll("<", "\\u003c")
|
|
17
|
+
.replaceAll(">", "\\u003e");
|
|
18
|
+
}
|
|
19
|
+
function firstAgentName(machineView) {
|
|
20
|
+
return machineView?.agents[0]?.agentName ?? "";
|
|
21
|
+
}
|
|
22
|
+
function renderAgentButtons(machineView) {
|
|
23
|
+
const agents = machineView?.agents ?? [];
|
|
24
|
+
if (agents.length === 0) {
|
|
25
|
+
return [
|
|
26
|
+
"<div class=\"outlook-empty-agent-list\">",
|
|
27
|
+
" <p>No agents are visible yet.</p>",
|
|
28
|
+
" <p>When the daemon sees enabled bundles on this machine, they will gather here.</p>",
|
|
29
|
+
"</div>",
|
|
30
|
+
].join("\n");
|
|
31
|
+
}
|
|
32
|
+
return agents.map((agent, index) => [
|
|
33
|
+
`<button class="outlook-agent-chip${index === 0 ? " is-selected" : ""}" type="button" data-agent-name="${escapeHtml(agent.agentName)}">`,
|
|
34
|
+
` <span class="outlook-agent-chip__name">${escapeHtml(agent.agentName)}</span>`,
|
|
35
|
+
` <span class="outlook-agent-chip__attention attention-${escapeHtml(agent.attention.level)}">${escapeHtml(agent.attention.label)}</span>`,
|
|
36
|
+
` <span class="outlook-agent-chip__meta">${agent.tasks.liveCount} live tasks · ${agent.coding.activeCount} coding · ${agent.obligations.openCount} obligations</span>`,
|
|
37
|
+
"</button>",
|
|
38
|
+
].join("\n")).join("\n");
|
|
39
|
+
}
|
|
40
|
+
function renderOverviewCards(machineView, machine) {
|
|
41
|
+
const agents = Array.isArray(machine.agents) ? machine.agents : [];
|
|
42
|
+
const totals = machineView?.overview.totals ?? {
|
|
43
|
+
agents: machine.agentCount,
|
|
44
|
+
enabledAgents: agents.filter((agent) => agent.enabled).length,
|
|
45
|
+
degradedAgents: agents.filter((agent) => agent.degraded?.status === "degraded").length,
|
|
46
|
+
staleAgents: agents.filter((agent) => agent.freshness?.status === "stale").length,
|
|
47
|
+
liveTasks: agents.reduce((sum, agent) => sum + (agent.tasks?.liveCount ?? 0), 0),
|
|
48
|
+
blockedTasks: agents.reduce((sum, agent) => sum + (agent.tasks?.blockedCount ?? 0), 0),
|
|
49
|
+
openObligations: agents.reduce((sum, agent) => sum + (agent.obligations?.openCount ?? 0), 0),
|
|
50
|
+
activeCodingAgents: agents.reduce((sum, agent) => sum + (agent.coding?.activeCount ?? 0), 0),
|
|
51
|
+
blockedCodingAgents: agents.reduce((sum, agent) => sum + (agent.coding?.blockedCount ?? 0), 0),
|
|
52
|
+
};
|
|
53
|
+
const cards = [
|
|
54
|
+
{ label: "Visible agents", value: totals.agents.toString() },
|
|
55
|
+
{ label: "Live tasks", value: totals.liveTasks.toString() },
|
|
56
|
+
{ label: "Open obligations", value: totals.openObligations.toString() },
|
|
57
|
+
{ label: "Active coding", value: totals.activeCodingAgents.toString() },
|
|
58
|
+
{ label: "Blocked tasks", value: totals.blockedTasks.toString() },
|
|
59
|
+
{ label: "Stale agents", value: totals.staleAgents.toString() },
|
|
60
|
+
];
|
|
61
|
+
return cards.map((card) => [
|
|
62
|
+
"<article class=\"outlook-stat-card\">",
|
|
63
|
+
` <span class="outlook-kicker">${escapeHtml(card.label)}</span>`,
|
|
64
|
+
` <strong class="outlook-stat-card__value">${escapeHtml(card.value)}</strong>`,
|
|
65
|
+
"</article>",
|
|
66
|
+
].join("\n")).join("\n");
|
|
67
|
+
}
|
|
68
|
+
function renderEntrypoints(machineView, origin) {
|
|
69
|
+
const entrypoints = machineView?.overview.entrypoints ?? [
|
|
70
|
+
{ kind: "web", label: "Open Outlook", target: `${origin}/outlook` },
|
|
71
|
+
{ kind: "cli", label: "CLI JSON", target: "ouro outlook --json" },
|
|
72
|
+
];
|
|
73
|
+
return entrypoints.map((entrypoint) => [
|
|
74
|
+
"<div class=\"outlook-entrypoint\">",
|
|
75
|
+
` <span class="outlook-kicker">${escapeHtml(entrypoint.label)}</span>`,
|
|
76
|
+
` <code>${escapeHtml(entrypoint.target)}</code>`,
|
|
77
|
+
"</div>",
|
|
78
|
+
].join("\n")).join("\n");
|
|
79
|
+
}
|
|
80
|
+
function renderRuntimeFacts(machineView, machine) {
|
|
81
|
+
const runtime = machineView?.overview.runtime ?? machine.runtime;
|
|
82
|
+
const daemon = machineView?.overview.daemon;
|
|
83
|
+
const freshness = machineView?.overview.freshness ?? machine.freshness;
|
|
84
|
+
const degraded = machineView?.overview.degraded ?? machine.degraded;
|
|
85
|
+
const latestActivity = freshness?.latestActivityAt ?? "unknown";
|
|
86
|
+
return [
|
|
87
|
+
`<div class="outlook-fact"><span class="outlook-kicker">Runtime</span><strong>${escapeHtml(runtime?.version ?? "unknown")}</strong></div>`,
|
|
88
|
+
`<div class="outlook-fact"><span class="outlook-kicker">Mode</span><strong>${escapeHtml(daemon?.mode ?? "production")}</strong></div>`,
|
|
89
|
+
`<div class="outlook-fact"><span class="outlook-kicker">Freshness</span><strong>${escapeHtml(freshness?.status ?? "unknown")}</strong></div>`,
|
|
90
|
+
`<div class="outlook-fact"><span class="outlook-kicker">Latest activity</span><strong>${escapeHtml(latestActivity)}</strong></div>`,
|
|
91
|
+
`<div class="outlook-fact"><span class="outlook-kicker">Degraded</span><strong>${escapeHtml(degraded?.status ?? "ok")}</strong></div>`,
|
|
92
|
+
].join("\n");
|
|
93
|
+
}
|
|
94
|
+
const APP_CSS = `
|
|
95
|
+
@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,600;1,400;1,600&family=Outfit:wght@300;400;500;600&family=JetBrains+Mono:wght@400;500&display=swap');
|
|
96
|
+
|
|
97
|
+
:root {
|
|
98
|
+
--outlook-void: #07110d;
|
|
99
|
+
--outlook-deep: #102116;
|
|
100
|
+
--outlook-moss: #183325;
|
|
101
|
+
--outlook-scale: #2f8f4e;
|
|
102
|
+
--outlook-glow: #74e08f;
|
|
103
|
+
--outlook-bone: #eef2ea;
|
|
104
|
+
--outlook-mist: #a5b8a8;
|
|
105
|
+
--outlook-shadow: #708373;
|
|
106
|
+
--outlook-fang: #d35f47;
|
|
107
|
+
--outlook-line: rgba(110, 160, 117, 0.22);
|
|
108
|
+
--outlook-panel: rgba(10, 22, 16, 0.74);
|
|
109
|
+
--outlook-panel-strong: rgba(13, 29, 21, 0.9);
|
|
110
|
+
--outlook-glass: rgba(21, 44, 32, 0.4);
|
|
111
|
+
--outlook-ring: rgba(116, 224, 143, 0.14);
|
|
112
|
+
--outlook-gold: #d6b56f;
|
|
113
|
+
--outlook-font-display: "Cormorant Garamond", "Iowan Old Style", "Palatino Linotype", serif;
|
|
114
|
+
--outlook-font-body: "Outfit", "Avenir Next", "Segoe UI Variable Text", sans-serif;
|
|
115
|
+
--outlook-font-mono: "JetBrains Mono", "SFMono-Regular", monospace;
|
|
116
|
+
--outlook-radius-lg: 28px;
|
|
117
|
+
--outlook-radius-md: 18px;
|
|
118
|
+
--outlook-radius-sm: 12px;
|
|
119
|
+
--outlook-shadow-lg: 0 30px 80px rgba(0, 0, 0, 0.38);
|
|
120
|
+
}
|
|
121
|
+
* { box-sizing: border-box; margin: 0; }
|
|
122
|
+
html { color-scheme: dark; }
|
|
123
|
+
body {
|
|
124
|
+
min-height: 100vh;
|
|
125
|
+
font-family: var(--outlook-font-body);
|
|
126
|
+
color: var(--outlook-bone);
|
|
127
|
+
background:
|
|
128
|
+
radial-gradient(circle at top left, rgba(116, 224, 143, 0.12), transparent 28%),
|
|
129
|
+
radial-gradient(circle at 85% 15%, rgba(214, 181, 111, 0.08), transparent 24%),
|
|
130
|
+
linear-gradient(180deg, #08110d 0%, #0c1a12 42%, #07110d 100%);
|
|
131
|
+
}
|
|
132
|
+
body::before {
|
|
133
|
+
content: "";
|
|
134
|
+
position: fixed;
|
|
135
|
+
inset: 0;
|
|
136
|
+
pointer-events: none;
|
|
137
|
+
background-image:
|
|
138
|
+
linear-gradient(rgba(255,255,255,0.02) 1px, transparent 1px),
|
|
139
|
+
linear-gradient(90deg, rgba(255,255,255,0.02) 1px, transparent 1px);
|
|
140
|
+
background-size: 34px 34px;
|
|
141
|
+
mask-image: radial-gradient(circle at center, black 30%, transparent 82%);
|
|
142
|
+
opacity: 0.35;
|
|
143
|
+
}
|
|
144
|
+
body::after {
|
|
145
|
+
content: "";
|
|
146
|
+
position: fixed;
|
|
147
|
+
inset: 0;
|
|
148
|
+
pointer-events: none;
|
|
149
|
+
background:
|
|
150
|
+
radial-gradient(circle at 20% 20%, rgba(116, 224, 143, 0.09), transparent 22%),
|
|
151
|
+
radial-gradient(circle at 70% 78%, rgba(47, 143, 78, 0.08), transparent 25%);
|
|
152
|
+
filter: blur(40px);
|
|
153
|
+
opacity: 0.75;
|
|
154
|
+
}
|
|
155
|
+
.outlook-shell {
|
|
156
|
+
position: relative;
|
|
157
|
+
z-index: 1;
|
|
158
|
+
max-width: 1520px;
|
|
159
|
+
margin: 0 auto;
|
|
160
|
+
padding: 28px 22px 48px;
|
|
161
|
+
}
|
|
162
|
+
.outlook-sr-only {
|
|
163
|
+
position: absolute;
|
|
164
|
+
width: 1px; height: 1px; padding: 0; margin: -1px;
|
|
165
|
+
overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* ─── NAV ─── */
|
|
169
|
+
.outlook-nav {
|
|
170
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
171
|
+
gap: 16px; margin-bottom: 20px; padding: 14px 18px;
|
|
172
|
+
border: 1px solid var(--outlook-line); border-radius: 999px;
|
|
173
|
+
background: rgba(8, 18, 13, 0.58); backdrop-filter: blur(20px);
|
|
174
|
+
box-shadow: 0 14px 40px rgba(0,0,0,0.22);
|
|
175
|
+
}
|
|
176
|
+
.outlook-wordmark { display: flex; align-items: center; gap: 12px; }
|
|
177
|
+
.outlook-orb {
|
|
178
|
+
width: 14px; height: 14px; border-radius: 999px;
|
|
179
|
+
background: radial-gradient(circle at 30% 30%, #c9ffd7 0%, var(--outlook-glow) 30%, var(--outlook-scale) 70%, #173725 100%);
|
|
180
|
+
box-shadow: 0 0 24px rgba(116, 224, 143, 0.45);
|
|
181
|
+
animation: orb-breathe 4s ease-in-out infinite;
|
|
182
|
+
}
|
|
183
|
+
@keyframes orb-breathe {
|
|
184
|
+
0%, 100% { box-shadow: 0 0 24px rgba(116, 224, 143, 0.45); }
|
|
185
|
+
50% { box-shadow: 0 0 32px rgba(116, 224, 143, 0.65); }
|
|
186
|
+
}
|
|
187
|
+
.outlook-product {
|
|
188
|
+
margin: 0; font-family: var(--outlook-font-display);
|
|
189
|
+
font-size: clamp(1.5rem, 2vw, 2rem); font-style: italic; font-weight: 600;
|
|
190
|
+
}
|
|
191
|
+
.outlook-subtitle { margin: 2px 0 0; color: var(--outlook-mist); font-size: 0.85rem; }
|
|
192
|
+
.outlook-nav-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
|
|
193
|
+
.outlook-badge {
|
|
194
|
+
display: inline-flex; align-items: center; gap: 8px;
|
|
195
|
+
padding: 6px 11px; border-radius: 999px;
|
|
196
|
+
border: 1px solid var(--outlook-line); background: rgba(12, 29, 20, 0.7);
|
|
197
|
+
color: var(--outlook-bone); font-family: var(--outlook-font-mono);
|
|
198
|
+
font-size: 0.7rem; letter-spacing: 0.05em; text-transform: uppercase;
|
|
199
|
+
}
|
|
200
|
+
.outlook-badge::before {
|
|
201
|
+
content: ""; width: 7px; height: 7px; border-radius: 999px;
|
|
202
|
+
background: var(--outlook-glow); box-shadow: 0 0 18px rgba(116, 224, 143, 0.45);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/* ─── HERO ─── */
|
|
206
|
+
.outlook-hero {
|
|
207
|
+
position: relative; overflow: hidden;
|
|
208
|
+
padding: clamp(24px, 3vw, 42px); border-radius: calc(var(--outlook-radius-lg) + 8px);
|
|
209
|
+
border: 1px solid rgba(116, 224, 143, 0.14);
|
|
210
|
+
background: linear-gradient(135deg, rgba(9,18,14,0.97) 0%, rgba(13,30,21,0.94) 52%, rgba(11,21,16,0.95) 100%);
|
|
211
|
+
box-shadow: var(--outlook-shadow-lg);
|
|
212
|
+
}
|
|
213
|
+
.outlook-hero::before {
|
|
214
|
+
content: ""; position: absolute;
|
|
215
|
+
inset: auto -8% -42% 36%; height: 420px;
|
|
216
|
+
background: radial-gradient(circle, rgba(116,224,143,0.18) 0%, rgba(116,224,143,0.04) 35%, transparent 70%);
|
|
217
|
+
filter: blur(10px);
|
|
218
|
+
}
|
|
219
|
+
.outlook-hero__grid {
|
|
220
|
+
position: relative; display: grid; gap: 22px;
|
|
221
|
+
grid-template-columns: minmax(0, 1.4fr) minmax(280px, 0.9fr);
|
|
222
|
+
}
|
|
223
|
+
.outlook-kicker {
|
|
224
|
+
display: inline-block; font-family: var(--outlook-font-mono);
|
|
225
|
+
font-size: 0.68rem; letter-spacing: 0.22em; text-transform: uppercase;
|
|
226
|
+
color: var(--outlook-glow);
|
|
227
|
+
}
|
|
228
|
+
.outlook-hero h1,
|
|
229
|
+
.outlook-section h2, .outlook-panel h2,
|
|
230
|
+
.outlook-agent-panel__empty strong,
|
|
231
|
+
.outlook-agent-card h3 {
|
|
232
|
+
font-family: var(--outlook-font-display); font-style: italic;
|
|
233
|
+
font-weight: 600; letter-spacing: 0.01em;
|
|
234
|
+
}
|
|
235
|
+
.outlook-hero h1 { margin-top: 14px; font-size: clamp(2.6rem, 5vw, 4.8rem); line-height: 0.94; max-width: 8.3ch; }
|
|
236
|
+
.outlook-hero p { max-width: 60ch; margin: 14px 0 0; color: var(--outlook-mist); font-size: 0.98rem; line-height: 1.8; }
|
|
237
|
+
|
|
238
|
+
/* ─── STATS ─── */
|
|
239
|
+
.outlook-stat-grid { display: grid; gap: 12px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
240
|
+
.outlook-stat-card,
|
|
241
|
+
.outlook-facts, .outlook-entrypoints-panel, .outlook-agent-panel, .outlook-agents-rail {
|
|
242
|
+
border: 1px solid var(--outlook-line); border-radius: var(--outlook-radius-lg);
|
|
243
|
+
background: var(--outlook-panel); backdrop-filter: blur(18px);
|
|
244
|
+
}
|
|
245
|
+
.outlook-stat-card {
|
|
246
|
+
min-height: 110px; padding: 16px; display: flex;
|
|
247
|
+
flex-direction: column; justify-content: space-between;
|
|
248
|
+
box-shadow: inset 0 1px 0 rgba(255,255,255,0.02);
|
|
249
|
+
}
|
|
250
|
+
.outlook-stat-card__value { font-size: clamp(1.8rem, 3.5vw, 2.6rem); letter-spacing: -0.05em; }
|
|
251
|
+
|
|
252
|
+
/* ─── LAYOUT ─── */
|
|
253
|
+
.outlook-layout {
|
|
254
|
+
display: grid; gap: 20px; margin-top: 20px;
|
|
255
|
+
grid-template-columns: minmax(260px, 0.85fr) minmax(0, 1.75fr);
|
|
256
|
+
}
|
|
257
|
+
.outlook-agents-rail, .outlook-agent-panel, .outlook-facts, .outlook-entrypoints-panel { padding: 18px; }
|
|
258
|
+
.outlook-section, .outlook-panel { display: grid; gap: 14px; }
|
|
259
|
+
.outlook-section h2, .outlook-panel h2 { font-size: clamp(1.6rem, 2.2vw, 2.2rem); }
|
|
260
|
+
|
|
261
|
+
/* ─── AGENT CHIPS ─── */
|
|
262
|
+
.outlook-agent-list { display: grid; gap: 10px; }
|
|
263
|
+
.outlook-agent-chip {
|
|
264
|
+
width: 100%; display: grid; gap: 4px; padding: 14px;
|
|
265
|
+
border-radius: var(--outlook-radius-md);
|
|
266
|
+
border: 1px solid rgba(116, 224, 143, 0.08);
|
|
267
|
+
background: rgba(14, 31, 22, 0.72); color: inherit;
|
|
268
|
+
text-align: left; cursor: pointer;
|
|
269
|
+
transition: transform 180ms ease, border-color 180ms ease, background 180ms ease;
|
|
270
|
+
}
|
|
271
|
+
.outlook-agent-chip:hover, .outlook-agent-chip.is-selected {
|
|
272
|
+
transform: translateY(-2px);
|
|
273
|
+
border-color: rgba(116, 224, 143, 0.28); background: rgba(17, 39, 28, 0.88);
|
|
274
|
+
}
|
|
275
|
+
.outlook-agent-chip__name { font-family: var(--outlook-font-display); font-size: 1.35rem; font-style: italic; }
|
|
276
|
+
.outlook-agent-chip__attention, .outlook-agent-chip__meta { color: var(--outlook-mist); font-size: 0.84rem; }
|
|
277
|
+
.outlook-agent-chip__attention.attention-degraded,
|
|
278
|
+
.outlook-agent-chip__attention.attention-blocked { color: #ff8d79; }
|
|
279
|
+
.outlook-agent-chip__attention.attention-stale { color: var(--outlook-gold); }
|
|
280
|
+
.outlook-agent-chip__attention.attention-active { color: var(--outlook-glow); }
|
|
281
|
+
.outlook-empty-agent-list, .outlook-agent-panel__empty {
|
|
282
|
+
padding: 20px; border-radius: var(--outlook-radius-md);
|
|
283
|
+
border: 1px dashed rgba(116, 224, 143, 0.2);
|
|
284
|
+
background: rgba(10, 22, 16, 0.6); color: var(--outlook-mist);
|
|
285
|
+
}
|
|
286
|
+
.outlook-empty-agent-list p, .outlook-agent-panel__empty p { margin: 0; line-height: 1.7; }
|
|
287
|
+
.outlook-empty-agent-list p + p, .outlook-agent-panel__empty p + p { margin-top: 8px; }
|
|
288
|
+
|
|
289
|
+
/* ─── TABS ─── */
|
|
290
|
+
.outlook-tabs {
|
|
291
|
+
display: flex; gap: 2px; overflow-x: auto; padding-bottom: 2px;
|
|
292
|
+
border-bottom: 1px solid var(--outlook-line);
|
|
293
|
+
-webkit-overflow-scrolling: touch; scrollbar-width: none;
|
|
294
|
+
}
|
|
295
|
+
.outlook-tabs::-webkit-scrollbar { display: none; }
|
|
296
|
+
.outlook-tab {
|
|
297
|
+
padding: 10px 16px; border: none; border-radius: 12px 12px 0 0;
|
|
298
|
+
background: transparent; color: var(--outlook-mist); cursor: pointer;
|
|
299
|
+
font-family: var(--outlook-font-mono); font-size: 0.72rem;
|
|
300
|
+
letter-spacing: 0.08em; text-transform: uppercase; white-space: nowrap;
|
|
301
|
+
transition: color 140ms ease, background 140ms ease;
|
|
302
|
+
}
|
|
303
|
+
.outlook-tab:hover { color: var(--outlook-bone); background: rgba(116, 224, 143, 0.06); }
|
|
304
|
+
.outlook-tab.is-active {
|
|
305
|
+
color: var(--outlook-glow); background: rgba(116, 224, 143, 0.1);
|
|
306
|
+
border-bottom: 2px solid var(--outlook-glow);
|
|
307
|
+
}
|
|
308
|
+
.outlook-tab-content { display: none; padding-top: 16px; }
|
|
309
|
+
.outlook-tab-content.is-visible { display: block; animation: tab-fade 200ms ease; }
|
|
310
|
+
@keyframes tab-fade { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
|
|
311
|
+
|
|
312
|
+
/* ─── MACHINE FACTS ─── */
|
|
313
|
+
.outlook-facts { display: grid; gap: 14px; grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
|
314
|
+
.outlook-fact {
|
|
315
|
+
min-height: 82px; padding: 14px; border-radius: var(--outlook-radius-md);
|
|
316
|
+
background: rgba(12, 26, 18, 0.74); border: 1px solid rgba(116, 224, 143, 0.08);
|
|
317
|
+
}
|
|
318
|
+
.outlook-fact strong { display: block; margin-top: 8px; font-size: 0.95rem; line-height: 1.5; }
|
|
319
|
+
.outlook-entrypoints-panel { display: grid; gap: 12px; }
|
|
320
|
+
.outlook-entrypoint {
|
|
321
|
+
padding: 12px 14px; border-radius: var(--outlook-radius-md);
|
|
322
|
+
background: rgba(12, 27, 19, 0.7); border: 1px solid rgba(116, 224, 143, 0.08);
|
|
323
|
+
}
|
|
324
|
+
.outlook-entrypoint code, .outlook-agent-panel code {
|
|
325
|
+
display: block; margin-top: 6px; font-family: var(--outlook-font-mono);
|
|
326
|
+
font-size: 0.8rem; color: var(--outlook-bone); white-space: pre-wrap; word-break: break-word;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/* ─── AGENT CARD / METERS ─── */
|
|
330
|
+
.outlook-agent-card { display: grid; gap: 16px; }
|
|
331
|
+
.outlook-agent-card h3 { font-size: clamp(1.8rem, 2.5vw, 2.6rem); }
|
|
332
|
+
.outlook-agent-card__lede { margin: 0; color: var(--outlook-mist); line-height: 1.8; font-size: 0.95rem; }
|
|
333
|
+
.outlook-agent-meta, .outlook-agent-senses, .outlook-agent-recent { display: grid; gap: 8px; }
|
|
334
|
+
.outlook-agent-meta { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
335
|
+
.outlook-agent-meter {
|
|
336
|
+
padding: 12px; border-radius: var(--outlook-radius-md);
|
|
337
|
+
background: rgba(11, 23, 17, 0.75); border: 1px solid rgba(116, 224, 143, 0.08);
|
|
338
|
+
}
|
|
339
|
+
.outlook-agent-meter strong { display: block; margin-top: 6px; font-size: 1.4rem; }
|
|
340
|
+
.outlook-agent-meter span { color: var(--outlook-mist); font-size: 0.84rem; }
|
|
341
|
+
|
|
342
|
+
/* ─── PILLS ─── */
|
|
343
|
+
.outlook-pills { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
344
|
+
.outlook-pill {
|
|
345
|
+
display: inline-flex; align-items: center; padding: 5px 10px;
|
|
346
|
+
border-radius: 999px; background: rgba(15, 39, 27, 0.7);
|
|
347
|
+
border: 1px solid rgba(116, 224, 143, 0.1);
|
|
348
|
+
color: var(--outlook-bone); font-size: 0.8rem;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/* ─── RECENT ACTIVITY ─── */
|
|
352
|
+
.outlook-recent-list { display: grid; gap: 8px; }
|
|
353
|
+
.outlook-recent-item {
|
|
354
|
+
display: grid; gap: 3px; padding: 12px; border-radius: var(--outlook-radius-md);
|
|
355
|
+
background: rgba(11, 23, 17, 0.72); border: 1px solid rgba(116, 224, 143, 0.08);
|
|
356
|
+
}
|
|
357
|
+
.outlook-recent-item small { color: var(--outlook-shadow); font-family: var(--outlook-font-mono); font-size: 0.7rem; }
|
|
358
|
+
.outlook-recent-item strong { font-size: 0.9rem; }
|
|
359
|
+
.outlook-recent-item span { color: var(--outlook-mist); font-size: 0.84rem; }
|
|
360
|
+
|
|
361
|
+
/* ─── SESSION LIST ─── */
|
|
362
|
+
.outlook-session-list { display: grid; gap: 8px; }
|
|
363
|
+
.outlook-session-row {
|
|
364
|
+
display: grid; gap: 4px; padding: 14px; border-radius: var(--outlook-radius-md);
|
|
365
|
+
background: rgba(11, 23, 17, 0.72); border: 1px solid rgba(116, 224, 143, 0.08);
|
|
366
|
+
cursor: pointer; transition: border-color 140ms ease, background 140ms ease;
|
|
367
|
+
}
|
|
368
|
+
.outlook-session-row:hover, .outlook-session-row.is-expanded {
|
|
369
|
+
border-color: rgba(116, 224, 143, 0.22); background: rgba(14, 30, 22, 0.85);
|
|
370
|
+
}
|
|
371
|
+
.outlook-session-row__header { display: flex; justify-content: space-between; align-items: center; }
|
|
372
|
+
.outlook-session-row__name { font-family: var(--outlook-font-display); font-style: italic; font-size: 1.15rem; }
|
|
373
|
+
.outlook-session-row__meta { color: var(--outlook-mist); font-size: 0.8rem; }
|
|
374
|
+
.outlook-session-row__excerpt { color: var(--outlook-shadow); font-size: 0.82rem; line-height: 1.5; margin-top: 2px; }
|
|
375
|
+
|
|
376
|
+
/* ─── TRANSCRIPT VIEWER ─── */
|
|
377
|
+
.outlook-transcript { display: none; margin-top: 10px; padding: 14px; border-radius: var(--outlook-radius-sm); background: rgba(7, 17, 13, 0.85); border: 1px solid var(--outlook-line); max-height: 500px; overflow-y: auto; }
|
|
378
|
+
.outlook-transcript.is-visible { display: block; animation: tab-fade 200ms ease; }
|
|
379
|
+
.outlook-msg { padding: 10px 0; border-bottom: 1px solid rgba(110, 160, 117, 0.1); }
|
|
380
|
+
.outlook-msg:last-child { border-bottom: none; }
|
|
381
|
+
.outlook-msg__role {
|
|
382
|
+
display: inline-block; padding: 2px 8px; border-radius: 6px; margin-bottom: 4px;
|
|
383
|
+
font-family: var(--outlook-font-mono); font-size: 0.68rem; letter-spacing: 0.06em; text-transform: uppercase;
|
|
384
|
+
}
|
|
385
|
+
.outlook-msg__role--system { background: rgba(116, 224, 143, 0.12); color: var(--outlook-glow); }
|
|
386
|
+
.outlook-msg__role--user { background: rgba(214, 181, 111, 0.15); color: var(--outlook-gold); }
|
|
387
|
+
.outlook-msg__role--assistant { background: rgba(116, 224, 143, 0.08); color: var(--outlook-bone); }
|
|
388
|
+
.outlook-msg__role--tool { background: rgba(165, 184, 168, 0.1); color: var(--outlook-mist); }
|
|
389
|
+
.outlook-msg__content { color: var(--outlook-bone); font-size: 0.85rem; line-height: 1.7; white-space: pre-wrap; word-break: break-word; }
|
|
390
|
+
.outlook-msg__tool-calls { margin-top: 6px; }
|
|
391
|
+
.outlook-tool-call {
|
|
392
|
+
padding: 8px 10px; margin-top: 4px; border-radius: 8px;
|
|
393
|
+
background: rgba(15, 35, 25, 0.6); border: 1px solid rgba(116, 224, 143, 0.08);
|
|
394
|
+
font-family: var(--outlook-font-mono); font-size: 0.76rem; color: var(--outlook-glow);
|
|
395
|
+
}
|
|
396
|
+
.outlook-tool-call__args { color: var(--outlook-mist); font-size: 0.72rem; margin-top: 4px; white-space: pre-wrap; word-break: break-word; max-height: 120px; overflow-y: auto; }
|
|
397
|
+
|
|
398
|
+
/* ─── OBLIGATION / CODING DEEP ─── */
|
|
399
|
+
.outlook-obligation-row, .outlook-coding-row, .outlook-bridge-row, .outlook-habit-row {
|
|
400
|
+
padding: 12px; border-radius: var(--outlook-radius-md);
|
|
401
|
+
background: rgba(11, 23, 17, 0.72); border: 1px solid rgba(116, 224, 143, 0.08);
|
|
402
|
+
margin-bottom: 8px;
|
|
403
|
+
}
|
|
404
|
+
.outlook-obligation-row__status, .outlook-coding-row__status {
|
|
405
|
+
display: inline-block; padding: 2px 8px; border-radius: 6px;
|
|
406
|
+
font-family: var(--outlook-font-mono); font-size: 0.68rem; text-transform: uppercase;
|
|
407
|
+
background: rgba(116, 224, 143, 0.08); color: var(--outlook-glow);
|
|
408
|
+
}
|
|
409
|
+
.outlook-coding-row__status--failed { background: rgba(211, 95, 71, 0.15); color: var(--outlook-fang); }
|
|
410
|
+
.outlook-coding-row__stdout, .outlook-coding-row__stderr {
|
|
411
|
+
margin-top: 6px; padding: 8px; border-radius: 6px;
|
|
412
|
+
background: rgba(7, 17, 13, 0.7); font-family: var(--outlook-font-mono);
|
|
413
|
+
font-size: 0.72rem; color: var(--outlook-mist); white-space: pre-wrap; max-height: 100px; overflow-y: auto;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/* ─── DIARY / MEMORY ─── */
|
|
417
|
+
.outlook-diary-entry {
|
|
418
|
+
padding: 10px 12px; border-radius: var(--outlook-radius-sm);
|
|
419
|
+
background: rgba(11, 23, 17, 0.6); border: 1px solid rgba(116, 224, 143, 0.06);
|
|
420
|
+
margin-bottom: 6px; font-size: 0.85rem; line-height: 1.6;
|
|
421
|
+
}
|
|
422
|
+
.outlook-diary-entry__source { color: var(--outlook-shadow); font-family: var(--outlook-font-mono); font-size: 0.68rem; }
|
|
423
|
+
|
|
424
|
+
/* ─── CENTER OF GRAVITY ─── */
|
|
425
|
+
.outlook-cog {
|
|
426
|
+
padding: 18px; border-radius: var(--outlook-radius-lg);
|
|
427
|
+
background: linear-gradient(135deg, rgba(13, 30, 22, 0.92) 0%, rgba(10, 22, 16, 0.88) 100%);
|
|
428
|
+
border: 1px solid rgba(116, 224, 143, 0.18);
|
|
429
|
+
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);
|
|
430
|
+
}
|
|
431
|
+
.outlook-cog__heading { font-family: var(--outlook-font-display); font-style: italic; font-size: 1.5rem; margin-bottom: 10px; }
|
|
432
|
+
.outlook-cog__pressures { display: grid; gap: 6px; margin-top: 10px; }
|
|
433
|
+
.outlook-pressure {
|
|
434
|
+
display: flex; gap: 8px; align-items: center; padding: 8px 12px;
|
|
435
|
+
border-radius: 10px; background: rgba(10, 22, 16, 0.65);
|
|
436
|
+
border: 1px solid rgba(116, 224, 143, 0.06); font-size: 0.85rem;
|
|
437
|
+
}
|
|
438
|
+
.outlook-pressure__dot {
|
|
439
|
+
width: 8px; height: 8px; border-radius: 999px; flex-shrink: 0;
|
|
440
|
+
}
|
|
441
|
+
.outlook-pressure__dot--high { background: var(--outlook-fang); box-shadow: 0 0 10px rgba(211, 95, 71, 0.4); }
|
|
442
|
+
.outlook-pressure__dot--medium { background: var(--outlook-gold); box-shadow: 0 0 10px rgba(214, 181, 111, 0.3); }
|
|
443
|
+
.outlook-pressure__dot--low { background: var(--outlook-glow); box-shadow: 0 0 10px rgba(116, 224, 143, 0.3); }
|
|
444
|
+
|
|
445
|
+
/* ─── FOOTER ─── */
|
|
446
|
+
.outlook-footer-note {
|
|
447
|
+
margin-top: 12px; color: var(--outlook-shadow);
|
|
448
|
+
font-family: var(--outlook-font-mono); font-size: 0.72rem; letter-spacing: 0.04em;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/* ─── LOADING ─── */
|
|
452
|
+
.outlook-loading {
|
|
453
|
+
padding: 20px; text-align: center; color: var(--outlook-mist);
|
|
454
|
+
font-family: var(--outlook-font-mono); font-size: 0.8rem;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
@media (max-width: 1080px) {
|
|
458
|
+
.outlook-hero__grid, .outlook-layout { grid-template-columns: 1fr; }
|
|
459
|
+
}
|
|
460
|
+
@media (max-width: 760px) {
|
|
461
|
+
.outlook-shell { padding-inline: 14px; }
|
|
462
|
+
.outlook-nav { border-radius: 28px; align-items: flex-start; flex-direction: column; }
|
|
463
|
+
.outlook-nav-meta, .outlook-facts, .outlook-stat-grid, .outlook-agent-meta { grid-template-columns: 1fr; }
|
|
464
|
+
}
|
|
465
|
+
`;
|
|
466
|
+
const APP_SCRIPT = `
|
|
467
|
+
(function () {
|
|
468
|
+
var root = document.querySelector('[data-outlook-app]');
|
|
469
|
+
if (!root) return;
|
|
470
|
+
|
|
471
|
+
var machineScript = document.getElementById('outlook-machine-view');
|
|
472
|
+
var panel = document.querySelector('[data-outlook-agent-panel]');
|
|
473
|
+
var list = document.querySelector('[data-outlook-agent-list]');
|
|
474
|
+
var title = document.querySelector('[data-outlook-agent-title]');
|
|
475
|
+
var subtitle = document.querySelector('[data-outlook-agent-subtitle]');
|
|
476
|
+
var machineEndpoint = root.getAttribute('data-machine-endpoint');
|
|
477
|
+
var agentEndpointBase = root.getAttribute('data-agent-endpoint-base');
|
|
478
|
+
var selectedAgent = root.getAttribute('data-initial-agent') || '';
|
|
479
|
+
var machineView = machineScript ? JSON.parse(machineScript.textContent || '{}') : null;
|
|
480
|
+
var activeTab = 'overview';
|
|
481
|
+
var cachedSurfaces = {};
|
|
482
|
+
var lastAgentView = null;
|
|
483
|
+
|
|
484
|
+
function setSelected(name) {
|
|
485
|
+
selectedAgent = name || '';
|
|
486
|
+
root.setAttribute('data-selected-agent', selectedAgent);
|
|
487
|
+
cachedSurfaces = {};
|
|
488
|
+
activeTab = 'overview';
|
|
489
|
+
lastAgentView = null;
|
|
490
|
+
if (!list) return;
|
|
491
|
+
list.querySelectorAll('[data-agent-name]').forEach(function (button) {
|
|
492
|
+
button.classList.toggle('is-selected', button.getAttribute('data-agent-name') === selectedAgent);
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
function escapeHtml(value) {
|
|
497
|
+
return String(value).replaceAll('&','&').replaceAll('<','<').replaceAll('>','>').replaceAll('"','"');
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
function relTime(iso) {
|
|
501
|
+
if (!iso) return 'unknown';
|
|
502
|
+
var ms = Date.now() - new Date(iso).getTime();
|
|
503
|
+
if (ms < 60000) return 'just now';
|
|
504
|
+
if (ms < 3600000) return Math.floor(ms/60000) + 'm ago';
|
|
505
|
+
if (ms < 86400000) return Math.floor(ms/3600000) + 'h ago';
|
|
506
|
+
return Math.floor(ms/86400000) + 'd ago';
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
function truncate(str, max) {
|
|
510
|
+
if (!str) return '';
|
|
511
|
+
return str.length > max ? str.slice(0, max) + '...' : str;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
var TABS = [
|
|
515
|
+
{ id: 'overview', label: 'Overview' },
|
|
516
|
+
{ id: 'sessions', label: 'Sessions' },
|
|
517
|
+
{ id: 'work', label: 'Work' },
|
|
518
|
+
{ id: 'connections', label: 'Connections' },
|
|
519
|
+
{ id: 'inner', label: 'Inner' },
|
|
520
|
+
{ id: 'memory', label: 'Memory' },
|
|
521
|
+
{ id: 'runtime', label: 'Runtime' },
|
|
522
|
+
];
|
|
523
|
+
|
|
524
|
+
function renderTabs() {
|
|
525
|
+
return '<div class="outlook-tabs">' +
|
|
526
|
+
TABS.map(function(t) {
|
|
527
|
+
return '<button class="outlook-tab' + (t.id === activeTab ? ' is-active' : '') + '" data-tab="' + t.id + '">' + t.label + '</button>';
|
|
528
|
+
}).join('') + '</div>';
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
function renderOverviewTab(view) {
|
|
532
|
+
var senses = view.agent.senses.length
|
|
533
|
+
? view.agent.senses.map(function(s) { return '<span class="outlook-pill">' + escapeHtml(s) + '</span>'; }).join('')
|
|
534
|
+
: '<span class="outlook-pill">No active senses</span>';
|
|
535
|
+
var bridges = view.work.bridges.length
|
|
536
|
+
? view.work.bridges.map(function(b) { return '<span class="outlook-pill">' + escapeHtml(b) + '</span>'; }).join('')
|
|
537
|
+
: '<span class="outlook-pill">No active bridges</span>';
|
|
538
|
+
var recent = view.activity.recent.length
|
|
539
|
+
? '<div class="outlook-recent-list">' + view.activity.recent.map(function(item) {
|
|
540
|
+
return '<article class="outlook-recent-item"><small>' + escapeHtml(item.kind) + ' · ' + relTime(item.at) + '</small><strong>' + escapeHtml(truncate(item.label, 100)) + '</strong><span>' + escapeHtml(truncate(item.detail, 80)) + '</span></article>';
|
|
541
|
+
}).join('') + '</div>'
|
|
542
|
+
: '<p class="outlook-agent-card__lede">No recent activity yet.</p>';
|
|
543
|
+
var innerSummary = view.inner.summary || view.inner.status;
|
|
544
|
+
|
|
545
|
+
return '<article class="outlook-agent-card">' +
|
|
546
|
+
'<div class="outlook-cog">' +
|
|
547
|
+
' <div class="outlook-kicker">Center of gravity</div>' +
|
|
548
|
+
' <div class="outlook-cog__heading">' + escapeHtml(view.agent.attention.label) + '</div>' +
|
|
549
|
+
' <p class="outlook-agent-card__lede">' + escapeHtml(view.agent.agentName) +
|
|
550
|
+
' has ' + view.work.tasks.liveCount + ' live tasks, ' +
|
|
551
|
+
view.work.obligations.openCount + ' open obligations, ' +
|
|
552
|
+
view.work.coding.activeCount + ' coding lanes, ' +
|
|
553
|
+
'and is ' + escapeHtml(view.activity.freshness.status) + '.</p>' +
|
|
554
|
+
(view.agent.degraded.status === 'degraded' && view.agent.degraded.issues.length
|
|
555
|
+
? '<div class="outlook-cog__pressures">' + view.agent.degraded.issues.map(function(issue) {
|
|
556
|
+
return '<div class="outlook-pressure"><span class="outlook-pressure__dot outlook-pressure__dot--high"></span><span><strong>' + escapeHtml(issue.code) + '</strong> — ' + escapeHtml(issue.detail) + '</span></div>';
|
|
557
|
+
}).join('') + '</div>'
|
|
558
|
+
: '') +
|
|
559
|
+
'</div>' +
|
|
560
|
+
'<div class="outlook-agent-meta">' +
|
|
561
|
+
' <div class="outlook-agent-meter"><span class="outlook-kicker">Tasks</span><strong>' + view.work.tasks.liveCount + '</strong><span>' + view.work.tasks.blockedCount + ' blocked</span></div>' +
|
|
562
|
+
' <div class="outlook-agent-meter"><span class="outlook-kicker">Obligations</span><strong>' + view.work.obligations.openCount + '</strong><span>' + view.work.sessions.liveCount + ' live sessions</span></div>' +
|
|
563
|
+
' <div class="outlook-agent-meter"><span class="outlook-kicker">Coding</span><strong>' + view.work.coding.activeCount + '</strong><span>' + view.work.coding.blockedCount + ' blocked</span></div>' +
|
|
564
|
+
' <div class="outlook-agent-meter"><span class="outlook-kicker">Inner</span><strong>' + escapeHtml(view.inner.status) + '</strong><span>' + escapeHtml(truncate(innerSummary, 60) || 'No summary') + '</span></div>' +
|
|
565
|
+
'</div>' +
|
|
566
|
+
'<section class="outlook-agent-senses"><span class="outlook-kicker">Senses</span><div class="outlook-pills">' + senses + '</div></section>' +
|
|
567
|
+
'<section class="outlook-agent-senses"><span class="outlook-kicker">Bridges</span><div class="outlook-pills">' + bridges + '</div></section>' +
|
|
568
|
+
'<section class="outlook-agent-recent"><span class="outlook-kicker">Recent activity</span>' + recent + '</section>' +
|
|
569
|
+
'</article>';
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
function renderSessionsTab(data) {
|
|
573
|
+
if (!data || !data.items || data.items.length === 0) {
|
|
574
|
+
return '<p class="outlook-agent-card__lede">No sessions found.</p>';
|
|
575
|
+
}
|
|
576
|
+
return '<div class="outlook-kicker" style="margin-bottom:8px">' + data.totalCount + ' sessions (' + data.activeCount + ' active, ' + data.staleCount + ' stale)</div>' +
|
|
577
|
+
'<div class="outlook-session-list" data-session-list>' +
|
|
578
|
+
data.items.map(function(s) {
|
|
579
|
+
return '<div class="outlook-session-row" data-session-key="' + escapeHtml(s.friendId + '/' + s.channel + '/' + s.key) + '">' +
|
|
580
|
+
'<div class="outlook-session-row__header">' +
|
|
581
|
+
' <span class="outlook-session-row__name">' + escapeHtml(s.friendName) + ' <small style="color:var(--outlook-mist);font-style:normal;font-size:0.75rem">via ' + escapeHtml(s.channel) + '</small></span>' +
|
|
582
|
+
' <span class="outlook-session-row__meta">' + s.messageCount + ' msgs · ' + relTime(s.lastActivityAt) + (s.lastUsage ? ' · ' + s.lastUsage.total_tokens + ' tok' : '') + '</span>' +
|
|
583
|
+
'</div>' +
|
|
584
|
+
(s.latestUserExcerpt ? '<div class="outlook-session-row__excerpt">' + escapeHtml(truncate(s.latestUserExcerpt, 120)) + '</div>' : '') +
|
|
585
|
+
'<div class="outlook-transcript" data-transcript-for="' + escapeHtml(s.friendId + '/' + s.channel + '/' + s.key) + '"></div>' +
|
|
586
|
+
'</div>';
|
|
587
|
+
}).join('') + '</div>';
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
function renderTranscript(messages) {
|
|
591
|
+
return messages.map(function(m) {
|
|
592
|
+
var roleClass = 'outlook-msg__role--' + m.role;
|
|
593
|
+
var html = '<div class="outlook-msg">';
|
|
594
|
+
html += '<span class="outlook-msg__role ' + roleClass + '">' + escapeHtml(m.role) + (m.name ? ' (' + escapeHtml(m.name) + ')' : '') + '</span>';
|
|
595
|
+
if (m.content) html += '<div class="outlook-msg__content">' + escapeHtml(m.content) + '</div>';
|
|
596
|
+
if (m.tool_calls && m.tool_calls.length) {
|
|
597
|
+
html += '<div class="outlook-msg__tool-calls">';
|
|
598
|
+
m.tool_calls.forEach(function(tc) {
|
|
599
|
+
html += '<div class="outlook-tool-call">' + escapeHtml(tc.function.name) +
|
|
600
|
+
'<div class="outlook-tool-call__args">' + escapeHtml(truncate(tc.function.arguments, 300)) + '</div></div>';
|
|
601
|
+
});
|
|
602
|
+
html += '</div>';
|
|
603
|
+
}
|
|
604
|
+
if (m.tool_call_id) html += '<div style="color:var(--outlook-shadow);font-size:0.7rem;margin-top:2px">tool_call_id: ' + escapeHtml(m.tool_call_id) + '</div>';
|
|
605
|
+
html += '</div>';
|
|
606
|
+
return html;
|
|
607
|
+
}).join('');
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
function renderWorkTab(view, coding) {
|
|
611
|
+
var html = '';
|
|
612
|
+
// Obligations
|
|
613
|
+
html += '<div class="outlook-kicker" style="margin-bottom:6px">Obligations (' + view.work.obligations.openCount + ' open)</div>';
|
|
614
|
+
if (view.work.obligations.items && view.work.obligations.items.length) {
|
|
615
|
+
view.work.obligations.items.forEach(function(o) {
|
|
616
|
+
html += '<div class="outlook-obligation-row">' +
|
|
617
|
+
'<span class="outlook-obligation-row__status">' + escapeHtml(o.status) + '</span> ' +
|
|
618
|
+
'<strong style="font-size:0.9rem">' + escapeHtml(truncate(o.content, 100)) + '</strong>' +
|
|
619
|
+
(o.nextAction ? '<div style="color:var(--outlook-mist);font-size:0.82rem;margin-top:4px">Next: ' + escapeHtml(o.nextAction) + '</div>' : '') +
|
|
620
|
+
'<div style="color:var(--outlook-shadow);font-size:0.72rem;margin-top:2px">' + relTime(o.updatedAt) + '</div></div>';
|
|
621
|
+
});
|
|
622
|
+
} else { html += '<p class="outlook-agent-card__lede">No open obligations.</p>'; }
|
|
623
|
+
|
|
624
|
+
// Coding
|
|
625
|
+
html += '<div class="outlook-kicker" style="margin:14px 0 6px">Coding lanes (' + (coding ? coding.totalCount : 0) + ')</div>';
|
|
626
|
+
if (coding && coding.items && coding.items.length) {
|
|
627
|
+
coding.items.forEach(function(c) {
|
|
628
|
+
var statusClass = c.status === 'failed' ? ' outlook-coding-row__status--failed' : '';
|
|
629
|
+
html += '<div class="outlook-coding-row">' +
|
|
630
|
+
'<span class="outlook-coding-row__status' + statusClass + '">' + escapeHtml(c.status) + '</span> ' +
|
|
631
|
+
'<strong style="font-size:0.88rem">' + escapeHtml(c.runner) + ' — ' + escapeHtml(c.workdir) + '</strong>' +
|
|
632
|
+
(c.checkpoint ? '<div style="color:var(--outlook-mist);font-size:0.82rem;margin-top:4px">' + escapeHtml(truncate(c.checkpoint, 100)) + '</div>' : '') +
|
|
633
|
+
'<div style="color:var(--outlook-shadow);font-size:0.72rem;margin-top:2px">pid ' + (c.pid||'-') + ' · restarts ' + c.restartCount + ' · ' + relTime(c.lastActivityAt) + '</div>' +
|
|
634
|
+
(c.stdoutTail ? '<div class="outlook-coding-row__stdout">' + escapeHtml(truncate(c.stdoutTail, 300)) + '</div>' : '') +
|
|
635
|
+
(c.failure ? '<div class="outlook-coding-row__stderr">FAILURE: ' + escapeHtml(c.failure.command) + ' exited ' + (c.failure.code||c.failure.signal) + '</div>' : '') +
|
|
636
|
+
'</div>';
|
|
637
|
+
});
|
|
638
|
+
} else { html += '<p class="outlook-agent-card__lede">No coding sessions.</p>'; }
|
|
639
|
+
|
|
640
|
+
// Tasks
|
|
641
|
+
html += '<div class="outlook-kicker" style="margin:14px 0 6px">Tasks (' + view.work.tasks.liveCount + ' live)</div>';
|
|
642
|
+
if (view.work.tasks.liveTaskNames && view.work.tasks.liveTaskNames.length) {
|
|
643
|
+
html += '<div class="outlook-pills">' + view.work.tasks.liveTaskNames.map(function(t) { return '<span class="outlook-pill">' + escapeHtml(t) + '</span>'; }).join('') + '</div>';
|
|
644
|
+
} else { html += '<p class="outlook-agent-card__lede">No live tasks.</p>'; }
|
|
645
|
+
|
|
646
|
+
return html;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
function renderConnectionsTab(attention, bridges, friends) {
|
|
650
|
+
var html = '';
|
|
651
|
+
// Attention queue
|
|
652
|
+
html += '<div class="outlook-kicker" style="margin-bottom:6px">Attention queue (' + (attention ? attention.queueLength : 0) + ')</div>';
|
|
653
|
+
if (attention && attention.queueItems && attention.queueItems.length) {
|
|
654
|
+
attention.queueItems.forEach(function(item) {
|
|
655
|
+
html += '<div class="outlook-obligation-row">' +
|
|
656
|
+
'<strong style="font-size:0.88rem">' + escapeHtml(item.friendName) + '</strong> via ' + escapeHtml(item.channel) +
|
|
657
|
+
'<div style="color:var(--outlook-mist);font-size:0.82rem;margin-top:3px">' + escapeHtml(truncate(item.delegatedContent, 120)) + '</div>' +
|
|
658
|
+
(item.bridgeId ? '<div style="color:var(--outlook-shadow);font-size:0.72rem">bridge: ' + escapeHtml(item.bridgeId) + '</div>' : '') +
|
|
659
|
+
'</div>';
|
|
660
|
+
});
|
|
661
|
+
} else { html += '<p class="outlook-agent-card__lede">Nothing waiting.</p>'; }
|
|
662
|
+
|
|
663
|
+
// Bridges
|
|
664
|
+
html += '<div class="outlook-kicker" style="margin:14px 0 6px">Bridges (' + (bridges ? bridges.totalCount : 0) + ')</div>';
|
|
665
|
+
if (bridges && bridges.items && bridges.items.length) {
|
|
666
|
+
bridges.items.forEach(function(b) {
|
|
667
|
+
html += '<div class="outlook-bridge-row">' +
|
|
668
|
+
'<span class="outlook-obligation-row__status">' + escapeHtml(b.lifecycle) + '</span> ' +
|
|
669
|
+
'<strong style="font-size:0.88rem">' + escapeHtml(b.objective) + '</strong>' +
|
|
670
|
+
'<div style="color:var(--outlook-mist);font-size:0.82rem;margin-top:3px">' + escapeHtml(truncate(b.summary, 120)) + '</div>' +
|
|
671
|
+
'<div style="color:var(--outlook-shadow);font-size:0.72rem;margin-top:2px">' + b.attachedSessions.length + ' sessions · ' + relTime(b.updatedAt) + '</div>' +
|
|
672
|
+
'</div>';
|
|
673
|
+
});
|
|
674
|
+
} else { html += '<p class="outlook-agent-card__lede">No bridges.</p>'; }
|
|
675
|
+
|
|
676
|
+
// Friends
|
|
677
|
+
html += '<div class="outlook-kicker" style="margin:14px 0 6px">Friends (' + (friends ? friends.totalFriends : 0) + ')</div>';
|
|
678
|
+
if (friends && friends.friends && friends.friends.length) {
|
|
679
|
+
friends.friends.forEach(function(f) {
|
|
680
|
+
html += '<div class="outlook-obligation-row">' +
|
|
681
|
+
'<strong style="font-size:0.88rem">' + escapeHtml(f.friendName) + '</strong>' +
|
|
682
|
+
'<div style="color:var(--outlook-mist);font-size:0.82rem">' + f.totalTokens.toLocaleString() + ' tokens · ' + f.sessionCount + ' sessions · ' + f.channels.join(', ') + '</div>' +
|
|
683
|
+
'</div>';
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
return html;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
function renderInnerTab(view, habits) {
|
|
691
|
+
var html = '';
|
|
692
|
+
html += '<div class="outlook-cog" style="margin-bottom:12px">' +
|
|
693
|
+
'<div class="outlook-kicker">Inner work</div>' +
|
|
694
|
+
'<div class="outlook-cog__heading">' + escapeHtml(view.inner.status) + '</div>' +
|
|
695
|
+
(view.inner.summary ? '<p class="outlook-agent-card__lede">' + escapeHtml(view.inner.summary) + '</p>' : '') +
|
|
696
|
+
'<p class="outlook-agent-card__lede" style="margin-top:6px">' + (view.inner.hasPending ? 'Pending inner work queued.' : 'No pending inner work.') + '</p>' +
|
|
697
|
+
'</div>';
|
|
698
|
+
|
|
699
|
+
if (view.inner.mode === 'deep' && view.inner.origin) {
|
|
700
|
+
html += '<div class="outlook-kicker" style="margin:10px 0 4px">Origin</div>' +
|
|
701
|
+
'<code style="font-size:0.8rem;display:block">' + escapeHtml(JSON.stringify(view.inner.origin)) + '</code>';
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// Habits
|
|
705
|
+
html += '<div class="outlook-kicker" style="margin:14px 0 6px">Habits (' + (habits ? habits.totalCount : 0) + ')</div>';
|
|
706
|
+
if (habits && habits.items && habits.items.length) {
|
|
707
|
+
habits.items.forEach(function(h) {
|
|
708
|
+
var overdueTag = h.isOverdue ? ' <span style="color:var(--outlook-fang)">OVERDUE</span>' : '';
|
|
709
|
+
html += '<div class="outlook-habit-row">' +
|
|
710
|
+
'<strong style="font-size:0.88rem">' + escapeHtml(h.title) + overdueTag + '</strong>' +
|
|
711
|
+
'<div style="color:var(--outlook-mist);font-size:0.82rem">' + escapeHtml(h.status) + (h.cadence ? ' · every ' + escapeHtml(h.cadence) : '') + (h.lastRun ? ' · last ' + relTime(h.lastRun) : ' · never run') + '</div>' +
|
|
712
|
+
(h.bodyExcerpt ? '<div style="color:var(--outlook-shadow);font-size:0.8rem;margin-top:3px">' + escapeHtml(h.bodyExcerpt) + '</div>' : '') +
|
|
713
|
+
'</div>';
|
|
714
|
+
});
|
|
715
|
+
} else { html += '<p class="outlook-agent-card__lede">No habits configured.</p>'; }
|
|
716
|
+
|
|
717
|
+
return html;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
function renderMemoryTab(memory) {
|
|
721
|
+
var html = '';
|
|
722
|
+
html += '<div class="outlook-kicker" style="margin-bottom:6px">Diary (' + (memory ? memory.diaryEntryCount : 0) + ' entries)</div>';
|
|
723
|
+
if (memory && memory.recentDiaryEntries && memory.recentDiaryEntries.length) {
|
|
724
|
+
memory.recentDiaryEntries.forEach(function(e) {
|
|
725
|
+
html += '<div class="outlook-diary-entry">' +
|
|
726
|
+
'<div class="outlook-diary-entry__source">' + escapeHtml(e.source) + ' · ' + relTime(e.createdAt) + '</div>' +
|
|
727
|
+
escapeHtml(e.text) + '</div>';
|
|
728
|
+
});
|
|
729
|
+
} else { html += '<p class="outlook-agent-card__lede">No diary entries.</p>'; }
|
|
730
|
+
|
|
731
|
+
html += '<div class="outlook-kicker" style="margin:14px 0 6px">Journal (' + (memory ? memory.journalEntryCount : 0) + ' entries)</div>';
|
|
732
|
+
if (memory && memory.recentJournalEntries && memory.recentJournalEntries.length) {
|
|
733
|
+
memory.recentJournalEntries.forEach(function(e) {
|
|
734
|
+
html += '<div class="outlook-diary-entry">' +
|
|
735
|
+
'<strong style="font-size:0.85rem">' + escapeHtml(e.filename) + '</strong>' +
|
|
736
|
+
'<div style="color:var(--outlook-mist);font-size:0.82rem">' + escapeHtml(e.preview) + '</div></div>';
|
|
737
|
+
});
|
|
738
|
+
} else { html += '<p class="outlook-agent-card__lede">No journal entries.</p>'; }
|
|
739
|
+
|
|
740
|
+
return html;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
function renderRuntimeTab(health, logs, view) {
|
|
744
|
+
var html = '';
|
|
745
|
+
|
|
746
|
+
// Agent-level issues first — this is what "degraded" actually means
|
|
747
|
+
if (view && view.agent.degraded.status === 'degraded' && view.agent.degraded.issues.length) {
|
|
748
|
+
html += '<div class="outlook-kicker" style="margin-bottom:6px">Agent issues (' + view.agent.degraded.issues.length + ')</div>';
|
|
749
|
+
view.agent.degraded.issues.forEach(function(issue) {
|
|
750
|
+
html += '<div class="outlook-obligation-row" style="border-color:rgba(211,95,71,0.2)">' +
|
|
751
|
+
'<strong style="color:var(--outlook-fang)">' + escapeHtml(issue.code) + '</strong>' +
|
|
752
|
+
'<div style="color:var(--outlook-mist);font-size:0.82rem">' + escapeHtml(issue.detail) + '</div></div>';
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
// Agent identity / config
|
|
757
|
+
if (view) {
|
|
758
|
+
html += '<div class="outlook-kicker" style="margin:14px 0 6px">Agent config</div>';
|
|
759
|
+
html += '<div class="outlook-facts">' +
|
|
760
|
+
'<div class="outlook-fact"><span class="outlook-kicker">Provider</span><strong>' + escapeHtml(view.agent.provider || 'none') + '</strong></div>' +
|
|
761
|
+
'<div class="outlook-fact"><span class="outlook-kicker">Enabled</span><strong>' + (view.agent.enabled ? 'yes' : 'no') + '</strong></div>' +
|
|
762
|
+
'<div class="outlook-fact"><span class="outlook-kicker">Freshness</span><strong>' + escapeHtml(view.agent.freshness.status) + (view.agent.freshness.ageMs ? ' (' + Math.floor(view.agent.freshness.ageMs / 60000) + 'm)' : '') + '</strong></div>' +
|
|
763
|
+
'</div>';
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
html += '<div class="outlook-kicker" style="margin:14px 0 6px">Daemon health</div>';
|
|
767
|
+
if (health && health.status !== 'unavailable') {
|
|
768
|
+
html += '<div class="outlook-facts" style="margin-bottom:12px">' +
|
|
769
|
+
'<div class="outlook-fact"><span class="outlook-kicker">Status</span><strong>' + escapeHtml(health.status) + '</strong></div>' +
|
|
770
|
+
'<div class="outlook-fact"><span class="outlook-kicker">Mode</span><strong>' + escapeHtml(health.mode) + '</strong></div>' +
|
|
771
|
+
'<div class="outlook-fact"><span class="outlook-kicker">Uptime</span><strong>' + Math.floor(health.uptimeSeconds / 60) + 'm</strong></div>' +
|
|
772
|
+
'</div>';
|
|
773
|
+
if (health.degradedComponents && health.degradedComponents.length) {
|
|
774
|
+
html += '<div class="outlook-kicker" style="margin-bottom:4px">Degraded</div>';
|
|
775
|
+
health.degradedComponents.forEach(function(d) {
|
|
776
|
+
html += '<div class="outlook-obligation-row" style="border-color:rgba(211,95,71,0.2)">' +
|
|
777
|
+
'<strong style="color:var(--outlook-fang)">' + escapeHtml(d.component) + '</strong>' +
|
|
778
|
+
'<div style="color:var(--outlook-mist);font-size:0.82rem">' + escapeHtml(d.reason) + '</div></div>';
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
} else { html += '<p class="outlook-agent-card__lede">Health data unavailable.</p>'; }
|
|
782
|
+
|
|
783
|
+
html += '<div class="outlook-kicker" style="margin:14px 0 6px">Recent logs (' + (logs ? logs.totalLines : 0) + ' total)</div>';
|
|
784
|
+
if (logs && logs.entries && logs.entries.length) {
|
|
785
|
+
html += '<div style="max-height:400px;overflow-y:auto">';
|
|
786
|
+
logs.entries.slice(-30).reverse().forEach(function(e) {
|
|
787
|
+
var levelColor = e.level === 'error' ? 'var(--outlook-fang)' : e.level === 'warn' ? 'var(--outlook-gold)' : 'var(--outlook-mist)';
|
|
788
|
+
html += '<div style="padding:6px 0;border-bottom:1px solid rgba(110,160,117,0.08);font-size:0.78rem">' +
|
|
789
|
+
'<span style="color:' + levelColor + ';font-family:var(--outlook-font-mono);font-size:0.68rem">[' + escapeHtml(e.level) + ']</span> ' +
|
|
790
|
+
'<span style="color:var(--outlook-shadow);font-size:0.68rem">' + relTime(e.ts) + '</span> ' +
|
|
791
|
+
'<span style="color:var(--outlook-glow)">' + escapeHtml(e.event) + '</span> ' +
|
|
792
|
+
'<span style="color:var(--outlook-bone)">' + escapeHtml(truncate(e.message, 80)) + '</span></div>';
|
|
793
|
+
});
|
|
794
|
+
html += '</div>';
|
|
795
|
+
} else { html += '<p class="outlook-agent-card__lede">No log entries.</p>'; }
|
|
796
|
+
|
|
797
|
+
return html;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
function fetchSurface(name) {
|
|
801
|
+
if (cachedSurfaces[name]) return Promise.resolve(cachedSurfaces[name]);
|
|
802
|
+
var url = agentEndpointBase + encodeURIComponent(selectedAgent) + '/' + name;
|
|
803
|
+
return fetch(url, { headers: { accept: 'application/json' } })
|
|
804
|
+
.then(function(r) { return r.ok ? r.json() : null; })
|
|
805
|
+
.then(function(data) { cachedSurfaces[name] = data; return data; })
|
|
806
|
+
.catch(function() { return null; });
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
function renderTabContent(tabId, view) {
|
|
810
|
+
if (!panel) return;
|
|
811
|
+
var contentEl = panel.querySelector('[data-tab-content]');
|
|
812
|
+
if (!contentEl) return;
|
|
813
|
+
|
|
814
|
+
if (tabId === 'overview') {
|
|
815
|
+
contentEl.innerHTML = renderOverviewTab(view);
|
|
816
|
+
return;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
contentEl.innerHTML = '<div class="outlook-loading">Loading...</div>';
|
|
820
|
+
|
|
821
|
+
if (tabId === 'sessions') {
|
|
822
|
+
fetchSurface('sessions').then(function(data) { contentEl.innerHTML = renderSessionsTab(data); attachTranscriptListeners(contentEl); });
|
|
823
|
+
} else if (tabId === 'work') {
|
|
824
|
+
fetchSurface('coding').then(function(coding) { contentEl.innerHTML = renderWorkTab(view, coding); });
|
|
825
|
+
} else if (tabId === 'connections') {
|
|
826
|
+
Promise.all([fetchSurface('attention'), fetchSurface('bridges'), fetchSurface('friends')])
|
|
827
|
+
.then(function(results) { contentEl.innerHTML = renderConnectionsTab(results[0], results[1], results[2]); });
|
|
828
|
+
} else if (tabId === 'inner') {
|
|
829
|
+
fetchSurface('habits').then(function(habits) { contentEl.innerHTML = renderInnerTab(view, habits); });
|
|
830
|
+
} else if (tabId === 'memory') {
|
|
831
|
+
fetchSurface('memory').then(function(memory) { contentEl.innerHTML = renderMemoryTab(memory); });
|
|
832
|
+
} else if (tabId === 'runtime') {
|
|
833
|
+
Promise.all([
|
|
834
|
+
fetch(machineEndpoint.replace('/api/machine', '/api/machine/health'), { headers: { accept: 'application/json' } }).then(function(r) { return r.ok ? r.json() : null; }).catch(function() { return null; }),
|
|
835
|
+
fetch(machineEndpoint.replace('/api/machine', '/api/machine/logs'), { headers: { accept: 'application/json' } }).then(function(r) { return r.ok ? r.json() : null; }).catch(function() { return null; }),
|
|
836
|
+
]).then(function(results) { contentEl.innerHTML = renderRuntimeTab(results[0], results[1], view); });
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
function attachTranscriptListeners(container) {
|
|
841
|
+
container.querySelectorAll('.outlook-session-row').forEach(function(row) {
|
|
842
|
+
row.addEventListener('click', function(e) {
|
|
843
|
+
var transcriptEl = row.querySelector('.outlook-transcript');
|
|
844
|
+
if (!transcriptEl) return;
|
|
845
|
+
if (transcriptEl.classList.contains('is-visible')) {
|
|
846
|
+
transcriptEl.classList.remove('is-visible');
|
|
847
|
+
row.classList.remove('is-expanded');
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
var key = row.getAttribute('data-session-key');
|
|
851
|
+
if (!key) return;
|
|
852
|
+
row.classList.add('is-expanded');
|
|
853
|
+
transcriptEl.innerHTML = '<div class="outlook-loading">Loading transcript...</div>';
|
|
854
|
+
transcriptEl.classList.add('is-visible');
|
|
855
|
+
var parts = key.split('/');
|
|
856
|
+
var url = agentEndpointBase + encodeURIComponent(selectedAgent) + '/sessions/' +
|
|
857
|
+
encodeURIComponent(parts[0]) + '/' + encodeURIComponent(parts[1]) + '/' + encodeURIComponent(parts[2]);
|
|
858
|
+
fetch(url, { headers: { accept: 'application/json' } })
|
|
859
|
+
.then(function(r) { return r.ok ? r.json() : null; })
|
|
860
|
+
.then(function(data) {
|
|
861
|
+
if (data && data.messages) {
|
|
862
|
+
transcriptEl.innerHTML = renderTranscript(data.messages);
|
|
863
|
+
} else {
|
|
864
|
+
transcriptEl.innerHTML = '<p class="outlook-agent-card__lede">Could not load transcript.</p>';
|
|
865
|
+
}
|
|
866
|
+
})
|
|
867
|
+
.catch(function() { transcriptEl.innerHTML = '<p class="outlook-agent-card__lede">Error loading transcript.</p>'; });
|
|
868
|
+
});
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
function renderAgentPanel(view, isRefresh) {
|
|
873
|
+
if (!panel || !title || !subtitle) return;
|
|
874
|
+
if (!view) {
|
|
875
|
+
lastAgentView = null;
|
|
876
|
+
title.textContent = 'Choose an agent';
|
|
877
|
+
subtitle.textContent = 'Per-agent detail appears here as soon as you focus on one thread of the organism.';
|
|
878
|
+
panel.innerHTML = '<div class="outlook-agent-panel__empty"><strong>Choose an agent</strong><p>Select a visible agent from the left rail to inspect current work, obligations, senses, bridges, and inward pressure.</p></div>';
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
lastAgentView = view;
|
|
883
|
+
title.textContent = view.agent.agentName;
|
|
884
|
+
subtitle.textContent = view.agent.attention.label + ' · ' + view.activity.freshness.status + ' freshness';
|
|
885
|
+
|
|
886
|
+
if (isRefresh && panel.querySelector('.outlook-tabs')) {
|
|
887
|
+
// Preserve tab state — just refresh the current tab content
|
|
888
|
+
cachedSurfaces = {};
|
|
889
|
+
renderTabContent(activeTab, view);
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
panel.innerHTML = renderTabs() + '<div data-tab-content></div>';
|
|
894
|
+
|
|
895
|
+
panel.querySelector('.outlook-tabs').addEventListener('click', function(e) {
|
|
896
|
+
var btn = e.target.closest('.outlook-tab');
|
|
897
|
+
if (!btn) return;
|
|
898
|
+
activeTab = btn.getAttribute('data-tab');
|
|
899
|
+
panel.querySelectorAll('.outlook-tab').forEach(function(t) { t.classList.toggle('is-active', t.getAttribute('data-tab') === activeTab); });
|
|
900
|
+
cachedSurfaces = {};
|
|
901
|
+
renderTabContent(activeTab, view);
|
|
902
|
+
});
|
|
903
|
+
|
|
904
|
+
renderTabContent(activeTab, view);
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
function refreshMachine() {
|
|
908
|
+
if (!machineEndpoint) return Promise.resolve();
|
|
909
|
+
return fetch(machineEndpoint, { headers: { accept: 'application/json' } })
|
|
910
|
+
.then(function(r) { return r.ok ? r.json() : null; })
|
|
911
|
+
.then(function(next) {
|
|
912
|
+
if (!next) return;
|
|
913
|
+
machineView = next;
|
|
914
|
+
if (!selectedAgent && next.agents && next.agents[0]) setSelected(next.agents[0].agentName);
|
|
915
|
+
})
|
|
916
|
+
.catch(function() {});
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
function refreshAgent() {
|
|
920
|
+
if (!selectedAgent || !agentEndpointBase) { renderAgentPanel(null, false); return Promise.resolve(); }
|
|
921
|
+
return fetch(agentEndpointBase + encodeURIComponent(selectedAgent), { headers: { accept: 'application/json' } })
|
|
922
|
+
.then(function(r) { return r.ok ? r.json() : null; })
|
|
923
|
+
.then(function(view) { renderAgentPanel(view, !!lastAgentView); })
|
|
924
|
+
.catch(function() { renderAgentPanel(null, false); });
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
if (list) {
|
|
928
|
+
list.addEventListener('click', function(e) {
|
|
929
|
+
var target = e.target;
|
|
930
|
+
if (!(target instanceof Element)) return;
|
|
931
|
+
var button = target.closest('[data-agent-name]');
|
|
932
|
+
if (!(button instanceof HTMLElement)) return;
|
|
933
|
+
setSelected(button.getAttribute('data-agent-name') || '');
|
|
934
|
+
refreshAgent();
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
if (!selectedAgent && machineView && machineView.agents && machineView.agents[0]) {
|
|
939
|
+
setSelected(machineView.agents[0].agentName);
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
refreshAgent();
|
|
943
|
+
window.setInterval(refreshMachine, 20000);
|
|
944
|
+
window.setInterval(refreshAgent, 15000);
|
|
945
|
+
})();
|
|
946
|
+
`;
|
|
947
|
+
function renderOutlookApp(input) {
|
|
948
|
+
/* v8 ignore next */
|
|
949
|
+
(0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.outlook_render", message: "rendering outlook app", meta: {} });
|
|
950
|
+
const machineView = input.machineView;
|
|
951
|
+
const initialAgent = firstAgentName(machineView);
|
|
952
|
+
const productName = machineView?.overview.productName ?? input.machine.productName ?? outlook_types_1.OUTLOOK_PRODUCT_NAME;
|
|
953
|
+
const daemonMode = machineView?.overview.daemon?.mode ?? "production";
|
|
954
|
+
const freshnessStatus = machineView?.overview.freshness?.status ?? input.machine.freshness?.status ?? "unknown";
|
|
955
|
+
return [
|
|
956
|
+
"<!doctype html>",
|
|
957
|
+
"<html lang=\"en\">",
|
|
958
|
+
"<head>",
|
|
959
|
+
" <meta charset=\"utf-8\" />",
|
|
960
|
+
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />",
|
|
961
|
+
` <title>${escapeHtml(productName)}</title>`,
|
|
962
|
+
" <meta name=\"color-scheme\" content=\"dark\" />",
|
|
963
|
+
" <meta name=\"description\" content=\"Ouro Outlook is the daemon-hosted shared orientation surface for the agents alive on this machine.\" />",
|
|
964
|
+
` <style>${APP_CSS}</style>`,
|
|
965
|
+
"</head>",
|
|
966
|
+
`<body data-outlook-app="${escapeHtml(productName)}" data-machine-endpoint="${escapeHtml(`${input.origin}/outlook/api/machine`)}" data-agent-endpoint-base="${escapeHtml(`${input.origin}/outlook/api/agents/`)}" data-initial-agent="${escapeHtml(initialAgent)}">`,
|
|
967
|
+
" <div class=\"outlook-shell\">",
|
|
968
|
+
` <h1 class="outlook-sr-only">${escapeHtml(productName)}</h1>`,
|
|
969
|
+
" <header class=\"outlook-nav\">",
|
|
970
|
+
" <div class=\"outlook-wordmark\">",
|
|
971
|
+
" <span class=\"outlook-orb\" aria-hidden=\"true\"></span>",
|
|
972
|
+
" <div>",
|
|
973
|
+
` <p class="outlook-product">${escapeHtml(productName)}</p>`,
|
|
974
|
+
" <p class=\"outlook-subtitle\">Regain the plot together.</p>",
|
|
975
|
+
" </div>",
|
|
976
|
+
" </div>",
|
|
977
|
+
" <div class=\"outlook-nav-meta\">",
|
|
978
|
+
` <span class="outlook-badge">${escapeHtml(daemonMode)}</span>`,
|
|
979
|
+
` <span class="outlook-badge">${escapeHtml(freshnessStatus)}</span>`,
|
|
980
|
+
" </div>",
|
|
981
|
+
" </header>",
|
|
982
|
+
" <section class=\"outlook-hero\">",
|
|
983
|
+
" <div class=\"outlook-hero__grid\">",
|
|
984
|
+
" <div>",
|
|
985
|
+
" <span class=\"outlook-kicker\">Machine Overview</span>",
|
|
986
|
+
` <h1>${escapeHtml(productName)}</h1>`,
|
|
987
|
+
" <p>Where agents regain the plot together. The daemon keeps watch, and Outlook makes the body legible: runtime truth, active obligations, coding lanes, senses, bridges, habits, and inward pressure, all on the same living field.</p>",
|
|
988
|
+
" <div class=\"outlook-footer-note\">Daemon-hosted, loopback-only, direct-read, and read-only by design.</div>",
|
|
989
|
+
" </div>",
|
|
990
|
+
` <div class="outlook-stat-grid">${renderOverviewCards(machineView, input.machine)}</div>`,
|
|
991
|
+
" </div>",
|
|
992
|
+
" </section>",
|
|
993
|
+
" <section class=\"outlook-layout\">",
|
|
994
|
+
" <aside class=\"outlook-agents-rail\">",
|
|
995
|
+
" <div class=\"outlook-section\">",
|
|
996
|
+
" <span class=\"outlook-kicker\">Visible agents</span>",
|
|
997
|
+
" <h2>Choose a thread</h2>",
|
|
998
|
+
" <div class=\"outlook-agent-list\" data-outlook-agent-list>",
|
|
999
|
+
renderAgentButtons(machineView),
|
|
1000
|
+
" </div>",
|
|
1001
|
+
" </div>",
|
|
1002
|
+
" </aside>",
|
|
1003
|
+
" <main class=\"outlook-panel\">",
|
|
1004
|
+
" <div class=\"outlook-section\">",
|
|
1005
|
+
" <span class=\"outlook-kicker\">Machine facts</span>",
|
|
1006
|
+
" <h2>Current posture</h2>",
|
|
1007
|
+
` <div class="outlook-facts">${renderRuntimeFacts(machineView, input.machine)}</div>`,
|
|
1008
|
+
" </div>",
|
|
1009
|
+
" <div class=\"outlook-entrypoints-panel\">",
|
|
1010
|
+
" <span class=\"outlook-kicker\">Entrypoints</span>",
|
|
1011
|
+
renderEntrypoints(machineView, input.origin),
|
|
1012
|
+
" </div>",
|
|
1013
|
+
" <section class=\"outlook-agent-panel\">",
|
|
1014
|
+
" <span class=\"outlook-kicker\">Agent detail</span>",
|
|
1015
|
+
" <h2 data-outlook-agent-title>Choose an agent</h2>",
|
|
1016
|
+
" <p class=\"outlook-agent-card__lede\" data-outlook-agent-subtitle>Per-agent detail appears here as soon as you focus on one thread of the organism.</p>",
|
|
1017
|
+
" <div data-outlook-agent-panel>",
|
|
1018
|
+
" <div class=\"outlook-agent-panel__empty\">",
|
|
1019
|
+
" <strong>Choose an agent</strong>",
|
|
1020
|
+
" <p>Select a visible agent from the left rail to inspect current work, obligations, senses, bridges, and inward pressure.</p>",
|
|
1021
|
+
" </div>",
|
|
1022
|
+
" </div>",
|
|
1023
|
+
" </section>",
|
|
1024
|
+
" </main>",
|
|
1025
|
+
" </section>",
|
|
1026
|
+
" </div>",
|
|
1027
|
+
` <script id="outlook-machine-view" type="application/json">${escapeJsonForHtml(machineView ?? null)}</script>`,
|
|
1028
|
+
` <script>${APP_SCRIPT}</script>`,
|
|
1029
|
+
"</body>",
|
|
1030
|
+
"</html>",
|
|
1031
|
+
].join("\n");
|
|
1032
|
+
}
|