@office-xyz/claude-code 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.
- package/CHANGELOG.md +6 -0
- package/index.js +61 -14
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@office-xyz/claude-code` will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.1.1] - 2026-02-15
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- Fix crash when running `npx @office-xyz/claude-code` without `--agent` flag (`argv.agent` undefined → `.split()` TypeError)
|
|
9
|
+
- `label` variable now defaults to `'local-host'` in interactive onboarding mode and updates after onboarding completes
|
|
10
|
+
|
|
5
11
|
## [0.1.0] - 2026-02-15
|
|
6
12
|
|
|
7
13
|
### Added
|
package/index.js
CHANGED
|
@@ -144,7 +144,7 @@ function shellEscapeArg(s) {
|
|
|
144
144
|
|
|
145
145
|
// ── Logging ────────────────────────────────────────────────────────────────
|
|
146
146
|
|
|
147
|
-
|
|
147
|
+
let label = argv.agent ? (argv.agent.split('.')[0] || argv.agent) : 'local-host'
|
|
148
148
|
function log(...args) {
|
|
149
149
|
console.log(chalk.dim(`[${new Date().toISOString()}][${label}]`), ...args)
|
|
150
150
|
}
|
|
@@ -451,6 +451,11 @@ async function handleMessage(message) {
|
|
|
451
451
|
args.push(text)
|
|
452
452
|
|
|
453
453
|
log(chalk.blue(`Running: ${cmd} ${args.slice(0, 5).join(' ')}... [${args.length} args]`))
|
|
454
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
455
|
+
log(chalk.dim(` Auth: Claude login session (stripped inherited API key from env)`))
|
|
456
|
+
} else {
|
|
457
|
+
log(chalk.dim(` Auth: Claude login session`))
|
|
458
|
+
}
|
|
454
459
|
|
|
455
460
|
// 1. Send streaming.started
|
|
456
461
|
sendJSON({
|
|
@@ -467,9 +472,16 @@ async function handleMessage(message) {
|
|
|
467
472
|
// PATH by Node's child_process (works for npm global bins).
|
|
468
473
|
let child
|
|
469
474
|
try {
|
|
475
|
+
// Strip ANTHROPIC_API_KEY from child env so Claude Code CLI uses the
|
|
476
|
+
// user's local login session (claude login / Max subscription) instead
|
|
477
|
+
// of consuming API credits from a shared key that may have been loaded
|
|
478
|
+
// by load-aladdin-env.sh or other infra scripts in the same shell.
|
|
479
|
+
const childEnv = { ...process.env }
|
|
480
|
+
delete childEnv.ANTHROPIC_API_KEY
|
|
481
|
+
|
|
470
482
|
child = spawn(cmd, args, {
|
|
471
483
|
cwd: workspace,
|
|
472
|
-
env:
|
|
484
|
+
env: childEnv,
|
|
473
485
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
474
486
|
shell: false,
|
|
475
487
|
})
|
|
@@ -892,19 +904,36 @@ function connect() {
|
|
|
892
904
|
const ws = new WebSocket(managerUrl.href)
|
|
893
905
|
wsRef = ws
|
|
894
906
|
|
|
895
|
-
const
|
|
907
|
+
const PING_INTERVAL_MS = 10_000
|
|
908
|
+
const PONG_TIMEOUT_MS = 8_000 // must be < PING_INTERVAL_MS
|
|
896
909
|
let pingTimer = null
|
|
910
|
+
let pongTimer = null
|
|
911
|
+
let isAlive = false
|
|
912
|
+
|
|
913
|
+
const stopHeartbeat = () => {
|
|
914
|
+
if (pingTimer) { clearInterval(pingTimer); pingTimer = null }
|
|
915
|
+
if (pongTimer) { clearTimeout(pongTimer); pongTimer = null }
|
|
916
|
+
}
|
|
897
917
|
|
|
898
918
|
ws.on('open', async () => {
|
|
899
919
|
log(chalk.green('Connected to Virtual Office'))
|
|
900
920
|
reconnectAttempts = 0
|
|
921
|
+
isAlive = true
|
|
901
922
|
|
|
902
|
-
//
|
|
923
|
+
// Heartbeat: ping + pong timeout detection (matches cloud managerHostProxy pattern)
|
|
903
924
|
pingTimer = setInterval(() => {
|
|
904
|
-
if (ws.readyState
|
|
905
|
-
|
|
925
|
+
if (ws.readyState !== WebSocket.OPEN) { stopHeartbeat(); return }
|
|
926
|
+
if (!isAlive) {
|
|
927
|
+
log(chalk.red('Heartbeat timeout — no pong received, forcing reconnect'))
|
|
928
|
+
stopHeartbeat()
|
|
929
|
+
try { ws.terminate() } catch { /* ignore */ }
|
|
930
|
+
return
|
|
906
931
|
}
|
|
907
|
-
|
|
932
|
+
isAlive = false
|
|
933
|
+
try { ws.ping() } catch { /* ignore */ }
|
|
934
|
+
}, PING_INTERVAL_MS)
|
|
935
|
+
|
|
936
|
+
ws.on('pong', () => { isAlive = true })
|
|
908
937
|
|
|
909
938
|
sendHostMeta(ws)
|
|
910
939
|
|
|
@@ -950,7 +979,7 @@ function connect() {
|
|
|
950
979
|
const reasonStr = reason?.toString() || ''
|
|
951
980
|
log(chalk.red(`Disconnected (${code} ${reasonStr})`))
|
|
952
981
|
wsRef = null
|
|
953
|
-
|
|
982
|
+
stopHeartbeat()
|
|
954
983
|
|
|
955
984
|
// Kill all active CLI processes on disconnect
|
|
956
985
|
for (const [, entry] of activeChildren) {
|
|
@@ -1006,8 +1035,17 @@ function connectLocalDevice() {
|
|
|
1006
1035
|
const dws = new WebSocket(deviceUrl)
|
|
1007
1036
|
deviceWsRef = dws
|
|
1008
1037
|
|
|
1038
|
+
const DEVICE_PING_INTERVAL_MS = 25_000
|
|
1039
|
+
const DEVICE_PONG_TIMEOUT_MS = 10_000
|
|
1040
|
+
let deviceIsAlive = false
|
|
1041
|
+
|
|
1042
|
+
const stopDeviceHeartbeat = () => {
|
|
1043
|
+
if (devicePingTimer) { clearInterval(devicePingTimer); devicePingTimer = null }
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1009
1046
|
dws.on('open', () => {
|
|
1010
1047
|
log(chalk.green('Local device connected'))
|
|
1048
|
+
deviceIsAlive = true
|
|
1011
1049
|
const agentHandle = argv.agent
|
|
1012
1050
|
const officeId = agentHandle.split('.').slice(1).join('.')
|
|
1013
1051
|
// Register as agent-bound device (NOT office-wide).
|
|
@@ -1029,13 +1067,21 @@ function connectLocalDevice() {
|
|
|
1029
1067
|
},
|
|
1030
1068
|
}))
|
|
1031
1069
|
|
|
1032
|
-
//
|
|
1033
|
-
|
|
1070
|
+
// Heartbeat: ping + pong timeout detection
|
|
1071
|
+
stopDeviceHeartbeat()
|
|
1034
1072
|
devicePingTimer = setInterval(() => {
|
|
1035
|
-
if (dws.readyState
|
|
1036
|
-
|
|
1073
|
+
if (dws.readyState !== WebSocket.OPEN) { stopDeviceHeartbeat(); return }
|
|
1074
|
+
if (!deviceIsAlive) {
|
|
1075
|
+
log(chalk.red('[device] Heartbeat timeout — no pong received, forcing reconnect'))
|
|
1076
|
+
stopDeviceHeartbeat()
|
|
1077
|
+
try { dws.terminate() } catch { /* ignore */ }
|
|
1078
|
+
return
|
|
1037
1079
|
}
|
|
1038
|
-
|
|
1080
|
+
deviceIsAlive = false
|
|
1081
|
+
try { dws.ping() } catch { /* ignore */ }
|
|
1082
|
+
}, DEVICE_PING_INTERVAL_MS)
|
|
1083
|
+
|
|
1084
|
+
dws.on('pong', () => { deviceIsAlive = true })
|
|
1039
1085
|
})
|
|
1040
1086
|
|
|
1041
1087
|
dws.on('message', async (data) => {
|
|
@@ -1058,7 +1104,7 @@ function connectLocalDevice() {
|
|
|
1058
1104
|
dws.on('close', (code) => {
|
|
1059
1105
|
log(chalk.yellow(`Local device disconnected (${code})`))
|
|
1060
1106
|
deviceWsRef = null
|
|
1061
|
-
|
|
1107
|
+
stopDeviceHeartbeat()
|
|
1062
1108
|
// Reconnect after delay (only if not shutting down)
|
|
1063
1109
|
if (code !== 1000) {
|
|
1064
1110
|
deviceReconnectTimer = setTimeout(connectLocalDevice, 5000)
|
|
@@ -1186,6 +1232,7 @@ async function startup() {
|
|
|
1186
1232
|
argv.agent = result.agent
|
|
1187
1233
|
argv.token = result.token
|
|
1188
1234
|
hostId = result.agent
|
|
1235
|
+
label = result.agent.split('.')[0] || result.agent
|
|
1189
1236
|
|
|
1190
1237
|
// Rebuild manager URL with new agent/token
|
|
1191
1238
|
const newManagerUrl = new URL(argv.manager)
|