office-core 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -103,6 +103,7 @@ async function registerHostToken(input) {
|
|
|
103
103
|
project_id: registration.project_id,
|
|
104
104
|
workdir: input.workdir,
|
|
105
105
|
token: registration.host_token,
|
|
106
|
+
room_cursor_seq: Number(registration.room_cursor_seq ?? 0),
|
|
106
107
|
poll_ms: input.pollMs,
|
|
107
108
|
});
|
|
108
109
|
return registration.host_token;
|
|
@@ -293,7 +294,6 @@ async function switchProject(runtime, command) {
|
|
|
293
294
|
sessions: [],
|
|
294
295
|
}).catch(() => undefined);
|
|
295
296
|
runtime.projectId = targetProjectId;
|
|
296
|
-
runtime.roomCursorSeq = 0;
|
|
297
297
|
runtime.token = await registerHostToken({
|
|
298
298
|
baseUrl: runtime.baseUrl,
|
|
299
299
|
projectId: runtime.projectId,
|
|
@@ -302,6 +302,8 @@ async function switchProject(runtime, command) {
|
|
|
302
302
|
workdir: runtime.defaultWorkdir,
|
|
303
303
|
pollMs: runtime.pollMs,
|
|
304
304
|
});
|
|
305
|
+
const refreshedConfig = await loadHostConfig();
|
|
306
|
+
runtime.roomCursorSeq = Number(refreshedConfig?.room_cursor_seq ?? 0);
|
|
305
307
|
const activeWorkdir = resolveProjectWorkdir(runtime.defaultWorkdir, runtime.projectId);
|
|
306
308
|
await mkdir(activeWorkdir, { recursive: true });
|
|
307
309
|
await upsertHostConfig({
|
|
@@ -1277,7 +1279,17 @@ export async function postJson(runtime, pathname, body, tokenOverride) {
|
|
|
1277
1279
|
});
|
|
1278
1280
|
}
|
|
1279
1281
|
export async function postRoomMessageUpsert(runtime, body) {
|
|
1280
|
-
|
|
1282
|
+
try {
|
|
1283
|
+
return await postJson(runtime, `/api/projects/${runtime.projectId}/room/messages/upsert`, body);
|
|
1284
|
+
}
|
|
1285
|
+
catch (error) {
|
|
1286
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1287
|
+
if (!message.includes("/room/messages/upsert failed: 404")) {
|
|
1288
|
+
throw error;
|
|
1289
|
+
}
|
|
1290
|
+
const { message_id: _messageId, ...legacyBody } = body;
|
|
1291
|
+
return postJson(runtime, `/api/projects/${runtime.projectId}/room/messages`, legacyBody);
|
|
1292
|
+
}
|
|
1281
1293
|
}
|
|
1282
1294
|
function parseArgs(argv) {
|
|
1283
1295
|
const result = {};
|
|
@@ -40,7 +40,7 @@ async function main() {
|
|
|
40
40
|
workdir: args.workdir,
|
|
41
41
|
display_name: displayName,
|
|
42
42
|
token: registration.host_token,
|
|
43
|
-
room_cursor_seq: 0,
|
|
43
|
+
room_cursor_seq: Number(registration.room_cursor_seq ?? 0),
|
|
44
44
|
poll_ms: args.pollMs ? Number(args.pollMs) : undefined,
|
|
45
45
|
auto_start: args.autoStart ? args.autoStart !== "false" : undefined,
|
|
46
46
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createInterface, emitKeypressEvents } from "node:readline";
|
|
1
|
+
import { createInterface, emitKeypressEvents, clearScreenDown } from "node:readline";
|
|
2
2
|
import { spawn } from "node:child_process";
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
@@ -44,6 +44,12 @@ function printBanner() {
|
|
|
44
44
|
function printHeader(label) {
|
|
45
45
|
console.log(` ${BOLD}${WHT}office core${R} ${DIM}-${R} ${BOLD}${label}${R}`);
|
|
46
46
|
}
|
|
47
|
+
function truncateText(value, maxLength) {
|
|
48
|
+
if (maxLength <= 1) {
|
|
49
|
+
return value.slice(0, Math.max(0, maxLength));
|
|
50
|
+
}
|
|
51
|
+
return value.length <= maxLength ? value : `${value.slice(0, maxLength - 1)}…`;
|
|
52
|
+
}
|
|
47
53
|
// ─── Box Drawing ────────────────────────────────────────────────────────────
|
|
48
54
|
function wordWrap(text, width) {
|
|
49
55
|
const out = [];
|
|
@@ -117,6 +123,8 @@ function findCmd(name) {
|
|
|
117
123
|
// ─── Slash Menu Renderer ────────────────────────────────────────────────────
|
|
118
124
|
let _menuLines = 0;
|
|
119
125
|
let _menuSelection = 0;
|
|
126
|
+
let _menuScrollOffset = 0;
|
|
127
|
+
const MAX_VISIBLE_SLASH_ITEMS = 6;
|
|
120
128
|
function getSlashMatches(partial) {
|
|
121
129
|
const q = partial.toLowerCase();
|
|
122
130
|
return CMDS.filter((c) => c.name.startsWith(q) || c.alias?.some((a) => a.startsWith(q)));
|
|
@@ -127,22 +135,46 @@ function renderSlashMenu(partial) {
|
|
|
127
135
|
if (hits.length === 0)
|
|
128
136
|
return;
|
|
129
137
|
_menuSelection = Math.max(0, Math.min(_menuSelection, hits.length - 1));
|
|
130
|
-
|
|
131
|
-
|
|
138
|
+
if (_menuSelection < _menuScrollOffset) {
|
|
139
|
+
_menuScrollOffset = _menuSelection;
|
|
140
|
+
}
|
|
141
|
+
if (_menuSelection >= _menuScrollOffset + MAX_VISIBLE_SLASH_ITEMS) {
|
|
142
|
+
_menuScrollOffset = _menuSelection - MAX_VISIBLE_SLASH_ITEMS + 1;
|
|
143
|
+
}
|
|
144
|
+
const visibleHits = hits.slice(_menuScrollOffset, _menuScrollOffset + MAX_VISIBLE_SLASH_ITEMS);
|
|
145
|
+
const lines = [];
|
|
146
|
+
const terminalWidth = Math.max(40, process.stdout.columns ?? 100);
|
|
147
|
+
const commandWidth = Math.min(28, Math.max(16, Math.floor(terminalWidth * 0.32)));
|
|
148
|
+
const descWidth = Math.max(12, terminalWidth - commandWidth - 10);
|
|
149
|
+
if (_menuScrollOffset > 0) {
|
|
150
|
+
lines.push(` ${DIM}${truncateText("↑ more commands", terminalWidth - 4)}${R}`);
|
|
151
|
+
}
|
|
152
|
+
lines.push(...visibleHits.map((c) => {
|
|
153
|
+
const commandLabel = `/${c.name}${c.args ? ` ${c.args}` : ""}`;
|
|
154
|
+
const truncatedCommandLabel = truncateText(commandLabel, commandWidth);
|
|
155
|
+
const truncatedDesc = truncateText(c.desc, descWidth);
|
|
132
156
|
return c === hits[_menuSelection]
|
|
133
|
-
? ` ${BOLD}${WHT}>
|
|
134
|
-
: ` ${GRN}
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
|
|
157
|
+
? ` ${BOLD}${WHT}> ${truncatedCommandLabel.padEnd(commandWidth)}${R} ${DIM}${truncatedDesc}${R}`
|
|
158
|
+
: ` ${GRN}${truncatedCommandLabel.padEnd(commandWidth)}${R} ${DIM}${truncatedDesc}${R}`;
|
|
159
|
+
}));
|
|
160
|
+
if (_menuScrollOffset + visibleHits.length < hits.length) {
|
|
161
|
+
lines.push(` ${DIM}${truncateText("↓ more commands", terminalWidth - 4)}${R}`);
|
|
162
|
+
}
|
|
163
|
+
process.stdout.write(`\x1b[s\n`);
|
|
164
|
+
clearScreenDown(process.stdout);
|
|
165
|
+
process.stdout.write(lines.join("\n"));
|
|
166
|
+
process.stdout.write(`\x1b[u`);
|
|
138
167
|
_menuLines = lines.length;
|
|
139
168
|
}
|
|
140
169
|
function clearSlashMenu() {
|
|
141
170
|
if (_menuLines === 0)
|
|
142
171
|
return;
|
|
143
|
-
process.stdout.write(`\
|
|
172
|
+
process.stdout.write(`\x1b[s\n`);
|
|
173
|
+
clearScreenDown(process.stdout);
|
|
174
|
+
process.stdout.write(`\x1b[u`);
|
|
144
175
|
_menuLines = 0;
|
|
145
176
|
_menuSelection = 0;
|
|
177
|
+
_menuScrollOffset = 0;
|
|
146
178
|
}
|
|
147
179
|
// ─── Tab Completer ──────────────────────────────────────────────────────────
|
|
148
180
|
function completer(line) {
|
|
@@ -426,7 +458,16 @@ async function cmdSetup(_a, ctx) {
|
|
|
426
458
|
if (!resp.ok)
|
|
427
459
|
throw new Error(`${resp.status} ${await resp.text()}`);
|
|
428
460
|
const reg = (await resp.json());
|
|
429
|
-
await upsertHostConfig({
|
|
461
|
+
await upsertHostConfig({
|
|
462
|
+
host_id: reg.host_id,
|
|
463
|
+
base_url,
|
|
464
|
+
project_id,
|
|
465
|
+
workdir,
|
|
466
|
+
display_name,
|
|
467
|
+
token: reg.host_token,
|
|
468
|
+
room_cursor_seq: Number(reg.room_cursor_seq ?? 0),
|
|
469
|
+
poll_ms: 900,
|
|
470
|
+
});
|
|
430
471
|
console.log(` ${GRN}Registered!${R} Host ID: ${reg.host_id}`);
|
|
431
472
|
console.log(` ${DIM}${getHostConfigPath()}${R}`);
|
|
432
473
|
// Connect immediately
|