@mx-space/cli 0.4.0 → 0.5.0

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.
@@ -1,4 +1,4 @@
1
- import { $ as transduce, $a as constUndefined, $i as matchRight, $n as timeout, $r as of$3, $t as contextWithEffect, A as TaggedError, Aa as left, Ai as appendAll, An as onError, Ar as taggedEnum, At as unsafeMake, B as isConfig, Ba as toStringUnknown, Bi as flatMap$4, Bn as runPromise, Br as ParentSpan, Bt as annotateLogs, C as Literal, Ca as match, Ci as getOption, Cn as mapBoth, Cr as make$25, Ct as provideMerge, Da as boolean$3, Di as isMissingDataOnly, Dn as matchCauseEffect, Dr as Error$1, Dt as currentLoggers, Ea as some, Ei as isConfigError, En as match$2, Et as currentContext, F as decodeUnknown, Fa as Class, Fi as filter$2, Fn as provide$1, Fr as isInterrupted, Ft as _void, G as fromChannel, Ga as hash, Gi as isArray$1, Gn as serviceFunctions, Gr as updateAndGet, Gt as catchAll, H as bufferChunks, Ha as symbol$1, Hi as getSomes, Hn as runtime, Hr as make$22, Ht as asVoid, I as int, Ia as NodeInspectSymbol, Ii as filterMap, In as provideService, Ir as isInterruptedOnly, It as acquireRelease, J as mapError$1, Ji as join$1, Jn as suspend, Jr as updateAs, Jt as catchIf, Ka as string, Ki as isEmptyReadonlyArray, Kn as serviceOption, Kr as allLevels, Kt as catchAllCause, L as optional$7, La as format$3, Li as findFirst, Ln as repeatN, Lr as fail$5, Lt as acquireUseRelease$1, M as Unknown, Ma as right, Mi as drop, Mn as orDie, Mr as log, Mt as decodeSync, N as compose, Na as pipeArguments, Ni as empty$11, Nn as orElse$3, Nr as Scope, Nt as encodeSync, O as String$, Oa as mapInput, Oi as allocate, On as matchEffect, Or as TaggedError$1, Ot as currentTracerEnabled, Pa as BaseProto, Pi as every, Pn as orElseFail, Pr as addFinalizer$1, Pt as is$2, Q as suspend$1, Qa as constFalse, Qi as matchLeft, Qn as tapErrorCause, Qr as isNil, Qt as context, Ra as redact$1, Ri as findFirstIndex, Rn as retry, Rr as isFailure, Rt as addFinalizer, S as Int, Sa as map$8, Si as get$11, Sn as map$6, Sr as isDone, St as provide, T as NumberFromString, Ta as orElse$2, Ti as omit, Tn as mapInputContext, Tr as unsafeDone, Tt as succeed$3, U as ensuring$1, Ua as cached, Ui as head$2, Un as scope, Ur as set$3, Ut as async, V as asyncScoped, Va as equals, Vi as fromIterable$1, Vn as runSync, Vr as get$8, Vt as as, Wa as combine$2, Wi as headNonEmpty, Wn as scoped, Wr as update$6, Wt as cached$1, X as runCollect, Xa as isTagged, Xi as map$7, Xn as tap, Xr as round, Xt as catchTag, Y as run$5, Ya as isObject, Yi as make$21, Yn as sync, Yr as CommitPrototype, Yt as catchSome, Z as splitLines, Za as globalValue, Zi as match$1, Zn as tapError, Zr as cons$1, Zt as catchTags, _ as fromString, _a as getOrThrow, _i as toArray, _n as interruptible, _r as _await, _t as updateContext, a as make$26, aa as sort$2, ai as make$23, an as failCause, ao as __exportAll, ar as unlessEffect, at as fromChannel$1, b as Date$, ba as isOption, bi as Reference, bn as logError, br as failCause$1, bt as effect, c as make$24, ca as tailNonEmpty, ci as add$1, cn as filterOrDieMessage, cr as useSpan, ct as embedInput, d as defaultLogger, di as remove$3, dn as fnUntraced, dr as withParentSpan, dt as fromEffect, ea as of$2, ei as empty$12, en as die, eo as constVoid, er as tryMap, et as unwrap$5, f as prettyLoggerDefault, fa as map$9, fi as seconds, fn as forEach$1, fr as zip, ft as suspend$2, g as when, ga as getOrElse, gi as reduce$2, gn as ignore, gr as DeferredTypeId, gt as runFork, h as value$1, ha as fromNullable, hi as of$1, hn as gen, hr as zipWith, ht as spaced, i as isMailbox, ia as some$1, ii as isEmpty$5, in as fail$2, io as __commonJSMin, ir as uninterruptibleMask, it as forEach, j as Union, ja as merge$1, ji as contains, jn as onInterrupt, jr as error$1, jt as nominal, k as Struct, ka as string$1, ki as append$2, kn as negate, kr as tagged, kt as get$13, l as updateEffect, la as take, li as fromIterable$3, ln as flatMap$1, lr as when$1, lt as ensuring$2, m as orElse$1, ma as flatMap$3, mi as map$10, mn as forkScoped, mr as zipRight, mt as write, n as make$27, na as reduce$1, ni as get$9, nn as either, no as identity, nr as try_, nt as drain, o as toChannel, oa as span, oi as set$2, on as failSync, oo as __require, or as unsafeMakeLatch, ot as unwrapScoped$1, p as withMinimumLogLevel, pa as filter$3, pi as appendAll$1, pn as forkDaemon, pr as zipLeft, pt as void_, q as mapChunks, qa as symbol, qi as isNonEmptyReadonlyArray, qn as succeed$1, qr as getOrDefault, qt as catchAllDefect, r as unsafeAdd, ra as reduceRight, ri as has, rn as ensuring, ro as pipe, rr as uninterruptible, rt as foldLeftChunks, s as get$10, sa as splitAt, si as make$28, sn as filter$1, so as __toESM, sr as unsafeMakeSemaphore, st as acquireUseRelease, t as join$2, ta as prepend$1, ti as fromIterable$2, tn as dieMessage, to as dual, tr as tryPromise, tt as unwrapScoped, u as unify, ua as unsafeGet, ui as has$1, un as flatten$3, ur as withFiberRuntime, ut as flatMap$2, v as Array$, va as getOrUndefined, vi as unsafeFromArray, vn as isEffect, vr as complete, vt as get$12, w as Number$, wa as none$3, wi as merge$2, wn as mapError, wr as succeed$2, wt as scoped$1, x as Defect, xa as isSome, xi as Tag$2, xn as logWarning, xr as interrupt, xt as mergeAll, y as Cause, ya as isNone, yi as GenericTag, yn as locally, yr as fail$4, yt as make$29, z as make$20, za as symbolRedactable, zi as findLast, zn as runFork$1, zr as void_$1, zt as all$3 } from "./esm-DO9hVR8S.mjs";
1
+ import { $ as transduce, $a as constUndefined, $i as matchRight, $n as timeout, $r as of$3, $t as contextWithEffect, A as TaggedError, Aa as left, Ai as appendAll, An as onError, Ar as taggedEnum, At as unsafeMake, B as isConfig, Ba as toStringUnknown, Bi as flatMap$4, Bn as runPromise, Br as ParentSpan, Bt as annotateLogs, C as Literal, Ca as match, Ci as getOption, Cn as mapBoth, Cr as make$25, Ct as provideMerge, Da as boolean$3, Di as isMissingDataOnly, Dn as matchCauseEffect, Dr as Error$1, Dt as currentLoggers, Ea as some, Ei as isConfigError, En as match$2, Et as currentContext, F as decodeUnknown, Fa as Class, Fi as filter$2, Fn as provide$1, Fr as isInterrupted, Ft as _void, G as fromChannel, Ga as hash, Gi as isArray$1, Gn as serviceFunctions, Gr as updateAndGet, Gt as catchAll, H as bufferChunks, Ha as symbol$1, Hi as getSomes, Hn as runtime, Hr as make$22, Ht as asVoid, I as int, Ia as NodeInspectSymbol, Ii as filterMap, In as provideService, Ir as isInterruptedOnly, It as acquireRelease, J as mapError$1, Ji as join$1, Jn as suspend, Jr as updateAs, Jt as catchIf, Ka as string, Ki as isEmptyReadonlyArray, Kn as serviceOption, Kr as allLevels, Kt as catchAllCause, L as optional$7, La as format$3, Li as findFirst, Ln as repeatN, Lr as fail$5, Lt as acquireUseRelease$1, M as Unknown, Ma as right, Mi as drop, Mn as orDie, Mr as log, Mt as decodeSync, N as compose, Na as pipeArguments, Ni as empty$11, Nn as orElse$3, Nr as Scope, Nt as encodeSync, O as String$, Oa as mapInput, Oi as allocate, On as matchEffect, Or as TaggedError$1, Ot as currentTracerEnabled, Pa as BaseProto, Pi as every, Pn as orElseFail, Pr as addFinalizer$1, Pt as is$2, Q as suspend$1, Qa as constFalse, Qi as matchLeft, Qn as tapErrorCause, Qr as isNil, Qt as context, Ra as redact$1, Ri as findFirstIndex, Rn as retry, Rr as isFailure, Rt as addFinalizer, S as Int, Sa as map$8, Si as get$12, Sn as map$6, Sr as isDone, St as provide, T as NumberFromString, Ta as orElse$2, Ti as omit, Tn as mapInputContext, Tr as unsafeDone, Tt as succeed$3, U as ensuring$1, Ua as cached, Ui as head$2, Un as scope, Ur as set$3, Ut as async, V as asyncScoped, Va as equals, Vi as fromIterable$1, Vn as runSync, Vr as get$9, Vt as as, Wa as combine$2, Wi as headNonEmpty, Wn as scoped, Wr as update$6, Wt as cached$1, X as runCollect, Xa as isTagged, Xi as map$7, Xn as tap, Xr as round, Xt as catchTag, Y as run$5, Ya as isObject, Yi as make$21, Yn as sync, Yr as CommitPrototype, Yt as catchSome, Z as splitLines, Za as globalValue, Zi as match$1, Zn as tapError, Zr as cons$1, Zt as catchTags, _ as fromString, _a as getOrThrow, _i as toArray, _n as interruptible, _r as _await, _t as updateContext, a as make$26, aa as sort$2, ai as make$23, an as failCause, ao as __exportAll, ar as unlessEffect, at as fromChannel$1, b as Date$, ba as isOption, bi as Reference, bn as logError, br as failCause$1, bt as effect, c as make$24, ca as tailNonEmpty, ci as add$1, cn as filterOrDieMessage, cr as useSpan, ct as embedInput, d as defaultLogger, di as remove$3, dn as fnUntraced, dr as withParentSpan, dt as fromEffect, ea as of$2, ei as empty$12, en as die, eo as constVoid, er as tryMap, et as unwrap$5, f as prettyLoggerDefault, fa as map$9, fi as seconds, fn as forEach$1, fr as zip, ft as suspend$2, g as when, ga as getOrElse, gi as reduce$2, gn as ignore, gr as DeferredTypeId, gt as runFork, h as value$1, ha as fromNullable, hi as of$1, hn as gen, hr as zipWith, ht as spaced, i as isMailbox, ia as some$1, ii as isEmpty$5, in as fail$2, io as __commonJSMin, ir as uninterruptibleMask, it as forEach, j as Union, ja as merge$1, ji as contains, jn as onInterrupt, jr as error$1, jt as nominal, k as Struct, ka as string$1, ki as append$2, kn as negate, kr as tagged, kt as get$14, l as updateEffect, la as take, li as fromIterable$3, ln as flatMap$1, lr as when$1, lt as ensuring$2, m as orElse$1, ma as flatMap$3, mi as map$10, mn as forkScoped, mr as zipRight, mt as write, n as make$27, na as reduce$1, ni as get$10, nn as either, no as identity, nr as try_, nt as drain, o as toChannel, oa as span, oi as set$2, on as failSync, oo as __require, or as unsafeMakeLatch, ot as unwrapScoped$1, p as withMinimumLogLevel, pa as filter$3, pi as appendAll$1, pn as forkDaemon, pr as zipLeft, pt as void_, q as mapChunks, qa as symbol, qi as isNonEmptyReadonlyArray, qn as succeed$1, qr as getOrDefault, qt as catchAllDefect, r as unsafeAdd, ra as reduceRight, ri as has, rn as ensuring, ro as pipe, rr as uninterruptible, rt as foldLeftChunks, s as get$11, sa as splitAt, si as make$28, sn as filter$1, so as __toESM, sr as unsafeMakeSemaphore, st as acquireUseRelease, t as join$2, ta as prepend$1, ti as fromIterable$2, tn as dieMessage, to as dual, tr as tryPromise, tt as unwrapScoped, u as unify, ua as unsafeGet, ui as has$1, un as flatten$3, ur as withFiberRuntime, ut as flatMap$2, v as Array$, va as getOrUndefined, vi as unsafeFromArray, vn as isEffect, vr as complete, vt as get$13, w as Number$, wa as none$3, wi as merge$2, wn as mapError, wr as succeed$2, wt as scoped$1, x as Defect, xa as isSome, xi as Tag$2, xn as logWarning, xr as interrupt, xt as mergeAll, y as Cause, ya as isNone, yi as GenericTag, yn as locally, yr as fail$4, yt as make$29, z as make$20, za as symbolRedactable, zi as findLast, zn as runFork$1, zr as void_$1, zt as all$4 } from "./esm-DO9hVR8S.mjs";
2
2
  import { _ as LinkNode, a as HeadingNode, b as CodeHighlightNode, d as ListItemNode, f as ListNode, g as AutoLinkNode, o as QuoteNode, x as CodeNode } from "./LexicalRichText.node-DDpwfE-P.mjs";
3
3
  import { t as HorizontalRuleNode } from "./LexicalExtension.node-CF3EAPN7.mjs";
4
4
  import { Ht as ElementNode, Vt as DecoratorNode } from "./Lexical.node-BUsI9gWr.mjs";
@@ -13,7 +13,7 @@ import { webcrypto } from "node:crypto";
13
13
  import * as NFS from "node:fs";
14
14
  import fs, { mkdirSync, readFileSync, realpathSync, renameSync, writeFileSync } from "node:fs";
15
15
  import * as OS from "node:os";
16
- import os from "node:os";
16
+ import os, { arch, platform } from "node:os";
17
17
  import * as Https from "node:https";
18
18
  import { Readable } from "node:stream";
19
19
  import { pipeline } from "node:stream/promises";
