hoomanjs 1.58.1 → 1.60.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +2 -1
  2. package/dist/acp/acp-agent.js +17 -3
  3. package/dist/acp/acp-agent.js.map +1 -1
  4. package/dist/acp/approvals.js +11 -0
  5. package/dist/acp/approvals.js.map +1 -1
  6. package/dist/acp/meta/daemon.d.ts +12 -0
  7. package/dist/acp/meta/daemon.js +16 -0
  8. package/dist/acp/meta/daemon.js.map +1 -0
  9. package/dist/acp/meta/origin.d.ts +8 -0
  10. package/dist/acp/meta/origin.js +38 -0
  11. package/dist/acp/meta/origin.js.map +1 -0
  12. package/dist/acp/sessions/store.d.ts +6 -0
  13. package/dist/acp/sessions/store.js.map +1 -1
  14. package/dist/chat/components/StatusBar.js +1 -25
  15. package/dist/chat/components/StatusBar.js.map +1 -1
  16. package/dist/cli.js +143 -26
  17. package/dist/cli.js.map +1 -1
  18. package/dist/configure/app.js +1 -0
  19. package/dist/configure/app.js.map +1 -1
  20. package/dist/core/config.d.ts +29 -0
  21. package/dist/core/config.js +32 -0
  22. package/dist/core/config.js.map +1 -1
  23. package/dist/core/index.d.ts +7 -0
  24. package/dist/core/index.js +2 -1
  25. package/dist/core/index.js.map +1 -1
  26. package/dist/core/mcp/manager.d.ts +15 -0
  27. package/dist/core/mcp/manager.js +28 -0
  28. package/dist/core/mcp/manager.js.map +1 -1
  29. package/dist/core/mcp/prefixed-mcp-tool.d.ts +1 -0
  30. package/dist/core/mcp/prefixed-mcp-tool.js +1 -1
  31. package/dist/core/mcp/prefixed-mcp-tool.js.map +1 -1
  32. package/dist/core/skills/built-in/hooman-channels/SKILL.md +6 -6
  33. package/dist/core/skills/built-in/hooman-config/SKILL.md +35 -3
  34. package/dist/core/utils/usage-format.d.ts +4 -0
  35. package/dist/core/utils/usage-format.js +27 -0
  36. package/dist/core/utils/usage-format.js.map +1 -0
  37. package/dist/daemon/acp-client.d.ts +53 -0
  38. package/dist/daemon/acp-client.js +132 -0
  39. package/dist/daemon/acp-client.js.map +1 -0
  40. package/dist/daemon/approvals.d.ts +9 -2
  41. package/dist/daemon/approvals.js +151 -6
  42. package/dist/daemon/approvals.js.map +1 -1
  43. package/dist/daemon/attachments.d.ts +9 -0
  44. package/dist/daemon/attachments.js +63 -0
  45. package/dist/daemon/attachments.js.map +1 -0
  46. package/dist/daemon/dashboard/store.d.ts +36 -0
  47. package/dist/daemon/dashboard/store.js +290 -0
  48. package/dist/daemon/dashboard/store.js.map +1 -0
  49. package/dist/daemon/dashboard/types.d.ts +60 -0
  50. package/dist/daemon/dashboard/types.js +2 -0
  51. package/dist/daemon/dashboard/types.js.map +1 -0
  52. package/dist/daemon/index.d.ts +19 -6
  53. package/dist/daemon/index.js +181 -74
  54. package/dist/daemon/index.js.map +1 -1
  55. package/dist/daemon/mcproxy/catalog.d.ts +17 -0
  56. package/dist/daemon/mcproxy/catalog.js +71 -0
  57. package/dist/daemon/mcproxy/catalog.js.map +1 -0
  58. package/dist/daemon/mcproxy/http-server.d.ts +15 -0
  59. package/dist/daemon/mcproxy/http-server.js +150 -0
  60. package/dist/daemon/mcproxy/http-server.js.map +1 -0
  61. package/dist/daemon/mcproxy/index.d.ts +23 -0
  62. package/dist/daemon/mcproxy/index.js +23 -0
  63. package/dist/daemon/mcproxy/index.js.map +1 -0
  64. package/dist/daemon/mcproxy/session.d.ts +9 -0
  65. package/dist/daemon/mcproxy/session.js +24 -0
  66. package/dist/daemon/mcproxy/session.js.map +1 -0
  67. package/dist/daemon/queue.d.ts +14 -5
  68. package/dist/daemon/queue.js +40 -33
  69. package/dist/daemon/queue.js.map +1 -1
  70. package/dist/daemon/session-registry.d.ts +112 -0
  71. package/dist/daemon/session-registry.js +272 -0
  72. package/dist/daemon/session-registry.js.map +1 -0
  73. package/dist/daemon/session-store.d.ts +20 -0
  74. package/dist/daemon/session-store.js +63 -0
  75. package/dist/daemon/session-store.js.map +1 -0
  76. package/dist/daemon/ui/Card.d.ts +8 -0
  77. package/dist/daemon/ui/Card.js +52 -0
  78. package/dist/daemon/ui/Card.js.map +1 -0
  79. package/dist/daemon/ui/DaemonDashboardApp.d.ts +6 -0
  80. package/dist/daemon/ui/DaemonDashboardApp.js +75 -0
  81. package/dist/daemon/ui/DaemonDashboardApp.js.map +1 -0
  82. package/dist/daemon/ui/Footer.d.ts +3 -0
  83. package/dist/daemon/ui/Footer.js +7 -0
  84. package/dist/daemon/ui/Footer.js.map +1 -0
  85. package/dist/daemon/ui/Header.d.ts +4 -0
  86. package/dist/daemon/ui/Header.js +22 -0
  87. package/dist/daemon/ui/Header.js.map +1 -0
  88. package/dist/daemon/ui/Lane.d.ts +11 -0
  89. package/dist/daemon/ui/Lane.js +10 -0
  90. package/dist/daemon/ui/Lane.js.map +1 -0
  91. package/dist/daemon/ui/format.d.ts +7 -0
  92. package/dist/daemon/ui/format.js +67 -0
  93. package/dist/daemon/ui/format.js.map +1 -0
  94. package/dist/daemon/ui/index.d.ts +11 -0
  95. package/dist/daemon/ui/index.js +14 -0
  96. package/dist/daemon/ui/index.js.map +1 -0
  97. package/package.json +1 -1
  98. package/dist/daemon/questions.d.ts +0 -18
  99. package/dist/daemon/questions.js +0 -44
  100. package/dist/daemon/questions.js.map +0 -1
