nfo-cli 0.0.3 → 0.0.5

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 (173) hide show
  1. package/dist/claude-command.js +6 -1
  2. package/dist/claude-command.js.map +1 -1
  3. package/dist/claude-trust.js +46 -0
  4. package/dist/claude-trust.js.map +1 -0
  5. package/dist/cli.js +64 -54
  6. package/dist/cli.js.map +1 -1
  7. package/dist/commands/restore.js +0 -1
  8. package/dist/commands/restore.js.map +1 -1
  9. package/dist/commands/tui.js +6 -4
  10. package/dist/commands/tui.js.map +1 -1
  11. package/dist/mcp/handlers.js +5 -0
  12. package/dist/mcp/handlers.js.map +1 -1
  13. package/dist/mcp/tool-defs.js +10 -0
  14. package/dist/mcp/tool-defs.js.map +1 -1
  15. package/dist/musicians/dismiss.js +1 -1
  16. package/dist/musicians/dismiss.js.map +1 -1
  17. package/dist/musicians/roles.js +15 -0
  18. package/dist/musicians/roles.js.map +1 -0
  19. package/dist/musicians/spawn.js +53 -18
  20. package/dist/musicians/spawn.js.map +1 -1
  21. package/dist/permission.js +14 -8
  22. package/dist/permission.js.map +1 -1
  23. package/dist/prompts/musician-role.js +2 -1
  24. package/dist/prompts/musician-role.js.map +1 -1
  25. package/dist/prompts/orchestrator-role.js +42 -8
  26. package/dist/prompts/orchestrator-role.js.map +1 -1
  27. package/dist/prompts/tool-discipline.js +10 -0
  28. package/dist/prompts/tool-discipline.js.map +1 -1
  29. package/dist/tui/{App.js → components/App.js} +20 -20
  30. package/dist/tui/components/App.js.map +1 -0
  31. package/dist/tui/components/AppView.js +13 -0
  32. package/dist/tui/components/AppView.js.map +1 -0
  33. package/dist/tui/{Auditorium.js → components/Auditorium.js} +2 -2
  34. package/dist/tui/components/Auditorium.js.map +1 -0
  35. package/dist/tui/components/ConcertHall.js.map +1 -0
  36. package/dist/tui/{Help.js → components/Help.js} +0 -8
  37. package/dist/tui/components/Help.js.map +1 -0
  38. package/dist/tui/components/OrchestratorPane.js.map +1 -0
  39. package/dist/tui/components/SidebarHeader.js +6 -0
  40. package/dist/tui/components/SidebarHeader.js.map +1 -0
  41. package/dist/tui/{StatusBar.js → components/StatusBar.js} +1 -1
  42. package/dist/tui/components/StatusBar.js.map +1 -0
  43. package/package.json +8 -1
  44. package/assets/agent-screen.png +0 -0
  45. package/assets/main-screen.png +0 -0
  46. package/assets/orche-clawd.png +0 -0
  47. package/dist/tui/App.js.map +0 -1
  48. package/dist/tui/AppView.js +0 -13
  49. package/dist/tui/AppView.js.map +0 -1
  50. package/dist/tui/Auditorium.js.map +0 -1
  51. package/dist/tui/ConcertHall.js.map +0 -1
  52. package/dist/tui/Help.js.map +0 -1
  53. package/dist/tui/OrchestratorPane.js.map +0 -1
  54. package/dist/tui/SidebarHeader.js +0 -6
  55. package/dist/tui/SidebarHeader.js.map +0 -1
  56. package/dist/tui/StatusBar.js.map +0 -1
  57. package/docs/plans/2026-05-29-nfo-phase-1-bootstrap.md +0 -2152
  58. package/docs/plans/2026-05-29-nfo-phase-2-mcp-musicians.md +0 -2467
  59. package/docs/plans/2026-05-29-nfo-phase-3-ink-tui.md +0 -1611
  60. package/docs/plans/2026-05-29-nfo-phase-4-permission-prompts.md +0 -460
  61. package/docs/plans/2026-05-29-nfo-phase-5-help-and-notify.md +0 -933
  62. package/docs/specs/2026-05-29-nfo-design.md +0 -468
  63. package/src/claude-command.ts +0 -35
  64. package/src/claude-detect.ts +0 -42
  65. package/src/cli.ts +0 -164
  66. package/src/commands/attach.ts +0 -24
  67. package/src/commands/dashboard-window.ts +0 -33
  68. package/src/commands/kill.ts +0 -50
  69. package/src/commands/launch.ts +0 -134
  70. package/src/commands/list.ts +0 -43
  71. package/src/commands/mcp-server.ts +0 -18
  72. package/src/commands/notes.ts +0 -18
  73. package/src/commands/restore.ts +0 -153
  74. package/src/commands/tui.tsx +0 -16
  75. package/src/config.ts +0 -44
  76. package/src/dashboard.ts +0 -1
  77. package/src/mcp/config.ts +0 -39
  78. package/src/mcp/handlers.ts +0 -141
  79. package/src/mcp/server.ts +0 -50
  80. package/src/mcp/tool-defs.ts +0 -151
  81. package/src/musicians/dismiss.ts +0 -60
  82. package/src/musicians/ids.ts +0 -21
  83. package/src/musicians/lookup.ts +0 -13
  84. package/src/musicians/message-log.ts +0 -152
  85. package/src/musicians/message.ts +0 -99
  86. package/src/musicians/query.ts +0 -19
  87. package/src/musicians/spawn.ts +0 -139
  88. package/src/notes.ts +0 -39
  89. package/src/notify.ts +0 -62
  90. package/src/orchestrator/report-back.ts +0 -33
  91. package/src/permission.ts +0 -30
  92. package/src/project-key.ts +0 -12
  93. package/src/prompts/musician-role.ts +0 -22
  94. package/src/prompts/orchestrator-role.ts +0 -60
  95. package/src/prompts/tool-discipline.ts +0 -35
  96. package/src/repo.ts +0 -14
  97. package/src/shell-quote.ts +0 -7
  98. package/src/state-updaters.ts +0 -132
  99. package/src/state.ts +0 -49
  100. package/src/state.types.ts +0 -67
  101. package/src/tmux.ts +0 -226
  102. package/src/tui/App.tsx +0 -532
  103. package/src/tui/AppView.tsx +0 -96
  104. package/src/tui/Auditorium.tsx +0 -56
  105. package/src/tui/ConcertHall.tsx +0 -31
  106. package/src/tui/Help.tsx +0 -72
  107. package/src/tui/OrchestratorPane.tsx +0 -98
  108. package/src/tui/SidebarHeader.tsx +0 -32
  109. package/src/tui/StatusBar.tsx +0 -44
  110. package/src/tui/activity-line.ts +0 -16
  111. package/src/tui/detect-permission.ts +0 -93
  112. package/src/tui/embedded-session-lifecycle.ts +0 -44
  113. package/src/tui/embedded-terminal.ts +0 -325
  114. package/src/tui/format-time.ts +0 -25
  115. package/src/tui/keymap.ts +0 -104
  116. package/src/tui/poll-activity.ts +0 -25
  117. package/src/tui/poll-idle.ts +0 -149
  118. package/src/tui/poll-permission.ts +0 -50
  119. package/src/tui/status-icon.ts +0 -35
  120. package/src/tui/terminal-input.ts +0 -136
  121. package/src/tui/watch-state.ts +0 -43
  122. package/src/worktree.ts +0 -41
  123. package/tests/claude-command.test.ts +0 -30
  124. package/tests/claude-detect.test.ts +0 -14
  125. package/tests/commands/attach.test.ts +0 -60
  126. package/tests/commands/kill.test.ts +0 -66
  127. package/tests/commands/launch.test.ts +0 -75
  128. package/tests/commands/list.test.ts +0 -47
  129. package/tests/commands/notes.test.ts +0 -53
  130. package/tests/commands/restore.test.ts +0 -126
  131. package/tests/helpers/tmp-config.ts +0 -16
  132. package/tests/helpers/tmp-repo.ts +0 -29
  133. package/tests/integration/orchestrator-spawn.test.ts +0 -108
  134. package/tests/mcp/handlers.test.ts +0 -163
  135. package/tests/mcp/tool-defs.test.ts +0 -35
  136. package/tests/musicians/dismiss.test.ts +0 -102
  137. package/tests/musicians/message.test.ts +0 -159
  138. package/tests/musicians/query.test.ts +0 -65
  139. package/tests/musicians/spawn.test.ts +0 -125
  140. package/tests/notes.test.ts +0 -56
  141. package/tests/notify.test.ts +0 -80
  142. package/tests/orchestrator/report-back.test.ts +0 -18
  143. package/tests/permission.test.ts +0 -29
  144. package/tests/project-key.test.ts +0 -33
  145. package/tests/prompts/tool-discipline.test.ts +0 -25
  146. package/tests/repo.test.ts +0 -38
  147. package/tests/state-updaters.test.ts +0 -126
  148. package/tests/state.test.ts +0 -85
  149. package/tests/tmux.test.ts +0 -126
  150. package/tests/tui/AppView.test.tsx +0 -92
  151. package/tests/tui/Auditorium.test.tsx +0 -67
  152. package/tests/tui/ConcertHall.test.tsx +0 -22
  153. package/tests/tui/Help.test.tsx +0 -38
  154. package/tests/tui/OrchestratorPane.test.ts +0 -30
  155. package/tests/tui/SidebarHeader.test.tsx +0 -20
  156. package/tests/tui/StatusBar.test.tsx +0 -51
  157. package/tests/tui/activity-line.test.ts +0 -21
  158. package/tests/tui/detect-permission.test.ts +0 -92
  159. package/tests/tui/embedded-session-lifecycle.test.ts +0 -55
  160. package/tests/tui/embedded-terminal.test.ts +0 -80
  161. package/tests/tui/format-time.test.ts +0 -25
  162. package/tests/tui/keymap.test.ts +0 -93
  163. package/tests/tui/poll-activity.test.ts +0 -81
  164. package/tests/tui/poll-idle.test.ts +0 -159
  165. package/tests/tui/poll-permission.test.ts +0 -222
  166. package/tests/tui/status-icon.test.ts +0 -27
  167. package/tests/tui/terminal-input.test.ts +0 -113
  168. package/tests/tui/watch-state.test.ts +0 -54
  169. package/tests/worktree.test.ts +0 -73
  170. package/tsconfig.json +0 -19
  171. package/vitest.config.ts +0 -12
  172. /package/dist/tui/{ConcertHall.js → components/ConcertHall.js} +0 -0
  173. /package/dist/tui/{OrchestratorPane.js → components/OrchestratorPane.js} +0 -0