@@ -2177,16 +2177,16 @@ const spans = (spans) => {
2177
2177
  return empty$7;
2178
2178
  };
2179
2179
  /** @internal */
2180
- const isEmpty$3 = (self) => size$2(self) === 0;
2180
+ const isEmpty$3 = (self) => size$4(self) === 0;
2181
2181
  /** @internal */
2182
- const size$2 = (self) => {
2182
+ const size$4 = (self) => {
2183
2183
  switch (self._tag) {
2184
2184
  case "Text":
2185
2185
  case "URI": return self.value.length;
2186
2186
  case "Highlight":
2187
2187
  case "Strong":
2188
- case "Weak": return size$2(self.value);
2189
- case "Sequence": return size$2(self.left) + size$2(self.right);
2188
+ case "Weak": return size$4(self.value);
2189
+ case "Sequence": return size$4(self.left) + size$4(self.right);
2190
2190
  }
2191
2191
  };
2192
2192
  /** @internal */
@@ -4115,7 +4115,7 @@ const optional$6 = (self) => ({
4115
4115
  usage: self
4116
4116
  });
4117
4117
  /** @internal */
4118
- const repeated = (self) => ({
4118
+ const repeated$2 = (self) => ({
4119
4119
  _tag: "Repeated",
4120
4120
  usage: self
4121
4121
  });
@@ -4156,7 +4156,7 @@ const simplify = (self, config) => {
4156
4156
  }
4157
4157
  case "Repeated": {
4158
4158
  const usage = simplify(self.usage, config);
4159
- return usage._tag === "Empty" ? empty$5 : repeated(usage);
4159
+ return usage._tag === "Empty" ? empty$5 : repeated$2(usage);
4160
4160
  }
4161
4161
  case "Alternation": {
4162
4162
  const leftUsage = simplify(self.left, config);
@@ -4305,7 +4305,7 @@ const isArgs = (u) => typeof u === "object" && u != null && ArgsTypeId in u;
4305
4305
  /** @internal */
4306
4306
  const isEmpty$1 = (self) => self._tag === "Empty";
4307
4307
  /** @internal */
4308
- const all$2 = function() {
4308
+ const all$3 = function() {
4309
4309
  if (arguments.length === 1) if (isArgs(arguments[0])) return map$2(arguments[0], (x) => [x]);
4310
4310
  else if (isArray$1(arguments[0])) return allTupled$1(arguments[0]);
4311
4311
  else {
@@ -4340,6 +4340,8 @@ const mapEffect$1 = /* @__PURE__ */ dual(2, (self, f) => makeMap$1(self, f));
4340
4340
  /** @internal */
4341
4341
  const optional$5 = (self) => makeWithDefault$1(map$2(self, some), none$3());
4342
4342
  /** @internal */
4343
+ const repeated$1 = (self) => makeVariadic$1(self, none$3(), none$3());
4344
+ /** @internal */
4343
4345
  const validate = /* @__PURE__ */ dual(3, (self, args, config) => validateInternal(self, args, config));
4344
4346
  /** @internal */
4345
4347
  const wizard$2 = /* @__PURE__ */ dual(2, (self, config) => wizardInternal$2(self, config));
@@ -4411,7 +4413,7 @@ const getUsageInternal$2 = (self) => {
4411
4413
  case "Single": return named(of$2(self.name), getChoices(self.primitiveType));
4412
4414
  case "Map": return getUsageInternal$2(self.args);
4413
4415
  case "Both": return concat(getUsageInternal$2(self.left), getUsageInternal$2(self.right));
4414
- case "Variadic": return repeated(getUsageInternal$2(self.args));
4416
+ case "Variadic": return repeated$2(getUsageInternal$2(self.args));
4415
4417
  case "WithDefault":
4416
4418
  case "WithFallbackConfig": return optional$6(getUsageInternal$2(self.args));
4417
4419
  }
@@ -4446,6 +4448,14 @@ const makeWithDefault$1 = (self, fallback) => {
4446
4448
  op.fallback = fallback;
4447
4449
  return op;
4448
4450
  };
4451
+ const makeVariadic$1 = (args, min, max) => {
4452
+ const op = Object.create(proto$3);
4453
+ op._tag = "Variadic";
4454
+ op.args = args;
4455
+ op.min = min;
4456
+ op.max = max;
4457
+ return op;
4458
+ };
4449
4459
  const validateInternal = (self, args, config) => {
4450
4460
  switch (self._tag) {
4451
4461
  case "Empty": return succeed$1([args, void 0]);
@@ -4506,7 +4516,7 @@ const wizardInternal$2 = (self, config) => {
4506
4516
  message: toAnsiText(pipe(getHelpInternal$2(self), sequence(repeatHelp))).trimEnd(),
4507
4517
  min: getMinSizeInternal$1(self),
4508
4518
  max: getMaxSizeInternal$1(self)
4509
- }).pipe(zipLeft(log()), flatMap$1((n) => n <= 0 ? succeed$1(empty$11()) : make$22(empty$11()).pipe(flatMap$1((ref) => wizardInternal$2(self.args, config).pipe(flatMap$1((args) => update$6(ref, appendAll(args))), repeatN(n - 1), zipRight(get$8(ref)), tap((args) => validateInternal(self, args, config)))))));
4519
+ }).pipe(zipLeft(log()), flatMap$1((n) => n <= 0 ? succeed$1(empty$11()) : make$22(empty$11()).pipe(flatMap$1((ref) => wizardInternal$2(self.args, config).pipe(flatMap$1((args) => update$6(ref, appendAll(args))), repeatN(n - 1), zipRight(get$9(ref)), tap((args) => validateInternal(self, args, config)))))));
4510
4520
  }
4511
4521
  case "WithDefault": {
4512
4522
  const defaultHelp = p$2(`This argument is optional - use the default?`);
@@ -4597,6 +4607,11 @@ const getZshCompletions$2 = (self, state = {
4597
4607
  */
4598
4608
  const optional$4 = optional$5;
4599
4609
  /**
4610
+ * @since 1.0.0
4611
+ * @category combinators
4612
+ */
4613
+ const repeated = repeated$1;
4614
+ /**
4600
4615
  * Creates a text argument.
4601
4616
  *
4602
4617
  * Can optionally provide a custom argument name (defaults to `"text"`).
@@ -4631,7 +4646,7 @@ const levensteinDistance = (first, second, config) => {
4631
4646
  //#endregion
4632
4647
  //#region ../../node_modules/.pnpm/@effect+cli@0.75.1_@effect+platform@0.96.1_effect@3.21.2__@effect+printer-ansi@0.49.0_@_d2b48786a958a46d59c00d71830aad4d/node_modules/@effect/cli/dist/esm/internal/prompt/list.js
4633
4648
  /** @internal */
4634
- const list$6 = (options) => text$6(options).pipe(map$3((output) => output.split(options.delimiter || ",")));
4649
+ const list$7 = (options) => text$6(options).pipe(map$3((output) => output.split(options.delimiter || ",")));
4635
4650
  /** @internal */
4636
4651
  const OptionsTypeId = /* @__PURE__ */ Symbol.for("@effect/cli/Options");
4637
4652
  const proto$2 = {
@@ -4647,7 +4662,7 @@ const isEmpty = (self) => self._tag === "Empty";
4647
4662
  /** @internal */
4648
4663
  const isSingle = (self) => self._tag === "Single";
4649
4664
  /** @internal */
4650
- const all$1 = function() {
4665
+ const all$2 = function() {
4651
4666
  if (arguments.length === 1) if (isOptions(arguments[0])) return map$1(arguments[0], (x) => [x]);
4652
4667
  else if (isArray$1(arguments[0])) return allTupled(arguments[0]);
4653
4668
  else {
@@ -4843,7 +4858,7 @@ const getUsageInternal$1 = (self) => {
4843
4858
  case "Map": return getUsageInternal$1(self.options);
4844
4859
  case "Both": return concat(getUsageInternal$1(self.left), getUsageInternal$1(self.right));
4845
4860
  case "OrElse": return alternation(getUsageInternal$1(self.left), getUsageInternal$1(self.right));
4846
- case "Variadic": return repeated(getUsageInternal$1(self.argumentOption));
4861
+ case "Variadic": return repeated$2(getUsageInternal$1(self.argumentOption));
4847
4862
  case "WithDefault":
4848
4863
  case "WithFallback": return optional$6(getUsageInternal$1(self.options));
4849
4864
  }
@@ -4969,7 +4984,7 @@ const parseInternal$1 = (self, args, config) => {
4969
4984
  switch (self._tag) {
4970
4985
  case "Empty": return _void;
4971
4986
  case "Single": {
4972
- const singleNames = filterMap(getNames$1(self), (name) => get$9(args, name));
4987
+ const singleNames = filterMap(getNames$1(self), (name) => get$10(args, name));
4973
4988
  if (isNonEmptyReadonlyArray(singleNames)) {
4974
4989
  const head = headNonEmpty(singleNames);
4975
4990
  if (isEmptyReadonlyArray(tailNonEmpty(singleNames))) {
@@ -5017,7 +5032,7 @@ const parseInternal$1 = (self, args, config) => {
5017
5032
  case "Variadic": {
5018
5033
  const min = getOrElse(self.min, () => 0);
5019
5034
  const max = getOrElse(self.max, () => Number.MAX_SAFE_INTEGER);
5020
- const matchedArgument = filterMap(getNames$1(self), (name) => get$9(args, name));
5035
+ const matchedArgument = filterMap(getNames$1(self), (name) => get$10(args, name));
5021
5036
  const validateMinMax = (values) => {
5022
5037
  if (values.length < min) return fail$2(invalidValue(p$2(`Expected at least ${min} value(s) for option: '${self.argumentOption.fullName}'`)));
5023
5038
  if (values.length > max) return fail$2(invalidValue(p$2(`Expected at most ${max} value(s) for option: '${self.argumentOption.fullName}'`)));
@@ -5049,7 +5064,7 @@ const wizardInternal$1 = (self, config) => {
5049
5064
  return parseCommandLine(self, args, config).pipe(as(args));
5050
5065
  }), zipLeft(log()));
5051
5066
  }
5052
- case "KeyValueMap": return list$6({
5067
+ case "KeyValueMap": return list$7({
5053
5068
  message: toAnsiText(p$2("Enter `key=value` pairs separated by spaces")).trim(),
5054
5069
  delimiter: " "
5055
5070
  }).pipe(flatMap$1((args) => {
@@ -5077,7 +5092,7 @@ const wizardInternal$1 = (self, config) => {
5077
5092
  message: toAnsiText(pipe(getHelpInternal$1(self), sequence(repeatHelp))).trimEnd(),
5078
5093
  min: getMinSizeInternal(self),
5079
5094
  max: getMaxSizeInternal(self)
5080
- }).pipe(flatMap$1((n) => n <= 0 ? succeed$1(empty$11()) : make$22(empty$11()).pipe(flatMap$1((ref) => wizardInternal$1(self.argumentOption, config).pipe(flatMap$1((args) => update$6(ref, appendAll(args))), repeatN(n - 1), zipRight(get$8(ref)))))));
5095
+ }).pipe(flatMap$1((n) => n <= 0 ? succeed$1(empty$11()) : make$22(empty$11()).pipe(flatMap$1((ref) => wizardInternal$1(self.argumentOption, config).pipe(flatMap$1((args) => update$6(ref, appendAll(args))), repeatN(n - 1), zipRight(get$9(ref)))))));
5081
5096
  }
5082
5097
  case "WithDefault": {
5083
5098
  if (isBoolInternal(self.options)) return wizardInternal$1(self.options, config);
@@ -5485,7 +5500,7 @@ const merge = (map1, map2) => {
5485
5500
  if (isNonEmptyReadonlyArray(map2)) {
5486
5501
  const head = headNonEmpty(map2);
5487
5502
  const tail = tailNonEmpty(map2);
5488
- return merge(match(get$9(map1, head[0]), {
5503
+ return merge(match(get$10(map1, head[0]), {
5489
5504
  onNone: () => set$2(map1, head[0], head[1]),
5490
5505
  onSome: (elems) => set$2(map1, head[0], appendAll(elems, head[1]))
5491
5506
  }), tail);
@@ -5625,7 +5640,7 @@ const helpOptions = /* @__PURE__ */ boolean$1("help").pipe(/* @__PURE__ */ withA
5625
5640
  /** @internal */
5626
5641
  const versionOptions = /* @__PURE__ */ boolean$1("version").pipe(/* @__PURE__ */ withDescription$4("Show the version of the application."));
5627
5642
  /** @internal */
5628
- const builtIns = /* @__PURE__ */ all$1({
5643
+ const builtIns = /* @__PURE__ */ all$2({
5629
5644
  completions: completionsOptions,
5630
5645
  logLevel: logLevelOptions,
5631
5646
  help: helpOptions,
@@ -5654,7 +5669,7 @@ const p$1 = p$2;
5654
5669
  * @since 1.0.0
5655
5670
  * @category constructors
5656
5671
  */
5657
- const all = all$1;
5672
+ const all$1 = all$2;
5658
5673
  /**
5659
5674
  * @since 1.0.0
5660
5675
  * @category constructors
@@ -5782,7 +5797,7 @@ const getHelpInternal = (self, config) => {
5782
5797
  const header = isEmpty$2(self.description) ? empty$6 : sequence(h1("DESCRIPTION"), self.description);
5783
5798
  const argsHelp = getHelp$2(self.args);
5784
5799
  const argsSection = isEmpty$2(argsHelp) ? empty$6 : sequence(h1("ARGUMENTS"), argsHelp);
5785
- const optionsHelp = getHelp$1(config.showBuiltIns ? all([self.options, builtIns]) : self.options);
5800
+ const optionsHelp = getHelp$1(config.showBuiltIns ? all$1([self.options, builtIns]) : self.options);
5786
5801
  return sequence(header, sequence(argsSection, isEmpty$2(optionsHelp) ? empty$6 : sequence(h1("OPTIONS"), optionsHelp)));
5787
5802
  }
5788
5803
  case "GetUserInput": return isEmpty$2(self.description) ? empty$6 : sequence(h1("DESCRIPTION"), self.description);
@@ -5809,10 +5824,10 @@ const getHelpInternal = (self, config) => {
5809
5824
  }
5810
5825
  };
5811
5826
  const printSubcommands = (subcommands) => {
5812
- const maxUsageLength = reduceRight(subcommands, 0, (max, [usage]) => Math.max(size$2(usage), max));
5827
+ const maxUsageLength = reduceRight(subcommands, 0, (max, [usage]) => Math.max(size$4(usage), max));
5813
5828
  const documents = map$7(subcommands, ([usage, desc]) => p$2(spans([
5814
5829
  usage,
5815
- text$7(" ".repeat(maxUsageLength - size$2(usage) + 2)),
5830
+ text$7(" ".repeat(maxUsageLength - size$4(usage) + 2)),
5816
5831
  desc
5817
5832
  ])));
5818
5833
  if (isNonEmptyReadonlyArray(documents)) return enumeration(documents);
@@ -6027,7 +6042,7 @@ const wizardInternal = (self, prefix, config) => {
6027
6042
  switch (self._tag) {
6028
6043
  case "GetUserInput":
6029
6044
  case "Standard": return gen(function* () {
6030
- const logCurrentCommand = get$8(commandLineRef).pipe(flatMap$1((commandLine) => {
6045
+ const logCurrentCommand = get$9(commandLineRef).pipe(flatMap$1((commandLine) => {
6031
6046
  return log(toAnsiText(p$2(pipe(strong(highlight("COMMAND:", cyan)), concat$1(space), concat$1(highlight(join$1(commandLine, " "), magenta))))));
6032
6047
  }));
6033
6048
  if (isStandard(self)) {
@@ -6044,7 +6059,7 @@ const wizardInternal = (self, prefix, config) => {
6044
6059
  yield* logCurrentCommand;
6045
6060
  }
6046
6061
  }
6047
- return yield* get$8(commandLineRef);
6062
+ return yield* get$9(commandLineRef);
6048
6063
  });
6049
6064
  case "Map": return loop(self.command, commandLineRef);
6050
6065
  case "Subcommands": {
@@ -6061,7 +6076,7 @@ const wizardInternal = (self, prefix, config) => {
6061
6076
  }
6062
6077
  }
6063
6078
  };
6064
- return make$22(prefix).pipe(flatMap$1((commandLineRef) => loop(self, commandLineRef).pipe(zipRight(get$8(commandLineRef)))));
6079
+ return make$22(prefix).pipe(flatMap$1((commandLineRef) => loop(self, commandLineRef).pipe(zipRight(get$9(commandLineRef)))));
6065
6080
  };
6066
6081
  const getShortDescription = (self) => {
6067
6082
  switch (self._tag) {
@@ -6105,14 +6120,14 @@ const traverseCommand = (self, initialState, f) => make$24(initialState).pipe(fl
6105
6120
  }
6106
6121
  }
6107
6122
  };
6108
- return suspend(() => loop(self, empty$11(), empty$11(), 0)).pipe(zipRight(get$10(ref)));
6123
+ return suspend(() => loop(self, empty$11(), empty$11(), 0)).pipe(zipRight(get$11(ref)));
6109
6124
  }));
6110
6125
  const indentAll = /* @__PURE__ */ dual(2, (self, indent) => {
6111
6126
  const indentation = allocate(indent + 1).join(" ");
6112
6127
  return map$7(self, (line) => `${indentation}${line}`);
6113
6128
  });
6114
6129
  const getBashCompletionsInternal = (self, executable) => traverseCommand(self, empty$11(), (state, info) => {
6115
- const optionNames = getNames$1(isStandard(info.command) ? all([info.command.options, builtIns]) : builtIns);
6130
+ const optionNames = getNames$1(isStandard(info.command) ? all$1([info.command.options, builtIns]) : builtIns);
6116
6131
  const optionCases = isStandard(info.command) ? getBashCompletions$1(info.command.options) : empty$11();
6117
6132
  const wordList = appendAll(optionNames, pipe(info.subcommands, map$7(([name]) => name), sort$2(string$1)));
6118
6133
  const preformatted = isEmptyReadonlyArray(info.parentCommands) ? of$2(info.command.name) : pipe(info.parentCommands, append$2(info.command.name), map$7((command) => command.replace("-", "__")));
@@ -6171,7 +6186,7 @@ const getBashCompletionsInternal = (self, executable) => traverseCommand(self, e
6171
6186
  }));
6172
6187
  const getFishCompletionsInternal = (self, executable) => traverseCommand(self, empty$11(), (state, info) => {
6173
6188
  const baseTemplate = make$21("complete", "-c", executable);
6174
- const optionsCompletions = getFishCompletions$1(isStandard(info.command) ? all$1([builtIns, info.command.options]) : builtIns);
6189
+ const optionsCompletions = getFishCompletions$1(isStandard(info.command) ? all$2([builtIns, info.command.options]) : builtIns);
6175
6190
  const argsCompletions = isStandard(info.command) ? getFishCompletions$2(info.command.args) : empty$11();
6176
6191
  const rootCompletions = (conditionals) => pipe(map$7(optionsCompletions, (option) => pipe(baseTemplate, appendAll(conditionals), append$2(option), join$1(" "))), appendAll(map$7(argsCompletions, (option) => pipe(baseTemplate, appendAll(conditionals), append$2(option), join$1(" ")))));
6177
6192
  const subcommandCompletions = (conditionals) => map$7(info.subcommands, ([name, subcommand]) => {
@@ -6237,7 +6252,7 @@ const getZshSubcommandCases = (self, parentCommands, subcommands) => {
6237
6252
  switch (self._tag) {
6238
6253
  case "Standard":
6239
6254
  case "GetUserInput": {
6240
- const options = isStandard(self) ? all$1([builtIns, self.options]) : builtIns;
6255
+ const options = isStandard(self) ? all$2([builtIns, self.options]) : builtIns;
6241
6256
  const args = isStandard(self) ? self.args : none$1;
6242
6257
  const optionCompletions = pipe(getZshCompletions$1(options), map$7((completion) => `'${completion}' \\`));
6243
6258
  const argCompletions = pipe(getZshCompletions$2(args), map$7((completion) => `'${completion}' \\`));
@@ -6545,7 +6560,7 @@ const fromDescriptor = /* @__PURE__ */ dual((args) => isCommand(args[0]), (descr
6545
6560
  });
6546
6561
  const makeDescriptor = (name, config) => {
6547
6562
  const { args, options, tree } = parseConfig(config);
6548
- return map(make$15(name, all$1(options), all$2(args)), ({ args, options }) => reconstructConfigTree(tree, args, options));
6563
+ return map(make$15(name, all$2(options), all$3(args)), ({ args, options }) => reconstructConfigTree(tree, args, options));
6549
6564
  };
6550
6565
  /** @internal */
6551
6566
  const make$13 = (name, config = {}, handler) => fromDescriptor(makeDescriptor(name, config), handler);
@@ -7164,7 +7179,7 @@ const make$10 = (method) => (url, options) => modify(empty, {
7164
7179
  ...options ?? void 0
7165
7180
  });
7166
7181
  /** @internal */
7167
- const get$7 = /* @__PURE__ */ make$10("GET");
7182
+ const get$8 = /* @__PURE__ */ make$10("GET");
7168
7183
  /** @internal */
7169
7184
  const post$1 = /* @__PURE__ */ make$10("POST");
7170
7185
  /** @internal */
@@ -7172,7 +7187,7 @@ const put$1 = /* @__PURE__ */ make$10("PUT");
7172
7187
  /** @internal */
7173
7188
  const patch$1 = /* @__PURE__ */ make$10("PATCH");
7174
7189
  /** @internal */
7175
- const del$6 = /* @__PURE__ */ make$10("DELETE");
7190
+ const del$7 = /* @__PURE__ */ make$10("DELETE");
7176
7191
  /** @internal */
7177
7192
  const head$1 = /* @__PURE__ */ make$10("HEAD");
7178
7193
  /** @internal */
@@ -7266,7 +7281,7 @@ const ClientProto = {
7266
7281
  return { _id: "@effect/platform/HttpClient" };
7267
7282
  },
7268
7283
  get(url, options) {
7269
- return this.execute(get$7(url, options));
7284
+ return this.execute(get$8(url, options));
7270
7285
  },
7271
7286
  head(url, options) {
7272
7287
  return this.execute(head$1(url, options));
@@ -7281,7 +7296,7 @@ const ClientProto = {
7281
7296
  return this.execute(patch$1(url, options));
7282
7297
  },
7283
7298
  del(url, options) {
7284
- return this.execute(del$6(url, options));
7299
+ return this.execute(del$7(url, options));
7285
7300
  },
7286
7301
  options(url, options) {
7287
7302
  return this.execute(options$1(url, options));
@@ -7350,7 +7365,7 @@ const make$9 = (f) => makeWith((effect) => flatMap$1(effect, (request) => withFi
7350
7365
  }
7351
7366
  }));
7352
7367
  }
7353
- return useSpan(get$11(fiber.currentContext, SpanNameGenerator)(request), {
7368
+ return useSpan(get$12(fiber.currentContext, SpanNameGenerator)(request), {
7354
7369
  kind: "client",
7355
7370
  captureStackTrace: false
7356
7371
  }, (span) => {
@@ -7444,7 +7459,7 @@ var InterruptibleResponse = class {
7444
7459
  return this.original[NodeInspectSymbol]();
7445
7460
  }
7446
7461
  };
7447
- const { del: del$5, execute, get: get$6, head, options, patch, post, put } = /* @__PURE__ */ serviceFunctions(tag);
7462
+ const { del: del$6, execute, get: get$7, head, options, patch, post, put } = /* @__PURE__ */ serviceFunctions(tag);
7448
7463
  /** @internal */
7449
7464
  const transformResponse = /* @__PURE__ */ dual(2, (self, f) => {
7450
7465
  const client = self;
@@ -8019,7 +8034,7 @@ const symlink = /* @__PURE__ */ (() => {
8019
8034
  const nodeSymlink = /* @__PURE__ */ effectify(NFS.symlink, /* @__PURE__ */ handleErrnoException("FileSystem", "symlink"), /* @__PURE__ */ handleBadArgument("symlink"));
8020
8035
  return (target, path) => nodeSymlink(target, path);
8021
8036
  })();
8022
- const truncate = /* @__PURE__ */ (() => {
8037
+ const truncate$1 = /* @__PURE__ */ (() => {
8023
8038
  const nodeTruncate = /* @__PURE__ */ effectify(NFS.truncate, /* @__PURE__ */ handleErrnoException("FileSystem", "truncate"), /* @__PURE__ */ handleBadArgument("truncate"));
8024
8039
  return (path, length) => nodeTruncate(path, length !== void 0 ? Number(length) : void 0);
8025
8040
  })();
@@ -8101,7 +8116,7 @@ const layer$9 = /* @__PURE__ */ effect(FileSystem, /* @__PURE__ */ map$6(/* @__P
8101
8116
  rename,
8102
8117
  stat,
8103
8118
  symlink,
8104
- truncate,
8119
+ truncate: truncate$1,
8105
8120
  utimes,
8106
8121
  watch(path, options) {
8107
8122
  return watch(backend, path, options);
@@ -8333,7 +8348,7 @@ const HttpAgentTypeId = /* @__PURE__ */ Symbol.for("@effect/platform-node/Http/N
8333
8348
  /** @internal */
8334
8349
  const HttpAgent = /* @__PURE__ */ GenericTag("@effect/platform-node/Http/NodeClient/HttpAgent");
8335
8350
  /** @internal */
8336
- const makeAgent = (options) => map$6(all$3([acquireRelease(sync(() => new Http.Agent(options)), (agent) => sync(() => agent.destroy())), acquireRelease(sync(() => new Https.Agent(options)), (agent) => sync(() => agent.destroy()))]), ([http, https]) => ({
8351
+ const makeAgent = (options) => map$6(all$4([acquireRelease(sync(() => new Http.Agent(options)), (agent) => sync(() => agent.destroy())), acquireRelease(sync(() => new Https.Agent(options)), (agent) => sync(() => agent.destroy()))]), ([http, https]) => ({
8337
8352
  [HttpAgentTypeId]: HttpAgentTypeId,
8338
8353
  http,
8339
8354
  https
@@ -8819,7 +8834,7 @@ const layer = /* @__PURE__ */ pipe(/* @__PURE__ */ mergeAll(layer$3, layer$5, /*
8819
8834
  const rows = sync(() => stdout.rows ?? 0);
8820
8835
  const isTTY = sync(() => Boolean(stdout.isTTY));
8821
8836
  const readInput = gen(function* () {
8822
- yield* get$12(rlRef);
8837
+ yield* get$13(rlRef);
8823
8838
  const mailbox = yield* make$26();
8824
8839
  const handleKeypress = (s, k) => {
8825
8840
  const userInput = {
@@ -8838,7 +8853,7 @@ const layer = /* @__PURE__ */ pipe(/* @__PURE__ */ mergeAll(layer$3, layer$5, /*
8838
8853
  stdin.on("keypress", handleKeypress);
8839
8854
  return mailbox;
8840
8855
  });
8841
- const readLine = get$12(rlRef).pipe(flatMap$1((readlineInterface) => async((resume) => {
8856
+ const readLine = get$13(rlRef).pipe(flatMap$1((readlineInterface) => async((resume) => {
8842
8857
  const onLine = (line) => resume(succeed$1(line));
8843
8858
  readlineInterface.once("line", onLine);
8844
8859
  return sync(() => readlineInterface.off("line", onLine));
@@ -9304,7 +9319,7 @@ const isInSsh = Boolean(process$1.env.SSH_CONNECTION || process$1.env.SSH_CLIENT
9304
9319
  const fallbackAttemptSymbol = Symbol("fallbackAttempt");
9305
9320
  const __dirname = import.meta.url ? path.dirname(fileURLToPath(import.meta.url)) : "";
9306
9321
  const localXdgOpenPath = path.join(__dirname, "xdg-open");
9307
- const { platform, arch } = process$1;
9322
+ const { platform: platform$1, arch: arch$1 } = process$1;
9308
9323
  const tryEachApp = async (apps, opener) => {
9309
9324
  if (apps.length === 0) return;
9310
9325
  const errors = [];
@@ -9385,13 +9400,13 @@ const baseOpen = async (options) => {
9385
9400
  const childProcessOptions = {};
9386
9401
  let shouldUseWindowsInWsl = false;
9387
9402
  if (is_wsl_default && !isInsideContainer() && !isInSsh && !app) shouldUseWindowsInWsl = await canAccessPowerShell();
9388
- if (platform === "darwin") {
9403
+ if (platform$1 === "darwin") {
9389
9404
  command = "open";
9390
9405
  if (options.wait) cliArguments.push("--wait-apps");
9391
9406
  if (options.background) cliArguments.push("--background");
9392
9407
  if (options.newInstance) cliArguments.push("--new");
9393
9408
  if (app) cliArguments.push("-a", app);
9394
- } else if (platform === "win32" || shouldUseWindowsInWsl) {
9409
+ } else if (platform$1 === "win32" || shouldUseWindowsInWsl) {
9395
9410
  command = await powerShellPath();
9396
9411
  cliArguments.push(...executePowerShell.argumentsPrefix);
9397
9412
  if (!is_wsl_default) childProcessOptions.windowsVerbatimArguments = true;
@@ -9417,7 +9432,7 @@ const baseOpen = async (options) => {
9417
9432
  await fs$1.access(localXdgOpenPath, constants.X_OK);
9418
9433
  exeLocalXdgOpen = true;
9419
9434
  } catch {}
9420
- command = process$1.versions.electron ?? (platform === "android" || isBundled || !exeLocalXdgOpen) ? "xdg-open" : localXdgOpenPath;
9435
+ command = process$1.versions.electron ?? (platform$1 === "android" || isBundled || !exeLocalXdgOpen) ? "xdg-open" : localXdgOpenPath;
9421
9436
  }
9422
9437
  if (appArguments.length > 0) cliArguments.push(...appArguments);
9423
9438
  if (!options.wait) {
@@ -9425,7 +9440,7 @@ const baseOpen = async (options) => {
9425
9440
  childProcessOptions.detached = true;
9426
9441
  }
9427
9442
  }
9428
- if (platform === "darwin" && appArguments.length > 0) cliArguments.push("--args", ...appArguments);
9443
+ if (platform$1 === "darwin" && appArguments.length > 0) cliArguments.push("--args", ...appArguments);
9429
9444
  if (options.target) cliArguments.push(options.target);
9430
9445
  const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
9431
9446
  if (options.wait) return new Promise((resolve, reject) => {
@@ -9470,13 +9485,13 @@ const open = (target, options) => {
9470
9485
  };
9471
9486
  function detectArchBinary(binary) {
9472
9487
  if (typeof binary === "string" || Array.isArray(binary)) return binary;
9473
- const { [arch]: archBinary } = binary;
9474
- if (!archBinary) throw new Error(`${arch} is not supported`);
9488
+ const { [arch$1]: archBinary } = binary;
9489
+ if (!archBinary) throw new Error(`${arch$1} is not supported`);
9475
9490
  return archBinary;
9476
9491
  }
9477
- function detectPlatformBinary({ [platform]: platformBinary }, { wsl } = {}) {
9492
+ function detectPlatformBinary({ [platform$1]: platformBinary }, { wsl } = {}) {
9478
9493
  if (wsl && is_wsl_default) return detectArchBinary(wsl);
9479
- if (!platformBinary) throw new Error(`${platform} is not supported`);
9494
+ if (!platformBinary) throw new Error(`${platform$1} is not supported`);
9480
9495
  return detectArchBinary(platformBinary);
9481
9496
  }
9482
9497
  const apps = {
@@ -11042,7 +11057,7 @@ const readStdinAll = () => new Promise((resolve, reject) => {
11042
11057
  stdin.on("error", reject);
11043
11058
  if (stdin.isPaused?.()) stdin.resume();
11044
11059
  });
11045
- const makeService$2 = (fs) => ({
11060
+ const makeService$3 = (fs) => ({
11046
11061
  openEditor: (opts) => tryPromise({
11047
11062
  try: async () => {
11048
11063
  const editor = opts.editor ?? process.env.EDITOR ?? process.env.VISUAL;
@@ -11093,7 +11108,7 @@ const makeService$2 = (fs) => ({
11093
11108
  });
11094
11109
  var Editor = class Editor extends Tag$2("Editor")() {
11095
11110
  static Default = effect(Editor, gen(function* () {
11096
- return makeService$2(yield* FileSystem);
11111
+ return makeService$3(yield* FileSystem);
11097
11112
  }));
11098
11113
  };
11099
11114
  //#endregion
@@ -11626,6 +11641,103 @@ const highlightCode = (code, lang, color) => {
11626
11641
  return work;
11627
11642
  };
11628
11643
  //#endregion
11644
+ //#region src/services/Renderer/datetime.ts
11645
+ const pad2 = (n) => String(n).padStart(2, "0");
11646
+ /**
11647
+ * Coerce an arbitrary value (ISO string, epoch ms or s, Date) into a Date.
11648
+ * Returns null when the value cannot be interpreted as a calendar time.
11649
+ */
11650
+ const toDate = (value) => {
11651
+ if (value === null || value === void 0) return null;
11652
+ if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value;
11653
+ if (typeof value === "number") {
11654
+ if (!Number.isFinite(value) || value <= 0) return null;
11655
+ const ms = value < 0xe8d4a51000 ? value * 1e3 : value;
11656
+ const date = new Date(ms);
11657
+ return Number.isNaN(date.getTime()) ? null : date;
11658
+ }
11659
+ if (typeof value === "string") {
11660
+ const trimmed = value.trim();
11661
+ if (!trimmed) return null;
11662
+ const date = new Date(trimmed);
11663
+ return Number.isNaN(date.getTime()) ? null : date;
11664
+ }
11665
+ return null;
11666
+ };
11667
+ /** Local-time `YYYY-MM-DD HH:mm`. Seconds are dropped for readability. */
11668
+ const formatAbsoluteDateTime = (date) => {
11669
+ return `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())} ${pad2(date.getHours())}:${pad2(date.getMinutes())}`;
11670
+ };
11671
+ const phrase = (count, unit, past) => {
11672
+ const plural = count === 1 ? unit : `${unit}s`;
11673
+ return past ? `${count} ${plural} ago` : `in ${count} ${plural}`;
11674
+ };
11675
+ /**
11676
+ * Relative phrase versus `now` (default = the moment of the call).
11677
+ * Bucketing uses the same thresholds as date-fns `formatDistance` so the
11678
+ * output reads naturally without 1-minute precision noise.
11679
+ */
11680
+ const formatRelativeTime = (date, now = /* @__PURE__ */ new Date()) => {
11681
+ const diffMs = date.getTime() - now.getTime();
11682
+ const past = diffMs < 0;
11683
+ const seconds = Math.abs(diffMs) / 1e3;
11684
+ if (seconds < 45) return past ? "just now" : "in a moment";
11685
+ if (seconds < 90) return phrase(1, "minute", past);
11686
+ const minutes = Math.round(seconds / 60);
11687
+ if (minutes < 45) return phrase(minutes, "minute", past);
11688
+ if (minutes < 90) return phrase(1, "hour", past);
11689
+ const hours = Math.round(minutes / 60);
11690
+ if (hours < 22) return phrase(hours, "hour", past);
11691
+ if (hours < 36) return phrase(1, "day", past);
11692
+ const days = Math.round(hours / 24);
11693
+ if (days < 7) return phrase(days, "day", past);
11694
+ if (days < 11) return phrase(1, "week", past);
11695
+ const weeks = Math.round(days / 7);
11696
+ if (weeks < 5) return phrase(weeks, "week", past);
11697
+ if (days < 60) return phrase(1, "month", past);
11698
+ const months = Math.round(days / 30);
11699
+ if (months < 12) return phrase(months, "month", past);
11700
+ return phrase(Math.round(days / 365.25), "year", past);
11701
+ };
11702
+ /**
11703
+ * Format an arbitrary timestamp-shaped value for a readable view.
11704
+ *
11705
+ * Falls back to `String(value)` when the value cannot be parsed as a date,
11706
+ * and to `''` when the value is nullish — letting the caller filter the
11707
+ * field out instead of rendering `null` / `undefined`.
11708
+ */
11709
+ const formatDateTime = (value, opts = {}) => {
11710
+ const date = toDate(value);
11711
+ if (!date) {
11712
+ if (value === null || value === void 0) return "";
11713
+ return String(value);
11714
+ }
11715
+ const style = opts.style ?? (opts.relative ? "both" : "abs");
11716
+ if (style === "rel") return formatRelativeTime(date, opts.now);
11717
+ const abs = formatAbsoluteDateTime(date);
11718
+ if (style === "both") {
11719
+ const rel = formatRelativeTime(date, opts.now);
11720
+ return rel ? `${abs} (${rel})` : abs;
11721
+ }
11722
+ return abs;
11723
+ };
11724
+ const ISO_LIKE_RE = /^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}/;
11725
+ /** True when `value` is a `Date` or an ISO-8601-ish string. */
11726
+ const looksLikeTimestamp = (value) => {
11727
+ if (value instanceof Date) return !Number.isNaN(value.getTime());
11728
+ if (typeof value === "string") return ISO_LIKE_RE.test(value);
11729
+ return false;
11730
+ };
11731
+ /**
11732
+ * Format `value` as a human-friendly timestamp when it looks like one;
11733
+ * return `null` otherwise so the caller can fall back to its scalar
11734
+ * formatter without committing to the timestamp shape.
11735
+ */
11736
+ const tryFormatTimestamp = (value, opts = {}) => {
11737
+ if (!looksLikeTimestamp(value)) return null;
11738
+ return formatDateTime(value, opts);
11739
+ };
11740
+ //#endregion
11629
11741
  //#region ../../node_modules/.pnpm/nanoid@5.1.11/node_modules/nanoid/index.js
11630
11742
  const POOL_SIZE_MULTIPLIER = 128;
11631
11743
  let pool, poolOffset;
@@ -13243,7 +13355,7 @@ var Parser$1 = class {
13243
13355
  //#region ../../node_modules/.pnpm/domelementtype@2.3.0/node_modules/domelementtype/lib/esm/index.js
13244
13356
  var esm_exports$2 = /* @__PURE__ */ __exportAll({
13245
13357
  CDATA: () => CDATA$1,
13246
- Comment: () => Comment$3,
13358
+ Comment: () => Comment$4,
13247
13359
  Directive: () => Directive,
13248
13360
  Doctype: () => Doctype,
13249
13361
  ElementType: () => ElementType,
@@ -13291,7 +13403,7 @@ const Text$3 = ElementType.Text;
13291
13403
  /** Type for <? ... ?> */
13292
13404
  const Directive = ElementType.Directive;
13293
13405
  /** Type for <!-- ... --> */
13294
- const Comment$3 = ElementType.Comment;
13406
+ const Comment$4 = ElementType.Comment;
13295
13407
  /** Type for <script> tags */
13296
13408
  const Script = ElementType.Script;
13297
13409
  /** Type for <style> tags */
@@ -13398,7 +13510,7 @@ var Text$2 = class extends DataNode {
13398
13510
  /**
13399
13511
  * Comments within the document.
13400
13512
  */
13401
- var Comment$2 = class extends DataNode {
13513
+ var Comment$3 = class extends DataNode {
13402
13514
  constructor() {
13403
13515
  super(...arguments);
13404
13516
  this.type = ElementType.Comment;
@@ -13570,7 +13682,7 @@ function hasChildren(node) {
13570
13682
  function cloneNode(node, recursive = false) {
13571
13683
  let result;
13572
13684
  if (isText(node)) result = new Text$2(node.data);
13573
- else if (isComment(node)) result = new Comment$2(node.data);
13685
+ else if (isComment(node)) result = new Comment$3(node.data);
13574
13686
  else if (isTag$1(node)) {
13575
13687
  const children = recursive ? cloneChildren(node.children) : [];
13576
13688
  const clone = new Element$2(node.name, { ...node.attribs }, children);
@@ -13697,7 +13809,7 @@ var DomHandler = class {
13697
13809
  this.lastNode.data += data;
13698
13810
  return;
13699
13811
  }
13700
- const node = new Comment$2(data);
13812
+ const node = new Comment$3(data);
13701
13813
  this.addNode(node);
13702
13814
  this.lastNode = node;
13703
13815
  }
@@ -13999,7 +14111,7 @@ function renderNode(node, options) {
13999
14111
  case Root: return render(node.children, options);
14000
14112
  case Doctype:
14001
14113
  case Directive: return renderDirective(node);
14002
- case Comment$3: return renderComment(node);
14114
+ case Comment$4: return renderComment(node);
14003
14115
  case CDATA$1: return renderCdata$1(node);
14004
14116
  case Script:
14005
14117
  case Style:
@@ -16120,13 +16232,13 @@ var CDATASection$1 = class CDATASection$1 extends CharacterData$1 {
16120
16232
  /**
16121
16233
  * @implements globalThis.Comment
16122
16234
  */
16123
- var Comment$1 = class Comment$1 extends CharacterData$1 {
16235
+ var Comment$2 = class Comment$2 extends CharacterData$1 {
16124
16236
  constructor(ownerDocument, data = "") {
16125
16237
  super(ownerDocument, "#comment", 8, data);
16126
16238
  }
16127
16239
  cloneNode() {
16128
16240
  const { ownerDocument, [VALUE]: data } = this;
16129
- return new Comment$1(ownerDocument, data);
16241
+ return new Comment$2(ownerDocument, data);
16130
16242
  }
16131
16243
  toString() {
16132
16244
  return `<!--${this[VALUE]}-->`;
@@ -18733,11 +18845,11 @@ function CharacterData() {
18733
18845
  }
18734
18846
  setPrototypeOf(CharacterData, CharacterData$1);
18735
18847
  CharacterData.prototype = CharacterData$1.prototype;
18736
- function Comment() {
18848
+ function Comment$1() {
18737
18849
  illegalConstructor();
18738
18850
  }
18739
- setPrototypeOf(Comment, Comment$1);
18740
- Comment.prototype = Comment$1.prototype;
18851
+ setPrototypeOf(Comment$1, Comment$2);
18852
+ Comment$1.prototype = Comment$2.prototype;
18741
18853
  function DocumentFragment() {
18742
18854
  illegalConstructor();
18743
18855
  }
@@ -18778,7 +18890,7 @@ const Facades = {
18778
18890
  Attr,
18779
18891
  CDATASection,
18780
18892
  CharacterData,
18781
- Comment,
18893
+ Comment: Comment$1,
18782
18894
  DocumentFragment,
18783
18895
  DocumentType,
18784
18896
  Element,
@@ -22429,7 +22541,7 @@ var Document$1 = class extends NonElementParentNode {
22429
22541
  return new CDATASection$1(this, data);
22430
22542
  }
22431
22543
  createComment(textContent) {
22432
- return new Comment$1(this, textContent);
22544
+ return new Comment$2(this, textContent);
22433
22545
  }
22434
22546
  createDocumentFragment() {
22435
22547
  return new DocumentFragment$1(this);
@@ -26116,7 +26228,7 @@ const normalizeAttrs = (raw) => {
26116
26228
  for (const [k, v] of Object.entries(raw)) out[k] = v == null ? "" : String(v);
26117
26229
  return out;
26118
26230
  };
26119
- const normalize$3 = (raw) => {
26231
+ const normalize$4 = (raw) => {
26120
26232
  if (!Array.isArray(raw)) return [];
26121
26233
  const out = [];
26122
26234
  for (const entry of raw) {
@@ -26136,7 +26248,7 @@ const normalize$3 = (raw) => {
26136
26248
  type: "element",
26137
26249
  tag: key,
26138
26250
  attrs,
26139
- children: normalize$3(value)
26251
+ children: normalize$4(value)
26140
26252
  });
26141
26253
  }
26142
26254
  }
@@ -26149,7 +26261,7 @@ const parseLitexml = (xml) => {
26149
26261
  const first = raw[0];
26150
26262
  if (!first) return [];
26151
26263
  const inner = first.root;
26152
- return normalize$3(inner);
26264
+ return normalize$4(inner);
26153
26265
  } catch {
26154
26266
  return [];
26155
26267
  }
@@ -26213,6 +26325,10 @@ const renderLexicalAnsi = (xml, opts) => {
26213
26325
  };
26214
26326
  //#endregion
26215
26327
  //#region src/cli/render/metadata-block.ts
26328
+ const formatFieldValue = (key, value, color) => {
26329
+ if (key === "state") return formatStateBadge(value, color) ?? formatScalar(value);
26330
+ return tryFormatTimestamp(value, { style: "both" }) ?? formatScalar(value);
26331
+ };
26216
26332
  const renderMetadataBlock = (input, ctx) => {
26217
26333
  const { color } = ctx;
26218
26334
  const { title, kind, fields: rawFields, summary, body, bodyFormat } = input;
@@ -26226,7 +26342,7 @@ const renderMetadataBlock = (input, ctx) => {
26226
26342
  const labelWidth = fields.reduce((max, [key]) => Math.max(max, key.length), 0);
26227
26343
  for (const [key, value] of fields) {
26228
26344
  const label = wrap(ANSI.dim, key.padEnd(labelWidth), color);
26229
- const rendered = key === "state" ? formatStateBadge(value, color) ?? formatScalar(value) : formatScalar(value);
26345
+ const rendered = formatFieldValue(key, value, color);
26230
26346
  lines.push(`${label} ${rendered}`);
26231
26347
  }
26232
26348
  if (summary) {
@@ -26301,12 +26417,15 @@ const emitErrorSync = (err, opts) => {
26301
26417
  //#endregion
26302
26418
  //#region src/services/Renderer/lists.ts
26303
26419
  const isPlainObject = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date);
26420
+ const formatLeaf = (value) => tryFormatTimestamp(value, { style: "both" }) ?? formatScalar(value);
26304
26421
  const renderReadableLines = (data, indent) => {
26305
26422
  const pad = " ".repeat(indent);
26306
26423
  if (data === null || data === void 0) return [];
26307
- if (data instanceof Date) return [`${pad}${data.toISOString()}`];
26424
+ if (data instanceof Date) return [`${pad}${formatLeaf(data)}`];
26308
26425
  if (typeof data === "string") {
26309
26426
  if (data.length === 0) return [];
26427
+ const ts = tryFormatTimestamp(data, { style: "both" });
26428
+ if (ts !== null) return [`${pad}${ts}`];
26310
26429
  return data.split("\n").map((line) => `${pad}${line}`);
26311
26430
  }
26312
26431
  if (typeof data === "number" || typeof data === "boolean") return [`${pad}${String(data)}`];
@@ -26324,7 +26443,7 @@ const renderReadableLines = (data, indent) => {
26324
26443
  if (inner.length === 0) continue;
26325
26444
  lines.push(`${pad}-`);
26326
26445
  lines.push(...inner);
26327
- } else if (item !== null && item !== void 0) lines.push(`${pad}- ${formatScalar(item)}`);
26446
+ } else if (item !== null && item !== void 0) lines.push(`${pad}- ${formatLeaf(item)}`);
26328
26447
  return lines;
26329
26448
  }
26330
26449
  if (isPlainObject(data)) {
@@ -26334,7 +26453,7 @@ const renderReadableLines = (data, indent) => {
26334
26453
  if (Array.isArray(value)) {
26335
26454
  if (value.length === 0) continue;
26336
26455
  if (value.every((v) => v === null || v === void 0 || v instanceof Date || typeof v !== "object")) {
26337
- const parts = value.filter((v) => v !== null && v !== void 0).map((v) => formatScalar(v));
26456
+ const parts = value.filter((v) => v !== null && v !== void 0).map((v) => formatLeaf(v));
26338
26457
  lines.push(`${pad}${key}: ${parts.join(", ")}`);
26339
26458
  } else {
26340
26459
  lines.push(`${pad}${key}:`);
@@ -26345,8 +26464,7 @@ const renderReadableLines = (data, indent) => {
26345
26464
  if (inner.length === 0) continue;
26346
26465
  lines.push(`${pad}${key}:`);
26347
26466
  lines.push(...inner);
26348
- } else if (value instanceof Date) lines.push(`${pad}${key}: ${value.toISOString()}`);
26349
- else lines.push(`${pad}${key}: ${formatScalar(value)}`);
26467
+ } else lines.push(`${pad}${key}: ${formatLeaf(value)}`);
26350
26468
  }
26351
26469
  return lines;
26352
26470
  }
@@ -26355,8 +26473,8 @@ const renderReadableLines = (data, indent) => {
26355
26473
  const renderReadableGeneric = (data) => renderReadableLines(data, 0).join("\n");
26356
26474
  //#endregion
26357
26475
  //#region src/services/Renderer/service.ts
26358
- const makeService$1 = () => {
26359
- const getOpts = get$13(currentOutputOptions);
26476
+ const makeService$2 = () => {
26477
+ const getOpts = get$14(currentOutputOptions);
26360
26478
  const emitSuccessSync = (data, opts) => {
26361
26479
  if (opts.json || opts.output === "json") {
26362
26480
  writeStdout(`${JSON.stringify({
@@ -26467,7 +26585,7 @@ const makeService$1 = () => {
26467
26585
  //#endregion
26468
26586
  //#region src/services/Renderer/index.ts
26469
26587
  var Renderer = class Renderer extends Tag$2("Renderer")() {
26470
- static Default = succeed$3(Renderer, makeService$1());
26588
+ static Default = succeed$3(Renderer, makeService$2());
26471
26589
  /** Apply the given `OutputOptions` for the duration of `effect`. */
26472
26590
  static withOptions = (options) => (effect) => locally(effect, currentOutputOptions, options);
26473
26591
  };
@@ -26721,7 +26839,7 @@ const whoami = make$12("whoami", {}, () => gen(function* () {
26721
26839
  }));
26722
26840
  //#endregion
26723
26841
  //#region src/cli/auth/index.ts
26724
- const help$7 = registerCommandHelp({
26842
+ const help$8 = registerCommandHelp({
26725
26843
  name: "auth",
26726
26844
  description: "authentication",
26727
26845
  verbs: [
@@ -26744,7 +26862,7 @@ const help$7 = registerCommandHelp({
26744
26862
  }
26745
26863
  ]
26746
26864
  });
26747
- const authCmd = make$12("auth").pipe(withDescription(help$7.description), withSubcommands([
26865
+ const authCmd = make$12("auth").pipe(withDescription(help$8.description), withSubcommands([
26748
26866
  login,
26749
26867
  logout,
26750
26868
  whoami,
@@ -26802,6 +26920,32 @@ const extractServerMessage = (body) => {
26802
26920
  return null;
26803
26921
  };
26804
26922
  //#endregion
26923
+ //#region src/domain/version.ts
26924
+ const requireFrom$2 = createRequire(import.meta.url);
26925
+ const resolveCliVersion$2 = () => {
26926
+ for (const candidate of [
26927
+ "../package.json",
26928
+ "../../package.json",
26929
+ "../../../package.json"
26930
+ ]) try {
26931
+ const pkg = requireFrom$2(candidate);
26932
+ if (pkg.name === "@mx-space/cli" && typeof pkg.version === "string") return pkg.version;
26933
+ } catch {}
26934
+ return "0.0.0-unknown";
26935
+ };
26936
+ /**
26937
+ * RFC-7231-style User-Agent. Format:
26938
+ * `mxs/<cli-version> (<os-platform> <os-arch>; node/<node-version>)`
26939
+ *
26940
+ * Example: `mxs/0.4.0 (darwin arm64; node/v22.22.2)`
26941
+ *
26942
+ * mx-core's spider guard whitelists any UA containing `mx-space`; this string
26943
+ * does (`mxs` is the @mx-space/cli binary). Authenticated requests bypass the
26944
+ * guard regardless of UA, but a well-formed UA helps server-side analytics
26945
+ * tell agent traffic apart from human browser sessions.
26946
+ */
26947
+ const USER_AGENT = `mxs/${resolveCliVersion$2()} (${platform()} ${arch()}; node/${process.version}) @mx-space/cli`;
26948
+ //#endregion
26805
26949
  //#region src/services/Api.ts
26806
26950
  var Api = class Api extends Tag$2("Api")() {
26807
26951
  /**
@@ -26830,7 +26974,7 @@ function makeApiService(http, config, auth, opts) {
26830
26974
  })));
26831
26975
  const maybeEmitBanner = (resolved) => gen(function* () {
26832
26976
  if (!resolved.isProduction || opts.quiet) return;
26833
- if (yield* get$8(bannerEmitted)) return;
26977
+ if (yield* get$9(bannerEmitted)) return;
26834
26978
  yield* set$3(bannerEmitted, true);
26835
26979
  yield* sync(() => {
26836
26980
  process.stderr.write(`mxs: profile=${resolved.profileName} (production) → ${resolved.apiUrl}\n`);
@@ -26883,6 +27027,7 @@ function makeApiService(http, config, auth, opts) {
26883
27027
  const url = buildUrl(resolved.apiBase, path, effectiveQuery);
26884
27028
  const baseHeaders = {
26885
27029
  accept: "application/json",
27030
+ "user-agent": USER_AGENT,
26886
27031
  ...options.headers
26887
27032
  };
26888
27033
  if (token) baseHeaders.authorization = `Bearer ${token}`;
@@ -27243,7 +27388,7 @@ var Resolver = class Resolver extends Tag$2("Resolver")() {
27243
27388
  return make$2(yield* Api);
27244
27389
  }));
27245
27390
  };
27246
- const del$4 = make$12("delete", {
27391
+ const del$5 = make$12("delete", {
27247
27392
  slugOrId: text$3({ name: "slugOrId" }),
27248
27393
  force: boolean("force")
27249
27394
  }, ({ slugOrId, force }) => gen(function* () {
@@ -27254,7 +27399,7 @@ const del$4 = make$12("delete", {
27254
27399
  yield* api.request(`/categories/${id}`, { method: "DELETE" });
27255
27400
  yield* renderer.emitSuccess({ deleted: id });
27256
27401
  }));
27257
- const get$5 = make$12("get", { slugOrId: text$3({ name: "slugOrId" }) }, ({ slugOrId }) => gen(function* () {
27402
+ const get$6 = make$12("get", { slugOrId: text$3({ name: "slugOrId" }) }, ({ slugOrId }) => gen(function* () {
27258
27403
  const api = yield* Api;
27259
27404
  const renderer = yield* Renderer;
27260
27405
  const res = yield* api.request(`/categories/${encodeURIComponent(slugOrId)}`);
@@ -27262,7 +27407,7 @@ const get$5 = make$12("get", { slugOrId: text$3({ name: "slugOrId" }) }, ({ slug
27262
27407
  }));
27263
27408
  //#endregion
27264
27409
  //#region src/cli/category/list.ts
27265
- const list$5 = make$12("list", {}, () => gen(function* () {
27410
+ const list$6 = make$12("list", {}, () => gen(function* () {
27266
27411
  const api = yield* Api;
27267
27412
  const renderer = yield* Renderer;
27268
27413
  const res = yield* api.request("/categories");
@@ -27295,7 +27440,7 @@ const update$4 = make$12("update", {
27295
27440
  }));
27296
27441
  //#endregion
27297
27442
  //#region src/cli/category/index.ts
27298
- const help$6 = registerCommandHelp({
27443
+ const help$7 = registerCommandHelp({
27299
27444
  name: "category",
27300
27445
  description: "manage categories / tags",
27301
27446
  verbs: [
@@ -27335,11 +27480,457 @@ const help$6 = registerCommandHelp({
27335
27480
  }
27336
27481
  ]
27337
27482
  });
27338
- const categoryCmd = make$12("category").pipe(withDescription(help$6.description), withSubcommands([
27339
- list$5,
27340
- get$5,
27483
+ const categoryCmd = make$12("category").pipe(withDescription(help$7.description), withSubcommands([
27484
+ list$6,
27485
+ get$6,
27341
27486
  create$4,
27342
27487
  update$4,
27488
+ del$5
27489
+ ]));
27490
+ //#endregion
27491
+ //#region src/services/Comment.ts
27492
+ const COMMENT_STATE_NAMES = [
27493
+ "unread",
27494
+ "read",
27495
+ "junk"
27496
+ ];
27497
+ const stateToCode = {
27498
+ unread: 0,
27499
+ read: 1,
27500
+ junk: 2
27501
+ };
27502
+ const codeToState = {
27503
+ 0: "unread",
27504
+ 1: "read",
27505
+ 2: "junk"
27506
+ };
27507
+ const stateNameToCode = (s) => stateToCode[s];
27508
+ const stateCodeToName = (n) => codeToState[n];
27509
+ const mergeListResponses = (responses) => {
27510
+ const data = [];
27511
+ const readers = {};
27512
+ let total = 0;
27513
+ for (const r of responses) {
27514
+ if (Array.isArray(r.data)) data.push(...r.data);
27515
+ if (r.readers) Object.assign(readers, r.readers);
27516
+ const t = r.pagination && typeof r.pagination.total === "number" ? r.pagination.total : 0;
27517
+ total += t;
27518
+ }
27519
+ return {
27520
+ data,
27521
+ pagination: {
27522
+ total,
27523
+ size: data.length,
27524
+ page: 1,
27525
+ totalPages: 1
27526
+ },
27527
+ readers
27528
+ };
27529
+ };
27530
+ const makeService$1 = (api) => {
27531
+ const requestList = (state, page, size) => api.request("/comments", { query: {
27532
+ page,
27533
+ size,
27534
+ state: stateNameToCode(state)
27535
+ } });
27536
+ const patchBatchState = (body) => asVoid(api.request("/comments/batch/state", {
27537
+ method: "PATCH",
27538
+ body
27539
+ }));
27540
+ const deleteBatch = (body) => asVoid(api.request("/comments/batch", {
27541
+ method: "DELETE",
27542
+ body
27543
+ }));
27544
+ return {
27545
+ list: (opts) => {
27546
+ if (opts.all) return all$4(COMMENT_STATE_NAMES.map((s) => requestList(s, opts.page, opts.size)), { concurrency: 3 }).pipe(map$6(mergeListResponses));
27547
+ return requestList(opts.state ?? "unread", opts.page, opts.size);
27548
+ },
27549
+ get: (id) => api.request(`/comments/${id}`),
27550
+ approve: (ids) => patchBatchState({
27551
+ ids: [...ids],
27552
+ state: stateToCode.read
27553
+ }),
27554
+ reject: (ids) => patchBatchState({
27555
+ ids: [...ids],
27556
+ state: stateToCode.junk
27557
+ }),
27558
+ delete: (ids) => deleteBatch({ ids: [...ids] }),
27559
+ approveAll: (filter) => patchBatchState({
27560
+ all: true,
27561
+ state: stateToCode.read,
27562
+ currentState: filter.currentState !== void 0 ? stateNameToCode(filter.currentState) : void 0
27563
+ }),
27564
+ rejectAll: (filter) => patchBatchState({
27565
+ all: true,
27566
+ state: stateToCode.junk,
27567
+ currentState: filter.currentState !== void 0 ? stateNameToCode(filter.currentState) : void 0
27568
+ }),
27569
+ deleteAll: (filter) => deleteBatch({
27570
+ all: true,
27571
+ state: filter.currentState !== void 0 ? stateNameToCode(filter.currentState) : void 0
27572
+ })
27573
+ };
27574
+ };
27575
+ var Comment = class Comment extends Tag$2("Comment")() {
27576
+ static Default = effect(Comment, gen(function* () {
27577
+ return makeService$1(yield* Api);
27578
+ }));
27579
+ };
27580
+ //#endregion
27581
+ //#region src/cli/comment/_flags.ts
27582
+ const ids = text$3({ name: "id" }).pipe(repeated);
27583
+ const all = boolean("all").pipe(withDescription$3("apply to every comment (optionally filtered by --state)"));
27584
+ const force$6 = boolean("force").pipe(withDescription$3("skip TTY confirmation guard"));
27585
+ const stateFilter = choice("state", [
27586
+ "unread",
27587
+ "read",
27588
+ "junk"
27589
+ ]).pipe(optional$2);
27590
+ const unwrapOption = (value) => getOrUndefined(value);
27591
+ /**
27592
+ * Shared invariants for ids/--all batch verbs (`approve`, `reject`, `delete`).
27593
+ *
27594
+ * - exactly one of `ids` (>= 1) or `--all` MUST be supplied
27595
+ * - `--all` in a non-TTY context requires `--force`
27596
+ * - additional guards (e.g. single-id `delete`) are applied per-verb
27597
+ */
27598
+ const validateBatchSelection = (params) => suspend(() => {
27599
+ if (params.all && params.ids.length > 0) return fail$2(new ValidationFailed({ message: "--all cannot be combined with explicit ids" }));
27600
+ if (!params.all && params.ids.length === 0) return fail$2(new ValidationFailed({ message: `${params.verb} requires at least one id or --all` }));
27601
+ if (params.all && !params.force && !process.stdin.isTTY) return fail$2(new ValidationFailed({ message: `refusing to ${params.verb} --all without --force in non-TTY context` }));
27602
+ return _void;
27603
+ });
27604
+ const requireForceForSingleDelete = (params) => suspend(() => {
27605
+ if (params.all) return _void;
27606
+ if (params.force) return _void;
27607
+ if (process.stdin.isTTY) return _void;
27608
+ return fail$2(new ValidationFailed({ message: "refusing to delete without --force in non-TTY context" }));
27609
+ });
27610
+ //#endregion
27611
+ //#region src/cli/comment/approve.ts
27612
+ const approve = make$12("approve", {
27613
+ ids,
27614
+ all,
27615
+ force: force$6,
27616
+ state: stateFilter
27617
+ }, ({ ids, all, force, state }) => gen(function* () {
27618
+ yield* validateBatchSelection({
27619
+ verb: "approve",
27620
+ ids,
27621
+ all,
27622
+ force
27623
+ });
27624
+ const comment = yield* Comment;
27625
+ const renderer = yield* Renderer;
27626
+ if (all) {
27627
+ yield* comment.approveAll({ currentState: unwrapOption(state) });
27628
+ yield* renderer.emitSuccess({
27629
+ approved: "all",
27630
+ filter: { currentState: unwrapOption(state) ?? null }
27631
+ });
27632
+ } else {
27633
+ yield* comment.approve(ids);
27634
+ yield* renderer.emitSuccess({ approved: ids });
27635
+ }
27636
+ })).pipe(withDescription("mark comments as read; pass ids or --all [--state <s>]"));
27637
+ //#endregion
27638
+ //#region src/cli/comment/delete.ts
27639
+ const del$4 = make$12("delete", {
27640
+ ids,
27641
+ all,
27642
+ force: force$6,
27643
+ state: stateFilter
27644
+ }, ({ ids, all, force, state }) => gen(function* () {
27645
+ yield* validateBatchSelection({
27646
+ verb: "delete",
27647
+ ids,
27648
+ all,
27649
+ force
27650
+ });
27651
+ yield* requireForceForSingleDelete({
27652
+ ids,
27653
+ all,
27654
+ force
27655
+ });
27656
+ const comment = yield* Comment;
27657
+ const renderer = yield* Renderer;
27658
+ if (all) {
27659
+ yield* comment.deleteAll({ currentState: unwrapOption(state) });
27660
+ yield* renderer.emitSuccess({
27661
+ deleted: "all",
27662
+ filter: { currentState: unwrapOption(state) ?? null }
27663
+ });
27664
+ } else {
27665
+ yield* comment.delete(ids);
27666
+ yield* renderer.emitSuccess({ deleted: ids });
27667
+ }
27668
+ })).pipe(withDescription("soft-delete comments; pass ids or --all [--state <s>]"));
27669
+ //#endregion
27670
+ //#region src/cli/comment/view.ts
27671
+ const normalize$3 = (data) => asRecord(unwrapDocument(data));
27672
+ const stateLabel = (raw) => {
27673
+ if (typeof raw === "number") return stateCodeToName(raw) ?? String(raw);
27674
+ if (typeof raw === "string") return raw;
27675
+ return "";
27676
+ };
27677
+ const colorForCommentState = (raw, color) => {
27678
+ const label = stateLabel(raw);
27679
+ if (!label) return void 0;
27680
+ if (label === "unread") return wrap(ANSI.yellow, label, color);
27681
+ if (label === "read") return wrap(ANSI.green, label, color);
27682
+ if (label === "junk") return wrap(ANSI.red, label, color);
27683
+ return formatStateBadge(label, color) ?? label;
27684
+ };
27685
+ const truncate = (s, max = 80) => s.length > max ? `${s.slice(0, max - 1)}…` : s;
27686
+ const oneLine = (s) => s.replaceAll(/\s+/g, " ").trim();
27687
+ const authorOf = (doc) => {
27688
+ const reader = asRecord(first(doc, "reader"));
27689
+ if (Object.keys(reader).length > 0) {
27690
+ const name = firstString(reader, "nickname", "name");
27691
+ if (name) return name;
27692
+ }
27693
+ return firstString(doc, "author") || "(anonymous)";
27694
+ };
27695
+ const refLabel = (doc) => {
27696
+ const refType = firstString(doc, "ref_type", "refType");
27697
+ const title = firstString(asRecord(first(doc, "ref")), "title", "slug", "id");
27698
+ if (refType && title) return `${refType}:${title}`;
27699
+ if (refType) return refType;
27700
+ return "";
27701
+ };
27702
+ const collectDetailFields = (doc) => {
27703
+ return [
27704
+ ["id", first(doc, "id")],
27705
+ ["author", authorOf(doc)],
27706
+ ["mail", first(doc, "mail")],
27707
+ ["url", first(doc, "url")],
27708
+ ["ip", first(doc, "ip")],
27709
+ ["location", first(doc, "location")],
27710
+ ["ref", refLabel(doc)],
27711
+ ["state", stateLabel(first(doc, "state"))],
27712
+ ["pin", first(doc, "pin")],
27713
+ ["is_whispers", first(doc, "is_whispers", "isWhispers")],
27714
+ ["created_at", first(doc, "created_at", "createdAt")]
27715
+ ].filter(([, value]) => value !== void 0 && value !== null && value !== "");
27716
+ };
27717
+ const renderCommentReadable = (data, color) => {
27718
+ const doc = normalize$3(data);
27719
+ return renderMetadataBlock({
27720
+ title: `comment from ${authorOf(doc)}`,
27721
+ kind: "comment",
27722
+ fields: collectDetailFields(doc),
27723
+ body: firstString(doc, "text") || void 0,
27724
+ bodyFormat: "markdown"
27725
+ }, { color });
27726
+ };
27727
+ const renderCommentLlm = (data) => {
27728
+ const doc = normalize$3(data);
27729
+ const fm = frontmatter({
27730
+ title: `comment ${firstString(doc, "id") || ""}`.trim(),
27731
+ fields: collectDetailFields(doc)
27732
+ });
27733
+ const text = firstString(doc, "text");
27734
+ return text ? `${fm}\n\n${text}` : fm;
27735
+ };
27736
+ const commentView = {
27737
+ kind: "comment",
27738
+ modes: new Set(["readable", "llm"]),
27739
+ readable: (data, ctx) => renderCommentReadable(data, ctx.color),
27740
+ llm: (data) => renderCommentLlm(data)
27741
+ };
27742
+ const renderListHeader = (payload, rowCount, color) => {
27743
+ const pagination = asRecord(first(payload, "pagination"));
27744
+ const page = first(pagination, "page", "currentPage");
27745
+ const size = first(pagination, "size", "pageSize");
27746
+ const total = first(pagination, "total", "totalCount");
27747
+ const meta = [`count: ${rowCount}`];
27748
+ if (page !== void 0) meta.push(`page: ${formatScalar(page)}`);
27749
+ if (size !== void 0) meta.push(`size: ${formatScalar(size)}`);
27750
+ if (total !== void 0) meta.push(`total: ${formatScalar(total)}`);
27751
+ const heading = wrap(ANSI.bold, "Comments", color);
27752
+ const ruleLen = Math.min(Math.max(visibleLen("Comments"), 24), 64);
27753
+ return `${heading}\n${wrap(ANSI.dim, "─".repeat(ruleLen), color)}\n${wrap(ANSI.dim, meta.join(" · "), color)}`;
27754
+ };
27755
+ const renderListItem = (doc, index, color) => {
27756
+ const author = authorOf(doc);
27757
+ const id = firstString(doc, "id");
27758
+ const stateBadge = colorForCommentState(first(doc, "state"), color) ?? stateLabel(first(doc, "state"));
27759
+ const ref = refLabel(doc);
27760
+ const created = first(doc, "created_at", "createdAt");
27761
+ const lines = [];
27762
+ const indexLabel = wrap(ANSI.dim, `${index + 1}.`, color);
27763
+ const authorBold = wrap(ANSI.bold, author, color);
27764
+ const idDim = id ? wrap(ANSI.dim, `#${id}`, color) : "";
27765
+ const header = [
27766
+ indexLabel,
27767
+ authorBold,
27768
+ `[${stateBadge}]`,
27769
+ idDim
27770
+ ].filter(Boolean).join(" ");
27771
+ lines.push(header);
27772
+ const metaParts = [];
27773
+ if (ref) metaParts.push(ref);
27774
+ if (created !== void 0) metaParts.push(tryFormatTimestamp(created, { style: "rel" }) ?? formatScalar(created));
27775
+ if (metaParts.length > 0) lines.push(wrap(ANSI.dim, ` ${metaParts.join(" · ")}`, color));
27776
+ const text = firstString(doc, "text");
27777
+ if (text) lines.push(` ${truncate(oneLine(text))}`);
27778
+ return lines.join("\n");
27779
+ };
27780
+ const renderCommentListReadable = (data, color) => {
27781
+ const payload = asRecord(data);
27782
+ const rows = Array.isArray(payload.data) ? payload.data : Array.isArray(data) ? data : [];
27783
+ const header = renderListHeader(payload, rows.length, color);
27784
+ if (rows.length === 0) return `${header}\n\n${wrap(ANSI.dim, "(no comments)", color)}`;
27785
+ return `${header}\n\n${rows.map((row, index) => renderListItem(asRecord(row), index, color)).join("\n\n")}`;
27786
+ };
27787
+ const renderCommentListLlm = (data) => {
27788
+ const payload = asRecord(data);
27789
+ const rows = Array.isArray(payload.data) ? payload.data : Array.isArray(data) ? data : [];
27790
+ if (rows.length === 0) return renderMarkdownToAnsi("# Comments\n\n_no comments_\n", { color: false });
27791
+ return rows.map((row) => {
27792
+ const doc = asRecord(row);
27793
+ const fm = frontmatter({
27794
+ title: `comment ${firstString(doc, "id") || ""}`.trim(),
27795
+ fields: collectDetailFields(doc)
27796
+ });
27797
+ const text = firstString(doc, "text");
27798
+ return text ? `${fm}\n\n${text}` : fm;
27799
+ }).join("\n\n---\n\n");
27800
+ };
27801
+ const commentListView = {
27802
+ kind: "comment-list",
27803
+ modes: new Set(["readable", "llm"]),
27804
+ readable: (data, ctx) => renderCommentListReadable(data, ctx.color),
27805
+ llm: (data) => renderCommentListLlm(data)
27806
+ };
27807
+ const get$5 = make$12("get", { id: text$3({ name: "id" }) }, ({ id }) => gen(function* () {
27808
+ const comment = yield* Comment;
27809
+ const renderer = yield* Renderer;
27810
+ const res = yield* comment.get(id);
27811
+ yield* renderer.emit(commentView, res);
27812
+ })).pipe(withDescription("show a single comment by id"));
27813
+ const list$5 = make$12("list", {
27814
+ page: integer("page").pipe(optional$2),
27815
+ size: integer("size").pipe(optional$2),
27816
+ state: stateFilter,
27817
+ all: boolean("all").pipe(withDescription$3("list comments across every state (ignores --state)"))
27818
+ }, ({ page, size, state, all }) => gen(function* () {
27819
+ const comment = yield* Comment;
27820
+ const renderer = yield* Renderer;
27821
+ const res = yield* comment.list({
27822
+ page: unwrapOption(page),
27823
+ size: unwrapOption(size),
27824
+ state: unwrapOption(state),
27825
+ all
27826
+ });
27827
+ yield* renderer.emit(commentListView, res);
27828
+ })).pipe(withDescription("list comments (default state: unread; use --all for every state)"));
27829
+ //#endregion
27830
+ //#region src/cli/comment/reject.ts
27831
+ const reject = make$12("reject", {
27832
+ ids,
27833
+ all,
27834
+ force: force$6,
27835
+ state: stateFilter
27836
+ }, ({ ids, all, force, state }) => gen(function* () {
27837
+ yield* validateBatchSelection({
27838
+ verb: "reject",
27839
+ ids,
27840
+ all,
27841
+ force
27842
+ });
27843
+ const comment = yield* Comment;
27844
+ const renderer = yield* Renderer;
27845
+ if (all) {
27846
+ yield* comment.rejectAll({ currentState: unwrapOption(state) });
27847
+ yield* renderer.emitSuccess({
27848
+ rejected: "all",
27849
+ filter: { currentState: unwrapOption(state) ?? null }
27850
+ });
27851
+ } else {
27852
+ yield* comment.reject(ids);
27853
+ yield* renderer.emitSuccess({ rejected: ids });
27854
+ }
27855
+ })).pipe(withDescription("mark comments as junk; pass ids or --all [--state <s>]"));
27856
+ const unread = make$12("unread", {
27857
+ page: integer("page").pipe(optional$2),
27858
+ size: integer("size").pipe(optional$2)
27859
+ }, ({ page, size }) => gen(function* () {
27860
+ const comment = yield* Comment;
27861
+ const renderer = yield* Renderer;
27862
+ const res = yield* comment.list({
27863
+ page: unwrapOption(page),
27864
+ size: unwrapOption(size),
27865
+ state: "unread"
27866
+ });
27867
+ yield* renderer.emit(commentListView, res);
27868
+ })).pipe(withDescription("list unread comments (alias for `comment list --state unread`)"));
27869
+ //#endregion
27870
+ //#region src/cli/comment/index.ts
27871
+ const help$6 = registerCommandHelp({
27872
+ name: "comment",
27873
+ description: "list and moderate comments",
27874
+ verbs: [
27875
+ {
27876
+ name: "list",
27877
+ args: [
27878
+ "[--page <n>]",
27879
+ "[--size <n>]",
27880
+ "[--state <s>]",
27881
+ "[--all]"
27882
+ ],
27883
+ description: "list comments (default state: unread; --all aggregates every state)"
27884
+ },
27885
+ {
27886
+ name: "unread",
27887
+ args: ["[--page <n>]", "[--size <n>]"],
27888
+ description: "alias for `list --state unread`"
27889
+ },
27890
+ {
27891
+ name: "get",
27892
+ args: ["<id>"],
27893
+ description: "show a single comment"
27894
+ },
27895
+ {
27896
+ name: "approve",
27897
+ args: [
27898
+ "<id...>",
27899
+ "|",
27900
+ "--all",
27901
+ "[--state <s>]"
27902
+ ],
27903
+ description: "mark comments as read"
27904
+ },
27905
+ {
27906
+ name: "reject",
27907
+ args: [
27908
+ "<id...>",
27909
+ "|",
27910
+ "--all",
27911
+ "[--state <s>]"
27912
+ ],
27913
+ description: "mark comments as junk"
27914
+ },
27915
+ {
27916
+ name: "delete",
27917
+ args: [
27918
+ "<id...>",
27919
+ "|",
27920
+ "--all",
27921
+ "[--state <s>]",
27922
+ "[--force]"
27923
+ ],
27924
+ description: "soft-delete comments"
27925
+ }
27926
+ ]
27927
+ });
27928
+ const commentCmd = make$12("comment").pipe(withDescription(help$6.description), withSubcommands([
27929
+ list$5,
27930
+ unread,
27931
+ get$5,
27932
+ approve,
27933
+ reject,
27343
27934
  del$4
27344
27935
  ]));
27345
27936
  //#endregion
@@ -27459,6 +28050,32 @@ const configCmd = make$12("config").pipe(withDescription(help$5.description), wi
27459
28050
  edit$3
27460
28051
  ]));
27461
28052
  //#endregion
28053
+ //#region src/domain/admin-link.ts
28054
+ const buildEditUrl = (adminUrl, kind, id) => {
28055
+ return `${adminUrl.replace(/\/+$/, "")}#/${kind}/edit?id=${encodeURIComponent(id)}`;
28056
+ };
28057
+ /**
28058
+ * Resolve the server's admin URL from `/options/url`, build the admin
28059
+ * edit-page URL for the given resource, and open it in the user's browser.
28060
+ * Non-fatal: missing admin_url or browser-launch failures emit a warning
28061
+ * and the parent effect continues.
28062
+ */
28063
+ const openAdminEdit = (kind, id) => gen(function* () {
28064
+ const renderer = yield* Renderer;
28065
+ const opts = yield* (yield* Api).request("/options/url");
28066
+ const adminUrl = opts.data?.admin_url ?? opts.admin_url;
28067
+ if (!adminUrl) {
28068
+ yield* renderer.emitWarn("admin_url is not configured on the server; skipping --open");
28069
+ return;
28070
+ }
28071
+ const url = buildEditUrl(adminUrl, kind, id);
28072
+ yield* renderer.emitInfo(`opening admin: ${url}`);
28073
+ yield* tryPromise({
28074
+ try: () => open(url),
28075
+ catch: () => /* @__PURE__ */ new Error("failed to launch browser")
28076
+ }).pipe(catchAll((e) => renderer.emitWarn(`could not launch browser: ${e instanceof Error ? e.message : String(e)}`)));
28077
+ });
28078
+ //#endregion
27462
28079
  //#region ../../node_modules/.pnpm/@lexical+table@0.44.0/node_modules/@lexical/table/LexicalTable.node.mjs
27463
28080
  /**
27464
28081
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -29130,28 +29747,102 @@ const resolveContent = (flagSpec, envelope, format) => gen(function* () {
29130
29747
  };
29131
29748
  });
29132
29749
  //#endregion
29133
- //#region src/cli/note/_flags.ts
29750
+ //#region src/cli/post/_flags.ts
29134
29751
  const optional$1 = (self) => optional$2(self);
29135
29752
  const unwrap$4 = (value) => getOrUndefined(value);
29136
29753
  const title$2 = optional$1(text$1("title"));
29137
29754
  const slug$4 = optional$1(text$1("slug"));
29138
- const topic = optional$1(text$1("topic"));
29755
+ const category = optional$1(text$1("category"));
29139
29756
  const content$2 = optional$1(text$1("content"));
29140
- const mood = optional$1(text$1("mood"));
29141
- const weather = optional$1(text$1("weather"));
29142
- const publicAt = optional$1(text$1("public-at"));
29143
- const password = optional$1(text$1("password"));
29144
- const coords = optional$1(text$1("coords"));
29145
- const location$1 = optional$1(text$1("location"));
29146
- const images = optional$1(text$1("images"));
29147
- const meta$2 = optional$1(text$1("meta"));
29757
+ const summary = optional$1(text$1("summary"));
29148
29758
  const file$2 = optional$1(text$1("file"));
29149
- const bookmark = optional$1(text$1("bookmark"));
29150
- const noteWriteOptions = {
29759
+ const meta$2 = optional$1(text$1("meta"));
29760
+ const pin = optional$1(text$1("pin"));
29761
+ const format$2 = choice("format", ["lexical", "markdown"]).pipe(optional$2);
29762
+ const state$3 = choice("state", ["publish", "draft"]).pipe(optional$2);
29763
+ const tags = optional$1(text$1("tags"));
29764
+ const related = optional$1(text$1("related"));
29765
+ const pinOrder = optional$1(integer("pin-order"));
29766
+ const copyright = optional$1(text$1("copyright"));
29767
+ const openFlag$2 = boolean("open").pipe(withDescription$3("After success, open the admin edit page in the default browser."));
29768
+ const silentFlag$2 = boolean("silent").pipe(withDescription$3("On success, emit a minimal `ok` instead of the full server response (saves output tokens). Errors still print normally."));
29769
+ const parseCsv = (v) => {
29770
+ if (v === void 0) return void 0;
29771
+ return v.split(",").map((s) => s.trim()).filter(Boolean);
29772
+ };
29773
+ const parseCopyright = (v) => v === void 0 ? void 0 : v === "true";
29774
+ const postWriteOptions = {
29151
29775
  title: title$2,
29152
29776
  slug: slug$4,
29153
- topic,
29777
+ category,
29154
29778
  content: content$2,
29779
+ format: format$2,
29780
+ summary,
29781
+ state: state$3,
29782
+ tags,
29783
+ copyright,
29784
+ pin,
29785
+ pinOrder,
29786
+ related,
29787
+ meta: meta$2,
29788
+ file: file$2,
29789
+ open: openFlag$2,
29790
+ silent: silentFlag$2
29791
+ };
29792
+ /** Resolve `__categoryName` placeholder (set by `buildPostPayload`) → `categoryId`. */
29793
+ const resolveCategoryRefs = (payload) => gen(function* () {
29794
+ const next = { ...payload };
29795
+ const nameRef = next.__categoryName;
29796
+ delete next.__categoryName;
29797
+ if (typeof nameRef === "string" && nameRef.length > 0 && !next.categoryId) next.categoryId = yield* (yield* Resolver).resolveCategory(nameRef);
29798
+ return next;
29799
+ });
29800
+ const toPostFlagInputs = (opts) => ({
29801
+ title: unwrap$4(opts.title),
29802
+ slug: unwrap$4(opts.slug),
29803
+ category: unwrap$4(opts.category),
29804
+ content: unwrap$4(opts.content),
29805
+ format: unwrap$4(opts.format),
29806
+ summary: unwrap$4(opts.summary),
29807
+ state: unwrap$4(opts.state),
29808
+ tags: parseCsv(unwrap$4(opts.tags)),
29809
+ copyright: parseCopyright(unwrap$4(opts.copyright)),
29810
+ pin: unwrap$4(opts.pin),
29811
+ pinOrder: unwrap$4(opts.pinOrder),
29812
+ related: parseCsv(unwrap$4(opts.related)),
29813
+ meta: unwrap$4(opts.meta),
29814
+ file: unwrap$4(opts.file)
29815
+ });
29816
+ /** Extract the id from a server response — handles both `id` and `_id`. */
29817
+ const extractId = (res) => {
29818
+ if (!res || typeof res !== "object") return void 0;
29819
+ const r = res;
29820
+ if (typeof r.id === "string") return r.id;
29821
+ if (typeof r._id === "string") return r._id;
29822
+ };
29823
+ //#endregion
29824
+ //#region src/cli/note/_flags.ts
29825
+ const optional = (self) => optional$2(self);
29826
+ const unwrap$3 = (value) => getOrUndefined(value);
29827
+ const title$1 = optional(text$1("title"));
29828
+ const slug$3 = optional(text$1("slug"));
29829
+ const topic = optional(text$1("topic"));
29830
+ const content$1 = optional(text$1("content"));
29831
+ const mood = optional(text$1("mood"));
29832
+ const weather = optional(text$1("weather"));
29833
+ const publicAt = optional(text$1("public-at"));
29834
+ const password = optional(text$1("password"));
29835
+ const coords = optional(text$1("coords"));
29836
+ const location$1 = optional(text$1("location"));
29837
+ const images = optional(text$1("images"));
29838
+ const meta$1 = optional(text$1("meta"));
29839
+ const file$1 = optional(text$1("file"));
29840
+ const bookmark = optional(text$1("bookmark"));
29841
+ const noteWriteOptions = {
29842
+ title: title$1,
29843
+ slug: slug$3,
29844
+ topic,
29845
+ content: content$1,
29155
29846
  format: choice("format", ["lexical", "markdown"]).pipe(optional$2),
29156
29847
  state: choice("state", ["publish", "draft"]).pipe(optional$2),
29157
29848
  mood,
@@ -29162,27 +29853,29 @@ const noteWriteOptions = {
29162
29853
  coords,
29163
29854
  location: location$1,
29164
29855
  images,
29165
- meta: meta$2,
29166
- file: file$2
29856
+ meta: meta$1,
29857
+ file: file$1,
29858
+ open: boolean("open").pipe(withDescription$3("After success, open the admin edit page in the default browser.")),
29859
+ silent: boolean("silent").pipe(withDescription$3("On success, emit a minimal `ok` instead of the full server response (saves output tokens). Errors still print normally."))
29167
29860
  };
29168
29861
  const parseBoolean = (v) => v === void 0 ? void 0 : v === "true";
29169
29862
  const toNoteFlagInputs = (opts) => ({
29170
- title: unwrap$4(opts.title),
29171
- slug: unwrap$4(opts.slug),
29172
- topic: unwrap$4(opts.topic),
29173
- content: unwrap$4(opts.content),
29174
- format: unwrap$4(opts.format),
29175
- state: unwrap$4(opts.state),
29176
- mood: unwrap$4(opts.mood),
29177
- weather: unwrap$4(opts.weather),
29178
- publicAt: unwrap$4(opts.publicAt),
29179
- password: unwrap$4(opts.password),
29180
- bookmark: parseBoolean(unwrap$4(opts.bookmark)),
29181
- coords: unwrap$4(opts.coords),
29182
- location: unwrap$4(opts.location),
29183
- images: unwrap$4(opts.images),
29184
- meta: unwrap$4(opts.meta),
29185
- file: unwrap$4(opts.file)
29863
+ title: unwrap$3(opts.title),
29864
+ slug: unwrap$3(opts.slug),
29865
+ topic: unwrap$3(opts.topic),
29866
+ content: unwrap$3(opts.content),
29867
+ format: unwrap$3(opts.format),
29868
+ state: unwrap$3(opts.state),
29869
+ mood: unwrap$3(opts.mood),
29870
+ weather: unwrap$3(opts.weather),
29871
+ publicAt: unwrap$3(opts.publicAt),
29872
+ password: unwrap$3(opts.password),
29873
+ bookmark: parseBoolean(unwrap$3(opts.bookmark)),
29874
+ coords: unwrap$3(opts.coords),
29875
+ location: unwrap$3(opts.location),
29876
+ images: unwrap$3(opts.images),
29877
+ meta: unwrap$3(opts.meta),
29878
+ file: unwrap$3(opts.file)
29186
29879
  });
29187
29880
  /** Resolve `__topicName` placeholder → `topicId`. */
29188
29881
  const resolveTopicRefs = (payload) => gen(function* () {
@@ -29202,7 +29895,11 @@ const create$3 = make$12("create", noteWriteOptions, (opts) => gen(function* ()
29202
29895
  method: "POST",
29203
29896
  body: payload
29204
29897
  });
29205
- yield* renderer.emitSuccess(res);
29898
+ yield* renderer.emitSuccess(opts.silent ? { ok: true } : res);
29899
+ if (opts.open) {
29900
+ const id = extractId(res);
29901
+ if (id) yield* openAdminEdit("notes", id);
29902
+ }
29206
29903
  })).pipe(withDescription("create a note"));
29207
29904
  const del$3 = make$12("delete", {
29208
29905
  slugOrId: text$3({ name: "slugOrId" }),
@@ -29405,21 +30102,21 @@ const get$3 = make$12("get", { slugOrId: text$3({ name: "slugOrId" }) }, ({ slug
29405
30102
  //#region src/cli/note/list.ts
29406
30103
  const page$1 = integer("page").pipe(optional$2);
29407
30104
  const size$1 = integer("size").pipe(optional$2);
29408
- const state$2 = text$1("state").pipe(optional$2);
30105
+ const state$1 = text$1("state").pipe(optional$2);
29409
30106
  const sort$1 = text$1("sort").pipe(optional$2);
29410
- const unwrap$3 = (value) => getOrUndefined(value);
30107
+ const unwrap$2 = (value) => getOrUndefined(value);
29411
30108
  const list$3 = make$12("list", {
29412
30109
  page: page$1,
29413
30110
  size: size$1,
29414
- state: state$2,
30111
+ state: state$1,
29415
30112
  sort: sort$1
29416
30113
  }, ({ page, size, sort }) => gen(function* () {
29417
30114
  const api = yield* Api;
29418
30115
  const renderer = yield* Renderer;
29419
30116
  const res = yield* api.request("/notes", { query: {
29420
- page: unwrap$3(page),
29421
- size: unwrap$3(size),
29422
- sortBy: unwrap$3(sort)
30117
+ page: unwrap$2(page),
30118
+ size: unwrap$2(size),
30119
+ sortBy: unwrap$2(sort)
29423
30120
  } });
29424
30121
  yield* renderer.emitSuccess(res);
29425
30122
  })).pipe(withDescription("list notes"));
@@ -29464,7 +30161,8 @@ const update$3 = make$12("update", {
29464
30161
  method: "PATCH",
29465
30162
  body: resolved
29466
30163
  });
29467
- yield* renderer.emitSuccess(res);
30164
+ yield* renderer.emitSuccess(rest.silent ? { ok: true } : res);
30165
+ if (rest.open) yield* openAdminEdit("notes", id);
29468
30166
  })).pipe(withDescription("partially update a note"));
29469
30167
  //#endregion
29470
30168
  //#region src/cli/note/index.ts
@@ -29549,18 +30247,20 @@ const pageWriteOptions = {
29549
30247
  content: optional$2(text$1("content")),
29550
30248
  format: choice("format", ["lexical", "markdown"]).pipe(optional$2),
29551
30249
  meta: optional$2(text$1("meta")),
29552
- file: optional$2(text$1("file"))
30250
+ file: optional$2(text$1("file")),
30251
+ open: boolean("open").pipe(withDescription$3("After success, open the admin edit page in the default browser.")),
30252
+ silent: boolean("silent").pipe(withDescription$3("On success, emit a minimal `ok` instead of the full server response (saves output tokens). Errors still print normally."))
29553
30253
  };
29554
- const unwrap$2 = (value) => getOrUndefined(value);
30254
+ const unwrap$1 = (value) => getOrUndefined(value);
29555
30255
  const toPageFlagInputs = (opts) => ({
29556
- title: unwrap$2(opts.title),
29557
- slug: unwrap$2(opts.slug),
29558
- subtitle: unwrap$2(opts.subtitle),
29559
- order: unwrap$2(opts.order),
29560
- content: unwrap$2(opts.content),
29561
- format: unwrap$2(opts.format),
29562
- meta: unwrap$2(opts.meta),
29563
- file: unwrap$2(opts.file)
30256
+ title: unwrap$1(opts.title),
30257
+ slug: unwrap$1(opts.slug),
30258
+ subtitle: unwrap$1(opts.subtitle),
30259
+ order: unwrap$1(opts.order),
30260
+ content: unwrap$1(opts.content),
30261
+ format: unwrap$1(opts.format),
30262
+ meta: unwrap$1(opts.meta),
30263
+ file: unwrap$1(opts.file)
29564
30264
  });
29565
30265
  const create$2 = make$12("create", pageWriteOptions, (opts) => gen(function* () {
29566
30266
  const built = yield* buildPagePayload(toPageFlagInputs(opts));
@@ -29570,7 +30270,11 @@ const create$2 = make$12("create", pageWriteOptions, (opts) => gen(function* ()
29570
30270
  method: "POST",
29571
30271
  body: built.payload
29572
30272
  });
29573
- yield* renderer.emitSuccess(res);
30273
+ yield* renderer.emitSuccess(opts.silent ? { ok: true } : res);
30274
+ if (opts.open) {
30275
+ const id = extractId(res);
30276
+ if (id) yield* openAdminEdit("pages", id);
30277
+ }
29574
30278
  }));
29575
30279
  //#endregion
29576
30280
  //#region src/cli/page/delete.ts
@@ -29803,7 +30507,8 @@ const update$2 = make$12("update", {
29803
30507
  method: "PATCH",
29804
30508
  body
29805
30509
  });
29806
- yield* renderer.emitSuccess(res);
30510
+ yield* renderer.emitSuccess(rest.silent ? { ok: true } : res);
30511
+ if (rest.open) yield* openAdminEdit("pages", id);
29807
30512
  }));
29808
30513
  //#endregion
29809
30514
  //#region src/cli/page/index.ts
@@ -29863,69 +30568,6 @@ const pageCmd = make$12("page").pipe(withDescription(help$3.description), withSu
29863
30568
  del$2
29864
30569
  ]));
29865
30570
  //#endregion
29866
- //#region src/cli/post/_flags.ts
29867
- const optional = (self) => optional$2(self);
29868
- const unwrap$1 = (value) => getOrUndefined(value);
29869
- const title = optional(text$1("title"));
29870
- const slug$2 = optional(text$1("slug"));
29871
- const category = optional(text$1("category"));
29872
- const content = optional(text$1("content"));
29873
- const summary = optional(text$1("summary"));
29874
- const file = optional(text$1("file"));
29875
- const meta = optional(text$1("meta"));
29876
- const pin = optional(text$1("pin"));
29877
- const format = choice("format", ["lexical", "markdown"]).pipe(optional$2);
29878
- const state$1 = choice("state", ["publish", "draft"]).pipe(optional$2);
29879
- const tags = optional(text$1("tags"));
29880
- const related = optional(text$1("related"));
29881
- const pinOrder = optional(integer("pin-order"));
29882
- const copyright = optional(text$1("copyright"));
29883
- const parseCsv = (v) => {
29884
- if (v === void 0) return void 0;
29885
- return v.split(",").map((s) => s.trim()).filter(Boolean);
29886
- };
29887
- const parseCopyright = (v) => v === void 0 ? void 0 : v === "true";
29888
- const postWriteOptions = {
29889
- title,
29890
- slug: slug$2,
29891
- category,
29892
- content,
29893
- format,
29894
- summary,
29895
- state: state$1,
29896
- tags,
29897
- copyright,
29898
- pin,
29899
- pinOrder,
29900
- related,
29901
- meta,
29902
- file
29903
- };
29904
- /** Resolve `__categoryName` placeholder (set by `buildPostPayload`) → `categoryId`. */
29905
- const resolveCategoryRefs = (payload) => gen(function* () {
29906
- const next = { ...payload };
29907
- const nameRef = next.__categoryName;
29908
- delete next.__categoryName;
29909
- if (typeof nameRef === "string" && nameRef.length > 0 && !next.categoryId) next.categoryId = yield* (yield* Resolver).resolveCategory(nameRef);
29910
- return next;
29911
- });
29912
- const toPostFlagInputs = (opts) => ({
29913
- title: unwrap$1(opts.title),
29914
- slug: unwrap$1(opts.slug),
29915
- category: unwrap$1(opts.category),
29916
- content: unwrap$1(opts.content),
29917
- format: unwrap$1(opts.format),
29918
- summary: unwrap$1(opts.summary),
29919
- state: unwrap$1(opts.state),
29920
- tags: parseCsv(unwrap$1(opts.tags)),
29921
- copyright: parseCopyright(unwrap$1(opts.copyright)),
29922
- pin: unwrap$1(opts.pin),
29923
- pinOrder: unwrap$1(opts.pinOrder),
29924
- related: parseCsv(unwrap$1(opts.related)),
29925
- meta: unwrap$1(opts.meta),
29926
- file: unwrap$1(opts.file)
29927
- });
29928
- //#endregion
29929
30571
  //#region src/cli/post/create.ts
29930
30572
  const create$1 = make$12("create", postWriteOptions, (opts) => gen(function* () {
29931
30573
  const payload = yield* resolveCategoryRefs((yield* buildPostPayload(toPostFlagInputs(opts))).payload);
@@ -29935,7 +30577,11 @@ const create$1 = make$12("create", postWriteOptions, (opts) => gen(function* ()
29935
30577
  method: "POST",
29936
30578
  body: payload
29937
30579
  });
29938
- yield* renderer.emitSuccess(res);
30580
+ yield* renderer.emitSuccess(opts.silent ? { ok: true } : res);
30581
+ if (opts.open) {
30582
+ const id = extractId(res);
30583
+ if (id) yield* openAdminEdit("posts", id);
30584
+ }
29939
30585
  })).pipe(withDescription("create a post"));
29940
30586
  const del$1 = make$12("delete", {
29941
30587
  slugOrId: text$3({ name: "slugOrId" }),
@@ -30029,7 +30675,8 @@ const edit = make$12("edit", {
30029
30675
  method: "PUT",
30030
30676
  body: resolved
30031
30677
  });
30032
- yield* renderer.emitSuccess(res);
30678
+ yield* renderer.emitSuccess(rest.silent ? { ok: true } : res);
30679
+ if (rest.open) yield* openAdminEdit("posts", id);
30033
30680
  return;
30034
30681
  }
30035
30682
  const resolved = yield* resolveCategoryRefs((yield* buildPostPayload(flags)).payload);
@@ -30038,7 +30685,8 @@ const edit = make$12("edit", {
30038
30685
  method: "PUT",
30039
30686
  body: resolved
30040
30687
  });
30041
- yield* renderer.emitSuccess(res);
30688
+ yield* renderer.emitSuccess(rest.silent ? { ok: true } : res);
30689
+ if (rest.open) yield* openAdminEdit("posts", id);
30042
30690
  })).pipe(withDescription("edit a post via $EDITOR or flags"));
30043
30691
  //#endregion
30044
30692
  //#region src/cli/post/view.ts
@@ -30142,7 +30790,8 @@ const renderPostListReadable = (data) => {
30142
30790
  const fields = collectListItemFields(doc);
30143
30791
  for (const [key, value] of fields) {
30144
30792
  if (value === void 0 || value === null || value === "") continue;
30145
- lines.push(`${key}: ${formatScalar(value)}`);
30793
+ const rendered = tryFormatTimestamp(value, { style: "rel" }) ?? formatScalar(value);
30794
+ lines.push(`${key}: ${rendered}`);
30146
30795
  }
30147
30796
  });
30148
30797
  return lines.join("\n");
@@ -30223,7 +30872,8 @@ const update$1 = make$12("update", {
30223
30872
  method: "PATCH",
30224
30873
  body: resolved
30225
30874
  });
30226
- yield* renderer.emitSuccess(res);
30875
+ yield* renderer.emitSuccess(rest.silent ? { ok: true } : res);
30876
+ if (rest.open) yield* openAdminEdit("posts", id);
30227
30877
  })).pipe(withDescription("partially update a post"));
30228
30878
  //#endregion
30229
30879
  //#region src/cli/post/index.ts
@@ -30412,7 +31062,7 @@ const show = make$12("show", { name: text$3({ name: "name" }).pipe(optional$4) }
30412
31062
  const cfg = yield* config.readProfileConfig(target);
30413
31063
  const creds = yield* config.readProfileCredentials(target);
30414
31064
  const expiresAt = creds?.expires_at ?? null;
30415
- const expiresHuman = expiresAt !== null ? new Date(expiresAt).toISOString() : null;
31065
+ const expiresHuman = expiresAt !== null ? formatDateTime(expiresAt, { style: "both" }) : null;
30416
31066
  yield* renderer.emitSuccess({
30417
31067
  name: target,
30418
31068
  api_url: cfg.api_url ?? null,
@@ -32602,6 +33252,7 @@ const GROUP_NAMES = [
32602
33252
  "page",
32603
33253
  "category",
32604
33254
  "topic",
33255
+ "comment",
32605
33256
  "config",
32606
33257
  "update"
32607
33258
  ];
@@ -33204,6 +33855,7 @@ const rootCmd = make$12("mxs", {}, () => flatMap$1(Renderer, (r) => r.emitInfo("
33204
33855
  pageCmd,
33205
33856
  categoryCmd,
33206
33857
  topicCmd,
33858
+ commentCmd,
33207
33859
  configCmd,
33208
33860
  updateCmd
33209
33861
  ]));
@@ -33293,7 +33945,8 @@ const run = (argv) => {
33293
33945
  });
33294
33946
  const appWithHttp = AppLayer.pipe(provideMerge(httpLayer));
33295
33947
  const apiWithDeps = apiLayer.pipe(provideMerge(appWithHttp));
33296
- const fullAppLayer = Resolver.Default.pipe(provideMerge(apiWithDeps));
33948
+ const commentWithDeps = Comment.Default.pipe(provideMerge(apiWithDeps));
33949
+ const fullAppLayer = Resolver.Default.pipe(provideMerge(commentWithDeps));
33297
33950
  const cli = run$1(rootCmd, {
33298
33951
  name: "mxs",
33299
33952
  version: CLI_VERSION