@quikcommit/cli 10.0.0 → 11.0.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.
Files changed (2) hide show
  1. package/dist/index.js +1333 -583
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -585,13 +585,13 @@ var require_identity = __commonJS({
585
585
  var require_visit = __commonJS({
586
586
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/visit.js"(exports2) {
587
587
  "use strict";
588
- var identity = require_identity();
588
+ var identity2 = require_identity();
589
589
  var BREAK = /* @__PURE__ */ Symbol("break visit");
590
590
  var SKIP = /* @__PURE__ */ Symbol("skip children");
591
591
  var REMOVE = /* @__PURE__ */ Symbol("remove node");
592
592
  function visit(node, visitor) {
593
593
  const visitor_ = initVisitor(visitor);
594
- if (identity.isDocument(node)) {
594
+ if (identity2.isDocument(node)) {
595
595
  const cd = visit_(null, node.contents, visitor_, Object.freeze([node]));
596
596
  if (cd === REMOVE)
597
597
  node.contents = null;
@@ -603,12 +603,12 @@ var require_visit = __commonJS({
603
603
  visit.REMOVE = REMOVE;
604
604
  function visit_(key, node, visitor, path) {
605
605
  const ctrl = callVisitor(key, node, visitor, path);
606
- if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
606
+ if (identity2.isNode(ctrl) || identity2.isPair(ctrl)) {
607
607
  replaceNode(key, path, ctrl);
608
608
  return visit_(key, ctrl, visitor, path);
609
609
  }
610
610
  if (typeof ctrl !== "symbol") {
611
- if (identity.isCollection(node)) {
611
+ if (identity2.isCollection(node)) {
612
612
  path = Object.freeze(path.concat(node));
613
613
  for (let i = 0; i < node.items.length; ++i) {
614
614
  const ci = visit_(i, node.items[i], visitor, path);
@@ -621,7 +621,7 @@ var require_visit = __commonJS({
621
621
  i -= 1;
622
622
  }
623
623
  }
624
- } else if (identity.isPair(node)) {
624
+ } else if (identity2.isPair(node)) {
625
625
  path = Object.freeze(path.concat(node));
626
626
  const ck = visit_("key", node.key, visitor, path);
627
627
  if (ck === BREAK)
@@ -639,7 +639,7 @@ var require_visit = __commonJS({
639
639
  }
640
640
  async function visitAsync(node, visitor) {
641
641
  const visitor_ = initVisitor(visitor);
642
- if (identity.isDocument(node)) {
642
+ if (identity2.isDocument(node)) {
643
643
  const cd = await visitAsync_(null, node.contents, visitor_, Object.freeze([node]));
644
644
  if (cd === REMOVE)
645
645
  node.contents = null;
@@ -651,12 +651,12 @@ var require_visit = __commonJS({
651
651
  visitAsync.REMOVE = REMOVE;
652
652
  async function visitAsync_(key, node, visitor, path) {
653
653
  const ctrl = await callVisitor(key, node, visitor, path);
654
- if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
654
+ if (identity2.isNode(ctrl) || identity2.isPair(ctrl)) {
655
655
  replaceNode(key, path, ctrl);
656
656
  return visitAsync_(key, ctrl, visitor, path);
657
657
  }
658
658
  if (typeof ctrl !== "symbol") {
659
- if (identity.isCollection(node)) {
659
+ if (identity2.isCollection(node)) {
660
660
  path = Object.freeze(path.concat(node));
661
661
  for (let i = 0; i < node.items.length; ++i) {
662
662
  const ci = await visitAsync_(i, node.items[i], visitor, path);
@@ -669,7 +669,7 @@ var require_visit = __commonJS({
669
669
  i -= 1;
670
670
  }
671
671
  }
672
- } else if (identity.isPair(node)) {
672
+ } else if (identity2.isPair(node)) {
673
673
  path = Object.freeze(path.concat(node));
674
674
  const ck = await visitAsync_("key", node.key, visitor, path);
675
675
  if (ck === BREAK)
@@ -706,31 +706,31 @@ var require_visit = __commonJS({
706
706
  function callVisitor(key, node, visitor, path) {
707
707
  if (typeof visitor === "function")
708
708
  return visitor(key, node, path);
709
- if (identity.isMap(node))
709
+ if (identity2.isMap(node))
710
710
  return visitor.Map?.(key, node, path);
711
- if (identity.isSeq(node))
711
+ if (identity2.isSeq(node))
712
712
  return visitor.Seq?.(key, node, path);
713
- if (identity.isPair(node))
713
+ if (identity2.isPair(node))
714
714
  return visitor.Pair?.(key, node, path);
715
- if (identity.isScalar(node))
715
+ if (identity2.isScalar(node))
716
716
  return visitor.Scalar?.(key, node, path);
717
- if (identity.isAlias(node))
717
+ if (identity2.isAlias(node))
718
718
  return visitor.Alias?.(key, node, path);
719
719
  return void 0;
720
720
  }
721
721
  function replaceNode(key, path, node) {
722
722
  const parent = path[path.length - 1];
723
- if (identity.isCollection(parent)) {
723
+ if (identity2.isCollection(parent)) {
724
724
  parent.items[key] = node;
725
- } else if (identity.isPair(parent)) {
725
+ } else if (identity2.isPair(parent)) {
726
726
  if (key === "key")
727
727
  parent.key = node;
728
728
  else
729
729
  parent.value = node;
730
- } else if (identity.isDocument(parent)) {
730
+ } else if (identity2.isDocument(parent)) {
731
731
  parent.contents = node;
732
732
  } else {
733
- const pt = identity.isAlias(parent) ? "alias" : "scalar";
733
+ const pt = identity2.isAlias(parent) ? "alias" : "scalar";
734
734
  throw new Error(`Cannot replace node with ${pt} parent`);
735
735
  }
736
736
  }
@@ -743,7 +743,7 @@ var require_visit = __commonJS({
743
743
  var require_directives = __commonJS({
744
744
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/doc/directives.js"(exports2) {
745
745
  "use strict";
746
- var identity = require_identity();
746
+ var identity2 = require_identity();
747
747
  var visit = require_visit();
748
748
  var escapeChars = {
749
749
  "!": "%21",
@@ -886,10 +886,10 @@ var require_directives = __commonJS({
886
886
  const lines = this.yaml.explicit ? [`%YAML ${this.yaml.version || "1.2"}`] : [];
887
887
  const tagEntries = Object.entries(this.tags);
888
888
  let tagNames;
889
- if (doc && tagEntries.length > 0 && identity.isNode(doc.contents)) {
889
+ if (doc && tagEntries.length > 0 && identity2.isNode(doc.contents)) {
890
890
  const tags = {};
891
891
  visit.visit(doc.contents, (_key, node) => {
892
- if (identity.isNode(node) && node.tag)
892
+ if (identity2.isNode(node) && node.tag)
893
893
  tags[node.tag] = true;
894
894
  });
895
895
  tagNames = Object.keys(tags);
@@ -914,7 +914,7 @@ var require_directives = __commonJS({
914
914
  var require_anchors = __commonJS({
915
915
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/doc/anchors.js"(exports2) {
916
916
  "use strict";
917
- var identity = require_identity();
917
+ var identity2 = require_identity();
918
918
  var visit = require_visit();
919
919
  function anchorIsValid(anchor) {
920
920
  if (/[\x00-\x19\s,[\]{}]/.test(anchor)) {
@@ -961,7 +961,7 @@ var require_anchors = __commonJS({
961
961
  setAnchors: () => {
962
962
  for (const source of aliasObjects) {
963
963
  const ref = sourceObjects.get(source);
964
- if (typeof ref === "object" && ref.anchor && (identity.isScalar(ref.node) || identity.isCollection(ref.node))) {
964
+ if (typeof ref === "object" && ref.anchor && (identity2.isScalar(ref.node) || identity2.isCollection(ref.node))) {
965
965
  ref.node.anchor = ref.anchor;
966
966
  } else {
967
967
  const error = new Error("Failed to resolve repeated object (this should not happen)");
@@ -1034,12 +1034,12 @@ var require_applyReviver = __commonJS({
1034
1034
  var require_toJS = __commonJS({
1035
1035
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/nodes/toJS.js"(exports2) {
1036
1036
  "use strict";
1037
- var identity = require_identity();
1037
+ var identity2 = require_identity();
1038
1038
  function toJS(value, arg, ctx) {
1039
1039
  if (Array.isArray(value))
1040
1040
  return value.map((v, i) => toJS(v, String(i), ctx));
1041
1041
  if (value && typeof value.toJSON === "function") {
1042
- if (!ctx || !identity.hasAnchor(value))
1042
+ if (!ctx || !identity2.hasAnchor(value))
1043
1043
  return value.toJSON(arg, ctx);
1044
1044
  const data = { aliasCount: 0, count: 1, res: void 0 };
1045
1045
  ctx.anchors.set(value, data);
@@ -1065,11 +1065,11 @@ var require_Node = __commonJS({
1065
1065
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/nodes/Node.js"(exports2) {
1066
1066
  "use strict";
1067
1067
  var applyReviver = require_applyReviver();
1068
- var identity = require_identity();
1068
+ var identity2 = require_identity();
1069
1069
  var toJS = require_toJS();
1070
1070
  var NodeBase = class {
1071
1071
  constructor(type) {
1072
- Object.defineProperty(this, identity.NODE_TYPE, { value: type });
1072
+ Object.defineProperty(this, identity2.NODE_TYPE, { value: type });
1073
1073
  }
1074
1074
  /** Create a copy of this node. */
1075
1075
  clone() {
@@ -1080,7 +1080,7 @@ var require_Node = __commonJS({
1080
1080
  }
1081
1081
  /** A plain JavaScript representation of this node. */
1082
1082
  toJS(doc, { mapAsMap, maxAliasCount, onAnchor, reviver } = {}) {
1083
- if (!identity.isDocument(doc))
1083
+ if (!identity2.isDocument(doc))
1084
1084
  throw new TypeError("A document argument is required");
1085
1085
  const ctx = {
1086
1086
  anchors: /* @__PURE__ */ new Map(),
@@ -1107,12 +1107,12 @@ var require_Alias = __commonJS({
1107
1107
  "use strict";
1108
1108
  var anchors = require_anchors();
1109
1109
  var visit = require_visit();
1110
- var identity = require_identity();
1110
+ var identity2 = require_identity();
1111
1111
  var Node = require_Node();
1112
1112
  var toJS = require_toJS();
1113
1113
  var Alias = class extends Node.NodeBase {
1114
1114
  constructor(source) {
1115
- super(identity.ALIAS);
1115
+ super(identity2.ALIAS);
1116
1116
  this.source = source;
1117
1117
  Object.defineProperty(this, "tag", {
1118
1118
  set() {
@@ -1134,7 +1134,7 @@ var require_Alias = __commonJS({
1134
1134
  nodes = [];
1135
1135
  visit.visit(doc, {
1136
1136
  Node: (_key, node) => {
1137
- if (identity.isAlias(node) || identity.hasAnchor(node))
1137
+ if (identity2.isAlias(node) || identity2.hasAnchor(node))
1138
1138
  nodes.push(node);
1139
1139
  }
1140
1140
  });
@@ -1194,11 +1194,11 @@ var require_Alias = __commonJS({
1194
1194
  }
1195
1195
  };
1196
1196
  function getAliasCount(doc, node, anchors2) {
1197
- if (identity.isAlias(node)) {
1197
+ if (identity2.isAlias(node)) {
1198
1198
  const source = node.resolve(doc);
1199
1199
  const anchor = anchors2 && source && anchors2.get(source);
1200
1200
  return anchor ? anchor.count * anchor.aliasCount : 0;
1201
- } else if (identity.isCollection(node)) {
1201
+ } else if (identity2.isCollection(node)) {
1202
1202
  let count = 0;
1203
1203
  for (const item of node.items) {
1204
1204
  const c = getAliasCount(doc, item, anchors2);
@@ -1206,7 +1206,7 @@ var require_Alias = __commonJS({
1206
1206
  count = c;
1207
1207
  }
1208
1208
  return count;
1209
- } else if (identity.isPair(node)) {
1209
+ } else if (identity2.isPair(node)) {
1210
1210
  const kc = getAliasCount(doc, node.key, anchors2);
1211
1211
  const vc = getAliasCount(doc, node.value, anchors2);
1212
1212
  return Math.max(kc, vc);
@@ -1221,13 +1221,13 @@ var require_Alias = __commonJS({
1221
1221
  var require_Scalar = __commonJS({
1222
1222
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/nodes/Scalar.js"(exports2) {
1223
1223
  "use strict";
1224
- var identity = require_identity();
1224
+ var identity2 = require_identity();
1225
1225
  var Node = require_Node();
1226
1226
  var toJS = require_toJS();
1227
1227
  var isScalarValue = (value) => !value || typeof value !== "function" && typeof value !== "object";
1228
1228
  var Scalar = class extends Node.NodeBase {
1229
1229
  constructor(value) {
1230
- super(identity.SCALAR);
1230
+ super(identity2.SCALAR);
1231
1231
  this.value = value;
1232
1232
  }
1233
1233
  toJSON(arg, ctx) {
@@ -1252,7 +1252,7 @@ var require_createNode = __commonJS({
1252
1252
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/doc/createNode.js"(exports2) {
1253
1253
  "use strict";
1254
1254
  var Alias = require_Alias();
1255
- var identity = require_identity();
1255
+ var identity2 = require_identity();
1256
1256
  var Scalar = require_Scalar();
1257
1257
  var defaultTagPrefix = "tag:yaml.org,2002:";
1258
1258
  function findTagObject(value, tagName, tags) {
@@ -1266,12 +1266,12 @@ var require_createNode = __commonJS({
1266
1266
  return tags.find((t) => t.identify?.(value) && !t.format);
1267
1267
  }
1268
1268
  function createNode(value, tagName, ctx) {
1269
- if (identity.isDocument(value))
1269
+ if (identity2.isDocument(value))
1270
1270
  value = value.contents;
1271
- if (identity.isNode(value))
1271
+ if (identity2.isNode(value))
1272
1272
  return value;
1273
- if (identity.isPair(value)) {
1274
- const map = ctx.schema[identity.MAP].createNode?.(ctx.schema, null, ctx);
1273
+ if (identity2.isPair(value)) {
1274
+ const map = ctx.schema[identity2.MAP].createNode?.(ctx.schema, null, ctx);
1275
1275
  map.items.push(value);
1276
1276
  return map;
1277
1277
  }
@@ -1303,7 +1303,7 @@ var require_createNode = __commonJS({
1303
1303
  ref.node = node2;
1304
1304
  return node2;
1305
1305
  }
1306
- tagObj = value instanceof Map ? schema[identity.MAP] : Symbol.iterator in Object(value) ? schema[identity.SEQ] : schema[identity.MAP];
1306
+ tagObj = value instanceof Map ? schema[identity2.MAP] : Symbol.iterator in Object(value) ? schema[identity2.SEQ] : schema[identity2.MAP];
1307
1307
  }
1308
1308
  if (onTagObj) {
1309
1309
  onTagObj(tagObj);
@@ -1327,7 +1327,7 @@ var require_Collection = __commonJS({
1327
1327
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/nodes/Collection.js"(exports2) {
1328
1328
  "use strict";
1329
1329
  var createNode = require_createNode();
1330
- var identity = require_identity();
1330
+ var identity2 = require_identity();
1331
1331
  var Node = require_Node();
1332
1332
  function collectionFromPath(schema, path, value) {
1333
1333
  let v = value;
@@ -1371,7 +1371,7 @@ var require_Collection = __commonJS({
1371
1371
  const copy = Object.create(Object.getPrototypeOf(this), Object.getOwnPropertyDescriptors(this));
1372
1372
  if (schema)
1373
1373
  copy.schema = schema;
1374
- copy.items = copy.items.map((it) => identity.isNode(it) || identity.isPair(it) ? it.clone(schema) : it);
1374
+ copy.items = copy.items.map((it) => identity2.isNode(it) || identity2.isPair(it) ? it.clone(schema) : it);
1375
1375
  if (this.range)
1376
1376
  copy.range = this.range.slice();
1377
1377
  return copy;
@@ -1387,7 +1387,7 @@ var require_Collection = __commonJS({
1387
1387
  else {
1388
1388
  const [key, ...rest] = path;
1389
1389
  const node = this.get(key, true);
1390
- if (identity.isCollection(node))
1390
+ if (identity2.isCollection(node))
1391
1391
  node.addIn(rest, value);
1392
1392
  else if (node === void 0 && this.schema)
1393
1393
  this.set(key, collectionFromPath(this.schema, rest, value));
@@ -1404,7 +1404,7 @@ var require_Collection = __commonJS({
1404
1404
  if (rest.length === 0)
1405
1405
  return this.delete(key);
1406
1406
  const node = this.get(key, true);
1407
- if (identity.isCollection(node))
1407
+ if (identity2.isCollection(node))
1408
1408
  return node.deleteIn(rest);
1409
1409
  else
1410
1410
  throw new Error(`Expected YAML collection at ${key}. Remaining path: ${rest}`);
@@ -1418,16 +1418,16 @@ var require_Collection = __commonJS({
1418
1418
  const [key, ...rest] = path;
1419
1419
  const node = this.get(key, true);
1420
1420
  if (rest.length === 0)
1421
- return !keepScalar && identity.isScalar(node) ? node.value : node;
1421
+ return !keepScalar && identity2.isScalar(node) ? node.value : node;
1422
1422
  else
1423
- return identity.isCollection(node) ? node.getIn(rest, keepScalar) : void 0;
1423
+ return identity2.isCollection(node) ? node.getIn(rest, keepScalar) : void 0;
1424
1424
  }
1425
1425
  hasAllNullValues(allowScalar) {
1426
1426
  return this.items.every((node) => {
1427
- if (!identity.isPair(node))
1427
+ if (!identity2.isPair(node))
1428
1428
  return false;
1429
1429
  const n = node.value;
1430
- return n == null || allowScalar && identity.isScalar(n) && n.value == null && !n.commentBefore && !n.comment && !n.tag;
1430
+ return n == null || allowScalar && identity2.isScalar(n) && n.value == null && !n.commentBefore && !n.comment && !n.tag;
1431
1431
  });
1432
1432
  }
1433
1433
  /**
@@ -1438,7 +1438,7 @@ var require_Collection = __commonJS({
1438
1438
  if (rest.length === 0)
1439
1439
  return this.has(key);
1440
1440
  const node = this.get(key, true);
1441
- return identity.isCollection(node) ? node.hasIn(rest) : false;
1441
+ return identity2.isCollection(node) ? node.hasIn(rest) : false;
1442
1442
  }
1443
1443
  /**
1444
1444
  * Sets a value in this collection. For `!!set`, `value` needs to be a
@@ -1450,7 +1450,7 @@ var require_Collection = __commonJS({
1450
1450
  this.set(key, value);
1451
1451
  } else {
1452
1452
  const node = this.get(key, true);
1453
- if (identity.isCollection(node))
1453
+ if (identity2.isCollection(node))
1454
1454
  node.setIn(rest, value);
1455
1455
  else if (node === void 0 && this.schema)
1456
1456
  this.set(key, collectionFromPath(this.schema, rest, value));
@@ -1906,7 +1906,7 @@ var require_stringify = __commonJS({
1906
1906
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/stringify/stringify.js"(exports2) {
1907
1907
  "use strict";
1908
1908
  var anchors = require_anchors();
1909
- var identity = require_identity();
1909
+ var identity2 = require_identity();
1910
1910
  var stringifyComment = require_stringifyComment();
1911
1911
  var stringifyString = require_stringifyString();
1912
1912
  function createStringifyContext(doc, options) {
@@ -1959,7 +1959,7 @@ var require_stringify = __commonJS({
1959
1959
  }
1960
1960
  let tagObj = void 0;
1961
1961
  let obj;
1962
- if (identity.isScalar(item)) {
1962
+ if (identity2.isScalar(item)) {
1963
1963
  obj = item.value;
1964
1964
  let match = tags.filter((t) => t.identify?.(obj));
1965
1965
  if (match.length > 1) {
@@ -1982,7 +1982,7 @@ var require_stringify = __commonJS({
1982
1982
  if (!doc.directives)
1983
1983
  return "";
1984
1984
  const props = [];
1985
- const anchor = (identity.isScalar(node) || identity.isCollection(node)) && node.anchor;
1985
+ const anchor = (identity2.isScalar(node) || identity2.isCollection(node)) && node.anchor;
1986
1986
  if (anchor && anchors.anchorIsValid(anchor)) {
1987
1987
  anchors$1.add(anchor);
1988
1988
  props.push(`&${anchor}`);
@@ -1993,9 +1993,9 @@ var require_stringify = __commonJS({
1993
1993
  return props.join(" ");
1994
1994
  }
1995
1995
  function stringify(item, ctx, onComment, onChompKeep) {
1996
- if (identity.isPair(item))
1996
+ if (identity2.isPair(item))
1997
1997
  return item.toString(ctx, onComment, onChompKeep);
1998
- if (identity.isAlias(item)) {
1998
+ if (identity2.isAlias(item)) {
1999
1999
  if (ctx.doc.directives)
2000
2000
  return item.toString(ctx);
2001
2001
  if (ctx.resolvedAliases?.has(item)) {
@@ -2009,15 +2009,15 @@ var require_stringify = __commonJS({
2009
2009
  }
2010
2010
  }
2011
2011
  let tagObj = void 0;
2012
- const node = identity.isNode(item) ? item : ctx.doc.createNode(item, { onTagObj: (o) => tagObj = o });
2012
+ const node = identity2.isNode(item) ? item : ctx.doc.createNode(item, { onTagObj: (o) => tagObj = o });
2013
2013
  tagObj ?? (tagObj = getTagObject(ctx.doc.schema.tags, node));
2014
2014
  const props = stringifyProps(node, tagObj, ctx);
2015
2015
  if (props.length > 0)
2016
2016
  ctx.indentAtStart = (ctx.indentAtStart ?? 0) + props.length + 1;
2017
- const str = typeof tagObj.stringify === "function" ? tagObj.stringify(node, ctx, onComment, onChompKeep) : identity.isScalar(node) ? stringifyString.stringifyString(node, ctx, onComment, onChompKeep) : node.toString(ctx, onComment, onChompKeep);
2017
+ const str = typeof tagObj.stringify === "function" ? tagObj.stringify(node, ctx, onComment, onChompKeep) : identity2.isScalar(node) ? stringifyString.stringifyString(node, ctx, onComment, onChompKeep) : node.toString(ctx, onComment, onChompKeep);
2018
2018
  if (!props)
2019
2019
  return str;
2020
- return identity.isScalar(node) || str[0] === "{" || str[0] === "[" ? `${props} ${str}` : `${props}
2020
+ return identity2.isScalar(node) || str[0] === "{" || str[0] === "[" ? `${props} ${str}` : `${props}
2021
2021
  ${ctx.indent}${str}`;
2022
2022
  }
2023
2023
  exports2.createStringifyContext = createStringifyContext;
@@ -2029,23 +2029,23 @@ ${ctx.indent}${str}`;
2029
2029
  var require_stringifyPair = __commonJS({
2030
2030
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/stringify/stringifyPair.js"(exports2) {
2031
2031
  "use strict";
2032
- var identity = require_identity();
2032
+ var identity2 = require_identity();
2033
2033
  var Scalar = require_Scalar();
2034
2034
  var stringify = require_stringify();
2035
2035
  var stringifyComment = require_stringifyComment();
2036
2036
  function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
2037
2037
  const { allNullValues, doc, indent, indentStep, options: { commentString, indentSeq, simpleKeys } } = ctx;
2038
- let keyComment = identity.isNode(key) && key.comment || null;
2038
+ let keyComment = identity2.isNode(key) && key.comment || null;
2039
2039
  if (simpleKeys) {
2040
2040
  if (keyComment) {
2041
2041
  throw new Error("With simple keys, key nodes cannot have comments");
2042
2042
  }
2043
- if (identity.isCollection(key) || !identity.isNode(key) && typeof key === "object") {
2043
+ if (identity2.isCollection(key) || !identity2.isNode(key) && typeof key === "object") {
2044
2044
  const msg = "With simple keys, collection cannot be used as a key value";
2045
2045
  throw new Error(msg);
2046
2046
  }
2047
2047
  }
2048
- let explicitKey = !simpleKeys && (!key || keyComment && value == null && !ctx.inFlow || identity.isCollection(key) || (identity.isScalar(key) ? key.type === Scalar.Scalar.BLOCK_FOLDED || key.type === Scalar.Scalar.BLOCK_LITERAL : typeof key === "object"));
2048
+ let explicitKey = !simpleKeys && (!key || keyComment && value == null && !ctx.inFlow || identity2.isCollection(key) || (identity2.isScalar(key) ? key.type === Scalar.Scalar.BLOCK_FOLDED || key.type === Scalar.Scalar.BLOCK_LITERAL : typeof key === "object"));
2049
2049
  ctx = Object.assign({}, ctx, {
2050
2050
  allNullValues: false,
2051
2051
  implicitKey: !explicitKey && (simpleKeys || !allNullValues),
@@ -2086,7 +2086,7 @@ ${indent}:`;
2086
2086
  str += stringifyComment.lineComment(str, ctx.indent, commentString(keyComment));
2087
2087
  }
2088
2088
  let vsb, vcb, valueComment;
2089
- if (identity.isNode(value)) {
2089
+ if (identity2.isNode(value)) {
2090
2090
  vsb = !!value.spaceBefore;
2091
2091
  vcb = value.commentBefore;
2092
2092
  valueComment = value.comment;
@@ -2098,10 +2098,10 @@ ${indent}:`;
2098
2098
  value = doc.createNode(value);
2099
2099
  }
2100
2100
  ctx.implicitKey = false;
2101
- if (!explicitKey && !keyComment && identity.isScalar(value))
2101
+ if (!explicitKey && !keyComment && identity2.isScalar(value))
2102
2102
  ctx.indentAtStart = str.length + 1;
2103
2103
  chompKeep = false;
2104
- if (!indentSeq && indentStep.length >= 2 && !ctx.inFlow && !explicitKey && identity.isSeq(value) && !value.flow && !value.tag && !value.anchor) {
2104
+ if (!indentSeq && indentStep.length >= 2 && !ctx.inFlow && !explicitKey && identity2.isSeq(value) && !value.flow && !value.tag && !value.anchor) {
2105
2105
  ctx.indent = ctx.indent.substring(2);
2106
2106
  }
2107
2107
  let valueCommentDone = false;
@@ -2121,7 +2121,7 @@ ${stringifyComment.indentComment(cs, ctx.indent)}`;
2121
2121
  ws += `
2122
2122
  ${ctx.indent}`;
2123
2123
  }
2124
- } else if (!explicitKey && identity.isCollection(value)) {
2124
+ } else if (!explicitKey && identity2.isCollection(value)) {
2125
2125
  const vs0 = valueStr[0];
2126
2126
  const nl0 = valueStr.indexOf("\n");
2127
2127
  const hasNewline = nl0 !== -1;
@@ -2184,7 +2184,7 @@ var require_log = __commonJS({
2184
2184
  var require_merge = __commonJS({
2185
2185
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/schema/yaml-1.1/merge.js"(exports2) {
2186
2186
  "use strict";
2187
- var identity = require_identity();
2187
+ var identity2 = require_identity();
2188
2188
  var Scalar = require_Scalar();
2189
2189
  var MERGE_KEY = "<<";
2190
2190
  var merge = {
@@ -2197,10 +2197,10 @@ var require_merge = __commonJS({
2197
2197
  }),
2198
2198
  stringify: () => MERGE_KEY
2199
2199
  };
2200
- var isMergeKey = (ctx, key) => (merge.identify(key) || identity.isScalar(key) && (!key.type || key.type === Scalar.Scalar.PLAIN) && merge.identify(key.value)) && ctx?.doc.schema.tags.some((tag) => tag.tag === merge.tag && tag.default);
2200
+ var isMergeKey = (ctx, key) => (merge.identify(key) || identity2.isScalar(key) && (!key.type || key.type === Scalar.Scalar.PLAIN) && merge.identify(key.value)) && ctx?.doc.schema.tags.some((tag) => tag.tag === merge.tag && tag.default);
2201
2201
  function addMergeToJSMap(ctx, map, value) {
2202
2202
  const source = resolveAliasValue(ctx, value);
2203
- if (identity.isSeq(source))
2203
+ if (identity2.isSeq(source))
2204
2204
  for (const it of source.items)
2205
2205
  mergeValue(ctx, map, it);
2206
2206
  else if (Array.isArray(source))
@@ -2211,7 +2211,7 @@ var require_merge = __commonJS({
2211
2211
  }
2212
2212
  function mergeValue(ctx, map, value) {
2213
2213
  const source = resolveAliasValue(ctx, value);
2214
- if (!identity.isMap(source))
2214
+ if (!identity2.isMap(source))
2215
2215
  throw new Error("Merge sources must be maps or map aliases");
2216
2216
  const srcMap = source.toJSON(null, ctx, Map);
2217
2217
  for (const [key, value2] of srcMap) {
@@ -2232,7 +2232,7 @@ var require_merge = __commonJS({
2232
2232
  return map;
2233
2233
  }
2234
2234
  function resolveAliasValue(ctx, value) {
2235
- return ctx && identity.isAlias(value) ? value.resolve(ctx.doc, ctx) : value;
2235
+ return ctx && identity2.isAlias(value) ? value.resolve(ctx.doc, ctx) : value;
2236
2236
  }
2237
2237
  exports2.addMergeToJSMap = addMergeToJSMap;
2238
2238
  exports2.isMergeKey = isMergeKey;
@@ -2247,10 +2247,10 @@ var require_addPairToJSMap = __commonJS({
2247
2247
  var log = require_log();
2248
2248
  var merge = require_merge();
2249
2249
  var stringify = require_stringify();
2250
- var identity = require_identity();
2250
+ var identity2 = require_identity();
2251
2251
  var toJS = require_toJS();
2252
2252
  function addPairToJSMap(ctx, map, { key, value }) {
2253
- if (identity.isNode(key) && key.addToJSMap)
2253
+ if (identity2.isNode(key) && key.addToJSMap)
2254
2254
  key.addToJSMap(ctx, map, value);
2255
2255
  else if (merge.isMergeKey(ctx, key))
2256
2256
  merge.addMergeToJSMap(ctx, map, value);
@@ -2281,7 +2281,7 @@ var require_addPairToJSMap = __commonJS({
2281
2281
  return "";
2282
2282
  if (typeof jsKey !== "object")
2283
2283
  return String(jsKey);
2284
- if (identity.isNode(key) && ctx?.doc) {
2284
+ if (identity2.isNode(key) && ctx?.doc) {
2285
2285
  const strCtx = stringify.createStringifyContext(ctx.doc, {});
2286
2286
  strCtx.anchors = /* @__PURE__ */ new Set();
2287
2287
  for (const node of ctx.anchors.keys())
@@ -2311,7 +2311,7 @@ var require_Pair = __commonJS({
2311
2311
  var createNode = require_createNode();
2312
2312
  var stringifyPair = require_stringifyPair();
2313
2313
  var addPairToJSMap = require_addPairToJSMap();
2314
- var identity = require_identity();
2314
+ var identity2 = require_identity();
2315
2315
  function createPair(key, value, ctx) {
2316
2316
  const k = createNode.createNode(key, void 0, ctx);
2317
2317
  const v = createNode.createNode(value, void 0, ctx);
@@ -2319,15 +2319,15 @@ var require_Pair = __commonJS({
2319
2319
  }
2320
2320
  var Pair = class _Pair {
2321
2321
  constructor(key, value = null) {
2322
- Object.defineProperty(this, identity.NODE_TYPE, { value: identity.PAIR });
2322
+ Object.defineProperty(this, identity2.NODE_TYPE, { value: identity2.PAIR });
2323
2323
  this.key = key;
2324
2324
  this.value = value;
2325
2325
  }
2326
2326
  clone(schema) {
2327
2327
  let { key, value } = this;
2328
- if (identity.isNode(key))
2328
+ if (identity2.isNode(key))
2329
2329
  key = key.clone(schema);
2330
- if (identity.isNode(value))
2330
+ if (identity2.isNode(value))
2331
2331
  value = value.clone(schema);
2332
2332
  return new _Pair(key, value);
2333
2333
  }
@@ -2348,7 +2348,7 @@ var require_Pair = __commonJS({
2348
2348
  var require_stringifyCollection = __commonJS({
2349
2349
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/stringify/stringifyCollection.js"(exports2) {
2350
2350
  "use strict";
2351
- var identity = require_identity();
2351
+ var identity2 = require_identity();
2352
2352
  var stringify = require_stringify();
2353
2353
  var stringifyComment = require_stringifyComment();
2354
2354
  function stringifyCollection(collection, ctx, options) {
@@ -2364,14 +2364,14 @@ var require_stringifyCollection = __commonJS({
2364
2364
  for (let i = 0; i < items.length; ++i) {
2365
2365
  const item = items[i];
2366
2366
  let comment2 = null;
2367
- if (identity.isNode(item)) {
2367
+ if (identity2.isNode(item)) {
2368
2368
  if (!chompKeep && item.spaceBefore)
2369
2369
  lines.push("");
2370
2370
  addCommentBefore(ctx, lines, item.commentBefore, chompKeep);
2371
2371
  if (item.comment)
2372
2372
  comment2 = item.comment;
2373
- } else if (identity.isPair(item)) {
2374
- const ik = identity.isNode(item.key) ? item.key : null;
2373
+ } else if (identity2.isPair(item)) {
2374
+ const ik = identity2.isNode(item.key) ? item.key : null;
2375
2375
  if (ik) {
2376
2376
  if (!chompKeep && ik.spaceBefore)
2377
2377
  lines.push("");
@@ -2419,14 +2419,14 @@ ${indent}${line}` : "\n";
2419
2419
  for (let i = 0; i < items.length; ++i) {
2420
2420
  const item = items[i];
2421
2421
  let comment = null;
2422
- if (identity.isNode(item)) {
2422
+ if (identity2.isNode(item)) {
2423
2423
  if (item.spaceBefore)
2424
2424
  lines.push("");
2425
2425
  addCommentBefore(ctx, lines, item.commentBefore, false);
2426
2426
  if (item.comment)
2427
2427
  comment = item.comment;
2428
- } else if (identity.isPair(item)) {
2429
- const ik = identity.isNode(item.key) ? item.key : null;
2428
+ } else if (identity2.isPair(item)) {
2429
+ const ik = identity2.isNode(item.key) ? item.key : null;
2430
2430
  if (ik) {
2431
2431
  if (ik.spaceBefore)
2432
2432
  lines.push("");
@@ -2434,7 +2434,7 @@ ${indent}${line}` : "\n";
2434
2434
  if (ik.comment)
2435
2435
  reqNewline = true;
2436
2436
  }
2437
- const iv = identity.isNode(item.value) ? item.value : null;
2437
+ const iv = identity2.isNode(item.value) ? item.value : null;
2438
2438
  if (iv) {
2439
2439
  if (iv.comment)
2440
2440
  comment = iv.comment;
@@ -2502,16 +2502,16 @@ var require_YAMLMap = __commonJS({
2502
2502
  var stringifyCollection = require_stringifyCollection();
2503
2503
  var addPairToJSMap = require_addPairToJSMap();
2504
2504
  var Collection = require_Collection();
2505
- var identity = require_identity();
2505
+ var identity2 = require_identity();
2506
2506
  var Pair = require_Pair();
2507
2507
  var Scalar = require_Scalar();
2508
2508
  function findPair(items, key) {
2509
- const k = identity.isScalar(key) ? key.value : key;
2509
+ const k = identity2.isScalar(key) ? key.value : key;
2510
2510
  for (const it of items) {
2511
- if (identity.isPair(it)) {
2511
+ if (identity2.isPair(it)) {
2512
2512
  if (it.key === key || it.key === k)
2513
2513
  return it;
2514
- if (identity.isScalar(it.key) && it.key.value === k)
2514
+ if (identity2.isScalar(it.key) && it.key.value === k)
2515
2515
  return it;
2516
2516
  }
2517
2517
  }
@@ -2522,7 +2522,7 @@ var require_YAMLMap = __commonJS({
2522
2522
  return "tag:yaml.org,2002:map";
2523
2523
  }
2524
2524
  constructor(schema) {
2525
- super(identity.MAP, schema);
2525
+ super(identity2.MAP, schema);
2526
2526
  this.items = [];
2527
2527
  }
2528
2528
  /**
@@ -2560,7 +2560,7 @@ var require_YAMLMap = __commonJS({
2560
2560
  */
2561
2561
  add(pair, overwrite) {
2562
2562
  let _pair;
2563
- if (identity.isPair(pair))
2563
+ if (identity2.isPair(pair))
2564
2564
  _pair = pair;
2565
2565
  else if (!pair || typeof pair !== "object" || !("key" in pair)) {
2566
2566
  _pair = new Pair.Pair(pair, pair?.value);
@@ -2571,7 +2571,7 @@ var require_YAMLMap = __commonJS({
2571
2571
  if (prev) {
2572
2572
  if (!overwrite)
2573
2573
  throw new Error(`Key ${_pair.key} already set`);
2574
- if (identity.isScalar(prev.value) && Scalar.isScalarValue(_pair.value))
2574
+ if (identity2.isScalar(prev.value) && Scalar.isScalarValue(_pair.value))
2575
2575
  prev.value.value = _pair.value;
2576
2576
  else
2577
2577
  prev.value = _pair.value;
@@ -2595,7 +2595,7 @@ var require_YAMLMap = __commonJS({
2595
2595
  get(key, keepScalar) {
2596
2596
  const it = findPair(this.items, key);
2597
2597
  const node = it?.value;
2598
- return (!keepScalar && identity.isScalar(node) ? node.value : node) ?? void 0;
2598
+ return (!keepScalar && identity2.isScalar(node) ? node.value : node) ?? void 0;
2599
2599
  }
2600
2600
  has(key) {
2601
2601
  return !!findPair(this.items, key);
@@ -2620,7 +2620,7 @@ var require_YAMLMap = __commonJS({
2620
2620
  if (!ctx)
2621
2621
  return JSON.stringify(this);
2622
2622
  for (const item of this.items) {
2623
- if (!identity.isPair(item))
2623
+ if (!identity2.isPair(item))
2624
2624
  throw new Error(`Map items must all be pairs; found ${JSON.stringify(item)} instead`);
2625
2625
  }
2626
2626
  if (!ctx.allNullValues && this.hasAllNullValues(false))
@@ -2643,7 +2643,7 @@ var require_YAMLMap = __commonJS({
2643
2643
  var require_map = __commonJS({
2644
2644
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/schema/common/map.js"(exports2) {
2645
2645
  "use strict";
2646
- var identity = require_identity();
2646
+ var identity2 = require_identity();
2647
2647
  var YAMLMap = require_YAMLMap();
2648
2648
  var map = {
2649
2649
  collection: "map",
@@ -2651,7 +2651,7 @@ var require_map = __commonJS({
2651
2651
  nodeClass: YAMLMap.YAMLMap,
2652
2652
  tag: "tag:yaml.org,2002:map",
2653
2653
  resolve(map2, onError) {
2654
- if (!identity.isMap(map2))
2654
+ if (!identity2.isMap(map2))
2655
2655
  onError("Expected a mapping for this tag");
2656
2656
  return map2;
2657
2657
  },
@@ -2668,7 +2668,7 @@ var require_YAMLSeq = __commonJS({
2668
2668
  var createNode = require_createNode();
2669
2669
  var stringifyCollection = require_stringifyCollection();
2670
2670
  var Collection = require_Collection();
2671
- var identity = require_identity();
2671
+ var identity2 = require_identity();
2672
2672
  var Scalar = require_Scalar();
2673
2673
  var toJS = require_toJS();
2674
2674
  var YAMLSeq = class extends Collection.Collection {
@@ -2676,7 +2676,7 @@ var require_YAMLSeq = __commonJS({
2676
2676
  return "tag:yaml.org,2002:seq";
2677
2677
  }
2678
2678
  constructor(schema) {
2679
- super(identity.SEQ, schema);
2679
+ super(identity2.SEQ, schema);
2680
2680
  this.items = [];
2681
2681
  }
2682
2682
  add(value) {
@@ -2702,7 +2702,7 @@ var require_YAMLSeq = __commonJS({
2702
2702
  if (typeof idx !== "number")
2703
2703
  return void 0;
2704
2704
  const it = this.items[idx];
2705
- return !keepScalar && identity.isScalar(it) ? it.value : it;
2705
+ return !keepScalar && identity2.isScalar(it) ? it.value : it;
2706
2706
  }
2707
2707
  /**
2708
2708
  * Checks if the collection includes a value with the key `key`.
@@ -2726,7 +2726,7 @@ var require_YAMLSeq = __commonJS({
2726
2726
  if (typeof idx !== "number")
2727
2727
  throw new Error(`Expected a valid index, not ${key}.`);
2728
2728
  const prev = this.items[idx];
2729
- if (identity.isScalar(prev) && Scalar.isScalarValue(value))
2729
+ if (identity2.isScalar(prev) && Scalar.isScalarValue(value))
2730
2730
  prev.value = value;
2731
2731
  else
2732
2732
  this.items[idx] = value;
@@ -2768,7 +2768,7 @@ var require_YAMLSeq = __commonJS({
2768
2768
  }
2769
2769
  };
2770
2770
  function asItemIndex(key) {
2771
- let idx = identity.isScalar(key) ? key.value : key;
2771
+ let idx = identity2.isScalar(key) ? key.value : key;
2772
2772
  if (idx && typeof idx === "string")
2773
2773
  idx = Number(idx);
2774
2774
  return typeof idx === "number" && Number.isInteger(idx) && idx >= 0 ? idx : null;
@@ -2781,7 +2781,7 @@ var require_YAMLSeq = __commonJS({
2781
2781
  var require_seq = __commonJS({
2782
2782
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/schema/common/seq.js"(exports2) {
2783
2783
  "use strict";
2784
- var identity = require_identity();
2784
+ var identity2 = require_identity();
2785
2785
  var YAMLSeq = require_YAMLSeq();
2786
2786
  var seq = {
2787
2787
  collection: "seq",
@@ -2789,7 +2789,7 @@ var require_seq = __commonJS({
2789
2789
  nodeClass: YAMLSeq.YAMLSeq,
2790
2790
  tag: "tag:yaml.org,2002:seq",
2791
2791
  resolve(seq2, onError) {
2792
- if (!identity.isSeq(seq2))
2792
+ if (!identity2.isSeq(seq2))
2793
2793
  onError("Expected a sequence for this tag");
2794
2794
  return seq2;
2795
2795
  },
@@ -3143,17 +3143,17 @@ var require_binary = __commonJS({
3143
3143
  var require_pairs = __commonJS({
3144
3144
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/schema/yaml-1.1/pairs.js"(exports2) {
3145
3145
  "use strict";
3146
- var identity = require_identity();
3146
+ var identity2 = require_identity();
3147
3147
  var Pair = require_Pair();
3148
3148
  var Scalar = require_Scalar();
3149
3149
  var YAMLSeq = require_YAMLSeq();
3150
3150
  function resolvePairs(seq, onError) {
3151
- if (identity.isSeq(seq)) {
3151
+ if (identity2.isSeq(seq)) {
3152
3152
  for (let i = 0; i < seq.items.length; ++i) {
3153
3153
  let item = seq.items[i];
3154
- if (identity.isPair(item))
3154
+ if (identity2.isPair(item))
3155
3155
  continue;
3156
- else if (identity.isMap(item)) {
3156
+ else if (identity2.isMap(item)) {
3157
3157
  if (item.items.length > 1)
3158
3158
  onError("Each pair must have its own sequence indicator");
3159
3159
  const pair = item.items[0] || new Pair.Pair(new Scalar.Scalar(null));
@@ -3167,7 +3167,7 @@ ${cn.comment}` : item.comment;
3167
3167
  }
3168
3168
  item = pair;
3169
3169
  }
3170
- seq.items[i] = identity.isPair(item) ? item : new Pair.Pair(item);
3170
+ seq.items[i] = identity2.isPair(item) ? item : new Pair.Pair(item);
3171
3171
  }
3172
3172
  } else
3173
3173
  onError("Expected a sequence for this tag");
@@ -3221,7 +3221,7 @@ ${cn.comment}` : item.comment;
3221
3221
  var require_omap = __commonJS({
3222
3222
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/schema/yaml-1.1/omap.js"(exports2) {
3223
3223
  "use strict";
3224
- var identity = require_identity();
3224
+ var identity2 = require_identity();
3225
3225
  var toJS = require_toJS();
3226
3226
  var YAMLMap = require_YAMLMap();
3227
3227
  var YAMLSeq = require_YAMLSeq();
@@ -3248,7 +3248,7 @@ var require_omap = __commonJS({
3248
3248
  ctx.onCreate(map);
3249
3249
  for (const pair of this.items) {
3250
3250
  let key, value;
3251
- if (identity.isPair(pair)) {
3251
+ if (identity2.isPair(pair)) {
3252
3252
  key = toJS.toJS(pair.key, "", ctx);
3253
3253
  value = toJS.toJS(pair.value, key, ctx);
3254
3254
  } else {
@@ -3278,7 +3278,7 @@ var require_omap = __commonJS({
3278
3278
  const pairs$1 = pairs.resolvePairs(seq, onError);
3279
3279
  const seenKeys = [];
3280
3280
  for (const { key } of pairs$1.items) {
3281
- if (identity.isScalar(key)) {
3281
+ if (identity2.isScalar(key)) {
3282
3282
  if (seenKeys.includes(key.value)) {
3283
3283
  onError(`Ordered maps must not include duplicate keys: ${key.value}`);
3284
3284
  } else {
@@ -3459,7 +3459,7 @@ var require_int2 = __commonJS({
3459
3459
  var require_set = __commonJS({
3460
3460
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/schema/yaml-1.1/set.js"(exports2) {
3461
3461
  "use strict";
3462
- var identity = require_identity();
3462
+ var identity2 = require_identity();
3463
3463
  var Pair = require_Pair();
3464
3464
  var YAMLMap = require_YAMLMap();
3465
3465
  var YAMLSet = class _YAMLSet extends YAMLMap.YAMLMap {
@@ -3469,7 +3469,7 @@ var require_set = __commonJS({
3469
3469
  }
3470
3470
  add(key) {
3471
3471
  let pair;
3472
- if (identity.isPair(key))
3472
+ if (identity2.isPair(key))
3473
3473
  pair = key;
3474
3474
  else if (key && typeof key === "object" && "key" in key && "value" in key && key.value === null)
3475
3475
  pair = new Pair.Pair(key.key, null);
@@ -3485,7 +3485,7 @@ var require_set = __commonJS({
3485
3485
  */
3486
3486
  get(key, keepPair) {
3487
3487
  const pair = YAMLMap.findPair(this.items, key);
3488
- return !keepPair && identity.isPair(pair) ? identity.isScalar(pair.key) ? pair.key.value : pair.key : pair;
3488
+ return !keepPair && identity2.isPair(pair) ? identity2.isScalar(pair.key) ? pair.key.value : pair.key : pair;
3489
3489
  }
3490
3490
  set(key, value) {
3491
3491
  if (typeof value !== "boolean")
@@ -3529,7 +3529,7 @@ var require_set = __commonJS({
3529
3529
  tag: "tag:yaml.org,2002:set",
3530
3530
  createNode: (schema, iterable, ctx) => YAMLSet.from(schema, iterable, ctx),
3531
3531
  resolve(map, onError) {
3532
- if (identity.isMap(map)) {
3532
+ if (identity2.isMap(map)) {
3533
3533
  if (map.hasAllNullValues(true))
3534
3534
  return Object.assign(new YAMLSet(), map);
3535
3535
  else
@@ -3774,7 +3774,7 @@ var require_tags = __commonJS({
3774
3774
  var require_Schema = __commonJS({
3775
3775
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/schema/Schema.js"(exports2) {
3776
3776
  "use strict";
3777
- var identity = require_identity();
3777
+ var identity2 = require_identity();
3778
3778
  var map = require_map();
3779
3779
  var seq = require_seq();
3780
3780
  var string = require_string();
@@ -3787,9 +3787,9 @@ var require_Schema = __commonJS({
3787
3787
  this.knownTags = resolveKnownTags ? tags.coreKnownTags : {};
3788
3788
  this.tags = tags.getTags(customTags, this.name, merge);
3789
3789
  this.toStringOptions = toStringDefaults ?? null;
3790
- Object.defineProperty(this, identity.MAP, { value: map.map });
3791
- Object.defineProperty(this, identity.SCALAR, { value: string.string });
3792
- Object.defineProperty(this, identity.SEQ, { value: seq.seq });
3790
+ Object.defineProperty(this, identity2.MAP, { value: map.map });
3791
+ Object.defineProperty(this, identity2.SCALAR, { value: string.string });
3792
+ Object.defineProperty(this, identity2.SEQ, { value: seq.seq });
3793
3793
  this.sortMapEntries = typeof sortMapEntries === "function" ? sortMapEntries : sortMapEntries === true ? sortMapEntriesByKey : null;
3794
3794
  }
3795
3795
  clone() {
@@ -3806,7 +3806,7 @@ var require_Schema = __commonJS({
3806
3806
  var require_stringifyDocument = __commonJS({
3807
3807
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/stringify/stringifyDocument.js"(exports2) {
3808
3808
  "use strict";
3809
- var identity = require_identity();
3809
+ var identity2 = require_identity();
3810
3810
  var stringify = require_stringify();
3811
3811
  var stringifyComment = require_stringifyComment();
3812
3812
  function stringifyDocument(doc, options) {
@@ -3833,7 +3833,7 @@ var require_stringifyDocument = __commonJS({
3833
3833
  let chompKeep = false;
3834
3834
  let contentComment = null;
3835
3835
  if (doc.contents) {
3836
- if (identity.isNode(doc.contents)) {
3836
+ if (identity2.isNode(doc.contents)) {
3837
3837
  if (doc.contents.spaceBefore && hasDirectives)
3838
3838
  lines.push("");
3839
3839
  if (doc.contents.commentBefore) {
@@ -3888,7 +3888,7 @@ var require_Document = __commonJS({
3888
3888
  "use strict";
3889
3889
  var Alias = require_Alias();
3890
3890
  var Collection = require_Collection();
3891
- var identity = require_identity();
3891
+ var identity2 = require_identity();
3892
3892
  var Pair = require_Pair();
3893
3893
  var toJS = require_toJS();
3894
3894
  var Schema = require_Schema();
@@ -3903,7 +3903,7 @@ var require_Document = __commonJS({
3903
3903
  this.comment = null;
3904
3904
  this.errors = [];
3905
3905
  this.warnings = [];
3906
- Object.defineProperty(this, identity.NODE_TYPE, { value: identity.DOC });
3906
+ Object.defineProperty(this, identity2.NODE_TYPE, { value: identity2.DOC });
3907
3907
  let _replacer = null;
3908
3908
  if (typeof replacer === "function" || Array.isArray(replacer)) {
3909
3909
  _replacer = replacer;
@@ -3939,7 +3939,7 @@ var require_Document = __commonJS({
3939
3939
  */
3940
3940
  clone() {
3941
3941
  const copy = Object.create(_Document.prototype, {
3942
- [identity.NODE_TYPE]: { value: identity.DOC }
3942
+ [identity2.NODE_TYPE]: { value: identity2.DOC }
3943
3943
  });
3944
3944
  copy.commentBefore = this.commentBefore;
3945
3945
  copy.comment = this.comment;
@@ -3949,7 +3949,7 @@ var require_Document = __commonJS({
3949
3949
  if (this.directives)
3950
3950
  copy.directives = this.directives.clone();
3951
3951
  copy.schema = this.schema.clone();
3952
- copy.contents = identity.isNode(this.contents) ? this.contents.clone(copy.schema) : this.contents;
3952
+ copy.contents = identity2.isNode(this.contents) ? this.contents.clone(copy.schema) : this.contents;
3953
3953
  if (this.range)
3954
3954
  copy.range = this.range.slice();
3955
3955
  return copy;
@@ -4012,7 +4012,7 @@ var require_Document = __commonJS({
4012
4012
  sourceObjects
4013
4013
  };
4014
4014
  const node = createNode.createNode(value, tag, ctx);
4015
- if (flow && identity.isCollection(node))
4015
+ if (flow && identity2.isCollection(node))
4016
4016
  node.flow = true;
4017
4017
  setAnchors();
4018
4018
  return node;
@@ -4052,7 +4052,7 @@ var require_Document = __commonJS({
4052
4052
  * `true` (collections are always returned intact).
4053
4053
  */
4054
4054
  get(key, keepScalar) {
4055
- return identity.isCollection(this.contents) ? this.contents.get(key, keepScalar) : void 0;
4055
+ return identity2.isCollection(this.contents) ? this.contents.get(key, keepScalar) : void 0;
4056
4056
  }
4057
4057
  /**
4058
4058
  * Returns item at `path`, or `undefined` if not found. By default unwraps
@@ -4061,14 +4061,14 @@ var require_Document = __commonJS({
4061
4061
  */
4062
4062
  getIn(path, keepScalar) {
4063
4063
  if (Collection.isEmptyPath(path))
4064
- return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
4065
- return identity.isCollection(this.contents) ? this.contents.getIn(path, keepScalar) : void 0;
4064
+ return !keepScalar && identity2.isScalar(this.contents) ? this.contents.value : this.contents;
4065
+ return identity2.isCollection(this.contents) ? this.contents.getIn(path, keepScalar) : void 0;
4066
4066
  }
4067
4067
  /**
4068
4068
  * Checks if the document includes a value with the key `key`.
4069
4069
  */
4070
4070
  has(key) {
4071
- return identity.isCollection(this.contents) ? this.contents.has(key) : false;
4071
+ return identity2.isCollection(this.contents) ? this.contents.has(key) : false;
4072
4072
  }
4073
4073
  /**
4074
4074
  * Checks if the document includes a value at `path`.
@@ -4076,7 +4076,7 @@ var require_Document = __commonJS({
4076
4076
  hasIn(path) {
4077
4077
  if (Collection.isEmptyPath(path))
4078
4078
  return this.contents !== void 0;
4079
- return identity.isCollection(this.contents) ? this.contents.hasIn(path) : false;
4079
+ return identity2.isCollection(this.contents) ? this.contents.hasIn(path) : false;
4080
4080
  }
4081
4081
  /**
4082
4082
  * Sets a value in this document. For `!!set`, `value` needs to be a
@@ -4183,7 +4183,7 @@ var require_Document = __commonJS({
4183
4183
  }
4184
4184
  };
4185
4185
  function assertCollection(contents) {
4186
- if (identity.isCollection(contents))
4186
+ if (identity2.isCollection(contents))
4187
4187
  return true;
4188
4188
  throw new Error("Expected a YAML collection as document contents");
4189
4189
  }
@@ -4454,12 +4454,12 @@ var require_util_flow_indent_check = __commonJS({
4454
4454
  var require_util_map_includes = __commonJS({
4455
4455
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/compose/util-map-includes.js"(exports2) {
4456
4456
  "use strict";
4457
- var identity = require_identity();
4457
+ var identity2 = require_identity();
4458
4458
  function mapIncludes(ctx, items, search) {
4459
4459
  const { uniqueKeys } = ctx.options;
4460
4460
  if (uniqueKeys === false)
4461
4461
  return false;
4462
- const isEqual = typeof uniqueKeys === "function" ? uniqueKeys : (a, b) => a === b || identity.isScalar(a) && identity.isScalar(b) && a.value === b.value;
4462
+ const isEqual = typeof uniqueKeys === "function" ? uniqueKeys : (a, b) => a === b || identity2.isScalar(a) && identity2.isScalar(b) && a.value === b.value;
4463
4463
  return items.some((pair) => isEqual(pair.key, search));
4464
4464
  }
4465
4465
  exports2.mapIncludes = mapIncludes;
@@ -4672,7 +4672,7 @@ var require_resolve_end = __commonJS({
4672
4672
  var require_resolve_flow_collection = __commonJS({
4673
4673
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/compose/resolve-flow-collection.js"(exports2) {
4674
4674
  "use strict";
4675
- var identity = require_identity();
4675
+ var identity2 = require_identity();
4676
4676
  var Pair = require_Pair();
4677
4677
  var YAMLMap = require_YAMLMap();
4678
4678
  var YAMLSeq = require_YAMLSeq();
@@ -4751,7 +4751,7 @@ var require_resolve_flow_collection = __commonJS({
4751
4751
  }
4752
4752
  if (prevItemComment) {
4753
4753
  let prev = coll.items[coll.items.length - 1];
4754
- if (identity.isPair(prev))
4754
+ if (identity2.isPair(prev))
4755
4755
  prev = prev.value ?? prev.key;
4756
4756
  if (prev.comment)
4757
4757
  prev.comment += "\n" + prevItemComment;
@@ -4866,7 +4866,7 @@ var require_resolve_flow_collection = __commonJS({
4866
4866
  var require_compose_collection = __commonJS({
4867
4867
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/compose/compose-collection.js"(exports2) {
4868
4868
  "use strict";
4869
- var identity = require_identity();
4869
+ var identity2 = require_identity();
4870
4870
  var Scalar = require_Scalar();
4871
4871
  var YAMLMap = require_YAMLMap();
4872
4872
  var YAMLSeq = require_YAMLSeq();
@@ -4916,7 +4916,7 @@ var require_compose_collection = __commonJS({
4916
4916
  }
4917
4917
  const coll = resolveCollection(CN, ctx, token, onError, tagName, tag);
4918
4918
  const res = tag.resolve?.(coll, (msg) => onError(tagToken, "TAG_RESOLVE_FAILED", msg), ctx.options) ?? coll;
4919
- const node = identity.isNode(res) ? res : new Scalar.Scalar(res);
4919
+ const node = identity2.isNode(res) ? res : new Scalar.Scalar(res);
4920
4920
  node.range = coll.range;
4921
4921
  node.tag = tagName;
4922
4922
  if (tag?.format)
@@ -5334,7 +5334,7 @@ var require_resolve_flow_scalar = __commonJS({
5334
5334
  var require_compose_scalar = __commonJS({
5335
5335
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/compose/compose-scalar.js"(exports2) {
5336
5336
  "use strict";
5337
- var identity = require_identity();
5337
+ var identity2 = require_identity();
5338
5338
  var Scalar = require_Scalar();
5339
5339
  var resolveBlockScalar = require_resolve_block_scalar();
5340
5340
  var resolveFlowScalar = require_resolve_flow_scalar();
@@ -5343,17 +5343,17 @@ var require_compose_scalar = __commonJS({
5343
5343
  const tagName = tagToken ? ctx.directives.tagName(tagToken.source, (msg) => onError(tagToken, "TAG_RESOLVE_FAILED", msg)) : null;
5344
5344
  let tag;
5345
5345
  if (ctx.options.stringKeys && ctx.atKey) {
5346
- tag = ctx.schema[identity.SCALAR];
5346
+ tag = ctx.schema[identity2.SCALAR];
5347
5347
  } else if (tagName)
5348
5348
  tag = findScalarTagByName(ctx.schema, value, tagName, tagToken, onError);
5349
5349
  else if (token.type === "scalar")
5350
5350
  tag = findScalarTagByTest(ctx, value, token, onError);
5351
5351
  else
5352
- tag = ctx.schema[identity.SCALAR];
5352
+ tag = ctx.schema[identity2.SCALAR];
5353
5353
  let scalar;
5354
5354
  try {
5355
5355
  const res = tag.resolve(value, (msg) => onError(tagToken ?? token, "TAG_RESOLVE_FAILED", msg), ctx.options);
5356
- scalar = identity.isScalar(res) ? res : new Scalar.Scalar(res);
5356
+ scalar = identity2.isScalar(res) ? res : new Scalar.Scalar(res);
5357
5357
  } catch (error) {
5358
5358
  const msg = error instanceof Error ? error.message : String(error);
5359
5359
  onError(tagToken ?? token, "TAG_RESOLVE_FAILED", msg);
@@ -5373,7 +5373,7 @@ var require_compose_scalar = __commonJS({
5373
5373
  }
5374
5374
  function findScalarTagByName(schema, value, tagName, tagToken, onError) {
5375
5375
  if (tagName === "!")
5376
- return schema[identity.SCALAR];
5376
+ return schema[identity2.SCALAR];
5377
5377
  const matchWithTest = [];
5378
5378
  for (const tag of schema.tags) {
5379
5379
  if (!tag.collection && tag.tag === tagName) {
@@ -5392,12 +5392,12 @@ var require_compose_scalar = __commonJS({
5392
5392
  return kt;
5393
5393
  }
5394
5394
  onError(tagToken, "TAG_RESOLVE_FAILED", `Unresolved tag: ${tagName}`, tagName !== "tag:yaml.org,2002:str");
5395
- return schema[identity.SCALAR];
5395
+ return schema[identity2.SCALAR];
5396
5396
  }
5397
5397
  function findScalarTagByTest({ atKey, directives, schema }, value, token, onError) {
5398
- const tag = schema.tags.find((tag2) => (tag2.default === true || atKey && tag2.default === "key") && tag2.test?.test(value)) || schema[identity.SCALAR];
5398
+ const tag = schema.tags.find((tag2) => (tag2.default === true || atKey && tag2.default === "key") && tag2.test?.test(value)) || schema[identity2.SCALAR];
5399
5399
  if (schema.compat) {
5400
- const compat = schema.compat.find((tag2) => tag2.default && tag2.test?.test(value)) ?? schema[identity.SCALAR];
5400
+ const compat = schema.compat.find((tag2) => tag2.default && tag2.test?.test(value)) ?? schema[identity2.SCALAR];
5401
5401
  if (tag.tag !== compat.tag) {
5402
5402
  const ts = directives.tagString(tag.tag);
5403
5403
  const cs = directives.tagString(compat.tag);
@@ -5446,7 +5446,7 @@ var require_compose_node = __commonJS({
5446
5446
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/compose/compose-node.js"(exports2) {
5447
5447
  "use strict";
5448
5448
  var Alias = require_Alias();
5449
- var identity = require_identity();
5449
+ var identity2 = require_identity();
5450
5450
  var composeCollection = require_compose_collection();
5451
5451
  var composeScalar = require_compose_scalar();
5452
5452
  var resolveEnd = require_resolve_end();
@@ -5492,7 +5492,7 @@ var require_compose_node = __commonJS({
5492
5492
  node ?? (node = composeEmptyNode(ctx, token.offset, void 0, null, props, onError));
5493
5493
  if (anchor && node.anchor === "")
5494
5494
  onError(anchor, "BAD_ALIAS", "Anchor cannot be an empty string");
5495
- if (atKey && ctx.options.stringKeys && (!identity.isScalar(node) || typeof node.value !== "string" || node.tag && node.tag !== "tag:yaml.org,2002:str")) {
5495
+ if (atKey && ctx.options.stringKeys && (!identity2.isScalar(node) || typeof node.value !== "string" || node.tag && node.tag !== "tag:yaml.org,2002:str")) {
5496
5496
  const msg = "With stringKeys, all keys must be strings";
5497
5497
  onError(tag ?? token, "NON_STRING_KEY", msg);
5498
5498
  }
@@ -5598,7 +5598,7 @@ var require_composer = __commonJS({
5598
5598
  var directives = require_directives();
5599
5599
  var Document = require_Document();
5600
5600
  var errors = require_errors();
5601
- var identity = require_identity();
5601
+ var identity2 = require_identity();
5602
5602
  var composeDoc = require_compose_doc();
5603
5603
  var resolveEnd = require_resolve_end();
5604
5604
  function getErrorPos(src) {
@@ -5660,9 +5660,9 @@ var require_composer = __commonJS({
5660
5660
  ${comment}` : comment;
5661
5661
  } else if (afterEmptyLine || doc.directives.docStart || !dc) {
5662
5662
  doc.commentBefore = comment;
5663
- } else if (identity.isCollection(dc) && !dc.flow && dc.items.length > 0) {
5663
+ } else if (identity2.isCollection(dc) && !dc.flow && dc.items.length > 0) {
5664
5664
  let it = dc.items[0];
5665
- if (identity.isPair(it))
5665
+ if (identity2.isPair(it))
5666
5666
  it = it.key;
5667
5667
  const cb = it.commentBefore;
5668
5668
  it.commentBefore = cb ? `${comment}
@@ -7691,7 +7691,7 @@ var require_public_api = __commonJS({
7691
7691
  var Document = require_Document();
7692
7692
  var errors = require_errors();
7693
7693
  var log = require_log();
7694
- var identity = require_identity();
7694
+ var identity2 = require_identity();
7695
7695
  var lineCounter = require_line_counter();
7696
7696
  var parser = require_parser();
7697
7697
  function parseOptions(options) {
@@ -7769,7 +7769,7 @@ var require_public_api = __commonJS({
7769
7769
  if (!keepUndefined)
7770
7770
  return void 0;
7771
7771
  }
7772
- if (identity.isDocument(value) && !_replacer)
7772
+ if (identity2.isDocument(value) && !_replacer)
7773
7773
  return value.toString(options);
7774
7774
  return new Document.Document(value, _replacer, options).toString(options);
7775
7775
  }
@@ -7789,7 +7789,7 @@ var require_dist = __commonJS({
7789
7789
  var Schema = require_Schema();
7790
7790
  var errors = require_errors();
7791
7791
  var Alias = require_Alias();
7792
- var identity = require_identity();
7792
+ var identity2 = require_identity();
7793
7793
  var Pair = require_Pair();
7794
7794
  var Scalar = require_Scalar();
7795
7795
  var YAMLMap = require_YAMLMap();
@@ -7807,14 +7807,14 @@ var require_dist = __commonJS({
7807
7807
  exports2.YAMLParseError = errors.YAMLParseError;
7808
7808
  exports2.YAMLWarning = errors.YAMLWarning;
7809
7809
  exports2.Alias = Alias.Alias;
7810
- exports2.isAlias = identity.isAlias;
7811
- exports2.isCollection = identity.isCollection;
7812
- exports2.isDocument = identity.isDocument;
7813
- exports2.isMap = identity.isMap;
7814
- exports2.isNode = identity.isNode;
7815
- exports2.isPair = identity.isPair;
7816
- exports2.isScalar = identity.isScalar;
7817
- exports2.isSeq = identity.isSeq;
7810
+ exports2.isAlias = identity2.isAlias;
7811
+ exports2.isCollection = identity2.isCollection;
7812
+ exports2.isDocument = identity2.isDocument;
7813
+ exports2.isMap = identity2.isMap;
7814
+ exports2.isNode = identity2.isNode;
7815
+ exports2.isPair = identity2.isPair;
7816
+ exports2.isScalar = identity2.isScalar;
7817
+ exports2.isSeq = identity2.isSeq;
7818
7818
  exports2.Pair = Pair.Pair;
7819
7819
  exports2.Scalar = Scalar.Scalar;
7820
7820
  exports2.YAMLMap = YAMLMap.YAMLMap;
@@ -7833,6 +7833,48 @@ var require_dist = __commonJS({
7833
7833
  });
7834
7834
 
7835
7835
  // src/git.ts
7836
+ var git_exports = {};
7837
+ __export(git_exports, {
7838
+ branchExists: () => branchExists,
7839
+ checkoutBranch: () => checkoutBranch,
7840
+ createAndCheckoutBranch: () => createAndCheckoutBranch,
7841
+ createBranch: () => createBranch,
7842
+ deleteBranch: () => deleteBranch,
7843
+ getAllChangedFiles: () => getAllChangedFiles,
7844
+ getBranchCommits: () => getBranchCommits,
7845
+ getChangedFilesSince: () => getChangedFilesSince,
7846
+ getCommitHash: () => getCommitHash,
7847
+ getCommitsAheadOfUpstream: () => getCommitsAheadOfUpstream,
7848
+ getCommitsSince: () => getCommitsSince,
7849
+ getCurrentBranch: () => getCurrentBranch,
7850
+ getDefaultBranch: () => getDefaultBranch,
7851
+ getDiffStat: () => getDiffStat,
7852
+ getFullDiff: () => getFullDiff,
7853
+ getGitRoot: () => getGitRoot,
7854
+ getHeadSha: () => getHeadSha,
7855
+ getLatestTag: () => getLatestTag,
7856
+ getOnlineLog: () => getOnlineLog,
7857
+ getPushStats: () => getPushStats,
7858
+ getRecentBranchCommits: () => getRecentBranchCommits,
7859
+ getShortStagedFiles: () => getShortStagedFiles,
7860
+ getStagedDiff: () => getStagedDiff,
7861
+ getStagedDiffShortstat: () => getStagedDiffShortstat,
7862
+ getStagedFileCount: () => getStagedFileCount,
7863
+ getStagedFiles: () => getStagedFiles,
7864
+ getUnstagedFiles: () => getUnstagedFiles,
7865
+ getUpstreamRef: () => getUpstreamRef,
7866
+ getWorkingTreeDiff: () => getWorkingTreeDiff,
7867
+ gitCommit: () => gitCommit,
7868
+ gitPush: () => gitPush,
7869
+ gitPushSetUpstream: () => gitPushSetUpstream,
7870
+ hasStagedChanges: () => hasStagedChanges,
7871
+ isGitRepo: () => isGitRepo,
7872
+ resetHard: () => resetHard,
7873
+ stageAll: () => stageAll,
7874
+ stashPop: () => stashPop,
7875
+ stashPushIfDirty: () => stashPushIfDirty,
7876
+ validateRef: () => validateRef
7877
+ });
7836
7878
  function validateRef(ref, name = "ref") {
7837
7879
  if (ref.startsWith("-")) {
7838
7880
  throw new Error(`Invalid git ref ${name}: starts with hyphen: "${ref}"`);
@@ -8032,6 +8074,13 @@ function getStagedDiffShortstat() {
8032
8074
  return { additions: 0, deletions: 0 };
8033
8075
  }
8034
8076
  }
8077
+ function getShortStagedFiles(max = 3) {
8078
+ const output = (0, import_child_process2.execFileSync)("git", ["diff", "--cached", "--name-only"], {
8079
+ encoding: "utf-8"
8080
+ });
8081
+ const all = output.trim().split("\n").filter(Boolean);
8082
+ return { files: all.slice(0, max), total: all.length };
8083
+ }
8035
8084
  function getCommitHash() {
8036
8085
  return (0, import_child_process2.execFileSync)("git", ["rev-parse", "--short", "HEAD"], {
8037
8086
  encoding: "utf-8"
@@ -8693,6 +8742,266 @@ var init_monorepo = __esm({
8693
8742
  }
8694
8743
  });
8695
8744
 
8745
+ // src/smart-diff.ts
8746
+ var smart_diff_exports = {};
8747
+ __export(smart_diff_exports, {
8748
+ classifyFile: () => classifyFile,
8749
+ preprocessDiff: () => preprocessDiff,
8750
+ preprocessDiffWithSizeBudget: () => preprocessDiffWithSizeBudget
8751
+ });
8752
+ function sanitizeFilepath(path) {
8753
+ return path.replace(/[\x00-\x1F\x7F[\]`]/g, "_").slice(0, 200);
8754
+ }
8755
+ function classifyFile(filepath) {
8756
+ const basename = filepath.split("/").pop() ?? filepath;
8757
+ if (LOCK_FILES.has(basename)) return "lock";
8758
+ if (filepath.endsWith(".map")) return "sourcemap";
8759
+ if (VENDORED_PREFIXES.some((p) => filepath.startsWith(p))) return "vendored";
8760
+ if (GENERATED_PATTERNS.some((p) => p.test(filepath))) return "generated";
8761
+ return "code";
8762
+ }
8763
+ function parseDiffIntoFiles(diff) {
8764
+ const files = [];
8765
+ const parts = diff.split(/^(diff --git .+)$/m);
8766
+ for (let i = 1; i < parts.length; i += 2) {
8767
+ const header = parts[i];
8768
+ const content = parts[i + 1] ?? "";
8769
+ const match = header.match(/diff --git a\/(.+?) b\/(.+)/);
8770
+ const filepath = match?.[2] ?? "unknown";
8771
+ const lines = content.split("\n");
8772
+ let additions = 0;
8773
+ let deletions = 0;
8774
+ for (const line of lines) {
8775
+ if (line.startsWith("+") && !line.startsWith("+++")) additions++;
8776
+ else if (line.startsWith("-") && !line.startsWith("---")) deletions++;
8777
+ }
8778
+ files.push({ filepath, content: header + content, additions, deletions });
8779
+ }
8780
+ return files;
8781
+ }
8782
+ function isMinified(content) {
8783
+ const lines = content.split("\n").filter(
8784
+ (l) => (l.startsWith("+") || l.startsWith("-")) && !l.startsWith("+++") && !l.startsWith("---")
8785
+ );
8786
+ if (lines.length === 0) return false;
8787
+ return lines.some((l) => l.length > 500);
8788
+ }
8789
+ function preprocessDiff(diff) {
8790
+ const files = parseDiffIntoFiles(diff);
8791
+ if (files.length === 0) return { processedDiff: diff, summarized: [], aggressivelySummarized: [], tokensSaved: 0 };
8792
+ const kept = [];
8793
+ const summarized = [];
8794
+ let tokensSaved = 0;
8795
+ for (const file of files) {
8796
+ const classification = classifyFile(file.filepath);
8797
+ switch (classification) {
8798
+ case "sourcemap":
8799
+ tokensSaved += estimateTokens(file.content);
8800
+ summarized.push(file.filepath);
8801
+ break;
8802
+ case "lock":
8803
+ tokensSaved += estimateTokens(file.content);
8804
+ kept.push(`[lock file updated: ${sanitizeFilepath(file.filepath)} (+${file.additions} \u2212${file.deletions} lines)]
8805
+ `);
8806
+ summarized.push(file.filepath);
8807
+ break;
8808
+ case "generated":
8809
+ tokensSaved += estimateTokens(file.content);
8810
+ kept.push(`[generated: ${sanitizeFilepath(file.filepath)} (+${file.additions} \u2212${file.deletions})]
8811
+ `);
8812
+ summarized.push(file.filepath);
8813
+ break;
8814
+ case "vendored":
8815
+ tokensSaved += estimateTokens(file.content);
8816
+ kept.push(`[vendored: ${sanitizeFilepath(file.filepath)} updated]
8817
+ `);
8818
+ summarized.push(file.filepath);
8819
+ break;
8820
+ case "code":
8821
+ if (isMinified(file.content)) {
8822
+ tokensSaved += estimateTokens(file.content);
8823
+ const sizeKB = Math.round(file.content.length / 1024);
8824
+ kept.push(`[minified asset: ${sanitizeFilepath(file.filepath)} (${sizeKB} KB)]
8825
+ `);
8826
+ summarized.push(file.filepath);
8827
+ } else {
8828
+ kept.push(file.content);
8829
+ }
8830
+ break;
8831
+ }
8832
+ }
8833
+ return {
8834
+ processedDiff: kept.join(""),
8835
+ summarized,
8836
+ aggressivelySummarized: [],
8837
+ tokensSaved
8838
+ };
8839
+ }
8840
+ function buildFileSummary(file) {
8841
+ const sizeKB = Math.round(file.content.length / 1024);
8842
+ return `[modified: ${sanitizeFilepath(file.filepath)} \u2014 +${file.additions} \u2212${file.deletions} lines, ~${sizeKB}KB]
8843
+ `;
8844
+ }
8845
+ function preprocessDiffWithSizeBudget(diff, maxBytes = 5 * 1024 * 1024) {
8846
+ const files = parseDiffIntoFiles(diff);
8847
+ if (files.length === 0) {
8848
+ return { processedDiff: diff, summarized: [], aggressivelySummarized: [], tokensSaved: 0 };
8849
+ }
8850
+ const entries = [];
8851
+ const summarized = [];
8852
+ let tokensSaved = 0;
8853
+ for (const file of files) {
8854
+ const classification = classifyFile(file.filepath);
8855
+ switch (classification) {
8856
+ case "sourcemap":
8857
+ tokensSaved += estimateTokens(file.content);
8858
+ summarized.push(file.filepath);
8859
+ entries.push({ file, isNoise: true, summaryLine: null });
8860
+ break;
8861
+ case "lock":
8862
+ tokensSaved += estimateTokens(file.content);
8863
+ summarized.push(file.filepath);
8864
+ entries.push({
8865
+ file,
8866
+ isNoise: true,
8867
+ summaryLine: `[lock file updated: ${sanitizeFilepath(file.filepath)} (+${file.additions} \u2212${file.deletions} lines)]
8868
+ `
8869
+ });
8870
+ break;
8871
+ case "generated":
8872
+ tokensSaved += estimateTokens(file.content);
8873
+ summarized.push(file.filepath);
8874
+ entries.push({
8875
+ file,
8876
+ isNoise: true,
8877
+ summaryLine: `[generated: ${sanitizeFilepath(file.filepath)} (+${file.additions} \u2212${file.deletions})]
8878
+ `
8879
+ });
8880
+ break;
8881
+ case "vendored":
8882
+ tokensSaved += estimateTokens(file.content);
8883
+ summarized.push(file.filepath);
8884
+ entries.push({
8885
+ file,
8886
+ isNoise: true,
8887
+ summaryLine: `[vendored: ${sanitizeFilepath(file.filepath)} updated]
8888
+ `
8889
+ });
8890
+ break;
8891
+ case "code":
8892
+ if (isMinified(file.content)) {
8893
+ tokensSaved += estimateTokens(file.content);
8894
+ const sizeKB = Math.round(file.content.length / 1024);
8895
+ summarized.push(file.filepath);
8896
+ entries.push({
8897
+ file,
8898
+ isNoise: true,
8899
+ summaryLine: `[minified asset: ${sanitizeFilepath(file.filepath)} (${sizeKB} KB)]
8900
+ `
8901
+ });
8902
+ } else {
8903
+ entries.push({ file, isNoise: false, summaryLine: null });
8904
+ }
8905
+ break;
8906
+ }
8907
+ }
8908
+ const aggressiveMap = /* @__PURE__ */ new Map();
8909
+ function buildOutput() {
8910
+ const parts = [];
8911
+ for (const entry of entries) {
8912
+ if (entry.isNoise) {
8913
+ if (entry.summaryLine !== null) parts.push(entry.summaryLine);
8914
+ } else if (aggressiveMap.has(entry.file.filepath)) {
8915
+ parts.push(aggressiveMap.get(entry.file.filepath));
8916
+ } else {
8917
+ parts.push(entry.file.content);
8918
+ }
8919
+ }
8920
+ return parts.join("");
8921
+ }
8922
+ const codeEntries = entries.filter((e) => !e.isNoise);
8923
+ let output = buildOutput();
8924
+ if (output.length <= maxBytes) {
8925
+ return {
8926
+ processedDiff: output,
8927
+ summarized,
8928
+ aggressivelySummarized: [],
8929
+ tokensSaved
8930
+ };
8931
+ }
8932
+ const TIER1_THRESHOLD = 5 * 1024;
8933
+ for (const entry of codeEntries) {
8934
+ if (entry.file.content.length > TIER1_THRESHOLD && !aggressiveMap.has(entry.file.filepath)) {
8935
+ tokensSaved += estimateTokens(entry.file.content);
8936
+ aggressiveMap.set(entry.file.filepath, buildFileSummary(entry.file));
8937
+ }
8938
+ }
8939
+ output = buildOutput();
8940
+ if (output.length <= maxBytes) {
8941
+ return {
8942
+ processedDiff: output,
8943
+ summarized,
8944
+ aggressivelySummarized: [...aggressiveMap.keys()],
8945
+ tokensSaved
8946
+ };
8947
+ }
8948
+ const TIER2_THRESHOLD = 2 * 1024;
8949
+ for (const entry of codeEntries) {
8950
+ if (entry.file.content.length > TIER2_THRESHOLD && !aggressiveMap.has(entry.file.filepath)) {
8951
+ tokensSaved += estimateTokens(entry.file.content);
8952
+ aggressiveMap.set(entry.file.filepath, buildFileSummary(entry.file));
8953
+ }
8954
+ }
8955
+ output = buildOutput();
8956
+ if (output.length <= maxBytes) {
8957
+ return {
8958
+ processedDiff: output,
8959
+ summarized,
8960
+ aggressivelySummarized: [...aggressiveMap.keys()],
8961
+ tokensSaved
8962
+ };
8963
+ }
8964
+ for (const entry of codeEntries) {
8965
+ if (!aggressiveMap.has(entry.file.filepath)) {
8966
+ tokensSaved += estimateTokens(entry.file.content);
8967
+ aggressiveMap.set(entry.file.filepath, buildFileSummary(entry.file));
8968
+ }
8969
+ }
8970
+ return {
8971
+ processedDiff: buildOutput(),
8972
+ summarized,
8973
+ aggressivelySummarized: [...aggressiveMap.keys()],
8974
+ tokensSaved
8975
+ };
8976
+ }
8977
+ var LOCK_FILES, GENERATED_PATTERNS, VENDORED_PREFIXES;
8978
+ var init_smart_diff = __esm({
8979
+ "src/smart-diff.ts"() {
8980
+ "use strict";
8981
+ init_dist();
8982
+ LOCK_FILES = /* @__PURE__ */ new Set([
8983
+ "pnpm-lock.yaml",
8984
+ "package-lock.json",
8985
+ "yarn.lock",
8986
+ "Cargo.lock",
8987
+ "Gemfile.lock",
8988
+ "poetry.lock",
8989
+ "composer.lock",
8990
+ "bun.lockb",
8991
+ "shrinkwrap.json"
8992
+ ]);
8993
+ GENERATED_PATTERNS = [
8994
+ /\.generated\.\w+$/,
8995
+ /\.g\.dart$/,
8996
+ /\.pb\.go$/,
8997
+ /\.pb\.ts$/,
8998
+ /(^|\/)\.prisma\/client\//,
8999
+ /\/generated\//
9000
+ ];
9001
+ VENDORED_PREFIXES = ["vendor/", "third_party/", "node_modules/"];
9002
+ }
9003
+ });
9004
+
8696
9005
  // src/commands/changeset.ts
8697
9006
  var changeset_exports = {};
8698
9007
  __export(changeset_exports, {
@@ -8756,7 +9065,9 @@ async function changeset(options) {
8756
9065
  }
8757
9066
  const changedFiles = getChangedFilesSince(base);
8758
9067
  if (changedFiles.length === 0) {
8759
- console.error(`No changes detected vs ${base}.`);
9068
+ console.error(`No commits with file changes detected on this branch vs ${base}.`);
9069
+ console.error(`Tip: \`qc changeset\` requires committed changes (not just staged files).`);
9070
+ console.error(` Commit first with \`qc\`, then run \`qc changeset\`.`);
8760
9071
  process.exit(1);
8761
9072
  }
8762
9073
  const packageMap = mapFilesToPackages(changedFiles, workspace);
@@ -8766,8 +9077,17 @@ async function changeset(options) {
8766
9077
  process.exit(1);
8767
9078
  }
8768
9079
  const commits = getOnlineLog(base);
8769
- const diff = getFullDiff(base);
8770
9080
  const commitCount = commits.split("\n").filter(Boolean).length;
9081
+ const { preprocessDiffWithSizeBudget: preprocessDiffWithSizeBudget2 } = await Promise.resolve().then(() => (init_smart_diff(), smart_diff_exports));
9082
+ const { getDiffStat: getDiffStat2, getFullDiff: getFullDiff2 } = await Promise.resolve().then(() => (init_git(), git_exports));
9083
+ const diffStat = getDiffStat2(base);
9084
+ const rawDiff = getFullDiff2(base);
9085
+ const { processedDiff } = preprocessDiffWithSizeBudget2(rawDiff, 6e4);
9086
+ const diff = `DIFF STAT:
9087
+ ${diffStat}
9088
+
9089
+ DETAILED DIFF (may be summarized for large changes):
9090
+ ${processedDiff}`;
8771
9091
  console.error(
8772
9092
  `Analyzing changes vs ${base}... ${commitCount} commit(s), ${packageNames.length} package(s) changed`
8773
9093
  );
@@ -9261,12 +9581,199 @@ var require_picocolors = __commonJS({
9261
9581
  }
9262
9582
  });
9263
9583
 
9264
- // src/ui.ts
9265
- function hasCliNoColor() {
9266
- try {
9267
- return process.argv.slice(2).includes("--no-color");
9268
- } catch {
9269
- return false;
9584
+ // src/ui-theme.ts
9585
+ function overlayTypeColors(base, custom) {
9586
+ if (!custom || Object.keys(custom).length === 0) return { ...base };
9587
+ const next = { ...base };
9588
+ const pmap = import_picocolors.default;
9589
+ for (const [key, raw] of Object.entries(custom)) {
9590
+ const name = typeof raw === "string" ? raw.trim().toLowerCase() : "";
9591
+ if (!name) continue;
9592
+ const fn = pmap[name];
9593
+ if (typeof fn === "function") {
9594
+ next[key] = fn;
9595
+ }
9596
+ }
9597
+ return next;
9598
+ }
9599
+ function buildVibrant() {
9600
+ return {
9601
+ step: import_picocolors.default.dim,
9602
+ success: import_picocolors.default.greenBright,
9603
+ error: import_picocolors.default.redBright,
9604
+ dim: import_picocolors.default.dim,
9605
+ bullet: import_picocolors.default.greenBright,
9606
+ inlineCode: import_picocolors.default.magentaBright,
9607
+ scope: (s) => import_picocolors.default.bold(import_picocolors.default.yellow(s)),
9608
+ strong: import_picocolors.default.bold,
9609
+ additions: import_picocolors.default.greenBright,
9610
+ deletions: import_picocolors.default.redBright,
9611
+ branchName: (s) => import_picocolors.default.bold(import_picocolors.default.magenta(s)),
9612
+ commitHash: import_picocolors.default.dim,
9613
+ boxBorder: import_picocolors.default.dim,
9614
+ boxBorderAccent: import_picocolors.default.cyanBright,
9615
+ spinner: {
9616
+ aiGenerate: import_picocolors.default.cyanBright,
9617
+ branchGen: import_picocolors.default.cyanBright,
9618
+ gitOp: import_picocolors.default.blueBright,
9619
+ localProvider: import_picocolors.default.magentaBright,
9620
+ smartDiff: import_picocolors.default.dim
9621
+ },
9622
+ type: {
9623
+ feat: (s) => import_picocolors.default.bold(import_picocolors.default.cyanBright(s)),
9624
+ fix: (s) => import_picocolors.default.bold(import_picocolors.default.redBright(s)),
9625
+ perf: (s) => import_picocolors.default.bold(import_picocolors.default.magentaBright(s)),
9626
+ refactor: (s) => import_picocolors.default.bold(import_picocolors.default.yellow(s)),
9627
+ docs: (s) => import_picocolors.default.bold(import_picocolors.default.blue(s)),
9628
+ test: (s) => import_picocolors.default.bold(import_picocolors.default.green(s)),
9629
+ chore: (s) => import_picocolors.default.dim(import_picocolors.default.bold(import_picocolors.default.white(s))),
9630
+ ci: (s) => import_picocolors.default.dim(import_picocolors.default.bold(import_picocolors.default.cyan(s))),
9631
+ style: (s) => import_picocolors.default.dim(import_picocolors.default.bold(import_picocolors.default.magenta(s)))
9632
+ }
9633
+ };
9634
+ }
9635
+ function buildMuted() {
9636
+ return {
9637
+ step: import_picocolors.default.dim,
9638
+ success: import_picocolors.default.green,
9639
+ error: import_picocolors.default.red,
9640
+ dim: import_picocolors.default.dim,
9641
+ bullet: import_picocolors.default.green,
9642
+ inlineCode: import_picocolors.default.magenta,
9643
+ scope: (s) => import_picocolors.default.bold(import_picocolors.default.yellow(s)),
9644
+ strong: import_picocolors.default.bold,
9645
+ additions: import_picocolors.default.green,
9646
+ deletions: import_picocolors.default.red,
9647
+ branchName: (s) => import_picocolors.default.bold(import_picocolors.default.magenta(s)),
9648
+ commitHash: import_picocolors.default.dim,
9649
+ boxBorder: import_picocolors.default.dim,
9650
+ boxBorderAccent: import_picocolors.default.cyan,
9651
+ spinner: {
9652
+ aiGenerate: import_picocolors.default.cyan,
9653
+ branchGen: import_picocolors.default.cyan,
9654
+ gitOp: import_picocolors.default.blue,
9655
+ localProvider: import_picocolors.default.magenta,
9656
+ smartDiff: import_picocolors.default.dim
9657
+ },
9658
+ type: {
9659
+ feat: (s) => import_picocolors.default.bold(import_picocolors.default.cyan(s)),
9660
+ fix: (s) => import_picocolors.default.bold(import_picocolors.default.red(s)),
9661
+ perf: (s) => import_picocolors.default.bold(import_picocolors.default.magenta(s)),
9662
+ refactor: (s) => import_picocolors.default.bold(import_picocolors.default.yellow(s)),
9663
+ docs: (s) => import_picocolors.default.bold(import_picocolors.default.blue(s)),
9664
+ test: (s) => import_picocolors.default.bold(import_picocolors.default.green(s)),
9665
+ chore: (s) => import_picocolors.default.dim(import_picocolors.default.bold(import_picocolors.default.white(s))),
9666
+ ci: (s) => import_picocolors.default.dim(import_picocolors.default.bold(import_picocolors.default.cyan(s))),
9667
+ style: (s) => import_picocolors.default.dim(import_picocolors.default.bold(import_picocolors.default.magenta(s)))
9668
+ }
9669
+ };
9670
+ }
9671
+ function buildMono() {
9672
+ const bold = import_picocolors.default.bold;
9673
+ const dim = import_picocolors.default.dim;
9674
+ return {
9675
+ step: dim,
9676
+ success: bold,
9677
+ error: bold,
9678
+ dim,
9679
+ bullet: bold,
9680
+ inlineCode: bold,
9681
+ scope: bold,
9682
+ strong: bold,
9683
+ additions: bold,
9684
+ deletions: bold,
9685
+ branchName: bold,
9686
+ commitHash: dim,
9687
+ boxBorder: dim,
9688
+ boxBorderAccent: bold,
9689
+ spinner: {
9690
+ aiGenerate: identity,
9691
+ branchGen: identity,
9692
+ gitOp: identity,
9693
+ localProvider: identity,
9694
+ smartDiff: dim
9695
+ },
9696
+ type: {
9697
+ feat: bold,
9698
+ fix: bold,
9699
+ perf: bold,
9700
+ refactor: bold,
9701
+ docs: bold,
9702
+ test: bold,
9703
+ chore: dim,
9704
+ ci: dim,
9705
+ style: dim
9706
+ }
9707
+ };
9708
+ }
9709
+ function applyAdaptive(theme, bg) {
9710
+ if (bg !== "light") return theme;
9711
+ return {
9712
+ ...theme,
9713
+ boxBorder: import_picocolors.default.dim,
9714
+ boxBorderAccent: import_picocolors.default.blue,
9715
+ type: {
9716
+ ...theme.type,
9717
+ feat: (s) => theme.strong(import_picocolors.default.cyan(s)),
9718
+ fix: (s) => theme.strong(import_picocolors.default.red(s)),
9719
+ perf: (s) => theme.strong(import_picocolors.default.magenta(s))
9720
+ }
9721
+ };
9722
+ }
9723
+ function getTheme(name, adaptive) {
9724
+ let base;
9725
+ if (name === "muted") base = buildMuted();
9726
+ else if (name === "mono") base = buildMono();
9727
+ else base = buildVibrant();
9728
+ if (!adaptive) return base;
9729
+ return applyAdaptive(base, detectTerminalBackground());
9730
+ }
9731
+ function detectTerminalBackground() {
9732
+ const raw = process.env.COLORFGBG;
9733
+ if (!raw) return "unknown";
9734
+ const parts = raw.split(";").map((p) => p.trim());
9735
+ if (parts.length < 2) return "unknown";
9736
+ const last = parts[parts.length - 1];
9737
+ const n = parseInt(last, 10);
9738
+ if (!Number.isFinite(n)) return "unknown";
9739
+ if (n >= 232 && n <= 255) return n >= 244 ? "light" : "dark";
9740
+ if (n >= 16 && n <= 231) {
9741
+ const i = n - 16;
9742
+ const r = Math.floor(i / 36) / 5;
9743
+ const g = Math.floor(i % 36 / 6) / 5;
9744
+ const b = i % 6 / 5;
9745
+ const luminance = 0.299 * r + 0.587 * g + 0.114 * b;
9746
+ return luminance >= 0.55 ? "light" : "dark";
9747
+ }
9748
+ if (n >= 8 && n <= 15) return "light";
9749
+ if (n >= 0 && n <= 7) return "dark";
9750
+ return "unknown";
9751
+ }
9752
+ function resolveTheme(opts) {
9753
+ if (opts.noColor) return getTheme("mono", false);
9754
+ const baseName = opts.name ?? "vibrant";
9755
+ const adaptive = opts.adaptive ?? true;
9756
+ let theme = getTheme(baseName, adaptive);
9757
+ if (opts.typeColors && Object.keys(opts.typeColors).length > 0) {
9758
+ theme = { ...theme, type: overlayTypeColors(theme.type, opts.typeColors) };
9759
+ }
9760
+ return theme;
9761
+ }
9762
+ var import_picocolors, identity;
9763
+ var init_ui_theme = __esm({
9764
+ "src/ui-theme.ts"() {
9765
+ "use strict";
9766
+ import_picocolors = __toESM(require_picocolors());
9767
+ identity = (s) => s;
9768
+ }
9769
+ });
9770
+
9771
+ // src/ui.ts
9772
+ function hasCliNoColor() {
9773
+ try {
9774
+ return process.argv.slice(2).includes("--no-color");
9775
+ } catch {
9776
+ return false;
9270
9777
  }
9271
9778
  }
9272
9779
  function getTerminalWidth() {
@@ -9274,16 +9781,21 @@ function getTerminalWidth() {
9274
9781
  }
9275
9782
  function createUI(options) {
9276
9783
  const isColor = options.isTTY && !options.noColor;
9277
- const wrap = (fn) => (s) => isColor ? fn(s) : s;
9784
+ const theme = resolveTheme({
9785
+ name: options.themeName,
9786
+ adaptive: options.adaptive,
9787
+ noColor: !isColor,
9788
+ typeColors: options.typeColors
9789
+ });
9278
9790
  const format = {
9279
- step: (msg) => `${isColor ? import_picocolors.default.dim("\u203A") : "\u203A"} ${isColor ? import_picocolors.default.dim(msg) : msg}`,
9280
- success: (msg) => `${isColor ? import_picocolors.default.green("\u2713") : "\u2713"} ${msg}`,
9281
- error: (msg) => `${isColor ? import_picocolors.default.red("\u2717") : "\u2717"} ${msg}`,
9282
- dim: wrap(import_picocolors.default.dim),
9283
- bold: wrap(import_picocolors.default.bold),
9284
- commitType: wrap(import_picocolors.default.cyan),
9285
- commitScope: wrap(import_picocolors.default.yellow),
9286
- accent: wrap(import_picocolors.default.magenta)
9791
+ step: (msg) => isColor ? `${theme.step("\u203A")} ${theme.dim(msg)}` : `\u203A ${msg}`,
9792
+ success: (msg) => isColor ? `${theme.success("\u2713")} ${msg}` : `\u2713 ${msg}`,
9793
+ error: (msg) => isColor ? `${theme.error("\u2717")} ${msg}` : `\u2717 ${msg}`,
9794
+ dim: (msg) => isColor ? theme.dim(msg) : msg,
9795
+ bold: (msg) => isColor ? theme.strong(msg) : msg,
9796
+ commitType: (t) => isColor ? (theme.type[t] ?? theme.type.feat ?? ((s) => s))(t) : t,
9797
+ commitScope: (scope) => isColor ? theme.scope(scope) : scope,
9798
+ accent: (msg) => isColor ? theme.inlineCode(msg) : msg
9287
9799
  };
9288
9800
  function createSpinner(message, write = (s) => process.stderr.write(s)) {
9289
9801
  let frame = 0;
@@ -9294,7 +9806,7 @@ function createUI(options) {
9294
9806
  if (!options.isTTY) return;
9295
9807
  interval = setInterval(() => {
9296
9808
  const f = SPINNER_FRAMES2[frame++ % SPINNER_FRAMES2.length];
9297
- write(`\r${format.step(message)} ${isColor ? import_picocolors.default.cyan(f) : f}`);
9809
+ write(`\r${format.step(message)} ${isColor ? theme.spinner.aiGenerate(f) : f}`);
9298
9810
  }, 80);
9299
9811
  },
9300
9812
  stop(finalMessage) {
@@ -9317,22 +9829,27 @@ function createUI(options) {
9317
9829
  error: (msg) => process.stderr.write(format.error(msg) + "\n"),
9318
9830
  dim: (msg) => process.stderr.write(format.dim(msg) + "\n")
9319
9831
  };
9320
- return { isColor, format, spinner: createSpinner, log };
9832
+ return { isColor, format, spinner: createSpinner, log, theme };
9321
9833
  }
9322
9834
  function getUI() {
9323
9835
  if (!_defaultUI) {
9836
+ const cfg = getConfig();
9324
9837
  _defaultUI = createUI({
9325
9838
  isTTY: !!process.stderr.isTTY,
9326
- noColor: !!process.env.NO_COLOR || hasCliNoColor()
9839
+ noColor: !!process.env.NO_COLOR || hasCliNoColor(),
9840
+ themeName: cfg.ui?.theme,
9841
+ adaptive: cfg.ui?.adaptive !== false,
9842
+ typeColors: cfg.ui?.type_colors
9327
9843
  });
9328
9844
  }
9329
9845
  return _defaultUI;
9330
9846
  }
9331
- var import_picocolors, SPINNER_FRAMES2, _defaultUI, ui;
9847
+ var SPINNER_FRAMES2, _defaultUI, ui;
9332
9848
  var init_ui = __esm({
9333
9849
  "src/ui.ts"() {
9334
9850
  "use strict";
9335
- import_picocolors = __toESM(require_picocolors());
9851
+ init_config();
9852
+ init_ui_theme();
9336
9853
  SPINNER_FRAMES2 = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
9337
9854
  ui = new Proxy({}, {
9338
9855
  get(_target, prop) {
@@ -9342,7 +9859,10 @@ var init_ui = __esm({
9342
9859
  }
9343
9860
  });
9344
9861
 
9345
- // src/ui-rich.ts
9862
+ // src/ui-layout.ts
9863
+ function stripAnsi(s) {
9864
+ return s.replace(/\x1b\[[0-9;]*m/g, "");
9865
+ }
9346
9866
  function splitCommitForBox(message) {
9347
9867
  const firstLine = message.split("\n")[0] ?? "";
9348
9868
  const m = firstLine.match(HEADER_RX);
@@ -9354,91 +9874,174 @@ function splitCommitForBox(message) {
9354
9874
  subject: m[4] ?? ""
9355
9875
  };
9356
9876
  }
9357
- function renderFileTree(files, maxFiles) {
9877
+ function colorizePath(filepath, isColor) {
9878
+ if (!isColor) return filepath;
9879
+ const slashIdx = filepath.lastIndexOf("/");
9880
+ const dir = slashIdx >= 0 ? filepath.slice(0, slashIdx + 1) : "";
9881
+ const name = slashIdx >= 0 ? filepath.slice(slashIdx + 1) : filepath;
9882
+ const dotIdx = name.lastIndexOf(".");
9883
+ const ext = dotIdx > 0 ? name.slice(dotIdx) : "";
9884
+ const colorize = EXTENSION_COLORS[ext];
9885
+ const coloredName = colorize ? colorize(name) : name;
9886
+ return (dir ? import_picocolors2.default.dim(dir) : "") + coloredName;
9887
+ }
9888
+ function renderFileTree(files, maxFiles, opts = {}) {
9358
9889
  if (files.length === 0) return "";
9890
+ const isColor = opts.isColor ?? false;
9359
9891
  const lines = [];
9360
9892
  const display = files.slice(0, maxFiles);
9361
- const overflow = Math.max(0, files.length - maxFiles);
9893
+ const overflow = files.length - maxFiles;
9362
9894
  for (let i = 0; i < display.length; i++) {
9363
- const isLast = i === display.length - 1 && overflow === 0;
9895
+ const isLast = i === display.length - 1 && overflow <= 0;
9364
9896
  const connector = isLast ? "\u2514\u2500" : "\u251C\u2500";
9365
- lines.push(` ${connector} ${display[i]}`);
9897
+ const colored = colorizePath(display[i] ?? "", isColor);
9898
+ const connectorRendered = isColor ? import_picocolors2.default.dim(connector) : connector;
9899
+ lines.push(` ${connectorRendered} ${colored}`);
9366
9900
  }
9367
9901
  if (overflow > 0) {
9368
- lines.push(` \u2514\u2500 +${overflow} more files`);
9902
+ const connector = isColor ? import_picocolors2.default.dim("\u2514\u2500") : "\u2514\u2500";
9903
+ const more = isColor ? import_picocolors2.default.dim(`+${overflow} more files`) : `+${overflow} more files`;
9904
+ lines.push(` ${connector} ${more}`);
9369
9905
  }
9370
9906
  return lines.join("\n");
9371
9907
  }
9908
+ function renderStatsLine(stats, isColor, theme) {
9909
+ if (stats.files === 0 && stats.additions === 0 && stats.deletions === 0) return "";
9910
+ const dim = theme?.dim ?? import_picocolors2.default.dim;
9911
+ const addFn = theme?.additions ?? ((s) => import_picocolors2.default.green(s));
9912
+ const delFn = theme?.deletions ?? ((s) => import_picocolors2.default.red(s));
9913
+ const filesText = isColor ? dim(`${stats.files} files`) : `${stats.files} files`;
9914
+ const additions = isColor ? addFn(`+${stats.additions}`) : `+${stats.additions}`;
9915
+ const deletions = isColor ? delFn(`\u2212${stats.deletions}`) : `\u2212${stats.deletions}`;
9916
+ const sep = isColor ? dim(" \xB7 ") : " \xB7 ";
9917
+ let text = `${filesText}${sep}${additions} ${deletions}`;
9918
+ if (stats.tokens !== void 0) {
9919
+ const tokens = isColor ? dim(`${stats.tokens} tokens`) : `${stats.tokens} tokens`;
9920
+ text += `${sep}${tokens}`;
9921
+ }
9922
+ return ` ${text}`;
9923
+ }
9372
9924
  function wrapLine(text, width) {
9373
- if (text.length <= width) return [text];
9925
+ if (stripAnsi(text).length <= width) return [text];
9374
9926
  const result = [];
9375
9927
  let remaining = text;
9376
- while (remaining.length > width) {
9377
- let breakAt = remaining.lastIndexOf(" ", width);
9378
- if (breakAt < width / 2) breakAt = width;
9928
+ while (stripAnsi(remaining).length > width) {
9929
+ let visibleCount = 0;
9930
+ let rawIdx = 0;
9931
+ let lastSpaceRaw = -1;
9932
+ const len = remaining.length;
9933
+ while (rawIdx < len && visibleCount < width) {
9934
+ if (remaining[rawIdx] === "\x1B") {
9935
+ while (rawIdx < len && remaining[rawIdx] !== "m") rawIdx++;
9936
+ if (rawIdx < len) rawIdx++;
9937
+ continue;
9938
+ }
9939
+ if (remaining[rawIdx] === " ") lastSpaceRaw = rawIdx;
9940
+ visibleCount++;
9941
+ rawIdx++;
9942
+ }
9943
+ const breakAt = lastSpaceRaw > 0 && lastSpaceRaw > width / 2 ? lastSpaceRaw : rawIdx;
9379
9944
  result.push(remaining.slice(0, breakAt));
9380
9945
  remaining = remaining.slice(breakAt).trimStart();
9381
9946
  }
9382
9947
  if (remaining) result.push(remaining);
9383
9948
  return result;
9384
9949
  }
9385
- function stripAnsi(s) {
9386
- return s.replace(/\x1b\[[0-9;]*m/g, "");
9950
+ function isImportantCommit(header, body) {
9951
+ if (/BREAKING CHANGE/i.test(body)) return true;
9952
+ if (/^[a-z]+(\([^)]+\))?!:/i.test(header)) return true;
9953
+ return false;
9954
+ }
9955
+ function styleBoxTopRow(box, horizRepeat, isColor, theme) {
9956
+ if (!isColor) return box.topLeft + box.horizontal.repeat(horizRepeat) + box.topRight;
9957
+ const edge = theme?.boxBorder ?? import_picocolors2.default.dim;
9958
+ const corner = theme?.boxBorderAccent ?? edge;
9959
+ return corner(box.topLeft) + edge(box.horizontal.repeat(horizRepeat)) + corner(box.topRight);
9960
+ }
9961
+ function styleBoxBottomRow(box, horizRepeat, isColor, theme) {
9962
+ if (!isColor) return box.bottomLeft + box.horizontal.repeat(horizRepeat) + box.bottomRight;
9963
+ const edge = theme?.boxBorder ?? import_picocolors2.default.dim;
9964
+ const corner = theme?.boxBorderAccent ?? edge;
9965
+ return corner(box.bottomLeft) + edge(box.horizontal.repeat(horizRepeat)) + corner(box.bottomRight);
9387
9966
  }
9388
- function boxedLine(content, innerWidth, isColor) {
9967
+ function boxedLine(vertical, content, innerWidth, isColor, theme) {
9389
9968
  const visibleLen = stripAnsi(content).length;
9390
9969
  const padding = " ".repeat(Math.max(0, innerWidth - visibleLen));
9391
- const border = isColor ? import_picocolors2.default.dim("\u2502") : "\u2502";
9970
+ const border = isColor ? (theme?.boxBorder ?? import_picocolors2.default.dim)(vertical) : vertical;
9392
9971
  return ` ${border} ${content}${padding} ${border}`;
9393
9972
  }
9973
+ function buildHeaderPrefixAndSubject(parsed, headerFirstLine, isColor, theme) {
9974
+ if (!parsed.type) {
9975
+ return { prefix: "", subjectText: headerFirstLine };
9976
+ }
9977
+ const bangPlain = parsed.breaking ? "!" : "";
9978
+ if (parsed.scope) {
9979
+ const prefixPlain2 = `${parsed.type}(${parsed.scope})${bangPlain}: `;
9980
+ if (!isColor) {
9981
+ return { prefix: prefixPlain2, subjectText: parsed.subject };
9982
+ }
9983
+ const typeCell2 = theme ? theme.type[parsed.type] ?? theme.type.feat ?? ((s) => s) : (s) => import_picocolors2.default.bold(import_picocolors2.default.cyan(s));
9984
+ const scopeCell = theme ? theme.scope : (s) => import_picocolors2.default.bold(import_picocolors2.default.yellow(s));
9985
+ const bangCell2 = theme ? parsed.breaking ? theme.error("!") : "" : parsed.breaking ? import_picocolors2.default.bold(import_picocolors2.default.red("!")) : "";
9986
+ const prefixStyled2 = `${typeCell2(parsed.type)}(${scopeCell(parsed.scope)})${bangCell2}: `;
9987
+ return { prefix: prefixStyled2, subjectText: parsed.subject };
9988
+ }
9989
+ const prefixPlain = `${parsed.type}${bangPlain}: `;
9990
+ if (!isColor) {
9991
+ return { prefix: prefixPlain, subjectText: parsed.subject };
9992
+ }
9993
+ const typeCell = theme ? theme.type[parsed.type] ?? theme.type.feat ?? ((s) => s) : (s) => import_picocolors2.default.bold(import_picocolors2.default.cyan(s));
9994
+ const bangCell = theme ? parsed.breaking ? theme.error("!") : "" : parsed.breaking ? import_picocolors2.default.bold(import_picocolors2.default.red("!")) : "";
9995
+ const prefixStyled = `${typeCell(parsed.type)}${bangCell}: `;
9996
+ return { prefix: prefixStyled, subjectText: parsed.subject };
9997
+ }
9394
9998
  function renderBoxedCommit(header, body, opts) {
9395
- if (opts.width < MIN_BOX_WIDTH) {
9999
+ const requestedStyle = opts.style ?? "gradient";
10000
+ const promoted = opts.autoEmphasis !== false && requestedStyle !== "none" && isImportantCommit(header.split("\n")[0] ?? header, body);
10001
+ const style = promoted ? "double" : requestedStyle;
10002
+ if (style === "none" || opts.width < MIN_BOX_WIDTH) {
9396
10003
  const lines2 = [header.split("\n")[0] ?? header];
9397
10004
  if (body) lines2.push("", body);
9398
10005
  return lines2.join("\n");
9399
10006
  }
10007
+ const chars = BOX_CHARS[style];
9400
10008
  const innerWidth = opts.width - 6;
9401
10009
  const horiz = opts.width - 2;
9402
- const top = " " + (opts.isColor ? import_picocolors2.default.dim("\u256D" + "\u2500".repeat(horiz) + "\u256E") : "\u256D" + "\u2500".repeat(horiz) + "\u256E");
9403
- const bottom = " " + (opts.isColor ? import_picocolors2.default.dim("\u2570" + "\u2500".repeat(horiz) + "\u256F") : "\u2570" + "\u2500".repeat(horiz) + "\u256F");
10010
+ const firstLineHeader = header.split("\n")[0] ?? header;
9404
10011
  const parsed = splitCommitForBox(header);
9405
- let firstLineStyled;
9406
- if (parsed.type && parsed.scope) {
9407
- const bare = `${parsed.type}(${parsed.scope})${parsed.breaking ? "!" : ""}: ${parsed.subject}`;
9408
- firstLineStyled = opts.isColor ? `${import_picocolors2.default.bold(import_picocolors2.default.cyan(parsed.type))}(${import_picocolors2.default.bold(import_picocolors2.default.yellow(parsed.scope))})${parsed.breaking ? import_picocolors2.default.bold(import_picocolors2.default.red("!")) : ""}: ${parsed.subject}` : bare;
9409
- } else if (parsed.type) {
9410
- const bare = `${parsed.type}${parsed.breaking ? "!" : ""}: ${parsed.subject}`;
9411
- firstLineStyled = opts.isColor ? `${import_picocolors2.default.bold(import_picocolors2.default.cyan(parsed.type))}${parsed.breaking ? import_picocolors2.default.bold(import_picocolors2.default.red("!")) : ""}: ${parsed.subject}` : bare;
9412
- } else {
9413
- firstLineStyled = header.split("\n")[0] ?? header;
9414
- }
10012
+ const { prefix: headerPrefix, subjectText } = buildHeaderPrefixAndSubject(
10013
+ parsed,
10014
+ firstLineHeader,
10015
+ opts.isColor,
10016
+ opts.theme
10017
+ );
10018
+ const prefixLen = stripAnsi(headerPrefix).length;
10019
+ const subjectLines = wrapLine(subjectText, Math.max(1, innerWidth - prefixLen));
10020
+ const styledTop = styleBoxTopRow(chars, horiz, opts.isColor, opts.theme);
10021
+ const styledBottom = styleBoxBottomRow(chars, horiz, opts.isColor, opts.theme);
9415
10022
  const lines = [];
9416
- const headerParts = wrapLine(firstLineStyled, innerWidth);
9417
- for (let i = 0; i < headerParts.length; i++) {
9418
- const indent = i === 0 ? "" : " ";
9419
- lines.push(boxedLine(indent + (headerParts[i] ?? ""), innerWidth, opts.isColor));
10023
+ lines.push(" " + styledTop);
10024
+ lines.push(boxedLine(chars.vertical, headerPrefix + (subjectLines[0] ?? ""), innerWidth, opts.isColor, opts.theme));
10025
+ for (let i = 1; i < subjectLines.length; i++) {
10026
+ lines.push(boxedLine(chars.vertical, " " + (subjectLines[i] ?? ""), innerWidth, opts.isColor, opts.theme));
9420
10027
  }
9421
10028
  if (body) {
9422
- lines.push(boxedLine("", innerWidth, opts.isColor));
10029
+ lines.push(boxedLine(chars.vertical, "", innerWidth, opts.isColor, opts.theme));
9423
10030
  for (const bline of body.split("\n")) {
9424
10031
  const trimmed = bline.trim();
9425
10032
  if (!trimmed) continue;
9426
- const rendered = trimmed.replace(/^[-*]\s+/, opts.isColor ? `${import_picocolors2.default.green("\u2022")} ` : "\u2022 ");
10033
+ const bulletChar = opts.isColor ? (opts.theme?.bullet ?? import_picocolors2.default.green)("\u2022") : "\u2022";
10034
+ const rendered = trimmed.replace(/^[-*]\s+/, `${bulletChar} `);
9427
10035
  const wrapped = wrapLine(rendered, innerWidth);
9428
10036
  for (let i = 0; i < wrapped.length; i++) {
9429
- lines.push(boxedLine((i === 0 ? "" : " ") + (wrapped[i] ?? ""), innerWidth, opts.isColor));
10037
+ lines.push(
10038
+ boxedLine(chars.vertical, (i === 0 ? "" : " ") + (wrapped[i] ?? ""), innerWidth, opts.isColor, opts.theme)
10039
+ );
9430
10040
  }
9431
10041
  }
9432
10042
  }
9433
- return [top, ...lines, bottom].join("\n");
9434
- }
9435
- function renderStatsLine(stats, isColor) {
9436
- const parts = [];
9437
- parts.push(`${stats.files} files`);
9438
- parts.push(`+${stats.additions} \u2212${stats.deletions}`);
9439
- if (stats.tokens !== void 0) parts.push(`${stats.tokens} tokens`);
9440
- const text = parts.join(" \xB7 ");
9441
- return isColor ? ` ${import_picocolors2.default.dim(text)}` : ` ${text}`;
10043
+ lines.push(" " + styledBottom);
10044
+ return lines.join("\n");
9442
10045
  }
9443
10046
  function shouldUseRichOutput(opts) {
9444
10047
  if (!opts.isTTY) return false;
@@ -9447,14 +10050,162 @@ function shouldUseRichOutput(opts) {
9447
10050
  if (opts.width < MIN_BOX_WIDTH) return false;
9448
10051
  return true;
9449
10052
  }
9450
- var import_picocolors2, HEADER_RX, MIN_BOX_WIDTH;
9451
- var init_ui_rich = __esm({
9452
- "src/ui-rich.ts"() {
10053
+ var import_picocolors2, HEADER_RX, EXTENSION_COLORS, MIN_BOX_WIDTH, BOX_CHARS;
10054
+ var init_ui_layout = __esm({
10055
+ "src/ui-layout.ts"() {
9453
10056
  "use strict";
9454
10057
  import_picocolors2 = __toESM(require_picocolors());
9455
- init_ui();
9456
10058
  HEADER_RX = /^([a-z]+)(?:\(([^)]+)\))?(!)?:\s*(.*)$/;
10059
+ EXTENSION_COLORS = {
10060
+ ".ts": import_picocolors2.default.cyan,
10061
+ ".mts": import_picocolors2.default.cyan,
10062
+ ".tsx": import_picocolors2.default.cyanBright,
10063
+ ".js": import_picocolors2.default.yellow,
10064
+ ".mjs": import_picocolors2.default.yellow,
10065
+ ".cjs": import_picocolors2.default.yellow,
10066
+ ".jsx": import_picocolors2.default.yellowBright,
10067
+ ".py": import_picocolors2.default.blue,
10068
+ ".rs": import_picocolors2.default.red,
10069
+ ".go": import_picocolors2.default.cyanBright,
10070
+ ".css": import_picocolors2.default.magenta,
10071
+ ".scss": import_picocolors2.default.magenta,
10072
+ ".sass": import_picocolors2.default.magenta,
10073
+ ".html": import_picocolors2.default.redBright,
10074
+ ".md": import_picocolors2.default.green,
10075
+ ".json": (s) => import_picocolors2.default.dim(import_picocolors2.default.cyan(s)),
10076
+ ".yaml": (s) => import_picocolors2.default.dim(import_picocolors2.default.cyan(s)),
10077
+ ".yml": (s) => import_picocolors2.default.dim(import_picocolors2.default.cyan(s)),
10078
+ ".toml": (s) => import_picocolors2.default.dim(import_picocolors2.default.cyan(s)),
10079
+ ".lock": import_picocolors2.default.dim
10080
+ };
9457
10081
  MIN_BOX_WIDTH = 60;
10082
+ BOX_CHARS = {
10083
+ rounded: {
10084
+ topLeft: "\u256D",
10085
+ topRight: "\u256E",
10086
+ bottomLeft: "\u2570",
10087
+ bottomRight: "\u256F",
10088
+ horizontal: "\u2500",
10089
+ vertical: "\u2502"
10090
+ },
10091
+ gradient: {
10092
+ topLeft: "\u256D",
10093
+ topRight: "\u256E",
10094
+ bottomLeft: "\u2570",
10095
+ bottomRight: "\u256F",
10096
+ horizontal: "\u2500",
10097
+ vertical: "\u2502"
10098
+ },
10099
+ double: {
10100
+ topLeft: "\u2554",
10101
+ topRight: "\u2557",
10102
+ bottomLeft: "\u255A",
10103
+ bottomRight: "\u255D",
10104
+ horizontal: "\u2550",
10105
+ vertical: "\u2551"
10106
+ }
10107
+ };
10108
+ }
10109
+ });
10110
+
10111
+ // src/ui-rich.ts
10112
+ function buildUIContext(ui2, config2, args) {
10113
+ return {
10114
+ theme: ui2.theme,
10115
+ animate: args.noAnimate ? "none" : config2.ui?.animate ?? "tasteful",
10116
+ isTTY: !!process.stderr.isTTY,
10117
+ isColor: ui2.isColor,
10118
+ asciiFallback: !ui2.isColor,
10119
+ uniform: config2.ui?.spinner === "uniform"
10120
+ };
10121
+ }
10122
+ function createStageSpinner(opts) {
10123
+ const origCfg = STAGE_CONFIG[opts.stage];
10124
+ const cfg = opts.uniform ? {
10125
+ frames: STAGE_CONFIG.aiGenerate.frames,
10126
+ intervalMs: STAGE_CONFIG.aiGenerate.intervalMs,
10127
+ themeKey: origCfg.themeKey
10128
+ } : origCfg;
10129
+ const intervalMs = Math.max(16, Math.round(cfg.intervalMs * (opts.animate === "full" ? 0.55 : 1)));
10130
+ const frames = !opts.isColor && opts.asciiFallback ? ASCII_FRAMES : cfg.frames;
10131
+ const colorize = opts.isColor && opts.animate !== "none" ? opts.theme.spinner[cfg.themeKey] : (s) => s;
10132
+ const dim = opts.theme.dim;
10133
+ const write = opts.write ?? ((s) => process.stderr.write(s));
10134
+ let frame = 0;
10135
+ let interval = null;
10136
+ return {
10137
+ start() {
10138
+ if (interval) return;
10139
+ if (!opts.isTTY) return;
10140
+ if (opts.animate === "none") return;
10141
+ interval = setInterval(() => {
10142
+ const f = frames[frame++ % frames.length];
10143
+ write(`\r${dim("\u203A")} ${dim(opts.message)} ${colorize(f)}`);
10144
+ }, intervalMs);
10145
+ },
10146
+ stop(finalMessage) {
10147
+ if (interval) {
10148
+ clearInterval(interval);
10149
+ interval = null;
10150
+ }
10151
+ if (opts.isTTY) {
10152
+ write("\r\x1B[2K");
10153
+ }
10154
+ if (finalMessage) {
10155
+ write(finalMessage + "\n");
10156
+ }
10157
+ }
10158
+ };
10159
+ }
10160
+ async function flashSuccess(opts) {
10161
+ const write = opts.write ?? ((s) => process.stderr.write(s));
10162
+ const animate = opts.animate !== "none" && opts.isTTY;
10163
+ const rawFallback = opts.settledMessage ?? opts.theme.success(opts.message);
10164
+ const fallbackLine = animate ? rawFallback : stripAnsi(rawFallback);
10165
+ if (!animate) {
10166
+ write(fallbackLine + "\n");
10167
+ return;
10168
+ }
10169
+ write(opts.theme.success(opts.message));
10170
+ await new Promise((r) => setTimeout(r, opts.flashMs ?? 200));
10171
+ write("\r\x1B[2K");
10172
+ write((opts.settledMessage ?? opts.message) + "\n");
10173
+ }
10174
+ var STAGE_CONFIG, ASCII_FRAMES;
10175
+ var init_ui_rich = __esm({
10176
+ "src/ui-rich.ts"() {
10177
+ "use strict";
10178
+ init_ui();
10179
+ init_ui_layout();
10180
+ init_ui_layout();
10181
+ STAGE_CONFIG = {
10182
+ aiGenerate: {
10183
+ frames: ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"],
10184
+ intervalMs: 80,
10185
+ themeKey: "aiGenerate"
10186
+ },
10187
+ branchGen: {
10188
+ frames: ["\u25F0", "\u25F3", "\u25F2", "\u25F1"],
10189
+ intervalMs: 85,
10190
+ themeKey: "branchGen"
10191
+ },
10192
+ localProvider: {
10193
+ frames: ["\u25D0", "\u25D3", "\u25D1", "\u25D2"],
10194
+ intervalMs: 100,
10195
+ themeKey: "localProvider"
10196
+ },
10197
+ gitOp: {
10198
+ frames: ["\u2190", "\u2196", "\u2191", "\u2197", "\u2192", "\u2198", "\u2193", "\u2199"],
10199
+ intervalMs: 90,
10200
+ themeKey: "gitOp"
10201
+ },
10202
+ smartDiff: {
10203
+ frames: ["\u258F", "\u258E", "\u258D", "\u258C", "\u258B", "\u258A", "\u2589", "\u258A", "\u258B", "\u258C", "\u258D", "\u258E"],
10204
+ intervalMs: 70,
10205
+ themeKey: "smartDiff"
10206
+ }
10207
+ };
10208
+ ASCII_FRAMES = ["|", "/", "-", "\\"];
9458
10209
  }
9459
10210
  });
9460
10211
 
@@ -9503,324 +10254,126 @@ async function interactiveRefineMessage(initial, opts) {
9503
10254
  if (opts.skip) return { action: "accept", message: initial };
9504
10255
  const rl = import_promises.default.createInterface({ input: process.stdin, output: process.stderr });
9505
10256
  try {
9506
- process.stderr.write(`
9507
- ${initial}
9508
-
9509
- `);
9510
- const choice = (await rl.question("Keep? [Y/n/e]: ")).trim().toLowerCase();
9511
- if (choice === "n") {
9512
- return { action: "abort" };
9513
- }
9514
- if (choice === "e") {
9515
- process.stderr.write("Enter new message (end with a line containing only .):\n");
9516
- const lines = [];
9517
- while (true) {
9518
- const line = await rl.question("");
9519
- if (line === ".") break;
9520
- lines.push(line);
9521
- }
9522
- const edited = lines.join("\n").trim();
9523
- return { action: "edit", message: edited.length > 0 ? edited : initial };
9524
- }
9525
- return { action: "accept", message: initial };
9526
- } finally {
9527
- rl.close();
9528
- }
9529
- }
9530
- async function promptYesNo(question, defaultYes = true) {
9531
- const rl = import_promises.default.createInterface({ input: process.stdin, output: process.stderr });
9532
- const suffix = defaultYes ? "[Y/n]" : "[y/N]";
9533
- try {
9534
- const answer = (await rl.question(`${question} ${suffix} `)).trim().toLowerCase();
9535
- if (answer === "n" || answer === "no") return false;
9536
- if (answer === "y" || answer === "yes") return true;
9537
- return defaultYes;
9538
- } finally {
9539
- rl.close();
9540
- }
9541
- }
9542
- async function confirmCommit(prompt2, opts) {
9543
- if (opts.skip) return { action: "commit" };
9544
- const rl = import_promises.default.createInterface({ input: process.stdin, output: process.stderr });
9545
- try {
9546
- const ans = (await rl.question(prompt2)).trim().toLowerCase();
9547
- if (ans !== "y" && ans !== "yes") {
9548
- return { action: "abort" };
9549
- }
9550
- return { action: "commit" };
9551
- } finally {
9552
- rl.close();
9553
- }
9554
- }
9555
- function shouldSkipTTYInteraction(hookMode) {
9556
- return hookMode === true || process.stdin.isTTY !== true;
9557
- }
9558
- function logVerboseDiagnostics(dim, verbose, quiet, diagnostics, roundTripMs) {
9559
- if (!verbose || quiet) return;
9560
- process.stderr.write(
9561
- `
9562
- ${formatVerboseCommitDiagnostics(diagnostics, roundTripMs)}
9563
- `
9564
- );
9565
- dim("(verbose diagnostics on stderr)");
9566
- }
9567
- function isDisplayOpts(opts) {
9568
- return typeof opts === "object" && opts !== null && "log" in opts;
9569
- }
9570
- function createSilentLog() {
9571
- return {
9572
- step: () => {
9573
- },
9574
- success: () => {
9575
- },
9576
- error: (msg) => console.error(msg),
9577
- dim: () => {
9578
- }
9579
- };
9580
- }
9581
- function displayCommitMessage(message, opts) {
9582
- const display = isDisplayOpts(opts) ? opts : { log: opts };
9583
- const log = display.log;
9584
- const { subject, body } = splitCommitMessageForDisplay(message);
9585
- const tw = getTerminalWidth();
9586
- const useRich = shouldUseRichOutput({
9587
- isTTY: display.isTTY ?? !!process.stderr.isTTY,
9588
- noColor: display.isColor === false,
9589
- width: tw,
9590
- style: display.style ?? "rich"
9591
- });
9592
- if (useRich) {
9593
- const tree = display.stagedFiles && display.stagedFiles.length > 0 ? renderFileTree(display.stagedFiles, 8) : "";
9594
- if (tree) {
9595
- process.stderr.write(tree + "\n");
9596
- }
9597
- const boxed = renderBoxedCommit(subject, body, {
9598
- width: Math.min(Math.max(tw - 4, 60), 80),
9599
- isColor: !!display.isColor
9600
- });
9601
- process.stderr.write(boxed + "\n");
9602
- if (display.stats) {
9603
- process.stderr.write(renderStatsLine(display.stats, !!display.isColor) + "\n");
9604
- }
9605
- return;
9606
- }
9607
- log.success(subject);
9608
- if (body) {
9609
- for (const line of body.split("\n")) {
9610
- log.dim(` ${line}`);
9611
- }
9612
- process.stderr.write("\n");
9613
- }
9614
- }
9615
- var import_promises;
9616
- var init_commit_helpers = __esm({
9617
- "src/commit-helpers.ts"() {
9618
- "use strict";
9619
- import_promises = __toESM(require("node:readline/promises"));
9620
- init_ui_rich();
9621
- }
9622
- });
9623
-
9624
- // src/smart-diff.ts
9625
- function sanitizeFilepath(path) {
9626
- return path.replace(/[\x00-\x1F\x7F[\]`]/g, "_").slice(0, 200);
9627
- }
9628
- function classifyFile(filepath) {
9629
- const basename = filepath.split("/").pop() ?? filepath;
9630
- if (LOCK_FILES.has(basename)) return "lock";
9631
- if (filepath.endsWith(".map")) return "sourcemap";
9632
- if (VENDORED_PREFIXES.some((p) => filepath.startsWith(p))) return "vendored";
9633
- if (GENERATED_PATTERNS.some((p) => p.test(filepath))) return "generated";
9634
- return "code";
9635
- }
9636
- function parseDiffIntoFiles(diff) {
9637
- const files = [];
9638
- const parts = diff.split(/^(diff --git .+)$/m);
9639
- for (let i = 1; i < parts.length; i += 2) {
9640
- const header = parts[i];
9641
- const content = parts[i + 1] ?? "";
9642
- const match = header.match(/diff --git a\/(.+?) b\/(.+)/);
9643
- const filepath = match?.[2] ?? "unknown";
9644
- const lines = content.split("\n");
9645
- let additions = 0;
9646
- let deletions = 0;
9647
- for (const line of lines) {
9648
- if (line.startsWith("+") && !line.startsWith("+++")) additions++;
9649
- else if (line.startsWith("-") && !line.startsWith("---")) deletions++;
9650
- }
9651
- files.push({ filepath, content: header + content, additions, deletions });
9652
- }
9653
- return files;
9654
- }
9655
- function isMinified(content) {
9656
- const lines = content.split("\n").filter(
9657
- (l) => (l.startsWith("+") || l.startsWith("-")) && !l.startsWith("+++") && !l.startsWith("---")
9658
- );
9659
- if (lines.length === 0) return false;
9660
- return lines.some((l) => l.length > 500);
9661
- }
9662
- function buildFileSummary(file) {
9663
- const sizeKB = Math.round(file.content.length / 1024);
9664
- return `[modified: ${sanitizeFilepath(file.filepath)} \u2014 +${file.additions} \u2212${file.deletions} lines, ~${sizeKB}KB]
9665
- `;
9666
- }
9667
- function preprocessDiffWithSizeBudget(diff, maxBytes = 5 * 1024 * 1024) {
9668
- const files = parseDiffIntoFiles(diff);
9669
- if (files.length === 0) {
9670
- return { processedDiff: diff, summarized: [], aggressivelySummarized: [], tokensSaved: 0 };
9671
- }
9672
- const entries = [];
9673
- const summarized = [];
9674
- let tokensSaved = 0;
9675
- for (const file of files) {
9676
- const classification = classifyFile(file.filepath);
9677
- switch (classification) {
9678
- case "sourcemap":
9679
- tokensSaved += estimateTokens(file.content);
9680
- summarized.push(file.filepath);
9681
- entries.push({ file, isNoise: true, summaryLine: null });
9682
- break;
9683
- case "lock":
9684
- tokensSaved += estimateTokens(file.content);
9685
- summarized.push(file.filepath);
9686
- entries.push({
9687
- file,
9688
- isNoise: true,
9689
- summaryLine: `[lock file updated: ${sanitizeFilepath(file.filepath)} (+${file.additions} \u2212${file.deletions} lines)]
9690
- `
9691
- });
9692
- break;
9693
- case "generated":
9694
- tokensSaved += estimateTokens(file.content);
9695
- summarized.push(file.filepath);
9696
- entries.push({
9697
- file,
9698
- isNoise: true,
9699
- summaryLine: `[generated: ${sanitizeFilepath(file.filepath)} (+${file.additions} \u2212${file.deletions})]
9700
- `
9701
- });
9702
- break;
9703
- case "vendored":
9704
- tokensSaved += estimateTokens(file.content);
9705
- summarized.push(file.filepath);
9706
- entries.push({
9707
- file,
9708
- isNoise: true,
9709
- summaryLine: `[vendored: ${sanitizeFilepath(file.filepath)} updated]
9710
- `
9711
- });
9712
- break;
9713
- case "code":
9714
- if (isMinified(file.content)) {
9715
- tokensSaved += estimateTokens(file.content);
9716
- const sizeKB = Math.round(file.content.length / 1024);
9717
- summarized.push(file.filepath);
9718
- entries.push({
9719
- file,
9720
- isNoise: true,
9721
- summaryLine: `[minified asset: ${sanitizeFilepath(file.filepath)} (${sizeKB} KB)]
9722
- `
9723
- });
9724
- } else {
9725
- entries.push({ file, isNoise: false, summaryLine: null });
9726
- }
9727
- break;
10257
+ process.stderr.write(`
10258
+ ${initial}
10259
+
10260
+ `);
10261
+ const choice = (await rl.question("Keep? [Y/n/e]: ")).trim().toLowerCase();
10262
+ if (choice === "n") {
10263
+ return { action: "abort" };
9728
10264
  }
9729
- }
9730
- const aggressiveMap = /* @__PURE__ */ new Map();
9731
- function buildOutput() {
9732
- const parts = [];
9733
- for (const entry of entries) {
9734
- if (entry.isNoise) {
9735
- if (entry.summaryLine !== null) parts.push(entry.summaryLine);
9736
- } else if (aggressiveMap.has(entry.file.filepath)) {
9737
- parts.push(aggressiveMap.get(entry.file.filepath));
9738
- } else {
9739
- parts.push(entry.file.content);
10265
+ if (choice === "e") {
10266
+ process.stderr.write("Enter new message (end with a line containing only .):\n");
10267
+ const lines = [];
10268
+ while (true) {
10269
+ const line = await rl.question("");
10270
+ if (line === ".") break;
10271
+ lines.push(line);
9740
10272
  }
10273
+ const edited = lines.join("\n").trim();
10274
+ return { action: "edit", message: edited.length > 0 ? edited : initial };
9741
10275
  }
9742
- return parts.join("");
10276
+ return { action: "accept", message: initial };
10277
+ } finally {
10278
+ rl.close();
9743
10279
  }
9744
- const codeEntries = entries.filter((e) => !e.isNoise);
9745
- let output = buildOutput();
9746
- if (output.length <= maxBytes) {
9747
- return {
9748
- processedDiff: output,
9749
- summarized,
9750
- aggressivelySummarized: [],
9751
- tokensSaved
9752
- };
10280
+ }
10281
+ async function promptYesNo(question, defaultYes = true) {
10282
+ const rl = import_promises.default.createInterface({ input: process.stdin, output: process.stderr });
10283
+ const suffix = defaultYes ? "[Y/n]" : "[y/N]";
10284
+ try {
10285
+ const answer = (await rl.question(`${question} ${suffix} `)).trim().toLowerCase();
10286
+ if (answer === "n" || answer === "no") return false;
10287
+ if (answer === "y" || answer === "yes") return true;
10288
+ return defaultYes;
10289
+ } finally {
10290
+ rl.close();
9753
10291
  }
9754
- const TIER1_THRESHOLD = 5 * 1024;
9755
- for (const entry of codeEntries) {
9756
- if (entry.file.content.length > TIER1_THRESHOLD && !aggressiveMap.has(entry.file.filepath)) {
9757
- tokensSaved += estimateTokens(entry.file.content);
9758
- aggressiveMap.set(entry.file.filepath, buildFileSummary(entry.file));
10292
+ }
10293
+ async function confirmCommit(prompt2, opts) {
10294
+ if (opts.skip) return { action: "commit" };
10295
+ const rl = import_promises.default.createInterface({ input: process.stdin, output: process.stderr });
10296
+ try {
10297
+ const ans = (await rl.question(prompt2)).trim().toLowerCase();
10298
+ if (ans !== "y" && ans !== "yes") {
10299
+ return { action: "abort" };
9759
10300
  }
10301
+ return { action: "commit" };
10302
+ } finally {
10303
+ rl.close();
9760
10304
  }
9761
- output = buildOutput();
9762
- if (output.length <= maxBytes) {
9763
- return {
9764
- processedDiff: output,
9765
- summarized,
9766
- aggressivelySummarized: [...aggressiveMap.keys()],
9767
- tokensSaved
9768
- };
9769
- }
9770
- const TIER2_THRESHOLD = 2 * 1024;
9771
- for (const entry of codeEntries) {
9772
- if (entry.file.content.length > TIER2_THRESHOLD && !aggressiveMap.has(entry.file.filepath)) {
9773
- tokensSaved += estimateTokens(entry.file.content);
9774
- aggressiveMap.set(entry.file.filepath, buildFileSummary(entry.file));
10305
+ }
10306
+ function shouldSkipTTYInteraction(hookMode) {
10307
+ return hookMode === true || process.stdin.isTTY !== true;
10308
+ }
10309
+ function logVerboseDiagnostics(dim, verbose, quiet, diagnostics, roundTripMs) {
10310
+ if (!verbose || quiet) return;
10311
+ process.stderr.write(
10312
+ `
10313
+ ${formatVerboseCommitDiagnostics(diagnostics, roundTripMs)}
10314
+ `
10315
+ );
10316
+ dim("(verbose diagnostics on stderr)");
10317
+ }
10318
+ function isDisplayOpts(opts) {
10319
+ return typeof opts === "object" && opts !== null && "log" in opts;
10320
+ }
10321
+ function createSilentLog() {
10322
+ return {
10323
+ step: () => {
10324
+ },
10325
+ success: () => {
10326
+ },
10327
+ error: (msg) => console.error(msg),
10328
+ dim: () => {
9775
10329
  }
10330
+ };
10331
+ }
10332
+ function displayCommitMessage(message, opts) {
10333
+ const display = isDisplayOpts(opts) ? opts : { log: opts, isTTY: false };
10334
+ const log = display.log;
10335
+ const { subject, body } = splitCommitMessageForDisplay(message);
10336
+ const tw = getTerminalWidth();
10337
+ const useRich = shouldUseRichOutput({
10338
+ isTTY: display.isTTY ?? !!process.stderr.isTTY,
10339
+ noColor: display.isColor === false,
10340
+ width: tw,
10341
+ style: display.style ?? "rich"
10342
+ });
10343
+ if (useRich) {
10344
+ const theme = display.theme ?? getUI().theme;
10345
+ const tree = display.stagedFiles && display.stagedFiles.length > 0 ? renderFileTree(display.stagedFiles, 3, { isColor: !!display.isColor }) : "";
10346
+ if (tree) {
10347
+ process.stderr.write(tree + "\n");
10348
+ }
10349
+ const boxed = renderBoxedCommit(subject, body, {
10350
+ width: display.boxWidth ?? Math.min(getTerminalWidth() - 4, 80),
10351
+ isColor: !!display.isColor,
10352
+ style: display.boxStyle ?? "gradient",
10353
+ autoEmphasis: display.autoEmphasis ?? true,
10354
+ theme
10355
+ });
10356
+ process.stderr.write(boxed + "\n");
10357
+ if (display.stats) {
10358
+ process.stderr.write(renderStatsLine(display.stats, !!display.isColor, theme) + "\n");
10359
+ }
10360
+ return;
9776
10361
  }
9777
- output = buildOutput();
9778
- if (output.length <= maxBytes) {
9779
- return {
9780
- processedDiff: output,
9781
- summarized,
9782
- aggressivelySummarized: [...aggressiveMap.keys()],
9783
- tokensSaved
9784
- };
9785
- }
9786
- for (const entry of codeEntries) {
9787
- if (!aggressiveMap.has(entry.file.filepath)) {
9788
- tokensSaved += estimateTokens(entry.file.content);
9789
- aggressiveMap.set(entry.file.filepath, buildFileSummary(entry.file));
10362
+ log.success(subject);
10363
+ if (body) {
10364
+ for (const line of body.split("\n")) {
10365
+ log.dim(` ${line}`);
9790
10366
  }
10367
+ process.stderr.write("\n");
9791
10368
  }
9792
- return {
9793
- processedDiff: buildOutput(),
9794
- summarized,
9795
- aggressivelySummarized: [...aggressiveMap.keys()],
9796
- tokensSaved
9797
- };
9798
10369
  }
9799
- var LOCK_FILES, GENERATED_PATTERNS, VENDORED_PREFIXES;
9800
- var init_smart_diff = __esm({
9801
- "src/smart-diff.ts"() {
10370
+ var import_promises;
10371
+ var init_commit_helpers = __esm({
10372
+ "src/commit-helpers.ts"() {
9802
10373
  "use strict";
9803
- init_dist();
9804
- LOCK_FILES = /* @__PURE__ */ new Set([
9805
- "pnpm-lock.yaml",
9806
- "package-lock.json",
9807
- "yarn.lock",
9808
- "Cargo.lock",
9809
- "Gemfile.lock",
9810
- "poetry.lock",
9811
- "composer.lock",
9812
- "bun.lockb",
9813
- "shrinkwrap.json"
9814
- ]);
9815
- GENERATED_PATTERNS = [
9816
- /\.generated\.\w+$/,
9817
- /\.g\.dart$/,
9818
- /\.pb\.go$/,
9819
- /\.pb\.ts$/,
9820
- /(^|\/)\.prisma\/client\//,
9821
- /\/generated\//
9822
- ];
9823
- VENDORED_PREFIXES = ["vendor/", "third_party/", "node_modules/"];
10374
+ import_promises = __toESM(require("node:readline/promises"));
10375
+ init_ui();
10376
+ init_ui_rich();
9824
10377
  }
9825
10378
  });
9826
10379
 
@@ -10021,6 +10574,8 @@ async function runLocalCommit(args) {
10021
10574
  }
10022
10575
  const config2 = getConfig();
10023
10576
  const excludes = [...config2.excludes ?? [], ...args.exclude];
10577
+ const uiCtx = buildUIContext(ui2, config2, args);
10578
+ const boxStyle = args.boxStyleOverride ?? config2.ui?.box?.style ?? "gradient";
10024
10579
  let diff = getStagedDiff(excludes);
10025
10580
  const changes = getStagedFiles();
10026
10581
  if (!args.noSmartDiff) {
@@ -10078,7 +10633,11 @@ async function runLocalCommit(args) {
10078
10633
  "Cloudflare provider requires api_url. Run: qc config set api_url https://your-worker.workers.dev"
10079
10634
  );
10080
10635
  }
10081
- const spinner = ui2.spinner(`generating commit (${modelDisplay} via ${local.provider})...`);
10636
+ const spinner = createStageSpinner({
10637
+ stage: "localProvider",
10638
+ message: `generating commit (${modelDisplay} via ${local.provider})...`,
10639
+ ...uiCtx
10640
+ });
10082
10641
  if (!silent) spinner.start();
10083
10642
  const t0 = Date.now();
10084
10643
  let res;
@@ -10129,6 +10688,10 @@ async function runLocalCommit(args) {
10129
10688
  isTTY: !!process.stderr.isTTY,
10130
10689
  style: "rich",
10131
10690
  stagedFiles: stagedPaths,
10691
+ boxStyle,
10692
+ autoEmphasis: config2.ui?.box?.auto_emphasis ?? true,
10693
+ theme: ui2.theme,
10694
+ boxWidth: typeof config2.ui?.box?.width === "number" ? config2.ui.box.width : void 0,
10132
10695
  stats: {
10133
10696
  files: stagedPaths.length,
10134
10697
  additions: short.additions,
@@ -10148,15 +10711,39 @@ async function runLocalCommit(args) {
10148
10711
  }
10149
10712
  gitCommit(message);
10150
10713
  const branch = getCurrentBranch();
10151
- log.step(`[${branch} committed]`);
10714
+ const hash = getCommitHash();
10715
+ if (!silent) {
10716
+ await flashSuccess({
10717
+ message: `\u2713 committed ${branch} \xB7 ${hash}`,
10718
+ settledMessage: `${ui2.theme.success("\u2713 committed")}${ui2.theme.dim(` ${branch} \xB7 ${hash}`)}`,
10719
+ theme: ui2.theme,
10720
+ animate: uiCtx.animate,
10721
+ isTTY: uiCtx.isTTY
10722
+ });
10723
+ }
10152
10724
  if (args.push) {
10153
10725
  const pushStats = getPushStats();
10154
10726
  log.step(`pushing to origin/${branch}...`);
10155
10727
  gitPush();
10156
- if (pushStats) {
10157
- log.success(`pushed ${pushStats.commits} commit(s) \xB7 ${pushStats.stat}`);
10158
- } else {
10159
- log.success("pushed");
10728
+ if (!silent) {
10729
+ if (pushStats) {
10730
+ await flashSuccess({
10731
+ message: `\u2713 pushed ${pushStats.commits} commit(s) \xB7 ${pushStats.stat}`,
10732
+ settledMessage: `${ui2.theme.success("\u2713 pushed")}${ui2.theme.dim(
10733
+ ` ${pushStats.commits} commit(s) \xB7 ${pushStats.stat}`
10734
+ )}`,
10735
+ theme: ui2.theme,
10736
+ animate: uiCtx.animate,
10737
+ isTTY: uiCtx.isTTY
10738
+ });
10739
+ } else {
10740
+ await flashSuccess({
10741
+ message: "\u2713 pushed",
10742
+ theme: ui2.theme,
10743
+ animate: uiCtx.animate,
10744
+ isTTY: uiCtx.isTTY
10745
+ });
10746
+ }
10160
10747
  }
10161
10748
  }
10162
10749
  }
@@ -10272,7 +10859,13 @@ async function runLocalBranch(opts) {
10272
10859
  }
10273
10860
  const ui2 = getUI();
10274
10861
  const log = ui2.log;
10275
- const spinner = ui2.spinner(`generating branch name (${opts.model ?? local.model} via ${local.provider})...`);
10862
+ const config2 = getConfig();
10863
+ const branchUiCtx = buildUIContext(ui2, config2, { noAnimate: opts.noAnimate });
10864
+ const spinner = createStageSpinner({
10865
+ stage: "branchGen",
10866
+ message: `generating branch name (${opts.model ?? local.model} via ${local.provider})...`,
10867
+ ...branchUiCtx
10868
+ });
10276
10869
  if (process.stderr.isTTY) spinner.start();
10277
10870
  let final;
10278
10871
  try {
@@ -10322,6 +10915,7 @@ var init_local = __esm({
10322
10915
  init_ui();
10323
10916
  init_commit_helpers();
10324
10917
  init_branch_name();
10918
+ init_ui_rich();
10325
10919
  CONFIG_PATH2 = (0, import_path8.join)((0, import_os4.homedir)(), CONFIG_DIR);
10326
10920
  PROVIDER_URLS = {
10327
10921
  ollama: "http://localhost:11434",
@@ -10356,12 +10950,14 @@ function finalizeGeneratedBranchName(raw) {
10356
10950
  async function runBranch(opts) {
10357
10951
  const ui2 = getUI();
10358
10952
  const log = ui2.log;
10953
+ const config2 = getConfig();
10954
+ const animate = opts.noAnimate ? "none" : config2.ui?.animate ?? "tasteful";
10955
+ const uniformSpinner = config2.ui?.spinner === "uniform";
10359
10956
  if (!isGitRepo()) {
10360
10957
  log.error("Not a git repository.");
10361
10958
  process.exit(1);
10362
10959
  }
10363
10960
  const baseRef = opts.from ?? "HEAD";
10364
- const config2 = getConfig();
10365
10961
  const model = opts.model ?? config2.model;
10366
10962
  const genRules = branchGenerationRules(config2);
10367
10963
  if (opts.rescue) {
@@ -10390,7 +10986,16 @@ async function runBranch(opts) {
10390
10986
  const recent = getRecentBranchCommits(state.commitsAhead);
10391
10987
  const apiKey2 = opts.apiKey ?? getApiKey();
10392
10988
  if (apiKey2) {
10393
- const spinner2 = ui2.spinner(`generating branch name (${model ?? "default"})...`);
10989
+ const spinner2 = createStageSpinner({
10990
+ stage: "branchGen",
10991
+ message: `generating branch name (${model ?? "default"})...`,
10992
+ theme: ui2.theme,
10993
+ animate,
10994
+ isTTY: !!process.stderr.isTTY,
10995
+ isColor: ui2.isColor,
10996
+ asciiFallback: !ui2.isColor,
10997
+ uniform: uniformSpinner
10998
+ });
10394
10999
  if (process.stderr.isTTY) spinner2.start();
10395
11000
  try {
10396
11001
  const client = new ApiClient({ apiKey: apiKey2 });
@@ -10419,7 +11024,16 @@ async function runBranch(opts) {
10419
11024
  "Not authenticated. Run `qc login` first, or configure a local provider for `--rescue`."
10420
11025
  );
10421
11026
  }
10422
- const spinner2 = ui2.spinner(`generating branch name (${model ?? "default"} via local)...`);
11027
+ const spinner2 = createStageSpinner({
11028
+ stage: "branchGen",
11029
+ message: `generating branch name (${model ?? "default"} via local)...`,
11030
+ theme: ui2.theme,
11031
+ animate,
11032
+ isTTY: !!process.stderr.isTTY,
11033
+ isColor: ui2.isColor,
11034
+ asciiFallback: !ui2.isColor,
11035
+ uniform: uniformSpinner
11036
+ });
10423
11037
  if (process.stderr.isTTY) spinner2.start();
10424
11038
  try {
10425
11039
  try {
@@ -10516,13 +11130,23 @@ async function runBranch(opts) {
10516
11130
  noSwitch: opts.noSwitch,
10517
11131
  push: opts.push,
10518
11132
  baseRef,
10519
- rules: genRules
11133
+ rules: genRules,
11134
+ noAnimate: opts.noAnimate
10520
11135
  });
10521
11136
  return;
10522
11137
  }
10523
11138
  throw new Error("Not authenticated. Run `qc login` first, or provide --message.");
10524
11139
  }
10525
- const spinner = ui2.spinner(`generating branch name (${model ?? "default"})...`);
11140
+ const spinner = createStageSpinner({
11141
+ stage: "branchGen",
11142
+ message: `generating branch name (${model ?? "default"})...`,
11143
+ theme: ui2.theme,
11144
+ animate,
11145
+ isTTY: !!process.stderr.isTTY,
11146
+ isColor: ui2.isColor,
11147
+ asciiFallback: !ui2.isColor,
11148
+ uniform: uniformSpinner
11149
+ });
10526
11150
  if (process.stderr.isTTY) spinner.start();
10527
11151
  let result;
10528
11152
  try {
@@ -10560,6 +11184,7 @@ var init_branch2 = __esm({
10560
11184
  init_branch_name();
10561
11185
  init_commit_helpers();
10562
11186
  init_ui();
11187
+ init_ui_rich();
10563
11188
  }
10564
11189
  });
10565
11190
 
@@ -10965,7 +11590,12 @@ async function runBranchGuard(args, log) {
10965
11590
  }
10966
11591
  generateLocalBranchNameFn = generateLocalBranchName2;
10967
11592
  }
10968
- const spinner = ui2.spinner(`generating branch name...`);
11593
+ const guardUiCtx = buildUIContext(ui2, config2, args);
11594
+ const spinner = createStageSpinner({
11595
+ stage: "branchGen",
11596
+ message: "generating branch name...",
11597
+ ...guardUiCtx
11598
+ });
10969
11599
  if (process.stderr.isTTY) spinner.start();
10970
11600
  let rawName;
10971
11601
  let usedFallback = false;
@@ -11075,6 +11705,7 @@ var init_branch_guard = __esm({
11075
11705
  init_branch_name();
11076
11706
  init_ui();
11077
11707
  init_commit_helpers();
11708
+ init_ui_rich();
11078
11709
  }
11079
11710
  });
11080
11711
 
@@ -11101,7 +11732,8 @@ async function runCommit(args) {
11101
11732
  hookMode: !!args.hookMode,
11102
11733
  apiKey: apiKeyFlag ?? getApiKey() ?? void 0,
11103
11734
  model: args.model,
11104
- excludes
11735
+ excludes,
11736
+ noAnimate: args.noAnimate
11105
11737
  },
11106
11738
  log
11107
11739
  );
@@ -11182,7 +11814,13 @@ async function runCommit(args) {
11182
11814
  const skipInteractive = silent || args.quiet || shouldSkipTTYInteraction(args.hookMode);
11183
11815
  const skipConfirm = args.dryRun || messageOnly || silent || args.quiet || shouldSkipTTYInteraction(args.hookMode);
11184
11816
  const modelDisplay = model ?? "default";
11185
- const spinner = ui2.spinner(`generating commit (${modelDisplay})...`);
11817
+ const uiCtx = buildUIContext(ui2, config2, args);
11818
+ const boxStyle = args.boxStyleOverride ?? config2.ui?.box?.style ?? "gradient";
11819
+ const spinner = createStageSpinner({
11820
+ stage: "aiGenerate",
11821
+ message: `generating commit (${modelDisplay})...`,
11822
+ ...uiCtx
11823
+ });
11186
11824
  if (!silent) spinner.start();
11187
11825
  const t0 = Date.now();
11188
11826
  let generatedMessage;
@@ -11226,6 +11864,10 @@ async function runCommit(args) {
11226
11864
  isTTY: !!process.stderr.isTTY,
11227
11865
  style: "rich",
11228
11866
  stagedFiles: stagedPaths,
11867
+ boxStyle,
11868
+ autoEmphasis: config2.ui?.box?.auto_emphasis ?? true,
11869
+ theme: ui2.theme,
11870
+ boxWidth: typeof config2.ui?.box?.width === "number" ? config2.ui.box.width : void 0,
11229
11871
  stats: {
11230
11872
  files: stagedPaths.length,
11231
11873
  additions: short.additions,
@@ -11245,15 +11887,38 @@ async function runCommit(args) {
11245
11887
  gitCommit(message);
11246
11888
  const hash = getCommitHash();
11247
11889
  const branch = getCurrentBranch();
11248
- log.step(`[${branch} ${hash}] committed`);
11890
+ if (!silent) {
11891
+ await flashSuccess({
11892
+ message: `\u2713 committed ${branch} \xB7 ${hash}`,
11893
+ settledMessage: `${ui2.theme.success("\u2713 committed")}${ui2.theme.dim(` ${branch} \xB7 ${hash}`)}`,
11894
+ theme: ui2.theme,
11895
+ animate: uiCtx.animate,
11896
+ isTTY: !!process.stderr.isTTY
11897
+ });
11898
+ }
11249
11899
  if (push) {
11250
11900
  const pushStats = getPushStats();
11251
11901
  log.step(`pushing to origin/${branch}...`);
11252
11902
  gitPush();
11253
- if (pushStats) {
11254
- log.success(`pushed ${pushStats.commits} commit(s) \xB7 ${pushStats.stat}`);
11255
- } else {
11256
- log.success("pushed");
11903
+ if (!silent) {
11904
+ if (pushStats) {
11905
+ await flashSuccess({
11906
+ message: `\u2713 pushed ${pushStats.commits} commit(s) \xB7 ${pushStats.stat}`,
11907
+ settledMessage: `${ui2.theme.success("\u2713 pushed")}${ui2.theme.dim(
11908
+ ` ${pushStats.commits} commit(s) \xB7 ${pushStats.stat}`
11909
+ )}`,
11910
+ theme: ui2.theme,
11911
+ animate: uiCtx.animate,
11912
+ isTTY: !!process.stderr.isTTY
11913
+ });
11914
+ } else {
11915
+ await flashSuccess({
11916
+ message: "\u2713 pushed",
11917
+ theme: ui2.theme,
11918
+ animate: uiCtx.animate,
11919
+ isTTY: !!process.stderr.isTTY
11920
+ });
11921
+ }
11257
11922
  }
11258
11923
  }
11259
11924
  }
@@ -11269,6 +11934,7 @@ var init_commit = __esm({
11269
11934
  init_smart_diff();
11270
11935
  init_commit_helpers();
11271
11936
  init_branch_guard();
11937
+ init_ui_rich();
11272
11938
  }
11273
11939
  });
11274
11940
 
@@ -11285,8 +11951,8 @@ Usage:
11285
11951
  qc Generate commit message and commit (default)
11286
11952
  qc pr Generate PR description from branch commits
11287
11953
  qc changelog Generate changelog from commits since last tag
11288
- qc changeset Automate pnpm changeset with AI
11289
- qc branch Generate branch name + create branch (use --message for description)
11954
+ qc changeset Generate changesets from branch commits (pnpm monorepo)
11955
+ qc branch Generate and create a named branch from changes
11290
11956
  qc init Install prepare-commit-msg hook
11291
11957
  qc login Sign in via browser
11292
11958
  qc logout Clear local credentials
@@ -11294,11 +11960,13 @@ Usage:
11294
11960
  qc team Team management (info, rules, invite)
11295
11961
  qc config Show/set config
11296
11962
 
11297
- Flags:
11963
+ Run \`qc <command> -h\` for command-specific help.
11964
+
11965
+ Commit flags:
11298
11966
  -p, --push Commit and push
11299
- -a, --all Stage all tracked changes first
11967
+ -a, --all Stage all files (modified + untracked) first
11300
11968
  -m, --message-only Print message only (stdout, no commit)
11301
- -v, --verbose Show diagnostics (model, token estimates, rules) + API round-trip ms on stderr
11969
+ -v, --verbose Show diagnostics (model, tokens, latency)
11302
11970
  -q, --quiet Minimal output
11303
11971
  -n, --dry-run Show message without committing
11304
11972
  -i, --interactive Interactive refinement mode
@@ -11309,28 +11977,15 @@ Flags:
11309
11977
  -t, --type <type> Force commit type
11310
11978
  -S, --scope <scope> Force scope
11311
11979
  -e, --exclude <pat> Exclude files from diff (repeatable)
11312
-
11313
11980
  --no-context Skip commit history context
11314
11981
  --no-smart-diff Skip smart diff preprocessing
11315
11982
  --no-color Disable colors
11983
+ --no-animate Disable spinner animation and success flash
11984
+ --style <name> Box style: rounded | gradient | double | none
11316
11985
  --model <id> Use specific model
11317
- --base <branch> Base branch for pr/changeset (default: main)
11318
- --create Create PR with gh CLI (qc pr --create)
11319
- --from <ref> Start ref for changelog / base ref for qc branch
11320
- --to <ref> End ref for changelog
11321
- --write Write changelog to CHANGELOG.md
11322
11986
  --hook-mode Silent mode for git hooks
11323
-
11324
- Branch flags (qc branch):
11325
- --message <text> Generate from a description (no diff needed)
11326
- --from-commits Generate from recent commits instead of diff
11327
- --rescue Move commits off current protected branch (see docs)
11328
- --no-switch Create branch but don't checkout
11329
- --from <ref> Create branch from this ref (default: HEAD)
11330
-
11331
- Commit guard flags:
11332
- --allow-protected Bypass protected-branch guard for this run
11333
- --auto-branch Auto-create branch with generated name (no prompt)
11987
+ --allow-protected Bypass protected-branch guard
11988
+ --auto-branch Auto-create branch (no prompt) when on protected branch
11334
11989
 
11335
11990
  Compose short flags: qc -ap (stage all + push), qc -apv (+ verbose)
11336
11991
 
@@ -11343,6 +11998,81 @@ Examples:
11343
11998
  qc -e "*.lock" # exclude lock files
11344
11999
  qc -t fix -S auth # force type and scope
11345
12000
  `;
12001
+ var HELP_PR = `qc pr \u2014 Generate a PR description from branch commits
12002
+
12003
+ Usage:
12004
+ qc pr Generate PR description and print to stdout
12005
+ qc pr --create Generate and open a PR via \`gh\` CLI
12006
+
12007
+ Flags:
12008
+ --base <branch> Base branch to compare against (default: main)
12009
+ --create Create the PR with \`gh pr create\` (requires gh CLI)
12010
+ --model <id> Use specific model
12011
+
12012
+ Examples:
12013
+ qc pr # print PR description
12014
+ qc pr --create # create the PR directly
12015
+ qc pr --base develop # compare against develop
12016
+ `;
12017
+ var HELP_CHANGELOG = `qc changelog \u2014 Generate a changelog from commits since last tag
12018
+
12019
+ Usage:
12020
+ qc changelog Print changelog entry to stdout
12021
+ qc changelog --write Prepend to CHANGELOG.md
12022
+
12023
+ Flags:
12024
+ --from <ref> Start ref (default: latest tag)
12025
+ --to <ref> End ref (default: HEAD)
12026
+ --write Write/prepend to CHANGELOG.md
12027
+ --version <ver> Version label for header (default: derived from --to)
12028
+ --model <id> Use specific model
12029
+
12030
+ Examples:
12031
+ qc changelog # print changelog since last tag
12032
+ qc changelog --write # prepend to CHANGELOG.md
12033
+ qc changelog --from v1.0.0 # since a specific tag
12034
+ `;
12035
+ var HELP_CHANGESET = `qc changeset \u2014 Generate pnpm changesets from branch commits
12036
+
12037
+ Usage:
12038
+ qc changeset Analyze commits on current branch vs base, generate .changeset/ file
12039
+
12040
+ Requires: commits ahead of base branch (not just staged files).
12041
+ Tip: commit your changes first with \`qc\`, then run \`qc changeset\`.
12042
+
12043
+ Flags:
12044
+ --base <branch> Base branch to compare against (default: main)
12045
+ --model <id> Use specific model
12046
+
12047
+ Examples:
12048
+ qc changeset # changeset from commits vs main
12049
+ qc changeset --base develop # compare against develop
12050
+ `;
12051
+ var HELP_BRANCH = `qc branch \u2014 Generate and create a branch with an AI-generated name
12052
+
12053
+ Usage:
12054
+ qc branch Name from staged/unstaged diff
12055
+ qc branch <name> Use explicit name (skip AI)
12056
+ qc branch --message "..." Name from a description (no diff needed)
12057
+ qc branch --from-commits Name from recent commit history
12058
+ qc branch --rescue Move commits off a protected branch
12059
+
12060
+ Flags:
12061
+ --message <text> Generate name from a description
12062
+ --from-commits Use commit log instead of diff for naming
12063
+ --rescue Move existing commits off protected branch to new branch
12064
+ --no-switch Create branch but don't checkout
12065
+ --from <ref> Base from this ref (default: HEAD)
12066
+ -p, --push Push immediately and set upstream
12067
+ -n, --dry-run Show generated name without creating
12068
+
12069
+ Examples:
12070
+ qc branch # name from current changes
12071
+ qc branch -m "add oauth login" # name from description
12072
+ qc branch feat/my-feature # explicit name
12073
+ qc branch --rescue # move commits off main
12074
+ qc branch -np # dry-run (show name only)
12075
+ `;
11346
12076
  var SHORT_FLAGS = {
11347
12077
  p: "push",
11348
12078
  a: "all",
@@ -11405,6 +12135,7 @@ function parseArgs(args) {
11405
12135
  result[key] = val;
11406
12136
  }
11407
12137
  } else if (ch === "h") {
12138
+ if (result.command !== "commit") result.helpFor = result.command;
11408
12139
  result.command = "help";
11409
12140
  } else {
11410
12141
  throw new Error(`Unknown flag: -${ch}`);
@@ -11433,12 +12164,14 @@ function parseArgs(args) {
11433
12164
  continue;
11434
12165
  }
11435
12166
  if (ch === "h") {
12167
+ if (result.command !== "commit") result.helpFor = result.command;
11436
12168
  result.command = "help";
11437
12169
  continue;
11438
12170
  }
11439
12171
  throw new Error(`Unknown flag: -${ch}`);
11440
12172
  }
11441
12173
  if (arg === "--help") {
12174
+ if (result.command !== "commit") result.helpFor = result.command;
11442
12175
  result.command = "help";
11443
12176
  } else if (arg === "--all") {
11444
12177
  result.all = true;
@@ -11517,6 +12250,16 @@ function parseArgs(args) {
11517
12250
  const ex = args[++i];
11518
12251
  if (ex) result.exclude.push(ex);
11519
12252
  } else if (arg === "--no-color") {
12253
+ } else if (arg === "--no-animate") {
12254
+ result.noAnimate = true;
12255
+ } else if (arg === "--style" && i + 1 < args.length) {
12256
+ const v = args[++i];
12257
+ if (v !== "rounded" && v !== "gradient" && v !== "double" && v !== "none") {
12258
+ throw new Error(
12259
+ `Invalid --style value: ${v}. Must be: rounded | gradient | double | none.`
12260
+ );
12261
+ }
12262
+ result.boxStyleOverride = v;
11520
12263
  } else if (arg === "login") {
11521
12264
  result.command = "login";
11522
12265
  subcommandSeen = true;
@@ -11576,7 +12319,13 @@ async function main() {
11576
12319
  }
11577
12320
  const { command, apiKey } = values;
11578
12321
  if (command === "help") {
11579
- console.log(HELP);
12322
+ const subHelp = {
12323
+ pr: HELP_PR,
12324
+ changelog: HELP_CHANGELOG,
12325
+ changeset: HELP_CHANGESET,
12326
+ branch: HELP_BRANCH
12327
+ };
12328
+ console.log(values.helpFor && subHelp[values.helpFor] ? subHelp[values.helpFor] : HELP);
11580
12329
  return;
11581
12330
  }
11582
12331
  if (values.setProvider) {
@@ -11662,7 +12411,8 @@ async function main() {
11662
12411
  push: values.push,
11663
12412
  from: values.from,
11664
12413
  model: values.model,
11665
- apiKey: values.apiKey
12414
+ apiKey: values.apiKey,
12415
+ noAnimate: values.noAnimate
11666
12416
  });
11667
12417
  return;
11668
12418
  }