@@ -0,0 +1,63 @@
1
+ import { appendFile, mkdir, readFile } from "node:fs/promises";
2
+ import { dirname, join } from "node:path";
3
+ import { sessionsPath } from "../core/utils/paths.js";
4
+ const bindingsPath = () => join(sessionsPath(), "daemon", "bindings.jsonl");
5
+ function isCompleteBinding(entry) {
6
+ return (typeof entry.externalKey === "string" &&
7
+ typeof entry.acpSessionId === "string" &&
8
+ typeof entry.cwd === "string" &&
9
+ typeof entry.createdAt === "string" &&
10
+ typeof entry.updatedAt === "string");
11
+ }
12
+ /** Reads and folds the append-only bindings log; unparseable (torn) lines are skipped. */
13
+ export async function readDaemonSessionBindings() {
14
+ let raw;
15
+ try {
16
+ raw = await readFile(bindingsPath(), "utf8");
17
+ }
18
+ catch {
19
+ return new Map();
20
+ }
21
+ const folded = new Map();
22
+ for (const line of raw.split("\n")) {
23
+ const trimmed = line.trim();
24
+ if (!trimmed) {
25
+ continue;
26
+ }
27
+ let record;
28
+ try {
29
+ record = JSON.parse(trimmed);
30
+ }
31
+ catch {
32
+ continue;
33
+ }
34
+ if (!record || typeof record.externalKey !== "string") {
35
+ continue;
36
+ }
37
+ if (record.deleted) {
38
+ folded.delete(record.externalKey);
39
+ continue;
40
+ }
41
+ folded.set(record.externalKey, {
42
+ ...folded.get(record.externalKey),
43
+ ...record,
44
+ });
45
+ }
46
+ const entries = new Map();
47
+ for (const [key, entry] of folded) {
48
+ if (isCompleteBinding(entry)) {
49
+ entries.set(key, entry);
50
+ }
51
+ }
52
+ return entries;
53
+ }
54
+ /** Appends a full or partial binding patch; `updatedAt` is bumped unless the patch sets it. */
55
+ export async function patchDaemonSessionBinding(patch) {
56
+ const path = bindingsPath();
57
+ await mkdir(dirname(path), { recursive: true });
58
+ await appendFile(path, `${JSON.stringify({
59
+ ...patch,
60
+ updatedAt: patch.updatedAt ?? new Date().toISOString(),
61
+ })}\n`, "utf8");
62
+ }
63
+ //# sourceMappingURL=session-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-store.js","sourceRoot":"","sources":["../../src/daemon/session-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAsBtD,MAAM,YAAY,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC;AAE5E,SAAS,iBAAiB,CACxB,KAAoC;IAEpC,OAAO,CACL,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ;QACrC,OAAO,KAAK,CAAC,YAAY,KAAK,QAAQ;QACtC,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ;QAC7B,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ;QACnC,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,CACpC,CAAC;AACJ,CAAC;AAED,0FAA0F;AAC1F,MAAM,CAAC,KAAK,UAAU,yBAAyB;IAG7C,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,EAAE,MAAM,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,GAAG,EAAE,CAAC;IACnB,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAyC,CAAC;IAChE,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,SAAS;QACX,CAAC;QACD,IAAI,MAAqB,CAAC;QAC1B,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAkB,CAAC;QAChD,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,CAAC,WAAW,KAAK,QAAQ,EAAE,CAAC;YACtD,SAAS;QACX,CAAC;QACD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YAClC,SAAS;QACX,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE;YAC7B,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC;YACjC,GAAG,MAAM;SACV,CAAC,CAAC;IACL,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAgC,CAAC;IACxD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,EAAE,CAAC;QAClC,IAAI,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,+FAA+F;AAC/F,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,KAEC;IAED,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;IAC5B,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,MAAM,UAAU,CACd,IAAI,EACJ,GAAG,IAAI,CAAC,SAAS,CAAC;QAChB,GAAG,KAAK;QACR,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACvD,CAAC,IAAI,EACN,MAAM,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { DaemonSessionCard } from "../dashboard/types.js";
2
+ export type CardProps = {
3
+ card: DaemonSessionCard;
4
+ now: number;
5
+ width: number;
6
+ selected: boolean;
7
+ };
8
+ export declare function Card({ card, now, width, selected }: CardProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,52 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ import { theme } from "../../core/theme.js";
4
+ import { formatCostUsd, formatTokenCount, } from "../../core/utils/usage-format.js";
5
+ import { disposeReasonLabel, formatElapsed, originLabel, phaseLabel, sessionSuffix, } from "./format.js";
6
+ function phaseColor(card) {
7
+ if (card.errorMessage) {
8
+ return theme.error;
9
+ }
10
+ switch (card.phase) {
11
+ case "waiting_slot":
12
+ case "queued":
13
+ return theme.warning;
14
+ case "approval":
15
+ return theme.secondary;
16
+ default:
17
+ return theme.success;
18
+ }
19
+ }
20
+ function statusBadge(card) {
21
+ if (card.status === "in_progress") {
22
+ return `\u25cf ${phaseLabel(card.phase)}`;
23
+ }
24
+ if (card.status === "disposed") {
25
+ return `\u25cb ${disposeReasonLabel(card.disposeReason)}`;
26
+ }
27
+ return "idle";
28
+ }
29
+ export function Card({ card, now, width, selected }) {
30
+ const identity = card.title?.trim() || originLabel(card);
31
+ const suffix = sessionSuffix(card.acpSessionId);
32
+ const ageMs = card.status === "disposed" ? (card.disposedAt ?? now) : card.lastActiveAt;
33
+ const usage = card.usage;
34
+ const hasTokens = usage.inputTokens + usage.outputTokens > 0;
35
+ const contextPct = usage.contextSize && usage.contextSize > 0
36
+ ? Math.round(((usage.contextUsed ?? 0) / usage.contextSize) * 100)
37
+ : undefined;
38
+ return (_jsxs(Box, { flexDirection: "column", width: width, borderStyle: "round", borderColor: selected ? theme.primary : theme.muted, paddingX: 1, marginBottom: 1, children: [_jsxs(Text, { bold: true, color: selected ? theme.primary : undefined, wrap: "truncate", children: [identity, suffix ? (_jsxs(Text, { color: theme.muted, children: [" \u00b7 ", suffix] })) : null] }), _jsxs(Text, { children: [_jsx(Text, { color: phaseColor(card), children: statusBadge(card) }), _jsxs(Text, { color: theme.muted, children: [" \u00b7 ", formatElapsed(ageMs, now)] }), card.queueDepth > 1 ? (_jsx(Text, { color: theme.warning, children: ` \u00b7 q:${card.queueDepth - 1}` })) : null] }), card.errorMessage ? (_jsx(Text, { color: theme.error, wrap: "truncate-end", children: card.errorMessage })) : card.toolLabel ? (_jsxs(Text, { color: theme.secondary, wrap: "truncate-end", children: ["tool: ", card.toolLabel] })) : card.streamPreview ? (_jsx(Text, { wrap: "truncate-end", children: card.streamPreview })) : card.promptPreview ? (_jsx(Text, { color: theme.muted, wrap: "truncate-end", children: card.promptPreview })) : null, (() => {
39
+ const segments = [];
40
+ if (hasTokens) {
41
+ segments.push(`${formatTokenCount(usage.inputTokens)} in, ${formatTokenCount(usage.outputTokens)} out`);
42
+ }
43
+ if (contextPct !== undefined) {
44
+ segments.push(`ctx ${contextPct}%`);
45
+ }
46
+ if (usage.costUsd !== undefined) {
47
+ segments.push(formatCostUsd(usage.costUsd));
48
+ }
49
+ return segments.length > 0 ? (_jsx(Text, { color: theme.muted, wrap: "truncate-end", children: segments.join(" \u00b7 ") })) : null;
50
+ })()] }));
51
+ }
52
+ //# sourceMappingURL=Card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Card.js","sourceRoot":"","sources":["../../../src/daemon/ui/Card.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { DaemonDashboardStore } from "../dashboard/store.js";
2
+ export type DaemonDashboardAppProps = {
3
+ store: DaemonDashboardStore;
4
+ onQuit: () => void;
5
+ };
6
+ export declare function DaemonDashboardApp({ store, onQuit }: DaemonDashboardAppProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,75 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useState } from "react";
3
+ import { Box, Text, useInput, useStdout } from "ink";
4
+ import { theme } from "../../core/theme.js";
5
+ import { Footer } from "./Footer.js";
6
+ import { Header } from "./Header.js";
7
+ import { Lane } from "./Lane.js";
8
+ const WIDE_COLUMNS = 110;
9
+ const LANES = ["idle", "in_progress", "disposed"];
10
+ const LANE_TITLES = {
11
+ idle: "Idle",
12
+ in_progress: "In progress",
13
+ disposed: "Disposed",
14
+ };
15
+ const LANE_ACCENTS = {
16
+ idle: theme.secondary,
17
+ in_progress: theme.primary,
18
+ disposed: theme.muted,
19
+ };
20
+ function laneCards(snapshot, lane) {
21
+ if (lane === "idle") {
22
+ return snapshot.idle;
23
+ }
24
+ if (lane === "in_progress") {
25
+ return snapshot.inProgress;
26
+ }
27
+ return snapshot.disposed;
28
+ }
29
+ export function DaemonDashboardApp({ store, onQuit }) {
30
+ const [snapshot, setSnapshot] = useState(() => store.snapshot());
31
+ const [focusedLane, setFocusedLane] = useState(1);
32
+ const [showDiagnostics, setShowDiagnostics] = useState(false);
33
+ const { stdout } = useStdout();
34
+ const columns = stdout?.columns ?? 100;
35
+ const rows = stdout?.rows ?? 30;
36
+ useEffect(() => {
37
+ const unsubscribe = store.subscribe(() => setSnapshot(store.snapshot()));
38
+ const timer = setInterval(() => setSnapshot(store.snapshot()), 1000);
39
+ return () => {
40
+ unsubscribe();
41
+ clearInterval(timer);
42
+ };
43
+ }, [store]);
44
+ useInput((input, key) => {
45
+ if (input === "q" || (key.ctrl && input === "c")) {
46
+ onQuit();
47
+ return;
48
+ }
49
+ if (input === "l") {
50
+ setShowDiagnostics((prev) => !prev);
51
+ return;
52
+ }
53
+ if (key.leftArrow) {
54
+ setFocusedLane((prev) => (prev + LANES.length - 1) % LANES.length);
55
+ }
56
+ else if (key.rightArrow) {
57
+ setFocusedLane((prev) => (prev + 1) % LANES.length);
58
+ }
59
+ });
60
+ const wide = columns >= WIDE_COLUMNS;
61
+ const diagnosticRows = showDiagnostics
62
+ ? Math.min(8, snapshot.diagnostics.length + 1)
63
+ : 0;
64
+ const headerFooterRows = 7;
65
+ const availableRows = Math.max(4, rows - headerFooterRows - diagnosticRows);
66
+ const maxVisiblePerLane = Math.max(1, Math.floor(availableRows / 4));
67
+ return (_jsxs(Box, { flexDirection: "column", width: columns, children: [_jsx(Header, { snapshot: snapshot }), wide ? (_jsx(Box, { flexDirection: "row", gap: 1, children: LANES.map((lane) => (_jsx(Lane, { title: LANE_TITLES[lane], accent: LANE_ACCENTS[lane], cards: laneCards(snapshot, lane), now: snapshot.now, width: Math.floor(columns / 3) - 1, maxVisible: maxVisiblePerLane, selectedKey: undefined }, lane))) })) : (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: theme.muted, children: LANES.map((lane, index) => {
68
+ const active = index === focusedLane;
69
+ const label = `${LANE_TITLES[lane]} (${laneCards(snapshot, lane).length})`;
70
+ return active ? `[${label}] ` : `${label} `;
71
+ }).join("") }), _jsx(Lane, { title: LANE_TITLES[LANES[focusedLane]], accent: LANE_ACCENTS[LANES[focusedLane]], cards: laneCards(snapshot, LANES[focusedLane]), now: snapshot.now, width: columns - 1, maxVisible: maxVisiblePerLane * 2, selectedKey: undefined })] })), showDiagnostics ? (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.muted, paddingX: 1, children: [_jsx(Text, { bold: true, color: theme.muted, children: "Diagnostics" }), snapshot.diagnostics
72
+ .slice(-diagnosticRows + 1)
73
+ .map((line, index) => (_jsx(Text, { color: theme.muted, wrap: "truncate-end", children: line }, index)))] })) : null, _jsx(Footer, { showingDiagnostics: showDiagnostics })] }));
74
+ }
75
+ //# sourceMappingURL=DaemonDashboardApp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DaemonDashboardApp.js","sourceRoot":"","sources":["../../../src/daemon/ui/DaemonDashboardApp.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function Footer({ showingDiagnostics, }: {
2
+ showingDiagnostics: boolean;
3
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,7 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ import { theme } from "../../core/theme.js";
4
+ export function Footer({ showingDiagnostics, }) {
5
+ return (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: theme.muted, children: ["\u2191\u2193 select \u2190\u2192 lane L ", showingDiagnostics ? "hide" : "show", " diagnostics Q / Ctrl+C stop daemon"] }) }));
6
+ }
7
+ //# sourceMappingURL=Footer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Footer.js","sourceRoot":"","sources":["../../../src/daemon/ui/Footer.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAE5C,MAAM,UAAU,MAAM,CAAC,EACrB,kBAAkB,GAGnB;IACC,OAAO,CACL,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,MAAC,IAAI,IAAC,KAAK,EAAE,KAAK,CAAC,KAAK,aACrB,4CAA4C,EAC5C,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EACpC,sCAAsC,IAClC,GACH,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { DaemonDashboardSnapshot } from "../dashboard/types.js";
2
+ export declare function Header({ snapshot }: {
3
+ snapshot: DaemonDashboardSnapshot;
4
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ import { theme } from "../../core/theme.js";
4
+ import { formatCostUsd, formatTokenCount, } from "../../core/utils/usage-format.js";
5
+ import { formatElapsed } from "./format.js";
6
+ function childStateColor(state) {
7
+ switch (state) {
8
+ case "connected":
9
+ return theme.success;
10
+ case "reconnecting":
11
+ return theme.warning;
12
+ case "stopped":
13
+ return theme.error;
14
+ default:
15
+ return theme.muted;
16
+ }
17
+ }
18
+ export function Header({ snapshot }) {
19
+ const { aggregateUsage } = snapshot;
20
+ return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Text, { children: [_jsx(Text, { bold: true, color: theme.primary, children: "Hooman daemon" }), _jsx(Text, { color: theme.muted, children: ` ${snapshot.draining ? "draining" : "running"} \u00b7 uptime ${formatElapsed(snapshot.startedAt, snapshot.now)}` })] }), _jsxs(Text, { color: theme.muted, children: [`channels ${snapshot.channels.length || 0}`, " \u00b7 ", _jsxs(Text, { color: childStateColor(snapshot.acpChildState), children: ["acp ", snapshot.acpChildState] }), ` \u00b7 sessions ${snapshot.poolActive}/${snapshot.poolMax}`, snapshot.poolWaiting > 0 ? ` (+${snapshot.poolWaiting} waiting)` : "", ` \u00b7 queued ${snapshot.totalQueued}`, ` \u00b7 mcp ${snapshot.mcpServerCount}`] }), _jsxs(Text, { color: theme.muted, children: [`tokens ${formatTokenCount(aggregateUsage.inputTokens)} in / ${formatTokenCount(aggregateUsage.outputTokens)} out`, ` \u00b7 cost ${formatCostUsd(aggregateUsage.costUsd)}${aggregateUsage.costComplete ? "" : "+"}`] })] }));
21
+ }
22
+ //# sourceMappingURL=Header.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Header.js","sourceRoot":"","sources":["../../../src/daemon/ui/Header.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EACL,aAAa,EACb,gBAAgB,GACjB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,SAAS,eAAe,CACtB,KAA+C;IAE/C,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,WAAW;YACd,OAAO,KAAK,CAAC,OAAO,CAAC;QACvB,KAAK,cAAc;YACjB,OAAO,KAAK,CAAC,OAAO,CAAC;QACvB,KAAK,SAAS;YACZ,OAAO,KAAK,CAAC,KAAK,CAAC;QACrB;YACE,OAAO,KAAK,CAAC,KAAK,CAAC;IACvB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,EAAE,QAAQ,EAAyC;IACxE,MAAM,EAAE,cAAc,EAAE,GAAG,QAAQ,CAAC;IACpC,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,YAAY,EAAE,CAAC,aACzC,MAAC,IAAI,eACH,KAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAE,KAAK,CAAC,OAAO,8BAExB,EACP,KAAC,IAAI,IACH,KAAK,EAAE,KAAK,CAAC,KAAK,YAClB,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,kBAAkB,aAAa,CAAC,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,GAAQ,IACtH,EACP,MAAC,IAAI,IAAC,KAAK,EAAE,KAAK,CAAC,KAAK,aACrB,YAAY,QAAQ,CAAC,QAAQ,CAAC,MAAM,IAAI,CAAC,EAAE,EAC3C,UAAU,EACX,MAAC,IAAI,IAAC,KAAK,EAAE,eAAe,CAAC,QAAQ,CAAC,aAAa,CAAC,qBAC7C,QAAQ,CAAC,aAAa,IACtB,EACN,oBAAoB,QAAQ,CAAC,UAAU,IAAI,QAAQ,CAAC,OAAO,EAAE,EAC7D,QAAQ,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,WAAW,WAAW,CAAC,CAAC,CAAC,EAAE,EACrE,kBAAkB,QAAQ,CAAC,WAAW,EAAE,EACxC,eAAe,QAAQ,CAAC,cAAc,EAAE,IACpC,EACP,MAAC,IAAI,IAAC,KAAK,EAAE,KAAK,CAAC,KAAK,aACrB,UAAU,gBAAgB,CAAC,cAAc,CAAC,WAAW,CAAC,SAAS,gBAAgB,CAAC,cAAc,CAAC,YAAY,CAAC,MAAM,EAClH,gBAAgB,aAAa,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,IAC5F,IACH,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { DaemonSessionCard } from "../dashboard/types.js";
2
+ export type LaneProps = {
3
+ title: string;
4
+ cards: DaemonSessionCard[];
5
+ now: number;
6
+ width: number;
7
+ maxVisible: number;
8
+ selectedKey: string | undefined;
9
+ accent: string;
10
+ };
11
+ export declare function Lane({ title, cards, now, width, maxVisible, selectedKey, accent, }: LaneProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ import { theme } from "../../core/theme.js";
4
+ import { Card } from "./Card.js";
5
+ export function Lane({ title, cards, now, width, maxVisible, selectedKey, accent, }) {
6
+ const visible = cards.slice(0, maxVisible);
7
+ const hidden = cards.length - visible.length;
8
+ return (_jsxs(Box, { flexDirection: "column", width: width, children: [_jsx(Text, { bold: true, color: accent, children: `${title} \u00b7 ${cards.length}` }), visible.length === 0 ? (_jsx(Text, { color: theme.muted, children: "none" })) : (visible.map((card) => (_jsx(Card, { card: card, now: now, width: width - 1, selected: card.externalKey === selectedKey }, card.externalKey + (card.disposedAt ?? ""))))), hidden > 0 ? _jsxs(Text, { color: theme.muted, children: ["+", hidden, " more"] }) : null] }));
9
+ }
10
+ //# sourceMappingURL=Lane.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Lane.js","sourceRoot":"","sources":["../../../src/daemon/ui/Lane.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAE5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAYjC,MAAM,UAAU,IAAI,CAAC,EACnB,KAAK,EACL,KAAK,EACL,GAAG,EACH,KAAK,EACL,UAAU,EACV,WAAW,EACX,MAAM,GACI;IACV,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAC7C,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,KAAK,EAAE,KAAK,aACtC,KAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAE,MAAM,YACrB,GAAG,KAAK,WAAW,KAAK,CAAC,MAAM,EAAE,GAC7B,EACN,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CACtB,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,CAAC,KAAK,qBAAa,CACtC,CAAC,CAAC,CAAC,CACF,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACpB,KAAC,IAAI,IAEH,IAAI,EAAE,IAAI,EACV,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,KAAK,GAAG,CAAC,EAChB,QAAQ,EAAE,IAAI,CAAC,WAAW,KAAK,WAAW,IAJrC,IAAI,CAAC,WAAW,GAAG,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAK/C,CACH,CAAC,CACH,EACA,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAC,IAAI,IAAC,KAAK,EAAE,KAAK,CAAC,KAAK,kBAAI,MAAM,aAAa,CAAC,CAAC,CAAC,IAAI,IAChE,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { DaemonSessionCard, DaemonTurnPhase } from "../dashboard/types.js";
2
+ import type { DaemonDisposeReason } from "../session-registry.js";
3
+ export declare function formatElapsed(fromMs: number, nowMs: number): string;
4
+ export declare function phaseLabel(phase: DaemonTurnPhase | undefined): string;
5
+ export declare function disposeReasonLabel(reason: DaemonDisposeReason | undefined): string;
6
+ export declare function originLabel(card: DaemonSessionCard): string;
7
+ export declare function sessionSuffix(acpSessionId: string | undefined): string;
@@ -0,0 +1,67 @@
1
+ export function formatElapsed(fromMs, nowMs) {
2
+ const seconds = Math.max(0, Math.floor((nowMs - fromMs) / 1000));
3
+ if (seconds < 60) {
4
+ return `${seconds}s`;
5
+ }
6
+ const minutes = Math.floor(seconds / 60);
7
+ if (minutes < 60) {
8
+ return `${minutes}m ${seconds % 60}s`;
9
+ }
10
+ const hours = Math.floor(minutes / 60);
11
+ return `${hours}h ${minutes % 60}m`;
12
+ }
13
+ export function phaseLabel(phase) {
14
+ switch (phase) {
15
+ case "queued":
16
+ return "queued";
17
+ case "waiting_slot":
18
+ return "waiting for slot";
19
+ case "setting_up":
20
+ return "setting up session";
21
+ case "generating":
22
+ return "generating";
23
+ case "tool":
24
+ return "tool";
25
+ case "approval":
26
+ return "awaiting approval";
27
+ case "draining":
28
+ return "draining";
29
+ default:
30
+ return "active";
31
+ }
32
+ }
33
+ export function disposeReasonLabel(reason) {
34
+ switch (reason) {
35
+ case "idle_timeout":
36
+ return "idle timeout";
37
+ case "pool_pressure":
38
+ return "pool pressure";
39
+ case "shutdown":
40
+ return "shutdown";
41
+ case "child_exit":
42
+ return "acp child restart";
43
+ default:
44
+ return "closed";
45
+ }
46
+ }
47
+ export function originLabel(card) {
48
+ const origin = card.origin;
49
+ if (!origin) {
50
+ return card.externalKey;
51
+ }
52
+ const parts = [origin.server];
53
+ if (origin.thread) {
54
+ parts.push(`#${origin.thread}`);
55
+ }
56
+ else if (origin.session) {
57
+ parts.push(origin.session);
58
+ }
59
+ return parts.join(" \u00b7 ");
60
+ }
61
+ export function sessionSuffix(acpSessionId) {
62
+ if (!acpSessionId) {
63
+ return "";
64
+ }
65
+ return acpSessionId.slice(-6);
66
+ }
67
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../../src/daemon/ui/format.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,KAAa;IACzD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IACjE,IAAI,OAAO,GAAG,EAAE,EAAE,CAAC;QACjB,OAAO,GAAG,OAAO,GAAG,CAAC;IACvB,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC;IACzC,IAAI,OAAO,GAAG,EAAE,EAAE,CAAC;QACjB,OAAO,GAAG,OAAO,KAAK,OAAO,GAAG,EAAE,GAAG,CAAC;IACxC,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC;IACvC,OAAO,GAAG,KAAK,KAAK,OAAO,GAAG,EAAE,GAAG,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAkC;IAC3D,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,QAAQ;YACX,OAAO,QAAQ,CAAC;QAClB,KAAK,cAAc;YACjB,OAAO,kBAAkB,CAAC;QAC5B,KAAK,YAAY;YACf,OAAO,oBAAoB,CAAC;QAC9B,KAAK,YAAY;YACf,OAAO,YAAY,CAAC;QACtB,KAAK,MAAM;YACT,OAAO,MAAM,CAAC;QAChB,KAAK,UAAU;YACb,OAAO,mBAAmB,CAAC;QAC7B,KAAK,UAAU;YACb,OAAO,UAAU,CAAC;QACpB;YACE,OAAO,QAAQ,CAAC;IACpB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,MAAuC;IAEvC,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,cAAc;YACjB,OAAO,cAAc,CAAC;QACxB,KAAK,eAAe;YAClB,OAAO,eAAe,CAAC;QACzB,KAAK,UAAU;YACb,OAAO,UAAU,CAAC;QACpB,KAAK,YAAY;YACf,OAAO,mBAAmB,CAAC;QAC7B;YACE,OAAO,QAAQ,CAAC;IACpB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAuB;IACjD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC3B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IACD,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC9B,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,KAAK,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAClC,CAAC;SAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QAC1B,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,YAAgC;IAC5D,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { DaemonDashboardStore } from "../dashboard/store.js";
2
+ export type DaemonDashboardHandle = {
3
+ stop: () => void;
4
+ };
5
+ /**
6
+ * Renders the daemon dashboard into the normal terminal buffer. `onQuit`
7
+ * fires on `q` or Ctrl+C so the caller can trigger the same graceful
8
+ * shutdown path as SIGINT/SIGTERM; call `stop()` once daemon shutdown
9
+ * completes to unmount cleanly.
10
+ */
11
+ export declare function launchDaemonDashboard(store: DaemonDashboardStore, onQuit: () => void): DaemonDashboardHandle;
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { render } from "ink";
3
+ import { DaemonDashboardApp } from "./DaemonDashboardApp.js";
4
+ /**
5
+ * Renders the daemon dashboard into the normal terminal buffer. `onQuit`
6
+ * fires on `q` or Ctrl+C so the caller can trigger the same graceful
7
+ * shutdown path as SIGINT/SIGTERM; call `stop()` once daemon shutdown
8
+ * completes to unmount cleanly.
9
+ */
10
+ export function launchDaemonDashboard(store, onQuit) {
11
+ const { unmount } = render(_jsx(DaemonDashboardApp, { store: store, onQuit: onQuit }), { exitOnCtrlC: false });
12
+ return { stop: unmount };
13
+ }
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/daemon/ui/index.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAE7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAM7D;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CACnC,KAA2B,EAC3B,MAAkB;IAElB,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CACxB,KAAC,kBAAkB,IAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,GAAI,EACpD,EAAE,WAAW,EAAE,KAAK,EAAE,CACvB,CAAC;IACF,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC3B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hoomanjs",
3
- "version": "1.58.1",
3
+ "version": "1.60.0",
4
4
  "description": "Full-stack open-source agentic ecosystem — local-first CLI, VS Code, ACP, daemon channels, and Design mode. BYOK, custom inference endpoints, llama.cpp & MLX.",
5
5
  "author": {
6
6
  "name": "Vaibhav Pandey",
@@ -1,18 +0,0 @@
1
- import type { Manager as McpManager } from "../core/mcp/index.js";
2
- import type { AskUserBackend } from "../core/tools/ask-user.js";
3
- /**
4
- * `ask_user` backend for channel-driven daemon jobs: relays the question to
5
- * the originating MCP server over the `hooman/channel/ask` capability (the
6
- * question-flavoured sibling of `hooman/channel/permission`), so the server
7
- * can surface it wherever the human actually is — a Slack thread, a Telegram
8
- * chat, etc. — and post the answer back.
9
- *
10
- * Jobs without a channel origin, and servers that don't advertise the
11
- * capability, report "unavailable" so the model proceeds on its own
12
- * judgement, matching daemon behaviour before this backend existed.
13
- */
14
- export declare function createDaemonAskUserBackend(manager: McpManager, agent: {
15
- appState: {
16
- get(key: string): unknown;
17
- };
18
- }): AskUserBackend;
@@ -1,44 +0,0 @@
1
- import { readChannelOrigin } from "../core/approvals/channel-ask.js";
2
- /**
3
- * `ask_user` backend for channel-driven daemon jobs: relays the question to
4
- * the originating MCP server over the `hooman/channel/ask` capability (the
5
- * question-flavoured sibling of `hooman/channel/permission`), so the server
6
- * can surface it wherever the human actually is — a Slack thread, a Telegram
7
- * chat, etc. — and post the answer back.
8
- *
9
- * Jobs without a channel origin, and servers that don't advertise the
10
- * capability, report "unavailable" so the model proceeds on its own
11
- * judgement, matching daemon behaviour before this backend existed.
12
- */
13
- export function createDaemonAskUserBackend(manager, agent) {
14
- return {
15
- ask: async (request) => {
16
- const origin = readChannelOrigin(agent);
17
- if (!origin?.server) {
18
- return { kind: "unavailable" };
19
- }
20
- const supported = await manager
21
- .supportsChannelAsk(origin.server)
22
- .catch(() => false);
23
- if (!supported) {
24
- return { kind: "unavailable" };
25
- }
26
- try {
27
- return await manager.requestChannelAsk(origin.server, {
28
- requestId: crypto.randomUUID(),
29
- question: request.question,
30
- options: request.options,
31
- source: origin.source,
32
- user: origin.user,
33
- session: origin.session,
34
- thread: origin.thread,
35
- }, { signal: request.signal });
36
- }
37
- catch {
38
- // Relay failed or timed out; let the model proceed on its own.
39
- return { kind: "unavailable" };
40
- }
41
- },
42
- };
43
- }
44
- //# sourceMappingURL=questions.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"questions.js","sourceRoot":"","sources":["../../src/daemon/questions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAIrE;;;;;;;;;;GAUG;AACH,MAAM,UAAU,0BAA0B,CACxC,OAAmB,EACnB,KAAkD;IAElD,OAAO;QACL,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YACrB,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;YACxC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;gBACpB,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;YACjC,CAAC;YACD,MAAM,SAAS,GAAG,MAAM,OAAO;iBAC5B,kBAAkB,CAAC,MAAM,CAAC,MAAM,CAAC;iBACjC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;YACtB,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;YACjC,CAAC;YACD,IAAI,CAAC;gBACH,OAAO,MAAM,OAAO,CAAC,iBAAiB,CACpC,MAAM,CAAC,MAAM,EACb;oBACE,SAAS,EAAE,MAAM,CAAC,UAAU,EAAE;oBAC9B,QAAQ,EAAE,OAAO,CAAC,QAAQ;oBAC1B,OAAO,EAAE,OAAO,CAAC,OAAO;oBACxB,MAAM,EAAE,MAAM,CAAC,MAAM;oBACrB,IAAI,EAAE,MAAM,CAAC,IAAI;oBACjB,OAAO,EAAE,MAAM,CAAC,OAAO;oBACvB,MAAM,EAAE,MAAM,CAAC,MAAM;iBACtB,EACD,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAC3B,CAAC;YACJ,CAAC;YAAC,MAAM,CAAC;gBACP,+DAA+D;gBAC/D,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;YACjC,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}