@@ -1,31 +0,0 @@
1
- import type { ReactElement } from "react";
2
- import { Box, Text } from "ink";
3
- import type { OrchestraSummary } from "../commands/list.js";
4
-
5
- export interface ConcertHallProps {
6
- orchestras: OrchestraSummary[];
7
- currentId: string;
8
- }
9
-
10
- export function ConcertHall(props: ConcertHallProps): ReactElement {
11
- return (
12
- <Box
13
- flexDirection="column"
14
- borderStyle="single"
15
- borderBottom={true}
16
- paddingX={1}
17
- >
18
- <Text bold={true}>Concert Hall</Text>
19
- {props.orchestras.map((o) => {
20
- const current = o.id === props.currentId;
21
- const marker = current ? "▸" : " ";
22
- const dot = o.running ? "●" : "○";
23
- return (
24
- <Text key={o.id} bold={current}>
25
- {marker} {dot} {o.id} ({o.musician_count})
26
- </Text>
27
- );
28
- })}
29
- </Box>
30
- );
31
- }
package/src/tui/Help.tsx DELETED
@@ -1,72 +0,0 @@
1
- import type { ReactElement } from "react";
2
- import { Box, Text } from "ink";
3
-
4
- interface Row {
5
- key: string;
6
- label: string;
7
- }
8
-
9
- const ROWS: Row[] = [
10
- { key: "↑ / k", label: "move selection up" },
11
- { key: "↓ / j", label: "move selection down" },
12
- { key: "Enter", label: "open the selected target in the left pane" },
13
- { key: "n", label: "open notes for this orchestra" },
14
- {
15
- key: "d",
16
- label:
17
- "arm dismiss for selected Musician (press d again / y / Enter to confirm)",
18
- },
19
- { key: "n / Esc", label: "cancel pending dismiss confirmation" },
20
- { key: "p", label: "jump to next Musician awaiting permission" },
21
- {
22
- key: "q",
23
- label:
24
- "detach this tmux client from NFO without killing the orchestra session",
25
- },
26
- {
27
- key: "Ctrl+g",
28
- label: "switch focus between the sidebar and the embedded Claude terminal",
29
- },
30
- {
31
- key: "typed keys",
32
- label:
33
- "go directly to the currently open tmux terminal while the left pane is focused",
34
- },
35
- {
36
- key: "Alt+Enter / Shift+Enter / Ctrl+J",
37
- label:
38
- "insert a newline in the focused terminal without treating it like Enter",
39
- },
40
- {
41
- key: "Mouse wheel",
42
- label:
43
- "scroll the left terminal through local scrollback when the pointer is over that pane",
44
- },
45
- {
46
- key: "F6",
47
- label: "tmux global key: jump to the dashboard window from any NFO window",
48
- },
49
- {
50
- key: "F7",
51
- label:
52
- "tmux global key: jump to the Orchestrator window from any NFO window",
53
- },
54
- { key: "?", label: "toggle this help / close" },
55
- ];
56
-
57
- export function Help(): ReactElement {
58
- return (
59
- <Box flexDirection="column" paddingX={1}>
60
- <Text bold={true}>Keybindings</Text>
61
- {ROWS.map((row) => {
62
- return (
63
- <Text key={row.key}>
64
- <Text color="cyan">{row.key.padEnd(8)}</Text>
65
- <Text> {row.label}</Text>
66
- </Text>
67
- );
68
- })}
69
- <Text dimColor={true}>Press ? to close.</Text>
70
- </Box>
71
- );
72
- }
@@ -1,98 +0,0 @@
1
- import type { ReactElement } from "react";
2
- import { Box, Text } from "ink";
3
- import type {
4
- EmbeddedTerminalLine,
5
- EmbeddedTerminalSpan,
6
- } from "./embedded-terminal.js";
7
-
8
- export interface OrchestratorPaneProps {
9
- title: string;
10
- lines: EmbeddedTerminalLine[];
11
- focused: boolean;
12
- connected: boolean;
13
- }
14
-
15
- export function resolveSpanStyle(
16
- span: EmbeddedTerminalSpan,
17
- focused: boolean,
18
- ): Omit<EmbeddedTerminalSpan, "text" | "cursor"> {
19
- const style: Omit<EmbeddedTerminalSpan, "text" | "cursor"> = {
20
- color: span.color,
21
- backgroundColor: span.backgroundColor,
22
- dimColor: span.dimColor,
23
- bold: span.bold,
24
- italic: span.italic,
25
- underline: span.underline,
26
- strikethrough: span.strikethrough,
27
- inverse: span.inverse,
28
- };
29
- if (span.cursor === true && focused) {
30
- style.color = "black";
31
- style.backgroundColor = "white";
32
- style.inverse = false;
33
- }
34
- return style;
35
- }
36
-
37
- function renderSpan(
38
- span: EmbeddedTerminalSpan,
39
- index: number,
40
- focused: boolean,
41
- ): ReactElement {
42
- const style = resolveSpanStyle(span, focused);
43
- return (
44
- <Text
45
- key={`${index}:${span.text}`}
46
- color={style.color}
47
- backgroundColor={style.backgroundColor}
48
- dimColor={style.dimColor}
49
- bold={style.bold}
50
- italic={style.italic}
51
- underline={style.underline}
52
- strikethrough={style.strikethrough}
53
- inverse={style.inverse}
54
- >
55
- {span.text}
56
- </Text>
57
- );
58
- }
59
-
60
- export function OrchestratorPane(props: OrchestratorPaneProps): ReactElement {
61
- return (
62
- <Box
63
- flexGrow={1}
64
- flexDirection="column"
65
- borderStyle="single"
66
- marginRight={1}
67
- minHeight={16}
68
- paddingX={1}
69
- >
70
- <Text bold={true}>{props.title}</Text>
71
- <Box flexDirection="column" flexGrow={1}>
72
- {props.lines.length > 0 ? (
73
- props.lines.map((line, index) => {
74
- return (
75
- <Text key={String(index)} wrap="truncate-end">
76
- {line.spans.length > 0
77
- ? line.spans.map((span, spanIndex) =>
78
- renderSpan(span, spanIndex, props.focused),
79
- )
80
- : " "}
81
- </Text>
82
- );
83
- })
84
- ) : (
85
- <Text dimColor={true}>Waiting for Claude terminal…</Text>
86
- )}
87
- </Box>
88
- <Text color={props.focused ? "cyan" : "gray"} wrap="truncate-end">
89
- {props.focused
90
- ? "[Ctrl+g] sidebar · [Mouse wheel] scroll"
91
- : "[Ctrl+g] focus left terminal"}
92
- </Text>
93
- {!props.connected ? (
94
- <Text color="yellow">Embedded tmux client disconnected.</Text>
95
- ) : null}
96
- </Box>
97
- );
98
- }
@@ -1,32 +0,0 @@
1
- import type { ReactElement } from "react";
2
- import { Box, Text } from "ink";
3
-
4
- export interface SidebarHeaderProps {
5
- orchestraId: string;
6
- musicianCount: number;
7
- pendingCount: number;
8
- }
9
-
10
- export function SidebarHeader(props: SidebarHeaderProps): ReactElement {
11
- return (
12
- <Box
13
- flexDirection="column"
14
- borderStyle="single"
15
- borderBottom={true}
16
- paddingX={1}
17
- >
18
- <Text bold={true}>No Fluff Orchestra · {props.orchestraId}</Text>
19
- {props.pendingCount > 0 ? (
20
- <Text color="yellow">
21
- {props.musicianCount} musicians · {props.pendingCount} awaiting
22
- permission
23
- </Text>
24
- ) : (
25
- <Text dimColor={true}>
26
- {props.musicianCount} musicians · {props.pendingCount} awaiting
27
- permission
28
- </Text>
29
- )}
30
- </Box>
31
- );
32
- }
@@ -1,44 +0,0 @@
1
- import type { ReactElement } from "react";
2
- import { Box, Text } from "ink";
3
-
4
- export interface StatusBarProps {
5
- permissionLevel: string;
6
- tokenHint: string;
7
- pendingCount: number;
8
- dismissConfirmation?: string | null;
9
- orchestratorFocused: boolean;
10
- }
11
-
12
- export function StatusBar(props: StatusBarProps): ReactElement {
13
- return (
14
- <Box
15
- flexDirection="column"
16
- borderStyle="single"
17
- borderTop={true}
18
- paddingX={1}
19
- >
20
- {props.pendingCount > 0 ? (
21
- <Text color="yellow">
22
- ⚠ {props.pendingCount} awaiting permission · [p] jump to next
23
- </Text>
24
- ) : null}
25
- {props.dismissConfirmation ? (
26
- <Text color="red">{props.dismissConfirmation}</Text>
27
- ) : null}
28
- <Text>
29
- {props.permissionLevel} · {props.tokenHint}
30
- </Text>
31
- {props.orchestratorFocused ? (
32
- <Text dimColor={true}>[type] active terminal [Ctrl+g] sidebar</Text>
33
- ) : (
34
- <Text dimColor={true}>
35
- [↑↓] nav [⏎] open left pane [d] dismiss [p] pending [n] notes [Ctrl+g]
36
- terminal
37
- </Text>
38
- )}
39
- <Text dimColor={true}>
40
- [q] detach [F6] dashboard [F7] orchestrator [?] help
41
- </Text>
42
- </Box>
43
- );
44
- }
@@ -1,16 +0,0 @@
1
- const MAX_LEN = 60;
2
-
3
- export function extractActivityLine(paneText: string): string {
4
- const lines = paneText.split('\n');
5
- let last = '';
6
- for (const line of lines) {
7
- const trimmed = line.trim();
8
- if (trimmed.length > 0) {
9
- last = trimmed;
10
- }
11
- }
12
- if (last.length > MAX_LEN) {
13
- return last.slice(0, MAX_LEN - 1) + '…';
14
- }
15
- return last;
16
- }
@@ -1,93 +0,0 @@
1
- const LAST_N_LINES = 20;
2
- const MAX_TOOL_LEN = 60;
3
-
4
- const INTRO_PATTERNS: RegExp[] = [
5
- /allow\s+\S+/i,
6
- /do you want to/i,
7
- /permission required/i,
8
- /use this tool/i,
9
- ];
10
-
11
- export interface PermissionDetection {
12
- pending: boolean;
13
- tool: string | null;
14
- }
15
-
16
- function hasYesLine(lines: string[]): boolean {
17
- for (const line of lines) {
18
- const trimmed = line.trimStart();
19
- if (trimmed.startsWith('1.') || trimmed.startsWith('1)')) {
20
- return true;
21
- }
22
- }
23
- return false;
24
- }
25
-
26
- function hasNoLine(lines: string[]): boolean {
27
- for (const line of lines) {
28
- const trimmed = line.trimStart();
29
- const startsWithSmallDigit =
30
- trimmed.startsWith('2.') ||
31
- trimmed.startsWith('2)') ||
32
- trimmed.startsWith('3.') ||
33
- trimmed.startsWith('3)');
34
- if (startsWithSmallDigit && trimmed.includes('No')) {
35
- return true;
36
- }
37
- }
38
- return false;
39
- }
40
-
41
- function hasIntroPattern(lines: string[]): boolean {
42
- const block = lines.join('\n');
43
- for (const pattern of INTRO_PATTERNS) {
44
- if (pattern.test(block)) {
45
- return true;
46
- }
47
- }
48
- return false;
49
- }
50
-
51
- function extractTool(lines: string[]): string | null {
52
- try {
53
- const block = lines.join('\n');
54
- const nameMatch = /^Allow ([A-Z][A-Za-z]+)/m.exec(block);
55
- if (!nameMatch) {
56
- return null;
57
- }
58
- const toolName = nameMatch[1];
59
- // Find the full line that contains the Allow … match, to search for backticks.
60
- const matchIndex = nameMatch.index;
61
- const lineStart = matchIndex;
62
- const lineEnd = block.indexOf('\n', matchIndex);
63
- const fullLine = lineEnd === -1 ? block.slice(lineStart) : block.slice(lineStart, lineEnd);
64
- const backtickMatch = /`([^`]*)`/.exec(fullLine);
65
- let result: string;
66
- if (backtickMatch) {
67
- result = `${toolName}: \`${backtickMatch[1]}\``;
68
- } else {
69
- result = toolName;
70
- }
71
- if (result.length > MAX_TOOL_LEN) {
72
- return result.slice(0, MAX_TOOL_LEN - 1) + '…';
73
- }
74
- return result;
75
- } catch {
76
- return null;
77
- }
78
- }
79
-
80
- export function detectPermissionPrompt(paneText: string): PermissionDetection {
81
- const allLines = paneText.split('\n');
82
- const nonEmpty = allLines.filter((line) => { return line.trim().length > 0; });
83
- const lines = nonEmpty.slice(-LAST_N_LINES);
84
-
85
- const pending = hasYesLine(lines) && hasNoLine(lines) && hasIntroPattern(lines);
86
-
87
- if (!pending) {
88
- return { pending: false, tool: null };
89
- }
90
-
91
- const tool = extractTool(lines);
92
- return { pending: true, tool };
93
- }
@@ -1,44 +0,0 @@
1
- export interface EmbeddedSessionLease {
2
- readonly sessionName: string;
3
- readonly token: number;
4
- }
5
-
6
- const embeddedSessionTokens = new Map<string, number>();
7
- const embeddedSessionQueues = new Map<string, Promise<void>>();
8
-
9
- export function claimEmbeddedSessionLease(
10
- sessionName: string,
11
- ): EmbeddedSessionLease {
12
- const token = (embeddedSessionTokens.get(sessionName) ?? 0) + 1;
13
- embeddedSessionTokens.set(sessionName, token);
14
- return { sessionName, token };
15
- }
16
-
17
- export function embeddedSessionLeaseIsCurrent(
18
- lease: EmbeddedSessionLease,
19
- ): boolean {
20
- return embeddedSessionTokens.get(lease.sessionName) === lease.token;
21
- }
22
-
23
- export async function runEmbeddedSessionOperation<T>(
24
- sessionName: string,
25
- operation: () => Promise<T>,
26
- ): Promise<T> {
27
- const previous = embeddedSessionQueues.get(sessionName) ?? Promise.resolve();
28
- let releaseQueue: (() => void) | undefined;
29
- const current = new Promise<void>((resolve) => {
30
- releaseQueue = resolve;
31
- });
32
- embeddedSessionQueues.set(sessionName, current);
33
-
34
- await previous;
35
-
36
- try {
37
- return await operation();
38
- } finally {
39
- releaseQueue?.();
40
- if (embeddedSessionQueues.get(sessionName) === current) {
41
- embeddedSessionQueues.delete(sessionName);
42
- }
43
- }
44
- }