office-core 0.1.1 → 0.1.3

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.
@@ -182,7 +182,6 @@ async function processRoomMessages(runtime) {
182
182
  }
183
183
  return;
184
184
  }
185
- const runnableSessions = Array.from(sessions.values()).filter((session) => session.status === "running");
186
185
  const project = await getJson(runtime, `/api/projects/${runtime.projectId}`).catch(() => null);
187
186
  for (const message of messages) {
188
187
  hooks.onRoomMessage?.(message, runtime);
@@ -190,6 +189,7 @@ async function processRoomMessages(runtime) {
190
189
  runtime.roomCursorSeq = Math.max(runtime.roomCursorSeq, message.seq);
191
190
  continue;
192
191
  }
192
+ const runnableSessions = Array.from(sessions.values()).filter((session) => session.status === "running");
193
193
  const targetSessions = runnableSessions.filter((session) => shouldSessionReceiveMessage(runtime, session, message, settings));
194
194
  if (targetSessions.length === 0) {
195
195
  console.log(`[room] seq=${message.seq} no sessions matched (runnable=${runnableSessions.length}), skipping`);
@@ -124,16 +124,37 @@ function findCmd(name) {
124
124
  let _menuLines = 0;
125
125
  let _menuSelection = 0;
126
126
  let _menuScrollOffset = 0;
127
+ let _menuQuery = "";
127
128
  const MAX_VISIBLE_SLASH_ITEMS = 6;
128
129
  function getSlashMatches(partial) {
129
130
  const q = partial.toLowerCase();
130
131
  return CMDS.filter((c) => c.name.startsWith(q) || c.alias?.some((a) => a.startsWith(q)));
131
132
  }
132
- function renderSlashMenu(partial) {
133
- clearSlashMenu();
133
+ function eraseSlashMenu() {
134
+ if (_menuLines === 0)
135
+ return;
136
+ process.stdout.write(`\x1b[s\n`);
137
+ clearScreenDown(process.stdout);
138
+ process.stdout.write(`\x1b[u`);
139
+ _menuLines = 0;
140
+ }
141
+ function resetSlashMenuState() {
142
+ _menuSelection = 0;
143
+ _menuScrollOffset = 0;
144
+ _menuQuery = "";
145
+ }
146
+ function renderSlashMenu(partial, preserveSelection = false) {
147
+ eraseSlashMenu();
148
+ if (!preserveSelection || partial !== _menuQuery) {
149
+ _menuSelection = 0;
150
+ _menuScrollOffset = 0;
151
+ }
152
+ _menuQuery = partial;
134
153
  const hits = getSlashMatches(partial);
135
- if (hits.length === 0)
154
+ if (hits.length === 0) {
155
+ resetSlashMenuState();
136
156
  return;
157
+ }
137
158
  _menuSelection = Math.max(0, Math.min(_menuSelection, hits.length - 1));
138
159
  if (_menuSelection < _menuScrollOffset) {
139
160
  _menuScrollOffset = _menuSelection;
@@ -167,14 +188,29 @@ function renderSlashMenu(partial) {
167
188
  _menuLines = lines.length;
168
189
  }
169
190
  function clearSlashMenu() {
170
- if (_menuLines === 0)
191
+ eraseSlashMenu();
192
+ resetSlashMenuState();
193
+ }
194
+ let _menuRefreshPending = false;
195
+ let _queuedPreserveSelection = false;
196
+ function scheduleSlashMenuRefresh(rl, preserveSelection = false) {
197
+ _queuedPreserveSelection ||= preserveSelection;
198
+ if (_menuRefreshPending) {
171
199
  return;
172
- process.stdout.write(`\x1b[s\n`);
173
- clearScreenDown(process.stdout);
174
- process.stdout.write(`\x1b[u`);
175
- _menuLines = 0;
176
- _menuSelection = 0;
177
- _menuScrollOffset = 0;
200
+ }
201
+ _menuRefreshPending = true;
202
+ setImmediate(() => {
203
+ _menuRefreshPending = false;
204
+ const keepSelection = _queuedPreserveSelection;
205
+ _queuedPreserveSelection = false;
206
+ const line = rl.line ?? "";
207
+ if (line.startsWith("/") && line.length >= 1) {
208
+ renderSlashMenu(line.slice(1), keepSelection);
209
+ }
210
+ else {
211
+ clearSlashMenu();
212
+ }
213
+ });
178
214
  }
179
215
  // ─── Tab Completer ──────────────────────────────────────────────────────────
180
216
  function completer(line) {
@@ -571,8 +607,8 @@ async function main() {
571
607
  const rl = createInterface({
572
608
  input: process.stdin,
573
609
  output: process.stdout,
574
- completer,
575
610
  terminal: isInteractiveTerminal,
611
+ historySize: 0,
576
612
  });
577
613
  const ctx = { runtime: null, rl, running: true, isInteractiveTerminal };
578
614
  const sentIds = new Set();
@@ -608,16 +644,16 @@ async function main() {
608
644
  key.name === "up"
609
645
  ? (_menuSelection + hits.length - 1) % hits.length
610
646
  : (_menuSelection + 1) % hits.length;
611
- renderSlashMenu(line.slice(1));
647
+ scheduleSlashMenuRefresh(rl, true);
612
648
  return;
613
649
  }
614
650
  if (hits.length > 0 && key?.name === "tab") {
615
651
  const selected = hits[_menuSelection] ?? hits[0];
616
652
  replaceInputLine(rl, `/${selected.name} `);
617
- renderSlashMenu(selected.name);
653
+ scheduleSlashMenuRefresh(rl, false);
618
654
  return;
619
655
  }
620
- renderSlashMenu(line.slice(1));
656
+ scheduleSlashMenuRefresh(rl, false);
621
657
  }
622
658
  else {
623
659
  clearSlashMenu();
@@ -667,13 +703,16 @@ async function main() {
667
703
  sentIds.add(messageId);
668
704
  console.log(`${GRN}[${ts()}]${R} ${BOLD}You${R}: ${input}`);
669
705
  try {
670
- await postRoomMessageUpsert(ctx.runtime, {
706
+ const result = await postRoomMessageUpsert(ctx.runtime, {
671
707
  message_id: messageId,
672
708
  author_type: "user",
673
709
  author_id: ctx.runtime.hostId,
674
710
  author_label: "You",
675
711
  text: input,
676
712
  });
713
+ if (result?.message_id && result.message_id !== messageId) {
714
+ sentIds.add(String(result.message_id));
715
+ }
677
716
  }
678
717
  catch (e) {
679
718
  sentIds.delete(messageId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "office-core",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Installable CLI and local host runtime for Office Core",
5
5
  "type": "module",
6
6
  "bin": {