@mu-cabin/muc-cli 0.5.0 → 0.5.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/dist/muc.mjs CHANGED
@@ -24128,6 +24128,7 @@ function daemonPaths(kind, opts = {}) {
24128
24128
  sock: join7(runtimeDir2, "daemon.sock"),
24129
24129
  pid: join7(runtimeDir2, "daemon.pid"),
24130
24130
  state: join7(runtimeDir2, "daemon-state.json"),
24131
+ lifecycle: join7(runtimeDir2, "daemon-lifecycle.ndjson"),
24131
24132
  eventsLegacy: join7(runtimeDir2, "daemon-events.ndjson"),
24132
24133
  eventsPrefix: prefix2,
24133
24134
  eventsFile: (date) => join7(runtimeDir2, `${prefix2}-${date}.ndjson`)
@@ -24144,6 +24145,7 @@ function daemonPaths(kind, opts = {}) {
24144
24145
  sock: join7(runtimeDir2, "assistant.sock"),
24145
24146
  pid: join7(runtimeDir2, "assistant.pid"),
24146
24147
  state: join7(runtimeDir2, "assistant-state.json"),
24148
+ lifecycle: join7(runtimeDir2, "assistant-lifecycle.ndjson"),
24147
24149
  eventsLegacy: join7(runtimeDir2, "assistant-events.ndjson"),
24148
24150
  eventsPrefix: prefix2,
24149
24151
  eventsFile: (date) => join7(runtimeDir2, `${prefix2}-${date}.ndjson`),
@@ -24163,6 +24165,7 @@ function daemonPaths(kind, opts = {}) {
24163
24165
  sock: join7(runtimeDir, "assistant.sock"),
24164
24166
  pid: join7(runtimeDir, "daemon.pid"),
24165
24167
  state: join7(runtimeDir, "state.json"),
24168
+ lifecycle: join7(runtimeDir, "lifecycle.ndjson"),
24166
24169
  eventsLegacy: join7(runtimeDir, "events.ndjson"),
24167
24170
  eventsPrefix: prefix,
24168
24171
  eventsFile: (date) => join7(runtimeDir, `${prefix}-${date}.ndjson`),
@@ -28279,7 +28282,7 @@ function formatHuman(m) {
28279
28282
  import { existsSync as existsSync11, unlinkSync as unlinkSync4 } from "node:fs";
28280
28283
 
28281
28284
  // src/daemon/broker.ts
28282
- import { existsSync as existsSync10, mkdirSync as mkdirSync8, readFileSync as readFileSync7, unlinkSync as unlinkSync3, writeFileSync as writeFileSync5 } from "node:fs";
28285
+ import { appendFileSync as appendFileSync2, existsSync as existsSync10, mkdirSync as mkdirSync8, readFileSync as readFileSync7, unlinkSync as unlinkSync3, writeFileSync as writeFileSync5 } from "node:fs";
28283
28286
  import { setTimeout as delay } from "node:timers/promises";
28284
28287
 
28285
28288
  // src/daemon/kicked-policy.ts
@@ -28353,6 +28356,8 @@ var ChatBroker = class {
28353
28356
  status = "starting";
28354
28357
  lastMessage;
28355
28358
  startedAt = Date.now();
28359
+ lifecycleDetails = {};
28360
+ exitRecorded = false;
28356
28361
  socketEndDeferred = null;
28357
28362
  constructor(opts) {
28358
28363
  this.kind = opts.kind;
@@ -28402,11 +28407,10 @@ var ChatBroker = class {
28402
28407
  });
28403
28408
  this.eventLog.migrateLegacy();
28404
28409
  this.eventLog.prune();
28410
+ this.installProcessHandlers();
28405
28411
  this.ipc = new IpcServer(this.paths, (cmd) => this.handleIpc(cmd), { eventLog: this.eventLog });
28406
28412
  await this.ipc.start();
28407
28413
  this.publishState("starting", `${this.kind} daemon initializing (os=${this.os}, uid=${this.cred.uid})`);
28408
- process.on("SIGINT", () => void this.shutdown("SIGINT"));
28409
- process.on("SIGTERM", () => void this.shutdown("SIGTERM"));
28410
28414
  await this.connectChatLoop();
28411
28415
  }
28412
28416
  broadcast(event) {
@@ -28425,7 +28429,8 @@ var ChatBroker = class {
28425
28429
  uid: this.cred?.uid,
28426
28430
  os: this.os,
28427
28431
  kind: this.kind,
28428
- on_kicked: formatKickedRecoveryPolicy(this.kickedPolicy)
28432
+ on_kicked: formatKickedRecoveryPolicy(this.kickedPolicy),
28433
+ ...this.lifecycleDetails
28429
28434
  }, null, 2), { mode: 384 });
28430
28435
  } catch {
28431
28436
  }
@@ -28434,6 +28439,7 @@ var ChatBroker = class {
28434
28439
  async shutdown(reason) {
28435
28440
  if (this.shuttingDown) return;
28436
28441
  this.shuttingDown = true;
28442
+ this.recordLifecycle("shutdown_requested", { last_exit_reason: reason, last_signal: isSignal(reason) ? reason : void 0 });
28437
28443
  process.stderr.write(`[${this.kind}-daemon] shutting down (${reason})
28438
28444
  `);
28439
28445
  if (this.session) {
@@ -28451,11 +28457,24 @@ var ChatBroker = class {
28451
28457
  unlinkSync3(this.paths.pid);
28452
28458
  } catch {
28453
28459
  }
28460
+ this.lifecycleDetails = {
28461
+ ...this.lifecycleDetails,
28462
+ last_exit_reason: reason,
28463
+ last_exit_at: Date.now(),
28464
+ ...isSignal(reason) ? { last_signal: reason } : {}
28465
+ };
28454
28466
  this.publishState("stopped", `${this.kind} daemon stopped (${reason})`);
28467
+ this.recordLifecycle("process_exit", { last_exit_reason: reason, last_exit_at: Date.now() });
28468
+ this.exitRecorded = true;
28455
28469
  process.exit(0);
28456
28470
  }
28457
28471
  async connectChatLoop() {
28472
+ let connectionAttempt = 0;
28458
28473
  while (!this.shuttingDown) {
28474
+ connectionAttempt++;
28475
+ this.recordLifecycle(connectionAttempt === 1 ? "connection_attempt" : "reconnect_attempt", {
28476
+ reconnect_attempt: Math.max(0, connectionAttempt - 1)
28477
+ });
28459
28478
  let endReason;
28460
28479
  try {
28461
28480
  await this.openSocket();
@@ -28470,6 +28489,9 @@ var ChatBroker = class {
28470
28489
  }
28471
28490
  }
28472
28491
  async handleSocketEnd(reason) {
28492
+ this.recordLifecycle("socket_end", {
28493
+ last_error: socketEndDetail(reason)
28494
+ });
28473
28495
  if (reason.kind === "kicked") {
28474
28496
  const prefix = `chat slot taken by another device: ${reason.detail}`;
28475
28497
  if (this.kickedPolicy.mode === "pause") {
@@ -28486,6 +28508,10 @@ var ChatBroker = class {
28486
28508
  policy: waitMs === 0 ? "immediate" : "delayed",
28487
28509
  retry_in_ms: waitMs
28488
28510
  });
28511
+ this.recordLifecycle("reconnect_scheduled", {
28512
+ retry_in_ms: waitMs,
28513
+ retry_at: Date.now() + waitMs
28514
+ });
28489
28515
  if (waitMs > 0) await this.sleep(waitMs);
28490
28516
  return true;
28491
28517
  }
@@ -28505,6 +28531,12 @@ var ChatBroker = class {
28505
28531
  const backoff = expBackoffMs(this.reconnectAttempts);
28506
28532
  this.publishState("paused_network", `reconnect attempt ${this.reconnectAttempts} in ${Math.round(backoff / 1e3)}s: ${msg}`);
28507
28533
  this.broadcast({ event: "paused", reason: "network", detail: msg });
28534
+ this.recordLifecycle("reconnect_scheduled", {
28535
+ reconnect_attempt: this.reconnectAttempts,
28536
+ retry_in_ms: backoff,
28537
+ retry_at: Date.now() + backoff,
28538
+ last_error: msg
28539
+ });
28508
28540
  await this.sleep(backoff);
28509
28541
  return true;
28510
28542
  }
@@ -28514,6 +28546,7 @@ var ChatBroker = class {
28514
28546
  if (reloaded) this.cred = reloaded;
28515
28547
  this.session = session;
28516
28548
  this.publishState("connected", `chat socket open (os=${this.os}, uid=${this.cred.uid})`);
28549
+ this.recordLifecycle("connected", { reconnect_attempt: this.reconnectAttempts });
28517
28550
  this.broadcast({ event: "hello", os: this.os });
28518
28551
  const sock = session.socket;
28519
28552
  sock.on("kicked", (payload) => {
@@ -28564,6 +28597,78 @@ var ChatBroker = class {
28564
28597
  this.socketEndDeferred = null;
28565
28598
  }
28566
28599
  }
28600
+ installProcessHandlers() {
28601
+ for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) {
28602
+ process.on(signal, () => void this.shutdown(signal));
28603
+ }
28604
+ process.on("uncaughtException", (error) => this.crash("uncaught_exception", error));
28605
+ process.on("unhandledRejection", (reason) => this.crash("unhandled_rejection", reason));
28606
+ process.on("exit", (code) => {
28607
+ if (this.exitRecorded) return;
28608
+ this.recordLifecycle("process_exit", {
28609
+ last_exit_reason: `process_exit_${code}`,
28610
+ last_exit_at: Date.now()
28611
+ });
28612
+ });
28613
+ }
28614
+ crash(reason, error) {
28615
+ if (this.shuttingDown) process.exit(1);
28616
+ this.shuttingDown = true;
28617
+ const detail = errorDetail(error);
28618
+ this.lifecycleDetails = {
28619
+ ...this.lifecycleDetails,
28620
+ last_exit_reason: reason,
28621
+ last_exit_at: Date.now(),
28622
+ last_error: detail
28623
+ };
28624
+ this.publishState("stopped", `${this.kind} daemon crashed (${reason}): ${detail}`);
28625
+ this.recordLifecycle("process_crash", this.lifecycleDetails);
28626
+ this.exitRecorded = true;
28627
+ process.stderr.write(`[${this.kind}-daemon] ${reason}: ${detail}
28628
+ `);
28629
+ process.exit(1);
28630
+ }
28631
+ recordLifecycle(event, details = {}) {
28632
+ const now = Date.now();
28633
+ if (event === "connected" || event === "connection_attempt" || event === "reconnect_attempt" || event === "shutdown_requested" || event === "process_exit" || event === "process_crash") {
28634
+ delete this.lifecycleDetails.retry_in_ms;
28635
+ delete this.lifecycleDetails.retry_at;
28636
+ }
28637
+ this.lifecycleDetails = {
28638
+ ...this.lifecycleDetails,
28639
+ lifecycle_event: event,
28640
+ lifecycle_at: now,
28641
+ ...withoutUndefined(details)
28642
+ };
28643
+ ensureRuntimeDir(this.paths);
28644
+ try {
28645
+ appendFileSync2(this.paths.lifecycle, JSON.stringify({
28646
+ ts: now,
28647
+ event,
28648
+ pid: process.pid,
28649
+ kind: this.kind,
28650
+ status: this.status,
28651
+ uid: this.cred?.uid,
28652
+ os: this.os,
28653
+ ...withoutUndefined(details)
28654
+ }) + "\n", { mode: 384 });
28655
+ } catch {
28656
+ }
28657
+ try {
28658
+ const previous = readState(this.paths) ?? {};
28659
+ writeFileSync5(this.paths.state, JSON.stringify({
28660
+ ...previous,
28661
+ status: this.status,
28662
+ pid: process.pid,
28663
+ uid: this.cred?.uid,
28664
+ os: this.os,
28665
+ kind: this.kind,
28666
+ on_kicked: formatKickedRecoveryPolicy(this.kickedPolicy),
28667
+ ...this.lifecycleDetails
28668
+ }, null, 2), { mode: 384 });
28669
+ } catch {
28670
+ }
28671
+ }
28567
28672
  async handleIpc(cmd) {
28568
28673
  const extra = await this.opts.extraIpc?.(cmd, this);
28569
28674
  if (extra) return extra;
@@ -28684,6 +28789,22 @@ function readState(paths2) {
28684
28789
  return null;
28685
28790
  }
28686
28791
  }
28792
+ function inferredExitState(state, pid) {
28793
+ if (!pid || state?.status === "stopped") return {};
28794
+ try {
28795
+ process.kill(pid, 0);
28796
+ return {};
28797
+ } catch (e) {
28798
+ if (e?.code !== "ESRCH") return {};
28799
+ }
28800
+ if (state?.last_exit_reason) return {};
28801
+ const lastStateAt = state?.lifecycle_at ?? state?.ts;
28802
+ return {
28803
+ last_exit_reason: "process_disappeared",
28804
+ exit_inferred: true,
28805
+ ...lastStateAt ? { last_state_at: lastStateAt } : {}
28806
+ };
28807
+ }
28687
28808
  function readPid(paths2) {
28688
28809
  if (!existsSync10(paths2.pid)) return void 0;
28689
28810
  try {
@@ -28729,6 +28850,25 @@ function expBackoffMs(attempt) {
28729
28850
  const base = [5e3, 15e3, 6e4, 3e5, 3e5, 3e5, 3e5];
28730
28851
  return base[Math.min(attempt - 1, base.length - 1)];
28731
28852
  }
28853
+ function socketEndDetail(reason) {
28854
+ if (reason.kind === "kicked") return reason.detail;
28855
+ if (reason.kind === "error" || reason.kind === "open_failed") return reason.message;
28856
+ return "socket closed";
28857
+ }
28858
+ function errorDetail(error) {
28859
+ if (error instanceof Error) return (error.stack ?? error.message).slice(0, 4e3);
28860
+ try {
28861
+ return JSON.stringify(error).slice(0, 4e3);
28862
+ } catch {
28863
+ return String(error).slice(0, 4e3);
28864
+ }
28865
+ }
28866
+ function isSignal(reason) {
28867
+ return reason === "SIGINT" || reason === "SIGTERM" || reason === "SIGHUP";
28868
+ }
28869
+ function withoutUndefined(value) {
28870
+ return Object.fromEntries(Object.entries(value).filter(([, v]) => v !== void 0));
28871
+ }
28732
28872
  function ok(id, data) {
28733
28873
  return { id, ok: true, data };
28734
28874
  }
@@ -28773,7 +28913,18 @@ var StatusOutput = external_exports.object({
28773
28913
  pid: external_exports.number().optional(),
28774
28914
  socket: external_exports.string(),
28775
28915
  history_days: external_exports.number().optional(),
28776
- on_kicked: external_exports.string().optional()
28916
+ on_kicked: external_exports.string().optional(),
28917
+ lifecycle_event: external_exports.string().optional(),
28918
+ lifecycle_at: external_exports.number().optional(),
28919
+ reconnect_attempt: external_exports.number().optional(),
28920
+ retry_in_ms: external_exports.number().optional(),
28921
+ retry_at: external_exports.number().optional(),
28922
+ last_exit_reason: external_exports.string().optional(),
28923
+ last_exit_at: external_exports.number().optional(),
28924
+ exit_inferred: external_exports.boolean().optional(),
28925
+ last_state_at: external_exports.number().optional(),
28926
+ last_signal: external_exports.string().optional(),
28927
+ last_error: external_exports.string().optional()
28777
28928
  });
28778
28929
  var StopOutput = external_exports.object({
28779
28930
  stopped: external_exports.boolean(),
@@ -28851,6 +29002,7 @@ function register29(program3) {
28851
29002
  const probe = await probeDaemon(paths);
28852
29003
  const state = readState(paths);
28853
29004
  const pid = readPid(paths);
29005
+ const diagnostics = { ...stateDiagnostics(state), ...inferredExitState(state, pid) };
28854
29006
  if (probe === "absent" || probe === "stale") {
28855
29007
  return {
28856
29008
  running: false,
@@ -28861,7 +29013,8 @@ function register29(program3) {
28861
29013
  os: state?.os,
28862
29014
  ...pid ? { pid } : {},
28863
29015
  socket: paths.sock,
28864
- on_kicked: state?.on_kicked
29016
+ on_kicked: state?.on_kicked,
29017
+ ...diagnostics
28865
29018
  };
28866
29019
  }
28867
29020
  if (probe === "indeterminate") {
@@ -28872,7 +29025,8 @@ function register29(program3) {
28872
29025
  message: "socket present but unresponsive within probe budget",
28873
29026
  ...pid ? { pid } : {},
28874
29027
  socket: paths.sock,
28875
- on_kicked: state?.on_kicked
29028
+ on_kicked: state?.on_kicked,
29029
+ ...diagnostics
28876
29030
  };
28877
29031
  }
28878
29032
  const res = await callIpc(paths, { cmd: "status" }, 5e3).catch(() => null);
@@ -28888,7 +29042,8 @@ function register29(program3) {
28888
29042
  pid: typeof data.pid === "number" ? data.pid : pid,
28889
29043
  socket: typeof data.socket === "string" ? data.socket : paths.sock,
28890
29044
  history_days: typeof data.history_days === "number" ? data.history_days : void 0,
28891
- on_kicked: typeof data.on_kicked === "string" ? data.on_kicked : state?.on_kicked
29045
+ on_kicked: typeof data.on_kicked === "string" ? data.on_kicked : state?.on_kicked,
29046
+ ...diagnostics
28892
29047
  };
28893
29048
  }
28894
29049
  return {
@@ -28900,7 +29055,8 @@ function register29(program3) {
28900
29055
  os: state?.os,
28901
29056
  ...pid ? { pid } : {},
28902
29057
  socket: paths.sock,
28903
- on_kicked: state?.on_kicked
29058
+ on_kicked: state?.on_kicked,
29059
+ ...diagnostics
28904
29060
  };
28905
29061
  }
28906
29062
  });
@@ -28995,6 +29151,21 @@ function register29(program3) {
28995
29151
  }
28996
29152
  });
28997
29153
  }
29154
+ function stateDiagnostics(state) {
29155
+ if (!state) return {};
29156
+ const keys = [
29157
+ "lifecycle_event",
29158
+ "lifecycle_at",
29159
+ "reconnect_attempt",
29160
+ "retry_in_ms",
29161
+ "retry_at",
29162
+ "last_exit_reason",
29163
+ "last_exit_at",
29164
+ "last_signal",
29165
+ "last_error"
29166
+ ];
29167
+ return Object.fromEntries(keys.flatMap((key) => state[key] === void 0 ? [] : [[key, state[key]]]));
29168
+ }
28998
29169
  function parseIfMissing2(raw) {
28999
29170
  if (raw === "error" || raw === "earliest" || raw === "latest") return raw;
29000
29171
  throw new CliError("USAGE", `invalid --if-missing: ${raw}`, "expected error|earliest|latest");
@@ -30377,7 +30548,7 @@ function formatBytes(n) {
30377
30548
  }
30378
30549
 
30379
30550
  // src/assistant/memory.ts
30380
- import { appendFileSync as appendFileSync2, readFileSync as readFileSync10, readdirSync as readdirSync5, existsSync as existsSync15, writeFileSync as writeFileSync7, mkdirSync as mkdirSync11, renameSync as renameSync5, unlinkSync as unlinkSync7, rmSync as rmSync4 } from "node:fs";
30551
+ import { appendFileSync as appendFileSync3, readFileSync as readFileSync10, readdirSync as readdirSync5, existsSync as existsSync15, writeFileSync as writeFileSync7, mkdirSync as mkdirSync11, renameSync as renameSync5, unlinkSync as unlinkSync7, rmSync as rmSync4 } from "node:fs";
30381
30552
  import { dirname as dirname6, join as join12 } from "node:path";
30382
30553
  function scopeKey(scene, toId, fromUid, selfUid) {
30383
30554
  if (scene === "team_g") return `team_g:${toId}`;
@@ -30388,7 +30559,7 @@ function appendMemory(name, entry) {
30388
30559
  migrateLegacyMemoryFile(name);
30389
30560
  const file4 = assistantThreadFile(name, entry.tid);
30390
30561
  mkdirSync11(dirname6(file4), { recursive: true, mode: 448 });
30391
- appendFileSync2(file4, JSON.stringify(entry) + "\n", { mode: 384 });
30562
+ appendFileSync3(file4, JSON.stringify(entry) + "\n", { mode: 384 });
30392
30563
  }
30393
30564
  function readWindow(name, tid, limit, excludeMid) {
30394
30565
  migrateLegacyMemoryFile(name);
@@ -30504,7 +30675,7 @@ function migrateLegacyMemoryFile(name) {
30504
30675
  if (!obj || typeof obj !== "object") continue;
30505
30676
  if (typeof obj.tid !== "string" || !obj.tid) continue;
30506
30677
  const dest = assistantThreadFile(name, obj.tid);
30507
- appendFileSync2(dest, JSON.stringify(obj) + "\n", { mode: 384 });
30678
+ appendFileSync3(dest, JSON.stringify(obj) + "\n", { mode: 384 });
30508
30679
  }
30509
30680
  try {
30510
30681
  renameSync5(legacy, legacy + ".legacy");
@@ -30518,7 +30689,7 @@ function migrateLegacyMemoryFile(name) {
30518
30689
 
30519
30690
  // src/assistant/ipc.ts
30520
30691
  import { createServer as createServer2, connect as netConnect2 } from "node:net";
30521
- import { existsSync as existsSync16, mkdirSync as mkdirSync12, unlinkSync as unlinkSync8, chmodSync as chmodSync7, appendFileSync as appendFileSync3 } from "node:fs";
30692
+ import { existsSync as existsSync16, mkdirSync as mkdirSync12, unlinkSync as unlinkSync8, chmodSync as chmodSync7, appendFileSync as appendFileSync4 } from "node:fs";
30522
30693
  import { randomUUID as randomUUID2 } from "node:crypto";
30523
30694
  import { dirname as dirname7 } from "node:path";
30524
30695
  var IpcServer2 = class {
@@ -30623,7 +30794,7 @@ var IpcServer2 = class {
30623
30794
  }
30624
30795
  const date = historyDateString2(ts);
30625
30796
  if (this.currentDate !== date) this.currentDate = date;
30626
- appendFileSync3(historyFile(date), line, { mode: 384 });
30797
+ appendFileSync4(historyFile(date), line, { mode: 384 });
30627
30798
  } catch {
30628
30799
  }
30629
30800
  }
@@ -31659,7 +31830,7 @@ function parseConflictLine(line) {
31659
31830
  import { existsSync as existsSync23, readFileSync as readFileSync16, unlinkSync as unlinkSync11 } from "node:fs";
31660
31831
 
31661
31832
  // src/assistant/daemon.ts
31662
- import { existsSync as existsSync22, writeFileSync as writeFileSync12, readFileSync as readFileSync15, unlinkSync as unlinkSync10, appendFileSync as appendFileSync4, mkdirSync as mkdirSync17 } from "node:fs";
31833
+ import { existsSync as existsSync22, writeFileSync as writeFileSync12, readFileSync as readFileSync15, unlinkSync as unlinkSync10, appendFileSync as appendFileSync5, mkdirSync as mkdirSync17 } from "node:fs";
31663
31834
  import { promises as fsp4 } from "node:fs";
31664
31835
  import path7 from "node:path";
31665
31836
  import { setTimeout as delay2 } from "node:timers/promises";
@@ -35164,14 +35335,14 @@ function writePid2(pid) {
35164
35335
  function appendInboxLog(line) {
35165
35336
  ensureRuntimeDir2();
35166
35337
  try {
35167
- appendFileSync4(INBOX_LOG, JSON.stringify({ ts: Date.now(), ...line }) + "\n", { mode: 384 });
35338
+ appendFileSync5(INBOX_LOG, JSON.stringify({ ts: Date.now(), ...line }) + "\n", { mode: 384 });
35168
35339
  } catch {
35169
35340
  }
35170
35341
  }
35171
35342
  function appendConflictsLog(msg) {
35172
35343
  ensureRuntimeDir2();
35173
35344
  try {
35174
- appendFileSync4(CONFLICTS_LOG, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
35345
+ appendFileSync5(CONFLICTS_LOG, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
35175
35346
  `, { mode: 384 });
35176
35347
  } catch {
35177
35348
  }
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mu-cabin/muc-cli",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Terminal client for MUC IM (com.meicloud.im.dh).",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -22,6 +22,16 @@
22
22
  "im",
23
23
  "cli"
24
24
  ],
25
+ "scripts": {
26
+ "dev": "tsx src/index.ts",
27
+ "test": "tsx --test \"src/**/*.test.ts\"",
28
+ "typecheck": "tsc --noEmit",
29
+ "clean": "rm -rf dist",
30
+ "build": "node scripts/build.mjs",
31
+ "prepack": "npm run typecheck && npm run build",
32
+ "verify": "npm pack --dry-run",
33
+ "pack:offline": "bash ../../scripts/pack-offline.sh"
34
+ },
25
35
  "dependencies": {
26
36
  "commander": "^12.1.0",
27
37
  "crypto-js": "^4.2.0",
@@ -39,14 +49,5 @@
39
49
  },
40
50
  "publishConfig": {
41
51
  "access": "public"
42
- },
43
- "scripts": {
44
- "dev": "tsx src/index.ts",
45
- "test": "tsx --test \"src/**/*.test.ts\"",
46
- "typecheck": "tsc --noEmit",
47
- "clean": "rm -rf dist",
48
- "build": "node scripts/build.mjs",
49
- "verify": "npm pack --dry-run",
50
- "pack:offline": "bash ../../scripts/pack-offline.sh"
51
52
  }
52
- }
53
+ }